Skip to content

Commit f639557

Browse files
Trond Myklebustamschuma-ntap
authored andcommitted
pNFS: Fix a hang in nfs4_evict_inode()
We are not allowed to call pnfs_mark_matching_lsegs_return() without also holding a reference to the layout header, since doing so could lead to the reference count going to zero when we call pnfs_layout_remove_lseg(). This again can lead to a hang when we get to nfs4_evict_inode() and are unable to clear the layout pointer. pnfs_layout_return_unused_byserver() is guilty of this behaviour, and has been seen to trigger the refcount warning prior to a hang. Fixes: b6d49ec ("NFSv4: Fix a pNFS layout related use-after-free race when freeing the inode") Cc: [email protected] Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 6a6d464 commit f639557

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

fs/nfs/pnfs.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,31 +2634,44 @@ pnfs_should_return_unused_layout(struct pnfs_layout_hdr *lo,
26342634
return mode == 0;
26352635
}
26362636

2637-
static int
2638-
pnfs_layout_return_unused_byserver(struct nfs_server *server, void *data)
2637+
static int pnfs_layout_return_unused_byserver(struct nfs_server *server,
2638+
void *data)
26392639
{
26402640
const struct pnfs_layout_range *range = data;
2641+
const struct cred *cred;
26412642
struct pnfs_layout_hdr *lo;
26422643
struct inode *inode;
2644+
nfs4_stateid stateid;
2645+
enum pnfs_iomode iomode;
2646+
26432647
restart:
26442648
rcu_read_lock();
26452649
list_for_each_entry_rcu(lo, &server->layouts, plh_layouts) {
2646-
if (!pnfs_layout_can_be_returned(lo) ||
2650+
inode = lo->plh_inode;
2651+
if (!inode || !pnfs_layout_can_be_returned(lo) ||
26472652
test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
26482653
continue;
2649-
inode = lo->plh_inode;
26502654
spin_lock(&inode->i_lock);
2651-
if (!pnfs_should_return_unused_layout(lo, range)) {
2655+
if (!lo->plh_inode ||
2656+
!pnfs_should_return_unused_layout(lo, range)) {
26522657
spin_unlock(&inode->i_lock);
26532658
continue;
26542659
}
2660+
pnfs_get_layout_hdr(lo);
2661+
pnfs_set_plh_return_info(lo, range->iomode, 0);
2662+
if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs,
2663+
range, 0) != 0 ||
2664+
!pnfs_prepare_layoutreturn(lo, &stateid, &cred, &iomode)) {
2665+
spin_unlock(&inode->i_lock);
2666+
rcu_read_unlock();
2667+
pnfs_put_layout_hdr(lo);
2668+
cond_resched();
2669+
goto restart;
2670+
}
26552671
spin_unlock(&inode->i_lock);
2656-
inode = pnfs_grab_inode_layout_hdr(lo);
2657-
if (!inode)
2658-
continue;
26592672
rcu_read_unlock();
2660-
pnfs_mark_layout_for_return(inode, range);
2661-
iput(inode);
2673+
pnfs_send_layoutreturn(lo, &stateid, &cred, iomode, false);
2674+
pnfs_put_layout_hdr(lo);
26622675
cond_resched();
26632676
goto restart;
26642677
}

0 commit comments

Comments
 (0)