]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
xfs: separate dquot buffer reads from xfs_dqflush
authorDarrick J. Wong <djwong@kernel.org>
Mon, 2 Dec 2024 18:57:36 +0000 (10:57 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Fri, 13 Dec 2024 01:45:11 +0000 (17:45 -0800)
The first step towards holding the dquot buffer in the li_buf instead of
reading it in the AIL is to separate the part that reads the buffer from
the actual flush code.  There should be no functional changes.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_dquot_item.c
fs/xfs/xfs_qm.c

index ff982d983989b0c275eca9133bebdce8f6711e23..6ec4087e38dfc817dc3e9ea519c2a262986ad650 100644 (file)
@@ -1238,6 +1238,42 @@ xfs_qm_dqflush_check(
        return NULL;
 }
 
+/*
+ * Get the buffer containing the on-disk dquot.
+ *
+ * Requires dquot flush lock, will clear the dirty flag, delete the quota log
+ * item from the AIL, and shut down the system if something goes wrong.
+ */
+int
+xfs_dquot_read_buf(
+       struct xfs_trans        *tp,
+       struct xfs_dquot        *dqp,
+       struct xfs_buf          **bpp)
+{
+       struct xfs_mount        *mp = dqp->q_mount;
+       struct xfs_buf          *bp = NULL;
+       int                     error;
+
+       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, dqp->q_blkno,
+                                  mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK,
+                                  &bp, &xfs_dquot_buf_ops);
+       if (error == -EAGAIN)
+               return error;
+       if (xfs_metadata_is_sick(error))
+               xfs_dquot_mark_sick(dqp);
+       if (error)
+               goto out_abort;
+
+       *bpp = bp;
+       return 0;
+
+out_abort:
+       dqp->q_flags &= ~XFS_DQFLAG_DIRTY;
+       xfs_trans_ail_delete(&dqp->q_logitem.qli_item, 0);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+       return error;
+}
+
 /*
  * Write a modified dquot to disk.
  * The dquot must be locked and the flush lock too taken by caller.
@@ -1249,11 +1285,10 @@ xfs_qm_dqflush_check(
 int
 xfs_qm_dqflush(
        struct xfs_dquot        *dqp,
-       struct xfs_buf          **bpp)
+       struct xfs_buf          *bp)
 {
        struct xfs_mount        *mp = dqp->q_mount;
        struct xfs_log_item     *lip = &dqp->q_logitem.qli_item;
-       struct xfs_buf          *bp;
        struct xfs_dqblk        *dqblk;
        xfs_failaddr_t          fa;
        int                     error;
@@ -1263,28 +1298,12 @@ xfs_qm_dqflush(
 
        trace_xfs_dqflush(dqp);
 
-       *bpp = NULL;
-
        xfs_qm_dqunpin_wait(dqp);
 
-       /*
-        * Get the buffer containing the on-disk dquot
-        */
-       error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
-                                  mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK,
-                                  &bp, &xfs_dquot_buf_ops);
-       if (error == -EAGAIN)
-               goto out_unlock;
-       if (xfs_metadata_is_sick(error))
-               xfs_dquot_mark_sick(dqp);
-       if (error)
-               goto out_abort;
-
        fa = xfs_qm_dqflush_check(dqp);
        if (fa) {
                xfs_alert(mp, "corrupt dquot ID 0x%x in memory at %pS",
                                dqp->q_id, fa);
-               xfs_buf_relse(bp);
                xfs_dquot_mark_sick(dqp);
                error = -EFSCORRUPTED;
                goto out_abort;
@@ -1334,14 +1353,12 @@ xfs_qm_dqflush(
        }
 
        trace_xfs_dqflush_done(dqp);
-       *bpp = bp;
        return 0;
 
 out_abort:
        dqp->q_flags &= ~XFS_DQFLAG_DIRTY;
        xfs_trans_ail_delete(lip, 0);
        xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
-out_unlock:
        xfs_dqfunlock(dqp);
        return error;
 }
index d73d179df0095856d632cf222c02543b01d91f04..50f8404c41176ce06e53efb0fc3294c9bde0a5d9 100644 (file)
@@ -214,7 +214,9 @@ void xfs_dquot_to_disk(struct xfs_disk_dquot *ddqp, struct xfs_dquot *dqp);
 #define XFS_DQ_IS_DIRTY(dqp)   ((dqp)->q_flags & XFS_DQFLAG_DIRTY)
 
 void           xfs_qm_dqdestroy(struct xfs_dquot *dqp);
