]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: support logging EFIs for realtime extents
authorDarrick J. Wong <djwong@kernel.org>
Tue, 7 Mar 2023 03:55:42 +0000 (19:55 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 22 Nov 2023 23:03:36 +0000 (15:03 -0800)
Teach the EFI mechanism how to free realtime extents.  We're going to
need this to enforce proper ordering of operations when we enable
realtime rmap.

Declare a new log intent item type (XFS_LI_EFI_RT) and a separate defer
ops for rt extents.  This keeps the ondisk artifacts and processing code
completely separate between the rt and non-rt cases.  Hopefully this
will make it easier to debug filesystem problems.

Previous versions of this patch accomplished this by setting the high
bit in each rt EFI extent.  This was found to be less transparent by
reviewers.

[Contains a bug fix and cleanups from hch]

Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/defer_item.c
libxfs/xfs_alloc.c
libxfs/xfs_alloc.h
libxfs/xfs_defer.c
libxfs/xfs_defer.h
libxfs/xfs_log_format.h

index 0081d8ae7d05196db7203821feeb25049a18b40e..c0ea0fedcf82d11f011740a632f4b26850a83d75 100644 (file)
@@ -88,12 +88,21 @@ xfs_extent_free_defer_add(
 
        trace_xfs_extent_free_defer(mp, xefi);
 
-       if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
+       if (xfs_efi_is_realtime(xefi))
+               optype = XFS_DEFER_OPS_TYPE_FREE_RT;
+       else if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
                optype = XFS_DEFER_OPS_TYPE_AGFL_FREE;
        else
                optype = XFS_DEFER_OPS_TYPE_FREE;
 
-       xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
+       if (xfs_efi_is_realtime(xefi)) {
+               xfs_rgnumber_t          rgno;
+
+               rgno = xfs_rtb_to_rgno(mp, xefi->xefi_startblock);
+               xefi->xefi_rtg = xfs_rtgroup_get(mp, rgno);
+       } else {
+               xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
+       }
        *dfpp = xfs_defer_add(tp, optype, &xefi->xefi_list);
 }
 
@@ -159,6 +168,69 @@ const struct xfs_defer_op_type xfs_extent_free_defer_type = {
        .cancel_item    = xfs_extent_free_cancel_item,
 };
 
+/* Sort bmap items by rtgroup. */
+static int
+xfs_rtextent_free_diff_items(
+       void                            *priv,
+       const struct list_head          *a,
+       const struct list_head          *b)
+{
+       struct xfs_extent_free_item     *ra = xefi_entry(a);
+       struct xfs_extent_free_item     *rb = xefi_entry(b);
+
+       return ra->xefi_rtg->rtg_rgno - rb->xefi_rtg->rtg_rgno;
+}
+
+static struct xfs_log_item *
+xfs_rtextent_free_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_rtextent_free_diff_items);
+       return NULL;
+}
+
+/* Cancel a free extent. */
+STATIC void
+xfs_rtextent_free_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_extent_free_item     *xefi = xefi_entry(item);
+
+       xfs_rtgroup_put(xefi->xefi_rtg);
+       kmem_cache_free(xfs_extfree_item_cache, xefi);
+}
+
+STATIC int
+xfs_rtextent_free_finish_item(
+       struct xfs_trans                *tp,
+       struct xfs_log_item             *done,
+       struct list_head                *item,
+       struct xfs_btree_cur            **state)
+{
+       struct xfs_extent_free_item     *xefi = xefi_entry(item);
+       int                             error;
+
+       error = xfs_rtfree_blocks(tp, xefi->xefi_startblock,
+                       xefi->xefi_blockcount);
+       if (error != -EAGAIN)
+               xfs_rtextent_free_cancel_item(item);
+       return error;
+}
+
+const struct xfs_defer_op_type xfs_rtextent_free_defer_type = {
+       .create_intent  = xfs_rtextent_free_create_intent,
+       .abort_intent   = xfs_extent_free_abort_intent,
+       .create_done    = xfs_extent_free_create_done,
+       .finish_item    = xfs_rtextent_free_finish_item,
+       .cancel_item    = xfs_rtextent_free_cancel_item,
+};
+
 /*
  * AGFL blocks are accounted differently in the reserve pools and are not
  * inserted into the busy extent list.
index d7ff1ec7c2b02ef478ea849958356ba9b465dc1b..5578921c6cae26abe68a9664ad40e2d477c9b239 100644 (file)
@@ -2563,10 +2563,18 @@ xfs_defer_extent_free(
        ASSERT(len <= XFS_MAX_BMBT_EXTLEN);
        ASSERT(!isnullstartblock(bno));
        ASSERT(!(free_flags & ~XFS_FREE_EXTENT_ALL_FLAGS));
-       ASSERT(type != XFS_AG_RESV_AGFL);
 
-       if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
-               return -EFSCORRUPTED;
+       if (free_flags & XFS_FREE_EXTENT_REALTIME) {
+               if (type != XFS_AG_RESV_NONE) {
+                       ASSERT(type == XFS_AG_RESV_NONE);
+                       return -EFSCORRUPTED;
+               }
+               if (XFS_IS_CORRUPT(mp, !xfs_verify_rtbext(mp, bno, len)))
+                       return -EFSCORRUPTED;
+       } else {
+               if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
+                       return -EFSCORRUPTED;
+       }
 
        xefi = kmem_cache_zalloc(xfs_extfree_item_cache,
                               GFP_KERNEL | __GFP_NOFAIL);
@@ -2575,6 +2583,8 @@ xfs_defer_extent_free(
        xefi->xefi_agresv = type;
        if (free_flags & XFS_FREE_EXTENT_SKIP_DISCARD)
                xefi->xefi_flags |= XFS_EFI_SKIP_DISCARD;
+       if (free_flags & XFS_FREE_EXTENT_REALTIME)
+               xefi->xefi_flags |= XFS_EFI_REALTIME;
        if (oinfo) {
                ASSERT(oinfo->oi_offset == 0);
 
index 26d6a7192fe9f9e42853809417d0369596823977..879cc26c6c17b9b2a71b1b86e997fc9ab3248ffe 100644 (file)
@@ -240,7 +240,11 @@ int xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
 /* Don't issue a discard for the blocks freed. */
 #define XFS_FREE_EXTENT_SKIP_DISCARD   (1U << 0)
 
