diff options
Diffstat (limited to 'fs/nfs/nfs4client.c')
-rw-r--r-- | fs/nfs/nfs4client.c | 240 |
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 |
44 | static void nfs4_shutdown_session(struct nfs_client *clp) | 44 | /** |
45 | * Per auth flavor data server rpc clients | ||
46 | */ | ||
47 | struct 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 | */ | ||
55 | static struct nfs4_ds_server * | ||
56 | nfs4_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; | ||
67 | out: | ||
68 | rcu_read_unlock(); | ||
69 | return dss; | ||
70 | } | ||
71 | |||
72 | static struct nfs4_ds_server * | ||
73 | nfs4_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; | ||
87 | out: | ||
88 | spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */ | ||
89 | return dss; | ||
90 | } | ||
91 | |||
92 | static struct nfs4_ds_server * | ||
93 | nfs4_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 | |||
112 | static void | ||
113 | nfs4_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 | */ | ||
123 | struct rpc_clnt * | ||
124 | nfs4_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); | ||
138 | out: | ||
139 | return dss->rpc_clnt; | ||
140 | } | ||
141 | EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client); | ||
142 | |||
143 | static void | ||
144 | nfs4_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 | |||
158 | void 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 */ |
53 | static void nfs4_shutdown_session(struct nfs_client *clp) | 168 | |
169 | void 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 | ||
58 | struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | 177 | struct 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 | */ | ||
273 | int 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 | */ | ||
301 | int 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 | */ |
150 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | 331 | static 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 | */ |
188 | struct nfs_client *nfs4_init_client(struct nfs_client *clp, | 351 | struct 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 | ||
725 | static int nfs4_server_common_setup(struct nfs_server *server, | 887 | static 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: | |||
787 | static int nfs4_init_server(struct nfs_server *server, | 949 | static 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 | ||
830 | error: | 996 | error: |
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 | ||