]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: add a realtime flag to the rmap update log redo items
authorDarrick J. Wong <djwong@kernel.org>
Tue, 15 Oct 2024 19:39:49 +0000 (12:39 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 5 Nov 2024 21:36:23 +0000 (13:36 -0800)
Extend the rmap update (RUI) log items to handle realtime volumes by
adding a new log intent item type.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/libxfs/xfs_defer.h
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/libxfs/xfs_log_recover.h
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/libxfs/xfs_rmap.c
fs/xfs/libxfs/xfs_rmap.h
fs/xfs/scrub/alloc_repair.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_rmap_item.c

index ec51b8465e61cba15bbd99791e2596bc119b65a7..1e2477eaa5a844e1cc0e7338bb2a7da28a41e6d8 100644 (file)
@@ -69,6 +69,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_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;
 extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
 extern const struct xfs_defer_op_type xfs_rtextent_free_defer_type;
index 15dec19b6c32ad7aa182c378f3e0563075dfc6d7..a7e0e479454d3d5196abaea0094d0d8fc7b1492a 100644 (file)
@@ -250,6 +250,8 @@ typedef struct xfs_trans_header {
 #define        XFS_LI_XMD              0x1249  /* mapping exchange done */
 #define        XFS_LI_EFI_RT           0x124a  /* realtime extent free intent */
 #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_TYPE_DESC \
        { XFS_LI_EFI,           "XFS_LI_EFI" }, \
@@ -271,7 +273,9 @@ typedef struct xfs_trans_header {
        { XFS_LI_XMI,           "XFS_LI_XMI" }, \
        { XFS_LI_XMD,           "XFS_LI_XMD" }, \
        { XFS_LI_EFI_RT,        "XFS_LI_EFI_RT" }, \
-       { XFS_LI_EFD_RT,        "XFS_LI_EFD_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" }
 
 /*
  * Inode Log Item Format definitions.
index 5397a8ff004df8ef8c791ad349276dd15092f518..abc705aff26dfeb2ec3f7271e8fdb06b2695ed3d 100644 (file)
@@ -79,6 +79,8 @@ extern const struct xlog_recover_item_ops xlog_xmi_item_ops;
 extern const struct xlog_recover_item_ops xlog_xmd_item_ops;
 extern const struct xlog_recover_item_ops xlog_rtefi_item_ops;
 extern const struct xlog_recover_item_ops xlog_rtefd_item_ops;
+extern const struct xlog_recover_item_ops xlog_rtrui_item_ops;
+extern const struct xlog_recover_item_ops xlog_rtrud_item_ops;
 
 /*
  * Macros, structures, prototypes for internal log manager use.
index 26d3d7956e069d39a0c2f6a55539b0fb0e4f84f0..bbb86dc9a25c7f58fa56f5bce78a8ee7a80672eb 100644 (file)
@@ -1831,7 +1831,7 @@ xfs_refcount_alloc_cow_extent(
        __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len);
 
        /* Add rmap entry */
-       xfs_rmap_alloc_extent(tp, fsb, len, XFS_RMAP_OWN_COW);
+       xfs_rmap_alloc_extent(tp, false, fsb, len, XFS_RMAP_OWN_COW);
 }
 
 /* Forget a CoW staging event in the refcount btree. */
@@ -1847,7 +1847,7 @@ xfs_refcount_free_cow_extent(
                return;
 
        /* Remove rmap entry */
-       xfs_rmap_free_extent(tp, fsb, len, XFS_RMAP_OWN_COW);
+       xfs_rmap_free_extent(tp, false, fsb, len, XFS_RMAP_OWN_COW);
        __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len);
 }
 
index b107adc9ecd4a3edafbd240d34bfc35d8808b66a..0e0c593c1f68268ed03b1fca88a11d3bae976d27 100644 (file)
@@ -2712,6 +2712,7 @@ __xfs_rmap_add(
        struct xfs_trans                *tp,
        enum xfs_rmap_intent_type       type,
        uint64_t                        owner,
+       bool                            isrt,
        int                             whichfork,
        struct xfs_bmbt_irec            *bmap)
 {
@@ -2723,6 +2724,7 @@ __xfs_rmap_add(
        ri->ri_owner = owner;
        ri->ri_whichfork = whichfork;
        ri->ri_bmap = *bmap;
+       ri->ri_realtime = isrt;
 
        xfs_rmap_defer_add(tp, ri);
 }
@@ -2736,6 +2738,7 @@ xfs_rmap_map_extent(
        struct xfs_bmbt_irec    *PREV)
 {
        enum xfs_rmap_intent_type type = XFS_RMAP_MAP;
+       bool                    isrt = xfs_ifork_is_realtime(ip, whichfork);
 
        if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
                return;
@@ -2743,7 +2746,7 @@ xfs_rmap_map_extent(
        if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
                type = XFS_RMAP_MAP_SHARED;
 
-       __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
+       __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV);
 }
 
 /* Unmap an extent out of a file. */
@@ -2755,6 +2758,7 @@ xfs_rmap_unmap_extent(
        struct xfs_bmbt_irec    *PREV)
 {
        enum xfs_rmap_intent_type type = XFS_RMAP_UNMAP;
+       bool                    isrt = xfs_ifork_is_realtime(ip, whichfork);
 
        if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
                return;
@@ -2762,7 +2766,7 @@ xfs_rmap_unmap_extent(
        if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
                type = XFS_RMAP_UNMAP_SHARED;
 
-       __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
+       __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV);
 }
 
 /*
@@ -2780,6 +2784,7 @@ xfs_rmap_convert_extent(
        struct xfs_bmbt_irec    *PREV)
 {
        enum xfs_rmap_intent_type type = XFS_RMAP_CONVERT;
+       bool                    isrt = xfs_ifork_is_realtime(ip, whichfork);
 
        if (!xfs_rmap_update_is_needed(mp, whichfork))
                return;
@@ -2787,13 +2792,14 @@ xfs_rmap_convert_extent(
        if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
                type = XFS_RMAP_CONVERT_SHARED;
 
-       __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
+       __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV);
 }
 
 /* Schedule the creation of an rmap for non-file data. */
 void
 xfs_rmap_alloc_extent(
        struct xfs_trans        *tp,
+       bool                    isrt,
        xfs_fsblock_t           fsbno,
        xfs_extlen_t            len,
        uint64_t                owner)
@@ -2808,13 +2814,14 @@ xfs_rmap_alloc_extent(
        bmap.br_startoff = 0;
        bmap.br_state = XFS_EXT_NORM;
 
-       __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
+       __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, isrt, XFS_DATA_FORK, &bmap);
 }
 
 /* Schedule the deletion of an rmap for non-file data. */
 void
 xfs_rmap_free_extent(
        struct xfs_trans        *tp,
+       bool                    isrt,
        xfs_fsblock_t           fsbno,
        xfs_extlen_t            len,
        uint64_t                owner)
@@ -2829,7 +2836,7 @@ xfs_rmap_free_extent(
        bmap.br_startoff = 0;
        bmap.br_state = XFS_EXT_NORM;
 
-       __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
+       __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, isrt, XFS_DATA_FORK, &bmap);
 }
 
 /* Compare rmap records.  Returns -1 if a < b, 1 if a > b, and 0 if equal. */
