]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: make metabtree reservations global
authorChristoph Hellwig <hch@lst.de>
Mon, 6 Jan 2025 13:49:40 +0000 (14:49 +0100)
committerChristoph Hellwig <hch@lst.de>
Mon, 3 Feb 2025 04:49:08 +0000 (05:49 +0100)
Currently each metabtree inode has it's own space reservation to ensure
it can be expanded to the maximum size.  This is not very efficient as it
requires a large number of blocks to be set aside that can't be used at
all by other btrees.

Switch to a model that uses a global pool instead in preparation for
reducing the amount of reserved space.

Signed-off-by: Christoph Hellwig <hch@lst.de>
15 files changed:
fs/xfs/libxfs/xfs_metafile.c
fs/xfs/libxfs/xfs_metafile.h
fs/xfs/scrub/reap.c
fs/xfs/scrub/repair.c
fs/xfs/scrub/repair.h
fs/xfs/scrub/rtrefcount_repair.c
fs/xfs/scrub/rtrmap_repair.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_mount.h
fs/xfs/xfs_reflink.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_super.c
fs/xfs/xfs_trace.h

index 7625e694eb8dffbdd39e009d5d9cb9d278c7e83a..88f011750add5c4efc7298a5ddfa5b6310d3c78d 100644 (file)
@@ -21,6 +21,9 @@
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_alloc.h"
+#include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
+#include "xfs_rtrefcount_btree.h"
 
 static const struct {
        enum xfs_metafile_type  mtype;
@@ -74,12 +77,11 @@ xfs_metafile_clear_iflag(
 }
 
 /*
- * Is the amount of space that could be allocated towards a given metadata
- * file at or beneath a certain threshold?
+ * Is the metafile reservations at or beneath a certain threshold?
  */
 static inline bool
 xfs_metafile_resv_can_cover(
-       struct xfs_inode        *ip,
+       struct xfs_mount        *mp,
        int64_t                 rhs)
 {
        /*
@@ -88,43 +90,38 @@ xfs_metafile_resv_can_cover(
         * global free block count.  Take care of the first case to avoid
         * touching the per-cpu counter.
         */
-       if (ip->i_delayed_blks >= rhs)
+       if (mp->m_metafile_resv_avail >= rhs)
                return true;
 
        /*
         * There aren't enough blocks left in the inode's reservation, but it
         * isn't critical unless there also isn't enough free space.
         */
-       return xfs_compare_freecounter(ip->i_mount, XC_FREE_BLOCKS,
-                       rhs - ip->i_delayed_blks, 2048) >= 0;
+       return xfs_compare_freecounter(mp, XC_FREE_BLOCKS,
+                       rhs - mp->m_metafile_resv_avail, 2048) >= 0;
 }
 
 /*
- * Is this metadata file critically low on blocks?  For now we'll define that
- * as the number of blocks we can get our hands on being less than 10% of what
- * we reserved or less than some arbitrary number (maximum btree height).
+ * Is the metafile reservation critically low on blocks?  For now we'll define
+ * that as the number of blocks we can get our hands on being less than 10% of
+ * what we reserved or less than some arbitrary number (maximum btree height).
  */
 bool
 xfs_metafile_resv_critical(
-       struct xfs_inode        *ip)
+       struct xfs_mount        *mp)
 {
-       uint64_t                asked_low_water;
+       ASSERT(xfs_has_metadir(mp));
 
-       if (!ip)
-               return false;
-
-       ASSERT(xfs_is_metadir_inode(ip));
-       trace_xfs_metafile_resv_critical(ip, 0);
+       trace_xfs_metafile_resv_critical(mp, 0);
 
-       if (!xfs_metafile_resv_can_cover(ip, ip->i_mount->m_rtbtree_maxlevels))
+       if (!xfs_metafile_resv_can_cover(mp, mp->m_rtbtree_maxlevels))
                return true;
 
-       asked_low_water = div_u64(ip->i_meta_resv_asked, 10);
-       if (!xfs_metafile_resv_can_cover(ip, asked_low_water))
+       if (!xfs_metafile_resv_can_cover(mp,
+                       div_u64(mp->m_metafile_resv_target, 10)))
                return true;
 
-       return XFS_TEST_ERROR(false, ip->i_mount,
-                       XFS_ERRTAG_METAFILE_RESV_CRITICAL);
+       return XFS_TEST_ERROR(false, mp, XFS_ERRTAG_METAFILE_RESV_CRITICAL);
 }
 
 /* Allocate a block from the metadata file's reservation. */
