]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_db: display the realtime refcount btree contents
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:22:03 +0000 (10:22 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:16:02 +0000 (09:16 -0800)
Implement all the code we need to dump rtrefcountbt contents, starting
from the inode root.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
db/bmroot.c
db/bmroot.h
db/btblock.c
db/btblock.h
db/field.c
db/field.h
db/inode.c
db/type.c
db/type.h
libxfs/libxfs_api_defs.h
man/man8/xfs_db.8

index 65d808c46819460aed416b353ca351c4d71444d4..83507350b760cf7798829e7674aace390c54fdfe 100644 (file)
@@ -31,6 +31,13 @@ static int   rtrmaproot_key_offset(void *obj, int startoff, int idx);
 static int     rtrmaproot_ptr_count(void *obj, int startoff);
 static int     rtrmaproot_ptr_offset(void *obj, int startoff, int idx);
 
+static int     rtrefcroot_rec_count(void *obj, int startoff);
+static int     rtrefcroot_rec_offset(void *obj, int startoff, int idx);
+static int     rtrefcroot_key_count(void *obj, int startoff);
+static int     rtrefcroot_key_offset(void *obj, int startoff, int idx);
+static int     rtrefcroot_ptr_count(void *obj, int startoff);
+static int     rtrefcroot_ptr_offset(void *obj, int startoff, int idx);
+
 #define        OFF(f)  bitize(offsetof(xfs_bmdr_block_t, bb_ ## f))
 const field_t  bmroota_flds[] = {
        { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE },
@@ -73,6 +80,19 @@ const field_t        rtrmaproot_flds[] = {
          FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_RTRMAPBT },
        { NULL }
 };
+
+/* realtime refcount btree root */
+const field_t  rtrefcroot_flds[] = {
+       { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE },
+       { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE },
+       { "recs", FLDT_RTREFCBTREC, rtrefcroot_rec_offset, rtrefcroot_rec_count,
+         FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE },
+       { "keys", FLDT_RTREFCBTKEY, rtrefcroot_key_offset, rtrefcroot_key_count,
+         FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE },
+       { "ptrs", FLDT_RTREFCBTPTR, rtrefcroot_ptr_offset, rtrefcroot_ptr_count,
+         FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_RTREFCBT },
+       { NULL }
+};
 #undef OFF
 
 static int
@@ -376,3 +396,118 @@ rtrmaproot_size(
        dip = obj;
        return bitize((int)XFS_DFORK_DSIZE(dip, mp));
 }
+
+/* realtime refcount root */
+static int
+rtrefcroot_rec_count(
+       void                            *obj,
+       int                             startoff)
+{
+       struct xfs_dinode               *dip = obj;
+       struct xfs_rtrefcount_root      *block = XFS_DFORK_DPTR(dip);
+
+       ASSERT(block == obj + byteize(startoff));
+
+       if (be16_to_cpu(block->bb_level) > 0)
+               return 0;
+       return be16_to_cpu(block->bb_numrecs);
+}
+
+static int
+rtrefcroot_rec_offset(
+       void                            *obj,
+       int                             startoff,
+       int                             idx)
+{
+       struct xfs_dinode               *dip = obj;
+       struct xfs_rtrefcount_root      *block = XFS_DFORK_DPTR(dip);
+       struct xfs_refcount_rec         *kp;
+
+       ASSERT(block == obj + byteize(startoff));
+       ASSERT(be16_to_cpu(block->bb_level) == 0);
+
+       kp = xfs_rtrefcount_droot_rec_addr(block, idx);
+       return bitize((int)((char *)kp - (char *)block));
+}
+
+static int
+rtrefcroot_key_count(
+       void                            *obj,
+       int                             startoff)
+{
+       struct xfs_dinode               *dip = obj;
+       struct xfs_rtrefcount_root      *block = XFS_DFORK_DPTR(dip);
+
+       ASSERT(block == obj + byteize(startoff));
+
+       if (be16_to_cpu(block->bb_level) == 0)
+               return 0;
+       return be16_to_cpu(block->bb_numrecs);
+}
+
+static int
+rtrefcroot_key_offset(
+       void                            *obj,
+       int                             startoff,
+       int                             idx)
+{
+       struct xfs_dinode               *dip = obj;
+       struct xfs_rtrefcount_root      *block = XFS_DFORK_DPTR(dip);
+       struct xfs_refcount_key         *kp;
+
+       ASSERT(block == obj + byteize(startoff));
+       ASSERT(be16_to_cpu(block->bb_level) > 0);
+
+       kp = xfs_rtrefcount_droot_key_addr(block, idx);
+       return bitize((int)((char *)kp - (char *)block));
+}
+
+static int
+rtrefcroot_ptr_count(
+       void                            *obj,
+       int                             startoff)
+{
+       struct xfs_dinode               *dip = obj;
+       struct xfs_rtrefcount_root      *block = XFS_DFORK_DPTR(dip);
+
+       ASSERT(block == obj + byteize(startoff));
+
+       if (be16_to_cpu(block->bb_level) == 0)
+               return 0;
+       return be16_to_cpu(block->bb_numrecs);
+}
+
+static int
+rtrefcroot_ptr_offset(
+       void                            *obj,
+       int                             startoff,
+       int                             idx)
+{
+       struct xfs_dinode               *dip = obj;
+       struct xfs_rtrefcount_root      *block = XFS_DFORK_DPTR(dip);
+       xfs_rtrefcount_ptr_t            *pp;
+       int                             dmxr;
+
+       ASSERT(block == obj + byteize(startoff));
+       ASSERT(be16_to_cpu(block->bb_level) > 0);
+
+       dmxr = libxfs_rtrefcountbt_droot_maxrecs(XFS_DFORK_DSIZE(dip, mp),
+                       false);
+       pp = xfs_rtrefcount_droot_ptr_addr(block, idx, dmxr);
+       return bitize((int)((char *)pp - (char *)block));
+}
+
+int
+rtrefcroot_size(
+       void                    *obj,
+       int                     startoff,
+       int                     idx)
+{
+       struct xfs_dinode       *dip;
+
+       ASSERT(bitoffs(startoff) == 0);
+       ASSERT(obj == iocur_top->data);
+       ASSERT(idx == 0);
+       dip = obj;
+       return bitize((int)XFS_DFORK_DSIZE(dip, mp));
+}
index a2c5cfb18f0bb2ec0474f1a8317fb5036ffa2ad2..70bc8483cd85bc205c482a70325565cc3875b43a 100644 (file)
@@ -9,7 +9,9 @@ extern const struct field       bmroota_key_flds[];
 extern const struct field      bmrootd_flds[];
 extern const struct field      bmrootd_key_flds[];
 extern const struct field      rtrmaproot_flds[];
+extern const struct field      rtrefcroot_flds[];
 
 extern int     bmroota_size(void *obj, int startoff, int idx);
 extern int     bmrootd_size(void *obj, int startoff, int idx);
 extern int     rtrmaproot_size(void *obj, int startoff, int idx);
+extern int     rtrefcroot_size(void *obj, int startoff, int idx);
index 70f6c3f6aedde59f3886231a3844fec31f233bd7..40913a094375aa3b59232b17728e57cf40e8d840 100644 (file)
@@ -104,6 +104,12 @@ static struct xfs_db_btree {
                sizeof(struct xfs_refcount_rec),
                sizeof(__be32),
        },
+       {       XFS_RTREFC_CRC_MAGIC,
+               XFS_BTREE_LBLOCK_CRC_LEN,
+               sizeof(struct xfs_refcount_key),
+               sizeof(struct xfs_refcount_rec),
+               sizeof(__be64),
+       },
        {       0,
        },
 };
