]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: add a realtime flag to the refcount update log redo items
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:22:28 +0000 (14:22 -0700)
committerChristoph Hellwig <hch@lst.de>
Mon, 12 Aug 2024 11:53:50 +0000 (13:53 +0200)
Extend the refcount update (CUI) log items with a new realtime flag that
indicates that the updates apply against the realtime refcountbt.  We'll
wire up the actual refcount code later.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/defer_item.c
libxfs/xfs_bmap.c
libxfs/xfs_defer.h
libxfs/xfs_log_format.h
libxfs/xfs_refcount.c
libxfs/xfs_refcount.h

index e4f2c75dec7f1c5a66ee5a61404e17c3bfdef939..9ebaa9f1fcda4ebf2e3f6af53916463e8c35fc92 100644 (file)
@@ -537,8 +537,22 @@ xfs_refcount_defer_add(
 
        trace_xfs_refcount_defer(mp, ri);
 
-       ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_startblock);
-       xfs_defer_add(tp, &ri->ri_list, &xfs_refcount_update_defer_type);
+       /*
+        * Deferred refcount updates for the realtime and data sections must
+        * use separate transactions to finish deferred work because updates to
+        * realtime metadata files can lock AGFs to allocate btree blocks and
+        * we don't want that mixing with the AGF locks taken to finish data
+        * section updates.
+        */
+       if (ri->ri_realtime) {
+               ri->ri_rtg = xfs_rtgroup_intent_get(mp, ri->ri_startblock);
+               xfs_defer_add(tp, &ri->ri_list,
+                               &xfs_rtrefcount_update_defer_type);
+       } else {
+               ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_startblock);
+               xfs_defer_add(tp, &ri->ri_list,
+                               &xfs_refcount_update_defer_type);
+       }
 }
 
 /* Cancel a deferred refcount update. */
@@ -610,6 +624,89 @@ const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
        .cancel_item    = xfs_refcount_update_cancel_item,
 };
 
+/* Sort refcount intents by rtgroup. */
+static int
+xfs_rtrefcount_update_diff_items(
+       void                                    *priv,
+       const struct list_head                  *a,
+       const struct list_head                  *b)
+{
+       struct xfs_refcount_intent              *ra = ci_entry(a);
+       struct xfs_refcount_intent              *rb = ci_entry(b);
+
+       return ra->ri_rtg->rtg_rgno - rb->ri_rtg->rtg_rgno;
+}
+
+static struct xfs_log_item *
+xfs_rtrefcount_update_create_intent(
+       struct xfs_trans                *tp,
+       struct list_head                *items,
+       unsigned int                    count,
+       bool                            sort)
+{
+       struct xfs_mount                *mp = tp->t_mountp;
+
+       if (sort)
+               list_sort(mp, items, xfs_rtrefcount_update_diff_items);
+       return NULL;
+}
+
+/* Cancel a deferred realtime refcount update. */
+STATIC void
+xfs_rtrefcount_update_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_refcount_intent      *ri = ci_entry(item);
+
+       xfs_rtgroup_intent_put(ri->ri_rtg);
+       kmem_cache_free(xfs_refcount_intent_cache, ri);
+}
+
+/* Process a deferred realtime refcount update. */
+STATIC int
+xfs_rtrefcount_update_finish_item(
+       struct xfs_trans                *tp,
+       struct xfs_log_item             *done,
+       struct list_head                *item,
+       struct xfs_btree_cur            **state)
+{
+       struct xfs_refcount_intent      *ri = ci_entry(item);
+       int                             error;
+
+       error = xfs_rtrefcount_finish_one(tp, ri, state);
+
+       /* Did we run out of reservation?  Requeue what we didn't finish. */
+       if (!error && ri->ri_blockcount > 0) {
+               ASSERT(ri->ri_type == XFS_REFCOUNT_INCREASE ||
+                      ri->ri_type == XFS_REFCOUNT_DECREASE);
+               return -EAGAIN;
+       }
+
+       xfs_rtrefcount_update_cancel_item(item);
+       return error;
+}
+
+/* Clean up after calling xfs_rtrefcount_finish_one. */
+STATIC void
+xfs_rtrefcount_finish_one_cleanup(
+       struct xfs_trans        *tp,
+       struct xfs_btree_cur    *rcur,
+       int                     error)
+{
+       if (rcur)
+               xfs_btree_del_cursor(rcur, error);
+}
+
+const struct xfs_defer_op_type xfs_rtrefcount_update_defer_type = {
+       .name           = "rtrefcount",
+       .create_intent  = xfs_rtrefcount_update_create_intent,
+       .abort_intent   = xfs_refcount_update_abort_intent,
+       .create_done    = xfs_refcount_update_create_done,
+       .finish_item    = xfs_rtrefcount_update_finish_item,
+       .finish_cleanup = xfs_rtrefcount_finish_one_cleanup,
+       .cancel_item    = xfs_rtrefcount_update_cancel_item,
+};
+
 /* Inode Block Mapping */
 
 static inline struct xfs_bmap_intent *bi_entry(const struct list_head *e)
