From: Darrick J. Wong <djwong@xxxxxxxxxx> Source kernel commit: 87fe4c34a383d51ec75f254240bcd08828f4ce5a Create an incore object that will contain information about a realtime allocation group. This will eventually enable us to shard the realtime section in a similar manner to how we shard the data section, but for now just a single object for the entire RT subvolume is created. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- db/block.h | 16 --- db/convert.c | 1 db/faddr.c | 1 include/libxfs.h | 1 include/platform_defs.h | 33 +++++++ include/xfs_mount.h | 16 +++ include/xfs_trace.h | 7 + libxfs/Makefile | 2 libxfs/init.c | 17 ++++ libxfs/libxfs_api_defs.h | 4 + libxfs/libxfs_priv.h | 33 ------- libxfs/xfs_format.h | 3 + libxfs/xfs_rtgroup.c | 149 ++++++++++++++++++++++++++++++++ libxfs/xfs_rtgroup.h | 217 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_sb.c | 13 +++ libxfs/xfs_types.h | 8 +- mkfs/xfs_mkfs.c | 8 ++ 17 files changed, 477 insertions(+), 52 deletions(-) create mode 100644 libxfs/xfs_rtgroup.c create mode 100644 libxfs/xfs_rtgroup.h diff --git a/db/block.h b/db/block.h index 55843a6b521393..ed13e159064461 100644 --- a/db/block.h +++ b/db/block.h @@ -11,20 +11,4 @@ struct field; extern void block_init(void); extern void print_block(const struct field *fields, int argc, char **argv); -static inline xfs_daddr_t -xfs_rtb_to_daddr( - struct xfs_mount *mp, - xfs_rtblock_t rtb) -{ - return rtb << mp->m_blkbb_log; -} - -static inline xfs_rtblock_t -xfs_daddr_to_rtb( - struct xfs_mount *mp, - xfs_daddr_t daddr) -{ - return daddr >> mp->m_blkbb_log; -} - #endif /* __XFS_DB_BLOCK_H */ diff --git a/db/convert.c b/db/convert.c index 3014367e7d7652..0c5c942150fe6f 100644 --- a/db/convert.c +++ b/db/convert.c @@ -8,7 +8,6 @@ #include "command.h" #include "output.h" #include "init.h" -#include "block.h" #define M(A) (1 << CT_ ## A) #define agblock_to_bytes(x) \ diff --git a/db/faddr.c b/db/faddr.c index e2f9587da0a67c..bf9dd521f14068 100644 --- a/db/faddr.c +++ b/db/faddr.c @@ -15,7 +15,6 @@ #include "bmap.h" #include "output.h" #include "init.h" -#include "block.h" void fa_agblock( diff --git a/include/libxfs.h b/include/libxfs.h index 985646e6ad89d1..df38d875143ed9 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -97,6 +97,7 @@ struct iomap; #include "xfs_ag_resv.h" #include "xfs_metafile.h" #include "xfs_metadir.h" +#include "xfs_rtgroup.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) diff --git a/include/platform_defs.h b/include/platform_defs.h index a3644dea41cdef..051ee25a5b4fea 100644 --- a/include/platform_defs.h +++ b/include/platform_defs.h @@ -228,4 +228,37 @@ static inline size_t __ab_c_size(size_t a, size_t b, size_t c) */ #define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option)) +/* miscellaneous kernel routines not in user space */ +#define likely(x) (x) +#define unlikely(x) (x) + +#define __must_check __attribute__((__warn_unused_result__)) + +/* + * Allows for effectively applying __must_check to a macro so we can have + * both the type-agnostic benefits of the macros while also being able to + * enforce that the return value is, in fact, checked. + */ +static inline bool __must_check __must_check_overflow(bool overflow) +{ + return unlikely(overflow); +} + +/* + * For simplicity and code hygiene, the fallback code below insists on + * a, b and *d having the same type (similar to the min() and max() + * macros), whereas gcc's type-generic overflow checkers accept + * different types. Hence we don't just make check_add_overflow an + * alias for __builtin_add_overflow, but add type checks similar to + * below. + */ +#define check_add_overflow(a, b, d) __must_check_overflow(({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_add_overflow(__a, __b, __d); \ +})) + #endif /* __XFS_PLATFORM_DEFS_H__ */ diff --git a/include/xfs_mount.h b/include/xfs_mount.h index 6daf3f01ffa9cf..987ffea19d1586 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -82,6 +82,7 @@ typedef struct xfs_mount { struct xfs_ino_geometry m_ino_geo; /* inode geometry */ uint m_rsumlevels; /* rt summary levels */ xfs_filblks_t m_rsumblocks; /* size of rt summary, FSBs */ + uint32_t m_rgblocks; /* size of rtgroup in rtblocks */ /* * Optional cache of rt summary level per bitmap block with the * invariant that m_rsum_cache[bbno] <= the minimum i for which @@ -104,6 +105,7 @@ typedef struct xfs_mount { uint8_t m_sectbb_log; /* sectorlog - BBSHIFT */ uint8_t m_agno_log; /* log #ag's */ int8_t m_rtxblklog; /* log2 of rextsize, if possible */ + int8_t m_rgblklog; /* log2 of rt group sz if possible */ uint m_blockmask; /* sb_blocksize-1 */ uint m_blockwsize; /* sb_blocksize in words */ uint m_blockwmask; /* blockwsize-1 */ @@ -127,6 +129,7 @@ typedef struct xfs_mount { uint64_t m_features; /* active filesystem features */ uint64_t m_low_space[XFS_LOWSP_MAX]; uint64_t m_rtxblkmask; /* rt extent block mask */ + uint64_t m_rgblkmask; /* rt group block mask */ unsigned long m_opstate; /* dynamic state flags */ bool m_finobt_nores; /* no per-AG finobt resv. */ uint m_qflags; /* quota status flags */ @@ -250,6 +253,17 @@ __XFS_HAS_FEAT(large_extent_counts, NREXT64) __XFS_HAS_FEAT(exchange_range, EXCHANGE_RANGE) __XFS_HAS_FEAT(metadir, METADIR) + +static inline bool xfs_has_rtgroups(struct xfs_mount *mp) +{ + return false; +} + +static inline bool xfs_has_rtsb(struct xfs_mount *mp) +{ + return false; +} + /* Kernel mount features that we don't support */ #define __XFS_UNSUPP_FEAT(name) \ static inline bool xfs_has_ ## name (struct xfs_mount *mp) \ @@ -269,6 +283,7 @@ __XFS_UNSUPP_FEAT(grpid) #define XFS_OPSTATE_DEBUGGER 1 /* is this the debugger? */ #define XFS_OPSTATE_REPORT_CORRUPTION 2 /* report buffer corruption? */ #define XFS_OPSTATE_PERAG_DATA_LOADED 3 /* per-AG data initialized? */ +#define XFS_OPSTATE_RTGROUP_DATA_LOADED 4 /* rtgroup data initialized? */ #define __XFS_IS_OPSTATE(name, NAME) \ static inline bool xfs_is_ ## name (struct xfs_mount *mp) \ @@ -294,6 +309,7 @@ __XFS_IS_OPSTATE(inode32, INODE32) __XFS_IS_OPSTATE(debugger, DEBUGGER) __XFS_IS_OPSTATE(reporting_corruption, REPORT_CORRUPTION) __XFS_IS_OPSTATE(perag_data_loaded, PERAG_DATA_LOADED) +__XFS_IS_OPSTATE(rtgroup_data_loaded, RTGROUP_DATA_LOADED) #define __XFS_UNSUPP_OPSTATE(name) \ static inline bool xfs_is_ ## name (struct xfs_mount *mp) \ diff --git a/include/xfs_trace.h b/include/xfs_trace.h index f3e531ef118d05..a53ce092c8ea3b 100644 --- a/include/xfs_trace.h +++ b/include/xfs_trace.h @@ -356,6 +356,13 @@ #define trace_xfs_exchmaps_overhead(...) ((void) 0) #define trace_xfs_exchmaps_update_inode_size(...) ((void) 0) +/* set c = c to avoid unused var warnings */ +#define trace_xfs_rtgroup_get(a,b) ((a) = (a)) +#define trace_xfs_rtgroup_hold(a,b) ((a) = (a)) +#define trace_xfs_rtgroup_put(a,b) ((a) = (a)) +#define trace_xfs_rtgroup_grab(a,b) ((a) = (a)) +#define trace_xfs_rtgroup_rele(a,b) ((a) = (a)) + #define trace_xfs_fs_mark_healthy(a,b) ((void) 0) #define trace_xlog_intent_recovery_failed(...) ((void) 0) diff --git a/libxfs/Makefile b/libxfs/Makefile index c8267841e77b01..42c9f3cc439dc5 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -64,6 +64,7 @@ HFILES = \ xfs_rmap.h \ xfs_rmap_btree.h \ xfs_rtbitmap.h \ + xfs_rtgroup.h \ xfs_sb.h \ xfs_shared.h \ xfs_trans_resv.h \ @@ -124,6 +125,7 @@ CFILES = buf_mem.c \ xfs_rmap.c \ xfs_rmap_btree.c \ xfs_rtbitmap.c \ + xfs_rtgroup.c \ xfs_sb.c \ xfs_symlink_remote.c \ xfs_trans_inode.c \ diff --git a/libxfs/init.c b/libxfs/init.c index bf488c5d8533b1..b47d8eaf4f468c 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -32,6 +32,7 @@ #include "xfs_ondisk.h" #include "libxfs.h" /* for now */ +#include "xfs_rtgroup.h" #ifndef HAVE_LIBURCU_ATOMIC64 pthread_mutex_t atomic64_lock = PTHREAD_MUTEX_INITIALIZER; @@ -670,6 +671,7 @@ libxfs_mount( { struct xfs_buf *bp; struct xfs_sb *sbp; + struct xfs_rtgroup *rtg = NULL; xfs_daddr_t d; int i; int error; @@ -824,6 +826,19 @@ libxfs_mount( if (xfs_has_metadir(mp)) libxfs_mount_setup_metadir(mp); + error = libxfs_initialize_rtgroups(mp, 0, sbp->sb_rgcount, + sbp->sb_rextents); + if (error) { + fprintf(stderr, _("%s: rtgroup init failed\n"), + progname); + exit(1); + } + + while ((rtg = xfs_rtgroup_next(mp, rtg))) + rtg->rtg_extents = xfs_rtgroup_extents(mp, rtg_rgno(rtg)); + + xfs_set_rtgroup_data_loaded(mp); + return mp; out_da: xfs_da_unmount(mp); @@ -957,6 +972,8 @@ libxfs_umount( * Only try to free the per-AG structures if we set them up in the * first place. */ + if (xfs_is_rtgroup_data_loaded(mp)) + libxfs_free_rtgroups(mp, 0, mp->m_sb.sb_rgcount); if (xfs_is_perag_data_loaded(mp)) libxfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount); diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 2f218296688477..c4f42754c311fc 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -168,6 +168,7 @@ #define xfs_free_extent libxfs_free_extent #define xfs_free_extent_later libxfs_free_extent_later #define xfs_free_perag_range libxfs_free_perag_range +#define xfs_free_rtgroups libxfs_free_rtgroups #define xfs_fs_geometry libxfs_fs_geometry #define xfs_gbno_to_fsb libxfs_gbno_to_fsb #define xfs_get_initial_prid libxfs_get_initial_prid @@ -189,6 +190,7 @@ #define xfs_initialize_perag libxfs_initialize_perag #define xfs_initialize_perag_data libxfs_initialize_perag_data +#define xfs_initialize_rtgroups libxfs_initialize_rtgroups #define xfs_init_local_fork libxfs_init_local_fork #define xfs_inobt_init_cursor libxfs_inobt_init_cursor @@ -276,6 +278,8 @@ #define xfs_rtbitmap_setword libxfs_rtbitmap_setword #define xfs_rtbitmap_wordcount libxfs_rtbitmap_wordcount +#define xfs_rtgroup_alloc libxfs_rtgroup_alloc + #define xfs_suminfo_add libxfs_suminfo_add #define xfs_suminfo_get libxfs_suminfo_get #define xfs_rtsummary_wordcount libxfs_rtsummary_wordcount diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 631abf266ad526..620cd13b8ef796 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -204,10 +204,6 @@ enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; #define xfs_info_once(dev, fmt, ...) \ xfs_printk_once(xfs_info, dev, fmt, ##__VA_ARGS__) -/* miscellaneous kernel routines not in user space */ -#define likely(x) (x) -#define unlikely(x) (x) - /* Need to be able to handle this bare or in control flow */ static inline bool WARN_ON(bool expr) { return (expr); @@ -238,35 +234,6 @@ struct mnt_idmap; void inode_init_owner(struct mnt_idmap *idmap, struct inode *inode, const struct inode *dir, umode_t mode); -#define __must_check __attribute__((__warn_unused_result__)) - -/* - * Allows for effectively applying __must_check to a macro so we can have - * both the type-agnostic benefits of the macros while also being able to - * enforce that the return value is, in fact, checked. - */ -static inline bool __must_check __must_check_overflow(bool overflow) -{ - return unlikely(overflow); -} - -/* - * For simplicity and code hygiene, the fallback code below insists on - * a, b and *d having the same type (similar to the min() and max() - * macros), whereas gcc's type-generic overflow checkers accept - * different types. Hence we don't just make check_add_overflow an - * alias for __builtin_add_overflow, but add type checks similar to - * below. - */ -#define check_add_overflow(a, b, d) __must_check_overflow(({ \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - typeof(d) __d = (d); \ - (void) (&__a == &__b); \ - (void) (&__a == __d); \ - __builtin_add_overflow(__a, __b, __d); \ -})) - #define min_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) #define max_t(type,x,y) \ diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index 616f81045921b7..867060d60e8583 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -176,6 +176,9 @@ typedef struct xfs_sb { xfs_ino_t sb_metadirino; /* metadata directory tree root */ + xfs_rgnumber_t sb_rgcount; /* number of realtime groups */ + xfs_rtxlen_t sb_rgextents; /* size of a realtime group in rtx */ + /* must be padded to 64 bit alignment */ } xfs_sb_t; diff --git a/libxfs/xfs_rtgroup.c b/libxfs/xfs_rtgroup.c new file mode 100644 index 00000000000000..88f31384bf6961 --- /dev/null +++ b/libxfs/xfs_rtgroup.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong <djwong@xxxxxxxxxx> + */ +#include "libxfs_priv.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_bit.h" +#include "xfs_sb.h" +#include "xfs_mount.h" +#include "xfs_btree.h" +#include "xfs_alloc_btree.h" +#include "xfs_rmap_btree.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_rmap.h" +#include "xfs_ag.h" +#include "xfs_ag_resv.h" +#include "xfs_health.h" +#include "xfs_bmap.h" +#include "xfs_defer.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_trace.h" +#include "xfs_inode.h" +#include "xfs_rtgroup.h" +#include "xfs_rtbitmap.h" + +int +xfs_rtgroup_alloc( + struct xfs_mount *mp, + xfs_rgnumber_t rgno, + xfs_rgnumber_t rgcount, + xfs_rtbxlen_t rextents) +{ + struct xfs_rtgroup *rtg; + int error; + + rtg = kzalloc(sizeof(struct xfs_rtgroup), GFP_KERNEL); + if (!rtg) + return -ENOMEM; + + error = xfs_group_insert(mp, rtg_group(rtg), rgno, XG_TYPE_RTG); + if (error) + goto out_free_rtg; + return 0; + +out_free_rtg: + kfree(rtg); + return error; +} + +void +xfs_rtgroup_free( + struct xfs_mount *mp, + xfs_rgnumber_t rgno) +{ + xfs_group_free(mp, rgno, XG_TYPE_RTG, NULL); +} + +/* Free a range of incore rtgroup objects. */ +void +xfs_free_rtgroups( + struct xfs_mount *mp, + xfs_rgnumber_t first_rgno, + xfs_rgnumber_t end_rgno) +{ + xfs_rgnumber_t rgno; + + for (rgno = first_rgno; rgno < end_rgno; rgno++) + xfs_rtgroup_free(mp, rgno); +} + +/* Initialize some range of incore rtgroup objects. */ +int +xfs_initialize_rtgroups( + struct xfs_mount *mp, + xfs_rgnumber_t first_rgno, + xfs_rgnumber_t end_rgno, + xfs_rtbxlen_t rextents) +{ + xfs_rgnumber_t index; + int error; + + if (first_rgno >= end_rgno) + return 0; + + for (index = first_rgno; index < end_rgno; index++) { + error = xfs_rtgroup_alloc(mp, index, end_rgno, rextents); + if (error) + goto out_unwind_new_rtgs; + } + + return 0; + +out_unwind_new_rtgs: + xfs_free_rtgroups(mp, first_rgno, index); + return error; +} + +/* Compute the number of rt extents in this realtime group. */ +xfs_rtxnum_t +__xfs_rtgroup_extents( + struct xfs_mount *mp, + xfs_rgnumber_t rgno, + xfs_rgnumber_t rgcount, + xfs_rtbxlen_t rextents) +{ + ASSERT(rgno < rgcount); + if (rgno == rgcount - 1) + return rextents - ((xfs_rtxnum_t)rgno * mp->m_sb.sb_rgextents); + + ASSERT(xfs_has_rtgroups(mp)); + return mp->m_sb.sb_rgextents; +} + +xfs_rtxnum_t +xfs_rtgroup_extents( + struct xfs_mount *mp, + xfs_rgnumber_t rgno) +{ + return __xfs_rtgroup_extents(mp, rgno, mp->m_sb.sb_rgcount, + mp->m_sb.sb_rextents); +} + +/* + * Update the rt extent count of the previous tail rtgroup if it changed during + * recovery (i.e. recovery of a growfs). + */ +int +xfs_update_last_rtgroup_size( + struct xfs_mount *mp, + xfs_rgnumber_t prev_rgcount) +{ + struct xfs_rtgroup *rtg; + + ASSERT(prev_rgcount > 0); + + rtg = xfs_rtgroup_grab(mp, prev_rgcount - 1); + if (!rtg) + return -EFSCORRUPTED; + rtg->rtg_extents = __xfs_rtgroup_extents(mp, prev_rgcount - 1, + mp->m_sb.sb_rgcount, mp->m_sb.sb_rextents); + xfs_rtgroup_rele(rtg); + return 0; +} diff --git a/libxfs/xfs_rtgroup.h b/libxfs/xfs_rtgroup.h new file mode 100644 index 00000000000000..8872c27a9585fd --- /dev/null +++ b/libxfs/xfs_rtgroup.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong <djwong@xxxxxxxxxx> + */ +#ifndef __LIBXFS_RTGROUP_H +#define __LIBXFS_RTGROUP_H 1 + +#include "xfs_group.h" + +struct xfs_mount; +struct xfs_trans; + +/* + * Realtime group incore structure, similar to the per-AG structure. + */ +struct xfs_rtgroup { + struct xfs_group rtg_group; + + /* Number of blocks in this group */ + xfs_rtxnum_t rtg_extents; +}; + +static inline struct xfs_rtgroup *to_rtg(struct xfs_group *xg) +{ + return container_of(xg, struct xfs_rtgroup, rtg_group); +} + +static inline struct xfs_group *rtg_group(struct xfs_rtgroup *rtg) +{ + return &rtg->rtg_group; +} + +static inline struct xfs_mount *rtg_mount(const struct xfs_rtgroup *rtg) +{ + return rtg->rtg_group.xg_mount; +} + +static inline xfs_rgnumber_t rtg_rgno(const struct xfs_rtgroup *rtg) +{ + return rtg->rtg_group.xg_gno; +} + +/* Passive rtgroup references */ +static inline struct xfs_rtgroup * +xfs_rtgroup_get( + struct xfs_mount *mp, + xfs_rgnumber_t rgno) +{ + return to_rtg(xfs_group_get(mp, rgno, XG_TYPE_RTG)); +} + +static inline struct xfs_rtgroup * +xfs_rtgroup_hold( + struct xfs_rtgroup *rtg) +{ + return to_rtg(xfs_group_hold(rtg_group(rtg))); +} + +static inline void +xfs_rtgroup_put( + struct xfs_rtgroup *rtg) +{ + xfs_group_put(rtg_group(rtg)); +} + +/* Active rtgroup references */ +static inline struct xfs_rtgroup * +xfs_rtgroup_grab( + struct xfs_mount *mp, + xfs_rgnumber_t rgno) +{ + return to_rtg(xfs_group_grab(mp, rgno, XG_TYPE_RTG)); +} + +static inline void +xfs_rtgroup_rele( + struct xfs_rtgroup *rtg) +{ + xfs_group_rele(rtg_group(rtg)); +} + +static inline struct xfs_rtgroup * +xfs_rtgroup_next_range( + struct xfs_mount *mp, + struct xfs_rtgroup *rtg, + xfs_rgnumber_t start_rgno, + xfs_rgnumber_t end_rgno) +{ + return to_rtg(xfs_group_next_range(mp, rtg ? rtg_group(rtg) : NULL, + start_rgno, end_rgno, XG_TYPE_RTG)); +} + +static inline struct xfs_rtgroup * +xfs_rtgroup_next( + struct xfs_mount *mp, + struct xfs_rtgroup *rtg) +{ + return xfs_rtgroup_next_range(mp, rtg, 0, mp->m_sb.sb_rgcount - 1); +} + +static inline xfs_rtblock_t +xfs_rgno_start_rtb( + struct xfs_mount *mp, + xfs_rgnumber_t rgno) +{ + if (mp->m_rgblklog >= 0) + return ((xfs_rtblock_t)rgno << mp->m_rgblklog); + return ((xfs_rtblock_t)rgno * mp->m_rgblocks); +} + +static inline xfs_rtblock_t +__xfs_rgbno_to_rtb( + struct xfs_mount *mp, + xfs_rgnumber_t rgno, + xfs_rgblock_t rgbno) +{ + return xfs_rgno_start_rtb(mp, rgno) + rgbno; +} + +static inline xfs_rtblock_t +xfs_rgbno_to_rtb( + struct xfs_rtgroup *rtg, + xfs_rgblock_t rgbno) +{ + return __xfs_rgbno_to_rtb(rtg_mount(rtg), rtg_rgno(rtg), rgbno); +} + +static inline xfs_rgnumber_t +xfs_rtb_to_rgno( + struct xfs_mount *mp, + xfs_rtblock_t rtbno) +{ + if (!xfs_has_rtgroups(mp)) + return 0; + + if (mp->m_rgblklog >= 0) + return rtbno >> mp->m_rgblklog; + + return div_u64(rtbno, mp->m_rgblocks); +} + +static inline uint64_t +__xfs_rtb_to_rgbno( + struct xfs_mount *mp, + xfs_rtblock_t rtbno) +{ + uint32_t rem; + + if (!xfs_has_rtgroups(mp)) + return rtbno; + + if (mp->m_rgblklog >= 0) + return rtbno & mp->m_rgblkmask; + + div_u64_rem(rtbno, mp->m_rgblocks, &rem); + return rem; +} + +static inline xfs_rgblock_t +xfs_rtb_to_rgbno( + struct xfs_mount *mp, + xfs_rtblock_t rtbno) +{ + return __xfs_rtb_to_rgbno(mp, rtbno); +} + +static inline xfs_daddr_t +xfs_rtb_to_daddr( + struct xfs_mount *mp, + xfs_rtblock_t rtbno) +{ + return rtbno << mp->m_blkbb_log; +} + +static inline xfs_rtblock_t +xfs_daddr_to_rtb( + struct xfs_mount *mp, + xfs_daddr_t daddr) +{ + return daddr >> mp->m_blkbb_log; +} + +#ifdef CONFIG_XFS_RT +int xfs_rtgroup_alloc(struct xfs_mount *mp, xfs_rgnumber_t rgno, + xfs_rgnumber_t rgcount, xfs_rtbxlen_t rextents); +void xfs_rtgroup_free(struct xfs_mount *mp, xfs_rgnumber_t rgno); + +void xfs_free_rtgroups(struct xfs_mount *mp, xfs_rgnumber_t first_rgno, + xfs_rgnumber_t end_rgno); +int xfs_initialize_rtgroups(struct xfs_mount *mp, xfs_rgnumber_t first_rgno, + xfs_rgnumber_t end_rgno, xfs_rtbxlen_t rextents); + +xfs_rtxnum_t __xfs_rtgroup_extents(struct xfs_mount *mp, xfs_rgnumber_t rgno, + xfs_rgnumber_t rgcount, xfs_rtbxlen_t rextents); +xfs_rtxnum_t xfs_rtgroup_extents(struct xfs_mount *mp, xfs_rgnumber_t rgno); + +int xfs_update_last_rtgroup_size(struct xfs_mount *mp, + xfs_rgnumber_t prev_rgcount); +#else +static inline void xfs_free_rtgroups(struct xfs_mount *mp, + xfs_rgnumber_t first_rgno, xfs_rgnumber_t end_rgno) +{ +} + +static inline int xfs_initialize_rtgroups(struct xfs_mount *mp, + xfs_rgnumber_t first_rgno, xfs_rgnumber_t end_rgno, + xfs_rtbxlen_t rextents) +{ + return 0; +} + +# define xfs_rtgroup_extents(mp, rgno) (0) +# define xfs_update_last_rtgroup_size(mp, rgno) (-EOPNOTSUPP) +#endif /* CONFIG_XFS_RT */ + +#endif /* __LIBXFS_RTGROUP_H */ diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index 4ca57d592be8fa..2a5368c266ee91 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -707,6 +707,9 @@ __xfs_sb_from_disk( to->sb_metadirino = be64_to_cpu(from->sb_metadirino); else to->sb_metadirino = NULLFSINO; + + to->sb_rgcount = 1; + to->sb_rgextents = 0; } void @@ -991,8 +994,18 @@ xfs_mount_sb_set_rextsize( struct xfs_mount *mp, struct xfs_sb *sbp) { + struct xfs_groups *rgs = &mp->m_groups[XG_TYPE_RTG]; + mp->m_rtxblklog = log2_if_power2(sbp->sb_rextsize); mp->m_rtxblkmask = mask64_if_power2(sbp->sb_rextsize); + + mp->m_rgblocks = 0; + mp->m_rgblklog = 0; + mp->m_rgblkmask = (uint64_t)-1; + + rgs->blocks = 0; + rgs->blklog = 0; + rgs->blkmask = (uint64_t)-1; } /* diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h index 25053a66c225ed..bf33c2b1e43e5f 100644 --- a/libxfs/xfs_types.h +++ b/libxfs/xfs_types.h @@ -9,10 +9,12 @@ typedef uint32_t prid_t; /* project ID */ typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef uint32_t xfs_rgblock_t; /* blockno in realtime group */ typedef uint32_t xfs_agino_t; /* inode # within allocation grp */ typedef uint32_t xfs_extlen_t; /* extent length in blocks */ typedef uint32_t xfs_rtxlen_t; /* file extent length in rtextents */ typedef uint32_t xfs_agnumber_t; /* allocation group number */ +typedef uint32_t xfs_rgnumber_t; /* realtime group number */ typedef uint64_t xfs_extnum_t; /* # of extents in a file */ typedef uint32_t xfs_aextnum_t; /* # extents in an attribute fork */ typedef int64_t xfs_fsize_t; /* bytes in a file */ @@ -53,7 +55,9 @@ typedef void * xfs_failaddr_t; #define NULLFILEOFF ((xfs_fileoff_t)-1) #define NULLAGBLOCK ((xfs_agblock_t)-1) +#define NULLRGBLOCK ((xfs_rgblock_t)-1) #define NULLAGNUMBER ((xfs_agnumber_t)-1) +#define NULLRGNUMBER ((xfs_rgnumber_t)-1) #define NULLCOMMITLSN ((xfs_lsn_t)-1) @@ -214,11 +218,13 @@ enum xbtree_recpacking { enum xfs_group_type { XG_TYPE_AG, + XG_TYPE_RTG, XG_TYPE_MAX, } __packed; #define XG_TYPE_STRINGS \ - { XG_TYPE_AG, "ag" } + { XG_TYPE_AG, "ag" }, \ + { XG_TYPE_RTG, "rtg" } /* * Type verifier functions diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 4e51caead9dac2..2549a636568d1b 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3592,6 +3592,14 @@ sb_set_features( if (!fp->metadir) sbp->sb_bad_features2 = sbp->sb_features2; + /* + * This will be overriden later for real rtgroup file systems. For + * !rtgroups filesystems, we pretend that there's one huge group, just + * like __xfs_sb_from_disk does. + */ + sbp->sb_rgcount = 1; + sbp->sb_rgextents = 0; + if (!fp->crcs_enabled) return;