Skip to content

Commit 3838456

Browse files
author
Darrick J. Wong
committed
xfs: detect unwritten bit set in rmapbt node block keys
In the last patch, we changed the rmapbt code to remove the UNWRITTEN bit when creating an rmapbt key from an rmapbt record, and we changed the rmapbt key comparison code to start considering the ATTR and BMBT flags during lookup. This brought the behavior of the rmapbt implementation in line with its specification. However, there may exist filesystems that have the unwritten bit still set in the rmapbt keys. We should detect these situations and flag the rmapbt as one that would benefit from optimization. Eventually, online repair will be able to do something in response to this. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 08c987d commit 3838456

3 files changed

Lines changed: 65 additions & 0 deletions

File tree

fs/xfs/scrub/btree.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,16 @@ xchk_btree_xref_set_corrupt(
119119
__return_address);
120120
}
121121

122+
void
123+
xchk_btree_set_preen(
124+
struct xfs_scrub *sc,
125+
struct xfs_btree_cur *cur,
126+
int level)
127+
{
128+
__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_PREEN,
129+
__return_address);
130+
}
131+
122132
/*
123133
* Make sure this record is in order and doesn't stray outside of the parent
124134
* keys.

fs/xfs/scrub/btree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ bool xchk_btree_xref_process_error(struct xfs_scrub *sc,
1919
/* Check for btree corruption. */
2020
void xchk_btree_set_corrupt(struct xfs_scrub *sc,
2121
struct xfs_btree_cur *cur, int level);
22+
void xchk_btree_set_preen(struct xfs_scrub *sc, struct xfs_btree_cur *cur,
23+
int level);
2224

2325
/* Check for btree xref discrepancies. */
2426
void xchk_btree_xref_set_corrupt(struct xfs_scrub *sc,

fs/xfs/scrub/rmap.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,58 @@ xchk_rmapbt_xref(
8787
xchk_rmapbt_xref_refc(sc, irec);
8888
}
8989

90+
/*
91+
* Check for bogus UNWRITTEN flags in the rmapbt node block keys.
92+
*
93+
* In reverse mapping records, the file mapping extent state
94+
* (XFS_RMAP_OFF_UNWRITTEN) is a record attribute, not a key field. It is not
95+
* involved in lookups in any way. In older kernels, the functions that
96+
* convert rmapbt records to keys forgot to filter out the extent state bit,
97+
* even though the key comparison functions have filtered the flag correctly.
98+
* If we spot an rmap key with the unwritten bit set in rm_offset, we should
99+
* mark the btree as needing optimization to rebuild the btree without those
100+
* flags.
101+
*/
102+
STATIC void
103+
xchk_rmapbt_check_unwritten_in_keyflags(
104+
struct xchk_btree *bs)
105+
{
106+
struct xfs_scrub *sc = bs->sc;
107+
struct xfs_btree_cur *cur = bs->cur;
108+
struct xfs_btree_block *keyblock;
109+
union xfs_btree_key *lkey, *hkey;
110+
__be64 badflag = cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
111+
unsigned int level;
112+
113+
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_PREEN)
114+
return;
115+
116+
for (level = 1; level < cur->bc_nlevels; level++) {
117+
struct xfs_buf *bp;
118+
unsigned int ptr;
119+
120+
/* Only check the first time we've seen this node block. */
121+
if (cur->bc_levels[level].ptr > 1)
122+
continue;
123+
124+
keyblock = xfs_btree_get_block(cur, level, &bp);
125+
for (ptr = 1; ptr <= be16_to_cpu(keyblock->bb_numrecs); ptr++) {
126+
lkey = xfs_btree_key_addr(cur, ptr, keyblock);
127+
128+
if (lkey->rmap.rm_offset & badflag) {
129+
xchk_btree_set_preen(sc, cur, level);
130+
break;
131+
}
132+
133+
hkey = xfs_btree_high_key_addr(cur, ptr, keyblock);
134+
if (hkey->rmap.rm_offset & badflag) {
135+
xchk_btree_set_preen(sc, cur, level);
136+
break;
137+
}
138+
}
139+
}
140+
}
141+
90142
/* Scrub an rmapbt record. */
91143
STATIC int
92144
xchk_rmapbt_rec(
@@ -101,6 +153,7 @@ xchk_rmapbt_rec(
101153
return 0;
102154
}
103155

156+
xchk_rmapbt_check_unwritten_in_keyflags(bs);
104157
xchk_rmapbt_xref(bs->sc, &irec);
105158
return 0;
106159
}

0 commit comments

Comments
 (0)