Skip to content

Commit c4e3417

Browse files
author
Darrick J. Wong
committed
xfs: standardize ondisk to incore conversion for rmap btrees
Create a xfs_rmap_check_irec function to detect corruption in btree records. Fix all xfs_rmap_btrec_to_irec callsites to call the new helper and bubble up corruption reports. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 39ab26d commit c4e3417

3 files changed

Lines changed: 44 additions & 60 deletions

File tree

fs/xfs/libxfs/xfs_rmap.c

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,36 @@ xfs_rmap_btrec_to_irec(
205205
irec);
206206
}
207207

208+
/* Simple checks for rmap records. */
209+
xfs_failaddr_t
210+
xfs_rmap_check_irec(
211+
struct xfs_btree_cur *cur,
212+
const struct xfs_rmap_irec *irec)
213+
{
214+
struct xfs_mount *mp = cur->bc_mp;
215+
216+
if (irec->rm_blockcount == 0)
217+
return __this_address;
218+
if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
219+
if (irec->rm_owner != XFS_RMAP_OWN_FS)
220+
return __this_address;
221+
if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
222+
return __this_address;
223+
} else {
224+
/* check for valid extent range, including overflow */
225+
if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
226+
irec->rm_blockcount))
227+
return __this_address;
228+
}
229+
230+
if (!(xfs_verify_ino(mp, irec->rm_owner) ||
231+
(irec->rm_owner <= XFS_RMAP_OWN_FS &&
232+
irec->rm_owner >= XFS_RMAP_OWN_MIN)))
233+
return __this_address;
234+
235+
return NULL;
236+
}
237+
208238
/*
209239
* Get the data from the pointed-to record.
210240
*/
@@ -217,39 +247,24 @@ xfs_rmap_get_rec(
217247
struct xfs_mount *mp = cur->bc_mp;
218248
struct xfs_perag *pag = cur->bc_ag.pag;
219249
union xfs_btree_rec *rec;
250+
xfs_failaddr_t fa;
220251
int error;
221252

222253
error = xfs_btree_get_rec(cur, &rec, stat);
223254
if (error || !*stat)
224255
return error;
225256

226-
if (xfs_rmap_btrec_to_irec(rec, irec))
227-
goto out_bad_rec;
228-
229-
if (irec->rm_blockcount == 0)
230-
goto out_bad_rec;
231-
if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
232-
if (irec->rm_owner != XFS_RMAP_OWN_FS)
233-
goto out_bad_rec;
234-
if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
235-
goto out_bad_rec;
236-
} else {
237-
/* check for valid extent range, including overflow */
238-
if (!xfs_verify_agbext(pag, irec->rm_startblock,
239-
irec->rm_blockcount))
240-
goto out_bad_rec;
241-
}
242-
243-
if (!(xfs_verify_ino(mp, irec->rm_owner) ||
244-
(irec->rm_owner <= XFS_RMAP_OWN_FS &&
245-
irec->rm_owner >= XFS_RMAP_OWN_MIN)))
257+
fa = xfs_rmap_btrec_to_irec(rec, irec);
258+
if (!fa)
259+
fa = xfs_rmap_check_irec(cur, irec);
260+
if (fa)
246261
goto out_bad_rec;
247262

248263
return 0;
249264
out_bad_rec:
250265
xfs_warn(mp,
251-
"Reverse Mapping BTree record corruption in AG %d detected!",
252-
pag->pag_agno);
266+
"Reverse Mapping BTree record corruption in AG %d detected at %pS!",
267+
pag->pag_agno, fa);
253268
xfs_warn(mp,
254269
"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
255270
irec->rm_owner, irec->rm_flags, irec->rm_startblock,
@@ -2321,7 +2336,8 @@ xfs_rmap_query_range_helper(
23212336
struct xfs_rmap_query_range_info *query = priv;
23222337
struct xfs_rmap_irec irec;
23232338

2324-
if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL)
2339+
if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
2340+
xfs_rmap_check_irec(cur, &irec) != NULL)
23252341
return -EFSCORRUPTED;
23262342

23272343
return query->fn(cur, &irec, query->priv);

fs/xfs/libxfs/xfs_rmap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ int xfs_rmap_compare(const struct xfs_rmap_irec *a,
195195
union xfs_btree_rec;
196196
xfs_failaddr_t xfs_rmap_btrec_to_irec(const union xfs_btree_rec *rec,
197197
struct xfs_rmap_irec *irec);
198+
xfs_failaddr_t xfs_rmap_check_irec(struct xfs_btree_cur *cur,
199+
const struct xfs_rmap_irec *irec);
200+
198201
int xfs_rmap_has_record(struct xfs_btree_cur *cur, xfs_agblock_t bno,
199202
xfs_extlen_t len, bool *exists);
200203
int xfs_rmap_record_exists(struct xfs_btree_cur *cur, xfs_agblock_t bno,

fs/xfs/scrub/rmap.c

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -93,43 +93,18 @@ xchk_rmapbt_rec(
9393
struct xchk_btree *bs,
9494
const union xfs_btree_rec *rec)
9595
{
96-
struct xfs_mount *mp = bs->cur->bc_mp;
9796
struct xfs_rmap_irec irec;
98-
struct xfs_perag *pag = bs->cur->bc_ag.pag;
9997
bool non_inode;
10098
bool is_unwritten;
10199
bool is_bmbt;
102100
bool is_attr;
103101

104-
if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL) {
102+
if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
103+
xfs_rmap_check_irec(bs->cur, &irec) != NULL) {
105104
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
106105
return 0;
107106
}
108107

109-
/* Check extent. */
110-
if (irec.rm_startblock + irec.rm_blockcount <= irec.rm_startblock)
111-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
112-
113-
if (irec.rm_owner == XFS_RMAP_OWN_FS) {
114-
/*
115-
* xfs_verify_agbno returns false for static fs metadata.
116-
* Since that only exists at the start of the AG, validate
117-
* that by hand.
118-
*/
119-
if (irec.rm_startblock != 0 ||
120-
irec.rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
121-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
122-
} else {
123-
/*
124-
* Otherwise we must point somewhere past the static metadata
125-
* but before the end of the FS. Run the regular check.
126-
*/
127-
if (!xfs_verify_agbno(pag, irec.rm_startblock) ||
128-
!xfs_verify_agbno(pag, irec.rm_startblock +
129-
irec.rm_blockcount - 1))
130-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
131-
}
132-
133108
/* Check flags. */
134109
non_inode = XFS_RMAP_NON_INODE_OWNER(irec.rm_owner);
135110
is_bmbt = irec.rm_flags & XFS_RMAP_BMBT_BLOCK;
@@ -148,16 +123,6 @@ xchk_rmapbt_rec(
148123
if (non_inode && (is_bmbt || is_unwritten || is_attr))
149124
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
150125

151-
if (!non_inode) {
152-
if (!xfs_verify_ino(mp, irec.rm_owner))
153-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
154-
} else {
155-
/* Non-inode owner within the magic values? */
156-
if (irec.rm_owner <= XFS_RMAP_OWN_MIN ||
157-
irec.rm_owner > XFS_RMAP_OWN_FS)
158-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
159-
}
160-
161126
xchk_rmapbt_xref(bs->sc, &irec);
162127
return 0;
163128
}

0 commit comments

Comments
 (0)