Skip to content

Commit 537964b

Browse files
committed
xfs: create helpers to scrub a metadata btree
Create helper functions and tracepoints to deal with errors while scrubbing a metadata btree. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 4700d22 commit 537964b

File tree

5 files changed

+352
-0
lines changed

5 files changed

+352
-0
lines changed

fs/xfs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y)
143143

144144
xfs-y += $(addprefix scrub/, \
145145
trace.o \
146+
btree.o \
146147
common.o \
147148
scrub.o \
148149
)

fs/xfs/scrub/btree.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright (C) 2017 Oracle. All Rights Reserved.
3+
*
4+
* Author: Darrick J. Wong <darrick.wong@oracle.com>
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* as published by the Free Software Foundation; either version 2
9+
* of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it would be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
#include "xfs.h"
21+
#include "xfs_fs.h"
22+
#include "xfs_shared.h"
23+
#include "xfs_format.h"
24+
#include "xfs_trans_resv.h"
25+
#include "xfs_mount.h"
26+
#include "xfs_defer.h"
27+
#include "xfs_btree.h"
28+
#include "xfs_bit.h"
29+
#include "xfs_log_format.h"
30+
#include "xfs_trans.h"
31+
#include "xfs_sb.h"
32+
#include "xfs_inode.h"
33+
#include "xfs_alloc.h"
34+
#include "scrub/scrub.h"
35+
#include "scrub/common.h"
36+
#include "scrub/btree.h"
37+
#include "scrub/trace.h"
38+
39+
/* btree scrubbing */
40+
41+
/*
42+
* Check for btree operation errors. See the section about handling
43+
* operational errors in common.c.
44+
*/
45+
bool
46+
xfs_scrub_btree_process_error(
47+
struct xfs_scrub_context *sc,
48+
struct xfs_btree_cur *cur,
49+
int level,
50+
int *error)
51+
{
52+
if (*error == 0)
53+
return true;
54+
55+
switch (*error) {
56+
case -EDEADLOCK:
57+
/* Used to restart an op with deadlock avoidance. */
58+
trace_xfs_scrub_deadlock_retry(sc->ip, sc->sm, *error);
59+
break;
60+
case -EFSBADCRC:
61+
case -EFSCORRUPTED:
62+
/* Note the badness but don't abort. */
63+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
64+
*error = 0;
65+
/* fall through */
66+
default:
67+
if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
68+
trace_xfs_scrub_ifork_btree_op_error(sc, cur, level,
69+
*error, __return_address);
70+
else
71+
trace_xfs_scrub_btree_op_error(sc, cur, level,
72+
*error, __return_address);
73+
break;
74+
}
75+
return false;
76+
}
77+
78+
/* Record btree block corruption. */
79+
void
80+
xfs_scrub_btree_set_corrupt(
81+
struct xfs_scrub_context *sc,
82+
struct xfs_btree_cur *cur,
83+
int level)
84+
{
85+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
86+
87+
if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
88+
trace_xfs_scrub_ifork_btree_error(sc, cur, level,
89+
__return_address);
90+
else
91+
trace_xfs_scrub_btree_error(sc, cur, level,
92+
__return_address);
93+
}
94+
95+
/*
96+
* Visit all nodes and leaves of a btree. Check that all pointers and
97+
* records are in order, that the keys reflect the records, and use a callback
98+
* so that the caller can verify individual records. The callback is the same
99+
* as the one for xfs_btree_query_range, so therefore this function also
100+
* returns XFS_BTREE_QUERY_RANGE_ABORT, zero, or a negative error code.
101+
*/
102+
int
103+
xfs_scrub_btree(
104+
struct xfs_scrub_context *sc,
105+
struct xfs_btree_cur *cur,
106+
xfs_scrub_btree_rec_fn scrub_fn,
107+
struct xfs_owner_info *oinfo,
108+
void *private)
109+
{
110+
int error = -EOPNOTSUPP;
111+
112+
xfs_scrub_btree_process_error(sc, cur, 0, &error);
113+
return error;
114+
}

