summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:05:44 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-10-14 14:16:30 -0700
commitc9fea853e460d161d4745f125c45384bcfe32234 (patch)
treed488ca9ff7fc8640b199b627938b77ea408c73e1
parent4c19daa446e2e6b22927778659e769c42b3bc170 (diff)
xfs: convert xfs_ialloc_has_inodes_at_extent to return keyfill scan resultsscrub-detect-inobt-gaps_2022-10-14
Convert the xfs_ialloc_has_inodes_at_extent function to return keyfill scan results because for a given range of inode numbers, we might have no indexed inodes at all; the entire region might be allocated ondisk inodes; or there might be a mix of the two. Unfortunately, sparse inodes adds to the complexity, because each inode record can have holes, which means that we cannot use the generic btree _scan_keyfill function because we must look for holes in individual records to decide the result. On the plus side, online fsck can now detect sub-chunk discrepancies in the inobt. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c82
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.h5
-rw-r--r--fs/xfs/scrub/ialloc.c17
3 files changed, 62 insertions, 42 deletions
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 6cdfd64bc56b..63f5d637c83b 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2632,44 +2632,50 @@ xfs_ialloc_read_agi(
return 0;
}
-/* Is there an inode record covering a given range of inode numbers? */
-int
-xfs_ialloc_has_inode_record(
- struct xfs_btree_cur *cur,
- xfs_agino_t low,
- xfs_agino_t high,
- bool *exists)
+/* How many inodes are backed by inode clusters ondisk? */
+STATIC int
+xfs_ialloc_count_ondisk(
+ struct xfs_btree_cur *cur,
+ xfs_agino_t low,
+ xfs_agino_t high,
+ unsigned int *allocated)
{
struct xfs_inobt_rec_incore irec;
- xfs_agino_t agino;
- uint16_t holemask;
- int has_record;
- int i;
- int error;
+ unsigned int ret = 0;
+ int has_record;
+ int error;
- *exists = false;
error = xfs_inobt_lookup(cur, low, XFS_LOOKUP_LE, &has_record);
- while (error == 0 && has_record) {
+ if (error)
+ return error;
+
+ while (has_record) {
+ unsigned int i, hole_idx;
+
error = xfs_inobt_get_rec(cur, &irec, &has_record);
- if (error || irec.ir_startino > high)
+ if (error)
+ return error;
+ if (irec.ir_startino > high)
break;
- agino = irec.ir_startino;
- holemask = irec.ir_holemask;
- for (i = 0; i < XFS_INOBT_HOLEMASK_BITS; holemask >>= 1,
- i++, agino += XFS_INODES_PER_HOLEMASK_BIT) {
- if (holemask & 1)
+ for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {
+ if (irec.ir_startino + i < low)
continue;
- if (agino + XFS_INODES_PER_HOLEMASK_BIT > low &&
- agino <= high) {
- *exists = true;
- return 0;
- }
+ if (irec.ir_startino + i > high)
+ break;
+
+ hole_idx = i / XFS_INODES_PER_HOLEMASK_BIT;
+ if (!(irec.ir_holemask & (1U << hole_idx)))
+ ret++;
}
error = xfs_btree_increment(cur, 0, &has_record);
+ if (error)
+ return error;
}
- return error;
+
+ *allocated = ret;
+ return 0;
}
/* Is there an inode record covering a given extent? */
@@ -2678,15 +2684,27 @@ xfs_ialloc_has_inodes_at_extent(
struct xfs_btree_cur *cur,
xfs_agblock_t bno,
xfs_extlen_t len,
- bool *exists)
+ enum xfs_btree_keyfill *outcome)
{
- xfs_agino_t low;
- xfs_agino_t high;
+ xfs_agino_t agino;
+ xfs_agino_t last_agino;
+ unsigned int allocated;
+ int error;
- low = XFS_AGB_TO_AGINO(cur->bc_mp, bno);
- high = XFS_AGB_TO_AGINO(cur->bc_mp, bno + len) - 1;
+ agino = XFS_AGB_TO_AGINO(cur->bc_mp, bno);
+ last_agino = XFS_AGB_TO_AGINO(cur->bc_mp, bno + len) - 1;
- return xfs_ialloc_has_inode_record(cur, low, high, exists);
+ error = xfs_ialloc_count_ondisk(cur, agino, last_agino, &allocated);
+ if (error)
+ return error;
+
+ if (allocated == 0)
+ *outcome = XFS_BTREE_KEYFILL_EMPTY;
+ else if (allocated == last_agino - agino + 1)
+ *outcome = XFS_BTREE_KEYFILL_FULL;
+ else
+ *outcome = XFS_BTREE_KEYFILL_SPARSE;
+ return 0;
}
struct xfs_ialloc_count_inodes {
diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
index 9bbbca6ac4ed..96b99e6fbe11 100644
--- a/fs/xfs/libxfs/xfs_ialloc.h
+++ b/fs/xfs/libxfs/xfs_ialloc.h
@@ -93,9 +93,8 @@ void xfs_inobt_btrec_to_irec(struct xfs_mount *mp,
const union xfs_btree_rec *rec,
struct xfs_inobt_rec_incore *irec);
int xfs_ialloc_has_inodes_at_extent(struct xfs_btree_cur *cur,
- xfs_agblock_t bno, xfs_extlen_t len, bool *exists);
-int xfs_ialloc_has_inode_record(struct xfs_btree_cur *cur, xfs_agino_t low,
- xfs_agino_t high, bool *exists);
+ xfs_agblock_t bno, xfs_extlen_t len,
+ enum xfs_btree_keyfill *outcome);
int xfs_ialloc_count_inodes(struct xfs_btree_cur *cur, xfs_agino_t *count,
xfs_agino_t *freecount);
int xfs_inobt_insert_rec(struct xfs_btree_cur *cur, uint16_t holemask,
diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index b889142ccebe..43228f44d18f 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -788,18 +788,18 @@ xchk_xref_inode_check(
xfs_agblock_t agbno,
xfs_extlen_t len,
struct xfs_btree_cur **icur,
- bool should_have_inodes)
+ enum xfs_btree_keyfill expected)
{
- bool has_inodes;
+ enum xfs_btree_keyfill keyfill;
int error;
if (!(*icur) || xchk_skip_xref(sc->sm))
return;
- error = xfs_ialloc_has_inodes_at_extent(*icur, agbno, len, &has_inodes);
+ error = xfs_ialloc_has_inodes_at_extent(*icur, agbno, len, &keyfill);
if (!xchk_should_check_xref(sc, &error, icur))
return;
- if (has_inodes != should_have_inodes)
+ if (keyfill != expected)
xchk_btree_xref_set_corrupt(sc, *icur, 0);
}
@@ -810,8 +810,10 @@ xchk_xref_is_not_inode_chunk(
xfs_agblock_t agbno,
xfs_extlen_t len)
{
- xchk_xref_inode_check(sc, agbno, len, &sc->sa.ino_cur, false);
- xchk_xref_inode_check(sc, agbno, len, &sc->sa.fino_cur, false);
+ xchk_xref_inode_check(sc, agbno, len, &sc->sa.ino_cur,
+ XFS_BTREE_KEYFILL_EMPTY);
+ xchk_xref_inode_check(sc, agbno, len, &sc->sa.fino_cur,
+ XFS_BTREE_KEYFILL_EMPTY);
}
/* xref check that the extent is covered by inodes */
@@ -821,5 +823,6 @@ xchk_xref_is_inode_chunk(
xfs_agblock_t agbno,
xfs_extlen_t len)
{
- xchk_xref_inode_check(sc, agbno, len, &sc->sa.ino_cur, true);
+ xchk_xref_inode_check(sc, agbno, len, &sc->sa.ino_cur,
+ XFS_BTREE_KEYFILL_FULL);
}