@@ -962,3 +968,47 @@ const field_t      refcbt_rec_flds[] = {
        { NULL }
 };
 #undef ROFF
+
+/* realtime refcount btree blocks */
+const field_t  rtrefcbt_crc_hfld[] = {
+       { "", FLDT_RTREFCBT_CRC, OI(0), C1, 0, TYP_NONE },
+       { NULL }
+};
+
+#define        OFF(f)  bitize(offsetof(struct xfs_btree_block, bb_ ## f))
+const field_t  rtrefcbt_crc_flds[] = {
+       { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE },
+       { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE },
+       { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE },
+       { "leftsib", FLDT_DFSBNO, OI(OFF(u.l.bb_leftsib)), C1, 0, TYP_RTREFCBT },
+       { "rightsib", FLDT_DFSBNO, OI(OFF(u.l.bb_rightsib)), C1, 0, TYP_RTREFCBT },
+       { "bno", FLDT_DFSBNO, OI(OFF(u.l.bb_blkno)), C1, 0, TYP_REFCBT },
+       { "lsn", FLDT_UINT64X, OI(OFF(u.l.bb_lsn)), C1, 0, TYP_NONE },
+       { "uuid", FLDT_UUID, OI(OFF(u.l.bb_uuid)), C1, 0, TYP_NONE },
+       { "owner", FLDT_INO, OI(OFF(u.l.bb_owner)), C1, 0, TYP_NONE },
+       { "crc", FLDT_CRC, OI(OFF(u.l.bb_crc)), C1, 0, TYP_NONE },
+       { "recs", FLDT_RTREFCBTREC, btblock_rec_offset, btblock_rec_count,
+         FLD_ARRAY | FLD_ABASE1 | FLD_COUNT | FLD_OFFSET, TYP_NONE },
+       { "keys", FLDT_RTREFCBTKEY, btblock_key_offset, btblock_key_count,
+         FLD_ARRAY | FLD_ABASE1 | FLD_COUNT | FLD_OFFSET, TYP_NONE },
+       { "ptrs", FLDT_RTREFCBTPTR, btblock_ptr_offset, btblock_key_count,
+         FLD_ARRAY | FLD_ABASE1 | FLD_COUNT | FLD_OFFSET, TYP_RTREFCBT },
+       { NULL }
+};
+#undef OFF
+
+const field_t  rtrefcbt_key_flds[] = {
+       { "startblock", FLDT_CRGBLOCK, OI(REFCNTBT_STARTBLOCK_BITOFF), C1, 0, TYP_DATA },
+       { "cowflag", FLDT_CCOWFLG, OI(REFCNTBT_COWFLAG_BITOFF), C1, 0, TYP_DATA },
+       { NULL }
+};
+
+#define        ROFF(f) bitize(offsetof(struct xfs_refcount_rec, rc_ ## f))
+const field_t  rtrefcbt_rec_flds[] = {
+       { "startblock", FLDT_CRGBLOCK, OI(REFCNTBT_STARTBLOCK_BITOFF), C1, 0, TYP_DATA },
+       { "blockcount", FLDT_EXTLEN, OI(ROFF(blockcount)), C1, 0, TYP_NONE },
+       { "refcount", FLDT_UINT32D, OI(ROFF(refcount)), C1, 0, TYP_DATA },
+       { "cowflag", FLDT_CCOWFLG, OI(REFCNTBT_COWFLAG_BITOFF), C1, 0, TYP_DATA },
+       { NULL }
+};
+#undef ROFF
index b4013ea8073ec62b7bdad927b3d059d6c94eacb2..5bbe857a7effd02ce6b92e1745d8ffe6a2cc195a 100644 (file)
@@ -63,4 +63,9 @@ extern const struct field     refcbt_crc_hfld[];
 extern const struct field      refcbt_key_flds[];
 extern const struct field      refcbt_rec_flds[];
 