@@ -133,22 +130,24 @@ xfs_metafile_resv_alloc_space(
        struct xfs_inode        *ip,
        struct xfs_alloc_arg    *args)
 {
+       struct xfs_mount        *mp = ip->i_mount;
        int64_t                 len = args->len;
 
        ASSERT(xfs_is_metadir_inode(ip));
        ASSERT(args->resv == XFS_AG_RESV_METAFILE);
 
-       trace_xfs_metafile_resv_alloc_space(ip, args->len);
+       trace_xfs_metafile_resv_alloc_space(mp, args->len);
 
        /*
         * Allocate the blocks from the metadata inode's block reservation
         * and update the ondisk sb counter.
         */
-       if (ip->i_delayed_blks > 0) {
+       mutex_lock(&mp->m_metafile_resv_lock);
+       if (mp->m_metafile_resv_avail > 0) {
                int64_t         from_resv;
 
-               from_resv = min_t(int64_t, len, ip->i_delayed_blks);
-               ip->i_delayed_blks -= from_resv;
+               from_resv = min_t(int64_t, len, mp->m_metafile_resv_avail);
+               mp->m_metafile_resv_avail -= from_resv;
                xfs_mod_delalloc(ip, 0, -from_resv);
                xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS,
                                -from_resv);
@@ -175,6 +174,9 @@ xfs_metafile_resv_alloc_space(
                xfs_trans_mod_sb(args->tp, field, -len);
        }
 
+       mp->m_metafile_resv_used += args->len;
+       mutex_unlock(&mp->m_metafile_resv_lock);
+
        ip->i_nblocks += args->len;
        xfs_trans_log_inode(args->tp, ip, XFS_ILOG_CORE);
 }
@@ -186,26 +188,33 @@ xfs_metafile_resv_free_space(
        struct xfs_trans        *tp,
        xfs_filblks_t           len)
 {
+       struct xfs_mount        *mp = ip->i_mount;
        int64_t                 to_resv;
 
        ASSERT(xfs_is_metadir_inode(ip));
-       trace_xfs_metafile_resv_free_space(ip, len);
+
+       trace_xfs_metafile_resv_free_space(mp, len);
 
        ip->i_nblocks -= len;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
+       mutex_lock(&mp->m_metafile_resv_lock);
+       mp->m_metafile_resv_used -= len;
+
        /*
         * Add the freed blocks back into the inode's delalloc reservation
         * until it reaches the maximum size.  Update the ondisk fdblocks only.
         */
-       to_resv = ip->i_meta_resv_asked - (ip->i_nblocks + ip->i_delayed_blks);
+       to_resv = mp->m_metafile_resv_target -
+               (mp->m_metafile_resv_used + mp->m_metafile_resv_avail);
        if (to_resv > 0) {
                to_resv = min_t(int64_t, to_resv, len);
-               ip->i_delayed_blks += to_resv;
+               mp->m_metafile_resv_avail += to_resv;
                xfs_mod_delalloc(ip, 0, to_resv);
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, to_resv);
                len -= to_resv;
        }
+       mutex_unlock(&mp->m_metafile_resv_lock);
 
        /*
         * Everything else goes back to the filesystem, so update the in-core
@@ -215,61 +224,96 @@ xfs_metafile_resv_free_space(
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len);
 }
 
-/* Release a metadata file's space reservation. */
+static void
+__xfs_metafile_resv_free(
+       struct xfs_mount        *mp)
+{
+       if (mp->m_metafile_resv_avail) {
+               xfs_mod_sb_delalloc(mp, -(int64_t)mp->m_metafile_resv_avail);
+               xfs_add_fdblocks(mp, mp->m_metafile_resv_avail);
+       }
+       mp->m_metafile_resv_avail = 0;
+       mp->m_metafile_resv_used = 0;
+       mp->m_metafile_resv_target = 0;
+}
+
+/* Release unused metafile space reservation. */
 void
 xfs_metafile_resv_free(
-       struct xfs_inode        *ip)
+       struct xfs_mount        *mp)
 {
-       /* Non-btree metadata inodes don't need space reservations. */
-       if (!ip || !ip->i_meta_resv_asked)
+       if (!xfs_has_metadir(mp))
                return;
 
-       ASSERT(xfs_is_metadir_inode(ip));
-       trace_xfs_metafile_resv_free(ip, 0);
+       trace_xfs_metafile_resv_free(mp, 0);
 
-       if (ip->i_delayed_blks) {
-               xfs_mod_delalloc(ip, 0, -ip->i_delayed_blks);
-               xfs_add_fdblocks(ip->i_mount, ip->i_delayed_blks);
-               ip->i_delayed_blks = 0;
-       }
-       ip->i_meta_resv_asked = 0;
+       mutex_lock(&mp->m_metafile_resv_lock);
+       __xfs_metafile_resv_free(mp);
+       mutex_unlock(&mp->m_metafile_resv_lock);
 }
 