fs/xfs/scrub/btree.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (C) 2017 Oracle. All Rights Reserved.
3+
*
4+
* Author: Darrick J. Wong <darrick.wong@oracle.com>
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* as published by the Free Software Foundation; either version 2
9+
* of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it would be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
#ifndef __XFS_SCRUB_BTREE_H__
21+
#define __XFS_SCRUB_BTREE_H__
22+
23+
/* btree scrub */
24+
25+
/* Check for btree operation errors. */
26+
bool xfs_scrub_btree_process_error(struct xfs_scrub_context *sc,
27+
struct xfs_btree_cur *cur, int level, int *error);
28+
29+
/* Check for btree corruption. */
30+
void xfs_scrub_btree_set_corrupt(struct xfs_scrub_context *sc,
31+
struct xfs_btree_cur *cur, int level);
32+
33+
struct xfs_scrub_btree;
34+
typedef int (*xfs_scrub_btree_rec_fn)(
35+
struct xfs_scrub_btree *bs,
36+
union xfs_btree_rec *rec);
37+
38+
struct xfs_scrub_btree {
39+
/* caller-provided scrub state */
40+
struct xfs_scrub_context *sc;
41+
struct xfs_btree_cur *cur;
42+
xfs_scrub_btree_rec_fn scrub_rec;
43+
struct xfs_owner_info *oinfo;
44+
void *private;
45+
46+
/* internal scrub state */
47+
union xfs_btree_rec lastrec;
48+
bool firstrec;
49+
union xfs_btree_key lastkey[XFS_BTREE_MAXLEVELS];
50+
bool firstkey[XFS_BTREE_MAXLEVELS];
51+
struct list_head to_check;
52+
};
53+
int xfs_scrub_btree(struct xfs_scrub_context *sc, struct xfs_btree_cur *cur,
54+
xfs_scrub_btree_rec_fn scrub_fn,
55+
struct xfs_owner_info *oinfo, void *private);
56+
57+
#endif /* __XFS_SCRUB_BTREE_H__ */

fs/xfs/scrub/trace.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,27 @@
3030
#include "xfs_inode.h"
3131
#include "xfs_btree.h"
3232
#include "xfs_trans.h"
33+
#include "xfs_bit.h"
3334
#include "scrub/xfs_scrub.h"
3435
#include "scrub/scrub.h"
3536
#include "scrub/common.h"
3637

