Commit a2a32cd1d7c3085da129ab6e2060f6afae187176
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
Merge tag 'nfs-for-3.19-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: "Highlights include: - Stable fix for a NFSv3/lockd race - Fixes for several NFSv4.1 client id trunking bugs - Remove an incorrect test when checking for delegated opens" * tag 'nfs-for-3.19-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFSv4: Remove incorrect check in can_open_delegated() NFS: Ignore transport protocol when detecting server trunking NFSv4/v4.1: Verify the client owner id during trunking detection NFSv4: Cache the NFSv4/v4.1 client owner_id in the struct nfs_client NFSv4.1: Fix client id trunking on Linux LOCKD: Fix a race when initialising nlmsvc_timeout
Showing 4 changed files Side-by-side Diff
fs/lockd/svc.c
... | ... | @@ -138,10 +138,6 @@ |
138 | 138 | |
139 | 139 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); |
140 | 140 | |
141 | - if (!nlm_timeout) | |
142 | - nlm_timeout = LOCKD_DFLT_TIMEO; | |
143 | - nlmsvc_timeout = nlm_timeout * HZ; | |
144 | - | |
145 | 141 | /* |
146 | 142 | * The main request loop. We don't terminate until the last |
147 | 143 | * NFS mount or NFS daemon has gone away. |
... | ... | @@ -349,6 +345,10 @@ |
349 | 345 | if (nlmsvc_users) |
350 | 346 | printk(KERN_WARNING |
351 | 347 | "lockd_up: no pid, %d users??\n", nlmsvc_users); |
348 | + | |
349 | + if (!nlm_timeout) | |
350 | + nlm_timeout = LOCKD_DFLT_TIMEO; | |
351 | + nlmsvc_timeout = nlm_timeout * HZ; | |
352 | 352 | |
353 | 353 | serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, svc_rpcb_cleanup); |
354 | 354 | if (!serv) { |
fs/nfs/nfs4client.c
... | ... | @@ -228,6 +228,7 @@ |
228 | 228 | kfree(clp->cl_serverowner); |
229 | 229 | kfree(clp->cl_serverscope); |
230 | 230 | kfree(clp->cl_implid); |
231 | + kfree(clp->cl_owner_id); | |
231 | 232 | } |
232 | 233 | |
233 | 234 | void nfs4_free_client(struct nfs_client *clp) |
... | ... | @@ -452,6 +453,14 @@ |
452 | 453 | spin_unlock(&nn->nfs_client_lock); |
453 | 454 | } |
454 | 455 | |
456 | +static bool nfs4_match_client_owner_id(const struct nfs_client *clp1, | |
457 | + const struct nfs_client *clp2) | |
458 | +{ | |
459 | + if (clp1->cl_owner_id == NULL || clp2->cl_owner_id == NULL) | |
460 | + return true; | |
461 | + return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0; | |
462 | +} | |
463 | + | |
455 | 464 | /** |
456 | 465 | * nfs40_walk_client_list - Find server that recognizes a client ID |
457 | 466 | * |
... | ... | @@ -483,9 +492,6 @@ |
483 | 492 | if (pos->rpc_ops != new->rpc_ops) |
484 | 493 | continue; |
485 | 494 | |
486 | - if (pos->cl_proto != new->cl_proto) | |
487 | - continue; | |
488 | - | |
489 | 495 | if (pos->cl_minorversion != new->cl_minorversion) |
490 | 496 | continue; |
491 | 497 | |
... | ... | @@ -510,6 +516,9 @@ |
510 | 516 | if (pos->cl_clientid != new->cl_clientid) |
511 | 517 | continue; |
512 | 518 | |
519 | + if (!nfs4_match_client_owner_id(pos, new)) | |
520 | + continue; | |
521 | + | |
513 | 522 | atomic_inc(&pos->cl_count); |
514 | 523 | spin_unlock(&nn->nfs_client_lock); |
515 | 524 | |
516 | 525 | |
517 | 526 | |
... | ... | @@ -566,20 +575,14 @@ |
566 | 575 | } |
567 | 576 | |
568 | 577 | /* |
569 | - * Returns true if the server owners match | |
578 | + * Returns true if the server major ids match | |
570 | 579 | */ |
571 | 580 | static bool |
572 | -nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b) | |
581 | +nfs4_check_clientid_trunking(struct nfs_client *a, struct nfs_client *b) | |
573 | 582 | { |
574 | 583 | struct nfs41_server_owner *o1 = a->cl_serverowner; |
575 | 584 | struct nfs41_server_owner *o2 = b->cl_serverowner; |
576 | 585 | |
577 | - if (o1->minor_id != o2->minor_id) { | |
578 | - dprintk("NFS: --> %s server owner minor IDs do not match\n", | |
579 | - __func__); | |
580 | - return false; | |
581 | - } | |
582 | - | |
583 | 586 | if (o1->major_id_sz != o2->major_id_sz) |
584 | 587 | goto out_major_mismatch; |
585 | 588 | if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0) |
... | ... | @@ -621,9 +624,6 @@ |
621 | 624 | if (pos->rpc_ops != new->rpc_ops) |
622 | 625 | continue; |
623 | 626 | |
624 | - if (pos->cl_proto != new->cl_proto) | |
625 | - continue; | |
626 | - | |
627 | 627 | if (pos->cl_minorversion != new->cl_minorversion) |
628 | 628 | continue; |
629 | 629 | |
... | ... | @@ -654,7 +654,19 @@ |
654 | 654 | if (!nfs4_match_clientids(pos, new)) |
655 | 655 | continue; |
656 | 656 | |
657 | - if (!nfs4_match_serverowners(pos, new)) | |
657 | + /* | |
658 | + * Note that session trunking is just a special subcase of | |
659 | + * client id trunking. In either case, we want to fall back | |
660 | + * to using the existing nfs_client. | |
661 | + */ | |
662 | + if (!nfs4_check_clientid_trunking(pos, new)) | |
663 | + continue; | |
664 | + | |
665 | + /* Unlike NFSv4.0, we know that NFSv4.1 always uses the | |
666 | + * uniform string, however someone might switch the | |
667 | + * uniquifier string on us. | |
668 | + */ | |
669 | + if (!nfs4_match_client_owner_id(pos, new)) | |
658 | 670 | continue; |
659 | 671 | |
660 | 672 | atomic_inc(&pos->cl_count); |
fs/nfs/nfs4proc.c
... | ... | @@ -1117,8 +1117,6 @@ |
1117 | 1117 | return 0; |
1118 | 1118 | if ((delegation->type & fmode) != fmode) |
1119 | 1119 | return 0; |
1120 | - if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) | |
1121 | - return 0; | |
1122 | 1120 | if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) |
1123 | 1121 | return 0; |
1124 | 1122 | nfs_mark_delegation_referenced(delegation); |
1125 | 1123 | |
... | ... | @@ -4917,11 +4915,14 @@ |
4917 | 4915 | } |
4918 | 4916 | |
4919 | 4917 | static unsigned int |
4920 | -nfs4_init_nonuniform_client_string(const struct nfs_client *clp, | |
4918 | +nfs4_init_nonuniform_client_string(struct nfs_client *clp, | |
4921 | 4919 | char *buf, size_t len) |
4922 | 4920 | { |
4923 | 4921 | unsigned int result; |
4924 | 4922 | |
4923 | + if (clp->cl_owner_id != NULL) | |
4924 | + return strlcpy(buf, clp->cl_owner_id, len); | |
4925 | + | |
4925 | 4926 | rcu_read_lock(); |
4926 | 4927 | result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s", |
4927 | 4928 | clp->cl_ipaddr, |
4928 | 4929 | |
4929 | 4930 | |
4930 | 4931 | |
4931 | 4932 | |
4932 | 4933 | |
4933 | 4934 | |
... | ... | @@ -4930,24 +4931,32 @@ |
4930 | 4931 | rpc_peeraddr2str(clp->cl_rpcclient, |
4931 | 4932 | RPC_DISPLAY_PROTO)); |
4932 | 4933 | rcu_read_unlock(); |
4934 | + clp->cl_owner_id = kstrdup(buf, GFP_KERNEL); | |
4933 | 4935 | return result; |
4934 | 4936 | } |
4935 | 4937 | |
4936 | 4938 | static unsigned int |
4937 | -nfs4_init_uniform_client_string(const struct nfs_client *clp, | |
4939 | +nfs4_init_uniform_client_string(struct nfs_client *clp, | |
4938 | 4940 | char *buf, size_t len) |
4939 | 4941 | { |
4940 | 4942 | const char *nodename = clp->cl_rpcclient->cl_nodename; |
4943 | + unsigned int result; | |
4941 | 4944 | |
4945 | + if (clp->cl_owner_id != NULL) | |
4946 | + return strlcpy(buf, clp->cl_owner_id, len); | |
4947 | + | |
4942 | 4948 | if (nfs4_client_id_uniquifier[0] != '\0') |
4943 | - return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s", | |
4949 | + result = scnprintf(buf, len, "Linux NFSv%u.%u %s/%s", | |
4944 | 4950 | clp->rpc_ops->version, |
4945 | 4951 | clp->cl_minorversion, |
4946 | 4952 | nfs4_client_id_uniquifier, |
4947 | 4953 | nodename); |
4948 | - return scnprintf(buf, len, "Linux NFSv%u.%u %s", | |
4954 | + else | |
4955 | + result = scnprintf(buf, len, "Linux NFSv%u.%u %s", | |
4949 | 4956 | clp->rpc_ops->version, clp->cl_minorversion, |
4950 | 4957 | nodename); |
4958 | + clp->cl_owner_id = kstrdup(buf, GFP_KERNEL); | |
4959 | + return result; | |
4951 | 4960 | } |
4952 | 4961 | |
4953 | 4962 | /* |
include/linux/nfs_fs_sb.h