-/* Set up a metadata file's space reservation. */
+/* Set up a metafile space reservation. */
 int
 xfs_metafile_resv_init(
-       struct xfs_inode        *ip,
-       xfs_filblks_t           ask)
+       struct xfs_mount        *mp)
 {
+       struct xfs_rtgroup      *rtg = NULL;
+       xfs_filblks_t           used = 0, target = 0;
        xfs_filblks_t           hidden_space;
-       xfs_filblks_t           used;
-       int                     error;
+       int                     error = 0;
 
-       if (!ip || ip->i_meta_resv_asked > 0)
+       if (!xfs_has_metadir(mp))
                return 0;
 
-       ASSERT(xfs_is_metadir_inode(ip));
+       /*
+        * Free any previous reservation to have a clean slate.
+        */
+       mutex_lock(&mp->m_metafile_resv_lock);
+       __xfs_metafile_resv_free(mp);
+
+       /*
+        * Currently the only btree metafiles that require reservations are the
+        * rtrmap and the rtrefcount.  Anything new will have to be added here
+        * as well.
+        */
+       while ((rtg = xfs_rtgroup_next(mp, rtg))) {
+               if (xfs_has_rtrmapbt(mp)) {
+                       used += rtg_rmap(rtg)->i_nblocks;
+                       target += xfs_rtrmapbt_calc_reserves(mp);
+               }
+               if (xfs_has_rtreflink(mp)) {
+                       used += rtg_refcount(rtg)->i_nblocks;
+                       target += xfs_rtrefcountbt_calc_reserves(mp);
+               }
+       }
+
+       if (!target)
+               goto out_unlock;
 
        /*
-        * Space taken by all other metadata btrees are accounted on-disk as
+        * Space taken by the per-AG metadata btrees are accounted on-disk as
         * used space.  We therefore only hide the space that is reserved but
         * not used by the trees.
         */
-       used = ip->i_nblocks;
-       if (used > ask)
-               ask = used;
-       hidden_space = ask - used;
+       if (used > target)
+               target = used;
+       hidden_space = target - used;
 
-       error = xfs_dec_fdblocks(ip->i_mount, hidden_space, true);
+       error = xfs_dec_fdblocks(mp, hidden_space, true);
        if (error) {
-               trace_xfs_metafile_resv_init_error(ip, error, _RET_IP_);
-               return error;
+               trace_xfs_metafile_resv_init_error(mp, 0);
+               goto out_unlock;
        }
 
-       xfs_mod_delalloc(ip, 0, hidden_space);
-       ip->i_delayed_blks = hidden_space;
-       ip->i_meta_resv_asked = ask;
+       xfs_mod_sb_delalloc(mp, hidden_space);
+
+       mp->m_metafile_resv_target = target;
+       mp->m_metafile_resv_used = used;
+       mp->m_metafile_resv_avail = hidden_space;
+
+       trace_xfs_metafile_resv_init(mp, target);
 
-       trace_xfs_metafile_resv_init(ip, ask);
-       return 0;
+out_unlock:
+       mutex_unlock(&mp->m_metafile_resv_lock);
+       return error;
 }
