Skip to content

Commit 32080a9

Browse files
author
Darrick J. Wong
committed
xfs: repair the rmapbt
Rebuild the reverse mapping btree from all primary metadata. This first patch establishes the bare mechanics of finding records and putting together a new ondisk tree; more complex pieces are needed to make it work properly. Link: Documentation/filesystems/xfs-online-fsck-design.rst Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent e4fd1de commit 32080a9

18 files changed

Lines changed: 1608 additions & 19 deletions

fs/xfs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ xfs-y += $(addprefix scrub/, \
201201
reap.o \
202202
refcount_repair.o \
203203
repair.o \
204+
rmap_repair.o \
204205
)
205206

206207
xfs-$(CONFIG_XFS_RT) += $(addprefix scrub/, \

fs/xfs/libxfs/xfs_ag.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct xfs_perag {
9090
uint8_t pagf_repair_bno_level;
9191
uint8_t pagf_repair_cnt_level;
9292
uint8_t pagf_repair_refcount_level;
93+
uint8_t pagf_repair_rmap_level;
9394
#endif
9495

9596
spinlock_t pag_state_lock;

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6379,3 +6379,46 @@ xfs_bunmapi_range(
63796379
out:
63806380
return error;
63816381
}
6382+
6383+
struct xfs_bmap_query_range {
6384+
xfs_bmap_query_range_fn fn;
6385+
void *priv;
6386+
};
6387+
6388+
/* Format btree record and pass to our callback. */
6389+
STATIC int
6390+
xfs_bmap_query_range_helper(
6391+
struct xfs_btree_cur *cur,
6392+
const union xfs_btree_rec *rec,
6393+
void *priv)
6394+
{
6395+
struct xfs_bmap_query_range *query = priv;
6396+
struct xfs_bmbt_irec irec;
6397+
xfs_failaddr_t fa;
6398+
6399+
xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
6400+
fa = xfs_bmap_validate_extent(cur->bc_ino.ip, cur->bc_ino.whichfork,
6401+
&irec);
6402+
if (fa) {
6403+
xfs_btree_mark_sick(cur);
6404+
return xfs_bmap_complain_bad_rec(cur->bc_ino.ip,
6405+
cur->bc_ino.whichfork, fa, &irec);
6406+
}
6407+
6408+
return query->fn(cur, &irec, query->priv);
6409+
}
6410+
6411+
/* Find all bmaps. */
6412+
int
6413+
xfs_bmap_query_all(
6414+
struct xfs_btree_cur *cur,
6415+
xfs_bmap_query_range_fn fn,
6416+
void *priv)
6417+
{
6418+
struct xfs_bmap_query_range query = {
6419+
.priv = priv,
6420+
.fn = fn,
6421+
};
6422+
6423+
return xfs_btree_query_all(cur, xfs_bmap_query_range_helper, &query);
6424+
}

fs/xfs/libxfs/xfs_bmap.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,12 @@ extern struct kmem_cache *xfs_bmap_intent_cache;
280280
int __init xfs_bmap_intent_init_cache(void);
281281
void xfs_bmap_intent_destroy_cache(void);
282282

283+
typedef int (*xfs_bmap_query_range_fn)(
284+
struct xfs_btree_cur *cur,
285+
struct xfs_bmbt_irec *rec,
286+
void *priv);
287+
288+
int xfs_bmap_query_all(struct xfs_btree_cur *cur, xfs_bmap_query_range_fn fn,
289+
void *priv);
290+
283291
#endif /* __XFS_BMAP_H__ */

fs/xfs/libxfs/xfs_rmap.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ xfs_rmap_btrec_to_irec(
215215
/* Simple checks for rmap records. */
216216
xfs_failaddr_t
217217
xfs_rmap_check_irec(
218-
struct xfs_btree_cur *cur,
218+
struct xfs_perag *pag,
219219
const struct xfs_rmap_irec *irec)
220220
{
221-
struct xfs_mount *mp = cur->bc_mp;
221+
struct xfs_mount *mp = pag->pag_mount;
222222
bool is_inode;
223223
bool is_unwritten;
224224
bool is_bmbt;
@@ -233,8 +233,8 @@ xfs_rmap_check_irec(
233233
return __this_address;
234234
} else {
235235
/* check for valid extent range, including overflow */
236-
if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
237-
irec->rm_blockcount))
236+
if (!xfs_verify_agbext(pag, irec->rm_startblock,
237+
irec->rm_blockcount))
238238
return __this_address;
239239
}
240240

@@ -307,7 +307,7 @@ xfs_rmap_get_rec(
307307

308308
fa = xfs_rmap_btrec_to_irec(rec, irec);
309309
if (!fa)
310-
fa = xfs_rmap_check_irec(cur, irec);
310+
fa = xfs_rmap_check_irec(cur->bc_ag.pag, irec);
311311
if (fa)
312312
return xfs_rmap_complain_bad_rec(cur, fa, irec);
313313

@@ -2442,7 +2442,7 @@ xfs_rmap_query_range_helper(
24422442

24432443
fa = xfs_rmap_btrec_to_irec(rec, &irec);
24442444
if (!fa)
2445-
fa = xfs_rmap_check_irec(cur, &irec);
2445+
fa = xfs_rmap_check_irec(cur->bc_ag.pag, &irec);
24462446
if (fa)
24472447
return xfs_rmap_complain_bad_rec(cur, fa, &irec);
24482448

fs/xfs/libxfs/xfs_rmap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ 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,
198+
xfs_failaddr_t xfs_rmap_check_irec(struct xfs_perag *pag,
199199
const struct xfs_rmap_irec *irec);
200200

201201
int xfs_rmap_has_records(struct xfs_btree_cur *cur, xfs_agblock_t bno,

fs/xfs/libxfs/xfs_rmap_btree.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,18 @@ xfs_rmapbt_verify(
342342

343343
level = be16_to_cpu(block->bb_level);
344344
if (pag && xfs_perag_initialised_agf(pag)) {
345-
if (level >= pag->pagf_rmap_level)
345+
unsigned int maxlevel = pag->pagf_rmap_level;
346+
347+
#ifdef CONFIG_XFS_ONLINE_REPAIR
348+
/*
349+
* Online repair could be rewriting the free space btrees, so
350+
* we'll validate against the larger of either tree while this
351+
* is going on.
352+
*/
353+
maxlevel = max_t(unsigned int, maxlevel,
354+
pag->pagf_repair_rmap_level);
355+
#endif
356+
if (level >= maxlevel)
346357
return __this_address;
347358
} else if (level >= mp->m_rmap_maxlevels)
348359
return __this_address;

fs/xfs/scrub/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ xchk_perag_read_headers(
460460
* Grab the AG headers for the attached perag structure and wait for pending
461461
* intents to drain.
462462
*/
463-
static int
463+
int
464464
xchk_perag_drain_and_lock(
465465
struct xfs_scrub *sc)
466466
{

fs/xfs/scrub/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ int xchk_setup_nlinks(struct xfs_scrub *sc);
134134
void xchk_ag_free(struct xfs_scrub *sc, struct xchk_ag *sa);
135135
int xchk_ag_init(struct xfs_scrub *sc, xfs_agnumber_t agno,
136136
struct xchk_ag *sa);
137+
int xchk_perag_drain_and_lock(struct xfs_scrub *sc);
137138

138139
/*
139140
* Grab all AG resources, treating the inability to grab the perag structure as

fs/xfs/scrub/newbt.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,11 @@ xrep_newbt_alloc_ag_blocks(
239239

240240
xrep_newbt_validate_ag_alloc_hint(xnr);
241241

242-
error = xfs_alloc_vextent_near_bno(&args, xnr->alloc_hint);
242+
if (xnr->alloc_vextent)
243+
error = xnr->alloc_vextent(sc, &args, xnr->alloc_hint);
244+
else
245+
error = xfs_alloc_vextent_near_bno(&args,
246+
xnr->alloc_hint);
243247
if (error)
244248
return error;
245249
if (args.fsbno == NULLFSBLOCK)
@@ -309,7 +313,11 @@ xrep_newbt_alloc_file_blocks(
309313

310314
xrep_newbt_validate_file_alloc_hint(xnr);
311315

312-
error = xfs_alloc_vextent_start_ag(&args, xnr->alloc_hint);
316+
if (xnr->alloc_vextent)
317+
error = xnr->alloc_vextent(sc, &args, xnr->alloc_hint);
318+
else
319+
error = xfs_alloc_vextent_start_ag(&args,
320+
xnr->alloc_hint);
313321
if (error)
314322
return error;
315323
if (args.fsbno == NULLFSBLOCK)

0 commit comments

Comments
 (0)