#include "init.h"
#include "malloc.h"
#include "dir2.h"
+#include "inode.h"
typedef enum {
IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA,
DBM_RLDATA,
DBM_COWDATA,
DBM_RTSB,
+ DBM_BTRTRMAP,
DBM_NDBM
} dbm_t;
xfs_ino_t ino;
struct inodata *parent;
char *name;
+ xfs_rgnumber_t rgno; /* only if rtgroup metadata inode */
} inodata_t;
#define MIN_INODATA_HASH_SIZE 256
#define MAX_INODATA_HASH_SIZE 65536
"rldata",
"cowdata",
"rtsb",
+ "btrtrmap",
NULL
};
static void process_rtsummary(blkmap_t *blkmap);
static xfs_ino_t process_sf_dir_v2(struct xfs_dinode *dip, int *dot,
int *dotdot, inodata_t *id);
+static void process_rtrmap(struct inodata *id,
+ struct xfs_dinode *dip,
+ xfs_rfsblock_t *toti);
static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u,
int dq, xfs_qcnt_t bc, xfs_qcnt_t ic,
xfs_qcnt_t rc);
xfs_rfsblock_t *toti, xfs_extnum_t *nex,
blkmap_t **blkmapp, int isroot,
typnm_t btype);
+static void scanfunc_rtrmap(struct xfs_btree_block *block,
+ int level, dbm_t type, xfs_fsblock_t bno,
+ inodata_t *id, xfs_rfsblock_t *totd,
+ xfs_rfsblock_t *toti, xfs_extnum_t *nex,
+ blkmap_t **blkmapp, int isroot,
+ typnm_t btype);
static void scanfunc_bno(struct xfs_btree_block *block, int level,
xfs_agf_t *agf, xfs_agblock_t bno,
int isroot);
xfs_agnumber_t agno;
int oldprefix;
int sbyell;
+ int error;
if (dbmap) {
dbprintf(_("already have block usage information\n"));
return 0;
}
+ error = init_rtmeta_inode_bitmaps(mp);
+ if (error) {
+ dbprintf(_("error %d setting up rt metadata inode bitmaps\n"),
+ error);
+ exitcode = 3;
+ return 0;
+ }
+
if (!init(argc, argv)) {
if (serious_error)
exitcode = 3;
(1 << DBM_QUOTA) |
(1 << DBM_RTBITMAP) |
(1 << DBM_RTSUM) |
+ (1 << DBM_BTRTRMAP) |
(1 << DBM_SYMLINK) |
(1 << DBM_BTFINO) |
(1 << DBM_BTRMAP) |
0 /* type 15 unused */
};
static char *fmtnames[] = {
- "dev", "local", "extents", "btree", "uuid"
+ "dev", "local", "extents", "btree", "uuid", "rmap"
};
ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino);
be32_to_cpu(dip->di_next_unlinked), ino);
error++;
}
- /*
- * di_mode is a 16-bit uint so no need to check the < 0 case
- */
+
+ /* Check that mode and data fork format match. */
mode = be16_to_cpu(dip->di_mode);
- if ((((mode & S_IFMT) >> 12) > 15) ||
+ if (is_rtrmap_inode(ino)) {
+ if (!S_ISREG(mode) || dip->di_format != XFS_DINODE_FMT_RMAP) {
+ if (v)
+ dbprintf(
+ _("bad format %d for rtrmap inode %lld type %#o\n"),
+ dip->di_format, (long long)ino,
+ mode & S_IFMT);
+ error++;
+ return;
+ }
+ } else if ((((mode & S_IFMT) >> 12) > 15) ||
(!(okfmts[(mode & S_IFMT) >> 12] & (1 << dip->di_format)))) {
if (v)
dbprintf(_("bad format %d for inode %lld type %#o\n"),
type = DBM_QUOTA;
blkmap = blkmap_alloc(dnextents);
addlink_inode(id);
+ } else if (is_rtrmap_inode(id->ino)) {
+ type = DBM_BTRTRMAP;
+ blkmap = blkmap_alloc(be32_to_cpu(dip->di_nextents));
}
else
type = DBM_DATA;
process_btinode(id, dip, type, &totdblocks, &totiblocks,
&nextents, &blkmap, XFS_DATA_FORK);
break;
+ case XFS_DINODE_FMT_RMAP:
+ id->rgno = rtgroup_for_rtrmap_ino(mp, id->ino);
+ process_rtrmap(id, dip, &totiblocks);
+ break;
}
if (dip->di_forkoff) {
sbversion |= XFS_SB_VERSION_ATTRBIT;
case DBM_RTBITMAP:
case DBM_RTSUM:
case DBM_SYMLINK:
+ case DBM_BTRTRMAP:
case DBM_UNKNOWN:
bc = totdblocks + totiblocks +
atotdblocks + atotiblocks;
}
}
+static void
+process_rtrmap(
+ struct inodata *id,
+ struct xfs_dinode *dip,
+ xfs_rfsblock_t *toti)
+{
+ xfs_extnum_t nex = 0;
+ xfs_rfsblock_t totd = 0;
+ struct xfs_rtrmap_root *dib;
+ int whichfork = XFS_DATA_FORK;
+ int i;
+ int maxrecs;
+ xfs_rtrmap_ptr_t *pp;
+
+ if (id->rgno == NULLRGNUMBER) {
+ dbprintf(
+ _("rt group for rmap ino %lld not found\n"),
+ id->ino);
+ error++;
+ return;
+ }
+
+ dib = (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
+ if (be16_to_cpu(dib->bb_level) >= mp->m_rtrmap_maxlevels) {
+ if (!sflag || id->ilist)
+ dbprintf(_("level for ino %lld rtrmap root too "
+ "large (%u)\n"),
+ id->ino,
+ be16_to_cpu(dib->bb_level));
+ error++;
+ return;
+ }
+ maxrecs = libxfs_rtrmapbt_droot_maxrecs(
+ XFS_DFORK_SIZE(dip, mp, whichfork),
+ dib->bb_level == 0);
+ if (be16_to_cpu(dib->bb_numrecs) > maxrecs) {
+ if (!sflag || id->ilist)
+ dbprintf(_("numrecs for ino %lld rtrmap root too "
+ "large (%u)\n"),
+ id->ino,
+ be16_to_cpu(dib->bb_numrecs));
+ error++;
+ return;
+ }
+ if (be16_to_cpu(dib->bb_level) == 0) {
+ struct xfs_rmap_rec *rp;
+ xfs_fsblock_t lastblock;
+
+ rp = xfs_rtrmap_droot_rec_addr(dib, 1);
+ lastblock = 0;
+ for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++) {
+ if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
+ dbprintf(_(
+ "out-of-order rtrmap btree record %d (%u %u) root\n"),
+ i, be32_to_cpu(rp[i].rm_startblock),
+ be32_to_cpu(rp[i].rm_startblock));
+ } else {
+ lastblock = be32_to_cpu(rp[i].rm_startblock) +
+ be32_to_cpu(rp[i].rm_blockcount);
+ }
+ }
+ return;
+ } else {
+ pp = xfs_rtrmap_droot_ptr_addr(dib, 1, maxrecs);
+ for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
+ scan_lbtree(get_unaligned_be64(&pp[i]),
+ be16_to_cpu(dib->bb_level),
+ scanfunc_rtrmap, DBM_BTRTRMAP,
+ id, &totd, toti,
+ &nex, NULL, 1, TYP_RTRMAPBT);
+ }
+}
+
static xfs_ino_t
process_sf_dir_v2(
struct xfs_dinode *dip,
TYP_RMAPBT);
}
+static void
+scanfunc_rtrmap(
+ struct xfs_btree_block *block,
+ int level,
+ dbm_t type,
+ xfs_fsblock_t bno,
+ inodata_t *id,
+ xfs_rfsblock_t *totd,
+ xfs_rfsblock_t *toti,
+ xfs_extnum_t *nex,
+ blkmap_t **blkmapp,
+ int isroot,
+ typnm_t btype)
+{
+ xfs_agblock_t agbno;
+ xfs_agnumber_t agno;
+ int i;
+ xfs_rtrmap_ptr_t *pp;
+ struct xfs_rmap_rec *rp;
+ xfs_fsblock_t lastblock;
+
+ agno = XFS_FSB_TO_AGNO(mp, bno);
+ agbno = XFS_FSB_TO_AGBNO(mp, bno);
+ if (be32_to_cpu(block->bb_magic) != XFS_RTRMAP_CRC_MAGIC) {
+ dbprintf(_("bad magic # %#x in rtrmapbt block %u/%u\n"),
+ be32_to_cpu(block->bb_magic), agno, bno);
+ serious_error++;
+ return;
+ }
+ if (be16_to_cpu(block->bb_level) != level) {
+ if (!sflag)
+ dbprintf(_("expected level %d got %d in rtrmapbt block "
+ "%u/%u\n"),
+ level, be16_to_cpu(block->bb_level), agno, bno);
+ error++;
+ }
+ set_dbmap(agno, agbno, 1, type, agno, agbno);
+ set_inomap(agno, agbno, 1, id);
+ (*toti)++;
+ if (level == 0) {
+ if (be16_to_cpu(block->bb_numrecs) > mp->m_rtrmap_mxr[0] ||
+ (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rtrmap_mnr[0])) {
+ dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
+ "rtrmapbt block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs), mp->m_rtrmap_mnr[0],
+ mp->m_rtrmap_mxr[0], agno, bno);
+ serious_error++;
+ return;
+ }
+ rp = xfs_rtrmap_rec_addr(block, 1);
+ lastblock = 0;
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
+ if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
+ dbprintf(_(
+ "out-of-order rtrmap btree record %d (%u %u) block %u/%u l %llu\n"),
+ i, be32_to_cpu(rp[i].rm_startblock),
+ be32_to_cpu(rp[i].rm_blockcount),
+ agno, bno, lastblock);
+ } else {
+ lastblock = be32_to_cpu(rp[i].rm_startblock) +
+ be32_to_cpu(rp[i].rm_blockcount);
+ }
+ }
+ return;
+ }
+ if (be16_to_cpu(block->bb_numrecs) > mp->m_rtrmap_mxr[1] ||
+ (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rtrmap_mnr[1])) {
+ dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rtrmapbt "
+ "block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs), mp->m_rtrmap_mnr[1],
+ mp->m_rtrmap_mxr[1], agno, bno);
+ serious_error++;
+ return;
+ }
+ pp = xfs_rtrmap_ptr_addr(block, 1, mp->m_rtrmap_mxr[1]);
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
+ scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_rtrmap, type, id,
+ totd, toti, nex, blkmapp, 0, btype);
+}
+
static void
scanfunc_refcnt(
struct xfs_btree_block *block,