Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2454dfea authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: ab7d763e ("pNFS: Ensure nfs4_layoutget_prepare returns...")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent d07fbb8f
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -252,6 +252,27 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
	}
}

/*
 * Mark a pnfs_layout_hdr and all associated layout segments as invalid
 *
 * In order to continue using the pnfs_layout_hdr, a full recovery
 * is required.
 * Note that caller must hold inode->i_lock.
 */
static void
pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
		struct list_head *lseg_list)
{
	struct pnfs_layout_range range = {
		.iomode = IOMODE_ANY,
		.offset = 0,
		.length = NFS4_MAX_UINT64,
	};

	set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
	pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range);
}

static int
pnfs_iomode_to_fail_bit(u32 iomode)
{
@@ -554,9 +575,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
	spin_lock(&nfsi->vfs_inode.i_lock);
	lo = nfsi->layout;
	if (lo) {
		lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
		pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
		pnfs_get_layout_hdr(lo);
		pnfs_mark_layout_stateid_invalid(lo, &tmp_list);
		pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED);
		pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED);
		spin_unlock(&nfsi->vfs_inode.i_lock);