index 7513991f58a1bc736645c6f4a7ad2c104fbfa21e..2323990a172ac8e36119b8702b58ad58f7f16182 100644 (file)
@@ -4609,8 +4609,9 @@ xfs_bmapi_write(
                         * the refcount btree for orphan recovery.
                         */
                        if (whichfork == XFS_COW_FORK)
-                               xfs_refcount_alloc_cow_extent(tp, bma.blkno,
-                                               bma.length);
+                               xfs_refcount_alloc_cow_extent(tp,
+                                               XFS_IS_REALTIME_INODE(ip),
+                                               bma.blkno, bma.length);
                }
 
                /* Deal with the allocated space we found.  */
@@ -4785,7 +4786,8 @@ xfs_bmapi_convert_one_delalloc(
                *seq = READ_ONCE(ifp->if_seq);
 
        if (whichfork == XFS_COW_FORK)
-               xfs_refcount_alloc_cow_extent(tp, bma.blkno, bma.length);
+               xfs_refcount_alloc_cow_extent(tp, XFS_IS_REALTIME_INODE(ip),
+                               bma.blkno, bma.length);
 
        error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &bma.logflags,
                        whichfork);
@@ -5432,7 +5434,7 @@ xfs_bmap_del_extent_real(
                bool    isrt = xfs_ifork_is_realtime(ip, whichfork);
 
                if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
-                       xfs_refcount_decrease_extent(tp, del);
+                       xfs_refcount_decrease_extent(tp, isrt, del);
                } else if (isrt && !xfs_has_rtgroups(mp)) {
                        error = xfs_bmap_free_rtblocks(tp, del);
                } else {
index 1e2477eaa5a844e1cc0e7338bb2a7da28a41e6d8..9effd95ddcd4eef152122eac47a78face2798c04 100644 (file)
@@ -68,6 +68,7 @@ struct xfs_defer_op_type {
 
 extern const struct xfs_defer_op_type xfs_bmap_update_defer_type;
 extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;
+extern const struct xfs_defer_op_type xfs_rtrefcount_update_defer_type;
 extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
 extern const struct xfs_defer_op_type xfs_rtrmap_update_defer_type;
 extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
index a7e0e479454d3d5196abaea0094d0d8fc7b1492a..ec7157eaba5f682e264dd8df1db199a86da21c8a 100644 (file)
@@ -252,6 +252,8 @@ typedef struct xfs_trans_header {
 #define        XFS_LI_EFD_RT           0x124b  /* realtime extent free done */
 #define        XFS_LI_RUI_RT           0x124c  /* realtime rmap update intent */
 #define        XFS_LI_RUD_RT           0x124d  /* realtime rmap update done */
+#define        XFS_LI_CUI_RT           0x124e  /* realtime refcount update intent */
+#define        XFS_LI_CUD_RT           0x124f  /* realtime refcount update done */
 
 #define XFS_LI_TYPE_DESC \
        { XFS_LI_EFI,           "XFS_LI_EFI" }, \
@@ -275,7 +277,9 @@ typedef struct xfs_trans_header {
        { XFS_LI_EFI_RT,        "XFS_LI_EFI_RT" }, \
        { XFS_LI_EFD_RT,        "XFS_LI_EFD_RT" }, \
        { XFS_LI_RUI_RT,        "XFS_LI_RUI_RT" }, \
-       { XFS_LI_RUD_RT,        "XFS_LI_RUD_RT" }
+       { XFS_LI_RUD_RT,        "XFS_LI_RUD_RT" }, \
+       { XFS_LI_CUI_RT,        "XFS_LI_CUI_RT" }, \
+       { XFS_LI_CUD_RT,        "XFS_LI_CUD_RT" }
 
 /*
  * Inode Log Item Format definitions.
index a89a8507c707ba257a9c66d2e8ce80192893a145..66c3ac15aba73facbcf9d9d597b04db40df7b743 100644 (file)
@@ -1132,6 +1132,28 @@ xfs_refcount_still_have_space(
                cur->bc_refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD;
 }
 
+/* Schedule an extent free. */
+static int
+xrefc_free_extent(
+       struct xfs_btree_cur            *cur,
+       struct xfs_refcount_irec        *rec)
+{
+       xfs_fsblock_t                   fsbno;
+       unsigned int                    flags = 0;
+
+       if (xfs_btree_is_rtrefcount(cur->bc_ops)) {
+               flags |= XFS_FREE_EXTENT_REALTIME;
+               fsbno = xfs_rgbno_to_rtb(cur->bc_mp, cur->bc_ino.rtg->rtg_rgno,
+                               rec->rc_startblock);
+       } else {
+               fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
+                               rec->rc_startblock);
+       }
+
+       return xfs_free_extent_later(cur->bc_tp, fsbno, rec->rc_blockcount,
+                       NULL, XFS_AG_RESV_NONE, flags);
+}
+
 /*
  * Adjust the refcounts of middle extents.  At this point we should have
  * split extents that crossed the adjustment range; merged with adjacent
@@ -1148,7 +1170,6 @@ xfs_refcount_adjust_extents(
        struct xfs_refcount_irec        ext, tmp;
        int                             error;
        int                             found_rec, found_tmp;
-       xfs_fsblock_t                   fsbno;
 
        /* Merging did all the work already. */
        if (*aglen == 0)
@@ -1201,12 +1222,7 @@ xfs_refcount_adjust_extents(
                                        goto out_error;
                                }
                        } else {
-                               fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
-                                               cur->bc_ag.pag->pag_agno,
-                                               tmp.rc_startblock);
-                               error = xfs_free_extent_later(cur->bc_tp, fsbno,
-                                                 tmp.rc_blockcount, NULL,
-                                                 XFS_AG_RESV_NONE, 0);
+                               error = xrefc_free_extent(cur, &tmp);
                                if (error)
                                        goto out_error;
                        }
@@ -1264,12 +1280,7 @@ xfs_refcount_adjust_extents(
                        }
                        goto advloop;
                } else {
-                       fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
-                                       cur->bc_ag.pag->pag_agno,
-                                       ext.rc_startblock);
-                       error = xfs_free_extent_later(cur->bc_tp, fsbno,
-                                       ext.rc_blockcount, NULL,
-                                       XFS_AG_RESV_NONE, 0);
+                       error = xrefc_free_extent(cur, &ext);
                        if (error)
                                goto out_error;
                }
