xfs_extent_busy_clear_one() calls kmem_free() with the pag spinlock locked. Fix this by adding a new temporary list, and, make xfs_extent_busy_clear_one() to move the extent_busy items to this new list, instead of freeing them. Free the objects in the temporary list after we drop the pagb_lock Reported-by: Jeff Layton <jlayton@xxxxxxxxxx> Signed-off-by: Carlos Maiolino <cmaiolino@xxxxxxxxxx> --- fs/xfs/xfs_extent_busy.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c index 0ed68379e551..0a7dcf03340b 100644 --- a/fs/xfs/xfs_extent_busy.c +++ b/fs/xfs/xfs_extent_busy.c @@ -523,7 +523,8 @@ STATIC void xfs_extent_busy_clear_one( struct xfs_mount *mp, struct xfs_perag *pag, - struct xfs_extent_busy *busyp) + struct xfs_extent_busy *busyp, + struct list_head *list) { if (busyp->length) { trace_xfs_extent_busy_clear(mp, busyp->agno, busyp->bno, @@ -531,8 +532,7 @@ xfs_extent_busy_clear_one( rb_erase(&busyp->rb_node, &pag->pagb_tree); } - list_del_init(&busyp->list); - kmem_free(busyp); + list_move(&busyp->list, list); } static void @@ -565,6 +565,7 @@ xfs_extent_busy_clear( struct xfs_perag *pag = NULL; xfs_agnumber_t agno = NULLAGNUMBER; bool wakeup = false; + LIST_HEAD(busy_list); list_for_each_entry_safe(busyp, n, list, list) { if (busyp->agno != agno) { @@ -580,13 +581,18 @@ xfs_extent_busy_clear( !(busyp->flags & XFS_EXTENT_BUSY_SKIP_DISCARD)) { busyp->flags = XFS_EXTENT_BUSY_DISCARDED; } else { - xfs_extent_busy_clear_one(mp, pag, busyp); + xfs_extent_busy_clear_one(mp, pag, busyp, &busy_list); wakeup = true; } } if (pag) xfs_extent_busy_put_pag(pag, wakeup); + + list_for_each_entry_safe(busyp, n, &busy_list, list) { + list_del_init(&busyp->list); + kmem_free(busyp); + } } /* -- 2.20.1