diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-02-22 17:34:59 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-02-22 17:34:59 -0500 |
commit | 2454dfea0aef8a883d4302c38124edb373d47a25 (patch) | |
tree | e6ffc2bd5a1bc51a60bd22c5d7d59aa0f72d9935 | |
parent | d07fbb8fdf57c4af28679ad7c4b2542e78ca7218 (diff) |
NFSv4.x/pnfs: Fix a race between layoutget and pnfs_destroy_layout
If the server reboots while there is a layoutget outstanding, then
the call to pnfs_choose_layoutget_stateid() will fail with an EAGAIN
error, which causes an infinite loop in send_layoutget(). The reason
why we never break out of the loop is that the layout 'plh_block_lgets'
field is never cleared.
Fix is to replace plh_block_lgets with NFS_LAYOUT_INVALID_STID, which
can be reset after a new layoutget.
Fixes: ab7d763e477c5 ("pNFS: Ensure nfs4_layoutget_prepare returns...")
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | fs/nfs/pnfs.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 5064f23ca8cc..8a41538f1155 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -252,6 +252,27 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) | |||
252 | } | 252 | } |
253 | } | 253 | } |
254 | 254 | ||
255 | /* | ||
256 | * Mark a pnfs_layout_hdr and all associated layout segments as invalid | ||
257 | * | ||
258 | * In order to continue using the pnfs_layout_hdr, a full recovery | ||
259 | * is required. | ||
260 | * Note that caller must hold inode->i_lock. | ||
261 | */ | ||
262 | static void | ||
263 | pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, | ||
264 | struct list_head *lseg_list) | ||
265 | { | ||
266 | struct pnfs_layout_range range = { | ||
267 | .iomode = IOMODE_ANY, | ||
268 | .offset = 0, | ||
269 | .length = NFS4_MAX_UINT64, | ||
270 | }; | ||
271 | |||
272 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); | ||
273 | pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range); | ||
274 | } | ||
275 | |||
255 | static int | 276 | static int |
256 | pnfs_iomode_to_fail_bit(u32 iomode) | 277 | pnfs_iomode_to_fail_bit(u32 iomode) |
257 | { | 278 | { |
@@ -554,9 +575,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) | |||
554 | spin_lock(&nfsi->vfs_inode.i_lock); | 575 | spin_lock(&nfsi->vfs_inode.i_lock); |
555 | lo = nfsi->layout; | 576 | lo = nfsi->layout; |
556 | if (lo) { | 577 | if (lo) { |
557 | lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ | ||
558 | pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); | ||
559 | pnfs_get_layout_hdr(lo); | 578 | pnfs_get_layout_hdr(lo); |
579 | pnfs_mark_layout_stateid_invalid(lo, &tmp_list); | ||
560 | pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED); | 580 | pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED); |
561 | pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED); | 581 | pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED); |
562 | spin_unlock(&nfsi->vfs_inode.i_lock); | 582 | spin_unlock(&nfsi->vfs_inode.i_lock); |