-#define XFS_FREE_EXTENT_ALL_FLAGS      (XFS_FREE_EXTENT_SKIP_DISCARD)
+/* Free blocks on the realtime device. */
+#define XFS_FREE_EXTENT_REALTIME       (1U << 1)
+
+#define XFS_FREE_EXTENT_ALL_FLAGS      (XFS_FREE_EXTENT_SKIP_DISCARD | \
+                                        XFS_FREE_EXTENT_REALTIME)
 
 /*
  * List of extents to be free "later".
@@ -251,7 +255,10 @@ struct xfs_extent_free_item {
        uint64_t                xefi_owner;
        xfs_fsblock_t           xefi_startblock;/* starting fs block number */
        xfs_extlen_t            xefi_blockcount;/* number of blocks in extent */
-       struct xfs_perag        *xefi_pag;
+       union {
+               struct xfs_perag        *xefi_pag;
+               struct xfs_rtgroup      *xefi_rtg;
+       };
        unsigned int            xefi_flags;
        enum xfs_ag_resv_type   xefi_agresv;
 };
@@ -260,6 +267,12 @@ struct xfs_extent_free_item {
 #define XFS_EFI_ATTR_FORK      (1U << 1) /* freeing attr fork block */
 #define XFS_EFI_BMBT_BLOCK     (1U << 2) /* freeing bmap btree block */
 #define XFS_EFI_CANCELLED      (1U << 3) /* dont actually free the space */
+#define XFS_EFI_REALTIME       (1U << 4) /* freeing realtime extent */
+
+static inline bool xfs_efi_is_realtime(const struct xfs_extent_free_item *xefi)
+{
+       return xefi->xefi_flags & XFS_EFI_REALTIME;
+}
 
 struct xfs_alloc_autoreap {
        struct xfs_defer_pending        *dfp;
index b193a8f8b33ab60c55c841cc486f5512a1bfb26d..fb5e72640dbc58485671c191c40c659ce8927682 100644 (file)
@@ -230,7 +230,7 @@ static const struct xfs_defer_op_type xfs_barrier_defer_type = {
        .cancel_item    = xfs_defer_barrier_cancel_item,
 };
 
-static const struct xfs_defer_op_type *defer_op_types[] = {
+static const struct xfs_defer_op_type *defer_op_types[XFS_DEFER_OPS_TYPE_MAX] = {
        [XFS_DEFER_OPS_TYPE_BMAP]       = &xfs_bmap_update_defer_type,
        [XFS_DEFER_OPS_TYPE_REFCOUNT]   = &xfs_refcount_update_defer_type,
        [XFS_DEFER_OPS_TYPE_RMAP]       = &xfs_rmap_update_defer_type,
@@ -239,6 +239,9 @@ static const struct xfs_defer_op_type *defer_op_types[] = {
        [XFS_DEFER_OPS_TYPE_ATTR]       = &xfs_attr_defer_type,
        [XFS_DEFER_OPS_TYPE_BARRIER]    = &xfs_barrier_defer_type,
        [XFS_DEFER_OPS_TYPE_SWAPEXT]    = &xfs_swapext_defer_type,
+#ifdef CONFIG_XFS_RT
+       [XFS_DEFER_OPS_TYPE_FREE_RT]    = &xfs_rtextent_free_defer_type,
+#endif
 };
 
 /*
@@ -258,6 +261,11 @@ xfs_defer_create_intent(
        if (dfp->dfp_intent)
                return 1;
 
+       if (!ops) {
+               ASSERT(ops != NULL);
+               return -EFSCORRUPTED;
+       }
+
        lip = ops->create_intent(tp, &dfp->dfp_work, dfp->dfp_count, sort);
        if (!lip)
                return 0;
index fd75540a6ca379a1754e9b5ca961946026dd5e07..93f899fd2f21d3216e03034ba74bbb2a7fe482c2 100644 (file)
@@ -22,6 +22,7 @@ enum xfs_defer_ops_type {
        XFS_DEFER_OPS_TYPE_ATTR,
        XFS_DEFER_OPS_TYPE_BARRIER,
        XFS_DEFER_OPS_TYPE_SWAPEXT,
+       XFS_DEFER_OPS_TYPE_FREE_RT,
        XFS_DEFER_OPS_TYPE_MAX,
 };
 
@@ -79,6 +80,7 @@ extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;
 extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
 extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
 extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
+extern const struct xfs_defer_op_type xfs_rtextent_free_defer_type;
 extern const struct xfs_defer_op_type xfs_attr_defer_type;
 extern const struct xfs_defer_op_type xfs_swapext_defer_type;
 
index bded03634e53d9156147b504f71027ef5859fd0c..1f5fe4a588eca2930f67eea100805a238de67248 100644 (file)
@@ -248,6 +248,8 @@ typedef struct xfs_trans_header {
 #define        XFS_LI_ATTRD            0x1247  /* attr set/remove done */
 #define        XFS_LI_SXI              0x1248  /* extent swap intent */
 #define        XFS_LI_SXD              0x1249  /* extent swap done */
+#define        XFS_LI_EFI_RT           0x124a  /* realtime extent free intent */
+#define        XFS_LI_EFD_RT           0x124b  /* realtime extent free done */
 
 #define XFS_LI_TYPE_DESC \
        { XFS_LI_EFI,           "XFS_LI_EFI" }, \
@@ -267,7 +269,9 @@ typedef struct xfs_trans_header {
        { XFS_LI_ATTRI,         "XFS_LI_ATTRI" }, \
        { XFS_LI_ATTRD,         "XFS_LI_ATTRD" }, \
        { XFS_LI_SXI,           "XFS_LI_SXI" }, \
-       { XFS_LI_SXD,           "XFS_LI_SXD" }
+       { XFS_LI_SXD,           "XFS_LI_SXD" }, \
+       { XFS_LI_EFI_RT,        "XFS_LI_EFI_RT" }, \
+       { XFS_LI_EFD_RT,        "XFS_LI_EFD_RT" }
 
 /*
  * Inode Log Item Format definitions.