diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-07-20 17:00:02 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2017-07-21 14:08:45 -0400 |
commit | 1ebf980127924c639e2b85c08468311ba1c95b70 (patch) | |
tree | 514331ff7257270cc81f6963cc483b91cd0f0530 | |
parent | ecbb903c56745d59c301db26dd7d8b74b520eb84 (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.c | 13 |
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; | ||
573 | out: | 582 | out: |
574 | return status; | 583 | return status; |
575 | out_put: | 584 | out_put: |