index 95af4b52e5a75f8f2b6c228141e53f21f91cf4e2..ae6f9e779b988e3667cc83b723f5e3febf3921ee 100644 (file)
@@ -26,13 +26,13 @@ void xfs_metafile_clear_iflag(struct xfs_trans *tp, struct xfs_inode *ip);
 /* Space reservations for metadata inodes. */
 struct xfs_alloc_arg;
 
-bool xfs_metafile_resv_critical(struct xfs_inode *ip);
+bool xfs_metafile_resv_critical(struct xfs_mount *mp);
 void xfs_metafile_resv_alloc_space(struct xfs_inode *ip,
                struct xfs_alloc_arg *args);
 void xfs_metafile_resv_free_space(struct xfs_inode *ip, struct xfs_trans *tp,
                xfs_filblks_t len);
-void xfs_metafile_resv_free(struct xfs_inode *ip);
-int xfs_metafile_resv_init(struct xfs_inode *ip, xfs_filblks_t ask);
+void xfs_metafile_resv_free(struct xfs_mount *mp);
+int xfs_metafile_resv_init(struct xfs_mount *mp);
 
 /* Code specific to kernel/userspace; must be provided externally. */
 
index b32fb233cf847672e4798d2ae0c6ab160e244b31..cb66918832a910930b37ba57422c240ca58316ba 100644 (file)
@@ -932,13 +932,17 @@ xrep_reap_metadir_fsblocks(
        xfs_rmap_ino_bmbt_owner(&oinfo, sc->ip->i_ino, XFS_DATA_FORK);
 
        error = xfsb_bitmap_walk(bitmap, xreap_fsmeta_extent, &rs);
-       if (error)
+       if (error || !xreap_dirty(&rs))
                return error;
 
-       if (xreap_dirty(&rs))
-               return xrep_defer_finish(sc);
+       error = xrep_defer_finish(sc);
+       if (error)
+               return error;
 
-       return 0;
+       /*
+        * Resize the reservations so that we don't fail to expand the btree.
+        */
+       return xfs_metafile_resv_init(sc->mp);
 }
 
 /*
index 3b5288d3ef4e341ff02e46228657c7a2512b762a..5cdaf82aee7b6e8a5394d77867d7fbbdd24fd647 100644 (file)
@@ -1380,57 +1380,3 @@ xrep_inode_set_nblocks(
                xfs_trans_mod_dquot_byino(sc->tp, sc->ip, XFS_TRANS_DQ_BCOUNT,
                                delta);
 }
-
-/* Reset the block reservation for a metadata inode. */
-int
-xrep_reset_metafile_resv(
-       struct xfs_scrub        *sc)
-{
-       struct xfs_inode        *ip = sc->ip;
-       int64_t                 delta;
-       int                     error;
-
-       delta = ip->i_nblocks + ip->i_delayed_blks - ip->i_meta_resv_asked;
-       if (delta == 0)
-               return 0;
-
-       /*
-        * Too many blocks have been reserved, transfer some from the incore
-        * reservation back to the filesystem.
-        */
-       if (delta > 0) {
-               int64_t         give_back;
-
-               give_back = min_t(uint64_t, delta, ip->i_delayed_blks);
-               if (give_back > 0) {
-                       xfs_mod_delalloc(ip, 0, -give_back);
-                       xfs_add_fdblocks(ip->i_mount, give_back);
-                       ip->i_delayed_blks -= give_back;
-               }
-
-               return 0;
-       }
-
-       /*
-        * Not enough reservation; try to take some blocks from the filesystem
-        * to the metadata inode.  @delta is negative here, so invert the sign.
-        */
-       delta = -delta;
-       error = xfs_dec_fdblocks(sc->mp, delta, true);
-       while (error == -ENOSPC) {
-               delta--;
-               if (delta == 0) {
-                       xfs_warn(sc->mp,
-"Insufficient free space to reset space reservation for inode 0x%llx after repair.",
-                                       ip->i_ino);
-                       return 0;
-               }
-               error = xfs_dec_fdblocks(sc->mp, delta, true);
-       }
-       if (error)
-               return error;
-
-       xfs_mod_delalloc(ip, 0, delta);
-       ip->i_delayed_blks += delta;
-       return 0;
-}
index 823c00d1a502621e947a4481c575feda6f578c24..342bae348b4745713e14cf7e6622b96fe1f93b81 100644 (file)
@@ -186,7 +186,6 @@ void xrep_trans_cancel_hook_dummy(void **cookiep, struct xfs_trans *tp);
 
 bool xrep_buf_verify_struct(struct xfs_buf *bp, const struct xfs_buf_ops *ops);
 void xrep_inode_set_nblocks(struct xfs_scrub *sc, int64_t new_blocks);
