diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 458 |
1 files changed, 333 insertions, 125 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index e7340729af89..b3dc2b88b65b 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "iostat.h" | 48 | #include "iostat.h" |
49 | #include "internal.h" | 49 | #include "internal.h" |
50 | #include "fscache.h" | 50 | #include "fscache.h" |
51 | #include "pnfs.h" | ||
51 | 52 | ||
52 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 53 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
53 | 54 | ||
@@ -55,6 +56,35 @@ static DEFINE_SPINLOCK(nfs_client_lock); | |||
55 | static LIST_HEAD(nfs_client_list); | 56 | static LIST_HEAD(nfs_client_list); |
56 | static LIST_HEAD(nfs_volume_list); | 57 | static LIST_HEAD(nfs_volume_list); |
57 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 58 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); |
59 | #ifdef CONFIG_NFS_V4 | ||
60 | static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ | ||
61 | |||
62 | /* | ||
63 | * Get a unique NFSv4.0 callback identifier which will be used | ||
64 | * by the V4.0 callback service to lookup the nfs_client struct | ||
65 | */ | ||
66 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | ||
67 | { | ||
68 | int ret = 0; | ||
69 | |||
70 | if (clp->rpc_ops->version != 4 || minorversion != 0) | ||
71 | return ret; | ||
72 | retry: | ||
73 | if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL)) | ||
74 | return -ENOMEM; | ||
75 | spin_lock(&nfs_client_lock); | ||
76 | ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident); | ||
77 | spin_unlock(&nfs_client_lock); | ||
78 | if (ret == -EAGAIN) | ||
79 | goto retry; | ||
80 | return ret; | ||
81 | } | ||
82 | #endif /* CONFIG_NFS_V4 */ | ||
83 | |||
84 | /* | ||
85 | * Turn off NFSv4 uid/gid mapping when using AUTH_SYS | ||
86 | */ | ||
87 | static int nfs4_disable_idmapping = 0; | ||
58 | 88 | ||
59 | /* | 89 | /* |
60 | * RPC cruft for NFS | 90 | * RPC cruft for NFS |
@@ -143,7 +173,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
143 | clp->cl_proto = cl_init->proto; | 173 | clp->cl_proto = cl_init->proto; |
144 | 174 | ||
145 | #ifdef CONFIG_NFS_V4 | 175 | #ifdef CONFIG_NFS_V4 |
146 | INIT_LIST_HEAD(&clp->cl_delegations); | 176 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); |
177 | if (err) | ||
178 | goto error_cleanup; | ||
179 | |||
147 | spin_lock_init(&clp->cl_lock); | 180 | spin_lock_init(&clp->cl_lock); |
148 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | 181 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); |
149 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 182 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
@@ -155,7 +188,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
155 | cred = rpc_lookup_machine_cred(); | 188 | cred = rpc_lookup_machine_cred(); |
156 | if (!IS_ERR(cred)) | 189 | if (!IS_ERR(cred)) |
157 | clp->cl_machine_cred = cred; | 190 | clp->cl_machine_cred = cred; |
158 | 191 | #if defined(CONFIG_NFS_V4_1) | |
192 | INIT_LIST_HEAD(&clp->cl_layouts); | ||
193 | #endif | ||
159 | nfs_fscache_get_client_cookie(clp); | 194 | nfs_fscache_get_client_cookie(clp); |
160 | 195 | ||
161 | return clp; | 196 | return clp; |
@@ -167,21 +202,17 @@ error_0: | |||
167 | } | 202 | } |
168 | 203 | ||
169 | #ifdef CONFIG_NFS_V4 | 204 | #ifdef CONFIG_NFS_V4 |
170 | /* | ||
171 | * Clears/puts all minor version specific parts from an nfs_client struct | ||
172 | * reverting it to minorversion 0. | ||
173 | */ | ||
174 | static void nfs4_clear_client_minor_version(struct nfs_client *clp) | ||
175 | { | ||
176 | #ifdef CONFIG_NFS_V4_1 | 205 | #ifdef CONFIG_NFS_V4_1 |
177 | if (nfs4_has_session(clp)) { | 206 | static void nfs4_shutdown_session(struct nfs_client *clp) |
207 | { | ||
208 | if (nfs4_has_session(clp)) | ||
178 | nfs4_destroy_session(clp->cl_session); | 209 | nfs4_destroy_session(clp->cl_session); |
179 | clp->cl_session = NULL; | ||
180 | } | ||
181 | |||
182 | clp->cl_mvops = nfs_v4_minor_ops[0]; | ||
183 | #endif /* CONFIG_NFS_V4_1 */ | ||
184 | } | 210 | } |
211 | #else /* CONFIG_NFS_V4_1 */ | ||
212 | static void nfs4_shutdown_session(struct nfs_client *clp) | ||
213 | { | ||
214 | } | ||
215 | #endif /* CONFIG_NFS_V4_1 */ | ||
185 | 216 | ||
186 | /* | 217 | /* |
187 | * Destroy the NFS4 callback service | 218 | * Destroy the NFS4 callback service |
@@ -196,17 +227,49 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
196 | { | 227 | { |
197 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | 228 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) |
198 | nfs4_kill_renewd(clp); | 229 | nfs4_kill_renewd(clp); |
199 | nfs4_clear_client_minor_version(clp); | 230 | nfs4_shutdown_session(clp); |
200 | nfs4_destroy_callback(clp); | 231 | nfs4_destroy_callback(clp); |
201 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | 232 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) |
202 | nfs_idmap_delete(clp); | 233 | nfs_idmap_delete(clp); |
203 | 234 | ||
204 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | 235 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); |
205 | } | 236 | } |
237 | |||
238 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ | ||
239 | void nfs_cleanup_cb_ident_idr(void) | ||
240 | { | ||
241 | idr_destroy(&cb_ident_idr); | ||
242 | } | ||
243 | |||
244 | /* nfs_client_lock held */ | ||
245 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) | ||
246 | { | ||
247 | if (clp->cl_cb_ident) | ||
248 | idr_remove(&cb_ident_idr, clp->cl_cb_ident); | ||
249 | } | ||
250 | |||
251 | static void pnfs_init_server(struct nfs_server *server) | ||
252 | { | ||
253 | rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC"); | ||
254 | } | ||
255 | |||
206 | #else | 256 | #else |
207 | static void nfs4_shutdown_client(struct nfs_client *clp) | 257 | static void nfs4_shutdown_client(struct nfs_client *clp) |
208 | { | 258 | { |
209 | } | 259 | } |
260 | |||
261 | void nfs_cleanup_cb_ident_idr(void) | ||
262 | { | ||
263 | } | ||
264 | |||
265 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) | ||
266 | { | ||
267 | } | ||
268 | |||
269 | static void pnfs_init_server(struct nfs_server *server) | ||
270 | { | ||
271 | } | ||
272 | |||
210 | #endif /* CONFIG_NFS_V4 */ | 273 | #endif /* CONFIG_NFS_V4 */ |
211 | 274 | ||
212 | /* | 275 | /* |
@@ -227,6 +290,8 @@ static void nfs_free_client(struct nfs_client *clp) | |||
227 | if (clp->cl_machine_cred != NULL) | 290 | if (clp->cl_machine_cred != NULL) |
228 | put_rpccred(clp->cl_machine_cred); | 291 | put_rpccred(clp->cl_machine_cred); |
229 | 292 | ||
293 | nfs4_deviceid_purge_client(clp); | ||
294 | |||
230 | kfree(clp->cl_hostname); | 295 | kfree(clp->cl_hostname); |
231 | kfree(clp); | 296 | kfree(clp); |
232 | 297 | ||
@@ -245,6 +310,7 @@ void nfs_put_client(struct nfs_client *clp) | |||
245 | 310 | ||
246 | if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { | 311 | if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { |
247 | list_del(&clp->cl_share_link); | 312 | list_del(&clp->cl_share_link); |
313 | nfs_cb_idr_remove_locked(clp); | ||
248 | spin_unlock(&nfs_client_lock); | 314 | spin_unlock(&nfs_client_lock); |
249 | 315 | ||
250 | BUG_ON(!list_empty(&clp->cl_superblocks)); | 316 | BUG_ON(!list_empty(&clp->cl_superblocks)); |
@@ -252,6 +318,7 @@ void nfs_put_client(struct nfs_client *clp) | |||
252 | nfs_free_client(clp); | 318 | nfs_free_client(clp); |
253 | } | 319 | } |
254 | } | 320 | } |
321 | EXPORT_SYMBOL_GPL(nfs_put_client); | ||
255 | 322 | ||
256 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 323 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
257 | /* | 324 | /* |
@@ -359,70 +426,28 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | |||
359 | return 0; | 426 | return 0; |
360 | } | 427 | } |
361 | 428 | ||
362 | /* | 429 | /* Common match routine for v4.0 and v4.1 callback services */ |
363 | * Find a client by IP address and protocol version | 430 | bool |
364 | * - returns NULL if no such client | 431 | nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp, |
365 | */ | 432 | u32 minorversion) |
366 | struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | ||
367 | { | 433 | { |
368 | struct nfs_client *clp; | 434 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
369 | 435 | ||
370 | spin_lock(&nfs_client_lock); | 436 | /* Don't match clients that failed to initialise */ |
371 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 437 | if (!(clp->cl_cons_state == NFS_CS_READY || |
372 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 438 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) |
439 | return false; | ||
373 | 440 | ||
374 | /* Don't match clients that failed to initialise properly */ | 441 | /* Match the version and minorversion */ |
375 | if (!(clp->cl_cons_state == NFS_CS_READY || | 442 | if (clp->rpc_ops->version != 4 || |
376 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | 443 | clp->cl_minorversion != minorversion) |
377 | continue; | 444 | return false; |
378 | 445 | ||
379 | /* Different NFS versions cannot share the same nfs_client */ | 446 | /* Match only the IP address, not the port number */ |
380 | if (clp->rpc_ops->version != nfsversion) | 447 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) |
381 | continue; | 448 | return false; |
382 | |||
383 | /* Match only the IP address, not the port number */ | ||
384 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | ||
385 | continue; | ||
386 | 449 | ||
387 | atomic_inc(&clp->cl_count); | 450 | return true; |
388 | spin_unlock(&nfs_client_lock); | ||
389 | return clp; | ||
390 | } | ||
391 | spin_unlock(&nfs_client_lock); | ||
392 | return NULL; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Find a client by IP address and protocol version | ||
397 | * - returns NULL if no such client | ||
398 | */ | ||
399 | struct nfs_client *nfs_find_client_next(struct nfs_client *clp) | ||
400 | { | ||
401 | struct sockaddr *sap = (struct sockaddr *)&clp->cl_addr; | ||
402 | u32 nfsvers = clp->rpc_ops->version; | ||
403 | |||
404 | spin_lock(&nfs_client_lock); | ||
405 | list_for_each_entry_continue(clp, &nfs_client_list, cl_share_link) { | ||
406 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
407 | |||
408 | /* Don't match clients that failed to initialise properly */ | ||
409 | if (clp->cl_cons_state != NFS_CS_READY) | ||
410 | continue; | ||
411 | |||
412 | /* Different NFS versions cannot share the same nfs_client */ | ||
413 | if (clp->rpc_ops->version != nfsvers) | ||
414 | continue; | ||
415 | |||
416 | /* Match only the IP address, not the port number */ | ||
417 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) | ||
418 | continue; | ||
419 | |||
420 | atomic_inc(&clp->cl_count); | ||
421 | spin_unlock(&nfs_client_lock); | ||
422 | return clp; | ||
423 | } | ||
424 | spin_unlock(&nfs_client_lock); | ||
425 | return NULL; | ||
426 | } | 451 | } |
427 | 452 | ||
428 | /* | 453 | /* |
@@ -463,7 +488,12 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
463 | * Look up a client by IP address and protocol version | 488 | * Look up a client by IP address and protocol version |
464 | * - creates a new record if one doesn't yet exist | 489 | * - creates a new record if one doesn't yet exist |
465 | */ | 490 | */ |
466 | static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) | 491 | static struct nfs_client * |
492 | nfs_get_client(const struct nfs_client_initdata *cl_init, | ||
493 | const struct rpc_timeout *timeparms, | ||
494 | const char *ip_addr, | ||
495 | rpc_authflavor_t authflavour, | ||
496 | int noresvport) | ||
467 | { | 497 | { |
468 | struct nfs_client *clp, *new = NULL; | 498 | struct nfs_client *clp, *new = NULL; |
469 | int error; | 499 | int error; |
@@ -494,6 +524,13 @@ install_client: | |||
494 | clp = new; | 524 | clp = new; |
495 | list_add(&clp->cl_share_link, &nfs_client_list); | 525 | list_add(&clp->cl_share_link, &nfs_client_list); |
496 | spin_unlock(&nfs_client_lock); | 526 | spin_unlock(&nfs_client_lock); |
527 | |||
528 | error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, | ||
529 | authflavour, noresvport); | ||
530 | if (error < 0) { | ||
531 | nfs_put_client(clp); | ||
532 | return ERR_PTR(error); | ||
533 | } | ||
497 | dprintk("--> nfs_get_client() = %p [new]\n", clp); | 534 | dprintk("--> nfs_get_client() = %p [new]\n", clp); |
498 | return clp; | 535 | return clp; |
499 | 536 | ||
@@ -601,6 +638,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
601 | { | 638 | { |
602 | struct rpc_clnt *clnt = NULL; | 639 | struct rpc_clnt *clnt = NULL; |
603 | struct rpc_create_args args = { | 640 | struct rpc_create_args args = { |
641 | .net = &init_net, | ||
604 | .protocol = clp->cl_proto, | 642 | .protocol = clp->cl_proto, |
605 | .address = (struct sockaddr *)&clp->cl_addr, | 643 | .address = (struct sockaddr *)&clp->cl_addr, |
606 | .addrsize = clp->cl_addrlen, | 644 | .addrsize = clp->cl_addrlen, |
@@ -635,7 +673,8 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
635 | */ | 673 | */ |
636 | static void nfs_destroy_server(struct nfs_server *server) | 674 | static void nfs_destroy_server(struct nfs_server *server) |
637 | { | 675 | { |
638 | if (!(server->flags & NFS_MOUNT_NONLM)) | 676 | if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) || |
677 | !(server->flags & NFS_MOUNT_LOCAL_FCNTL)) | ||
639 | nlmclnt_done(server->nlm_host); | 678 | nlmclnt_done(server->nlm_host); |
640 | } | 679 | } |
641 | 680 | ||
@@ -657,7 +696,8 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
657 | 696 | ||
658 | if (nlm_init.nfs_version > 3) | 697 | if (nlm_init.nfs_version > 3) |
659 | return 0; | 698 | return 0; |
660 | if (server->flags & NFS_MOUNT_NONLM) | 699 | if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) && |
700 | (server->flags & NFS_MOUNT_LOCAL_FCNTL)) | ||
661 | return 0; | 701 | return 0; |
662 | 702 | ||
663 | switch (clp->cl_proto) { | 703 | switch (clp->cl_proto) { |
@@ -746,9 +786,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, | |||
746 | /* | 786 | /* |
747 | * Initialise an NFS2 or NFS3 client | 787 | * Initialise an NFS2 or NFS3 client |
748 | */ | 788 | */ |
749 | static int nfs_init_client(struct nfs_client *clp, | 789 | int nfs_init_client(struct nfs_client *clp, const struct rpc_timeout *timeparms, |
750 | const struct rpc_timeout *timeparms, | 790 | const char *ip_addr, rpc_authflavor_t authflavour, |
751 | const struct nfs_parsed_mount_data *data) | 791 | int noresvport) |
752 | { | 792 | { |
753 | int error; | 793 | int error; |
754 | 794 | ||
@@ -763,7 +803,7 @@ static int nfs_init_client(struct nfs_client *clp, | |||
763 | * - RFC 2623, sec 2.3.2 | 803 | * - RFC 2623, sec 2.3.2 |
764 | */ | 804 | */ |
765 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, | 805 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, |
766 | 0, data->flags & NFS_MOUNT_NORESVPORT); | 806 | 0, noresvport); |
767 | if (error < 0) | 807 | if (error < 0) |
768 | goto error; | 808 | goto error; |
769 | nfs_mark_client_ready(clp, NFS_CS_READY); | 809 | nfs_mark_client_ready(clp, NFS_CS_READY); |
@@ -799,19 +839,17 @@ static int nfs_init_server(struct nfs_server *server, | |||
799 | cl_init.rpc_ops = &nfs_v3_clientops; | 839 | cl_init.rpc_ops = &nfs_v3_clientops; |
800 | #endif | 840 | #endif |
801 | 841 | ||
842 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
843 | data->timeo, data->retrans); | ||
844 | |||
802 | /* Allocate or find a client reference we can use */ | 845 | /* Allocate or find a client reference we can use */ |
803 | clp = nfs_get_client(&cl_init); | 846 | clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX, |
847 | data->flags & NFS_MOUNT_NORESVPORT); | ||
804 | if (IS_ERR(clp)) { | 848 | if (IS_ERR(clp)) { |
805 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | 849 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); |
806 | return PTR_ERR(clp); | 850 | return PTR_ERR(clp); |
807 | } | 851 | } |
808 | 852 | ||
809 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
810 | data->timeo, data->retrans); | ||
811 | error = nfs_init_client(clp, &timeparms, data); | ||
812 | if (error < 0) | ||
813 | goto error; | ||
814 | |||
815 | server->nfs_client = clp; | 853 | server->nfs_client = clp; |
816 | 854 | ||
817 | /* Initialise the client representation from the mount data */ | 855 | /* Initialise the client representation from the mount data */ |
@@ -898,11 +936,13 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo * | |||
898 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) | 936 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) |
899 | server->wsize = NFS_MAX_FILE_IO_SIZE; | 937 | server->wsize = NFS_MAX_FILE_IO_SIZE; |
900 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 938 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
939 | set_pnfs_layoutdriver(server, fsinfo->layouttype); | ||
940 | |||
901 | server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); | 941 | server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); |
902 | 942 | ||
903 | server->dtsize = nfs_block_size(fsinfo->dtpref, NULL); | 943 | server->dtsize = nfs_block_size(fsinfo->dtpref, NULL); |
904 | if (server->dtsize > PAGE_CACHE_SIZE) | 944 | if (server->dtsize > PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES) |
905 | server->dtsize = PAGE_CACHE_SIZE; | 945 | server->dtsize = PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES; |
906 | if (server->dtsize > server->rsize) | 946 | if (server->dtsize > server->rsize) |
907 | server->dtsize = server->rsize; | 947 | server->dtsize = server->rsize; |
908 | 948 | ||
@@ -913,6 +953,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo * | |||
913 | 953 | ||
914 | server->maxfilesize = fsinfo->maxfilesize; | 954 | server->maxfilesize = fsinfo->maxfilesize; |
915 | 955 | ||
956 | server->time_delta = fsinfo->time_delta; | ||
957 | |||
916 | /* We're airborne Set socket buffersize */ | 958 | /* We're airborne Set socket buffersize */ |
917 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); | 959 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); |
918 | } | 960 | } |
@@ -935,6 +977,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str | |||
935 | } | 977 | } |
936 | 978 | ||
937 | fsinfo.fattr = fattr; | 979 | fsinfo.fattr = fattr; |
980 | fsinfo.layouttype = 0; | ||
938 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); | 981 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); |
939 | if (error < 0) | 982 | if (error < 0) |
940 | goto out_error; | 983 | goto out_error; |
@@ -976,6 +1019,32 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve | |||
976 | target->options = source->options; | 1019 | target->options = source->options; |
977 | } | 1020 | } |
978 | 1021 | ||
1022 | static void nfs_server_insert_lists(struct nfs_server *server) | ||
1023 | { | ||
1024 | struct nfs_client *clp = server->nfs_client; | ||
1025 | |||
1026 | spin_lock(&nfs_client_lock); | ||
1027 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); | ||
1028 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1029 | clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); | ||
1030 | spin_unlock(&nfs_client_lock); | ||
1031 | |||
1032 | } | ||
1033 | |||
1034 | static void nfs_server_remove_lists(struct nfs_server *server) | ||
1035 | { | ||
1036 | struct nfs_client *clp = server->nfs_client; | ||
1037 | |||
1038 | spin_lock(&nfs_client_lock); | ||
1039 | list_del_rcu(&server->client_link); | ||
1040 | if (clp && list_empty(&clp->cl_superblocks)) | ||
1041 | set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); | ||
1042 | list_del(&server->master_link); | ||
1043 | spin_unlock(&nfs_client_lock); | ||
1044 | |||
1045 | synchronize_rcu(); | ||
1046 | } | ||
1047 | |||
979 | /* | 1048 | /* |
980 | * Allocate and initialise a server record | 1049 | * Allocate and initialise a server record |
981 | */ | 1050 | */ |
@@ -992,6 +1061,7 @@ static struct nfs_server *nfs_alloc_server(void) | |||
992 | /* Zero out the NFS state stuff */ | 1061 | /* Zero out the NFS state stuff */ |
993 | INIT_LIST_HEAD(&server->client_link); | 1062 | INIT_LIST_HEAD(&server->client_link); |
994 | INIT_LIST_HEAD(&server->master_link); | 1063 | INIT_LIST_HEAD(&server->master_link); |
1064 | INIT_LIST_HEAD(&server->delegations); | ||
995 | 1065 | ||
996 | atomic_set(&server->active, 0); | 1066 | atomic_set(&server->active, 0); |
997 | 1067 | ||
@@ -1007,6 +1077,8 @@ static struct nfs_server *nfs_alloc_server(void) | |||
1007 | return NULL; | 1077 | return NULL; |
1008 | } | 1078 | } |
1009 | 1079 | ||
1080 | pnfs_init_server(server); | ||
1081 | |||
1010 | return server; | 1082 | return server; |
1011 | } | 1083 | } |
1012 | 1084 | ||
@@ -1017,10 +1089,8 @@ void nfs_free_server(struct nfs_server *server) | |||
1017 | { | 1089 | { |
1018 | dprintk("--> nfs_free_server()\n"); | 1090 | dprintk("--> nfs_free_server()\n"); |
1019 | 1091 | ||
1020 | spin_lock(&nfs_client_lock); | 1092 | nfs_server_remove_lists(server); |
1021 | list_del(&server->client_link); | 1093 | unset_pnfs_layoutdriver(server); |
1022 | list_del(&server->master_link); | ||
1023 | spin_unlock(&nfs_client_lock); | ||
1024 | 1094 | ||
1025 | if (server->destroy != NULL) | 1095 | if (server->destroy != NULL) |
1026 | server->destroy(server); | 1096 | server->destroy(server); |
@@ -1095,11 +1165,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
1095 | (unsigned long long) server->fsid.major, | 1165 | (unsigned long long) server->fsid.major, |
1096 | (unsigned long long) server->fsid.minor); | 1166 | (unsigned long long) server->fsid.minor); |
1097 | 1167 | ||
1098 | spin_lock(&nfs_client_lock); | 1168 | nfs_server_insert_lists(server); |
1099 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1100 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1101 | spin_unlock(&nfs_client_lock); | ||
1102 | |||
1103 | server->mount_time = jiffies; | 1169 | server->mount_time = jiffies; |
1104 | nfs_free_fattr(fattr); | 1170 | nfs_free_fattr(fattr); |
1105 | return server; | 1171 | return server; |
@@ -1112,6 +1178,96 @@ error: | |||
1112 | 1178 | ||
1113 | #ifdef CONFIG_NFS_V4 | 1179 | #ifdef CONFIG_NFS_V4 |
1114 | /* | 1180 | /* |
1181 | * NFSv4.0 callback thread helper | ||
1182 | * | ||
1183 | * Find a client by IP address, protocol version, and minorversion | ||
1184 | * | ||
1185 | * Called from the pg_authenticate method. The callback identifier | ||
1186 | * is not used as it has not been decoded. | ||
1187 | * | ||
1188 | * Returns NULL if no such client | ||
1189 | */ | ||
1190 | struct nfs_client * | ||
1191 | nfs4_find_client_no_ident(const struct sockaddr *addr) | ||
1192 | { | ||
1193 | struct nfs_client *clp; | ||
1194 | |||
1195 | spin_lock(&nfs_client_lock); | ||
1196 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
1197 | if (nfs4_cb_match_client(addr, clp, 0) == false) | ||
1198 | continue; | ||
1199 | atomic_inc(&clp->cl_count); | ||
1200 | spin_unlock(&nfs_client_lock); | ||
1201 | return clp; | ||
1202 | } | ||
1203 | spin_unlock(&nfs_client_lock); | ||
1204 | return NULL; | ||
1205 | } | ||
1206 | |||
1207 | /* | ||
1208 | * NFSv4.0 callback thread helper | ||
1209 | * | ||
1210 | * Find a client by callback identifier | ||
1211 | */ | ||
1212 | struct nfs_client * | ||
1213 | nfs4_find_client_ident(int cb_ident) | ||
1214 | { | ||
1215 | struct nfs_client *clp; | ||
1216 | |||
1217 | spin_lock(&nfs_client_lock); | ||
1218 | clp = idr_find(&cb_ident_idr, cb_ident); | ||
1219 | if (clp) | ||
1220 | atomic_inc(&clp->cl_count); | ||
1221 | spin_unlock(&nfs_client_lock); | ||
1222 | return clp; | ||
1223 | } | ||
1224 | |||
1225 | #if defined(CONFIG_NFS_V4_1) | ||
1226 | /* | ||
1227 | * NFSv4.1 callback thread helper | ||
1228 | * For CB_COMPOUND calls, find a client by IP address, protocol version, | ||
1229 | * minorversion, and sessionID | ||
1230 | * | ||
1231 | * Returns NULL if no such client | ||
1232 | */ | ||
1233 | struct nfs_client * | ||
1234 | nfs4_find_client_sessionid(const struct sockaddr *addr, | ||
1235 | struct nfs4_sessionid *sid) | ||
1236 | { | ||
1237 | struct nfs_client *clp; | ||
1238 | |||
1239 | spin_lock(&nfs_client_lock); | ||
1240 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
1241 | if (nfs4_cb_match_client(addr, clp, 1) == false) | ||
1242 | continue; | ||
1243 | |||
1244 | if (!nfs4_has_session(clp)) | ||
1245 | continue; | ||
1246 | |||
1247 | /* Match sessionid*/ | ||
1248 | if (memcmp(clp->cl_session->sess_id.data, | ||
1249 | sid->data, NFS4_MAX_SESSIONID_LEN) != 0) | ||
1250 | continue; | ||
1251 | |||
1252 | atomic_inc(&clp->cl_count); | ||
1253 | spin_unlock(&nfs_client_lock); | ||
1254 | return clp; | ||
1255 | } | ||
1256 | spin_unlock(&nfs_client_lock); | ||
1257 | return NULL; | ||
1258 | } | ||
1259 | |||
1260 | #else /* CONFIG_NFS_V4_1 */ | ||
1261 | |||
1262 | struct nfs_client * | ||
1263 | nfs4_find_client_sessionid(const struct sockaddr *addr, | ||
1264 | struct nfs4_sessionid *sid) | ||
1265 | { | ||
1266 | return NULL; | ||
1267 | } | ||
1268 | #endif /* CONFIG_NFS_V4_1 */ | ||
1269 | |||
1270 | /* | ||
1115 | * Initialize the NFS4 callback service | 1271 | * Initialize the NFS4 callback service |
1116 | */ | 1272 | */ |
1117 | static int nfs4_init_callback(struct nfs_client *clp) | 1273 | static int nfs4_init_callback(struct nfs_client *clp) |
@@ -1173,11 +1329,11 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) | |||
1173 | /* | 1329 | /* |
1174 | * Initialise an NFS4 client record | 1330 | * Initialise an NFS4 client record |
1175 | */ | 1331 | */ |
1176 | static int nfs4_init_client(struct nfs_client *clp, | 1332 | int nfs4_init_client(struct nfs_client *clp, |
1177 | const struct rpc_timeout *timeparms, | 1333 | const struct rpc_timeout *timeparms, |
1178 | const char *ip_addr, | 1334 | const char *ip_addr, |
1179 | rpc_authflavor_t authflavour, | 1335 | rpc_authflavor_t authflavour, |
1180 | int flags) | 1336 | int noresvport) |
1181 | { | 1337 | { |
1182 | int error; | 1338 | int error; |
1183 | 1339 | ||
@@ -1191,7 +1347,7 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
1191 | clp->rpc_ops = &nfs_v4_clientops; | 1347 | clp->rpc_ops = &nfs_v4_clientops; |
1192 | 1348 | ||
1193 | error = nfs_create_rpc_client(clp, timeparms, authflavour, | 1349 | error = nfs_create_rpc_client(clp, timeparms, authflavour, |
1194 | 1, flags & NFS_MOUNT_NORESVPORT); | 1350 | 1, noresvport); |
1195 | if (error < 0) | 1351 | if (error < 0) |
1196 | goto error; | 1352 | goto error; |
1197 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | 1353 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); |
@@ -1244,27 +1400,71 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1244 | dprintk("--> nfs4_set_client()\n"); | 1400 | dprintk("--> nfs4_set_client()\n"); |
1245 | 1401 | ||
1246 | /* Allocate or find a client reference we can use */ | 1402 | /* Allocate or find a client reference we can use */ |
1247 | clp = nfs_get_client(&cl_init); | 1403 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour, |
1404 | server->flags & NFS_MOUNT_NORESVPORT); | ||
1248 | if (IS_ERR(clp)) { | 1405 | if (IS_ERR(clp)) { |
1249 | error = PTR_ERR(clp); | 1406 | error = PTR_ERR(clp); |
1250 | goto error; | 1407 | goto error; |
1251 | } | 1408 | } |
1252 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour, | 1409 | |
1253 | server->flags); | 1410 | /* |
1254 | if (error < 0) | 1411 | * Query for the lease time on clientid setup or renewal |
1255 | goto error_put; | 1412 | * |
1413 | * Note that this will be set on nfs_clients that were created | ||
1414 | * only for the DS role and did not set this bit, but now will | ||
1415 | * serve a dual role. | ||
1416 | */ | ||
1417 | set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state); | ||
1256 | 1418 | ||
1257 | server->nfs_client = clp; | 1419 | server->nfs_client = clp; |
1258 | dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); | 1420 | dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); |
1259 | return 0; | 1421 | return 0; |
1260 | |||
1261 | error_put: | ||
1262 | nfs_put_client(clp); | ||
1263 | error: | 1422 | error: |
1264 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); | 1423 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); |
1265 | return error; | 1424 | return error; |
1266 | } | 1425 | } |
1267 | 1426 | ||
1427 | /* | ||
1428 | * Set up a pNFS Data Server client. | ||
1429 | * | ||
1430 | * Return any existing nfs_client that matches server address,port,version | ||
1431 | * and minorversion. | ||
1432 | * | ||
1433 | * For a new nfs_client, use a soft mount (default), a low retrans and a | ||
1434 | * low timeout interval so that if a connection is lost, we retry through | ||
1435 | * the MDS. | ||
1436 | */ | ||
1437 | struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | ||
1438 | const struct sockaddr *ds_addr, | ||
1439 | int ds_addrlen, int ds_proto) | ||
1440 | { | ||
1441 | struct nfs_client_initdata cl_init = { | ||
1442 | .addr = ds_addr, | ||
1443 | .addrlen = ds_addrlen, | ||
1444 | .rpc_ops = &nfs_v4_clientops, | ||
1445 | .proto = ds_proto, | ||
1446 | .minorversion = mds_clp->cl_minorversion, | ||
1447 | }; | ||
1448 | struct rpc_timeout ds_timeout = { | ||
1449 | .to_initval = 15 * HZ, | ||
1450 | .to_maxval = 15 * HZ, | ||
1451 | .to_retries = 1, | ||
1452 | .to_exponential = 1, | ||
1453 | }; | ||
1454 | struct nfs_client *clp; | ||
1455 | |||
1456 | /* | ||
1457 | * Set an authflavor equual to the MDS value. Use the MDS nfs_client | ||
1458 | * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS | ||
1459 | * (section 13.1 RFC 5661). | ||
1460 | */ | ||
1461 | clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, | ||
1462 | mds_clp->cl_rpcclient->cl_auth->au_flavor, 0); | ||
1463 | |||
1464 | dprintk("<-- %s %p\n", __func__, clp); | ||
1465 | return clp; | ||
1466 | } | ||
1467 | EXPORT_SYMBOL(nfs4_set_ds_client); | ||
1268 | 1468 | ||
1269 | /* | 1469 | /* |
1270 | * Session has been established, and the client marked ready. | 1470 | * Session has been established, and the client marked ready. |
@@ -1301,6 +1501,10 @@ static int nfs4_server_common_setup(struct nfs_server *server, | |||
1301 | BUG_ON(!server->nfs_client->rpc_ops); | 1501 | BUG_ON(!server->nfs_client->rpc_ops); |
1302 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1502 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1303 | 1503 | ||
1504 | /* data servers support only a subset of NFSv4.1 */ | ||
1505 | if (is_ds_only_client(server->nfs_client)) | ||
1506 | return -EPROTONOSUPPORT; | ||
1507 | |||
1304 | fattr = nfs_alloc_fattr(); | 1508 | fattr = nfs_alloc_fattr(); |
1305 | if (fattr == NULL) | 1509 | if (fattr == NULL) |
1306 | return -ENOMEM; | 1510 | return -ENOMEM; |
@@ -1329,11 +1533,7 @@ static int nfs4_server_common_setup(struct nfs_server *server, | |||
1329 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | 1533 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) |
1330 | server->namelen = NFS4_MAXNAMLEN; | 1534 | server->namelen = NFS4_MAXNAMLEN; |
1331 | 1535 | ||
1332 | spin_lock(&nfs_client_lock); | 1536 | nfs_server_insert_lists(server); |
1333 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1334 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1335 | spin_unlock(&nfs_client_lock); | ||
1336 | |||
1337 | server->mount_time = jiffies; | 1537 | server->mount_time = jiffies; |
1338 | out: | 1538 | out: |
1339 | nfs_free_fattr(fattr); | 1539 | nfs_free_fattr(fattr); |
@@ -1356,8 +1556,9 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1356 | 1556 | ||
1357 | /* Initialise the client representation from the mount data */ | 1557 | /* Initialise the client representation from the mount data */ |
1358 | server->flags = data->flags; | 1558 | server->flags = data->flags; |
1359 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR| | 1559 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK; |
1360 | NFS_CAP_POSIX_LOCK; | 1560 | if (!(data->flags & NFS_MOUNT_NORDIRPLUS)) |
1561 | server->caps |= NFS_CAP_READDIRPLUS; | ||
1361 | server->options = data->options; | 1562 | server->options = data->options; |
1362 | 1563 | ||
1363 | /* Get a client record */ | 1564 | /* Get a client record */ |
@@ -1373,6 +1574,13 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1373 | if (error < 0) | 1574 | if (error < 0) |
1374 | goto error; | 1575 | goto error; |
1375 | 1576 | ||
1577 | /* | ||
1578 | * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower | ||
1579 | * authentication. | ||
1580 | */ | ||
1581 | if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX) | ||
1582 | server->caps |= NFS_CAP_UIDGID_NOMAP; | ||
1583 | |||
1376 | if (data->rsize) | 1584 | if (data->rsize) |
1377 | server->rsize = nfs_block_size(data->rsize, NULL); | 1585 | server->rsize = nfs_block_size(data->rsize, NULL); |
1378 | if (data->wsize) | 1586 | if (data->wsize) |
@@ -1537,11 +1745,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1537 | if (error < 0) | 1745 | if (error < 0) |
1538 | goto out_free_server; | 1746 | goto out_free_server; |
1539 | 1747 | ||
1540 | spin_lock(&nfs_client_lock); | 1748 | nfs_server_insert_lists(server); |
1541 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1542 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1543 | spin_unlock(&nfs_client_lock); | ||
1544 | |||
1545 | server->mount_time = jiffies; | 1749 | server->mount_time = jiffies; |
1546 | 1750 | ||
1547 | nfs_free_fattr(fattr_fsinfo); | 1751 | nfs_free_fattr(fattr_fsinfo); |
@@ -1794,3 +1998,7 @@ void nfs_fs_proc_exit(void) | |||
1794 | } | 1998 | } |
1795 | 1999 | ||
1796 | #endif /* CONFIG_PROC_FS */ | 2000 | #endif /* CONFIG_PROC_FS */ |
2001 | |||
2002 | module_param(nfs4_disable_idmapping, bool, 0644); | ||
2003 | MODULE_PARM_DESC(nfs4_disable_idmapping, | ||
2004 | "Turn off NFSv4 idmapping when using 'sec=sys'"); | ||