diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 268 |
1 files changed, 145 insertions, 123 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 60f7e4ec842c..7d108753af81 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -65,7 +65,7 @@ static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | |||
65 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | 65 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) |
66 | { | 66 | { |
67 | int ret = 0; | 67 | int ret = 0; |
68 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | 68 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); |
69 | 69 | ||
70 | if (clp->rpc_ops->version != 4 || minorversion != 0) | 70 | if (clp->rpc_ops->version != 4 || minorversion != 0) |
71 | return ret; | 71 | return ret; |
@@ -90,7 +90,9 @@ static bool nfs4_disable_idmapping = true; | |||
90 | * RPC cruft for NFS | 90 | * RPC cruft for NFS |
91 | */ | 91 | */ |
92 | static const struct rpc_version *nfs_version[5] = { | 92 | static const struct rpc_version *nfs_version[5] = { |
93 | #ifdef CONFIG_NFS_V2 | ||
93 | [2] = &nfs_version2, | 94 | [2] = &nfs_version2, |
95 | #endif | ||
94 | #ifdef CONFIG_NFS_V3 | 96 | #ifdef CONFIG_NFS_V3 |
95 | [3] = &nfs_version3, | 97 | [3] = &nfs_version3, |
96 | #endif | 98 | #endif |
@@ -129,6 +131,7 @@ const struct rpc_program nfsacl_program = { | |||
129 | #endif /* CONFIG_NFS_V3_ACL */ | 131 | #endif /* CONFIG_NFS_V3_ACL */ |
130 | 132 | ||
131 | struct nfs_client_initdata { | 133 | struct nfs_client_initdata { |
134 | unsigned long init_flags; | ||
132 | const char *hostname; | 135 | const char *hostname; |
133 | const struct sockaddr *addr; | 136 | const struct sockaddr *addr; |
134 | size_t addrlen; | 137 | size_t addrlen; |
@@ -172,7 +175,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
172 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 175 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
173 | 176 | ||
174 | clp->cl_proto = cl_init->proto; | 177 | clp->cl_proto = cl_init->proto; |
175 | clp->net = get_net(cl_init->net); | 178 | clp->cl_net = get_net(cl_init->net); |
176 | 179 | ||
177 | #ifdef CONFIG_NFS_V4 | 180 | #ifdef CONFIG_NFS_V4 |
178 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); | 181 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); |
@@ -182,7 +185,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
182 | spin_lock_init(&clp->cl_lock); | 185 | spin_lock_init(&clp->cl_lock); |
183 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | 186 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); |
184 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 187 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
185 | clp->cl_boot_time = CURRENT_TIME; | ||
186 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 188 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
187 | clp->cl_minorversion = cl_init->minorversion; | 189 | clp->cl_minorversion = cl_init->minorversion; |
188 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | 190 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; |
@@ -207,6 +209,7 @@ static void nfs4_shutdown_session(struct nfs_client *clp) | |||
207 | if (nfs4_has_session(clp)) { | 209 | if (nfs4_has_session(clp)) { |
208 | nfs4_deviceid_purge_client(clp); | 210 | nfs4_deviceid_purge_client(clp); |
209 | nfs4_destroy_session(clp->cl_session); | 211 | nfs4_destroy_session(clp->cl_session); |
212 | nfs4_destroy_clientid(clp); | ||
210 | } | 213 | } |
211 | 214 | ||
212 | } | 215 | } |
@@ -235,6 +238,9 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
235 | nfs_idmap_delete(clp); | 238 | nfs_idmap_delete(clp); |
236 | 239 | ||
237 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | 240 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); |
241 | kfree(clp->cl_serverowner); | ||
242 | kfree(clp->cl_serverscope); | ||
243 | kfree(clp->cl_implid); | ||
238 | } | 244 | } |
239 | 245 | ||
240 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ | 246 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ |
@@ -248,7 +254,7 @@ void nfs_cleanup_cb_ident_idr(struct net *net) | |||
248 | /* nfs_client_lock held */ | 254 | /* nfs_client_lock held */ |
249 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) | 255 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) |
250 | { | 256 | { |
251 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | 257 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); |
252 | 258 | ||
253 | if (clp->cl_cb_ident) | 259 | if (clp->cl_cb_ident) |
254 | idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident); | 260 | idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident); |
@@ -301,10 +307,8 @@ static void nfs_free_client(struct nfs_client *clp) | |||
301 | if (clp->cl_machine_cred != NULL) | 307 | if (clp->cl_machine_cred != NULL) |
302 | put_rpccred(clp->cl_machine_cred); | 308 | put_rpccred(clp->cl_machine_cred); |
303 | 309 | ||
304 | put_net(clp->net); | 310 | put_net(clp->cl_net); |
305 | kfree(clp->cl_hostname); | 311 | kfree(clp->cl_hostname); |
306 | kfree(clp->server_scope); | ||
307 | kfree(clp->impl_id); | ||
308 | kfree(clp); | 312 | kfree(clp); |
309 | 313 | ||
310 | dprintk("<-- nfs_free_client()\n"); | 314 | dprintk("<-- nfs_free_client()\n"); |
@@ -321,7 +325,7 @@ void nfs_put_client(struct nfs_client *clp) | |||
321 | return; | 325 | return; |
322 | 326 | ||
323 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); | 327 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); |
324 | nn = net_generic(clp->net, nfs_net_id); | 328 | nn = net_generic(clp->cl_net, nfs_net_id); |
325 | 329 | ||
326 | if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) { | 330 | if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) { |
327 | list_del(&clp->cl_share_link); | 331 | list_del(&clp->cl_share_link); |
@@ -456,6 +460,8 @@ static bool nfs4_cb_match_client(const struct sockaddr *addr, | |||
456 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | 460 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) |
457 | return false; | 461 | return false; |
458 | 462 | ||
463 | smp_rmb(); | ||
464 | |||
459 | /* Match the version and minorversion */ | 465 | /* Match the version and minorversion */ |
460 | if (clp->rpc_ops->version != 4 || | 466 | if (clp->rpc_ops->version != 4 || |
461 | clp->cl_minorversion != minorversion) | 467 | clp->cl_minorversion != minorversion) |
@@ -504,6 +510,47 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
504 | return NULL; | 510 | return NULL; |
505 | } | 511 | } |
506 | 512 | ||
513 | static bool nfs_client_init_is_complete(const struct nfs_client *clp) | ||
514 | { | ||
515 | return clp->cl_cons_state != NFS_CS_INITING; | ||
516 | } | ||
517 | |||
518 | int nfs_wait_client_init_complete(const struct nfs_client *clp) | ||
519 | { | ||
520 | return wait_event_killable(nfs_client_active_wq, | ||
521 | nfs_client_init_is_complete(clp)); | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * Found an existing client. Make sure it's ready before returning. | ||
526 | */ | ||
527 | static struct nfs_client * | ||
528 | nfs_found_client(const struct nfs_client_initdata *cl_init, | ||
529 | struct nfs_client *clp) | ||
530 | { | ||
531 | int error; | ||
532 | |||
533 | error = nfs_wait_client_init_complete(clp); | ||
534 | if (error < 0) { | ||
535 | nfs_put_client(clp); | ||
536 | return ERR_PTR(-ERESTARTSYS); | ||
537 | } | ||
538 | |||
539 | if (clp->cl_cons_state < NFS_CS_READY) { | ||
540 | error = clp->cl_cons_state; | ||
541 | nfs_put_client(clp); | ||
542 | return ERR_PTR(error); | ||
543 | } | ||
544 | |||
545 | smp_rmb(); | ||
546 | |||
547 | BUG_ON(clp->cl_cons_state != NFS_CS_READY); | ||
548 | |||
549 | dprintk("<-- %s found nfs_client %p for %s\n", | ||
550 | __func__, clp, cl_init->hostname ?: ""); | ||
551 | return clp; | ||
552 | } | ||
553 | |||
507 | /* | 554 | /* |
508 | * Look up a client by IP address and protocol version | 555 | * Look up a client by IP address and protocol version |
509 | * - creates a new record if one doesn't yet exist | 556 | * - creates a new record if one doesn't yet exist |
@@ -512,11 +559,9 @@ static struct nfs_client * | |||
512 | nfs_get_client(const struct nfs_client_initdata *cl_init, | 559 | nfs_get_client(const struct nfs_client_initdata *cl_init, |
513 | const struct rpc_timeout *timeparms, | 560 | const struct rpc_timeout *timeparms, |
514 | const char *ip_addr, | 561 | const char *ip_addr, |
515 | rpc_authflavor_t authflavour, | 562 | rpc_authflavor_t authflavour) |
516 | int noresvport) | ||
517 | { | 563 | { |
518 | struct nfs_client *clp, *new = NULL; | 564 | struct nfs_client *clp, *new = NULL; |
519 | int error; | ||
520 | struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); | 565 | struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); |
521 | 566 | ||
522 | dprintk("--> nfs_get_client(%s,v%u)\n", | 567 | dprintk("--> nfs_get_client(%s,v%u)\n", |
@@ -527,60 +572,29 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
527 | spin_lock(&nn->nfs_client_lock); | 572 | spin_lock(&nn->nfs_client_lock); |
528 | 573 | ||
529 | clp = nfs_match_client(cl_init); | 574 | clp = nfs_match_client(cl_init); |
530 | if (clp) | 575 | if (clp) { |
531 | goto found_client; | 576 | spin_unlock(&nn->nfs_client_lock); |
532 | if (new) | 577 | if (new) |
533 | goto install_client; | 578 | nfs_free_client(new); |
579 | return nfs_found_client(cl_init, clp); | ||
580 | } | ||
581 | if (new) { | ||
582 | list_add(&new->cl_share_link, &nn->nfs_client_list); | ||
583 | spin_unlock(&nn->nfs_client_lock); | ||
584 | new->cl_flags = cl_init->init_flags; | ||
585 | return cl_init->rpc_ops->init_client(new, | ||
586 | timeparms, ip_addr, | ||
587 | authflavour); | ||
588 | } | ||
534 | 589 | ||
535 | spin_unlock(&nn->nfs_client_lock); | 590 | spin_unlock(&nn->nfs_client_lock); |
536 | 591 | ||
537 | new = nfs_alloc_client(cl_init); | 592 | new = nfs_alloc_client(cl_init); |
538 | } while (!IS_ERR(new)); | 593 | } while (!IS_ERR(new)); |
539 | 594 | ||
540 | dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new)); | 595 | dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n", |
596 | cl_init->hostname ?: "", PTR_ERR(new)); | ||
541 | return new; | 597 | return new; |
542 | |||
543 | /* install a new client and return with it unready */ | ||
544 | install_client: | ||
545 | clp = new; | ||
546 | list_add(&clp->cl_share_link, &nn->nfs_client_list); | ||
547 | spin_unlock(&nn->nfs_client_lock); | ||
548 | |||
549 | error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, | ||
550 | authflavour, noresvport); | ||
551 | if (error < 0) { | ||
552 | nfs_put_client(clp); | ||
553 | return ERR_PTR(error); | ||
554 | } | ||
555 | dprintk("--> nfs_get_client() = %p [new]\n", clp); | ||
556 | return clp; | ||
557 | |||
558 | /* found an existing client | ||
559 | * - make sure it's ready before returning | ||
560 | */ | ||
561 | found_client: | ||
562 | spin_unlock(&nn->nfs_client_lock); | ||
563 | |||
564 | if (new) | ||
565 | nfs_free_client(new); | ||
566 | |||
567 | error = wait_event_killable(nfs_client_active_wq, | ||
568 | clp->cl_cons_state < NFS_CS_INITING); | ||
569 | if (error < 0) { | ||
570 | nfs_put_client(clp); | ||
571 | return ERR_PTR(-ERESTARTSYS); | ||
572 | } | ||
573 | |||
574 | if (clp->cl_cons_state < NFS_CS_READY) { | ||
575 | error = clp->cl_cons_state; | ||
576 | nfs_put_client(clp); | ||
577 | return ERR_PTR(error); | ||
578 | } | ||
579 | |||
580 | BUG_ON(clp->cl_cons_state != NFS_CS_READY); | ||
581 | |||
582 | dprintk("--> nfs_get_client() = %p [share]\n", clp); | ||
583 | return clp; | ||
584 | } | 598 | } |
585 | 599 | ||
586 | /* | 600 | /* |
@@ -588,27 +602,12 @@ found_client: | |||
588 | */ | 602 | */ |
589 | void nfs_mark_client_ready(struct nfs_client *clp, int state) | 603 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
590 | { | 604 | { |
605 | smp_wmb(); | ||
591 | clp->cl_cons_state = state; | 606 | clp->cl_cons_state = state; |
592 | wake_up_all(&nfs_client_active_wq); | 607 | wake_up_all(&nfs_client_active_wq); |
593 | } | 608 | } |
594 | 609 | ||
595 | /* | 610 | /* |
596 | * With sessions, the client is not marked ready until after a | ||
597 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
598 | * | ||
599 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
600 | * other versions of NFS can be tried. | ||
601 | */ | ||
602 | int nfs4_check_client_ready(struct nfs_client *clp) | ||
603 | { | ||
604 | if (!nfs4_has_session(clp)) | ||
605 | return 0; | ||
606 | if (clp->cl_cons_state < NFS_CS_READY) | ||
607 | return -EPROTONOSUPPORT; | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * Initialise the timeout values for a connection | 611 | * Initialise the timeout values for a connection |
613 | */ | 612 | */ |
614 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 613 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
@@ -654,12 +653,11 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
654 | */ | 653 | */ |
655 | static int nfs_create_rpc_client(struct nfs_client *clp, | 654 | static int nfs_create_rpc_client(struct nfs_client *clp, |
656 | const struct rpc_timeout *timeparms, | 655 | const struct rpc_timeout *timeparms, |
657 | rpc_authflavor_t flavor, | 656 | rpc_authflavor_t flavor) |
658 | int discrtry, int noresvport) | ||
659 | { | 657 | { |
660 | struct rpc_clnt *clnt = NULL; | 658 | struct rpc_clnt *clnt = NULL; |
661 | struct rpc_create_args args = { | 659 | struct rpc_create_args args = { |
662 | .net = clp->net, | 660 | .net = clp->cl_net, |
663 | .protocol = clp->cl_proto, | 661 | .protocol = clp->cl_proto, |
664 | .address = (struct sockaddr *)&clp->cl_addr, | 662 | .address = (struct sockaddr *)&clp->cl_addr, |
665 | .addrsize = clp->cl_addrlen, | 663 | .addrsize = clp->cl_addrlen, |
@@ -670,9 +668,9 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
670 | .authflavor = flavor, | 668 | .authflavor = flavor, |
671 | }; | 669 | }; |
672 | 670 | ||
673 | if (discrtry) | 671 | if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags)) |
674 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; | 672 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; |
675 | if (noresvport) | 673 | if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags)) |
676 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | 674 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; |
677 | 675 | ||
678 | if (!IS_ERR(clp->cl_rpcclient)) | 676 | if (!IS_ERR(clp->cl_rpcclient)) |
@@ -713,7 +711,7 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
713 | .nfs_version = clp->rpc_ops->version, | 711 | .nfs_version = clp->rpc_ops->version, |
714 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? | 712 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? |
715 | 1 : 0, | 713 | 1 : 0, |
716 | .net = clp->net, | 714 | .net = clp->cl_net, |
717 | }; | 715 | }; |
718 | 716 | ||
719 | if (nlm_init.nfs_version > 3) | 717 | if (nlm_init.nfs_version > 3) |
@@ -805,36 +803,43 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, | |||
805 | return 0; | 803 | return 0; |
806 | } | 804 | } |
807 | 805 | ||
808 | /* | 806 | /** |
809 | * Initialise an NFS2 or NFS3 client | 807 | * nfs_init_client - Initialise an NFS2 or NFS3 client |
808 | * | ||
809 | * @clp: nfs_client to initialise | ||
810 | * @timeparms: timeout parameters for underlying RPC transport | ||
811 | * @ip_addr: IP presentation address (not used) | ||
812 | * @authflavor: authentication flavor for underlying RPC transport | ||
813 | * | ||
814 | * Returns pointer to an NFS client, or an ERR_PTR value. | ||
810 | */ | 815 | */ |
811 | int nfs_init_client(struct nfs_client *clp, const struct rpc_timeout *timeparms, | 816 | struct nfs_client *nfs_init_client(struct nfs_client *clp, |
812 | const char *ip_addr, rpc_authflavor_t authflavour, | 817 | const struct rpc_timeout *timeparms, |
813 | int noresvport) | 818 | const char *ip_addr, rpc_authflavor_t authflavour) |
814 | { | 819 | { |
815 | int error; | 820 | int error; |
816 | 821 | ||
817 | if (clp->cl_cons_state == NFS_CS_READY) { | 822 | if (clp->cl_cons_state == NFS_CS_READY) { |
818 | /* the client is already initialised */ | 823 | /* the client is already initialised */ |
819 | dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp); | 824 | dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp); |
820 | return 0; | 825 | return clp; |
821 | } | 826 | } |
822 | 827 | ||
823 | /* | 828 | /* |
824 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | 829 | * Create a client RPC handle for doing FSSTAT with UNIX auth only |
825 | * - RFC 2623, sec 2.3.2 | 830 | * - RFC 2623, sec 2.3.2 |
826 | */ | 831 | */ |
827 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, | 832 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); |
828 | 0, noresvport); | ||
829 | if (error < 0) | 833 | if (error < 0) |
830 | goto error; | 834 | goto error; |
831 | nfs_mark_client_ready(clp, NFS_CS_READY); | 835 | nfs_mark_client_ready(clp, NFS_CS_READY); |
832 | return 0; | 836 | return clp; |
833 | 837 | ||
834 | error: | 838 | error: |
835 | nfs_mark_client_ready(clp, error); | 839 | nfs_mark_client_ready(clp, error); |
840 | nfs_put_client(clp); | ||
836 | dprintk("<-- nfs_init_client() = xerror %d\n", error); | 841 | dprintk("<-- nfs_init_client() = xerror %d\n", error); |
837 | return error; | 842 | return ERR_PTR(error); |
838 | } | 843 | } |
839 | 844 | ||
840 | /* | 845 | /* |
@@ -847,7 +852,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
847 | .hostname = data->nfs_server.hostname, | 852 | .hostname = data->nfs_server.hostname, |
848 | .addr = (const struct sockaddr *)&data->nfs_server.address, | 853 | .addr = (const struct sockaddr *)&data->nfs_server.address, |
849 | .addrlen = data->nfs_server.addrlen, | 854 | .addrlen = data->nfs_server.addrlen, |
850 | .rpc_ops = &nfs_v2_clientops, | 855 | .rpc_ops = NULL, |
851 | .proto = data->nfs_server.protocol, | 856 | .proto = data->nfs_server.protocol, |
852 | .net = data->net, | 857 | .net = data->net, |
853 | }; | 858 | }; |
@@ -857,17 +862,28 @@ static int nfs_init_server(struct nfs_server *server, | |||
857 | 862 | ||
858 | dprintk("--> nfs_init_server()\n"); | 863 | dprintk("--> nfs_init_server()\n"); |
859 | 864 | ||
865 | switch (data->version) { | ||
866 | #ifdef CONFIG_NFS_V2 | ||
867 | case 2: | ||
868 | cl_init.rpc_ops = &nfs_v2_clientops; | ||
869 | break; | ||
870 | #endif | ||
860 | #ifdef CONFIG_NFS_V3 | 871 | #ifdef CONFIG_NFS_V3 |
861 | if (data->version == 3) | 872 | case 3: |
862 | cl_init.rpc_ops = &nfs_v3_clientops; | 873 | cl_init.rpc_ops = &nfs_v3_clientops; |
874 | break; | ||
863 | #endif | 875 | #endif |
876 | default: | ||
877 | return -EPROTONOSUPPORT; | ||
878 | } | ||
864 | 879 | ||
865 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | 880 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, |
866 | data->timeo, data->retrans); | 881 | data->timeo, data->retrans); |
882 | if (data->flags & NFS_MOUNT_NORESVPORT) | ||
883 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); | ||
867 | 884 | ||
868 | /* Allocate or find a client reference we can use */ | 885 | /* Allocate or find a client reference we can use */ |
869 | clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX, | 886 | clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX); |
870 | data->flags & NFS_MOUNT_NORESVPORT); | ||
871 | if (IS_ERR(clp)) { | 887 | if (IS_ERR(clp)) { |
872 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | 888 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); |
873 | return PTR_ERR(clp); | 889 | return PTR_ERR(clp); |
@@ -880,7 +896,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
880 | server->options = data->options; | 896 | server->options = data->options; |
881 | server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| | 897 | server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| |
882 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| | 898 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| |
883 | NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME; | 899 | NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME|NFS_CAP_CHANGE_ATTR; |
884 | 900 | ||
885 | if (data->rsize) | 901 | if (data->rsize) |
886 | server->rsize = nfs_block_size(data->rsize, NULL); | 902 | server->rsize = nfs_block_size(data->rsize, NULL); |
@@ -1048,7 +1064,7 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve | |||
1048 | static void nfs_server_insert_lists(struct nfs_server *server) | 1064 | static void nfs_server_insert_lists(struct nfs_server *server) |
1049 | { | 1065 | { |
1050 | struct nfs_client *clp = server->nfs_client; | 1066 | struct nfs_client *clp = server->nfs_client; |
1051 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | 1067 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); |
1052 | 1068 | ||
1053 | spin_lock(&nn->nfs_client_lock); | 1069 | spin_lock(&nn->nfs_client_lock); |
1054 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); | 1070 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); |
@@ -1065,7 +1081,7 @@ static void nfs_server_remove_lists(struct nfs_server *server) | |||
1065 | 1081 | ||
1066 | if (clp == NULL) | 1082 | if (clp == NULL) |
1067 | return; | 1083 | return; |
1068 | nn = net_generic(clp->net, nfs_net_id); | 1084 | nn = net_generic(clp->cl_net, nfs_net_id); |
1069 | spin_lock(&nn->nfs_client_lock); | 1085 | spin_lock(&nn->nfs_client_lock); |
1070 | list_del_rcu(&server->client_link); | 1086 | list_del_rcu(&server->client_link); |
1071 | if (list_empty(&clp->cl_superblocks)) | 1087 | if (list_empty(&clp->cl_superblocks)) |
@@ -1333,21 +1349,27 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) | |||
1333 | * so that the client back channel can find the | 1349 | * so that the client back channel can find the |
1334 | * nfs_client struct | 1350 | * nfs_client struct |
1335 | */ | 1351 | */ |
1336 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | 1352 | nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING); |
1337 | } | 1353 | } |
1338 | #endif /* CONFIG_NFS_V4_1 */ | 1354 | #endif /* CONFIG_NFS_V4_1 */ |
1339 | 1355 | ||
1340 | return nfs4_init_callback(clp); | 1356 | return nfs4_init_callback(clp); |
1341 | } | 1357 | } |
1342 | 1358 | ||
1343 | /* | 1359 | /** |
1344 | * Initialise an NFS4 client record | 1360 | * nfs4_init_client - Initialise an NFS4 client record |
1361 | * | ||
1362 | * @clp: nfs_client to initialise | ||
1363 | * @timeparms: timeout parameters for underlying RPC transport | ||
1364 | * @ip_addr: callback IP address in presentation format | ||
1365 | * @authflavor: authentication flavor for underlying RPC transport | ||
1366 | * | ||
1367 | * Returns pointer to an NFS client, or an ERR_PTR value. | ||
1345 | */ | 1368 | */ |
1346 | int nfs4_init_client(struct nfs_client *clp, | 1369 | struct nfs_client *nfs4_init_client(struct nfs_client *clp, |
1347 | const struct rpc_timeout *timeparms, | 1370 | const struct rpc_timeout *timeparms, |
1348 | const char *ip_addr, | 1371 | const char *ip_addr, |
1349 | rpc_authflavor_t authflavour, | 1372 | rpc_authflavor_t authflavour) |
1350 | int noresvport) | ||
1351 | { | 1373 | { |
1352 | char buf[INET6_ADDRSTRLEN + 1]; | 1374 | char buf[INET6_ADDRSTRLEN + 1]; |
1353 | int error; | 1375 | int error; |
@@ -1355,14 +1377,14 @@ int nfs4_init_client(struct nfs_client *clp, | |||
1355 | if (clp->cl_cons_state == NFS_CS_READY) { | 1377 | if (clp->cl_cons_state == NFS_CS_READY) { |
1356 | /* the client is initialised already */ | 1378 | /* the client is initialised already */ |
1357 | dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); | 1379 | dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); |
1358 | return 0; | 1380 | return clp; |
1359 | } | 1381 | } |
1360 | 1382 | ||
1361 | /* Check NFS protocol revision and initialize RPC op vector */ | 1383 | /* Check NFS protocol revision and initialize RPC op vector */ |
1362 | clp->rpc_ops = &nfs_v4_clientops; | 1384 | clp->rpc_ops = &nfs_v4_clientops; |
1363 | 1385 | ||
1364 | error = nfs_create_rpc_client(clp, timeparms, authflavour, | 1386 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); |
1365 | 1, noresvport); | 1387 | error = nfs_create_rpc_client(clp, timeparms, authflavour); |
1366 | if (error < 0) | 1388 | if (error < 0) |
1367 | goto error; | 1389 | goto error; |
1368 | 1390 | ||
@@ -1395,12 +1417,13 @@ int nfs4_init_client(struct nfs_client *clp, | |||
1395 | 1417 | ||
1396 | if (!nfs4_has_session(clp)) | 1418 | if (!nfs4_has_session(clp)) |
1397 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1419 | nfs_mark_client_ready(clp, NFS_CS_READY); |
1398 | return 0; | 1420 | return clp; |
1399 | 1421 | ||
1400 | error: | 1422 | error: |
1401 | nfs_mark_client_ready(clp, error); | 1423 | nfs_mark_client_ready(clp, error); |
1424 | nfs_put_client(clp); | ||
1402 | dprintk("<-- nfs4_init_client() = xerror %d\n", error); | 1425 | dprintk("<-- nfs4_init_client() = xerror %d\n", error); |
1403 | return error; | 1426 | return ERR_PTR(error); |
1404 | } | 1427 | } |
1405 | 1428 | ||
1406 | /* | 1429 | /* |
@@ -1429,9 +1452,11 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1429 | 1452 | ||
1430 | dprintk("--> nfs4_set_client()\n"); | 1453 | dprintk("--> nfs4_set_client()\n"); |
1431 | 1454 | ||
1455 | if (server->flags & NFS_MOUNT_NORESVPORT) | ||
1456 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); | ||
1457 | |||
1432 | /* Allocate or find a client reference we can use */ | 1458 | /* Allocate or find a client reference we can use */ |
1433 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour, | 1459 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); |
1434 | server->flags & NFS_MOUNT_NORESVPORT); | ||
1435 | if (IS_ERR(clp)) { | 1460 | if (IS_ERR(clp)) { |
1436 | error = PTR_ERR(clp); | 1461 | error = PTR_ERR(clp); |
1437 | goto error; | 1462 | goto error; |
@@ -1465,8 +1490,8 @@ error: | |||
1465 | * the MDS. | 1490 | * the MDS. |
1466 | */ | 1491 | */ |
1467 | struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | 1492 | struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, |
1468 | const struct sockaddr *ds_addr, | 1493 | const struct sockaddr *ds_addr, int ds_addrlen, |
1469 | int ds_addrlen, int ds_proto) | 1494 | int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans) |
1470 | { | 1495 | { |
1471 | struct nfs_client_initdata cl_init = { | 1496 | struct nfs_client_initdata cl_init = { |
1472 | .addr = ds_addr, | 1497 | .addr = ds_addr, |
@@ -1474,14 +1499,9 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | |||
1474 | .rpc_ops = &nfs_v4_clientops, | 1499 | .rpc_ops = &nfs_v4_clientops, |
1475 | .proto = ds_proto, | 1500 | .proto = ds_proto, |
1476 | .minorversion = mds_clp->cl_minorversion, | 1501 | .minorversion = mds_clp->cl_minorversion, |
1477 | .net = mds_clp->net, | 1502 | .net = mds_clp->cl_net, |
1478 | }; | ||
1479 | struct rpc_timeout ds_timeout = { | ||
1480 | .to_initval = 15 * HZ, | ||
1481 | .to_maxval = 15 * HZ, | ||
1482 | .to_retries = 1, | ||
1483 | .to_exponential = 1, | ||
1484 | }; | 1503 | }; |
1504 | struct rpc_timeout ds_timeout; | ||
1485 | struct nfs_client *clp; | 1505 | struct nfs_client *clp; |
1486 | 1506 | ||
1487 | /* | 1507 | /* |
@@ -1489,8 +1509,9 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | |||
1489 | * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS | 1509 | * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS |
1490 | * (section 13.1 RFC 5661). | 1510 | * (section 13.1 RFC 5661). |
1491 | */ | 1511 | */ |
1512 | nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); | ||
1492 | clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, | 1513 | clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, |
1493 | mds_clp->cl_rpcclient->cl_auth->au_flavor, 0); | 1514 | mds_clp->cl_rpcclient->cl_auth->au_flavor); |
1494 | 1515 | ||
1495 | dprintk("<-- %s %p\n", __func__, clp); | 1516 | dprintk("<-- %s %p\n", __func__, clp); |
1496 | return clp; | 1517 | return clp; |
@@ -1701,7 +1722,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1701 | rpc_protocol(parent_server->client), | 1722 | rpc_protocol(parent_server->client), |
1702 | parent_server->client->cl_timeout, | 1723 | parent_server->client->cl_timeout, |
1703 | parent_client->cl_mvops->minor_version, | 1724 | parent_client->cl_mvops->minor_version, |
1704 | parent_client->net); | 1725 | parent_client->cl_net); |
1705 | if (error < 0) | 1726 | if (error < 0) |
1706 | goto error; | 1727 | goto error; |
1707 | 1728 | ||
@@ -1805,6 +1826,7 @@ void nfs_clients_init(struct net *net) | |||
1805 | idr_init(&nn->cb_ident_idr); | 1826 | idr_init(&nn->cb_ident_idr); |
1806 | #endif | 1827 | #endif |
1807 | spin_lock_init(&nn->nfs_client_lock); | 1828 | spin_lock_init(&nn->nfs_client_lock); |
1829 | nn->boot_time = CURRENT_TIME; | ||
1808 | } | 1830 | } |
1809 | 1831 | ||
1810 | #ifdef CONFIG_PROC_FS | 1832 | #ifdef CONFIG_PROC_FS |