Skip to content

Commit b6c1beb

Browse files
committed
xfs: create helpers to scan an allocation group
Add some helpers to enable us to lock an AG's headers, create btree cursors for all btrees in that allocation group, and clean up afterwards. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 37f3fa7 commit b6c1beb

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

fs/xfs/scrub/common.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "scrub/scrub.h"
4545
#include "scrub/common.h"
4646
#include "scrub/trace.h"
47+
#include "scrub/btree.h"
4748

4849
/* Common code for the metadata scrubbers. */
4950

@@ -237,6 +238,184 @@ xfs_scrub_set_incomplete(
237238
trace_xfs_scrub_incomplete(sc, __return_address);
238239
}
239240

241+
/*
242+
* AG scrubbing
243+
*
244+
* These helpers facilitate locking an allocation group's header
245+
* buffers, setting up cursors for all btrees that are present, and
246+
* cleaning everything up once we're through.
247+
*/
248+
249+
/*
250+
* Grab all the headers for an AG.
251+
*
252+
* The headers should be released by xfs_scrub_ag_free, but as a fail
253+
* safe we attach all the buffers we grab to the scrub transaction so
254+
* they'll all be freed when we cancel it.
255+
*/
256+
int
257+
xfs_scrub_ag_read_headers(
258+
struct xfs_scrub_context *sc,
259+
xfs_agnumber_t agno,
260+
struct xfs_buf **agi,
261+
struct xfs_buf **agf,
262+
struct xfs_buf **agfl)
263+
{
264+
struct xfs_mount *mp = sc->mp;
265+
int error;
266+
267+
error = xfs_ialloc_read_agi(mp, sc->tp, agno, agi);
268+
if (error)
269+
goto out;
270+
271+
error = xfs_alloc_read_agf(mp, sc->tp, agno, 0, agf);
272+
if (error)
273+
goto out;
274+
if (!*agf) {
275+
error = -ENOMEM;
276+
goto out;
277+
}
278+
279+
error = xfs_alloc_read_agfl(mp, sc->tp, agno, agfl);
280+
if (error)
281+
goto out;
282+
283+
out:
284+
return error;
285+
}
286+
287+
/* Release all the AG btree cursors. */
288+
void
289+
xfs_scrub_ag_btcur_free(
290+
struct xfs_scrub_ag *sa)
291+
{
292+
if (sa->refc_cur)
293+
xfs_btree_del_cursor(sa->refc_cur, XFS_BTREE_ERROR);
294+
if (sa->rmap_cur)
295+
xfs_btree_del_cursor(sa->rmap_cur, XFS_BTREE_ERROR);
296+
if (sa->fino_cur)
297+
xfs_btree_del_cursor(sa->fino_cur, XFS_BTREE_ERROR);
298+
if (sa->ino_cur)
299+
xfs_btree_del_cursor(sa->ino_cur, XFS_BTREE_ERROR);
300+
if (sa->cnt_cur)
301+
xfs_btree_del_cursor(sa->cnt_cur, XFS_BTREE_ERROR);
302+
if (sa->bno_cur)
303+
xfs_btree_del_cursor(sa->bno_cur, XFS_BTREE_ERROR);
304+
305+
sa->refc_cur = NULL;
306+
sa->rmap_cur = NULL;
307+
sa->fino_cur = NULL;
308+
sa->ino_cur = NULL;
309+
sa->bno_cur = NULL;
310+
sa->cnt_cur = NULL;
311+
}
312+
313+
/* Initialize all the btree cursors for an AG. */
314+
int
315+
xfs_scrub_ag_btcur_init(
316+
struct xfs_scrub_context *sc,
317+
struct xfs_scrub_ag *sa)
318+
{
319+
struct xfs_mount *mp = sc->mp;
320+
xfs_agnumber_t agno = sa->agno;
321+
322+
if (sa->agf_bp) {
323+
/* Set up a bnobt cursor for cross-referencing. */
324+
sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
325+
agno, XFS_BTNUM_BNO);
326+
if (!sa->bno_cur)
327+
goto err;
328+
329+
/* Set up a cntbt cursor for cross-referencing. */
330+
sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
331+
agno, XFS_BTNUM_CNT);
332+
if (!sa->cnt_cur)
333+
goto err;
334+
}
335+
336+
/* Set up a inobt cursor for cross-referencing. */
337+
if (sa->agi_bp) {
338+
sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
339+
agno, XFS_BTNUM_INO);
340+
if (!sa->ino_cur)
341+
goto err;
342+
}
343+
344+
/* Set up a finobt cursor for cross-referencing. */
345+
if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb)) {
346+
sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
347+
agno, XFS_BTNUM_FINO);
348+
if (!sa->fino_cur)
349+
goto err;
350+
}
351+
352+
/* Set up a rmapbt cursor for cross-referencing. */
353+
if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb)) {
354+
sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
355+
agno);
356+
if (!sa->rmap_cur)
357+
goto err;
358+
}
359+
360+
/* Set up a refcountbt cursor for cross-referencing. */
361+
if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb)) {
362+
sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
363+
sa->agf_bp, agno, NULL);
364+
if (!sa->refc_cur)
365+
goto err;
366+
}
367+
368+
return 0;
369+
err:
370+
return -ENOMEM;
371+
}
372+
373+
/* Release the AG header context and btree cursors. */
374+
void
375+
xfs_scrub_ag_free(
376+
struct xfs_scrub_context *sc,
377+
struct xfs_scrub_ag *sa)
378+
{
379+
xfs_scrub_ag_btcur_free(sa);
380+
if (sa->agfl_bp) {
381+
xfs_trans_brelse(sc->tp, sa->agfl_bp);
382+
sa->agfl_bp = NULL;
383+
}
384+
if (sa->agf_bp) {
385+
xfs_trans_brelse(sc->tp, sa->agf_bp);
386+
sa->agf_bp = NULL;
387+
}
388+
if (sa->agi_bp) {
389+
xfs_trans_brelse(sc->tp, sa->agi_bp);
390+
sa->agi_bp = NULL;
391+
}
392+
sa->agno = NULLAGNUMBER;
393+
}
394+
395+
/*
396+
* For scrub, grab the AGI and the AGF headers, in that order. Locking
397+
* order requires us to get the AGI before the AGF. We use the
398+
* transaction to avoid deadlocking on crosslinked metadata buffers;
399+
* either the caller passes one in (bmap scrub) or we have to create a
400+
* transaction ourselves.
401+
*/
402+
int
403+
xfs_scrub_ag_init(
404+
struct xfs_scrub_context *sc,
405+
xfs_agnumber_t agno,
406+
struct xfs_scrub_ag *sa)
407+
{
408+
int error;
409+
410+
sa->agno = agno;
411+
error = xfs_scrub_ag_read_headers(sc, agno, &sa->agi_bp,
412+
&sa->agf_bp, &sa->agfl_bp);
413+
if (error)
414+
return error;
415+
416+
return xfs_scrub_ag_btcur_init(sc, sa);
417+
}
418+
240419
/* Per-scrubber setup functions */
241420