+extern const struct field      rtrefcbt_crc_flds[];
+extern const struct field      rtrefcbt_crc_hfld[];
+extern const struct field      rtrefcbt_key_flds[];
+extern const struct field      rtrefcbt_rec_flds[];
+
 extern int     btblock_size(void *obj, int startoff, int idx);
index 60c4e16d781f488d6d81d24613c8628336b548b0..62c983fc3d49380ed9c7e49d63deccfc35221bc0 100644 (file)
@@ -214,6 +214,21 @@ const ftattr_t     ftattrtab[] = {
        { FLDT_REFCBTREC, "refcntbtrec", fp_sarray, (char *)refcbt_rec_flds,
          SI(bitsz(struct xfs_refcount_rec)), 0, NULL, refcbt_rec_flds },
 
+       { FLDT_CRGBLOCK, "crgblock", fp_num, "%u", SI(REFCNTBT_AGBLOCK_BITLEN),
+         FTARG_DONULL, NULL, NULL },
+       { FLDT_RTREFCBT_CRC, "rtrefcntbt", NULL, (char *)rtrefcbt_crc_flds,
+         btblock_size, FTARG_SIZE, NULL, rtrefcbt_crc_flds },
+       { FLDT_RTREFCBTKEY, "rtrefcntbtkey", fp_sarray,
+         (char *)rtrefcbt_key_flds, SI(bitsz(struct xfs_refcount_key)), 0,
+         NULL, rtrefcbt_key_flds },
+       { FLDT_RTREFCBTPTR, "rtrefcntbtptr", fp_num, "%u",
+         SI(bitsz(xfs_rtrefcount_ptr_t)), 0, fa_dfsbno, NULL },
+       { FLDT_RTREFCBTREC, "rtrefcntbtrec", fp_sarray,
+         (char *)rtrefcbt_rec_flds, SI(bitsz(struct xfs_refcount_rec)), 0,
+         NULL, rtrefcbt_rec_flds },
+       { FLDT_RTREFCROOT, "rtrefcroot", NULL, (char *)rtrefcroot_flds,
+         rtrefcroot_size, FTARG_SIZE, NULL, rtrefcroot_flds },
+
 /* CRC field */
        { FLDT_CRC, "crc", fp_crc, "%#x (%s)", SI(bitsz(uint32_t)),
          0, NULL, NULL },
index 67b6cb2a798719412ef69ec3554f93cd1f1384d0..27df5a0fcd1bdd784abb385e2d3622ee05f20463 100644 (file)
@@ -93,6 +93,12 @@ typedef enum fldt    {
        FLDT_REFCBTKEY,
        FLDT_REFCBTPTR,
        FLDT_REFCBTREC,
+       FLDT_CRGBLOCK,
+       FLDT_RTREFCBT_CRC,
+       FLDT_RTREFCBTKEY,
+       FLDT_RTREFCBTPTR,
+       FLDT_RTREFCBTREC,
+       FLDT_RTREFCROOT,
 
        /* CRC field type */
        FLDT_CRC,
index 45368a3343a17a710839c851299cd5a70b532cf9..46f83f18f083ce16aea6d9a5daf44bda8e088c6e 100644 (file)
@@ -49,6 +49,7 @@ static int    inode_u_sfdir2_count(void *obj, int startoff);
 static int     inode_u_sfdir3_count(void *obj, int startoff);
 static int     inode_u_symlink_count(void *obj, int startoff);
 static int     inode_u_rtrmapbt_count(void *obj, int startoff);
+static int     inode_u_rtrefcbt_count(void *obj, int startoff);
 
 static const cmdinfo_t inode_cmd =
        { "inode", NULL, inode_f, 0, 1, 1, "[inode#]",
@@ -236,6 +237,8 @@ const field_t       inode_u_flds[] = {
          TYP_NONE },
        { "rtrmapbt", FLDT_RTRMAPROOT, NULL, inode_u_rtrmapbt_count, FLD_COUNT,
          TYP_NONE },
+       { "rtrefcbt", FLDT_RTREFCROOT, NULL, inode_u_rtrefcbt_count, FLD_COUNT,
+         TYP_NONE },
        { NULL }
 };
 
@@ -302,7 +305,7 @@ fp_dinode_fmt(
 
 static const char      *metatype_name[] =
        { "unknown", "dir", "usrquota", "grpquota", "prjquota", "rtbitmap",
-         "rtsummary", "rtrmap"
+         "rtsummary", "rtrmap", "rtrefcount"
        };
 static const int       metatype_name_size = ARRAY_SIZE(metatype_name);
 
@@ -722,6 +725,8 @@ inode_next_type(void)
                                return TYP_RGSUMMARY;
                        case XFS_METAFILE_RTRMAP:
                                return TYP_RTRMAPBT;
+                       case XFS_METAFILE_RTREFCOUNT:
+                               return TYP_RTREFCBT;
                        default:
                                return TYP_DATA;
                        }
@@ -886,6 +891,21 @@ inode_u_rtrmapbt_count(
               dip->di_metatype == cpu_to_be16(XFS_METAFILE_RTRMAP);
 }
 
+static int
+inode_u_rtrefcbt_count(
+       void                    *obj,
+       int                     startoff)
+{
+       struct xfs_dinode       *dip;
+
+       ASSERT(bitoffs(startoff) == 0);
+       ASSERT(obj == iocur_top->data);
+       dip = obj;
+       ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
+       return dip->di_format == XFS_DINODE_FMT_META_BTREE &&
+              dip->di_metatype == cpu_to_be16(XFS_METAFILE_RTREFCOUNT);
+}
+
 int
 inode_u_size(
        void                    *obj,
index 1dfc33ffb44b87f975a3b6d859071c5d03cc389b..324f416a49cc4dbcd7fe6536aa35c91fd7ac73ce 100644 (file)
--- a/db/type.c
+++ b/db/type.c
@@ -53,6 +53,7 @@ static const typ_t    __typtab[] = {
        { TYP_RMAPBT, NULL },
        { TYP_RTRMAPBT, NULL },
        { TYP_REFCBT, NULL },
+       { TYP_RTREFCBT, NULL },
        { TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF },
        { TYP_DIR2, "dir2", handle_struct, dir2_hfld, NULL, TYP_F_NO_CRC_OFF },
        { TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld, NULL, TYP_F_NO_CRC_OFF },
@@ -96,6 +97,8 @@ static const typ_t    __typtab_crc[] = {
                &xfs_rtrmapbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
        { TYP_REFCBT, "refcntbt", handle_struct, refcbt_crc_hfld,
                &xfs_refcountbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+       { TYP_RTREFCBT, "rtrefcntbt", handle_struct, rtrefcbt_crc_hfld,
+               &xfs_rtrefcountbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
        { TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF },
        { TYP_DIR2, "dir3", handle_struct, dir3_hfld,
                &xfs_dir3_db_buf_ops, TYP_F_CRC_FUNC, xfs_dir3_set_crc },
@@ -148,6 +151,8 @@ static const typ_t  __typtab_spcrc[] = {
                &xfs_rtrmapbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
        { TYP_REFCBT, "refcntbt", handle_struct, refcbt_crc_hfld,
                &xfs_refcountbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+       { TYP_RTREFCBT, "rtrefcntbt", handle_struct, rtrefcbt_crc_hfld,
+               &xfs_rtrefcountbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
        { TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF },
        { TYP_DIR2, "dir3", handle_struct, dir3_hfld,
                &xfs_dir3_db_buf_ops, TYP_F_CRC_FUNC, xfs_dir3_set_crc },
index c98f3640202e876ddd31b5b41c3ae0213a687964..a2488a663dbd795e73f0a99a8d6bc5fdd8c7bc1d 100644 (file)
--- a/db/type.h
+++ b/db/type.h
@@ -22,6 +22,7 @@ typedef enum typnm
        TYP_RMAPBT,
        TYP_RTRMAPBT,
        TYP_REFCBT,
+       TYP_RTREFCBT,
        TYP_DATA,
        TYP_DIR2,
        TYP_DQBLK,
index df24f36f0d2874a22bccc0098ff5a4b37b70df90..167df04df8fb1b2659e9e1ef7aeebcf8f8c879ca 100644 (file)
 #define xfs_update_rtsb                        libxfs_update_rtsb
 #define xfs_rtgroup_get                        libxfs_rtgroup_get
 #define xfs_rtgroup_put                        libxfs_rtgroup_put
+
+#define xfs_rtrefcountbt_droot_maxrecs libxfs_rtrefcountbt_droot_maxrecs
+#define xfs_rtrefcountbt_maxrecs       libxfs_rtrefcountbt_maxrecs
+
 #define xfs_rtrmapbt_calc_reserves     libxfs_rtrmapbt_calc_reserves
 #define xfs_rtrmapbt_calc_size         libxfs_rtrmapbt_calc_size
 #define xfs_rtrmapbt_commit_staged_btree       libxfs_rtrmapbt_commit_staged_btree
index 784aa3cb46c588287bb726ae2c35b460a23fda86..8326bddcef837847b32ac38d6f80d13d3a3ae340 100644 (file)
@@ -1308,7 +1308,7 @@ The possible data types are:
 .BR agf ", " agfl ", " agi ", " attr ", " bmapbta ", " bmapbtd ,
 .BR bnobt ", " cntbt ", " data ", " dir ", " dir2 ", " dqblk ,
 .BR inobt ", " inode ", " log ", " refcntbt ", " rmapbt ", " rtbitmap ,
-.BR rtsummary ", " sb ", " symlink ", " rtrmapbt ", and " text .
+.BR rtsummary ", " sb ", " symlink ", " rtrmapbt ", " rtrefcbt ", and " text .
 See the TYPES section below for more information on these data types.
 .TP
 .BI "timelimit [" OPTIONS ]
@@ -2402,6 +2402,52 @@ block number within the allocation group to the next level in the Btree.
 .PD
 .RE
 .TP
+.B rtrefcbt
+There is one reference count Btree for the entire realtime device.  The
+.BR startblock " and "
+.B blockcount
+fields are 32 bits wide and record block counts within a realtime group.
+The root of this Btree is the realtime refcount inode, which is recorded in the
+metadata directory.
+Blocks are linked to sibling left and right blocks at each level, as well as by
+pointers from parent to child blocks.
+Each block has the following fields:
+.RS 1.4i
+.PD 0
+.TP 1.2i
+.B magic
+RTREFC block magic number, 0x52434e54 ('RCNT').
+.TP
+.B level
+level number of this block, 0 is a leaf.
+.TP
+.B numrecs
+number of data entries in the block.
+.TP
+.B leftsib
+left (logically lower) sibling block, 0 if none.
+.TP
+.B rightsib
+right (logically higher) sibling block, 0 if none.
+.TP
+.B recs
+[leaf blocks only] array of reference count records. Each record contains
+.BR startblock ,
+.BR blockcount ,
+and
+.BR refcount .
+.TP
+.B keys
+[non-leaf blocks only] array of key records. These are the first value
+of each block in the level below this one. Each record contains
+.BR startblock .
+.TP
+.B ptrs
+[non-leaf blocks only] array of child block pointers. Each pointer is a
+block number within the allocation group to the next level in the Btree.
+.PD
+.RE
+.TP
 .B rmapbt
 There is one set of filesystem blocks forming the reverse mapping Btree for
 each allocation group. The root block of this Btree is designated by the