@@ -1464,6 +1475,20 @@ xfs_refcount_finish_one(
        return error;
 }
 
+/*
+ * Process one of the deferred realtime refcount operations.  We pass back the
+ * btree cursor to maintain our lock on the btree between calls.
+ */
+int
+xfs_rtrefcount_finish_one(
+       struct xfs_trans                *tp,
+       struct xfs_refcount_intent      *ri,
+       struct xfs_btree_cur            **pcur)
+{
+       ASSERT(0);
+       return -EFSCORRUPTED;
+}
+
 /*
  * Record a refcount intent for later processing.
  */
@@ -1471,6 +1496,7 @@ static void
 __xfs_refcount_add(
        struct xfs_trans                *tp,
        enum xfs_refcount_intent_type   type,
+       bool                            isrt,
        xfs_fsblock_t                   startblock,
        xfs_extlen_t                    blockcount)
 {
@@ -1482,6 +1508,7 @@ __xfs_refcount_add(
        ri->ri_type = type;
        ri->ri_startblock = startblock;
        ri->ri_blockcount = blockcount;
+       ri->ri_realtime = isrt;
 
        xfs_refcount_defer_add(tp, ri);
 }
@@ -1492,12 +1519,13 @@ __xfs_refcount_add(
 void
 xfs_refcount_increase_extent(
        struct xfs_trans                *tp,
+       bool                            isrt,
        struct xfs_bmbt_irec            *PREV)
 {
        if (!xfs_has_reflink(tp->t_mountp))
                return;
 
-       __xfs_refcount_add(tp, XFS_REFCOUNT_INCREASE, PREV->br_startblock,
+       __xfs_refcount_add(tp, XFS_REFCOUNT_INCREASE, isrt, PREV->br_startblock,
                        PREV->br_blockcount);
 }
 
@@ -1507,12 +1535,13 @@ xfs_refcount_increase_extent(
 void
 xfs_refcount_decrease_extent(
        struct xfs_trans                *tp,
+       bool                            isrt,
        struct xfs_bmbt_irec            *PREV)
 {
        if (!xfs_has_reflink(tp->t_mountp))
                return;
 
-       __xfs_refcount_add(tp, XFS_REFCOUNT_DECREASE, PREV->br_startblock,
+       __xfs_refcount_add(tp, XFS_REFCOUNT_DECREASE, isrt, PREV->br_startblock,
                        PREV->br_blockcount);
 }
 
@@ -1868,6 +1897,7 @@ __xfs_refcount_cow_free(
 void
 xfs_refcount_alloc_cow_extent(
        struct xfs_trans                *tp,
+       bool                            isrt,
        xfs_fsblock_t                   fsb,
        xfs_extlen_t                    len)
 {
@@ -1876,16 +1906,17 @@ xfs_refcount_alloc_cow_extent(
        if (!xfs_has_reflink(mp))
                return;
 
-       __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len);
+       __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, isrt, fsb, len);
 
        /* Add rmap entry */
-       xfs_rmap_alloc_extent(tp, false, fsb, len, XFS_RMAP_OWN_COW);
+       xfs_rmap_alloc_extent(tp, isrt, fsb, len, XFS_RMAP_OWN_COW);
 }
 
 /* Forget a CoW staging event in the refcount btree. */
 void
 xfs_refcount_free_cow_extent(
        struct xfs_trans                *tp,
+       bool                            isrt,
        xfs_fsblock_t                   fsb,
        xfs_extlen_t                    len)
 {
@@ -1895,8 +1926,8 @@ xfs_refcount_free_cow_extent(
                return;
 
        /* Remove rmap entry */
-       xfs_rmap_free_extent(tp, false, fsb, len, XFS_RMAP_OWN_COW);
-       __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len);
+       xfs_rmap_free_extent(tp, isrt, fsb, len, XFS_RMAP_OWN_COW);
+       __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, isrt, fsb, len);
 }
 
 struct xfs_refcount_recovery {
@@ -2003,7 +2034,7 @@ xfs_refcount_recover_cow_leftovers(
                /* Free the orphan record */
                fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno,
                                rr->rr_rrec.rc_startblock);
-               xfs_refcount_free_cow_extent(tp, fsb,
+               xfs_refcount_free_cow_extent(tp, false, fsb,
                                rr->rr_rrec.rc_blockcount);
 
                /* Free the block. */
index 13344b402a72cb47b0fdddbea2d9c8896a09b369..56e5834feb624264dd1b3ab1248a39cc5e1d03d4 100644 (file)
@@ -57,10 +57,14 @@ enum xfs_refcount_intent_type {
 
 struct xfs_refcount_intent {
        struct list_head                        ri_list;
-       struct xfs_perag                        *ri_pag;
+       union {
+               struct xfs_perag                *ri_pag;
+               struct xfs_rtgroup              *ri_rtg;
+       };
        enum xfs_refcount_intent_type           ri_type;
        xfs_extlen_t                            ri_blockcount;
        xfs_fsblock_t                           ri_startblock;
+       bool                                    ri_realtime;
 };
 
 /* Check that the refcount is appropriate for the record domain. */
@@ -75,22 +79,24 @@ xfs_refcount_check_domain(
        return true;
 }
 
-void xfs_refcount_increase_extent(struct xfs_trans *tp,
+void xfs_refcount_increase_extent(struct xfs_trans *tp, bool isrt,
                struct xfs_bmbt_irec *irec);
-void xfs_refcount_decrease_extent(struct xfs_trans *tp,
+void xfs_refcount_decrease_extent(struct xfs_trans *tp, bool isrt,
                struct xfs_bmbt_irec *irec);
 
-extern int xfs_refcount_finish_one(struct xfs_trans *tp,
+int xfs_refcount_finish_one(struct xfs_trans *tp,
+               struct xfs_refcount_intent *ri, struct xfs_btree_cur **pcur);
+int xfs_rtrefcount_finish_one(struct xfs_trans *tp,
                struct xfs_refcount_intent *ri, struct xfs_btree_cur **pcur);
 
 extern int xfs_refcount_find_shared(struct xfs_btree_cur *cur,
                xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno,
                xfs_extlen_t *flen, bool find_end_of_shared);
 
-void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
-               xfs_extlen_t len);
-void xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
-               xfs_extlen_t len);
+void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, bool isrt,
+               xfs_fsblock_t fsb, xfs_extlen_t len);
+void xfs_refcount_free_cow_extent(struct xfs_trans *tp, bool isrt,
+               xfs_fsblock_t fsb, xfs_extlen_t len);
 extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
                struct xfs_perag *pag);