@@ -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
@@ -390,3 +410,131 @@ 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_rtrefcount_root *block;
+#ifdef DEBUG
+ struct xfs_dinode *dip = obj;
+#endif
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrefcount_root *)((char *)obj + byteize(startoff));
+ ASSERT((char *)block == XFS_DFORK_DPTR(dip));
+ 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_rtrefcount_root *block;
+ struct xfs_refcount_rec *kp;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrefcount_root *)((char *)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_rtrefcount_root *block;
+#ifdef DEBUG
+ struct xfs_dinode *dip = obj;
+#endif
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrefcount_root *)((char *)obj + byteize(startoff));
+ ASSERT((char *)block == XFS_DFORK_DPTR(dip));
+ 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_rtrefcount_root *block;
+ struct xfs_refcount_key *kp;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrefcount_root *)((char *)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_rtrefcount_root *block;
+#ifdef DEBUG
+ struct xfs_dinode *dip = obj;
+#endif
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrefcount_root *)((char *)obj + byteize(startoff));
+ ASSERT((char *)block == XFS_DFORK_DPTR(dip));
+ 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_rtrefcount_root *block;
+ xfs_rtrefcount_ptr_t *pp;
+ struct xfs_dinode *dip;
+ int dmxr;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ dip = obj;
+ block = (struct xfs_rtrefcount_root *)((char *)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));
+}
@@ -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);
@@ -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
@@ -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);
@@ -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 },
@@ -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,
@@ -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,
@@ -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 },
@@ -22,6 +22,7 @@ typedef enum typnm
TYP_RMAPBT,
TYP_RTRMAPBT,
TYP_REFCBT,
+ TYP_RTREFCBT,
TYP_DATA,
TYP_DIR2,
TYP_DQBLK,
@@ -319,6 +319,10 @@
#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
@@ -1308,7 +1308,7 @@ .SH COMMANDS
.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 @@ .SH TYPES
.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