diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 246 |
1 files changed, 152 insertions, 94 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d4f772ebd1ef..4a108a0a2a60 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
41 | #include <linux/nfs_xdr.h> | 41 | #include <linux/nfs_xdr.h> |
42 | #include <linux/sunrpc/bc_xprt.h> | 42 | #include <linux/sunrpc/bc_xprt.h> |
43 | #include <linux/nsproxy.h> | ||
44 | #include <linux/pid_namespace.h> | ||
43 | 45 | ||
44 | #include <asm/system.h> | 46 | #include <asm/system.h> |
45 | 47 | ||
@@ -50,15 +52,12 @@ | |||
50 | #include "internal.h" | 52 | #include "internal.h" |
51 | #include "fscache.h" | 53 | #include "fscache.h" |
52 | #include "pnfs.h" | 54 | #include "pnfs.h" |
55 | #include "netns.h" | ||
53 | 56 | ||
54 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 57 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
55 | 58 | ||
56 | static DEFINE_SPINLOCK(nfs_client_lock); | ||
57 | static LIST_HEAD(nfs_client_list); | ||
58 | static LIST_HEAD(nfs_volume_list); | ||
59 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 59 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); |
60 | #ifdef CONFIG_NFS_V4 | 60 | #ifdef CONFIG_NFS_V4 |
61 | static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ | ||
62 | 61 | ||
63 | /* | 62 | /* |
64 | * Get a unique NFSv4.0 callback identifier which will be used | 63 | * Get a unique NFSv4.0 callback identifier which will be used |
@@ -67,15 +66,16 @@ static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ | |||
67 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | 66 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) |
68 | { | 67 | { |
69 | int ret = 0; | 68 | int ret = 0; |
69 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | ||
70 | 70 | ||
71 | if (clp->rpc_ops->version != 4 || minorversion != 0) | 71 | if (clp->rpc_ops->version != 4 || minorversion != 0) |
72 | return ret; | 72 | return ret; |
73 | retry: | 73 | retry: |
74 | if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL)) | 74 | if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) |
75 | return -ENOMEM; | 75 | return -ENOMEM; |
76 | spin_lock(&nfs_client_lock); | 76 | spin_lock(&nn->nfs_client_lock); |
77 | ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident); | 77 | ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); |
78 | spin_unlock(&nfs_client_lock); | 78 | spin_unlock(&nn->nfs_client_lock); |
79 | if (ret == -EAGAIN) | 79 | if (ret == -EAGAIN) |
80 | goto retry; | 80 | goto retry; |
81 | return ret; | 81 | return ret; |
@@ -90,7 +90,7 @@ static bool nfs4_disable_idmapping = true; | |||
90 | /* | 90 | /* |
91 | * RPC cruft for NFS | 91 | * RPC cruft for NFS |
92 | */ | 92 | */ |
93 | static struct rpc_version *nfs_version[5] = { | 93 | static const struct rpc_version *nfs_version[5] = { |
94 | [2] = &nfs_version2, | 94 | [2] = &nfs_version2, |
95 | #ifdef CONFIG_NFS_V3 | 95 | #ifdef CONFIG_NFS_V3 |
96 | [3] = &nfs_version3, | 96 | [3] = &nfs_version3, |
@@ -100,7 +100,7 @@ static struct rpc_version *nfs_version[5] = { | |||
100 | #endif | 100 | #endif |
101 | }; | 101 | }; |
102 | 102 | ||
103 | struct rpc_program nfs_program = { | 103 | const struct rpc_program nfs_program = { |
104 | .name = "nfs", | 104 | .name = "nfs", |
105 | .number = NFS_PROGRAM, | 105 | .number = NFS_PROGRAM, |
106 | .nrvers = ARRAY_SIZE(nfs_version), | 106 | .nrvers = ARRAY_SIZE(nfs_version), |
@@ -116,11 +116,11 @@ struct rpc_stat nfs_rpcstat = { | |||
116 | 116 | ||
117 | #ifdef CONFIG_NFS_V3_ACL | 117 | #ifdef CONFIG_NFS_V3_ACL |
118 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | 118 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; |
119 | static struct rpc_version * nfsacl_version[] = { | 119 | static const struct rpc_version *nfsacl_version[] = { |
120 | [3] = &nfsacl_version3, | 120 | [3] = &nfsacl_version3, |
121 | }; | 121 | }; |
122 | 122 | ||
123 | struct rpc_program nfsacl_program = { | 123 | const struct rpc_program nfsacl_program = { |
124 | .name = "nfsacl", | 124 | .name = "nfsacl", |
125 | .number = NFS_ACL_PROGRAM, | 125 | .number = NFS_ACL_PROGRAM, |
126 | .nrvers = ARRAY_SIZE(nfsacl_version), | 126 | .nrvers = ARRAY_SIZE(nfsacl_version), |
@@ -136,6 +136,7 @@ struct nfs_client_initdata { | |||
136 | const struct nfs_rpc_ops *rpc_ops; | 136 | const struct nfs_rpc_ops *rpc_ops; |
137 | int proto; | 137 | int proto; |
138 | u32 minorversion; | 138 | u32 minorversion; |
139 | struct net *net; | ||
139 | }; | 140 | }; |
140 | 141 | ||
141 | /* | 142 | /* |
@@ -172,6 +173,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
172 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 173 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
173 | 174 | ||
174 | clp->cl_proto = cl_init->proto; | 175 | clp->cl_proto = cl_init->proto; |
176 | clp->net = get_net(cl_init->net); | ||
175 | 177 | ||
176 | #ifdef CONFIG_NFS_V4 | 178 | #ifdef CONFIG_NFS_V4 |
177 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); | 179 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); |
@@ -203,8 +205,11 @@ error_0: | |||
203 | #ifdef CONFIG_NFS_V4_1 | 205 | #ifdef CONFIG_NFS_V4_1 |
204 | static void nfs4_shutdown_session(struct nfs_client *clp) | 206 | static void nfs4_shutdown_session(struct nfs_client *clp) |
205 | { | 207 | { |
206 | if (nfs4_has_session(clp)) | 208 | if (nfs4_has_session(clp)) { |
209 | nfs4_deviceid_purge_client(clp); | ||
207 | nfs4_destroy_session(clp->cl_session); | 210 | nfs4_destroy_session(clp->cl_session); |
211 | } | ||
212 | |||
208 | } | 213 | } |
209 | #else /* CONFIG_NFS_V4_1 */ | 214 | #else /* CONFIG_NFS_V4_1 */ |
210 | static void nfs4_shutdown_session(struct nfs_client *clp) | 215 | static void nfs4_shutdown_session(struct nfs_client *clp) |
@@ -234,16 +239,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
234 | } | 239 | } |
235 | 240 | ||
236 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ | 241 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ |
237 | void nfs_cleanup_cb_ident_idr(void) | 242 | void nfs_cleanup_cb_ident_idr(struct net *net) |
238 | { | 243 | { |
239 | idr_destroy(&cb_ident_idr); | 244 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
245 | |||
246 | idr_destroy(&nn->cb_ident_idr); | ||
240 | } | 247 | } |
241 | 248 | ||
242 | /* nfs_client_lock held */ | 249 | /* nfs_client_lock held */ |
243 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) | 250 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) |
244 | { | 251 | { |
252 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | ||
253 | |||
245 | if (clp->cl_cb_ident) | 254 | if (clp->cl_cb_ident) |
246 | idr_remove(&cb_ident_idr, clp->cl_cb_ident); | 255 | idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident); |
247 | } | 256 | } |
248 | 257 | ||
249 | static void pnfs_init_server(struct nfs_server *server) | 258 | static void pnfs_init_server(struct nfs_server *server) |
@@ -261,7 +270,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
261 | { | 270 | { |
262 | } | 271 | } |
263 | 272 | ||
264 | void nfs_cleanup_cb_ident_idr(void) | 273 | void nfs_cleanup_cb_ident_idr(struct net *net) |
265 | { | 274 | { |
266 | } | 275 | } |
267 | 276 | ||
@@ -293,10 +302,10 @@ static void nfs_free_client(struct nfs_client *clp) | |||
293 | if (clp->cl_machine_cred != NULL) | 302 | if (clp->cl_machine_cred != NULL) |
294 | put_rpccred(clp->cl_machine_cred); | 303 | put_rpccred(clp->cl_machine_cred); |
295 | 304 | ||
296 | nfs4_deviceid_purge_client(clp); | 305 | put_net(clp->net); |
297 | |||
298 | kfree(clp->cl_hostname); | 306 | kfree(clp->cl_hostname); |
299 | kfree(clp->server_scope); | 307 | kfree(clp->server_scope); |
308 | kfree(clp->impl_id); | ||
300 | kfree(clp); | 309 | kfree(clp); |
301 | 310 | ||
302 | dprintk("<-- nfs_free_client()\n"); | 311 | dprintk("<-- nfs_free_client()\n"); |
@@ -307,15 +316,18 @@ static void nfs_free_client(struct nfs_client *clp) | |||
307 | */ | 316 | */ |
308 | void nfs_put_client(struct nfs_client *clp) | 317 | void nfs_put_client(struct nfs_client *clp) |
309 | { | 318 | { |
319 | struct nfs_net *nn; | ||
320 | |||
310 | if (!clp) | 321 | if (!clp) |
311 | return; | 322 | return; |
312 | 323 | ||
313 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); | 324 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); |
325 | nn = net_generic(clp->net, nfs_net_id); | ||
314 | 326 | ||
315 | if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { | 327 | if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) { |
316 | list_del(&clp->cl_share_link); | 328 | list_del(&clp->cl_share_link); |
317 | nfs_cb_idr_remove_locked(clp); | 329 | nfs_cb_idr_remove_locked(clp); |
318 | spin_unlock(&nfs_client_lock); | 330 | spin_unlock(&nn->nfs_client_lock); |
319 | 331 | ||
320 | BUG_ON(!list_empty(&clp->cl_superblocks)); | 332 | BUG_ON(!list_empty(&clp->cl_superblocks)); |
321 | 333 | ||
@@ -393,6 +405,7 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, | |||
393 | (sin1->sin_port == sin2->sin_port); | 405 | (sin1->sin_port == sin2->sin_port); |
394 | } | 406 | } |
395 | 407 | ||
408 | #if defined(CONFIG_NFS_V4_1) | ||
396 | /* | 409 | /* |
397 | * Test if two socket addresses represent the same actual socket, | 410 | * Test if two socket addresses represent the same actual socket, |
398 | * by comparing (only) relevant fields, excluding the port number. | 411 | * by comparing (only) relevant fields, excluding the port number. |
@@ -411,6 +424,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
411 | } | 424 | } |
412 | return 0; | 425 | return 0; |
413 | } | 426 | } |
427 | #endif /* CONFIG_NFS_V4_1 */ | ||
414 | 428 | ||
415 | /* | 429 | /* |
416 | * Test if two socket addresses represent the same actual socket, | 430 | * Test if two socket addresses represent the same actual socket, |
@@ -431,10 +445,10 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | |||
431 | return 0; | 445 | return 0; |
432 | } | 446 | } |
433 | 447 | ||
448 | #if defined(CONFIG_NFS_V4_1) | ||
434 | /* Common match routine for v4.0 and v4.1 callback services */ | 449 | /* Common match routine for v4.0 and v4.1 callback services */ |
435 | bool | 450 | static bool nfs4_cb_match_client(const struct sockaddr *addr, |
436 | nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp, | 451 | struct nfs_client *clp, u32 minorversion) |
437 | u32 minorversion) | ||
438 | { | 452 | { |
439 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 453 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
440 | 454 | ||
@@ -454,6 +468,7 @@ nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp, | |||
454 | 468 | ||
455 | return true; | 469 | return true; |
456 | } | 470 | } |
471 | #endif /* CONFIG_NFS_V4_1 */ | ||
457 | 472 | ||
458 | /* | 473 | /* |
459 | * Find an nfs_client on the list that matches the initialisation data | 474 | * Find an nfs_client on the list that matches the initialisation data |
@@ -463,8 +478,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
463 | { | 478 | { |
464 | struct nfs_client *clp; | 479 | struct nfs_client *clp; |
465 | const struct sockaddr *sap = data->addr; | 480 | const struct sockaddr *sap = data->addr; |
481 | struct nfs_net *nn = net_generic(data->net, nfs_net_id); | ||
466 | 482 | ||
467 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 483 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
468 | const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 484 | const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
469 | /* Don't match clients that failed to initialise properly */ | 485 | /* Don't match clients that failed to initialise properly */ |
470 | if (clp->cl_cons_state < 0) | 486 | if (clp->cl_cons_state < 0) |
@@ -502,13 +518,14 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
502 | { | 518 | { |
503 | struct nfs_client *clp, *new = NULL; | 519 | struct nfs_client *clp, *new = NULL; |
504 | int error; | 520 | int error; |
521 | struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); | ||
505 | 522 | ||
506 | dprintk("--> nfs_get_client(%s,v%u)\n", | 523 | dprintk("--> nfs_get_client(%s,v%u)\n", |
507 | cl_init->hostname ?: "", cl_init->rpc_ops->version); | 524 | cl_init->hostname ?: "", cl_init->rpc_ops->version); |
508 | 525 | ||
509 | /* see if the client already exists */ | 526 | /* see if the client already exists */ |
510 | do { | 527 | do { |
511 | spin_lock(&nfs_client_lock); | 528 | spin_lock(&nn->nfs_client_lock); |
512 | 529 | ||
513 | clp = nfs_match_client(cl_init); | 530 | clp = nfs_match_client(cl_init); |
514 | if (clp) | 531 | if (clp) |
@@ -516,7 +533,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
516 | if (new) | 533 | if (new) |
517 | goto install_client; | 534 | goto install_client; |
518 | 535 | ||
519 | spin_unlock(&nfs_client_lock); | 536 | spin_unlock(&nn->nfs_client_lock); |
520 | 537 | ||
521 | new = nfs_alloc_client(cl_init); | 538 | new = nfs_alloc_client(cl_init); |
522 | } while (!IS_ERR(new)); | 539 | } while (!IS_ERR(new)); |
@@ -527,8 +544,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
527 | /* install a new client and return with it unready */ | 544 | /* install a new client and return with it unready */ |
528 | install_client: | 545 | install_client: |
529 | clp = new; | 546 | clp = new; |
530 | list_add(&clp->cl_share_link, &nfs_client_list); | 547 | list_add(&clp->cl_share_link, &nn->nfs_client_list); |
531 | spin_unlock(&nfs_client_lock); | 548 | spin_unlock(&nn->nfs_client_lock); |
532 | 549 | ||
533 | error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, | 550 | error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, |
534 | authflavour, noresvport); | 551 | authflavour, noresvport); |
@@ -543,7 +560,7 @@ install_client: | |||
543 | * - make sure it's ready before returning | 560 | * - make sure it's ready before returning |
544 | */ | 561 | */ |
545 | found_client: | 562 | found_client: |
546 | spin_unlock(&nfs_client_lock); | 563 | spin_unlock(&nn->nfs_client_lock); |
547 | 564 | ||
548 | if (new) | 565 | if (new) |
549 | nfs_free_client(new); | 566 | nfs_free_client(new); |
@@ -643,7 +660,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
643 | { | 660 | { |
644 | struct rpc_clnt *clnt = NULL; | 661 | struct rpc_clnt *clnt = NULL; |
645 | struct rpc_create_args args = { | 662 | struct rpc_create_args args = { |
646 | .net = &init_net, | 663 | .net = clp->net, |
647 | .protocol = clp->cl_proto, | 664 | .protocol = clp->cl_proto, |
648 | .address = (struct sockaddr *)&clp->cl_addr, | 665 | .address = (struct sockaddr *)&clp->cl_addr, |
649 | .addrsize = clp->cl_addrlen, | 666 | .addrsize = clp->cl_addrlen, |
@@ -697,6 +714,7 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
697 | .nfs_version = clp->rpc_ops->version, | 714 | .nfs_version = clp->rpc_ops->version, |
698 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? | 715 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? |
699 | 1 : 0, | 716 | 1 : 0, |
717 | .net = clp->net, | ||
700 | }; | 718 | }; |
701 | 719 | ||
702 | if (nlm_init.nfs_version > 3) | 720 | if (nlm_init.nfs_version > 3) |
@@ -832,6 +850,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
832 | .addrlen = data->nfs_server.addrlen, | 850 | .addrlen = data->nfs_server.addrlen, |
833 | .rpc_ops = &nfs_v2_clientops, | 851 | .rpc_ops = &nfs_v2_clientops, |
834 | .proto = data->nfs_server.protocol, | 852 | .proto = data->nfs_server.protocol, |
853 | .net = data->net, | ||
835 | }; | 854 | }; |
836 | struct rpc_timeout timeparms; | 855 | struct rpc_timeout timeparms; |
837 | struct nfs_client *clp; | 856 | struct nfs_client *clp; |
@@ -1030,25 +1049,30 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve | |||
1030 | static void nfs_server_insert_lists(struct nfs_server *server) | 1049 | static void nfs_server_insert_lists(struct nfs_server *server) |
1031 | { | 1050 | { |
1032 | struct nfs_client *clp = server->nfs_client; | 1051 | struct nfs_client *clp = server->nfs_client; |
1052 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | ||
1033 | 1053 | ||
1034 | spin_lock(&nfs_client_lock); | 1054 | spin_lock(&nn->nfs_client_lock); |
1035 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); | 1055 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); |
1036 | list_add_tail(&server->master_link, &nfs_volume_list); | 1056 | list_add_tail(&server->master_link, &nn->nfs_volume_list); |
1037 | clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); | 1057 | clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); |
1038 | spin_unlock(&nfs_client_lock); | 1058 | spin_unlock(&nn->nfs_client_lock); |
1039 | 1059 | ||
1040 | } | 1060 | } |
1041 | 1061 | ||
1042 | static void nfs_server_remove_lists(struct nfs_server *server) | 1062 | static void nfs_server_remove_lists(struct nfs_server *server) |
1043 | { | 1063 | { |
1044 | struct nfs_client *clp = server->nfs_client; | 1064 | struct nfs_client *clp = server->nfs_client; |
1065 | struct nfs_net *nn; | ||
1045 | 1066 | ||
1046 | spin_lock(&nfs_client_lock); | 1067 | if (clp == NULL) |
1068 | return; | ||
1069 | nn = net_generic(clp->net, nfs_net_id); | ||
1070 | spin_lock(&nn->nfs_client_lock); | ||
1047 | list_del_rcu(&server->client_link); | 1071 | list_del_rcu(&server->client_link); |
1048 | if (clp && list_empty(&clp->cl_superblocks)) | 1072 | if (list_empty(&clp->cl_superblocks)) |
1049 | set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); | 1073 | set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); |
1050 | list_del(&server->master_link); | 1074 | list_del(&server->master_link); |
1051 | spin_unlock(&nfs_client_lock); | 1075 | spin_unlock(&nn->nfs_client_lock); |
1052 | 1076 | ||
1053 | synchronize_rcu(); | 1077 | synchronize_rcu(); |
1054 | } | 1078 | } |
@@ -1087,6 +1111,8 @@ static struct nfs_server *nfs_alloc_server(void) | |||
1087 | return NULL; | 1111 | return NULL; |
1088 | } | 1112 | } |
1089 | 1113 | ||
1114 | ida_init(&server->openowner_id); | ||
1115 | ida_init(&server->lockowner_id); | ||
1090 | pnfs_init_server(server); | 1116 | pnfs_init_server(server); |
1091 | 1117 | ||
1092 | return server; | 1118 | return server; |
@@ -1112,6 +1138,8 @@ void nfs_free_server(struct nfs_server *server) | |||
1112 | 1138 | ||
1113 | nfs_put_client(server->nfs_client); | 1139 | nfs_put_client(server->nfs_client); |
1114 | 1140 | ||
1141 | ida_destroy(&server->lockowner_id); | ||
1142 | ida_destroy(&server->openowner_id); | ||
1115 | nfs_free_iostats(server->io_stats); | 1143 | nfs_free_iostats(server->io_stats); |
1116 | bdi_destroy(&server->backing_dev_info); | 1144 | bdi_destroy(&server->backing_dev_info); |
1117 | kfree(server); | 1145 | kfree(server); |
@@ -1190,45 +1218,19 @@ error: | |||
1190 | /* | 1218 | /* |
1191 | * NFSv4.0 callback thread helper | 1219 | * NFSv4.0 callback thread helper |
1192 | * | 1220 | * |
1193 | * Find a client by IP address, protocol version, and minorversion | ||
1194 | * | ||
1195 | * Called from the pg_authenticate method. The callback identifier | ||
1196 | * is not used as it has not been decoded. | ||
1197 | * | ||
1198 | * Returns NULL if no such client | ||
1199 | */ | ||
1200 | struct nfs_client * | ||
1201 | nfs4_find_client_no_ident(const struct sockaddr *addr) | ||
1202 | { | ||
1203 | struct nfs_client *clp; | ||
1204 | |||
1205 | spin_lock(&nfs_client_lock); | ||
1206 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
1207 | if (nfs4_cb_match_client(addr, clp, 0) == false) | ||
1208 | continue; | ||
1209 | atomic_inc(&clp->cl_count); | ||
1210 | spin_unlock(&nfs_client_lock); | ||
1211 | return clp; | ||
1212 | } | ||
1213 | spin_unlock(&nfs_client_lock); | ||
1214 | return NULL; | ||
1215 | } | ||
1216 | |||
1217 | /* | ||
1218 | * NFSv4.0 callback thread helper | ||
1219 | * | ||
1220 | * Find a client by callback identifier | 1221 | * Find a client by callback identifier |
1221 | */ | 1222 | */ |
1222 | struct nfs_client * | 1223 | struct nfs_client * |
1223 | nfs4_find_client_ident(int cb_ident) | 1224 | nfs4_find_client_ident(struct net *net, int cb_ident) |
1224 | { | 1225 | { |
1225 | struct nfs_client *clp; | 1226 | struct nfs_client *clp; |
1227 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
1226 | 1228 | ||
1227 | spin_lock(&nfs_client_lock); | 1229 | spin_lock(&nn->nfs_client_lock); |
1228 | clp = idr_find(&cb_ident_idr, cb_ident); | 1230 | clp = idr_find(&nn->cb_ident_idr, cb_ident); |
1229 | if (clp) | 1231 | if (clp) |
1230 | atomic_inc(&clp->cl_count); | 1232 | atomic_inc(&clp->cl_count); |
1231 | spin_unlock(&nfs_client_lock); | 1233 | spin_unlock(&nn->nfs_client_lock); |
1232 | return clp; | 1234 | return clp; |
1233 | } | 1235 | } |
1234 | 1236 | ||
@@ -1241,13 +1243,14 @@ nfs4_find_client_ident(int cb_ident) | |||
1241 | * Returns NULL if no such client | 1243 | * Returns NULL if no such client |
1242 | */ | 1244 | */ |
1243 | struct nfs_client * | 1245 | struct nfs_client * |
1244 | nfs4_find_client_sessionid(const struct sockaddr *addr, | 1246 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, |
1245 | struct nfs4_sessionid *sid) | 1247 | struct nfs4_sessionid *sid) |
1246 | { | 1248 | { |
1247 | struct nfs_client *clp; | 1249 | struct nfs_client *clp; |
1250 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
1248 | 1251 | ||
1249 | spin_lock(&nfs_client_lock); | 1252 | spin_lock(&nn->nfs_client_lock); |
1250 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 1253 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
1251 | if (nfs4_cb_match_client(addr, clp, 1) == false) | 1254 | if (nfs4_cb_match_client(addr, clp, 1) == false) |
1252 | continue; | 1255 | continue; |
1253 | 1256 | ||
@@ -1260,17 +1263,17 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, | |||
1260 | continue; | 1263 | continue; |
1261 | 1264 | ||
1262 | atomic_inc(&clp->cl_count); | 1265 | atomic_inc(&clp->cl_count); |
1263 | spin_unlock(&nfs_client_lock); | 1266 | spin_unlock(&nn->nfs_client_lock); |
1264 | return clp; | 1267 | return clp; |
1265 | } | 1268 | } |
1266 | spin_unlock(&nfs_client_lock); | 1269 | spin_unlock(&nn->nfs_client_lock); |
1267 | return NULL; | 1270 | return NULL; |
1268 | } | 1271 | } |
1269 | 1272 | ||
1270 | #else /* CONFIG_NFS_V4_1 */ | 1273 | #else /* CONFIG_NFS_V4_1 */ |
1271 | 1274 | ||
1272 | struct nfs_client * | 1275 | struct nfs_client * |
1273 | nfs4_find_client_sessionid(const struct sockaddr *addr, | 1276 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, |
1274 | struct nfs4_sessionid *sid) | 1277 | struct nfs4_sessionid *sid) |
1275 | { | 1278 | { |
1276 | return NULL; | 1279 | return NULL; |
@@ -1285,16 +1288,18 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
1285 | int error; | 1288 | int error; |
1286 | 1289 | ||
1287 | if (clp->rpc_ops->version == 4) { | 1290 | if (clp->rpc_ops->version == 4) { |
1291 | struct rpc_xprt *xprt; | ||
1292 | |||
1293 | xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); | ||
1294 | |||
1288 | if (nfs4_has_session(clp)) { | 1295 | if (nfs4_has_session(clp)) { |
1289 | error = xprt_setup_backchannel( | 1296 | error = xprt_setup_backchannel(xprt, |
1290 | clp->cl_rpcclient->cl_xprt, | ||
1291 | NFS41_BC_MIN_CALLBACKS); | 1297 | NFS41_BC_MIN_CALLBACKS); |
1292 | if (error < 0) | 1298 | if (error < 0) |
1293 | return error; | 1299 | return error; |
1294 | } | 1300 | } |
1295 | 1301 | ||
1296 | error = nfs_callback_up(clp->cl_mvops->minor_version, | 1302 | error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); |
1297 | clp->cl_rpcclient->cl_xprt); | ||
1298 | if (error < 0) { | 1303 | if (error < 0) { |
1299 | dprintk("%s: failed to start callback. Error = %d\n", | 1304 | dprintk("%s: failed to start callback. Error = %d\n", |
1300 | __func__, error); | 1305 | __func__, error); |
@@ -1345,6 +1350,7 @@ int nfs4_init_client(struct nfs_client *clp, | |||
1345 | rpc_authflavor_t authflavour, | 1350 | rpc_authflavor_t authflavour, |
1346 | int noresvport) | 1351 | int noresvport) |
1347 | { | 1352 | { |
1353 | char buf[INET6_ADDRSTRLEN + 1]; | ||
1348 | int error; | 1354 | int error; |
1349 | 1355 | ||
1350 | if (clp->cl_cons_state == NFS_CS_READY) { | 1356 | if (clp->cl_cons_state == NFS_CS_READY) { |
@@ -1360,6 +1366,20 @@ int nfs4_init_client(struct nfs_client *clp, | |||
1360 | 1, noresvport); | 1366 | 1, noresvport); |
1361 | if (error < 0) | 1367 | if (error < 0) |
1362 | goto error; | 1368 | goto error; |
1369 | |||
1370 | /* If no clientaddr= option was specified, find a usable cb address */ | ||
1371 | if (ip_addr == NULL) { | ||
1372 | struct sockaddr_storage cb_addr; | ||
1373 | struct sockaddr *sap = (struct sockaddr *)&cb_addr; | ||
1374 | |||
1375 | error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); | ||
1376 | if (error < 0) | ||
1377 | goto error; | ||
1378 | error = rpc_ntop(sap, buf, sizeof(buf)); | ||
1379 | if (error < 0) | ||
1380 | goto error; | ||
1381 | ip_addr = (const char *)buf; | ||
1382 | } | ||
1363 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | 1383 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); |
1364 | 1384 | ||
1365 | error = nfs_idmap_new(clp); | 1385 | error = nfs_idmap_new(clp); |
@@ -1394,7 +1414,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1394 | const char *ip_addr, | 1414 | const char *ip_addr, |
1395 | rpc_authflavor_t authflavour, | 1415 | rpc_authflavor_t authflavour, |
1396 | int proto, const struct rpc_timeout *timeparms, | 1416 | int proto, const struct rpc_timeout *timeparms, |
1397 | u32 minorversion) | 1417 | u32 minorversion, struct net *net) |
1398 | { | 1418 | { |
1399 | struct nfs_client_initdata cl_init = { | 1419 | struct nfs_client_initdata cl_init = { |
1400 | .hostname = hostname, | 1420 | .hostname = hostname, |
@@ -1403,6 +1423,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1403 | .rpc_ops = &nfs_v4_clientops, | 1423 | .rpc_ops = &nfs_v4_clientops, |
1404 | .proto = proto, | 1424 | .proto = proto, |
1405 | .minorversion = minorversion, | 1425 | .minorversion = minorversion, |
1426 | .net = net, | ||
1406 | }; | 1427 | }; |
1407 | struct nfs_client *clp; | 1428 | struct nfs_client *clp; |
1408 | int error; | 1429 | int error; |
@@ -1454,6 +1475,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | |||
1454 | .rpc_ops = &nfs_v4_clientops, | 1475 | .rpc_ops = &nfs_v4_clientops, |
1455 | .proto = ds_proto, | 1476 | .proto = ds_proto, |
1456 | .minorversion = mds_clp->cl_minorversion, | 1477 | .minorversion = mds_clp->cl_minorversion, |
1478 | .net = mds_clp->net, | ||
1457 | }; | 1479 | }; |
1458 | struct rpc_timeout ds_timeout = { | 1480 | struct rpc_timeout ds_timeout = { |
1459 | .to_initval = 15 * HZ, | 1481 | .to_initval = 15 * HZ, |
@@ -1581,7 +1603,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1581 | data->auth_flavors[0], | 1603 | data->auth_flavors[0], |
1582 | data->nfs_server.protocol, | 1604 | data->nfs_server.protocol, |
1583 | &timeparms, | 1605 | &timeparms, |
1584 | data->minorversion); | 1606 | data->minorversion, |
1607 | data->net); | ||
1585 | if (error < 0) | 1608 | if (error < 0) |
1586 | goto error; | 1609 | goto error; |
1587 | 1610 | ||
@@ -1676,9 +1699,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1676 | data->addrlen, | 1699 | data->addrlen, |
1677 | parent_client->cl_ipaddr, | 1700 | parent_client->cl_ipaddr, |
1678 | data->authflavor, | 1701 | data->authflavor, |
1679 | parent_server->client->cl_xprt->prot, | 1702 | rpc_protocol(parent_server->client), |
1680 | parent_server->client->cl_timeout, | 1703 | parent_server->client->cl_timeout, |
1681 | parent_client->cl_mvops->minor_version); | 1704 | parent_client->cl_mvops->minor_version, |
1705 | parent_client->net); | ||
1682 | if (error < 0) | 1706 | if (error < 0) |
1683 | goto error; | 1707 | goto error; |
1684 | 1708 | ||
@@ -1771,6 +1795,18 @@ out_free_server: | |||
1771 | return ERR_PTR(error); | 1795 | return ERR_PTR(error); |
1772 | } | 1796 | } |
1773 | 1797 | ||
1798 | void nfs_clients_init(struct net *net) | ||
1799 | { | ||
1800 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
1801 | |||
1802 | INIT_LIST_HEAD(&nn->nfs_client_list); | ||
1803 | INIT_LIST_HEAD(&nn->nfs_volume_list); | ||
1804 | #ifdef CONFIG_NFS_V4 | ||
1805 | idr_init(&nn->cb_ident_idr); | ||
1806 | #endif | ||
1807 | spin_lock_init(&nn->nfs_client_lock); | ||
1808 | } | ||
1809 | |||
1774 | #ifdef CONFIG_PROC_FS | 1810 | #ifdef CONFIG_PROC_FS |
1775 | static struct proc_dir_entry *proc_fs_nfs; | 1811 | static struct proc_dir_entry *proc_fs_nfs; |
1776 | 1812 | ||
@@ -1824,13 +1860,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) | |||
1824 | { | 1860 | { |
1825 | struct seq_file *m; | 1861 | struct seq_file *m; |
1826 | int ret; | 1862 | int ret; |
1863 | struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; | ||
1864 | struct net *net = pid_ns->child_reaper->nsproxy->net_ns; | ||
1827 | 1865 | ||
1828 | ret = seq_open(file, &nfs_server_list_ops); | 1866 | ret = seq_open(file, &nfs_server_list_ops); |
1829 | if (ret < 0) | 1867 | if (ret < 0) |
1830 | return ret; | 1868 | return ret; |
1831 | 1869 | ||
1832 | m = file->private_data; | 1870 | m = file->private_data; |
1833 | m->private = PDE(inode)->data; | 1871 | m->private = net; |
1834 | 1872 | ||
1835 | return 0; | 1873 | return 0; |
1836 | } | 1874 | } |
@@ -1840,9 +1878,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) | |||
1840 | */ | 1878 | */ |
1841 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | 1879 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) |
1842 | { | 1880 | { |
1881 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
1882 | |||
1843 | /* lock the list against modification */ | 1883 | /* lock the list against modification */ |
1844 | spin_lock(&nfs_client_lock); | 1884 | spin_lock(&nn->nfs_client_lock); |
1845 | return seq_list_start_head(&nfs_client_list, *_pos); | 1885 | return seq_list_start_head(&nn->nfs_client_list, *_pos); |
1846 | } | 1886 | } |
1847 | 1887 | ||
1848 | /* | 1888 | /* |
@@ -1850,7 +1890,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | |||
1850 | */ | 1890 | */ |
1851 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | 1891 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) |
1852 | { | 1892 | { |
1853 | return seq_list_next(v, &nfs_client_list, pos); | 1893 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
1894 | |||
1895 | return seq_list_next(v, &nn->nfs_client_list, pos); | ||
1854 | } | 1896 | } |
1855 | 1897 | ||
1856 | /* | 1898 | /* |
@@ -1858,7 +1900,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | |||
1858 | */ | 1900 | */ |
1859 | static void nfs_server_list_stop(struct seq_file *p, void *v) | 1901 | static void nfs_server_list_stop(struct seq_file *p, void *v) |
1860 | { | 1902 | { |
1861 | spin_unlock(&nfs_client_lock); | 1903 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
1904 | |||
1905 | spin_unlock(&nn->nfs_client_lock); | ||
1862 | } | 1906 | } |
1863 | 1907 | ||
1864 | /* | 1908 | /* |
@@ -1867,9 +1911,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v) | |||
1867 | static int nfs_server_list_show(struct seq_file *m, void *v) | 1911 | static int nfs_server_list_show(struct seq_file *m, void *v) |
1868 | { | 1912 | { |
1869 | struct nfs_client *clp; | 1913 | struct nfs_client *clp; |
1914 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
1870 | 1915 | ||
1871 | /* display header on line 1 */ | 1916 | /* display header on line 1 */ |
1872 | if (v == &nfs_client_list) { | 1917 | if (v == &nn->nfs_client_list) { |
1873 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); | 1918 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); |
1874 | return 0; | 1919 | return 0; |
1875 | } | 1920 | } |
@@ -1881,12 +1926,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v) | |||
1881 | if (clp->cl_cons_state != NFS_CS_READY) | 1926 | if (clp->cl_cons_state != NFS_CS_READY) |
1882 | return 0; | 1927 | return 0; |
1883 | 1928 | ||
1929 | rcu_read_lock(); | ||
1884 | seq_printf(m, "v%u %s %s %3d %s\n", | 1930 | seq_printf(m, "v%u %s %s %3d %s\n", |
1885 | clp->rpc_ops->version, | 1931 | clp->rpc_ops->version, |
1886 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 1932 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1887 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), | 1933 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1888 | atomic_read(&clp->cl_count), | 1934 | atomic_read(&clp->cl_count), |
1889 | clp->cl_hostname); | 1935 | clp->cl_hostname); |
1936 | rcu_read_unlock(); | ||
1890 | 1937 | ||
1891 | return 0; | 1938 | return 0; |
1892 | } | 1939 | } |
@@ -1898,13 +1945,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) | |||
1898 | { | 1945 | { |
1899 | struct seq_file *m; | 1946 | struct seq_file *m; |
1900 | int ret; | 1947 | int ret; |
1948 | struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; | ||
1949 | struct net *net = pid_ns->child_reaper->nsproxy->net_ns; | ||
1901 | 1950 | ||
1902 | ret = seq_open(file, &nfs_volume_list_ops); | 1951 | ret = seq_open(file, &nfs_volume_list_ops); |
1903 | if (ret < 0) | 1952 | if (ret < 0) |
1904 | return ret; | 1953 | return ret; |
1905 | 1954 | ||
1906 | m = file->private_data; | 1955 | m = file->private_data; |
1907 | m->private = PDE(inode)->data; | 1956 | m->private = net; |
1908 | 1957 | ||
1909 | return 0; | 1958 | return 0; |
1910 | } | 1959 | } |
@@ -1914,9 +1963,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) | |||
1914 | */ | 1963 | */ |
1915 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | 1964 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) |
1916 | { | 1965 | { |
1966 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
1967 | |||
1917 | /* lock the list against modification */ | 1968 | /* lock the list against modification */ |
1918 | spin_lock(&nfs_client_lock); | 1969 | spin_lock(&nn->nfs_client_lock); |
1919 | return seq_list_start_head(&nfs_volume_list, *_pos); | 1970 | return seq_list_start_head(&nn->nfs_volume_list, *_pos); |
1920 | } | 1971 | } |
1921 | 1972 | ||
1922 | /* | 1973 | /* |
@@ -1924,7 +1975,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | |||
1924 | */ | 1975 | */ |
1925 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | 1976 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) |
1926 | { | 1977 | { |
1927 | return seq_list_next(v, &nfs_volume_list, pos); | 1978 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
1979 | |||
1980 | return seq_list_next(v, &nn->nfs_volume_list, pos); | ||
1928 | } | 1981 | } |
1929 | 1982 | ||
1930 | /* | 1983 | /* |
@@ -1932,7 +1985,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | |||
1932 | */ | 1985 | */ |
1933 | static void nfs_volume_list_stop(struct seq_file *p, void *v) | 1986 | static void nfs_volume_list_stop(struct seq_file *p, void *v) |
1934 | { | 1987 | { |
1935 | spin_unlock(&nfs_client_lock); | 1988 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
1989 | |||
1990 | spin_unlock(&nn->nfs_client_lock); | ||
1936 | } | 1991 | } |
1937 | 1992 | ||
1938 | /* | 1993 | /* |
@@ -1943,9 +1998,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1943 | struct nfs_server *server; | 1998 | struct nfs_server *server; |
1944 | struct nfs_client *clp; | 1999 | struct nfs_client *clp; |
1945 | char dev[8], fsid[17]; | 2000 | char dev[8], fsid[17]; |
2001 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
1946 | 2002 | ||
1947 | /* display header on line 1 */ | 2003 | /* display header on line 1 */ |
1948 | if (v == &nfs_volume_list) { | 2004 | if (v == &nn->nfs_volume_list) { |
1949 | seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); | 2005 | seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); |
1950 | return 0; | 2006 | return 0; |
1951 | } | 2007 | } |
@@ -1960,6 +2016,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1960 | (unsigned long long) server->fsid.major, | 2016 | (unsigned long long) server->fsid.major, |
1961 | (unsigned long long) server->fsid.minor); | 2017 | (unsigned long long) server->fsid.minor); |
1962 | 2018 | ||
2019 | rcu_read_lock(); | ||
1963 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", | 2020 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", |
1964 | clp->rpc_ops->version, | 2021 | clp->rpc_ops->version, |
1965 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 2022 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
@@ -1967,6 +2024,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1967 | dev, | 2024 | dev, |
1968 | fsid, | 2025 | fsid, |
1969 | nfs_server_fscache_state(server)); | 2026 | nfs_server_fscache_state(server)); |
2027 | rcu_read_unlock(); | ||
1970 | 2028 | ||
1971 | return 0; | 2029 | return 0; |
1972 | } | 2030 | } |