libxfs_buf_relse(bp);
}
- error = libxfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
+ error = libxfs_initialize_perag(mp, sbp->sb_agcount, sbp->sb_dblocks,
+ &mp->m_maxagi);
if (error) {
fprintf(stderr, _("%s: perag init failed\n"),
progname);
}
}
+/* Find the size of the AG, in blocks. */
+static xfs_agblock_t
+__xfs_ag_block_count(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agnumber_t agcount,
+ xfs_rfsblock_t dblocks)
+{
+ ASSERT(agno < agcount);
+
+ if (agno < agcount - 1)
+ return mp->m_sb.sb_agblocks;
+ return dblocks - (agno * mp->m_sb.sb_agblocks);
+}
+
+xfs_agblock_t
+xfs_ag_block_count(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno)
+{
+ return __xfs_ag_block_count(mp, agno, mp->m_sb.sb_agcount,
+ mp->m_sb.sb_dblocks);
+}
+
int
xfs_initialize_perag(
struct xfs_mount *mp,
xfs_agnumber_t agcount,
+ xfs_rfsblock_t dblocks,
xfs_agnumber_t *maxagi)
{
struct xfs_perag *pag;
/* first new pag is fully initialized */
if (first_initialised == NULLAGNUMBER)
first_initialised = index;
+
+ /*
+ * Pre-calculated geometry
+ */
+ pag->block_count = __xfs_ag_block_count(mp, index, agcount,
+ dblocks);
+ pag->min_block = XFS_AGFL_BLOCK(mp);
}
index = xfs_set_inode_alloc(mp, agcount);
if (error)
return error;
- return xfs_free_extent(tp, XFS_AGB_TO_FSB(pag->pag_mount, pag->pag_agno,
+ error = xfs_free_extent(tp, XFS_AGB_TO_FSB(pag->pag_mount, pag->pag_agno,
be32_to_cpu(agf->agf_length) - len),
len, &XFS_RMAP_OINFO_SKIP_UPDATE,
XFS_AG_RESV_NONE);
+ if (error)
+ return error;
+
+ /* Update perag geometry */
+ pag->block_count = be32_to_cpu(agf->agf_length);
+ return 0;
}
/* Retrieve AG geometry. */
/* for rcu-safe freeing */
struct rcu_head rcu_head;
+ /* Precalculated geometry info */
+ xfs_agblock_t block_count;
+ xfs_agblock_t min_block;
+
#ifdef __KERNEL__
/* -- kernel only structures below this line -- */
};
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
- xfs_agnumber_t *maxagi);
+ xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
void xfs_free_perag(struct xfs_mount *mp);
unsigned int tag);
void xfs_perag_put(struct xfs_perag *pag);
+/*
+ * Per-ag geometry infomation and validation
+ */
+xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
+
+static inline bool
+xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
+{
+ if (agbno >= pag->block_count)
+ return false;
+ if (agbno <= pag->min_block)
+ return false;
+ return true;
+}
+
/*
* Perag iteration APIs
*/
int *stat) /* output: success/failure */
{
struct xfs_mount *mp = cur->bc_mp;
- xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
+ struct xfs_perag *pag = cur->bc_ag.pag;
union xfs_btree_rec *rec;
int error;
goto out_bad_rec;
/* check for valid extent range, including overflow */
- if (!xfs_verify_agbno(mp, agno, *bno))
+ if (!xfs_verify_agbno(pag, *bno))
goto out_bad_rec;
if (*bno > *bno + *len)
goto out_bad_rec;
- if (!xfs_verify_agbno(mp, agno, *bno + *len - 1))
+ if (!xfs_verify_agbno(pag, *bno + *len - 1))
goto out_bad_rec;
return 0;
out_bad_rec:
xfs_warn(mp,
"%s Freespace BTree record corruption in AG %d detected!",
- cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size", agno);
+ cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size",
+ pag->pag_agno);
xfs_warn(mp,
"start block 0x%x block count 0x%x", *bno, *len);
return -EFSCORRUPTED;
static inline xfs_failaddr_t
xfs_btree_check_sblock_siblings(
- struct xfs_mount *mp,
+ struct xfs_perag *pag,
struct xfs_btree_cur *cur,
int level,
- xfs_agnumber_t agno,
xfs_agblock_t agbno,
__be32 dsibling)
{
if (!xfs_btree_check_sptr(cur, sibling, level + 1))
return __this_address;
} else {
- if (!xfs_verify_agbno(mp, agno, sibling))
+ if (!xfs_verify_agbno(pag, sibling))
return __this_address;
}
return NULL;
struct xfs_buf *bp)
{
struct xfs_mount *mp = cur->bc_mp;
+ struct xfs_perag *pag = cur->bc_ag.pag;
xfs_btnum_t btnum = cur->bc_btnum;
int crc = xfs_has_crc(mp);
xfs_failaddr_t fa;
xfs_agblock_t agbno = NULLAGBLOCK;
- xfs_agnumber_t agno = NULLAGNUMBER;
if (crc) {
if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
cur->bc_ops->get_maxrecs(cur, level))
return __this_address;
- if (bp) {
+ if (bp)
agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
- agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
- }
- fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno,
+ fa = xfs_btree_check_sblock_siblings(pag, cur, level, agbno,
block->bb_u.s.bb_leftsib);
if (!fa)
- fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno,
- agbno, block->bb_u.s.bb_rightsib);
+ fa = xfs_btree_check_sblock_siblings(pag, cur, level, agbno,
+ block->bb_u.s.bb_rightsib);
return fa;
}
{
if (level <= 0)
return false;
- return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.pag->pag_agno, agbno);
+ return xfs_verify_agbno(cur->bc_ag.pag, agbno);
}
/*
{
struct xfs_mount *mp = bp->b_mount;
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
- xfs_agnumber_t agno;
xfs_agblock_t agbno;
xfs_failaddr_t fa;
return __this_address;
/* sibling pointer verification */
- agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
- fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno,
+ fa = xfs_btree_check_sblock_siblings(bp->b_pag, NULL, -1, agbno,
block->bb_u.s.bb_leftsib);
if (!fa)
- fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno,
+ fa = xfs_btree_check_sblock_siblings(bp->b_pag, NULL, -1, agbno,
block->bb_u.s.bb_rightsib);
return fa;
}
int *stat)
{
struct xfs_mount *mp = cur->bc_mp;
- xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
+ struct xfs_perag *pag = cur->bc_ag.pag;
union xfs_btree_rec *rec;
int error;
xfs_agblock_t realstart;
return error;
xfs_refcount_btrec_to_irec(rec, irec);
-
- agno = cur->bc_ag.pag->pag_agno;
if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
goto out_bad_rec;
}
/* check for valid extent range, including overflow */
- if (!xfs_verify_agbno(mp, agno, realstart))
+ if (!xfs_verify_agbno(pag, realstart))
goto out_bad_rec;
if (realstart > realstart + irec->rc_blockcount)
goto out_bad_rec;
- if (!xfs_verify_agbno(mp, agno, realstart + irec->rc_blockcount - 1))
+ if (!xfs_verify_agbno(pag, realstart + irec->rc_blockcount - 1))
goto out_bad_rec;
if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
goto out_bad_rec;
- trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
+ trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec);
return 0;
out_bad_rec:
xfs_warn(mp,
- "Refcount BTree record corruption in AG %d detected!", agno);
+ "Refcount BTree record corruption in AG %d detected!",
+ pag->pag_agno);
xfs_warn(mp,
"Start block 0x%x, block count 0x%x, references 0x%x",
irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
int *stat)
{
struct xfs_mount *mp = cur->bc_mp;
- xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
+ struct xfs_perag *pag = cur->bc_ag.pag;
union xfs_btree_rec *rec;
int error;
goto out_bad_rec;
} else {
/* check for valid extent range, including overflow */
- if (!xfs_verify_agbno(mp, agno, irec->rm_startblock))
+ if (!xfs_verify_agbno(pag, irec->rm_startblock))
goto out_bad_rec;
if (irec->rm_startblock >
irec->rm_startblock + irec->rm_blockcount)
goto out_bad_rec;
- if (!xfs_verify_agbno(mp, agno,
+ if (!xfs_verify_agbno(pag,
irec->rm_startblock + irec->rm_blockcount - 1))
goto out_bad_rec;
}
out_bad_rec:
xfs_warn(mp,
"Reverse Mapping BTree record corruption in AG %d detected!",
- agno);
+ pag->pag_agno);
xfs_warn(mp,
"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
irec->rm_owner, irec->rm_flags, irec->rm_startblock,
#include "xfs_mount.h"
#include "xfs_ag.h"
-/* Find the size of the AG, in blocks. */
-inline xfs_agblock_t
-xfs_ag_block_count(
- struct xfs_mount *mp,
- xfs_agnumber_t agno)
-{
- ASSERT(agno < mp->m_sb.sb_agcount);
-
- if (agno < mp->m_sb.sb_agcount - 1)
- return mp->m_sb.sb_agblocks;
- return mp->m_sb.sb_dblocks - (agno * mp->m_sb.sb_agblocks);
-}
/*
* Verify that an AG block number pointer neither points outside the AG
* nor points at static metadata.
*/
-inline bool
-xfs_verify_agbno(
+static inline bool
+xfs_verify_agno_agbno(
struct xfs_mount *mp,
xfs_agnumber_t agno,
xfs_agblock_t agbno)
if (agno >= mp->m_sb.sb_agcount)
return false;
- return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));
+ return xfs_verify_agno_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));
}
/*
*/
struct xfs_mount;
-xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
-bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
- xfs_agblock_t agbno);
bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno);
bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno,
xfs_fsblock_t len);
const struct xfs_buf_ops *ops)
{
struct aghdr_cnts *agcnts = priv;
+ struct xfs_perag *pag;
const char *name;
int i;
xfs_alloc_ptr_t *pp;
}
rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
+ pag = libxfs_perag_get(mp, agno);
+
for (i = 0; i < numrecs; i++) {
xfs_agblock_t b, end;
xfs_extlen_t len, blen;
len = be32_to_cpu(rp[i].ar_blockcount);
end = b + len;
- if (!libxfs_verify_agbno(mp, agno, b)) {
+ if (!libxfs_verify_agbno(pag, b)) {
do_warn(
_("invalid start block %u in record %u of %s btree block %u/%u\n"),
b, i, name, agno, bno);
continue;
}
if (len == 0 || end <= b ||
- !libxfs_verify_agbno(mp, agno, end - 1)) {
+ !libxfs_verify_agbno(pag, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
}
}
}
+ libxfs_perag_put(pag);
return;
}
suspect = 0;
}
+ pag = libxfs_perag_get(mp, agno);
for (i = 0; i < numrecs; i++) {
xfs_agblock_t agbno = be32_to_cpu(pp[i]);
- if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ if (!libxfs_verify_agbno(pag, agbno)) {
do_warn(
_("bad btree pointer (%u) in %sbt block %u/%u\n"),
agbno, name, agno, bno);
suspect++;
+ libxfs_perag_put(pag);
return;
}
scan_sbtree(agbno, level, agno, suspect, scan_allocbt, 0,
magic, priv, ops);
}
+ libxfs_perag_put(pag);
}
static bool
uint64_t lastoffset = 0;
struct xfs_rmap_key *kp;
struct xfs_rmap_irec key = {0};
+ struct xfs_perag *pag;
if (magic != XFS_RMAP_CRC_MAGIC) {
name = "(unknown)";
i, agno, bno, name);
}
+ pag = libxfs_perag_get(mp, agno);
for (i = 0; i < numrecs; i++) {
xfs_agblock_t agbno = be32_to_cpu(pp[i]);
continue;
}
- if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ if (!libxfs_verify_agbno(pag, agbno)) {
do_warn(
_("bad btree pointer (%u) in %sbt block %u/%u\n"),
agbno, name, agno, bno);
suspect++;
+ libxfs_perag_put(pag);
return;
}
scan_sbtree(agbno, level, agno, suspect, scan_rmapbt, 0, magic,
priv, ops);
}
+ libxfs_perag_put(pag);
out:
if (suspect)
int state;
xfs_agblock_t lastblock = 0;
struct refc_priv *refc_priv = priv;
+ struct xfs_perag *pag;
if (magic != XFS_REFC_CRC_MAGIC) {
name = "(unknown)";
}
rp = XFS_REFCOUNT_REC_ADDR(block, 1);
+ pag = libxfs_perag_get(mp, agno);
+
for (i = 0; i < numrecs; i++) {
xfs_agblock_t b, agb, end;
xfs_extlen_t len;
}
end = agb + len;
- if (!libxfs_verify_agbno(mp, agno, agb)) {
+ if (!libxfs_verify_agbno(pag, agb)) {
do_warn(
_("invalid start block %u in record %u of %s btree block %u/%u\n"),
b, i, name, agno, bno);
continue;
}
if (len == 0 || end <= agb ||
- !libxfs_verify_agbno(mp, agno, end - 1)) {
+ !libxfs_verify_agbno(pag, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
/* XXX: probably want to mark the reflinked areas? */
}
+ libxfs_perag_put(pag);
goto out;
}
suspect = 0;
}
+ pag = libxfs_perag_get(mp, agno);
for (i = 0; i < numrecs; i++) {
xfs_agblock_t agbno = be32_to_cpu(pp[i]);
- if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ if (!libxfs_verify_agbno(pag, agbno)) {
do_warn(
_("bad btree pointer (%u) in %sbt block %u/%u\n"),
agbno, name, agno, bno);
suspect++;
+ libxfs_perag_put(pag);
return;
}
scan_sbtree(agbno, level, agno, suspect, scan_refcbt, 0, magic,
priv, ops);
}
+ libxfs_perag_put(pag);
out:
if (suspect)
refcount_avoid_check();
int hdr_errors;
int freecount;
struct xfs_ino_geometry *igeo = M_IGEO(mp);
+ struct xfs_perag *pag;
hdr_errors = 0;
else suspect++;
}
+ pag = libxfs_perag_get(mp, agno);
for (i = 0; i < numrecs; i++) {
xfs_agblock_t agbno = be32_to_cpu(pp[i]);
- if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ if (!libxfs_verify_agbno(pag, agbno)) {
do_warn(
_("bad btree pointer (%u) in %sbt block %u/%u\n"),
agbno, name, agno, bno);
suspect++;
+ libxfs_perag_put(pag);
return;
}
scan_sbtree(be32_to_cpu(pp[i]), level, agno, suspect,
scan_inobt, 0, magic, priv, ops);
}
+ libxfs_perag_put(pag);
}
struct agfl_state {
void *priv)
{
struct agfl_state *as = priv;
+ struct xfs_perag *pag;
- if (libxfs_verify_agbno(mp, as->agno, bno))
+ pag = libxfs_perag_get(mp, as->agno);
+ if (libxfs_verify_agbno(pag, bno))
set_bmap(as->agno, bno, XR_E_FREE);
else
do_warn(_("bad agbno %u in agfl, agno %d\n"),
bno, as->agno);
+
+ libxfs_perag_put(pag);
as->count++;
return 0;
}
xfs_agblock_t bno;
uint32_t magic;
unsigned int levels;
+ struct xfs_perag *pag = libxfs_perag_get(mp, agno);
levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
if (levels == 0 || levels > mp->m_alloc_maxlevels) {
}
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
- if (libxfs_verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(pag, bno)) {
magic = xfs_has_crc(mp) ? XFS_ABTB_CRC_MAGIC
: XFS_ABTB_MAGIC;
scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
}
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
- if (libxfs_verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(pag, bno)) {
magic = xfs_has_crc(mp) ? XFS_ABTC_CRC_MAGIC
: XFS_ABTC_MAGIC;
scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
}
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
- if (libxfs_verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(pag, bno)) {
scan_sbtree(bno, levels, agno, 0, scan_rmapbt, 1,
XFS_RMAP_CRC_MAGIC, &priv,
&xfs_rmapbt_buf_ops);
}
bno = be32_to_cpu(agf->agf_refcount_root);
- if (libxfs_verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(pag, bno)) {
struct refc_priv priv;
memset(&priv, 0, sizeof(priv));
do_warn(_("agf_btreeblks %u, counted %" PRIu64 " in ag %u\n"),
be32_to_cpu(agf->agf_btreeblks), agcnts->agfbtreeblks, agno);
}
+ libxfs_perag_put(pag);
}
int i;
uint32_t magic;
unsigned int levels;
+ struct xfs_perag *pag = libxfs_perag_get(mp, agno);
levels = be32_to_cpu(agi->agi_level);
if (levels == 0 || levels > M_IGEO(mp)->inobt_maxlevels) {
}
bno = be32_to_cpu(agi->agi_root);
- if (libxfs_verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(pag, bno)) {
magic = xfs_has_crc(mp) ? XFS_IBT_CRC_MAGIC
: XFS_IBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_level),
}
bno = be32_to_cpu(agi->agi_free_root);
- if (libxfs_verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(pag, bno)) {
magic = xfs_has_crc(mp) ?
XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_free_level),
XFS_AGINO_TO_INO(mp, agno, agino));
}
}
+ libxfs_perag_put(pag);
}
/*