From 91643efd0e4c6ab2028a014fac2294d65975305c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 14 Apr 2025 07:35:44 +0200 Subject: [PATCH] xfs: generalize the freespace and reserved blocks handling Source kernel commit: 712bae96631852c1a1822ee4f57a08ccd843358b xfs_{add,dec}_freecounter already handles the block and RT extent percpu counters, but it currently hardcodes the passed in counter. Add a freecounter abstraction that uses an enum to designate the counter and add wrappers that hide the actual percpu_counters. This will allow expanding the reserved block handling to the RT extent counter in the next step, and also prepares for adding yet another such counter that can share the code. Both these additions will be needed for the zoned allocator. Also switch the flooring of the frextents counter to 0 in statfs for the rthinherit case to a manual min_t call to match the handling of the fdblocks counter for normal file systems. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Christoph Hellwig --- include/xfs_mount.h | 32 ++++++++++++++++++++++++++++++-- libxfs/libxfs_priv.h | 13 +------------ libxfs/xfs_ialloc.c | 2 +- libxfs/xfs_metafile.c | 2 +- libxfs/xfs_sb.c | 8 ++++---- libxfs/xfs_types.h | 17 +++++++++++++++++ 6 files changed, 54 insertions(+), 20 deletions(-) diff --git a/include/xfs_mount.h b/include/xfs_mount.h index 383cba7d..e0f72fc3 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -63,8 +63,6 @@ typedef struct xfs_mount { xfs_sb_t m_sb; /* copy of fs superblock */ #define m_icount m_sb.sb_icount #define m_ifree m_sb.sb_ifree -#define m_fdblocks m_sb.sb_fdblocks -#define m_frextents m_sb.sb_frextents spinlock_t m_sb_lock; /* @@ -332,6 +330,36 @@ static inline bool xfs_is_ ## name (struct xfs_mount *mp) \ __XFS_UNSUPP_OPSTATE(readonly) __XFS_UNSUPP_OPSTATE(shutdown) +static inline int64_t xfs_sum_freecounter(struct xfs_mount *mp, + enum xfs_free_counter ctr) +{ + if (ctr == XC_FREE_RTEXTENTS) + return mp->m_sb.sb_frextents; + return mp->m_sb.sb_fdblocks; +} + +static inline int64_t xfs_estimate_freecounter(struct xfs_mount *mp, + enum xfs_free_counter ctr) +{ + return xfs_sum_freecounter(mp, ctr); +} + +static inline int xfs_compare_freecounter(struct xfs_mount *mp, + enum xfs_free_counter ctr, int64_t rhs, int32_t batch) +{ + uint64_t count; + + if (ctr == XC_FREE_RTEXTENTS) + count = mp->m_sb.sb_frextents; + else + count = mp->m_sb.sb_fdblocks; + if (count > rhs) + return 1; + else if (count < rhs) + return -1; + return 0; +} + /* don't fail on device size or AG count checks */ #define LIBXFS_MOUNT_DEBUGGER (1U << 0) /* report metadata corruption to stdout */ diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 7e5c125b..cb4800de 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -209,7 +209,7 @@ static inline bool WARN_ON(bool expr) { } #define WARN_ON_ONCE(e) WARN_ON(e) -#define percpu_counter_read(x) (*x) + #define percpu_counter_read_positive(x) ((*x) > 0 ? (*x) : 0) #define percpu_counter_sum_positive(x) ((*x) > 0 ? (*x) : 0) @@ -219,17 +219,6 @@ uint32_t get_random_u32(void); #define get_random_u32() (0) #endif -static inline int -__percpu_counter_compare(uint64_t *count, int64_t rhs, int32_t batch) -{ - if (*count > rhs) - return 1; - else if (*count < rhs) - return -1; - return 0; -} - - #define PAGE_SIZE getpagesize() extern unsigned int PAGE_SHIFT; diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c index 63ce7675..b401299a 100644 --- a/libxfs/xfs_ialloc.c +++ b/libxfs/xfs_ialloc.c @@ -1922,7 +1922,7 @@ xfs_dialloc( * that we can immediately allocate, but then we allow allocation on the * second pass if we fail to find an AG with free inodes in it. */ - if (percpu_counter_read_positive(&mp->m_fdblocks) < + if (xfs_estimate_freecounter(mp, XC_FREE_BLOCKS) < mp->m_low_space[XFS_LOWSP_1_PCNT]) { ok_alloc = false; low_space = true; diff --git a/libxfs/xfs_metafile.c b/libxfs/xfs_metafile.c index 4488e38a..76732655 100644 --- a/libxfs/xfs_metafile.c +++ b/libxfs/xfs_metafile.c @@ -93,7 +93,7 @@ xfs_metafile_resv_can_cover( * 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 __percpu_counter_compare(&ip->i_mount->m_fdblocks, + return xfs_compare_freecounter(ip->i_mount, XC_FREE_BLOCKS, rhs - ip->i_delayed_blks, 2048) >= 0; } diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index 50a43c03..1781ca36 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -1262,8 +1262,7 @@ xfs_log_sb( mp->m_sb.sb_ifree = min_t(uint64_t, percpu_counter_sum_positive(&mp->m_ifree), mp->m_sb.sb_icount); - mp->m_sb.sb_fdblocks = - percpu_counter_sum_positive(&mp->m_fdblocks); + mp->m_sb.sb_fdblocks = xfs_sum_freecounter(mp, XC_FREE_BLOCKS); } /* @@ -1272,9 +1271,10 @@ xfs_log_sb( * we handle nearly-lockless reservations, so we must use the _positive * variant here to avoid writing out nonsense frextents. */ - if (xfs_has_rtgroups(mp)) + if (xfs_has_rtgroups(mp)) { mp->m_sb.sb_frextents = - percpu_counter_sum_positive(&mp->m_frextents); + xfs_sum_freecounter(mp, XC_FREE_RTEXTENTS); + } xfs_sb_to_disk(bp->b_addr, &mp->m_sb); xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h index ca2401c1..76f3c315 100644 --- a/libxfs/xfs_types.h +++ b/libxfs/xfs_types.h @@ -233,6 +233,23 @@ enum xfs_group_type { { XG_TYPE_AG, "ag" }, \ { XG_TYPE_RTG, "rtg" } +enum xfs_free_counter { + /* + * Number of free blocks on the data device. + */ + XC_FREE_BLOCKS, + + /* + * Number of free RT extents on the RT device. + */ + XC_FREE_RTEXTENTS, + XC_FREE_NR, +}; + +#define XFS_FREECOUNTER_STR \ + { XC_FREE_BLOCKS, "blocks" }, \ + { XC_FREE_RTEXTENTS, "rtextents" } + /* * Type verifier functions */ -- 2.47.2