38+
/* Figure out which block the btree cursor was pointing to. */
39+
static inline xfs_fsblock_t
40+
xfs_scrub_btree_cur_fsbno(
41+
struct xfs_btree_cur *cur,
42+
int level)
43+
{
44+
if (level < cur->bc_nlevels && cur->bc_bufs[level])
45+
return XFS_DADDR_TO_FSB(cur->bc_mp, cur->bc_bufs[level]->b_bn);
46+
else if (level == cur->bc_nlevels - 1 &&
47+
cur->bc_flags & XFS_BTREE_LONG_PTRS)
48+
return XFS_INO_TO_FSB(cur->bc_mp, cur->bc_private.b.ip->i_ino);
49+
else if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS))
50+
return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno, 0);
51+
return NULLFSBLOCK;
52+
}
53+
3754
/*
3855
* We include this last to have the helpers above available for the trace
3956
* event implementations.

fs/xfs/scrub/trace.h

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,169 @@ TRACE_EVENT(xfs_scrub_incomplete,
283283
__entry->ret_ip)
284284
);
285285

286+
TRACE_EVENT(xfs_scrub_btree_op_error,
287+
TP_PROTO(struct xfs_scrub_context *sc, struct xfs_btree_cur *cur,
288+
int level, int error, void *ret_ip),
289+
TP_ARGS(sc, cur, level, error, ret_ip),
290+
TP_STRUCT__entry(
291+
__field(dev_t, dev)
292+
__field(unsigned int, type)
293+
__field(xfs_btnum_t, btnum)
294+
__field(int, level)
295+
__field(xfs_agnumber_t, agno)
296+
__field(xfs_agblock_t, bno)
297+
__field(int, ptr);
298+
__field(int, error)
299+
__field(void *, ret_ip)
300+
),
301+
TP_fast_assign(
302+
xfs_fsblock_t fsbno = xfs_scrub_btree_cur_fsbno(cur, level);
303+
304+
__entry->dev = sc->mp->m_super->s_dev;
305+
__entry->type = sc->sm->sm_type;
306+
__entry->btnum = cur->bc_btnum;
307+
__entry->level = level;
308+
__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno);
309+
__entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno);
310+
__entry->ptr = cur->bc_ptrs[level];
311+
__entry->error = error;
312+
__entry->ret_ip = ret_ip;
313+
),
314+
TP_printk("dev %d:%d type %u btnum %d level %d ptr %d agno %u agbno %u error %d ret_ip %pF",
315+
MAJOR(__entry->dev), MINOR(__entry->dev),
316+
__entry->type,
317+
__entry->btnum,
318+
__entry->level,
319+
__entry->ptr,
320+
__entry->agno,
321+
__entry->bno,
322+
__entry->error,
323+
__entry->ret_ip)
324+
);
325+
326+
TRACE_EVENT(xfs_scrub_ifork_btree_op_error,
327+
TP_PROTO(struct xfs_scrub_context *sc, struct xfs_btree_cur *cur,
328+
int level, int error, void *ret_ip),
329+
TP_ARGS(sc, cur, level, error, ret_ip),
330+
TP_STRUCT__entry(
331+
__field(dev_t, dev)
332+
__field(xfs_ino_t, ino)
333+
__field(int, whichfork)
334+
__field(unsigned int, type)
335+
__field(xfs_btnum_t, btnum)
336+
__field(int, level)
337+
__field(int, ptr)
338+
__field(xfs_agnumber_t, agno)
339+
__field(xfs_agblock_t, bno)
340+
__field(int, error)
341+
__field(void *, ret_ip)
342+
),
343+
TP_fast_assign(
344+
xfs_fsblock_t fsbno = xfs_scrub_btree_cur_fsbno(cur, level);
345+
__entry->dev = sc->mp->m_super->s_dev;
346+
__entry->ino = sc->ip->i_ino;
347+
__entry->whichfork = cur->bc_private.b.whichfork;
348+
__entry->type = sc->sm->sm_type;
349+
__entry->btnum = cur->bc_btnum;
350+
__entry->level = level;
351+
__entry->ptr = cur->bc_ptrs[level];
352+
__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno);
353+
__entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno);
354+
__entry->error = error;
355+
__entry->ret_ip = ret_ip;
356+
),
357+
TP_printk("dev %d:%d ino %llu fork %d type %u btnum %d level %d ptr %d agno %u agbno %u error %d ret_ip %pF",
358+
MAJOR(__entry->dev), MINOR(__entry->dev),
359+
__entry->ino,
360+
__entry->whichfork,
361+
__entry->type,
362+
__entry->btnum,
363+
__entry->level,
364+
__entry->ptr,
365+
__entry->agno,
366+
__entry->bno,
367+
__entry->error,
368+
__entry->ret_ip)
369+
);
370+
371+
TRACE_EVENT(xfs_scrub_btree_error,
372+
TP_PROTO(struct xfs_scrub_context *sc, struct xfs_btree_cur *cur,
373+
int level, void *ret_ip),
374+
TP_ARGS(sc, cur, level, ret_ip),
375+
TP_STRUCT__entry(
376+
__field(dev_t, dev)
377+
__field(unsigned int, type)
378+
__field(xfs_btnum_t, btnum)
379+
__field(int, level)
380+
__field(xfs_agnumber_t, agno)
381+
__field(xfs_agblock_t, bno)
382+
__field(int, ptr);
383+
__field(void *, ret_ip)
384+
),
385+
TP_fast_assign(
386+
xfs_fsblock_t fsbno = xfs_scrub_btree_cur_fsbno(cur, level);
387+
__entry->dev = sc->mp->m_super->s_dev;
388+
__entry->type = sc->sm->sm_type;
389+
__entry->btnum = cur->bc_btnum;
390+
__entry->level = level;
391+
__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno);
392+
__entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno);
393+
__entry->ptr = cur->bc_ptrs[level];
394+
__entry->ret_ip = ret_ip;
395+
),
396+
TP_printk("dev %d:%d type %u btnum %d level %d ptr %d agno %u agbno %u ret_ip %pF",
397+
MAJOR(__entry->dev), MINOR(__entry->dev),
398+
__entry->type,
399+
__entry->btnum,
400+
__entry->level,
401+
__entry->ptr,
402+
__entry->agno,
403+
__entry->bno,
404+
__entry->ret_ip)
405+
);
406+
407+
TRACE_EVENT(xfs_scrub_ifork_btree_error,
408+
TP_PROTO(struct xfs_scrub_context *sc, struct xfs_btree_cur *cur,
409+
int level, void *ret_ip),
410+
TP_ARGS(sc, cur, level, ret_ip),
411+
TP_STRUCT__entry(
412+
__field(dev_t, dev)
413+
__field(xfs_ino_t, ino)
414+
__field(int, whichfork)
415+
__field(unsigned int, type)
416+
__field(xfs_btnum_t, btnum)
417+
__field(int, level)
418+
__field(xfs_agnumber_t, agno)
419+
__field(xfs_agblock_t, bno)
420+
__field(int, ptr);
421+
__field(void *, ret_ip)
422+
),
423+
TP_fast_assign(
424+
xfs_fsblock_t fsbno = xfs_scrub_btree_cur_fsbno(cur, level);
425+
__entry->dev = sc->mp->m_super->s_dev;
426+
__entry->ino = sc->ip->i_ino;
427+
__entry->whichfork = cur->bc_private.b.whichfork;
428+
__entry->type = sc->sm->sm_type;
429+
__entry->btnum = cur->bc_btnum;
430+
__entry->level = level;
431+
__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno);
432+
__entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno);
433+
__entry->ptr = cur->bc_ptrs[level];
434+
__entry->ret_ip = ret_ip;
435+
),
436+
TP_printk("dev %d:%d ino %llu fork %d type %u btnum %d level %d ptr %d agno %u agbno %u ret_ip %pF",
437+
MAJOR(__entry->dev), MINOR(__entry->dev),
438+
__entry->ino,
439+
__entry->whichfork,
440+
__entry->type,
441+
__entry->btnum,
442+
__entry->level,
443+
__entry->ptr,
444+
__entry->agno,
445+
__entry->bno,
446+
__entry->ret_ip)
447+
);
448+
286449
#endif /* _TRACE_XFS_SCRUB_TRACE_H */
287450

288451
#undef TRACE_INCLUDE_PATH

0 commit comments

Comments
 (0)