-int            xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf **bpp);
+int            xfs_dquot_read_buf(struct xfs_trans *tp, struct xfs_dquot *dqp,
+                               struct xfs_buf **bpp);
+int            xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf *bp);
 void           xfs_qm_dqunpin_wait(struct xfs_dquot *dqp);
 void           xfs_qm_adjust_dqtimers(struct xfs_dquot *d);
 void           xfs_qm_adjust_dqlimits(struct xfs_dquot *d);
index 7d19091215b08030a22c6cad064dec29e38fe873..56ecc5ed01934d702516a0d5a4c297c2f626860c 100644 (file)
@@ -155,14 +155,26 @@ xfs_qm_dquot_logitem_push(
 
        spin_unlock(&lip->li_ailp->ail_lock);
 
-       error = xfs_qm_dqflush(dqp, &bp);
+       error = xfs_dquot_read_buf(NULL, dqp, &bp);
+       if (error) {
+               if (error == -EAGAIN)
+                       rval = XFS_ITEM_LOCKED;
+               xfs_dqfunlock(dqp);
+               goto out_relock_ail;
+       }
+
+       /*
+        * dqflush completes dqflock on error, and the delwri ioend does it on
+        * success.
+        */
+       error = xfs_qm_dqflush(dqp, bp);
        if (!error) {
                if (!xfs_buf_delwri_queue(bp, buffer_list))
                        rval = XFS_ITEM_FLUSHING;
-               xfs_buf_relse(bp);
-       } else if (error == -EAGAIN)
-               rval = XFS_ITEM_LOCKED;
+       }
+       xfs_buf_relse(bp);
 
+out_relock_ail:
        spin_lock(&lip->li_ailp->ail_lock);
 out_unlock:
        xfs_dqunlock(dqp);
index 3c0189831f14dd939a88543d5ce061ec2ad1322a..d9ac50a33c57ff41e0ece1cc197bfd63b45c62b6 100644 (file)
@@ -148,17 +148,28 @@ xfs_qm_dqpurge(
                 * We don't care about getting disk errors here. We need
                 * to purge this dquot anyway, so we go ahead regardless.
                 */
-               error = xfs_qm_dqflush(dqp, &bp);
+               error = xfs_dquot_read_buf(NULL, dqp, &bp);
+               if (error == -EAGAIN) {
+                       xfs_dqfunlock(dqp);
+                       dqp->q_flags &= ~XFS_DQFLAG_FREEING;
+                       goto out_unlock;
+               }
+               if (error)
+                       goto out_funlock;
+
+               /*
+                * dqflush completes dqflock on error, and the bwrite ioend
+                * does it on success.
+                */
+               error = xfs_qm_dqflush(dqp, bp);
                if (!error) {
                        error = xfs_bwrite(bp);
                        xfs_buf_relse(bp);
-               } else if (error == -EAGAIN) {
-                       dqp->q_flags &= ~XFS_DQFLAG_FREEING;
-                       goto out_unlock;
                }
                xfs_dqflock(dqp);
        }
 
+out_funlock:
        ASSERT(atomic_read(&dqp->q_pincount) == 0);
        ASSERT(xlog_is_shutdown(dqp->q_logitem.qli_item.li_log) ||
                !test_bit(XFS_LI_IN_AIL, &dqp->q_logitem.qli_item.li_flags));
@@ -494,7 +505,17 @@ xfs_qm_dquot_isolate(
                /* we have to drop the LRU lock to flush the dquot */
                spin_unlock(&lru->lock);
 
-               error = xfs_qm_dqflush(dqp, &bp);
+               error = xfs_dquot_read_buf(NULL, dqp, &bp);
+               if (error) {
+                       xfs_dqfunlock(dqp);
+                       goto out_unlock_dirty;
+               }
+
+               /*
+                * dqflush completes dqflock on error, and the delwri ioend
+                * does it on success.
+                */
+               error = xfs_qm_dqflush(dqp, bp);
                if (error)
                        goto out_unlock_dirty;
 
@@ -1489,11 +1510,13 @@ xfs_qm_flush_one(
                goto out_unlock;
        }
 
-       error = xfs_qm_dqflush(dqp, &bp);
+       error = xfs_dquot_read_buf(NULL, dqp, &bp);
        if (error)
                goto out_unlock;
 
-       xfs_buf_delwri_queue(bp, buffer_list);
+       error = xfs_qm_dqflush(dqp, bp);
+       if (!error)
+               xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
 out_unlock:
        xfs_dqunlock(dqp);