-int xrep_reset_metafile_resv(struct xfs_scrub *sc);
 
 #else
 
index 257cfb24beb428df29f1bdfeeab827bceb6bd842..983362447826dec2eebfc0cdb3fbd6bc8b136c7c 100644 (file)
@@ -697,32 +697,6 @@ err_cur:
        return error;
 }
 
-/*
- * Now that we've logged the roots of the new btrees, invalidate all of the
- * old blocks and free them.
- */
-STATIC int
-xrep_rtrefc_remove_old_tree(
-       struct xrep_rtrefc      *rr)
-{
-       int                     error;
-
-       /*
-        * Free all the extents that were allocated to the former rtrefcountbt
-        * and aren't cross-linked with something else.
-        */
-       error = xrep_reap_metadir_fsblocks(rr->sc,
-                       &rr->old_rtrefcountbt_blocks);
-       if (error)
-               return error;
-
-       /*
-        * Ensure the proper reservation for the rtrefcount inode so that we
-        * don't fail to expand the btree.
-        */
-       return xrep_reset_metafile_resv(rr->sc);
-}
-
 /* Rebuild the rt refcount btree. */
 int
 xrep_rtrefcountbt(
@@ -769,8 +743,12 @@ xrep_rtrefcountbt(
        if (error)
                goto out_bitmap;
 
-       /* Kill the old tree. */
-       error = xrep_rtrefc_remove_old_tree(rr);
+       /*
+        * Free all the extents that were allocated to the former rtrefcountbt
+        * and aren't cross-linked with something else.
+        */
+       error = xrep_reap_metadir_fsblocks(rr->sc,
+                       &rr->old_rtrefcountbt_blocks);
        if (error)
                goto out_bitmap;
 
index f2fdd7a9fc248342c3f66550a483707c92ef7c26..fc2592c53af56926a9adcc6929acf9ddd4ef2e32 100644 (file)
@@ -810,28 +810,6 @@ err_cur:
 
 /* Reaping the old btree. */
 
-/* Reap the old rtrmapbt blocks. */
-STATIC int
-xrep_rtrmap_remove_old_tree(
-       struct xrep_rtrmap      *rr)
-{
-       int                     error;
-
-       /*
-        * Free all the extents that were allocated to the former rtrmapbt and
-        * aren't cross-linked with something else.
-        */
-       error = xrep_reap_metadir_fsblocks(rr->sc, &rr->old_rtrmapbt_blocks);
-       if (error)
-               return error;
-
-       /*
-        * Ensure the proper reservation for the rtrmap inode so that we don't
-        * fail to expand the new btree.
-        */
-       return xrep_reset_metafile_resv(rr->sc);
-}
-
 static inline bool
 xrep_rtrmapbt_want_live_update(
        struct xchk_iscan               *iscan,
@@ -995,8 +973,11 @@ xrep_rtrmapbt(
        if (error)
                goto out_records;
 
-       /* Kill the old tree. */
-       error = xrep_rtrmap_remove_old_tree(rr);
+       /*
+        * Free all the extents that were allocated to the former rtrmapbt and
+        * aren't cross-linked with something else.
+        */
+       error = xrep_reap_metadir_fsblocks(rr->sc, &rr->old_rtrmapbt_blocks);
        if (error)
                goto out_records;
 
index 73275d7a6ec0d80a6ebb05bdf278c02e1d475898..22d50f8acd92ef7157f40c6e0992dc44a4b27105 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_rtalloc.h"
 #include "xfs_rtrmap_btree.h"
 #include "xfs_rtrefcount_btree.h"
+#include "xfs_metafile.h"
 
 /*
  * Write new AG headers to disk. Non-transactional, but need to be
@@ -561,15 +562,13 @@ xfs_fs_reserve_ag_blocks(
                return error;
        }
 
-       if (xfs_has_realtime(mp)) {
-               err2 = xfs_rt_resv_init(mp);
-               if (err2 && err2 != -ENOSPC) {
-                       xfs_warn(mp,
-               "Error %d reserving realtime metadata reserve pool.", err2);
-                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
-               }
+       err2 = xfs_metafile_resv_init(mp);
+       if (err2 && err2 != -ENOSPC) {
+               xfs_warn(mp,
+       "Error %d reserving realtime metadata reserve pool.", err2);
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 
-               if (err2 && !error)
+               if (!error)
                        error = err2;
        }
 
@@ -585,9 +584,7 @@ xfs_fs_unreserve_ag_blocks(
 {
        struct xfs_perag        *pag = NULL;
 
-       if (xfs_has_realtime(mp))
-               xfs_rt_resv_free(mp);
-
+       xfs_metafile_resv_free(mp);
        while ((pag = xfs_perag_next(mp, pag)))
                xfs_ag_resv_free(pag);
 }
index c08093a65352ecc99ead78ba6d9354334d67b3a0..1648dc5a806882278d7eec1cc7451cc9818332fa 100644 (file)
@@ -25,19 +25,9 @@ struct xfs_dquot;
 typedef struct xfs_inode {
        /* Inode linking and identification information. */
        struct xfs_mount        *i_mount;       /* fs mount struct ptr */
-       union {
-               struct {
-                       struct xfs_dquot *i_udquot;     /* user dquot */
-                       struct xfs_dquot *i_gdquot;     /* group dquot */
-                       struct xfs_dquot *i_pdquot;     /* project dquot */
-               };
-
-               /*
-                * Space that has been set aside to accomodate expansions of a
-                * metadata btree rooted in this file.
-                */
-               uint64_t        i_meta_resv_asked;
-       };
+       struct xfs_dquot        *i_udquot;      /* user dquot */
+       struct xfs_dquot        *i_gdquot;      /* group dquot */
+       struct xfs_dquot        *i_pdquot;      /* project dquot */
 
        /* Inode location stuff */
        xfs_ino_t               i_ino;          /* inode number (agno/agino)*/
index d4a57e2fdcc51544d8a3dce61c152c080c4b75a9..9bfb5e08715d9349696edc69922087f063528632 100644 (file)
@@ -263,6 +263,11 @@ typedef struct xfs_mount {
        atomic_t                m_agirotor;     /* last ag dir inode alloced */
        atomic_t                m_rtgrotor;     /* last rtgroup rtpicked */
 
+       struct mutex            m_metafile_resv_lock;
+       uint64_t                m_metafile_resv_target;
+       uint64_t                m_metafile_resv_used;
+       uint64_t                m_metafile_resv_avail;
+
        /* Memory shrinker to throttle and reprioritize inodegc */
        struct shrinker         *m_inodegc_shrinker;
        /*
@@ -737,5 +742,9 @@ int xfs_add_incompat_log_feature(struct xfs_mount *mp, uint32_t feature);
 bool xfs_clear_incompat_log_features(struct xfs_mount *mp);
 void xfs_mod_delalloc(struct xfs_inode *ip, int64_t data_delta,
                int64_t ind_delta);
+static inline void xfs_mod_sb_delalloc(struct xfs_mount *mp, int64_t delta)
+{
+       percpu_counter_add(&mp->m_delalloc_blks, delta);
+}
 
 #endif /* __XFS_MOUNT_H__ */
index 3e778e077d09377ed3d730cba4d244307469e31e..fd65e5d7994a5e934e2f80704263267ad0b0187a 100644 (file)
@@ -1207,15 +1207,9 @@ xfs_reflink_ag_has_free_space(
        if (!xfs_has_rmapbt(mp))
                return 0;
        if (XFS_IS_REALTIME_INODE(ip)) {
-               struct xfs_rtgroup      *rtg;
-               xfs_rgnumber_t          rgno;
-
-               rgno = xfs_rtb_to_rgno(mp, fsb);
-               rtg = xfs_rtgroup_get(mp, rgno);
-               if (xfs_metafile_resv_critical(rtg_rmap(rtg)))
-                       error = -ENOSPC;
-               xfs_rtgroup_put(rtg);
-               return error;
+               if (xfs_metafile_resv_critical(mp))
+                       return -ENOSPC;
+               return 0;
        }
 
        agno = XFS_FSB_TO_AGNO(mp, fsb);
index 8da2498417f5039af3783ccdd04216d4ce9bd2c8..f5a0dbc46a14349c30369c7ec9ab5412157191f6 100644 (file)
@@ -1398,8 +1398,7 @@ xfs_growfs_rt(
                        error = error2;
 
                /* Reset the rt metadata btree space reservations. */
-               xfs_rt_resv_free(mp);
-               error2 = xfs_rt_resv_init(mp);
+               error2 = xfs_metafile_resv_init(mp);
                if (error2 && error2 != -ENOSPC)
                        error = error2;
        }
@@ -1523,46 +1522,6 @@ xfs_rtalloc_reinit_frextents(
        return 0;
 }
 
-/* Free space reservations for rt metadata inodes. */
-void
-xfs_rt_resv_free(
-       struct xfs_mount        *mp)
-{
-       struct xfs_rtgroup      *rtg = NULL;
-       unsigned int            i;
-
-       while ((rtg = xfs_rtgroup_next(mp, rtg))) {
-               for (i = 0; i < XFS_RTGI_MAX; i++)
-                       xfs_metafile_resv_free(rtg->rtg_inodes[i]);
-       }
-}
-
-/* Reserve space for rt metadata inodes' space expansion. */
-int
-xfs_rt_resv_init(
-       struct xfs_mount        *mp)
-{
-       struct xfs_rtgroup      *rtg = NULL;
-       xfs_filblks_t           ask;
-       int                     error = 0;
-
-       while ((rtg = xfs_rtgroup_next(mp, rtg))) {
-               int             err2;
-
-               ask = xfs_rtrmapbt_calc_reserves(mp);
-               err2 = xfs_metafile_resv_init(rtg_rmap(rtg), ask);
-               if (err2 && !error)
-                       error = err2;
-
-               ask = xfs_rtrefcountbt_calc_reserves(mp);
-               err2 = xfs_metafile_resv_init(rtg_refcount(rtg), ask);
-               if (err2 && !error)
-                       error = err2;
-       }
-
-       return error;
-}
-
 /*
  * Read in the bmbt of an rt metadata inode so that we never have to load them
  * at runtime.  This enables the use of shared ILOCKs for rtbitmap scans.  Use
index 0d95b29092c9f30c261faceec455275cf815661e..78a690b489ed59b3541f1b38977ac4f89bc34158 100644 (file)
@@ -34,9 +34,6 @@ int                                   /* error */
 xfs_rtmount_inodes(
        struct xfs_mount        *mp);   /* file system mount structure */
 
-void xfs_rt_resv_free(struct xfs_mount *mp);
-int xfs_rt_resv_init(struct xfs_mount *mp);
-
 /*
  * Grow the realtime area of the filesystem.
  */
@@ -65,8 +62,6 @@ xfs_rtmount_init(
 }
 # define xfs_rtmount_inodes(m)  (((mp)->m_sb.sb_rblocks == 0)? 0 : (-ENOSYS))
 # define xfs_rtunmount_inodes(m)
-# define xfs_rt_resv_free(mp)                          ((void)0)
-# define xfs_rt_resv_init(mp)                          (0)
 
 static inline int
 xfs_growfs_check_rtgeom(const struct xfs_mount *mp,
index 5c9a2a0826ffb71b30a56da2e1a3c2f316c44ccc..4414c8542144f23359ee4efa09057e2087716214 100644 (file)
@@ -2089,6 +2089,7 @@ xfs_init_fs_context(
        for (i = 0; i < XG_TYPE_MAX; i++)
                xa_init(&mp->m_groups[i].xa);
        mutex_init(&mp->m_growlock);
+       mutex_init(&mp->m_metafile_resv_lock);
        INIT_WORK(&mp->m_flush_inodes_work, xfs_flush_inodes_worker);
        INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
        mp->m_kobj.kobject.kset = xfs_kset;
index 740e0a8c3eca3ff7a0d2243f4ad4da2d6c7f3d97..a02129c202b2caf857569987a028d743e0f3840f 100644 (file)
@@ -5605,11 +5605,10 @@ DEFINE_METADIR_EVENT(xfs_metadir_lookup);
 /* metadata inode space reservations */
 
 DECLARE_EVENT_CLASS(xfs_metafile_resv_class,
-       TP_PROTO(struct xfs_inode *ip, xfs_filblks_t len),
-       TP_ARGS(ip, len),
+       TP_PROTO(struct xfs_mount *mp, xfs_filblks_t len),
+       TP_ARGS(mp, len),
        TP_STRUCT__entry(
                __field(dev_t, dev)
-               __field(xfs_ino_t, ino)
                __field(unsigned long long, freeblks)
                __field(unsigned long long, reserved)
                __field(unsigned long long, asked)
@@ -5617,19 +5616,15 @@ DECLARE_EVENT_CLASS(xfs_metafile_resv_class,
                __field(unsigned long long, len)
        ),
        TP_fast_assign(
-               struct xfs_mount *mp = ip->i_mount;
-
                __entry->dev = mp->m_super->s_dev;
-               __entry->ino = ip->i_ino;
                __entry->freeblks = xfs_sum_freecounter_raw(mp, XC_FREE_BLOCKS);
-               __entry->reserved = ip->i_delayed_blks;
-               __entry->asked = ip->i_meta_resv_asked;
-               __entry->used = ip->i_nblocks;
+               __entry->reserved = mp->m_metafile_resv_avail;
+               __entry->asked = mp->m_metafile_resv_target;
+               __entry->used = mp->m_metafile_resv_used;
                __entry->len = len;
        ),
-       TP_printk("dev %d:%d ino 0x%llx freeblks %llu resv %llu ask %llu used %llu len %llu",
+       TP_printk("dev %d:%d freeblks %llu resv %llu ask %llu used %llu len %llu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->ino,
                  __entry->freeblks,
                  __entry->reserved,
                  __entry->asked,
@@ -5638,14 +5633,14 @@ DECLARE_EVENT_CLASS(xfs_metafile_resv_class,
 )
 #define DEFINE_METAFILE_RESV_EVENT(name) \
 DEFINE_EVENT(xfs_metafile_resv_class, name, \
-       TP_PROTO(struct xfs_inode *ip, xfs_filblks_t len), \
-       TP_ARGS(ip, len))
+       TP_PROTO(struct xfs_mount *mp, xfs_filblks_t len), \
+       TP_ARGS(mp, len))
 DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_init);
 DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_free);
 DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_alloc_space);
 DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_free_space);
 DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_critical);
-DEFINE_INODE_ERROR_EVENT(xfs_metafile_resv_init_error);
+DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_init_error);
 
 #ifdef CONFIG_XFS_RT
 TRACE_EVENT(xfs_growfs_check_rtgeom,