Commit 1ebf9801 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

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: default avatarOlga Kornievskaia <kolga@netapp.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent ecbb903c
...@@ -542,6 +542,10 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo, ...@@ -542,6 +542,10 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
struct nfs4_file_layout_dsaddr *dsaddr; struct nfs4_file_layout_dsaddr *dsaddr;
int status = -EINVAL; int status = -EINVAL;
/* Is the deviceid already set? If so, we're good. */
if (fl->dsaddr != NULL)
return 0;
/* find and reference the deviceid */ /* find and reference the deviceid */
d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid, d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
lo->plh_lc_cred, gfp_flags); lo->plh_lc_cred, gfp_flags);
...@@ -553,8 +557,6 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo, ...@@ -553,8 +557,6 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
if (filelayout_test_devid_unavailable(&dsaddr->id_node)) if (filelayout_test_devid_unavailable(&dsaddr->id_node))
goto out_put; goto out_put;
fl->dsaddr = dsaddr;
if (fl->first_stripe_index >= dsaddr->stripe_count) { if (fl->first_stripe_index >= dsaddr->stripe_count) {
dprintk("%s Bad first_stripe_index %u\n", dprintk("%s Bad first_stripe_index %u\n",
__func__, fl->first_stripe_index); __func__, fl->first_stripe_index);
...@@ -570,6 +572,13 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo, ...@@ -570,6 +572,13 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
goto out_put; goto out_put;
} }
status = 0; status = 0;
/*
* Atomic compare and xchange to ensure we don't scribble
* over a non-NULL pointer.
*/
if (cmpxchg(&fl->dsaddr, NULL, dsaddr) != NULL)
goto out_put;
out: out:
return status; return status;
out_put: out_put:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment