Merge tag 'xfs-6.9-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[sfrench/cifs-2.6.git] / fs / xfs / libxfs / xfs_rmap.c
index 76bf7f48cb5acf19f00f04307b625afc017364cd..ef16f6f9cef67bee2c4f75587f2d53578c4af582 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_error.h"
 #include "xfs_inode.h"
 #include "xfs_ag.h"
+#include "xfs_health.h"
 
 struct kmem_cache      *xfs_rmap_intent_cache;
 
@@ -56,8 +57,10 @@ xfs_rmap_lookup_le(
        error = xfs_rmap_get_rec(cur, irec, &get_stat);
        if (error)
                return error;
-       if (!get_stat)
+       if (!get_stat) {
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
+       }
 
        return 0;
 }
@@ -132,6 +135,7 @@ xfs_rmap_insert(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
+               xfs_btree_mark_sick(rcur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -145,6 +149,7 @@ xfs_rmap_insert(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
+               xfs_btree_mark_sick(rcur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -174,6 +179,7 @@ xfs_rmap_delete(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
+               xfs_btree_mark_sick(rcur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -182,6 +188,7 @@ xfs_rmap_delete(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
+               xfs_btree_mark_sick(rcur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -208,10 +215,10 @@ xfs_rmap_btrec_to_irec(
 /* Simple checks for rmap records. */
 xfs_failaddr_t
 xfs_rmap_check_irec(
-       struct xfs_btree_cur            *cur,
+       struct xfs_perag                *pag,
        const struct xfs_rmap_irec      *irec)
 {
-       struct xfs_mount                *mp = cur->bc_mp;
+       struct xfs_mount                *mp = pag->pag_mount;
        bool                            is_inode;
        bool                            is_unwritten;
        bool                            is_bmbt;
@@ -226,8 +233,8 @@ xfs_rmap_check_irec(
                        return __this_address;
        } else {
                /* check for valid extent range, including overflow */
-               if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
-                                                      irec->rm_blockcount))
+               if (!xfs_verify_agbext(pag, irec->rm_startblock,
+                                           irec->rm_blockcount))
                        return __this_address;
        }
 
@@ -262,6 +269,16 @@ xfs_rmap_check_irec(
        return NULL;
 }
 
+static inline xfs_failaddr_t
+xfs_rmap_check_btrec(
+       struct xfs_btree_cur            *cur,
+       const struct xfs_rmap_irec      *irec)
+{
+       if (xfs_btree_is_mem_rmap(cur->bc_ops))
+               return xfs_rmap_check_irec(cur->bc_mem.pag, irec);
+       return xfs_rmap_check_irec(cur->bc_ag.pag, irec);
+}
+
 static inline int
 xfs_rmap_complain_bad_rec(
        struct xfs_btree_cur            *cur,
@@ -270,13 +287,18 @@ xfs_rmap_complain_bad_rec(
 {
        struct xfs_mount                *mp = cur->bc_mp;
 
-       xfs_warn(mp,
-               "Reverse Mapping BTree record corruption in AG %d detected at %pS!",
-               cur->bc_ag.pag->pag_agno, fa);
+       if (xfs_btree_is_mem_rmap(cur->bc_ops))
+               xfs_warn(mp,
+ "In-Memory Reverse Mapping BTree record corruption detected at %pS!", fa);
+       else
+               xfs_warn(mp,
+ "Reverse Mapping BTree record corruption in AG %d detected at %pS!",
+                       cur->bc_ag.pag->pag_agno, fa);
        xfs_warn(mp,
                "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
                irec->rm_owner, irec->rm_flags, irec->rm_startblock,
                irec->rm_blockcount);
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
@@ -299,7 +321,7 @@ xfs_rmap_get_rec(
 
        fa = xfs_rmap_btrec_to_irec(rec, irec);
        if (!fa)
-               fa = xfs_rmap_check_irec(cur, irec);
+               fa = xfs_rmap_check_btrec(cur, irec);
        if (fa)
                return xfs_rmap_complain_bad_rec(cur, fa, irec);
 
@@ -512,7 +534,7 @@ xfs_rmap_lookup_le_range(
  */
 static int
 xfs_rmap_free_check_owner(
-       struct xfs_mount        *mp,
+       struct xfs_btree_cur    *cur,
        uint64_t                ltoff,
        struct xfs_rmap_irec    *rec,
        xfs_filblks_t           len,
@@ -520,6 +542,7 @@ xfs_rmap_free_check_owner(
        uint64_t                offset,
        unsigned int            flags)
 {
+       struct xfs_mount        *mp = cur->bc_mp;
        int                     error = 0;
 
        if (owner == XFS_RMAP_OWN_UNKNOWN)
@@ -529,12 +552,14 @@ xfs_rmap_free_check_owner(
        if (XFS_IS_CORRUPT(mp,
                           (flags & XFS_RMAP_UNWRITTEN) !=
                           (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out;
        }
 
        /* Make sure the owner matches what we expect to find in the tree. */
        if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out;
        }
@@ -546,16 +571,19 @@ xfs_rmap_free_check_owner(
        if (flags & XFS_RMAP_BMBT_BLOCK) {
                if (XFS_IS_CORRUPT(mp,
                                   !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out;
                }
        } else {
                if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out;
                }
                if (XFS_IS_CORRUPT(mp,
                                   offset + len > ltoff + rec->rm_blockcount)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -618,6 +646,7 @@ xfs_rmap_unmap(
        if (error)
                goto out_error;
        if (XFS_IS_CORRUPT(mp, i != 1)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
@@ -639,6 +668,7 @@ xfs_rmap_unmap(
                if (XFS_IS_CORRUPT(mp,
                                   bno <
                                   ltrec.rm_startblock + ltrec.rm_blockcount)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -665,6 +695,7 @@ xfs_rmap_unmap(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -677,12 +708,13 @@ xfs_rmap_unmap(
                           ltrec.rm_startblock > bno ||
                           ltrec.rm_startblock + ltrec.rm_blockcount <
                           bno + len)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
 
        /* Check owner information. */
-       error = xfs_rmap_free_check_owner(mp, ltoff, &ltrec, len, owner,
+       error = xfs_rmap_free_check_owner(cur, ltoff, &ltrec, len, owner,
                        offset, flags);
        if (error)
                goto out_error;
@@ -697,6 +729,7 @@ xfs_rmap_unmap(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -788,6 +821,86 @@ out_error:
        return error;
 }
 
+#ifdef CONFIG_XFS_LIVE_HOOKS
+/*
+ * Use a static key here to reduce the overhead of rmapbt live updates.  If
+ * the compiler supports jump labels, the static branch will be replaced by a
+ * nop sled when there are no hook users.  Online fsck is currently the only
+ * caller, so this is a reasonable tradeoff.
+ *
+ * Note: Patching the kernel code requires taking the cpu hotplug lock.  Other
+ * parts of the kernel allocate memory with that lock held, which means that
+ * XFS callers cannot hold any locks that might be used by memory reclaim or
+ * writeback when calling the static_branch_{inc,dec} functions.
+ */
+DEFINE_STATIC_XFS_HOOK_SWITCH(xfs_rmap_hooks_switch);
+
+void
+xfs_rmap_hook_disable(void)
+{
+       xfs_hooks_switch_off(&xfs_rmap_hooks_switch);
+}
+
+void
+xfs_rmap_hook_enable(void)
+{
+       xfs_hooks_switch_on(&xfs_rmap_hooks_switch);
+}
+
+/* Call downstream hooks for a reverse mapping update. */
+static inline void
+xfs_rmap_update_hook(
+       struct xfs_trans                *tp,
+       struct xfs_perag                *pag,
+       enum xfs_rmap_intent_type       op,
+       xfs_agblock_t                   startblock,
+       xfs_extlen_t                    blockcount,
+       bool                            unwritten,
+       const struct xfs_owner_info     *oinfo)
+{
+       if (xfs_hooks_switched_on(&xfs_rmap_hooks_switch)) {
+               struct xfs_rmap_update_params   p = {
+                       .startblock     = startblock,
+                       .blockcount     = blockcount,
+                       .unwritten      = unwritten,
+                       .oinfo          = *oinfo, /* struct copy */
+               };
+
+               if (pag)
+                       xfs_hooks_call(&pag->pag_rmap_update_hooks, op, &p);
+       }
+}
+
+/* Call the specified function during a reverse mapping update. */
+int
+xfs_rmap_hook_add(
+       struct xfs_perag        *pag,
+       struct xfs_rmap_hook    *hook)
+{
+       return xfs_hooks_add(&pag->pag_rmap_update_hooks, &hook->rmap_hook);
+}
+
+/* Stop calling the specified function during a reverse mapping update. */
+void
+xfs_rmap_hook_del(
+       struct xfs_perag        *pag,
+       struct xfs_rmap_hook    *hook)
+{
+       xfs_hooks_del(&pag->pag_rmap_update_hooks, &hook->rmap_hook);
+}
+
+/* Configure rmap update hook functions. */
+void
+xfs_rmap_hook_setup(
+       struct xfs_rmap_hook    *hook,
+       notifier_fn_t           mod_fn)
+{
+       xfs_hook_setup(&hook->rmap_hook, mod_fn);
+}
+#else
+# define xfs_rmap_update_hook(t, p, o, s, b, u, oi)    do { } while (0)
+#endif /* CONFIG_XFS_LIVE_HOOKS */
+
 /*
  * Remove a reference to an extent in the rmap btree.
  */
@@ -808,7 +921,7 @@ xfs_rmap_free(
                return 0;
 
        cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
-
+       xfs_rmap_update_hook(tp, pag, XFS_RMAP_UNMAP, bno, len, false, oinfo);
        error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
 
        xfs_btree_del_cursor(cur, error);
@@ -900,6 +1013,7 @@ xfs_rmap_map(
        if (XFS_IS_CORRUPT(mp,
                           have_lt != 0 &&
                           ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
@@ -917,10 +1031,12 @@ xfs_rmap_map(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
                if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -974,6 +1090,7 @@ xfs_rmap_map(
                        if (error)
                                goto out_error;
                        if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               xfs_btree_mark_sick(cur);
                                error = -EFSCORRUPTED;
                                goto out_error;
                        }
@@ -1021,6 +1138,7 @@ xfs_rmap_map(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -1055,6 +1173,7 @@ xfs_rmap_alloc(
                return 0;
 
        cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
+       xfs_rmap_update_hook(tp, pag, XFS_RMAP_MAP, bno, len, false, oinfo);
        error = xfs_rmap_map(cur, bno, len, false, oinfo);
 
        xfs_btree_del_cursor(cur, error);
@@ -1116,6 +1235,7 @@ xfs_rmap_convert(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(mp, i != 1)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -1153,12 +1273,14 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
                if (XFS_IS_CORRUPT(mp,
                                   LEFT.rm_startblock + LEFT.rm_blockcount >
                                   bno)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1181,6 +1303,7 @@ xfs_rmap_convert(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(mp, i != 1)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -1193,10 +1316,12 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
                if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1227,6 +1352,7 @@ xfs_rmap_convert(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(mp, i != 1)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -1246,6 +1372,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1257,6 +1384,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1264,6 +1392,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1275,6 +1404,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1282,6 +1412,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1305,6 +1436,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1312,6 +1444,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1331,6 +1464,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1342,6 +1476,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1349,6 +1484,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1419,6 +1555,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1461,6 +1598,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 0)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1476,6 +1614,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1509,6 +1648,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1522,6 +1662,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 0)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1534,6 +1675,7 @@ xfs_rmap_convert(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1606,6 +1748,7 @@ xfs_rmap_convert_shared(
        if (error)
                goto done;
        if (XFS_IS_CORRUPT(mp, i != 1)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto done;
        }
@@ -1634,6 +1777,7 @@ xfs_rmap_convert_shared(
                if (XFS_IS_CORRUPT(mp,
                                   LEFT.rm_startblock + LEFT.rm_blockcount >
                                   bno)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1652,10 +1796,12 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
                if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1706,6 +1852,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1732,6 +1879,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1758,6 +1906,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1781,6 +1930,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1816,6 +1966,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1861,6 +2012,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1896,6 +2048,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -1934,6 +2087,7 @@ xfs_rmap_convert_shared(
                if (error)
                        goto done;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -2023,6 +2177,7 @@ xfs_rmap_unmap_shared(
        if (error)
                goto out_error;
        if (XFS_IS_CORRUPT(mp, i != 1)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
@@ -2033,12 +2188,14 @@ xfs_rmap_unmap_shared(
                           ltrec.rm_startblock > bno ||
                           ltrec.rm_startblock + ltrec.rm_blockcount <
                           bno + len)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
 
        /* Make sure the owner matches what we expect to find in the tree. */
        if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
@@ -2047,16 +2204,19 @@ xfs_rmap_unmap_shared(
        if (XFS_IS_CORRUPT(mp,
                           (flags & XFS_RMAP_UNWRITTEN) !=
                           (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
 
        /* Check the offset. */
        if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
        if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto out_error;
        }
@@ -2113,6 +2273,7 @@ xfs_rmap_unmap_shared(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -2142,6 +2303,7 @@ xfs_rmap_unmap_shared(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -2221,6 +2383,7 @@ xfs_rmap_map_shared(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -2273,6 +2436,7 @@ xfs_rmap_map_shared(
                if (error)
                        goto out_error;
                if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       xfs_btree_mark_sick(cur);
                        error = -EFSCORRUPTED;
                        goto out_error;
                }
@@ -2335,15 +2499,12 @@ xfs_rmap_map_raw(
 {
        struct xfs_owner_info   oinfo;
 
-       oinfo.oi_owner = rmap->rm_owner;
-       oinfo.oi_offset = rmap->rm_offset;
-       oinfo.oi_flags = 0;
-       if (rmap->rm_flags & XFS_RMAP_ATTR_FORK)
-               oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
-       if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK)
-               oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
+       xfs_owner_info_pack(&oinfo, rmap->rm_owner, rmap->rm_offset,
+                       rmap->rm_flags);
 
-       if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
+       if ((rmap->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK |
+                              XFS_RMAP_UNWRITTEN)) ||
+           XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
                return xfs_rmap_map(cur, rmap->rm_startblock,
                                rmap->rm_blockcount,
                                rmap->rm_flags & XFS_RMAP_UNWRITTEN,
@@ -2373,7 +2534,7 @@ xfs_rmap_query_range_helper(
 
        fa = xfs_rmap_btrec_to_irec(rec, &irec);
        if (!fa)
-               fa = xfs_rmap_check_irec(cur, &irec);
+               fa = xfs_rmap_check_btrec(cur, &irec);
        if (fa)
                return xfs_rmap_complain_bad_rec(cur, fa, &irec);
 
@@ -2428,6 +2589,38 @@ xfs_rmap_finish_one_cleanup(
                xfs_trans_brelse(tp, agbp);
 }
 
+/* Commit an rmap operation into the ondisk tree. */
+int
+__xfs_rmap_finish_intent(
+       struct xfs_btree_cur            *rcur,
+       enum xfs_rmap_intent_type       op,
+       xfs_agblock_t                   bno,
+       xfs_extlen_t                    len,
+       const struct xfs_owner_info     *oinfo,
+       bool                            unwritten)
+{
+       switch (op) {
+       case XFS_RMAP_ALLOC:
+       case XFS_RMAP_MAP:
+               return xfs_rmap_map(rcur, bno, len, unwritten, oinfo);
+       case XFS_RMAP_MAP_SHARED:
+               return xfs_rmap_map_shared(rcur, bno, len, unwritten, oinfo);
+       case XFS_RMAP_FREE:
+       case XFS_RMAP_UNMAP:
+               return xfs_rmap_unmap(rcur, bno, len, unwritten, oinfo);
+       case XFS_RMAP_UNMAP_SHARED:
+               return xfs_rmap_unmap_shared(rcur, bno, len, unwritten, oinfo);
+       case XFS_RMAP_CONVERT:
+               return xfs_rmap_convert(rcur, bno, len, !unwritten, oinfo);
+       case XFS_RMAP_CONVERT_SHARED:
+               return xfs_rmap_convert_shared(rcur, bno, len, !unwritten,
+                               oinfo);
+       default:
+               ASSERT(0);
+               return -EFSCORRUPTED;
+       }
+}
+
 /*
  * Process one of the deferred rmap operations.  We pass back the
  * btree cursor to maintain our lock on the rmapbt between calls.
@@ -2476,10 +2669,14 @@ xfs_rmap_finish_one(
                 * allocate blocks.
                 */
                error = xfs_free_extent_fix_freelist(tp, ri->ri_pag, &agbp);
-               if (error)
+               if (error) {
+                       xfs_ag_mark_sick(ri->ri_pag, XFS_SICK_AG_AGFL);
                        return error;
-               if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
+               }
+               if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) {
+                       xfs_ag_mark_sick(ri->ri_pag, XFS_SICK_AG_AGFL);
                        return -EFSCORRUPTED;
+               }
 
                rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, ri->ri_pag);
        }
@@ -2490,39 +2687,14 @@ xfs_rmap_finish_one(
        unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
        bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, ri->ri_bmap.br_startblock);
 
-       switch (ri->ri_type) {
-       case XFS_RMAP_ALLOC:
-       case XFS_RMAP_MAP:
-               error = xfs_rmap_map(rcur, bno, ri->ri_bmap.br_blockcount,
-                               unwritten, &oinfo);
-               break;
-       case XFS_RMAP_MAP_SHARED:
-               error = xfs_rmap_map_shared(rcur, bno,
-                               ri->ri_bmap.br_blockcount, unwritten, &oinfo);
-               break;
-       case XFS_RMAP_FREE:
-       case XFS_RMAP_UNMAP:
-               error = xfs_rmap_unmap(rcur, bno, ri->ri_bmap.br_blockcount,
-                               unwritten, &oinfo);
-               break;
-       case XFS_RMAP_UNMAP_SHARED:
-               error = xfs_rmap_unmap_shared(rcur, bno,
-                               ri->ri_bmap.br_blockcount, unwritten, &oinfo);
-               break;
-       case XFS_RMAP_CONVERT:
-               error = xfs_rmap_convert(rcur, bno, ri->ri_bmap.br_blockcount,
-                               !unwritten, &oinfo);
-               break;
-       case XFS_RMAP_CONVERT_SHARED:
-               error = xfs_rmap_convert_shared(rcur, bno,
-                               ri->ri_bmap.br_blockcount, !unwritten, &oinfo);
-               break;
-       default:
-               ASSERT(0);
-               error = -EFSCORRUPTED;
-       }
+       error = __xfs_rmap_finish_intent(rcur, ri->ri_type, bno,
+                       ri->ri_bmap.br_blockcount, &oinfo, unwritten);
+       if (error)
+               return error;
 
-       return error;
+       xfs_rmap_update_hook(tp, ri->ri_pag, ri->ri_type, bno,
+                       ri->ri_bmap.br_blockcount, unwritten, &oinfo);
+       return 0;
 }
 
 /*
@@ -2559,7 +2731,7 @@ __xfs_rmap_add(
                        bmap->br_blockcount,
                        bmap->br_state);
 
-       ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
+       ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_KERNEL | __GFP_NOFAIL);
        INIT_LIST_HEAD(&ri->ri_list);
        ri->ri_type = type;
        ri->ri_owner = owner;