]> git.baikalelectronics.ru Git - kernel.git/commitdiff
xfs: use background worker pool when transactions can't get free space
authorDarrick J. Wong <djwong@kernel.org>
Fri, 6 Aug 2021 18:05:42 +0000 (11:05 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 9 Aug 2021 18:13:16 +0000 (11:13 -0700)
In xfs_trans_alloc, if the block reservation call returns ENOSPC, we
call xfs_blockgc_free_space with a NULL icwalk structure to try to free
space.  Each frontend thread that encounters this situation starts its
own walk of the inode cache to see if it can find anything, which is
wasteful since we don't have any additional selection criteria.  For
this one common case, create a function that reschedules all pending
background work immediately and flushes the workqueue so that the scan
can run in parallel.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c

index 41bd84fd9e872821208f883aac3587a8a04ba97b..93ab83dfa36eddd6d4a9e7a4b100aeb78742953b 100644 (file)
@@ -1500,6 +1500,34 @@ xfs_blockgc_free_space(
        return 0;
 }
 
+/*
+ * Reclaim all the free space that we can by scheduling the background blockgc
+ * and inodegc workers immediately and waiting for them all to clear.
+ */
+void
+xfs_blockgc_flush_all(
+       struct xfs_mount        *mp)
+{
+       struct xfs_perag        *pag;
+       xfs_agnumber_t          agno;
+
+       trace_xfs_blockgc_flush_all(mp, __return_address);
+
+       /*
+        * For each blockgc worker, move its queue time up to now.  If it
+        * wasn't queued, it will not be requeued.  Then flush whatever's
+        * left.
+        */
+       for_each_perag_tag(mp, agno, pag, XFS_ICI_BLOCKGC_TAG)
+               mod_delayed_work(pag->pag_mount->m_blockgc_wq,
+                               &pag->pag_blockgc_work, 0);
+
+       for_each_perag_tag(mp, agno, pag, XFS_ICI_BLOCKGC_TAG)
+               flush_delayed_work(&pag->pag_blockgc_work);
+
+       xfs_inodegc_flush(mp);
+}
+
 /*
  * Run cow/eofblocks scans on the supplied dquots.  We don't know exactly which
  * quota caused an allocation failure, so we make a best effort by including
index 8175148afd503d0cf3af3a773053ed8ea9b3ba0e..18c2d224aa78b7585272d489b3e09e61d329775f 100644 (file)
@@ -59,6 +59,7 @@ int xfs_blockgc_free_dquots(struct xfs_mount *mp, struct xfs_dquot *udqp,
                unsigned int iwalk_flags);
 int xfs_blockgc_free_quota(struct xfs_inode *ip, unsigned int iwalk_flags);
 int xfs_blockgc_free_space(struct xfs_mount *mp, struct xfs_icwalk *icm);
+void xfs_blockgc_flush_all(struct xfs_mount *mp);
 
 void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
 void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
index 3440046facc70cb5bf906a149e9627cc5b541215..4a6616490315b905576b790cd276aa40b8947478 100644 (file)
@@ -198,6 +198,7 @@ DEFINE_FS_EVENT(xfs_fs_sync_fs);
 DEFINE_FS_EVENT(xfs_blockgc_start);
 DEFINE_FS_EVENT(xfs_blockgc_stop);
 DEFINE_FS_EVENT(xfs_blockgc_worker);
+DEFINE_FS_EVENT(xfs_blockgc_flush_all);
 
 DECLARE_EVENT_CLASS(xfs_ag_class,
        TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno),
index 87bffd12c20c7f8d6c262bba445100167d8f2667..83abaa21961605064a9aa48e9fcf0d2781e9f286 100644 (file)
@@ -295,10 +295,7 @@ retry:
                 * Do not perform a synchronous scan because callers can hold
                 * other locks.
                 */
-               error = xfs_blockgc_free_space(mp, NULL);
-               if (error)
-                       return error;
-
+               xfs_blockgc_flush_all(mp);
                want_retry = false;
                goto retry;
        }