aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4client.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4client.c')
-rw-r--r--fs/nfs/nfs4client.c240
1 files changed, 205 insertions, 35 deletions
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 90dce91dd5b5..a860ab566d6e 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -41,19 +41,138 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
41} 41}
42 42
43#ifdef CONFIG_NFS_V4_1 43#ifdef CONFIG_NFS_V4_1
44static void nfs4_shutdown_session(struct nfs_client *clp) 44/**
45 * Per auth flavor data server rpc clients
46 */
47struct nfs4_ds_server {
48 struct list_head list; /* ds_clp->cl_ds_clients */
49 struct rpc_clnt *rpc_clnt;
50};
51
52/**
53 * Common lookup case for DS I/O
54 */
55static struct nfs4_ds_server *
56nfs4_find_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
57{
58 struct nfs4_ds_server *dss;
59
60 rcu_read_lock();
61 list_for_each_entry_rcu(dss, &ds_clp->cl_ds_clients, list) {
62 if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
63 continue;
64 goto out;
65 }
66 dss = NULL;
67out:
68 rcu_read_unlock();
69 return dss;
70}
71
72static struct nfs4_ds_server *
73nfs4_add_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor,
74 struct nfs4_ds_server *new)
75{
76 struct nfs4_ds_server *dss;
77
78 spin_lock(&ds_clp->cl_lock);
79 list_for_each_entry(dss, &ds_clp->cl_ds_clients, list) {
80 if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
81 continue;
82 goto out;
83 }
84 if (new)
85 list_add_rcu(&new->list, &ds_clp->cl_ds_clients);
86 dss = new;
87out:
88 spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */
89 return dss;
90}
91
92static struct nfs4_ds_server *
93nfs4_alloc_ds_server(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
94{
95 struct nfs4_ds_server *dss;
96
97 dss = kmalloc(sizeof(*dss), GFP_NOFS);
98 if (dss == NULL)
99 return ERR_PTR(-ENOMEM);
100
101 dss->rpc_clnt = rpc_clone_client_set_auth(ds_clp->cl_rpcclient, flavor);
102 if (IS_ERR(dss->rpc_clnt)) {
103 int err = PTR_ERR(dss->rpc_clnt);
104 kfree (dss);
105 return ERR_PTR(err);
106 }
107 INIT_LIST_HEAD(&dss->list);
108
109 return dss;
110}
111
112static void
113nfs4_free_ds_server(struct nfs4_ds_server *dss)
114{
115 rpc_release_client(dss->rpc_clnt);
116 kfree(dss);
117}
118
119/**
120* Find or create a DS rpc client with th MDS server rpc client auth flavor
121* in the nfs_client cl_ds_clients list.
122*/
123struct rpc_clnt *
124nfs4_find_or_create_ds_client(struct nfs_client *ds_clp, struct inode *inode)
125{
126 struct nfs4_ds_server *dss, *new;
127 rpc_authflavor_t flavor = NFS_SERVER(inode)->client->cl_auth->au_flavor;
128
129 dss = nfs4_find_ds_client(ds_clp, flavor);
130 if (dss != NULL)
131 goto out;
132 new = nfs4_alloc_ds_server(ds_clp, flavor);
133 if (IS_ERR(new))
134 return ERR_CAST(new);
135 dss = nfs4_add_ds_client(ds_clp, flavor, new);
136 if (dss != new)
137 nfs4_free_ds_server(new);
138out:
139 return dss->rpc_clnt;
140}
141EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client);
142
143static void
144nfs4_shutdown_ds_clients(struct nfs_client *clp)
145{
146 struct nfs4_ds_server *dss;
147 LIST_HEAD(shutdown_list);
148
149 while (!list_empty(&clp->cl_ds_clients)) {
150 dss = list_entry(clp->cl_ds_clients.next,
151 struct nfs4_ds_server, list);
152 list_del(&dss->list);
153 rpc_shutdown_client(dss->rpc_clnt);
154 kfree (dss);
155 }
156}
157
158void nfs41_shutdown_client(struct nfs_client *clp)
45{ 159{
46 if (nfs4_has_session(clp)) { 160 if (nfs4_has_session(clp)) {
161 nfs4_shutdown_ds_clients(clp);
47 nfs4_destroy_session(clp->cl_session); 162 nfs4_destroy_session(clp->cl_session);
48 nfs4_destroy_clientid(clp); 163 nfs4_destroy_clientid(clp);
49 } 164 }
50 165
51} 166}
52#else /* CONFIG_NFS_V4_1 */ 167#endif /* CONFIG_NFS_V4_1 */
53static void nfs4_shutdown_session(struct nfs_client *clp) 168
169void nfs40_shutdown_client(struct nfs_client *clp)
54{ 170{
171 if (clp->cl_slot_tbl) {
172 nfs4_release_slot_table(clp->cl_slot_tbl);
173 kfree(clp->cl_slot_tbl);
174 }
55} 175}
56#endif /* CONFIG_NFS_V4_1 */
57 176
58struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) 177struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
59{ 178{
@@ -73,6 +192,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
73 192
74 spin_lock_init(&clp->cl_lock); 193 spin_lock_init(&clp->cl_lock);
75 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); 194 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
195 INIT_LIST_HEAD(&clp->cl_ds_clients);
76 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); 196 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
77 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; 197 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
78 clp->cl_minorversion = cl_init->minorversion; 198 clp->cl_minorversion = cl_init->minorversion;
@@ -97,7 +217,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
97{ 217{
98 if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) 218 if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
99 nfs4_kill_renewd(clp); 219 nfs4_kill_renewd(clp);
100 nfs4_shutdown_session(clp); 220 clp->cl_mvops->shutdown_client(clp);
101 nfs4_destroy_callback(clp); 221 nfs4_destroy_callback(clp);
102 if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) 222 if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
103 nfs_idmap_delete(clp); 223 nfs_idmap_delete(clp);
@@ -144,34 +264,77 @@ static int nfs4_init_callback(struct nfs_client *clp)
144 return 0; 264 return 0;
145} 265}
146 266
267/**
268 * nfs40_init_client - nfs_client initialization tasks for NFSv4.0
269 * @clp - nfs_client to initialize
270 *
271 * Returns zero on success, or a negative errno if some error occurred.
272 */
273int nfs40_init_client(struct nfs_client *clp)
274{
275 struct nfs4_slot_table *tbl;
276 int ret;
277
278 tbl = kzalloc(sizeof(*tbl), GFP_NOFS);
279 if (tbl == NULL)
280 return -ENOMEM;
281
282 ret = nfs4_setup_slot_table(tbl, NFS4_MAX_SLOT_TABLE,
283 "NFSv4.0 transport Slot table");
284 if (ret) {
285 kfree(tbl);
286 return ret;
287 }
288
289 clp->cl_slot_tbl = tbl;
290 return 0;
291}
292
293#if defined(CONFIG_NFS_V4_1)
294
295/**
296 * nfs41_init_client - nfs_client initialization tasks for NFSv4.1+
297 * @clp - nfs_client to initialize
298 *
299 * Returns zero on success, or a negative errno if some error occurred.
300 */
301int nfs41_init_client(struct nfs_client *clp)
302{
303 struct nfs4_session *session = NULL;
304
305 /*
306 * Create the session and mark it expired.
307 * When a SEQUENCE operation encounters the expired session
308 * it will do session recovery to initialize it.
309 */
310 session = nfs4_alloc_session(clp);
311 if (!session)
312 return -ENOMEM;
313
314 clp->cl_session = session;
315
316 /*
317 * The create session reply races with the server back
318 * channel probe. Mark the client NFS_CS_SESSION_INITING
319 * so that the client back channel can find the
320 * nfs_client struct
321 */
322 nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
323 return 0;
324}
325
326#endif /* CONFIG_NFS_V4_1 */
327
147/* 328/*
148 * Initialize the minor version specific parts of an NFS4 client record 329 * Initialize the minor version specific parts of an NFS4 client record
149 */ 330 */
150static int nfs4_init_client_minor_version(struct nfs_client *clp) 331static int nfs4_init_client_minor_version(struct nfs_client *clp)
151{ 332{
152#if defined(CONFIG_NFS_V4_1) 333 int ret;
153 if (clp->cl_mvops->minor_version) {
154 struct nfs4_session *session = NULL;
155 /*
156 * Create the session and mark it expired.
157 * When a SEQUENCE operation encounters the expired session
158 * it will do session recovery to initialize it.
159 */
160 session = nfs4_alloc_session(clp);
161 if (!session)
162 return -ENOMEM;
163
164 clp->cl_session = session;
165 /*
166 * The create session reply races with the server back
167 * channel probe. Mark the client NFS_CS_SESSION_INITING
168 * so that the client back channel can find the
169 * nfs_client struct
170 */
171 nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
172 }
173#endif /* CONFIG_NFS_V4_1 */
174 334
335 ret = clp->cl_mvops->init_client(clp);
336 if (ret)
337 return ret;
175 return nfs4_init_callback(clp); 338 return nfs4_init_callback(clp);
176} 339}
177 340
@@ -187,8 +350,7 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp)
187 */ 350 */
188struct nfs_client *nfs4_init_client(struct nfs_client *clp, 351struct nfs_client *nfs4_init_client(struct nfs_client *clp,
189 const struct rpc_timeout *timeparms, 352 const struct rpc_timeout *timeparms,
190 const char *ip_addr, 353 const char *ip_addr)
191 rpc_authflavor_t authflavour)
192{ 354{
193 char buf[INET6_ADDRSTRLEN + 1]; 355 char buf[INET6_ADDRSTRLEN + 1];
194 struct nfs_client *old; 356 struct nfs_client *old;
@@ -723,7 +885,7 @@ static void nfs4_session_set_rwsize(struct nfs_server *server)
723} 885}
724 886
725static int nfs4_server_common_setup(struct nfs_server *server, 887static int nfs4_server_common_setup(struct nfs_server *server,
726 struct nfs_fh *mntfh) 888 struct nfs_fh *mntfh, bool auth_probe)
727{ 889{
728 struct nfs_fattr *fattr; 890 struct nfs_fattr *fattr;
729 int error; 891 int error;
@@ -755,7 +917,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
755 917
756 918
757 /* Probe the root fh to retrieve its FSID and filehandle */ 919 /* Probe the root fh to retrieve its FSID and filehandle */
758 error = nfs4_get_rootfh(server, mntfh); 920 error = nfs4_get_rootfh(server, mntfh, auth_probe);
759 if (error < 0) 921 if (error < 0)
760 goto out; 922 goto out;
761 923
@@ -787,6 +949,7 @@ out:
787static int nfs4_init_server(struct nfs_server *server, 949static int nfs4_init_server(struct nfs_server *server,
788 const struct nfs_parsed_mount_data *data) 950 const struct nfs_parsed_mount_data *data)
789{ 951{
952 rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
790 struct rpc_timeout timeparms; 953 struct rpc_timeout timeparms;
791 int error; 954 int error;
792 955
@@ -799,13 +962,16 @@ static int nfs4_init_server(struct nfs_server *server,
799 server->flags = data->flags; 962 server->flags = data->flags;
800 server->options = data->options; 963 server->options = data->options;
801 964
965 if (data->auth_flavor_len >= 1)
966 pseudoflavor = data->auth_flavors[0];
967
802 /* Get a client record */ 968 /* Get a client record */
803 error = nfs4_set_client(server, 969 error = nfs4_set_client(server,
804 data->nfs_server.hostname, 970 data->nfs_server.hostname,
805 (const struct sockaddr *)&data->nfs_server.address, 971 (const struct sockaddr *)&data->nfs_server.address,
806 data->nfs_server.addrlen, 972 data->nfs_server.addrlen,
807 data->client_address, 973 data->client_address,
808 data->auth_flavors[0], 974 pseudoflavor,
809 data->nfs_server.protocol, 975 data->nfs_server.protocol,
810 &timeparms, 976 &timeparms,
811 data->minorversion, 977 data->minorversion,
@@ -825,7 +991,7 @@ static int nfs4_init_server(struct nfs_server *server,
825 991
826 server->port = data->nfs_server.port; 992 server->port = data->nfs_server.port;
827 993
828 error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); 994 error = nfs_init_server_rpcclient(server, &timeparms, pseudoflavor);
829 995
830error: 996error:
831 /* Done */ 997 /* Done */
@@ -843,6 +1009,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
843 struct nfs_subversion *nfs_mod) 1009 struct nfs_subversion *nfs_mod)
844{ 1010{
845 struct nfs_server *server; 1011 struct nfs_server *server;
1012 bool auth_probe;
846 int error; 1013 int error;
847 1014
848 dprintk("--> nfs4_create_server()\n"); 1015 dprintk("--> nfs4_create_server()\n");
@@ -851,12 +1018,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
851 if (!server) 1018 if (!server)
852 return ERR_PTR(-ENOMEM); 1019 return ERR_PTR(-ENOMEM);
853 1020
1021 auth_probe = mount_info->parsed->auth_flavor_len < 1;
1022
854 /* set up the general RPC client */ 1023 /* set up the general RPC client */
855 error = nfs4_init_server(server, mount_info->parsed); 1024 error = nfs4_init_server(server, mount_info->parsed);
856 if (error < 0) 1025 if (error < 0)
857 goto error; 1026 goto error;
858 1027
859 error = nfs4_server_common_setup(server, mount_info->mntfh); 1028 error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
860 if (error < 0) 1029 if (error < 0)
861 goto error; 1030 goto error;
862 1031
@@ -909,7 +1078,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
909 if (error < 0) 1078 if (error < 0)
910 goto error; 1079 goto error;
911 1080
912 error = nfs4_server_common_setup(server, mntfh); 1081 error = nfs4_server_common_setup(server, mntfh,
1082 !(parent_server->flags & NFS_MOUNT_SECFLAVOUR));
913 if (error < 0) 1083 if (error < 0)
914 goto error; 1084 goto error;
915 1085