Commit a2a32cd1d7c3085da129ab6e2060f6afae187176

Authored by Linus Torvalds

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

... ... @@ -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) {
... ... @@ -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);
... ... @@ -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
... ... @@ -74,6 +74,9 @@
74 74 /* idmapper */
75 75 struct idmap * cl_idmap;
76 76  
  77 + /* Client owner identifier */
  78 + const char * cl_owner_id;
  79 +
77 80 /* Our own IP address, as a null-terminated string.
78 81 * This is used to generate the mv0 callback address.
79 82 */