diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2018-03-07 14:49:06 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2018-03-08 12:56:31 -0500 |
commit | 9c6376ebddad585da4238532dd6d90ae23ffee67 (patch) | |
tree | a69494f605f82c0cb19dc8dc63fc65832c6b60dd /fs/nfs/pnfs.c | |
parent | d9ee65539d3eabd9ade46cca1780e3309ad0f907 (diff) |
pNFS: Prevent the layout header refcount going to zero in pnfs_roc()
Ensure that we hold a reference to the layout header when processing
the pNFS return-on-close so that the refcount value does not inadvertently
go to zero.
Reported-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org # v4.10+
Tested-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c13e826614b5..ee723aa153a3 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo) | |||
292 | void | 292 | void |
293 | pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) | 293 | pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) |
294 | { | 294 | { |
295 | struct inode *inode = lo->plh_inode; | 295 | struct inode *inode; |
296 | 296 | ||
297 | if (!lo) | ||
298 | return; | ||
299 | inode = lo->plh_inode; | ||
297 | pnfs_layoutreturn_before_put_layout_hdr(lo); | 300 | pnfs_layoutreturn_before_put_layout_hdr(lo); |
298 | 301 | ||
299 | if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { | 302 | if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { |
@@ -1241,10 +1244,12 @@ retry: | |||
1241 | spin_lock(&ino->i_lock); | 1244 | spin_lock(&ino->i_lock); |
1242 | lo = nfsi->layout; | 1245 | lo = nfsi->layout; |
1243 | if (!lo || !pnfs_layout_is_valid(lo) || | 1246 | if (!lo || !pnfs_layout_is_valid(lo) || |
1244 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) | 1247 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { |
1248 | lo = NULL; | ||
1245 | goto out_noroc; | 1249 | goto out_noroc; |
1250 | } | ||
1251 | pnfs_get_layout_hdr(lo); | ||
1246 | if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { | 1252 | if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { |
1247 | pnfs_get_layout_hdr(lo); | ||
1248 | spin_unlock(&ino->i_lock); | 1253 | spin_unlock(&ino->i_lock); |
1249 | wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, | 1254 | wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, |
1250 | TASK_UNINTERRUPTIBLE); | 1255 | TASK_UNINTERRUPTIBLE); |
@@ -1312,10 +1317,12 @@ out_noroc: | |||
1312 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; | 1317 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; |
1313 | if (ld->prepare_layoutreturn) | 1318 | if (ld->prepare_layoutreturn) |
1314 | ld->prepare_layoutreturn(args); | 1319 | ld->prepare_layoutreturn(args); |
1320 | pnfs_put_layout_hdr(lo); | ||
1315 | return true; | 1321 | return true; |
1316 | } | 1322 | } |
1317 | if (layoutreturn) | 1323 | if (layoutreturn) |
1318 | pnfs_send_layoutreturn(lo, &stateid, iomode, true); | 1324 | pnfs_send_layoutreturn(lo, &stateid, iomode, true); |
1325 | pnfs_put_layout_hdr(lo); | ||
1319 | return false; | 1326 | return false; |
1320 | } | 1327 | } |
1321 | 1328 | ||