Skip to content
/ linux Public

Commit 8e3d911

Browse files
Olga KornievskaiaSasha Levin
authored andcommitted
pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN
[ Upstream commit 5248d84 ] It is possible to have a task get stuck on waiting on the NFS_LAYOUT_DRAIN in the following scenario 1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) 2. cpu b: atomic_dec_and_test() -> clear bit -> wake up 3. cpu c: sets NFS_LAYOUT_DRAIN again 4. cpu a: calls wait_on_bit() sleeps forever. To expand on this we have say 2 outstanding pnfs write IO that get ESTALE which causes both to call pnfs_destroy_layout() and set the NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write from trying to call pnfs_destroy_layout()). If the 1st ESTALE write is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO on this file initiates new LAYOUTGET. Another new write would find NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of ESTALE writes is calling pnfs_destory_layout() and set the NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up to check the bit and goes back to sleep. The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID was already set, it should not do the work of pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not be set more than once for an invalid layout. Suggested-by: Trond Myklebust <trond.myklebust@hammerspace.com> Fixes: 880265c ("pNFS: Avoid a live lock condition in pnfs_update_layout()") Signed-off-by: Olga Kornievskaia <okorniev@redhat.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 34276d2 commit 8e3d911

File tree

1 file changed

+2
-1
lines changed

1 file changed

+2
-1
lines changed

fs/nfs/pnfs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
464464
};
465465
struct pnfs_layout_segment *lseg, *next;
466466

467-
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
467+
if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))
468+
return !list_empty(&lo->plh_segs);
468469
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags);
469470
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
470471
pnfs_clear_lseg_state(lseg, lseg_list);

0 commit comments

Comments
 (0)