index 1b19f54b65047f3e38903b0a56aaf46b37f116f9..5f39f6e53cd19a7ebf090b993f37ad08ba16cbf9 100644 (file)
@@ -175,6 +175,7 @@ struct xfs_rmap_intent {
        uint64_t                                ri_owner;
        struct xfs_bmbt_irec                    ri_bmap;
        struct xfs_group                        *ri_group;
+       bool                                    ri_realtime;
 };
 
 /* functions for updating the rmapbt based on bmbt map/unmap operations */
@@ -185,9 +186,9 @@ void xfs_rmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip,
 void xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_trans *tp,
                struct xfs_inode *ip, int whichfork,
                struct xfs_bmbt_irec *imap);
-void xfs_rmap_alloc_extent(struct xfs_trans *tp, xfs_fsblock_t fsbno,
+void xfs_rmap_alloc_extent(struct xfs_trans *tp, bool isrt, xfs_fsblock_t fsbno,
                xfs_extlen_t len, uint64_t owner);
-void xfs_rmap_free_extent(struct xfs_trans *tp, xfs_fsblock_t fsbno,
+void xfs_rmap_free_extent(struct xfs_trans *tp, bool isrt, xfs_fsblock_t fsbno,
                xfs_extlen_t len, uint64_t owner);
 
 int xfs_rmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
index 11e1e5404fc6dc2e2595b4b127f1d33b834077fc..bed6a09aa79112a9d64cffeba6bb785eb84431a6 100644 (file)
@@ -542,7 +542,7 @@ xrep_abt_dispose_one(
 
        /* Add a deferred rmap for each extent we used. */
        if (resv->used > 0)
-               xfs_rmap_alloc_extent(sc->tp,
+               xfs_rmap_alloc_extent(sc->tp, false,
                                xfs_agbno_to_fsb(pag, resv->agbno), resv->used,
                                XFS_RMAP_OWN_AG);
 
index 0af3d477197b2418170ad99c25dbc695633af9b3..5c95c97519c767923901e779724b2ad5257353e2 100644 (file)
@@ -1820,6 +1820,8 @@ static const struct xlog_recover_item_ops *xlog_recover_item_ops[] = {
        &xlog_xmd_item_ops,
        &xlog_rtefi_item_ops,
        &xlog_rtefd_item_ops,
+       &xlog_rtrui_item_ops,
+       &xlog_rtrud_item_ops,
 };
 
 static const struct xlog_recover_item_ops *
index ac2913a7335871fe85f4072eafe7e43b95f02331..b365520fbb01549de0c835beb273e174dc8473dc 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_ag.h"
 #include "xfs_btree.h"
 #include "xfs_trace.h"
+#include "xfs_rtgroup.h"
 
 struct kmem_cache      *xfs_rui_cache;
 struct kmem_cache      *xfs_rud_cache;
@@ -94,7 +95,9 @@ xfs_rui_item_format(
        ASSERT(atomic_read(&ruip->rui_next_extent) ==
                        ruip->rui_format.rui_nextents);
 
-       ruip->rui_format.rui_type = XFS_LI_RUI;
+       ASSERT(lip->li_type == XFS_LI_RUI || lip->li_type == XFS_LI_RUI_RT);
+
+       ruip->rui_format.rui_type = lip->li_type;
        ruip->rui_format.rui_size = 1;
 
        xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUI_FORMAT, &ruip->rui_format,
@@ -137,12 +140,15 @@ xfs_rui_item_release(
 STATIC struct xfs_rui_log_item *
 xfs_rui_init(
        struct xfs_mount                *mp,
+       unsigned short                  item_type,
        uint                            nextents)
 
 {
        struct xfs_rui_log_item         *ruip;
 
        ASSERT(nextents > 0);
+       ASSERT(item_type == XFS_LI_RUI || item_type == XFS_LI_RUI_RT);
+
        if (nextents > XFS_RUI_MAX_FAST_EXTENTS)
                ruip = kzalloc(xfs_rui_log_item_sizeof(nextents),
                                GFP_KERNEL | __GFP_NOFAIL);
@@ -150,7 +156,7 @@ xfs_rui_init(
                ruip = kmem_cache_zalloc(xfs_rui_cache,
                                         GFP_KERNEL | __GFP_NOFAIL);
 
-       xfs_log_item_init(mp, &ruip->rui_item, XFS_LI_RUI, &xfs_rui_item_ops);
+       xfs_log_item_init(mp, &ruip->rui_item, item_type, &xfs_rui_item_ops);
        ruip->rui_format.rui_nextents = nextents;
        ruip->rui_format.rui_id = (uintptr_t)(void *)ruip;
        atomic_set(&ruip->rui_next_extent, 0);
@@ -189,7 +195,9 @@ xfs_rud_item_format(
        struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
        struct xfs_log_iovec    *vecp = NULL;
 
-       rudp->rud_format.rud_type = XFS_LI_RUD;
+       ASSERT(lip->li_type == XFS_LI_RUD || lip->li_type == XFS_LI_RUD_RT);
+
+       rudp->rud_format.rud_type = lip->li_type;
        rudp->rud_format.rud_size = 1;
 
        xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUD_FORMAT, &rudp->rud_format,
@@ -233,6 +241,14 @@ static inline struct xfs_rmap_intent *ri_entry(const struct list_head *e)
        return list_entry(e, struct xfs_rmap_intent, ri_list);
 }
 
+static inline bool
+xfs_rui_item_isrt(const struct xfs_log_item *lip)
+{
+       ASSERT(lip->li_type == XFS_LI_RUI || lip->li_type == XFS_LI_RUI_RT);
+
+       return lip->li_type == XFS_LI_RUI_RT;
+}
+
 /* Sort rmap intents by AG. */
 static int
 xfs_rmap_update_diff_items(
@@ -305,18 +321,20 @@ xfs_rmap_update_log_item(
 }
 
 static struct xfs_log_item *
-xfs_rmap_update_create_intent(
+__xfs_rmap_update_create_intent(
        struct xfs_trans                *tp,
        struct list_head                *items,
        unsigned int                    count,
-       bool                            sort)
+       bool                            sort,
+       unsigned short                  item_type)
 {
        struct xfs_mount                *mp = tp->t_mountp;
-       struct xfs_rui_log_item         *ruip = xfs_rui_init(mp, count);
+       struct xfs_rui_log_item         *ruip;
        struct xfs_rmap_intent          *ri;
 
        ASSERT(count > 0);
 
+       ruip = xfs_rui_init(mp, item_type, count);
        if (sort)
                list_sort(mp, items, xfs_rmap_update_diff_items);
        list_for_each_entry(ri, items, ri_list)
@@ -324,6 +342,23 @@ xfs_rmap_update_create_intent(
        return &ruip->rui_item;
 }
 
+static struct xfs_log_item *
+xfs_rmap_update_create_intent(
+       struct xfs_trans                *tp,
+       struct list_head                *items,
+       unsigned int                    count,
+       bool                            sort)
+{
+       return __xfs_rmap_update_create_intent(tp, items, count, sort,
+                       XFS_LI_RUI);
+}
+
+static inline unsigned short
+xfs_rud_type_from_rui(const struct xfs_rui_log_item *ruip)
+{
+       return xfs_rui_item_isrt(&ruip->rui_item) ? XFS_LI_RUD_RT : XFS_LI_RUD;
+}
+
 /* Get an RUD so we can process all the deferred rmap updates. */
 static struct xfs_log_item *
 xfs_rmap_update_create_done(
@@ -335,8 +370,8 @@ xfs_rmap_update_create_done(
        struct xfs_rud_log_item         *rudp;
 
        rudp = kmem_cache_zalloc(xfs_rud_cache, GFP_KERNEL | __GFP_NOFAIL);
-       xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD,
-                         &xfs_rud_item_ops);
+       xfs_log_item_init(tp->t_mountp, &rudp->rud_item,
+                       xfs_rud_type_from_rui(ruip), &xfs_rud_item_ops);
        rudp->rud_ruip = ruip;
        rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id;
 
@@ -351,11 +386,20 @@ xfs_rmap_defer_add(
 {
        struct xfs_mount        *mp = tp->t_mountp;
 
+       /*
+        * Deferred rmap 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.
+        */
        ri->ri_group = xfs_group_intent_get(mp, ri->ri_bmap.br_startblock,
-                       XG_TYPE_AG);
+                       ri->ri_realtime ? XG_TYPE_RTG : XG_TYPE_AG);
 
        trace_xfs_rmap_defer(mp, ri);
-       xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
+       xfs_defer_add(tp, &ri->ri_list, ri->ri_realtime ?
+                       &xfs_rtrmap_update_defer_type :
+                       &xfs_rmap_update_defer_type);
 }
 
 /* Cancel a deferred rmap update. */
@@ -566,10 +610,12 @@ xfs_rmap_relog_intent(
        struct xfs_map_extent           *map;
        unsigned int                    count;
 
+       ASSERT(intent->li_type == XFS_LI_RUI || intent->li_type == XFS_LI_RUI_RT);
+
        count = RUI_ITEM(intent)->rui_format.rui_nextents;
        map = RUI_ITEM(intent)->rui_format.rui_extents;
 
-       ruip = xfs_rui_init(tp->t_mountp, count);
+       ruip = xfs_rui_init(tp->t_mountp, intent->li_type, count);
        memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map));
        atomic_set(&ruip->rui_next_extent, count);
 
@@ -589,6 +635,47 @@ const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
        .relog_intent   = xfs_rmap_relog_intent,
 };
 
+#ifdef CONFIG_XFS_RT
+static struct xfs_log_item *
+xfs_rtrmap_update_create_intent(
+       struct xfs_trans                *tp,
+       struct list_head                *items,
+       unsigned int                    count,
+       bool                            sort)
+{
+       return __xfs_rmap_update_create_intent(tp, items, count, sort,
+                       XFS_LI_RUI_RT);
+}
+
+/* Clean up after calling xfs_rmap_finish_one. */
+STATIC void
+xfs_rtrmap_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_rtrmap_update_defer_type = {
+       .name           = "rtrmap",
+       .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
+       .create_intent  = xfs_rtrmap_update_create_intent,
+       .abort_intent   = xfs_rmap_update_abort_intent,
+       .create_done    = xfs_rmap_update_create_done,
+       .finish_item    = xfs_rmap_update_finish_item,
+       .finish_cleanup = xfs_rtrmap_finish_one_cleanup,
+       .cancel_item    = xfs_rmap_update_cancel_item,
+       .recover_work   = xfs_rmap_recover_work,
+       .relog_intent   = xfs_rmap_relog_intent,
+};
+#else
+const struct xfs_defer_op_type xfs_rtrmap_update_defer_type = {
+       .name           = "rtrmap",
+};
+#endif
+
 STATIC bool
 xfs_rui_item_match(
        struct xfs_log_item     *lip,
@@ -654,7 +741,7 @@ xlog_recover_rui_commit_pass2(
                return -EFSCORRUPTED;
        }
 
-       ruip = xfs_rui_init(mp, rui_formatp->rui_nextents);
+       ruip = xfs_rui_init(mp, ITEM_TYPE(item), rui_formatp->rui_nextents);
        xfs_rui_copy_format(&ruip->rui_format, rui_formatp);
        atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents);
 
@@ -668,6 +755,61 @@ const struct xlog_recover_item_ops xlog_rui_item_ops = {
        .commit_pass2           = xlog_recover_rui_commit_pass2,
 };
 
+#ifdef CONFIG_XFS_RT
+STATIC int
+xlog_recover_rtrui_commit_pass2(
+       struct xlog                     *log,
+       struct list_head                *buffer_list,
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       lsn)
+{
+       struct xfs_mount                *mp = log->l_mp;
+       struct xfs_rui_log_item         *ruip;
+       struct xfs_rui_log_format       *rui_formatp;
+       size_t                          len;
+
+       rui_formatp = item->ri_buf[0].i_addr;
+
+       if (item->ri_buf[0].i_len < xfs_rui_log_format_sizeof(0)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
+                               item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+               return -EFSCORRUPTED;
+       }
+
+       len = xfs_rui_log_format_sizeof(rui_formatp->rui_nextents);
+       if (item->ri_buf[0].i_len != len) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
+                               item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+               return -EFSCORRUPTED;
+       }
+
+       ruip = xfs_rui_init(mp, ITEM_TYPE(item), rui_formatp->rui_nextents);
+       xfs_rui_copy_format(&ruip->rui_format, rui_formatp);
+       atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents);
+
+       xlog_recover_intent_item(log, &ruip->rui_item, lsn,
+                       &xfs_rtrmap_update_defer_type);
+       return 0;
+}
+#else
+STATIC int
+xlog_recover_rtrui_commit_pass2(
+       struct xlog                     *log,
+       struct list_head                *buffer_list,
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       lsn)
+{
+       XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
+                       item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+       return -EFSCORRUPTED;
+}
+#endif
+
+const struct xlog_recover_item_ops xlog_rtrui_item_ops = {
+       .item_type              = XFS_LI_RUI_RT,
+       .commit_pass2           = xlog_recover_rtrui_commit_pass2,
+};
+
 /*
  * This routine is called when an RUD format structure is found in a committed
  * transaction in the log. Its purpose is to cancel the corresponding RUI if it
@@ -699,3 +841,33 @@ const struct xlog_recover_item_ops xlog_rud_item_ops = {
        .item_type              = XFS_LI_RUD,
        .commit_pass2           = xlog_recover_rud_commit_pass2,
 };
+
+#ifdef CONFIG_XFS_RT
+STATIC int
+xlog_recover_rtrud_commit_pass2(
+       struct xlog                     *log,
+       struct list_head                *buffer_list,
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       lsn)
+{
+       struct xfs_rud_log_format       *rud_formatp;
+
+       rud_formatp = item->ri_buf[0].i_addr;
+       if (item->ri_buf[0].i_len != sizeof(struct xfs_rud_log_format)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
+                               rud_formatp, item->ri_buf[0].i_len);
+               return -EFSCORRUPTED;
+       }
+
+       xlog_recover_release_intent(log, XFS_LI_RUI_RT,
+                       rud_formatp->rud_rui_id);
+       return 0;
+}
+#else
+# define xlog_recover_rtrud_commit_pass2       xlog_recover_rtrui_commit_pass2
+#endif
+
+const struct xlog_recover_item_ops xlog_rtrud_item_ops = {
+       .item_type              = XFS_LI_RUD_RT,
+       .commit_pass2           = xlog_recover_rtrud_commit_pass2,
+};