242421
/* Set us up with a transaction and an empty context. */

fs/xfs/scrub/common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,14 @@ void xfs_scrub_set_incomplete(struct xfs_scrub_context *sc);
7777
/* Setup functions */
7878
int xfs_scrub_setup_fs(struct xfs_scrub_context *sc, struct xfs_inode *ip);
7979

80+
void xfs_scrub_ag_free(struct xfs_scrub_context *sc, struct xfs_scrub_ag *sa);
81+
int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
82+
struct xfs_scrub_ag *sa);
83+
int xfs_scrub_ag_read_headers(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
84+
struct xfs_buf **agi, struct xfs_buf **agf,
85+
struct xfs_buf **agfl);
86+
void xfs_scrub_ag_btcur_free(struct xfs_scrub_ag *sa);
87+
int xfs_scrub_ag_btcur_init(struct xfs_scrub_context *sc,
88+
struct xfs_scrub_ag *sa);
89+
8090
#endif /* __XFS_SCRUB_COMMON_H__ */

fs/xfs/scrub/scrub.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include "scrub/scrub.h"
4545
#include "scrub/common.h"
4646
#include "scrub/trace.h"
47+
#include "scrub/scrub.h"
48+
#include "scrub/btree.h"
4749

4850
/*
4951
* Online Scrub and Repair
@@ -141,6 +143,7 @@ xfs_scrub_teardown(
141143
struct xfs_scrub_context *sc,
142144
int error)
143145
{
146+
xfs_scrub_ag_free(sc, &sc->sa);
144147
if (sc->tp) {
145148
xfs_trans_cancel(sc->tp);
146149
sc->tp = NULL;
@@ -241,6 +244,7 @@ xfs_scrub_metadata(
241244
sc.sm = sm;
242245
sc.ops = ops;
243246
sc.try_harder = try_harder;
247+
sc.sa.agno = NULLAGNUMBER;
244248
error = sc.ops->setup(&sc, ip);
245249
if (error)
246250
goto out_teardown;

fs/xfs/scrub/scrub.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@ struct xfs_scrub_meta_ops {
3434
bool (*has)(struct xfs_sb *);
3535
};
3636

37+
/* Buffer pointers and btree cursors for an entire AG. */
38+
struct xfs_scrub_ag {
39+
xfs_agnumber_t agno;
40+
41+
/* AG btree roots */
42+
struct xfs_buf *agf_bp;
43+
struct xfs_buf *agfl_bp;
44+
struct xfs_buf *agi_bp;
45+
46+
/* AG btrees */
47+
struct xfs_btree_cur *bno_cur;
48+
struct xfs_btree_cur *cnt_cur;
49+
struct xfs_btree_cur *ino_cur;
50+
struct xfs_btree_cur *fino_cur;
51+
struct xfs_btree_cur *rmap_cur;
52+
struct xfs_btree_cur *refc_cur;
53+
};
54+
3755
struct xfs_scrub_context {
3856
/* General scrub state. */
3957
struct xfs_mount *mp;
@@ -42,6 +60,9 @@ struct xfs_scrub_context {
4260
struct xfs_trans *tp;
4361
struct xfs_inode *ip;
4462
bool try_harder;
63+
64+
/* State tracking for single-AG operations. */
65+
struct xfs_scrub_ag sa;
4566
};
4667

4768
/* Metadata scrubbers */

0 commit comments

Comments
 (0)