Entries on the plh_return_segs list have already had their refcount go to zero, and are only hanging around so that a LAYOUTRETURN can be issued. If there are still leftover lsegs on the plh_return_segs list when the last pnfs_layout_hdr reference is put, then that means that the layoutreturn just before the final refcount_dec_and_lock() has failed, or that new lsegs have somehow raced onto plh_return_segs. In either case, nothing else will be aware of the entries on that list, since there are no more outstanding references. On the last pnfs_layout_put(), do a final call to pnfs_mark_layout_stateid_invalid() to shuffle any leftover segments to a tmp_list. Then free that list after dropping the i_lock. Reported-by: Omar Sandoval <osandov@xxxxxxxxxxx> Closes: https://lore.kernel.org/linux-nfs/Z_ArpQC_vREh_hEA@telecaster/ Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> --- fs/nfs/pnfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 5f582713bf05eb72eb34b2e2c06d1edcd3c258d3..0bcb5a4bd420c157069ee63457518b206223b7cb 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -307,6 +307,7 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) { struct inode *inode; unsigned long i_state; + LIST_HEAD(tmp_list); if (!lo) return; @@ -316,9 +317,11 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { if (!list_empty(&lo->plh_segs)) WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n"); + pnfs_mark_layout_stateid_invalid(lo, &tmp_list); pnfs_detach_layout_hdr(lo); i_state = inode->i_state; spin_unlock(&inode->i_lock); + pnfs_free_lseg_list(&tmp_list); pnfs_free_layout_hdr(lo); /* Notify pnfs_destroy_layout_final() that we're done */ if (i_state & (I_FREEING | I_CLEAR)) -- 2.49.0