blob: b91c64046c0d2857d4c22c74b93663e1dfd44988 [file] [log] [blame]
Dave Chinner0b61f8a2018-06-05 19:42:14 -07001// SPDX-License-Identifier: GPL-2.0+
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -07002/*
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -07004 * Author: Darrick J. Wong <darrick.wong@oracle.com>
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -07005 */
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_trans_resv.h"
11#include "xfs_mount.h"
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070012#include "xfs_log_format.h"
13#include "xfs_trans.h"
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070014#include "xfs_inode.h"
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070015#include "xfs_dir2.h"
16#include "xfs_dir2_priv.h"
17#include "xfs_attr_leaf.h"
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070018#include "scrub/scrub.h"
19#include "scrub/common.h"
20#include "scrub/trace.h"
21#include "scrub/dabtree.h"
22
23/* Directory/Attribute Btree */
24
25/*
26 * Check for da btree operation errors. See the section about handling
27 * operational errors in common.c.
28 */
29bool
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070030xchk_da_process_error(
Darrick J. Wong032d91f2018-07-19 12:29:12 -070031 struct xchk_da_btree *ds,
32 int level,
33 int *error)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070034{
Darrick J. Wong1d8a7482018-07-19 12:29:12 -070035 struct xfs_scrub *sc = ds->sc;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070036
37 if (*error == 0)
38 return true;
39
40 switch (*error) {
41 case -EDEADLOCK:
42 /* Used to restart an op with deadlock avoidance. */
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070043 trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070044 break;
45 case -EFSBADCRC:
46 case -EFSCORRUPTED:
47 /* Note the badness but don't abort. */
48 sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
49 *error = 0;
50 /* fall through */
51 default:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070052 trace_xchk_file_op_error(sc, ds->dargs.whichfork,
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070053 xfs_dir2_da_to_db(ds->dargs.geo,
54 ds->state->path.blk[level].blkno),
55 *error, __return_address);
56 break;
57 }
58 return false;
59}
60
61/*
62 * Check for da btree corruption. See the section about handling
63 * operational errors in common.c.
64 */
65void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070066xchk_da_set_corrupt(
Darrick J. Wong032d91f2018-07-19 12:29:12 -070067 struct xchk_da_btree *ds,
68 int level)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070069{
Darrick J. Wong1d8a7482018-07-19 12:29:12 -070070 struct xfs_scrub *sc = ds->sc;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070071
72 sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
73
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070074 trace_xchk_fblock_error(sc, ds->dargs.whichfork,
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070075 xfs_dir2_da_to_db(ds->dargs.geo,
76 ds->state->path.blk[level].blkno),
77 __return_address);
78}
79
Christoph Hellwig649d9d92019-11-08 14:52:07 -080080static struct xfs_da_node_entry *
81xchk_da_btree_node_entry(
82 struct xchk_da_btree *ds,
83 int level)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070084{
Christoph Hellwig649d9d92019-11-08 14:52:07 -080085 struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070086
Christoph Hellwig649d9d92019-11-08 14:52:07 -080087 ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070088
Christoph Hellwig649d9d92019-11-08 14:52:07 -080089 return (void *)ds->dargs.dp->d_ops->node_tree_p(blk->bp->b_addr) +
90 (blk->index * sizeof(struct xfs_da_node_entry));
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070091}
92
93/* Scrub a da btree hash (key). */
94int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070095xchk_da_btree_hash(
96 struct xchk_da_btree *ds,
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -070097 int level,
98 __be32 *hashp)
99{
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700100 struct xfs_da_node_entry *entry;
101 xfs_dahash_t hash;
102 xfs_dahash_t parent_hash;
103
104 /* Is this hash in order? */
105 hash = be32_to_cpu(*hashp);
106 if (hash < ds->hashes[level])
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700107 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700108 ds->hashes[level] = hash;
109
110 if (level == 0)
111 return 0;
112
113 /* Is this hash no larger than the parent hash? */
Christoph Hellwig649d9d92019-11-08 14:52:07 -0800114 entry = xchk_da_btree_node_entry(ds, level - 1);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700115 parent_hash = be32_to_cpu(entry->hashval);
116 if (parent_hash < hash)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700117 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700118
119 return 0;
120}
121
122/*
123 * Check a da btree pointer. Returns true if it's ok to use this
124 * pointer.
125 */
126STATIC bool
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700127xchk_da_btree_ptr_ok(
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700128 struct xchk_da_btree *ds,
129 int level,
130 xfs_dablk_t blkno)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700131{
132 if (blkno < ds->lowest || (ds->highest != 0 && blkno >= ds->highest)) {
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700133 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700134 return false;
135 }
136
137 return true;
138}
139
140/*
141 * The da btree scrubber can handle leaf1 blocks as a degenerate
142 * form of leafn blocks. Since the regular da code doesn't handle
143 * leaf1, we must multiplex the verifiers.
144 */
145static void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700146xchk_da_btree_read_verify(
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700147 struct xfs_buf *bp)
148{
149 struct xfs_da_blkinfo *info = bp->b_addr;
150
151 switch (be16_to_cpu(info->magic)) {
152 case XFS_DIR2_LEAF1_MAGIC:
153 case XFS_DIR3_LEAF1_MAGIC:
154 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
155 bp->b_ops->verify_read(bp);
156 return;
157 default:
158 /*
159 * xfs_da3_node_buf_ops already know how to handle
160 * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
161 */
162 bp->b_ops = &xfs_da3_node_buf_ops;
163 bp->b_ops->verify_read(bp);
164 return;
165 }
166}
167static void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700168xchk_da_btree_write_verify(
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700169 struct xfs_buf *bp)
170{
171 struct xfs_da_blkinfo *info = bp->b_addr;
172
173 switch (be16_to_cpu(info->magic)) {
174 case XFS_DIR2_LEAF1_MAGIC:
175 case XFS_DIR3_LEAF1_MAGIC:
176 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
177 bp->b_ops->verify_write(bp);
178 return;
179 default:
180 /*
181 * xfs_da3_node_buf_ops already know how to handle
182 * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
183 */
184 bp->b_ops = &xfs_da3_node_buf_ops;
185 bp->b_ops->verify_write(bp);
186 return;
187 }
188}
Darrick J. Wongcf1b0b82018-01-16 18:53:11 -0800189static void *
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700190xchk_da_btree_verify(
Darrick J. Wongcf1b0b82018-01-16 18:53:11 -0800191 struct xfs_buf *bp)
192{
193 struct xfs_da_blkinfo *info = bp->b_addr;
194
195 switch (be16_to_cpu(info->magic)) {
196 case XFS_DIR2_LEAF1_MAGIC:
197 case XFS_DIR3_LEAF1_MAGIC:
198 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
199 return bp->b_ops->verify_struct(bp);
200 default:
201 bp->b_ops = &xfs_da3_node_buf_ops;
202 return bp->b_ops->verify_struct(bp);
203 }
204}
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700205
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700206static const struct xfs_buf_ops xchk_da_btree_buf_ops = {
207 .name = "xchk_da_btree",
208 .verify_read = xchk_da_btree_read_verify,
209 .verify_write = xchk_da_btree_write_verify,
210 .verify_struct = xchk_da_btree_verify,
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700211};
212
213/* Check a block's sibling. */
214STATIC int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700215xchk_da_btree_block_check_sibling(
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700216 struct xchk_da_btree *ds,
217 int level,
218 int direction,
219 xfs_dablk_t sibling)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700220{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700221 int retval;
222 int error;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700223
224 memcpy(&ds->state->altpath, &ds->state->path,
225 sizeof(ds->state->altpath));
226
227 /*
228 * If the pointer is null, we shouldn't be able to move the upper
229 * level pointer anywhere.
230 */
231 if (sibling == 0) {
232 error = xfs_da3_path_shift(ds->state, &ds->state->altpath,
233 direction, false, &retval);
234 if (error == 0 && retval == 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700235 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700236 error = 0;
237 goto out;
238 }
239
240 /* Move the alternate cursor one block in the direction given. */
241 error = xfs_da3_path_shift(ds->state, &ds->state->altpath,
242 direction, false, &retval);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700243 if (!xchk_da_process_error(ds, level, &error))
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700244 return error;
245 if (retval) {
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700246 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700247 return error;
248 }
Darrick J. Wongcf1b0b82018-01-16 18:53:11 -0800249 if (ds->state->altpath.blk[level].bp)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700250 xchk_buffer_recheck(ds->sc,
Darrick J. Wongcf1b0b82018-01-16 18:53:11 -0800251 ds->state->altpath.blk[level].bp);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700252
253 /* Compare upper level pointer to sibling pointer. */
254 if (ds->state->altpath.blk[level].blkno != sibling)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700255 xchk_da_set_corrupt(ds, level);
Jia-Ju Baiafa1d962019-07-30 11:28:20 -0700256 if (ds->state->altpath.blk[level].bp) {
257 xfs_trans_brelse(ds->dargs.trans,
258 ds->state->altpath.blk[level].bp);
259 ds->state->altpath.blk[level].bp = NULL;
260 }
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700261out:
262 return error;
263}
264
265/* Check a block's sibling pointers. */
266STATIC int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700267xchk_da_btree_block_check_siblings(
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700268 struct xchk_da_btree *ds,
269 int level,
270 struct xfs_da_blkinfo *hdr)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700271{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700272 xfs_dablk_t forw;
273 xfs_dablk_t back;
274 int error = 0;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700275
276 forw = be32_to_cpu(hdr->forw);
277 back = be32_to_cpu(hdr->back);
278
279 /* Top level blocks should not have sibling pointers. */
280 if (level == 0) {
281 if (forw != 0 || back != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700282 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700283 return 0;
284 }
285
286 /*
287 * Check back (left) and forw (right) pointers. These functions
288 * absorb error codes for us.
289 */
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700290 error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700291 if (error)
292 goto out;
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700293 error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700294
295out:
296 memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
297 return error;
298}
299
300/* Load a dir/attribute block from a btree. */
301STATIC int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700302xchk_da_btree_block(
303 struct xchk_da_btree *ds,
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700304 int level,
305 xfs_dablk_t blkno)
306{
307 struct xfs_da_state_blk *blk;
308 struct xfs_da_intnode *node;
309 struct xfs_da_node_entry *btree;
310 struct xfs_da3_blkinfo *hdr3;
311 struct xfs_da_args *dargs = &ds->dargs;
312 struct xfs_inode *ip = ds->dargs.dp;
313 xfs_ino_t owner;
314 int *pmaxrecs;
315 struct xfs_da3_icnode_hdr nodehdr;
Darrick J. Wong0dca0602017-11-02 12:48:11 -0700316 int error = 0;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700317
318 blk = &ds->state->path.blk[level];
319 ds->state->path.active = level + 1;
320
321 /* Release old block. */
322 if (blk->bp) {
323 xfs_trans_brelse(dargs->trans, blk->bp);
324 blk->bp = NULL;
325 }
326
327 /* Check the pointer. */
328 blk->blkno = blkno;
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700329 if (!xchk_da_btree_ptr_ok(ds, level, blkno))
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700330 goto out_nobuf;
331
332 /* Read the buffer. */
333 error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
334 &blk->bp, dargs->whichfork,
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700335 &xchk_da_btree_buf_ops);
336 if (!xchk_da_process_error(ds, level, &error))
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700337 goto out_nobuf;
Darrick J. Wongcf1b0b82018-01-16 18:53:11 -0800338 if (blk->bp)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700339 xchk_buffer_recheck(ds->sc, blk->bp);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700340
341 /*
342 * We didn't find a dir btree root block, which means that
343 * there's no LEAF1/LEAFN tree (at least not where it's supposed
344 * to be), so jump out now.
345 */
346 if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
347 blk->bp == NULL)
348 goto out_nobuf;
349
350 /* It's /not/ ok for attr trees not to have a da btree. */
351 if (blk->bp == NULL) {
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700352 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700353 goto out_nobuf;
354 }
355
356 hdr3 = blk->bp->b_addr;
357 blk->magic = be16_to_cpu(hdr3->hdr.magic);
358 pmaxrecs = &ds->maxrecs[level];
359
Darrick J. Wong4da4b102017-11-08 12:21:05 -0800360 /* We only started zeroing the header on v5 filesystems. */
361 if (xfs_sb_version_hascrc(&ds->sc->mp->m_sb) && hdr3->hdr.pad)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700362 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700363
364 /* Check the owner. */
365 if (xfs_sb_version_hascrc(&ip->i_mount->m_sb)) {
366 owner = be64_to_cpu(hdr3->owner);
367 if (owner != ip->i_ino)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700368 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700369 }
370
371 /* Check the siblings. */
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700372 error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700373 if (error)
374 goto out;
375
376 /* Interpret the buffer. */
377 switch (blk->magic) {
378 case XFS_ATTR_LEAF_MAGIC:
379 case XFS_ATTR3_LEAF_MAGIC:
380 xfs_trans_buf_set_type(dargs->trans, blk->bp,
381 XFS_BLFT_ATTR_LEAF_BUF);
382 blk->magic = XFS_ATTR_LEAF_MAGIC;
383 blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
384 if (ds->tree_level != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700385 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700386 break;
387 case XFS_DIR2_LEAFN_MAGIC:
388 case XFS_DIR3_LEAFN_MAGIC:
389 xfs_trans_buf_set_type(dargs->trans, blk->bp,
390 XFS_BLFT_DIR_LEAFN_BUF);
391 blk->magic = XFS_DIR2_LEAFN_MAGIC;
392 blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
393 if (ds->tree_level != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700394 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700395 break;
396 case XFS_DIR2_LEAF1_MAGIC:
397 case XFS_DIR3_LEAF1_MAGIC:
398 xfs_trans_buf_set_type(dargs->trans, blk->bp,
399 XFS_BLFT_DIR_LEAF1_BUF);
400 blk->magic = XFS_DIR2_LEAF1_MAGIC;
401 blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
402 if (ds->tree_level != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700403 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700404 break;
405 case XFS_DA_NODE_MAGIC:
406 case XFS_DA3_NODE_MAGIC:
407 xfs_trans_buf_set_type(dargs->trans, blk->bp,
408 XFS_BLFT_DA_NODE_BUF);
409 blk->magic = XFS_DA_NODE_MAGIC;
410 node = blk->bp->b_addr;
Christoph Hellwigf475dc4d2019-11-08 14:53:00 -0800411 xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700412 btree = ip->d_ops->node_tree_p(node);
413 *pmaxrecs = nodehdr.count;
414 blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
415 if (level == 0) {
416 if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700417 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700418 goto out_freebp;
419 }
420 ds->tree_level = nodehdr.level;
421 } else {
422 if (ds->tree_level != nodehdr.level) {
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700423 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700424 goto out_freebp;
425 }
426 }
427
428 /* XXX: Check hdr3.pad32 once we know how to fix it. */
429 break;
430 default:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700431 xchk_da_set_corrupt(ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700432 goto out_freebp;
433 }
434
435out:
436 return error;
437out_freebp:
438 xfs_trans_brelse(dargs->trans, blk->bp);
439 blk->bp = NULL;
440out_nobuf:
441 blk->blkno = 0;
442 return error;
443}
444
445/* Visit all nodes and leaves of a da btree. */
446int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700447xchk_da_btree(
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700448 struct xfs_scrub *sc,
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700449 int whichfork,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700450 xchk_da_btree_rec_fn scrub_fn,
Darrick J. Wong13791d32017-10-31 12:10:02 -0700451 void *private)
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700452{
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700453 struct xchk_da_btree ds = {};
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700454 struct xfs_mount *mp = sc->mp;
455 struct xfs_da_state_blk *blks;
456 struct xfs_da_node_entry *key;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700457 xfs_dablk_t blkno;
458 int level;
459 int error;
460
461 /* Skip short format data structures; no btree to scan. */
Darrick J. Wong2fe4f922019-11-07 15:05:21 -0800462 if (!xfs_ifork_has_extents(sc->ip, whichfork))
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700463 return 0;
464
465 /* Set up initial da state. */
466 ds.dargs.dp = sc->ip;
467 ds.dargs.whichfork = whichfork;
468 ds.dargs.trans = sc->tp;
469 ds.dargs.op_flags = XFS_DA_OP_OKNOENT;
470 ds.state = xfs_da_state_alloc();
471 ds.state->args = &ds.dargs;
472 ds.state->mp = mp;
473 ds.sc = sc;
Darrick J. Wong13791d32017-10-31 12:10:02 -0700474 ds.private = private;
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700475 if (whichfork == XFS_ATTR_FORK) {
476 ds.dargs.geo = mp->m_attr_geo;
477 ds.lowest = 0;
478 ds.highest = 0;
479 } else {
480 ds.dargs.geo = mp->m_dir_geo;
481 ds.lowest = ds.dargs.geo->leafblk;
482 ds.highest = ds.dargs.geo->freeblk;
483 }
484 blkno = ds.lowest;
485 level = 0;
486
487 /* Find the root of the da tree, if present. */
488 blks = ds.state->path.blk;
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700489 error = xchk_da_btree_block(&ds, level, blkno);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700490 if (error)
491 goto out_state;
492 /*
493 * We didn't find a block at ds.lowest, which means that there's
494 * no LEAF1/LEAFN tree (at least not where it's supposed to be),
495 * so jump out now.
496 */
497 if (blks[level].bp == NULL)
498 goto out_state;
499
500 blks[level].index = 0;
501 while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
502 /* Handle leaf block. */
503 if (blks[level].magic != XFS_DA_NODE_MAGIC) {
504 /* End of leaf, pop back towards the root. */
505 if (blks[level].index >= ds.maxrecs[level]) {
506 if (level > 0)
507 blks[level - 1].index++;
508 ds.tree_level++;
509 level--;
510 continue;
511 }
512
513 /* Dispatch record scrubbing. */
Christoph Hellwig649d9d92019-11-08 14:52:07 -0800514 error = scrub_fn(&ds, level);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700515 if (error)
516 break;
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700517 if (xchk_should_terminate(sc, &error) ||
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700518 (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
519 break;
520
521 blks[level].index++;
522 continue;
523 }
524
525
526 /* End of node, pop back towards the root. */
527 if (blks[level].index >= ds.maxrecs[level]) {
528 if (level > 0)
529 blks[level - 1].index++;
530 ds.tree_level++;
531 level--;
532 continue;
533 }
534
535 /* Hashes in order for scrub? */
Christoph Hellwig649d9d92019-11-08 14:52:07 -0800536 key = xchk_da_btree_node_entry(&ds, level);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700537 error = xchk_da_btree_hash(&ds, level, &key->hashval);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700538 if (error)
539 goto out;
540
541 /* Drill another level deeper. */
542 blkno = be32_to_cpu(key->before);
543 level++;
Darrick J. Wong228de122019-03-19 08:16:21 -0700544 if (level >= XFS_DA_NODE_MAXDEPTH) {
545 /* Too deep! */
546 xchk_da_set_corrupt(&ds, level - 1);
547 break;
548 }
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700549 ds.tree_level--;
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700550 error = xchk_da_btree_block(&ds, level, blkno);
Darrick J. Wong7c4a07a2017-10-17 21:37:43 -0700551 if (error)
552 goto out;
553 if (blks[level].bp == NULL)
554 goto out;
555
556 blks[level].index = 0;
557 }
558
559out:
560 /* Release all the buffers we're tracking. */
561 for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
562 if (blks[level].bp == NULL)
563 continue;
564 xfs_trans_brelse(sc->tp, blks[level].bp);
565 blks[level].bp = NULL;
566 }
567
568out_state:
569 xfs_da_state_free(ds.state);
570 return error;
571}