hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/fs/xfs/scrub/dir.c
....@@ -9,24 +9,14 @@
99 #include "xfs_format.h"
1010 #include "xfs_trans_resv.h"
1111 #include "xfs_mount.h"
12
-#include "xfs_defer.h"
13
-#include "xfs_btree.h"
14
-#include "xfs_bit.h"
1512 #include "xfs_log_format.h"
1613 #include "xfs_trans.h"
17
-#include "xfs_sb.h"
1814 #include "xfs_inode.h"
1915 #include "xfs_icache.h"
20
-#include "xfs_itable.h"
21
-#include "xfs_da_format.h"
22
-#include "xfs_da_btree.h"
2316 #include "xfs_dir2.h"
2417 #include "xfs_dir2_priv.h"
25
-#include "xfs_ialloc.h"
26
-#include "scrub/xfs_scrub.h"
2718 #include "scrub/scrub.h"
2819 #include "scrub/common.h"
29
-#include "scrub/trace.h"
3020 #include "scrub/dabtree.h"
3121
3222 /* Set us up to scrub directories. */
....@@ -123,8 +113,17 @@
123113 offset = xfs_dir2_db_to_da(mp->m_dir_geo,
124114 xfs_dir2_dataptr_to_db(mp->m_dir_geo, pos));
125115
116
+ if (xchk_should_terminate(sdc->sc, &error))
117
+ return error;
118
+
126119 /* Does this inode number make sense? */
127120 if (!xfs_verify_dir_ino(mp, ino)) {
121
+ xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset);
122
+ goto out;
123
+ }
124
+
125
+ /* Does this name make sense? */
126
+ if (!xfs_dir2_namecheck(name, namelen)) {
128127 xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset);
129128 goto out;
130129 }
....@@ -186,15 +185,17 @@
186185 STATIC int
187186 xchk_dir_rec(
188187 struct xchk_da_btree *ds,
189
- int level,
190
- void *rec)
188
+ int level)
191189 {
190
+ struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
192191 struct xfs_mount *mp = ds->state->mp;
193
- struct xfs_dir2_leaf_entry *ent = rec;
194192 struct xfs_inode *dp = ds->dargs.dp;
193
+ struct xfs_da_geometry *geo = mp->m_dir_geo;
195194 struct xfs_dir2_data_entry *dent;
196195 struct xfs_buf *bp;
197
- char *p, *endp;
196
+ struct xfs_dir2_leaf_entry *ent;
197
+ unsigned int end;
198
+ unsigned int iter_off;
198199 xfs_ino_t ino;
199200 xfs_dablk_t rec_bno;
200201 xfs_dir2_db_t db;
....@@ -202,8 +203,15 @@
202203 xfs_dir2_dataptr_t ptr;
203204 xfs_dahash_t calc_hash;
204205 xfs_dahash_t hash;
206
+ struct xfs_dir3_icleaf_hdr hdr;
205207 unsigned int tag;
206208 int error;
209
+
210
+ ASSERT(blk->magic == XFS_DIR2_LEAF1_MAGIC ||
211
+ blk->magic == XFS_DIR2_LEAFN_MAGIC);
212
+
213
+ xfs_dir2_leaf_hdr_from_disk(mp, &hdr, blk->bp->b_addr);
214
+ ent = hdr.ents + blk->index;
207215
208216 /* Check the hash of the entry. */
209217 error = xchk_da_btree_hash(ds, level, &ent->hashval);
....@@ -216,15 +224,16 @@
216224 return 0;
217225
218226 /* Find the directory entry's location. */
219
- db = xfs_dir2_dataptr_to_db(mp->m_dir_geo, ptr);
220
- off = xfs_dir2_dataptr_to_off(mp->m_dir_geo, ptr);
221
- rec_bno = xfs_dir2_db_to_da(mp->m_dir_geo, db);
227
+ db = xfs_dir2_dataptr_to_db(geo, ptr);
228
+ off = xfs_dir2_dataptr_to_off(geo, ptr);
229
+ rec_bno = xfs_dir2_db_to_da(geo, db);
222230
223
- if (rec_bno >= mp->m_dir_geo->leafblk) {
231
+ if (rec_bno >= geo->leafblk) {
224232 xchk_da_set_corrupt(ds, level);
225233 goto out;
226234 }
227
- error = xfs_dir3_data_read(ds->dargs.trans, dp, rec_bno, -2, &bp);
235
+ error = xfs_dir3_data_read(ds->dargs.trans, dp, rec_bno,
236
+ XFS_DABUF_MAP_HOLE_OK, &bp);
228237 if (!xchk_fblock_process_error(ds->sc, XFS_DATA_FORK, rec_bno,
229238 &error))
230239 goto out;
....@@ -237,38 +246,37 @@
237246 if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
238247 goto out_relse;
239248
240
- dent = (struct xfs_dir2_data_entry *)(((char *)bp->b_addr) + off);
249
+ dent = bp->b_addr + off;
241250
242251 /* Make sure we got a real directory entry. */
243
- p = (char *)mp->m_dir_inode_ops->data_entry_p(bp->b_addr);
244
- endp = xfs_dir3_data_endp(mp->m_dir_geo, bp->b_addr);
245
- if (!endp) {
252
+ iter_off = geo->data_entry_offset;
253
+ end = xfs_dir3_data_end_offset(geo, bp->b_addr);
254
+ if (!end) {
246255 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
247256 goto out_relse;
248257 }
249
- while (p < endp) {
250
- struct xfs_dir2_data_entry *dep;
251
- struct xfs_dir2_data_unused *dup;
258
+ for (;;) {
259
+ struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off;
260
+ struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off;
252261
253
- dup = (struct xfs_dir2_data_unused *)p;
262
+ if (iter_off >= end) {
263
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
264
+ goto out_relse;
265
+ }
266
+
254267 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
255
- p += be16_to_cpu(dup->length);
268
+ iter_off += be16_to_cpu(dup->length);
256269 continue;
257270 }
258
- dep = (struct xfs_dir2_data_entry *)p;
259271 if (dep == dent)
260272 break;
261
- p += mp->m_dir_inode_ops->data_entsize(dep->namelen);
262
- }
263
- if (p >= endp) {
264
- xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
265
- goto out_relse;
273
+ iter_off += xfs_dir2_data_entsize(mp, dep->namelen);
266274 }
267275
268276 /* Retrieve the entry, sanity check it, and compare hashes. */
269277 ino = be64_to_cpu(dent->inumber);
270278 hash = be32_to_cpu(ent->hashval);
271
- tag = be16_to_cpup(dp->d_ops->data_entry_tag_p(dent));
279
+ tag = be16_to_cpup(xfs_dir2_data_entry_tag_p(mp, dent));
272280 if (!xfs_verify_dir_ino(mp, ino) || tag != off)
273281 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
274282 if (dent->namelen == 0) {
....@@ -326,18 +334,14 @@
326334 struct xfs_buf *bp;
327335 struct xfs_dir2_data_free *bf;
328336 struct xfs_mount *mp = sc->mp;
329
- const struct xfs_dir_ops *d_ops;
330
- char *ptr;
331
- char *endptr;
332337 u16 tag;
333338 unsigned int nr_bestfrees = 0;
334339 unsigned int nr_frees = 0;
335340 unsigned int smallest_bestfree;
336341 int newlen;
337
- int offset;
342
+ unsigned int offset;
343
+ unsigned int end;
338344 int error;
339
-
340
- d_ops = sc->ip->d_ops;
341345
342346 if (is_block) {
343347 /* dir block format */
....@@ -346,7 +350,7 @@
346350 error = xfs_dir3_block_read(sc->tp, sc->ip, &bp);
347351 } else {
348352 /* dir data format */
349
- error = xfs_dir3_data_read(sc->tp, sc->ip, lblk, -1, &bp);
353
+ error = xfs_dir3_data_read(sc->tp, sc->ip, lblk, 0, &bp);
350354 }
351355 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
352356 goto out;
....@@ -358,7 +362,7 @@
358362 goto out_buf;
359363
360364 /* Do the bestfrees correspond to actual free space? */
361
- bf = d_ops->data_bestfree_p(bp->b_addr);
365
+ bf = xfs_dir2_data_bestfree_p(mp, bp->b_addr);
362366 smallest_bestfree = UINT_MAX;
363367 for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
364368 offset = be16_to_cpu(dfp->offset);
....@@ -368,13 +372,13 @@
368372 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
369373 goto out_buf;
370374 }
371
- dup = (struct xfs_dir2_data_unused *)(bp->b_addr + offset);
375
+ dup = bp->b_addr + offset;
372376 tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
373377
374378 /* bestfree doesn't match the entry it points at? */
375379 if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG) ||
376380 be16_to_cpu(dup->length) != be16_to_cpu(dfp->length) ||
377
- tag != ((char *)dup - (char *)bp->b_addr)) {
381
+ tag != offset) {
378382 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
379383 goto out_buf;
380384 }
....@@ -390,30 +394,30 @@
390394 }
391395
392396 /* Make sure the bestfrees are actually the best free spaces. */
393
- ptr = (char *)d_ops->data_entry_p(bp->b_addr);
394
- endptr = xfs_dir3_data_endp(mp->m_dir_geo, bp->b_addr);
397
+ offset = mp->m_dir_geo->data_entry_offset;
398
+ end = xfs_dir3_data_end_offset(mp->m_dir_geo, bp->b_addr);
395399
396400 /* Iterate the entries, stopping when we hit or go past the end. */
397
- while (ptr < endptr) {
398
- dup = (struct xfs_dir2_data_unused *)ptr;
401
+ while (offset < end) {
402
+ dup = bp->b_addr + offset;
403
+
399404 /* Skip real entries */
400405 if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG)) {
401
- struct xfs_dir2_data_entry *dep;
406
+ struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
402407
403
- dep = (struct xfs_dir2_data_entry *)ptr;
404
- newlen = d_ops->data_entsize(dep->namelen);
408
+ newlen = xfs_dir2_data_entsize(mp, dep->namelen);
405409 if (newlen <= 0) {
406410 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
407411 lblk);
408412 goto out_buf;
409413 }
410
- ptr += newlen;
414
+ offset += newlen;
411415 continue;
412416 }
413417
414418 /* Spot check this free entry */
415419 tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
416
- if (tag != ((char *)dup - (char *)bp->b_addr)) {
420
+ if (tag != offset) {
417421 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
418422 goto out_buf;
419423 }
....@@ -432,13 +436,13 @@
432436 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
433437 goto out_buf;
434438 }
435
- ptr += newlen;
436
- if (ptr <= endptr)
439
+ offset += newlen;
440
+ if (offset <= end)
437441 nr_frees++;
438442 }
439443
440444 /* We're required to fill all the space. */
441
- if (ptr != endptr)
445
+ if (offset != end)
442446 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
443447
444448 /* Did we see at least as many free slots as there are bestfrees? */
....@@ -465,7 +469,7 @@
465469 {
466470 struct xfs_dir2_data_free *dfp;
467471
468
- dfp = sc->ip->d_ops->data_bestfree_p(dbp->b_addr);
472
+ dfp = xfs_dir2_data_bestfree_p(sc->mp, dbp->b_addr);
469473
470474 if (len != be16_to_cpu(dfp->length))
471475 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
....@@ -482,12 +486,10 @@
482486 xfs_dablk_t lblk)
483487 {
484488 struct xfs_dir3_icleaf_hdr leafhdr;
485
- struct xfs_dir2_leaf_entry *ents;
486489 struct xfs_dir2_leaf_tail *ltp;
487490 struct xfs_dir2_leaf *leaf;
488491 struct xfs_buf *dbp;
489492 struct xfs_buf *bp;
490
- const struct xfs_dir_ops *d_ops = sc->ip->d_ops;
491493 struct xfs_da_geometry *geo = sc->mp->m_dir_geo;
492494 __be16 *bestp;
493495 __u16 best;
....@@ -499,14 +501,13 @@
499501 int error;
500502
501503 /* Read the free space block. */
502
- error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
504
+ error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, &bp);
503505 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
504
- goto out;
506
+ return error;
505507 xchk_buffer_recheck(sc, bp);
506508
507509 leaf = bp->b_addr;
508
- d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
509
- ents = d_ops->leaf_ents_p(leaf);
510
+ xfs_dir2_leaf_hdr_from_disk(sc->ip->i_mount, &leafhdr, leaf);
510511 ltp = xfs_dir2_leaf_tail_p(geo, leaf);
511512 bestcount = be32_to_cpu(ltp->bestcount);
512513 bestp = xfs_dir2_leaf_bests_p(ltp);
....@@ -528,24 +529,25 @@
528529 }
529530
530531 /* Is the leaf count even remotely sane? */
531
- if (leafhdr.count > d_ops->leaf_max_ents(geo)) {
532
+ if (leafhdr.count > geo->leaf_max_ents) {
532533 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
533534 goto out;
534535 }
535536
536537 /* Leaves and bests don't overlap in leaf format. */
537
- if ((char *)&ents[leafhdr.count] > (char *)bestp) {
538
+ if ((char *)&leafhdr.ents[leafhdr.count] > (char *)bestp) {
538539 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
539540 goto out;
540541 }
541542
542543 /* Check hash value order, count stale entries. */
543544 for (i = 0; i < leafhdr.count; i++) {
544
- hash = be32_to_cpu(ents[i].hashval);
545
+ hash = be32_to_cpu(leafhdr.ents[i].hashval);
545546 if (i > 0 && lasthash > hash)
546547 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
547548 lasthash = hash;
548
- if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
549
+ if (leafhdr.ents[i].address ==
550
+ cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
549551 stale++;
550552 }
551553 if (leafhdr.stale != stale)
....@@ -556,19 +558,33 @@
556558 /* Check all the bestfree entries. */
557559 for (i = 0; i < bestcount; i++, bestp++) {
558560 best = be16_to_cpu(*bestp);
559
- if (best == NULLDATAOFF)
560
- continue;
561561 error = xfs_dir3_data_read(sc->tp, sc->ip,
562
- i * args->geo->fsbcount, -1, &dbp);
562
+ xfs_dir2_db_to_da(args->geo, i),
563
+ XFS_DABUF_MAP_HOLE_OK,
564
+ &dbp);
563565 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
564566 &error))
565567 break;
566
- xchk_directory_check_freesp(sc, lblk, dbp, best);
568
+
569
+ if (!dbp) {
570
+ if (best != NULLDATAOFF) {
571
+ xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
572
+ lblk);
573
+ break;
574
+ }
575
+ continue;
576
+ }
577
+
578
+ if (best == NULLDATAOFF)
579
+ xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
580
+ else
581
+ xchk_directory_check_freesp(sc, lblk, dbp, best);
567582 xfs_trans_brelse(sc->tp, dbp);
568583 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
569
- goto out;
584
+ break;
570585 }
571586 out:
587
+ xfs_trans_brelse(sc->tp, bp);
572588 return error;
573589 }
574590
....@@ -582,7 +598,6 @@
582598 struct xfs_dir3_icfree_hdr freehdr;
583599 struct xfs_buf *dbp;
584600 struct xfs_buf *bp;
585
- __be16 *bestp;
586601 __u16 best;
587602 unsigned int stale = 0;
588603 int i;
....@@ -591,7 +606,7 @@
591606 /* Read the free space block */
592607 error = xfs_dir2_free_read(sc->tp, sc->ip, lblk, &bp);
593608 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
594
- goto out;
609
+ return error;
595610 xchk_buffer_recheck(sc, bp);
596611
597612 if (xfs_sb_version_hascrc(&sc->mp->m_sb)) {
....@@ -602,20 +617,19 @@
602617 }
603618
604619 /* Check all the entries. */
605
- sc->ip->d_ops->free_hdr_from_disk(&freehdr, bp->b_addr);
606
- bestp = sc->ip->d_ops->free_bests_p(bp->b_addr);
607
- for (i = 0; i < freehdr.nvalid; i++, bestp++) {
608
- best = be16_to_cpu(*bestp);
620
+ xfs_dir2_free_hdr_from_disk(sc->ip->i_mount, &freehdr, bp->b_addr);
621
+ for (i = 0; i < freehdr.nvalid; i++) {
622
+ best = be16_to_cpu(freehdr.bests[i]);
609623 if (best == NULLDATAOFF) {
610624 stale++;
611625 continue;
612626 }
613627 error = xfs_dir3_data_read(sc->tp, sc->ip,
614628 (freehdr.firstdb + i) * args->geo->fsbcount,
615
- -1, &dbp);
629
+ 0, &dbp);
616630 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
617631 &error))
618
- break;
632
+ goto out;
619633 xchk_directory_check_freesp(sc, lblk, dbp, best);
620634 xfs_trans_brelse(sc->tp, dbp);
621635 }
....@@ -623,6 +637,7 @@
623637 if (freehdr.nused + stale != freehdr.nvalid)
624638 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
625639 out:
640
+ xfs_trans_brelse(sc->tp, bp);
626641 return error;
627642 }
628643
....@@ -633,7 +648,7 @@
633648 {
634649 struct xfs_bmbt_irec got;
635650 struct xfs_da_args args;
636
- struct xfs_ifork *ifp;
651
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, XFS_DATA_FORK);
637652 struct xfs_mount *mp = sc->mp;
638653 xfs_fileoff_t leaf_lblk;
639654 xfs_fileoff_t free_lblk;
....@@ -645,11 +660,10 @@
645660 int error;
646661
647662 /* Ignore local format directories. */
648
- if (sc->ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
649
- sc->ip->i_d.di_format != XFS_DINODE_FMT_BTREE)
663
+ if (ifp->if_format != XFS_DINODE_FMT_EXTENTS &&
664
+ ifp->if_format != XFS_DINODE_FMT_BTREE)
650665 return 0;
651666
652
- ifp = XFS_IFORK_PTR(sc->ip, XFS_DATA_FORK);
653667 lblk = XFS_B_TO_FSB(mp, XFS_DIR2_DATA_OFFSET);
654668 leaf_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_LEAF_OFFSET);
655669 free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET);