1176 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */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"12#include "xfs_log_format.h"13#include "xfs_trans.h"14#include "xfs_inode.h"15#include "xfs_icache.h"16#include "xfs_dir2.h"17#include "xfs_dir2_priv.h"18#include "xfs_health.h"19#include "xfs_attr.h"20#include "xfs_parent.h"21#include "scrub/scrub.h"22#include "scrub/common.h"23#include "scrub/dabtree.h"24#include "scrub/readdir.h"25#include "scrub/health.h"26#include "scrub/repair.h"27#include "scrub/trace.h"28#include "scrub/xfile.h"29#include "scrub/xfarray.h"30#include "scrub/xfblob.h"31 32/* Set us up to scrub directories. */33int34xchk_setup_directory(35 struct xfs_scrub *sc)36{37 int error;38 39 if (xchk_could_repair(sc)) {40 error = xrep_setup_directory(sc);41 if (error)42 return error;43 }44 45 return xchk_setup_inode_contents(sc, 0);46}47 48/* Directories */49 50/* Deferred directory entry that we saved for later. */51struct xchk_dirent {52 /* Cookie for retrieval of the dirent name. */53 xfblob_cookie name_cookie;54 55 /* Child inode number. */56 xfs_ino_t ino;57 58 /* Length of the pptr name. */59 uint8_t namelen;60};61 62struct xchk_dir {63 struct xfs_scrub *sc;64 65 /* information for parent pointer validation. */66 struct xfs_parent_rec pptr_rec;67 struct xfs_da_args pptr_args;68 69 /* Fixed-size array of xchk_dirent structures. */70 struct xfarray *dir_entries;71 72 /* Blobs containing dirent names. */73 struct xfblob *dir_names;74 75 /* If we've cycled the ILOCK, we must revalidate deferred dirents. */76 bool need_revalidate;77 78 /* Name buffer for dirent revalidation. */79 struct xfs_name xname;80 uint8_t namebuf[MAXNAMELEN];81};82 83/* Scrub a directory entry. */84 85/* Check that an inode's mode matches a given XFS_DIR3_FT_* type. */86STATIC void87xchk_dir_check_ftype(88 struct xfs_scrub *sc,89 xfs_fileoff_t offset,90 struct xfs_inode *ip,91 int ftype)92{93 struct xfs_mount *mp = sc->mp;94 95 if (!xfs_has_ftype(mp)) {96 if (ftype != XFS_DIR3_FT_UNKNOWN && ftype != XFS_DIR3_FT_DIR)97 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);98 return;99 }100 101 if (xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype)102 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);103}104 105/*106 * Try to lock a child file for checking parent pointers. Returns the inode107 * flags for the locks we now hold, or zero if we failed.108 */109STATIC unsigned int110xchk_dir_lock_child(111 struct xfs_scrub *sc,112 struct xfs_inode *ip)113{114 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))115 return 0;116 117 if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {118 xfs_iunlock(ip, XFS_IOLOCK_SHARED);119 return 0;120 }121 122 if (!xfs_inode_has_attr_fork(ip) || !xfs_need_iread_extents(&ip->i_af))123 return XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED;124 125 xfs_iunlock(ip, XFS_ILOCK_SHARED);126 127 if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {128 xfs_iunlock(ip, XFS_IOLOCK_SHARED);129 return 0;130 }131 132 return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;133}134 135/* Check the backwards link (parent pointer) associated with this dirent. */136STATIC int137xchk_dir_parent_pointer(138 struct xchk_dir *sd,139 const struct xfs_name *name,140 struct xfs_inode *ip)141{142 struct xfs_scrub *sc = sd->sc;143 int error;144 145 xfs_inode_to_parent_rec(&sd->pptr_rec, sc->ip);146 error = xfs_parent_lookup(sc->tp, ip, name, &sd->pptr_rec,147 &sd->pptr_args);148 if (error == -ENOATTR)149 xchk_fblock_xref_set_corrupt(sc, XFS_DATA_FORK, 0);150 151 return 0;152}153 154/* Look for a parent pointer matching this dirent, if the child isn't busy. */155STATIC int156xchk_dir_check_pptr_fast(157 struct xchk_dir *sd,158 xfs_dir2_dataptr_t dapos,159 const struct xfs_name *name,160 struct xfs_inode *ip)161{162 struct xfs_scrub *sc = sd->sc;163 unsigned int lockmode;164 int error;165 166 /* dot and dotdot entries do not have parent pointers */167 if (xfs_dir2_samename(name, &xfs_name_dot) ||168 xfs_dir2_samename(name, &xfs_name_dotdot))169 return 0;170 171 /* No self-referential non-dot or dotdot dirents. */172 if (ip == sc->ip) {173 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);174 return -ECANCELED;175 }176 177 /* Try to lock the inode. */178 lockmode = xchk_dir_lock_child(sc, ip);179 if (!lockmode) {180 struct xchk_dirent save_de = {181 .namelen = name->len,182 .ino = ip->i_ino,183 };184 185 /* Couldn't lock the inode, so save the dirent for later. */186 trace_xchk_dir_defer(sc->ip, name, ip->i_ino);187 188 error = xfblob_storename(sd->dir_names, &save_de.name_cookie,189 name);190 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,191 &error))192 return error;193 194 error = xfarray_append(sd->dir_entries, &save_de);195 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,196 &error))197 return error;198 199 return 0;200 }201 202 error = xchk_dir_parent_pointer(sd, name, ip);203 xfs_iunlock(ip, lockmode);204 return error;205}206 207/*208 * Scrub a single directory entry.209 *210 * Check the inode number to make sure it's sane, then we check that we can211 * look up this filename. Finally, we check the ftype.212 */213STATIC int214xchk_dir_actor(215 struct xfs_scrub *sc,216 struct xfs_inode *dp,217 xfs_dir2_dataptr_t dapos,218 const struct xfs_name *name,219 xfs_ino_t ino,220 void *priv)221{222 struct xfs_mount *mp = dp->i_mount;223 struct xfs_inode *ip;224 struct xchk_dir *sd = priv;225 xfs_ino_t lookup_ino;226 xfs_dablk_t offset;227 int error = 0;228 229 offset = xfs_dir2_db_to_da(mp->m_dir_geo,230 xfs_dir2_dataptr_to_db(mp->m_dir_geo, dapos));231 232 if (xchk_should_terminate(sc, &error))233 return error;234 235 /* Does this inode number make sense? */236 if (!xfs_verify_dir_ino(mp, ino)) {237 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);238 return -ECANCELED;239 }240 241 /* Does this name make sense? */242 if (!xfs_dir2_namecheck(name->name, name->len)) {243 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);244 return -ECANCELED;245 }246 247 if (xfs_dir2_samename(name, &xfs_name_dot)) {248 /* If this is "." then check that the inum matches the dir. */249 if (ino != dp->i_ino)250 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);251 } else if (xfs_dir2_samename(name, &xfs_name_dotdot)) {252 /*253 * If this is ".." in the root inode, check that the inum254 * matches this dir.255 */256 if (dp->i_ino == mp->m_sb.sb_rootino && ino != dp->i_ino)257 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);258 }259 260 /* Verify that we can look up this name by hash. */261 error = xchk_dir_lookup(sc, dp, name, &lookup_ino);262 /* ENOENT means the hash lookup failed and the dir is corrupt */263 if (error == -ENOENT)264 error = -EFSCORRUPTED;265 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, offset, &error))266 goto out;267 if (lookup_ino != ino) {268 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);269 return -ECANCELED;270 }271 272 /*273 * Grab the inode pointed to by the dirent. We release the inode274 * before we cancel the scrub transaction.275 *276 * If _iget returns -EINVAL or -ENOENT then the child inode number is277 * garbage and the directory is corrupt. If the _iget returns278 * -EFSCORRUPTED or -EFSBADCRC then the child is corrupt which is a279 * cross referencing error. Any other error is an operational error.280 */281 error = xchk_iget(sc, ino, &ip);282 if (error == -EINVAL || error == -ENOENT) {283 error = -EFSCORRUPTED;284 xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);285 goto out;286 }287 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, offset, &error))288 goto out;289 290 xchk_dir_check_ftype(sc, offset, ip, name->type);291 292 if (xfs_has_parent(mp)) {293 error = xchk_dir_check_pptr_fast(sd, dapos, name, ip);294 if (error)295 goto out_rele;296 }297 298out_rele:299 xchk_irele(sc, ip);300out:301 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)302 return -ECANCELED;303 return error;304}305 306/* Scrub a directory btree record. */307STATIC int308xchk_dir_rec(309 struct xchk_da_btree *ds,310 int level)311{312 struct xfs_name dname = { };313 struct xfs_da_state_blk *blk = &ds->state->path.blk[level];314 struct xfs_mount *mp = ds->state->mp;315 struct xfs_inode *dp = ds->dargs.dp;316 struct xfs_da_geometry *geo = mp->m_dir_geo;317 struct xfs_dir2_data_entry *dent;318 struct xfs_buf *bp;319 struct xfs_dir2_leaf_entry *ent;320 unsigned int end;321 unsigned int iter_off;322 xfs_ino_t ino;323 xfs_dablk_t rec_bno;324 xfs_dir2_db_t db;325 xfs_dir2_data_aoff_t off;326 xfs_dir2_dataptr_t ptr;327 xfs_dahash_t calc_hash;328 xfs_dahash_t hash;329 struct xfs_dir3_icleaf_hdr hdr;330 unsigned int tag;331 int error;332 333 ASSERT(blk->magic == XFS_DIR2_LEAF1_MAGIC ||334 blk->magic == XFS_DIR2_LEAFN_MAGIC);335 336 xfs_dir2_leaf_hdr_from_disk(mp, &hdr, blk->bp->b_addr);337 ent = hdr.ents + blk->index;338 339 /* Check the hash of the entry. */340 error = xchk_da_btree_hash(ds, level, &ent->hashval);341 if (error)342 goto out;343 344 /* Valid hash pointer? */345 ptr = be32_to_cpu(ent->address);346 if (ptr == 0)347 return 0;348 349 /* Find the directory entry's location. */350 db = xfs_dir2_dataptr_to_db(geo, ptr);351 off = xfs_dir2_dataptr_to_off(geo, ptr);352 rec_bno = xfs_dir2_db_to_da(geo, db);353 354 if (rec_bno >= geo->leafblk) {355 xchk_da_set_corrupt(ds, level);356 goto out;357 }358 error = xfs_dir3_data_read(ds->dargs.trans, dp, ds->dargs.owner,359 rec_bno, XFS_DABUF_MAP_HOLE_OK, &bp);360 if (!xchk_fblock_process_error(ds->sc, XFS_DATA_FORK, rec_bno,361 &error))362 goto out;363 if (!bp) {364 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);365 goto out;366 }367 xchk_buffer_recheck(ds->sc, bp);368 369 if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)370 goto out_relse;371 372 dent = bp->b_addr + off;373 374 /* Make sure we got a real directory entry. */375 iter_off = geo->data_entry_offset;376 end = xfs_dir3_data_end_offset(geo, bp->b_addr);377 if (!end) {378 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);379 goto out_relse;380 }381 for (;;) {382 struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off;383 struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off;384 385 if (iter_off >= end) {386 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);387 goto out_relse;388 }389 390 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {391 iter_off += be16_to_cpu(dup->length);392 continue;393 }394 if (dep == dent)395 break;396 iter_off += xfs_dir2_data_entsize(mp, dep->namelen);397 }398 399 /* Retrieve the entry, sanity check it, and compare hashes. */400 ino = be64_to_cpu(dent->inumber);401 hash = be32_to_cpu(ent->hashval);402 tag = be16_to_cpup(xfs_dir2_data_entry_tag_p(mp, dent));403 if (!xfs_verify_dir_ino(mp, ino) || tag != off)404 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);405 if (dent->namelen == 0) {406 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);407 goto out_relse;408 }409 410 /* Does the directory hash match? */411 dname.name = dent->name;412 dname.len = dent->namelen;413 calc_hash = xfs_dir2_hashname(mp, &dname);414 if (calc_hash != hash)415 xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);416 417out_relse:418 xfs_trans_brelse(ds->dargs.trans, bp);419out:420 return error;421}422 423/*424 * Is this unused entry either in the bestfree or smaller than all of425 * them? We've already checked that the bestfrees are sorted longest to426 * shortest, and that there aren't any bogus entries.427 */428STATIC void429xchk_directory_check_free_entry(430 struct xfs_scrub *sc,431 xfs_dablk_t lblk,432 struct xfs_dir2_data_free *bf,433 struct xfs_dir2_data_unused *dup)434{435 struct xfs_dir2_data_free *dfp;436 unsigned int dup_length;437 438 dup_length = be16_to_cpu(dup->length);439 440 /* Unused entry is shorter than any of the bestfrees */441 if (dup_length < be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))442 return;443 444 for (dfp = &bf[XFS_DIR2_DATA_FD_COUNT - 1]; dfp >= bf; dfp--)445 if (dup_length == be16_to_cpu(dfp->length))446 return;447 448 /* Unused entry should be in the bestfrees but wasn't found. */449 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);450}451 452/* Check free space info in a directory data block. */453STATIC int454xchk_directory_data_bestfree(455 struct xfs_scrub *sc,456 xfs_dablk_t lblk,457 bool is_block)458{459 struct xfs_dir2_data_unused *dup;460 struct xfs_dir2_data_free *dfp;461 struct xfs_buf *bp;462 struct xfs_dir2_data_free *bf;463 struct xfs_mount *mp = sc->mp;464 u16 tag;465 unsigned int nr_bestfrees = 0;466 unsigned int nr_frees = 0;467 unsigned int smallest_bestfree;468 int newlen;469 unsigned int offset;470 unsigned int end;471 int error;472 473 if (is_block) {474 /* dir block format */475 if (lblk != XFS_B_TO_FSBT(mp, XFS_DIR2_DATA_OFFSET))476 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);477 error = xfs_dir3_block_read(sc->tp, sc->ip, sc->ip->i_ino, &bp);478 } else {479 /* dir data format */480 error = xfs_dir3_data_read(sc->tp, sc->ip, sc->ip->i_ino, lblk,481 0, &bp);482 }483 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))484 goto out;485 xchk_buffer_recheck(sc, bp);486 487 /* XXX: Check xfs_dir3_data_hdr.pad is zero once we start setting it. */488 489 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)490 goto out_buf;491 492 /* Do the bestfrees correspond to actual free space? */493 bf = xfs_dir2_data_bestfree_p(mp, bp->b_addr);494 smallest_bestfree = UINT_MAX;495 for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {496 offset = be16_to_cpu(dfp->offset);497 if (offset == 0)498 continue;499 if (offset >= mp->m_dir_geo->blksize) {500 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);501 goto out_buf;502 }503 dup = bp->b_addr + offset;504 tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));505 506 /* bestfree doesn't match the entry it points at? */507 if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG) ||508 be16_to_cpu(dup->length) != be16_to_cpu(dfp->length) ||509 tag != offset) {510 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);511 goto out_buf;512 }513 514 /* bestfree records should be ordered largest to smallest */515 if (smallest_bestfree < be16_to_cpu(dfp->length)) {516 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);517 goto out_buf;518 }519 520 smallest_bestfree = be16_to_cpu(dfp->length);521 nr_bestfrees++;522 }523 524 /* Make sure the bestfrees are actually the best free spaces. */525 offset = mp->m_dir_geo->data_entry_offset;526 end = xfs_dir3_data_end_offset(mp->m_dir_geo, bp->b_addr);527 528 /* Iterate the entries, stopping when we hit or go past the end. */529 while (offset < end) {530 dup = bp->b_addr + offset;531 532 /* Skip real entries */533 if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG)) {534 struct xfs_dir2_data_entry *dep = bp->b_addr + offset;535 536 newlen = xfs_dir2_data_entsize(mp, dep->namelen);537 if (newlen <= 0) {538 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,539 lblk);540 goto out_buf;541 }542 offset += newlen;543 continue;544 }545 546 /* Spot check this free entry */547 tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));548 if (tag != offset) {549 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);550 goto out_buf;551 }552 553 /*554 * Either this entry is a bestfree or it's smaller than555 * any of the bestfrees.556 */557 xchk_directory_check_free_entry(sc, lblk, bf, dup);558 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)559 goto out_buf;560 561 /* Move on. */562 newlen = be16_to_cpu(dup->length);563 if (newlen <= 0) {564 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);565 goto out_buf;566 }567 offset += newlen;568 if (offset <= end)569 nr_frees++;570 }571 572 /* We're required to fill all the space. */573 if (offset != end)574 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);575 576 /* Did we see at least as many free slots as there are bestfrees? */577 if (nr_frees < nr_bestfrees)578 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);579out_buf:580 xfs_trans_brelse(sc->tp, bp);581out:582 return error;583}584 585/*586 * Does the free space length in the free space index block ($len) match587 * the longest length in the directory data block's bestfree array?588 * Assume that we've already checked that the data block's bestfree589 * array is in order.590 */591STATIC void592xchk_directory_check_freesp(593 struct xfs_scrub *sc,594 xfs_dablk_t lblk,595 struct xfs_buf *dbp,596 unsigned int len)597{598 struct xfs_dir2_data_free *dfp;599 600 dfp = xfs_dir2_data_bestfree_p(sc->mp, dbp->b_addr);601 602 if (len != be16_to_cpu(dfp->length))603 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);604 605 if (len > 0 && be16_to_cpu(dfp->offset) == 0)606 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);607}608 609/* Check free space info in a directory leaf1 block. */610STATIC int611xchk_directory_leaf1_bestfree(612 struct xfs_scrub *sc,613 struct xfs_da_args *args,614 xfs_dir2_db_t last_data_db,615 xfs_dablk_t lblk)616{617 struct xfs_dir3_icleaf_hdr leafhdr;618 struct xfs_dir2_leaf_tail *ltp;619 struct xfs_dir2_leaf *leaf;620 struct xfs_buf *dbp;621 struct xfs_buf *bp;622 struct xfs_da_geometry *geo = sc->mp->m_dir_geo;623 __be16 *bestp;624 __u16 best;625 __u32 hash;626 __u32 lasthash = 0;627 __u32 bestcount;628 unsigned int stale = 0;629 int i;630 int error;631 632 /* Read the free space block. */633 error = xfs_dir3_leaf_read(sc->tp, sc->ip, sc->ip->i_ino, lblk, &bp);634 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))635 return error;636 xchk_buffer_recheck(sc, bp);637 638 leaf = bp->b_addr;639 xfs_dir2_leaf_hdr_from_disk(sc->ip->i_mount, &leafhdr, leaf);640 ltp = xfs_dir2_leaf_tail_p(geo, leaf);641 bestcount = be32_to_cpu(ltp->bestcount);642 bestp = xfs_dir2_leaf_bests_p(ltp);643 644 if (xfs_has_crc(sc->mp)) {645 struct xfs_dir3_leaf_hdr *hdr3 = bp->b_addr;646 647 if (hdr3->pad != cpu_to_be32(0))648 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);649 }650 651 /*652 * There must be enough bestfree slots to cover all the directory data653 * blocks that we scanned. It is possible for there to be a hole654 * between the last data block and i_disk_size. This seems like an655 * oversight to the scrub author, but as we have been writing out656 * directories like this (and xfs_repair doesn't mind them) for years,657 * that's what we have to check.658 */659 if (bestcount != last_data_db + 1) {660 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);661 goto out;662 }663 664 /* Is the leaf count even remotely sane? */665 if (leafhdr.count > geo->leaf_max_ents) {666 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);667 goto out;668 }669 670 /* Leaves and bests don't overlap in leaf format. */671 if ((char *)&leafhdr.ents[leafhdr.count] > (char *)bestp) {672 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);673 goto out;674 }675 676 /* Check hash value order, count stale entries. */677 for (i = 0; i < leafhdr.count; i++) {678 hash = be32_to_cpu(leafhdr.ents[i].hashval);679 if (i > 0 && lasthash > hash)680 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);681 lasthash = hash;682 if (leafhdr.ents[i].address ==683 cpu_to_be32(XFS_DIR2_NULL_DATAPTR))684 stale++;685 }686 if (leafhdr.stale != stale)687 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);688 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)689 goto out;690 691 /* Check all the bestfree entries. */692 for (i = 0; i < bestcount; i++, bestp++) {693 best = be16_to_cpu(*bestp);694 error = xfs_dir3_data_read(sc->tp, sc->ip, args->owner,695 xfs_dir2_db_to_da(args->geo, i),696 XFS_DABUF_MAP_HOLE_OK, &dbp);697 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,698 &error))699 break;700 701 if (!dbp) {702 if (best != NULLDATAOFF) {703 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,704 lblk);705 break;706 }707 continue;708 }709 710 if (best == NULLDATAOFF)711 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);712 else713 xchk_directory_check_freesp(sc, lblk, dbp, best);714 xfs_trans_brelse(sc->tp, dbp);715 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)716 break;717 }718out:719 xfs_trans_brelse(sc->tp, bp);720 return error;721}722 723/* Check free space info in a directory freespace block. */724STATIC int725xchk_directory_free_bestfree(726 struct xfs_scrub *sc,727 struct xfs_da_args *args,728 xfs_dablk_t lblk)729{730 struct xfs_dir3_icfree_hdr freehdr;731 struct xfs_buf *dbp;732 struct xfs_buf *bp;733 __u16 best;734 unsigned int stale = 0;735 int i;736 int error;737 738 /* Read the free space block */739 error = xfs_dir2_free_read(sc->tp, sc->ip, sc->ip->i_ino, lblk, &bp);740 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))741 return error;742 xchk_buffer_recheck(sc, bp);743 744 if (xfs_has_crc(sc->mp)) {745 struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;746 747 if (hdr3->pad != cpu_to_be32(0))748 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);749 }750 751 /* Check all the entries. */752 xfs_dir2_free_hdr_from_disk(sc->ip->i_mount, &freehdr, bp->b_addr);753 for (i = 0; i < freehdr.nvalid; i++) {754 best = be16_to_cpu(freehdr.bests[i]);755 if (best == NULLDATAOFF) {756 stale++;757 continue;758 }759 error = xfs_dir3_data_read(sc->tp, sc->ip, args->owner,760 (freehdr.firstdb + i) * args->geo->fsbcount,761 0, &dbp);762 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,763 &error))764 goto out;765 xchk_directory_check_freesp(sc, lblk, dbp, best);766 xfs_trans_brelse(sc->tp, dbp);767 }768 769 if (freehdr.nused + stale != freehdr.nvalid)770 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);771out:772 xfs_trans_brelse(sc->tp, bp);773 return error;774}775 776/* Check free space information in directories. */777STATIC int778xchk_directory_blocks(779 struct xfs_scrub *sc)780{781 struct xfs_bmbt_irec got;782 struct xfs_da_args args = {783 .dp = sc->ip,784 .whichfork = XFS_DATA_FORK,785 .geo = sc->mp->m_dir_geo,786 .trans = sc->tp,787 .owner = sc->ip->i_ino,788 };789 struct xfs_ifork *ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);790 struct xfs_mount *mp = sc->mp;791 xfs_fileoff_t leaf_lblk;792 xfs_fileoff_t free_lblk;793 xfs_fileoff_t lblk;794 struct xfs_iext_cursor icur;795 xfs_dablk_t dabno;796 xfs_dir2_db_t last_data_db = 0;797 bool found;798 bool is_block = false;799 int error;800 801 /* Ignore local format directories. */802 if (ifp->if_format != XFS_DINODE_FMT_EXTENTS &&803 ifp->if_format != XFS_DINODE_FMT_BTREE)804 return 0;805 806 lblk = XFS_B_TO_FSB(mp, XFS_DIR2_DATA_OFFSET);807 leaf_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_LEAF_OFFSET);808 free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET);809 810 /* Is this a block dir? */811 if (xfs_dir2_format(&args, &error) == XFS_DIR2_FMT_BLOCK)812 is_block = true;813 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))814 goto out;815 816 /* Iterate all the data extents in the directory... */817 found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);818 while (found && !(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {819 /* No more data blocks... */820 if (got.br_startoff >= leaf_lblk)821 break;822 823 /*824 * Check each data block's bestfree data.825 *826 * Iterate all the fsbcount-aligned block offsets in827 * this directory. The directory block reading code is828 * smart enough to do its own bmap lookups to handle829 * discontiguous directory blocks. When we're done830 * with the extent record, re-query the bmap at the831 * next fsbcount-aligned offset to avoid redundant832 * block checks.833 */834 for (lblk = roundup((xfs_dablk_t)got.br_startoff,835 args.geo->fsbcount);836 lblk < got.br_startoff + got.br_blockcount;837 lblk += args.geo->fsbcount) {838 last_data_db = xfs_dir2_da_to_db(args.geo, lblk);839 error = xchk_directory_data_bestfree(sc, lblk,840 is_block);841 if (error)842 goto out;843 }844 dabno = got.br_startoff + got.br_blockcount;845 lblk = roundup(dabno, args.geo->fsbcount);846 found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);847 }848 849 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)850 goto out;851 852 /* Look for a leaf1 block, which has free info. */853 if (xfs_iext_lookup_extent(sc->ip, ifp, leaf_lblk, &icur, &got) &&854 got.br_startoff == leaf_lblk &&855 got.br_blockcount == args.geo->fsbcount &&856 !xfs_iext_next_extent(ifp, &icur, &got)) {857 if (is_block) {858 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);859 goto out;860 }861 error = xchk_directory_leaf1_bestfree(sc, &args, last_data_db,862 leaf_lblk);863 if (error)864 goto out;865 }866 867 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)868 goto out;869 870 /* Scan for free blocks */871 lblk = free_lblk;872 found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);873 while (found && !(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {874 /*875 * Dirs can't have blocks mapped above 2^32.876 * Single-block dirs shouldn't even be here.877 */878 lblk = got.br_startoff;879 if (lblk & ~0xFFFFFFFFULL) {880 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);881 goto out;882 }883 if (is_block) {884 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);885 goto out;886 }887 888 /*889 * Check each dir free block's bestfree data.890 *891 * Iterate all the fsbcount-aligned block offsets in892 * this directory. The directory block reading code is893 * smart enough to do its own bmap lookups to handle894 * discontiguous directory blocks. When we're done895 * with the extent record, re-query the bmap at the896 * next fsbcount-aligned offset to avoid redundant897 * block checks.898 */899 for (lblk = roundup((xfs_dablk_t)got.br_startoff,900 args.geo->fsbcount);901 lblk < got.br_startoff + got.br_blockcount;902 lblk += args.geo->fsbcount) {903 error = xchk_directory_free_bestfree(sc, &args,904 lblk);905 if (error)906 goto out;907 }908 dabno = got.br_startoff + got.br_blockcount;909 lblk = roundup(dabno, args.geo->fsbcount);910 found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);911 }912out:913 return error;914}915 916/*917 * Revalidate a dirent that we collected in the past but couldn't check because918 * of lock contention. Returns 0 if the dirent is still valid, -ENOENT if it919 * has gone away on us, or a negative errno.920 */921STATIC int922xchk_dir_revalidate_dirent(923 struct xchk_dir *sd,924 const struct xfs_name *xname,925 xfs_ino_t ino)926{927 struct xfs_scrub *sc = sd->sc;928 xfs_ino_t child_ino;929 int error;930 931 /*932 * Look up the directory entry. If we get -ENOENT, the directory entry933 * went away and there's nothing to revalidate. Return any other934 * error.935 */936 error = xchk_dir_lookup(sc, sc->ip, xname, &child_ino);937 if (error)938 return error;939 940 /* The inode number changed, nothing to revalidate. */941 if (ino != child_ino)942 return -ENOENT;943 944 return 0;945}946 947/*948 * Check a directory entry's parent pointers the slow way, which means we cycle949 * locks a bunch and put up with revalidation until we get it done.950 */951STATIC int952xchk_dir_slow_dirent(953 struct xchk_dir *sd,954 struct xchk_dirent *dirent,955 const struct xfs_name *xname)956{957 struct xfs_scrub *sc = sd->sc;958 struct xfs_inode *ip;959 unsigned int lockmode;960 int error;961 962 /* Check that the deferred dirent still exists. */963 if (sd->need_revalidate) {964 error = xchk_dir_revalidate_dirent(sd, xname, dirent->ino);965 if (error == -ENOENT)966 return 0;967 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,968 &error))969 return error;970 }971 972 error = xchk_iget(sc, dirent->ino, &ip);973 if (error == -EINVAL || error == -ENOENT) {974 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);975 return 0;976 }977 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))978 return error;979 980 /*981 * If we can grab both IOLOCK and ILOCK of the alleged child, we can982 * proceed with the validation.983 */984 lockmode = xchk_dir_lock_child(sc, ip);985 if (lockmode) {986 trace_xchk_dir_slowpath(sc->ip, xname, ip->i_ino);987 goto check_pptr;988 }989 990 /*991 * We couldn't lock the child file. Drop all the locks and try to992 * get them again, one at a time.993 */994 xchk_iunlock(sc, sc->ilock_flags);995 sd->need_revalidate = true;996 997 trace_xchk_dir_ultraslowpath(sc->ip, xname, ip->i_ino);998 999 error = xchk_dir_trylock_for_pptrs(sc, ip, &lockmode);1000 if (error)1001 goto out_rele;1002 1003 /* Revalidate, since we just cycled the locks. */1004 error = xchk_dir_revalidate_dirent(sd, xname, dirent->ino);1005 if (error == -ENOENT) {1006 error = 0;1007 goto out_unlock;1008 }1009 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))1010 goto out_unlock;1011 1012check_pptr:1013 error = xchk_dir_parent_pointer(sd, xname, ip);1014out_unlock:1015 xfs_iunlock(ip, lockmode);1016out_rele:1017 xchk_irele(sc, ip);1018 return error;1019}1020 1021/* Check all the dirents that we deferred the first time around. */1022STATIC int1023xchk_dir_finish_slow_dirents(1024 struct xchk_dir *sd)1025{1026 xfarray_idx_t array_cur;1027 int error;1028 1029 foreach_xfarray_idx(sd->dir_entries, array_cur) {1030 struct xchk_dirent dirent;1031 1032 if (sd->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)1033 return 0;1034 1035 error = xfarray_load(sd->dir_entries, array_cur, &dirent);1036 if (error)1037 return error;1038 1039 error = xfblob_loadname(sd->dir_names, dirent.name_cookie,1040 &sd->xname, dirent.namelen);1041 if (error)1042 return error;1043 1044 error = xchk_dir_slow_dirent(sd, &dirent, &sd->xname);1045 if (error)1046 return error;1047 }1048 1049 return 0;1050}1051 1052/* Scrub a whole directory. */1053int1054xchk_directory(1055 struct xfs_scrub *sc)1056{1057 struct xchk_dir *sd;1058 int error;1059 1060 if (!S_ISDIR(VFS_I(sc->ip)->i_mode))1061 return -ENOENT;1062 1063 if (xchk_file_looks_zapped(sc, XFS_SICK_INO_DIR_ZAPPED)) {1064 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);1065 return 0;1066 }1067 1068 /* Plausible size? */1069 if (sc->ip->i_disk_size < xfs_dir2_sf_hdr_size(0)) {1070 xchk_ino_set_corrupt(sc, sc->ip->i_ino);1071 return 0;1072 }1073 1074 /* Check directory tree structure */1075 error = xchk_da_btree(sc, XFS_DATA_FORK, xchk_dir_rec, NULL);1076 if (error)1077 return error;1078 1079 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)1080 return 0;1081 1082 /* Check the freespace. */1083 error = xchk_directory_blocks(sc);1084 if (error)1085 return error;1086 1087 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)1088 return 0;1089 1090 sd = kvzalloc(sizeof(struct xchk_dir), XCHK_GFP_FLAGS);1091 if (!sd)1092 return -ENOMEM;1093 sd->sc = sc;1094 sd->xname.name = sd->namebuf;1095 1096 if (xfs_has_parent(sc->mp)) {1097 char *descr;1098 1099 /*1100 * Set up some staging memory for dirents that we can't check1101 * due to locking contention.1102 */1103 descr = xchk_xfile_ino_descr(sc, "slow directory entries");1104 error = xfarray_create(descr, 0, sizeof(struct xchk_dirent),1105 &sd->dir_entries);1106 kfree(descr);1107 if (error)1108 goto out_sd;1109 1110 descr = xchk_xfile_ino_descr(sc, "slow directory entry names");1111 error = xfblob_create(descr, &sd->dir_names);1112 kfree(descr);1113 if (error)1114 goto out_entries;1115 }1116 1117 /* Look up every name in this directory by hash. */1118 error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, sd);1119 if (error == -ECANCELED)1120 error = 0;1121 if (error)1122 goto out_names;1123 1124 if (xfs_has_parent(sc->mp)) {1125 error = xchk_dir_finish_slow_dirents(sd);1126 if (error == -ETIMEDOUT) {1127 /* Couldn't grab a lock, scrub was marked incomplete */1128 error = 0;1129 goto out_names;1130 }1131 if (error)1132 goto out_names;1133 }1134 1135out_names:1136 if (sd->dir_names)1137 xfblob_destroy(sd->dir_names);1138out_entries:1139 if (sd->dir_entries)1140 xfarray_destroy(sd->dir_entries);1141out_sd:1142 kvfree(sd);1143 if (error)1144 return error;1145 1146 /* If the dir is clean, it is clearly not zapped. */1147 xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_DIR_ZAPPED);1148 return 0;1149}1150 1151/*1152 * Decide if this directory has been zapped to satisfy the inode and ifork1153 * verifiers. Checking and repairing should be postponed until the directory1154 * is fixed.1155 */1156bool1157xchk_dir_looks_zapped(1158 struct xfs_inode *dp)1159{1160 /* Repair zapped this dir's data fork a short time ago */1161 if (xfs_ifork_zapped(dp, XFS_DATA_FORK))1162 return true;1163 1164 /*1165 * If the dinode repair found a bad data fork, it will reset the fork1166 * to extents format with zero records and wait for the bmapbtd1167 * scrubber to reconstruct the block mappings. Directories always1168 * contain some content, so this is a clear sign of a zapped directory.1169 * The state checked by xfs_ifork_zapped is not persisted, so this is1170 * the secondary strategy if repairs are interrupted by a crash or an1171 * unmount.1172 */1173 return dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS &&1174 dp->i_df.if_nextents == 0;1175}1176