aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-07-20 17:00:02 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2017-07-21 14:08:45 -0400
commit1ebf980127924c639e2b85c08468311ba1c95b70 (patch)
tree514331ff7257270cc81f6963cc483b91cd0f0530
parentecbb903c56745d59c301db26dd7d8b74b520eb84 (diff)
NFS/filelayout: Fix racy setting of fl->dsaddr in filelayout_check_deviceid()
We must set fl->dsaddr once, and once only, even if there are multiple processes calling filelayout_check_deviceid() for the same layout segment. Reported-by: Olga Kornievskaia <kolga@netapp.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--fs/nfs/filelayout/filelayout.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c
index 080fc6b278bd..44c638b7876c 100644
--- a/fs/nfs/filelayout/filelayout.c
+++ b/fs/nfs/filelayout/filelayout.c
@@ -542,6 +542,10 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
542 struct nfs4_file_layout_dsaddr *dsaddr; 542 struct nfs4_file_layout_dsaddr *dsaddr;
543 int status = -EINVAL; 543 int status = -EINVAL;
544 544
545 /* Is the deviceid already set? If so, we're good. */
546 if (fl->dsaddr != NULL)
547 return 0;
548
545 /* find and reference the deviceid */ 549 /* find and reference the deviceid */
546 d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid, 550 d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
547 lo->plh_lc_cred, gfp_flags); 551 lo->plh_lc_cred, gfp_flags);
@@ -553,8 +557,6 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
553 if (filelayout_test_devid_unavailable(&dsaddr->id_node)) 557 if (filelayout_test_devid_unavailable(&dsaddr->id_node))
554 goto out_put; 558 goto out_put;
555 559
556 fl->dsaddr = dsaddr;
557
558 if (fl->first_stripe_index >= dsaddr->stripe_count) { 560 if (fl->first_stripe_index >= dsaddr->stripe_count) {
559 dprintk("%s Bad first_stripe_index %u\n", 561 dprintk("%s Bad first_stripe_index %u\n",
560 __func__, fl->first_stripe_index); 562 __func__, fl->first_stripe_index);
@@ -570,6 +572,13 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
570 goto out_put; 572 goto out_put;
571 } 573 }
572 status = 0; 574 status = 0;
575
576 /*
577 * Atomic compare and xchange to ensure we don't scribble
578 * over a non-NULL pointer.
579 */
580 if (cmpxchg(&fl->dsaddr, NULL, dsaddr) != NULL)
581 goto out_put;
573out: 582out:
574 return status; 583 return status;
575out_put: 584out_put: