Skip to content

Commit 4700d22

Browse files
committed
xfs: create helpers to record and deal with scrub problems
Create helper functions to record crc and corruption problems, and deal with any other runtime errors that arise. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent dcb660f commit 4700d22

File tree

3 files changed

+428
-0
lines changed

3 files changed

+428
-0
lines changed

fs/xfs/scrub/common.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,196 @@
4747

4848
/* Common code for the metadata scrubbers. */
4949

50+
/*
51+
* Handling operational errors.
52+
*
53+
* The *_process_error() family of functions are used to process error return
54+
* codes from functions called as part of a scrub operation.
55+
*
56+
* If there's no error, we return true to tell the caller that it's ok
57+
* to move on to the next check in its list.
58+
*
59+
* For non-verifier errors (e.g. ENOMEM) we return false to tell the
60+
* caller that something bad happened, and we preserve *error so that
61+
* the caller can return the *error up the stack to userspace.
62+
*
63+
* Verifier errors (EFSBADCRC/EFSCORRUPTED) are recorded by setting
64+
* OFLAG_CORRUPT in sm_flags and the *error is cleared. In other words,
65+
* we track verifier errors (and failed scrub checks) via OFLAG_CORRUPT,
66+
* not via return codes. We return false to tell the caller that
67+
* something bad happened. Since the error has been cleared, the caller
68+
* will (presumably) return that zero and scrubbing will move on to
69+
* whatever's next.
70+
*
71+
* ftrace can be used to record the precise metadata location and the
72+
* approximate code location of the failed operation.
73+
*/
74+
75+
/* Check for operational errors. */
76+
bool
77+
xfs_scrub_process_error(
78+
struct xfs_scrub_context *sc,
79+
xfs_agnumber_t agno,
80+
xfs_agblock_t bno,
81+
int *error)
82+
{
83+
switch (*error) {
84+
case 0:
85+
return true;
86+
case -EDEADLOCK:
87+
/* Used to restart an op with deadlock avoidance. */
88+
trace_xfs_scrub_deadlock_retry(sc->ip, sc->sm, *error);
89+
break;
90+
case -EFSBADCRC:
91+
case -EFSCORRUPTED:
92+
/* Note the badness but don't abort. */
93+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
94+
*error = 0;
95+
/* fall through */
96+
default:
97+
trace_xfs_scrub_op_error(sc, agno, bno, *error,
98+
__return_address);
99+
break;
100+
}
101+
return false;
102+
}
103+
104+
/* Check for operational errors for a file offset. */
105+
bool
106+
xfs_scrub_fblock_process_error(
107+
struct xfs_scrub_context *sc,
108+
int whichfork,
109+
xfs_fileoff_t offset,
110+
int *error)
111+
{
112+
switch (*error) {
113+
case 0:
114+
return true;
115+
case -EDEADLOCK:
116+
/* Used to restart an op with deadlock avoidance. */
117+
trace_xfs_scrub_deadlock_retry(sc->ip, sc->sm, *error);
118+
break;
119+
case -EFSBADCRC:
120+
case -EFSCORRUPTED:
121+
/* Note the badness but don't abort. */
122+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
123+
*error = 0;
124+
/* fall through */
125+
default:
126+
trace_xfs_scrub_file_op_error(sc, whichfork, offset, *error,
127+
__return_address);
128+
break;
129+
}
130+
return false;
131+
}
132+
133+
/*
134+
* Handling scrub corruption/optimization/warning checks.
135+
*
136+
* The *_set_{corrupt,preen,warning}() family of functions are used to
137+
* record the presence of metadata that is incorrect (corrupt), could be
138+
* optimized somehow (preen), or should be flagged for administrative
139+
* review but is not incorrect (warn).
140+
*
141+
* ftrace can be used to record the precise metadata location and
142+
* approximate code location of the failed check.
143+
*/
144+
145+
/* Record a block which could be optimized. */
146+
void
147+
xfs_scrub_block_set_preen(
148+
struct xfs_scrub_context *sc,
149+
struct xfs_buf *bp)
150+
{
151+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
152+
trace_xfs_scrub_block_preen(sc, bp->b_bn, __return_address);
153+
}
154+
155+
/*
156+
* Record an inode which could be optimized. The trace data will
157+
* include the block given by bp if bp is given; otherwise it will use
158+
* the block location of the inode record itself.
159+
*/
160+
void
161+
xfs_scrub_ino_set_preen(
162+
struct xfs_scrub_context *sc,
163+
struct xfs_buf *bp)
164+
{
165+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
166+
trace_xfs_scrub_ino_preen(sc, sc->ip->i_ino, bp ? bp->b_bn : 0,
167+
__return_address);
168+
}
169+
170+
/* Record a corrupt block. */
171+
void
172+
xfs_scrub_block_set_corrupt(
173+
struct xfs_scrub_context *sc,
174+
struct xfs_buf *bp)
175+
{
176+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
177+
trace_xfs_scrub_block_error(sc, bp->b_bn, __return_address);
178+
}
179+
180+
/*
181+
* Record a corrupt inode. The trace data will include the block given
182+
* by bp if bp is given; otherwise it will use the block location of the
183+
* inode record itself.
184+
*/
185+
void
186+
xfs_scrub_ino_set_corrupt(
187+
struct xfs_scrub_context *sc,
188+
xfs_ino_t ino,
189+
struct xfs_buf *bp)
190+
{
191+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
192+
trace_xfs_scrub_ino_error(sc, ino, bp ? bp->b_bn : 0, __return_address);
193+
}
194+
195+
/* Record corruption in a block indexed by a file fork. */
196+
void
197+
xfs_scrub_fblock_set_corrupt(
198+
struct xfs_scrub_context *sc,
199+
int whichfork,
200+
xfs_fileoff_t offset)
201+
{
202+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
203+
trace_xfs_scrub_fblock_error(sc, whichfork, offset, __return_address);
204+
}
205+
206+
/*
207+
* Warn about inodes that need administrative review but is not
208+
* incorrect.
209+
*/
210+
void
211+
xfs_scrub_ino_set_warning(
212+
struct xfs_scrub_context *sc,
213+
struct xfs_buf *bp)
214+
{
215+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_WARNING;
216+
trace_xfs_scrub_ino_warning(sc, sc->ip->i_ino, bp ? bp->b_bn : 0,
217+
__return_address);
218+
}
219+
220+
/* Warn about a block indexed by a file fork that needs review. */
221+
void
222+
xfs_scrub_fblock_set_warning(
223+
struct xfs_scrub_context *sc,
224+
int whichfork,
225+
xfs_fileoff_t offset)
226+
{
227+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_WARNING;
228+
trace_xfs_scrub_fblock_warning(sc, whichfork, offset, __return_address);
229+
}
230+
231+
/* Signal an incomplete scrub. */
232+
void
233+
xfs_scrub_set_incomplete(
234+
struct xfs_scrub_context *sc)
235+
{
236+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_INCOMPLETE;
237+
trace_xfs_scrub_incomplete(sc, __return_address);
238+
}
239+
50240
/* Per-scrubber setup functions */
51241

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

fs/xfs/scrub/common.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@ xfs_scrub_trans_alloc(
5151
return xfs_trans_alloc_empty(mp, tpp);
5252
}
5353

54+
bool xfs_scrub_process_error(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
55+
xfs_agblock_t bno, int *error);
56+
bool xfs_scrub_fblock_process_error(struct xfs_scrub_context *sc, int whichfork,
57+
xfs_fileoff_t offset, int *error);
58+
59+
void xfs_scrub_block_set_preen(struct xfs_scrub_context *sc,
60+
struct xfs_buf *bp);
61+
void xfs_scrub_ino_set_preen(struct xfs_scrub_context *sc, struct xfs_buf *bp);
62+
63+
void xfs_scrub_block_set_corrupt(struct xfs_scrub_context *sc,
64+
struct xfs_buf *bp);
65+
void xfs_scrub_ino_set_corrupt(struct xfs_scrub_context *sc, xfs_ino_t ino,
66+
struct xfs_buf *bp);
67+
void xfs_scrub_fblock_set_corrupt(struct xfs_scrub_context *sc, int whichfork,
68+
xfs_fileoff_t offset);
69+
70+
void xfs_scrub_ino_set_warning(struct xfs_scrub_context *sc,
71+
struct xfs_buf *bp);
72+
void xfs_scrub_fblock_set_warning(struct xfs_scrub_context *sc, int whichfork,
73+
xfs_fileoff_t offset);
74+
75+
void xfs_scrub_set_incomplete(struct xfs_scrub_context *sc);
76+
5477
/* Setup functions */
5578
int xfs_scrub_setup_fs(struct xfs_scrub_context *sc, struct xfs_inode *ip);
5679

0 commit comments

Comments
 (0)