| .. | .. |
|---|
| 9 | 9 | #include "xfs_format.h" |
|---|
| 10 | 10 | #include "xfs_trans_resv.h" |
|---|
| 11 | 11 | #include "xfs_mount.h" |
|---|
| 12 | | -#include "xfs_defer.h" |
|---|
| 13 | | -#include "xfs_btree.h" |
|---|
| 14 | | -#include "xfs_bit.h" |
|---|
| 15 | 12 | #include "xfs_log_format.h" |
|---|
| 16 | 13 | #include "xfs_trans.h" |
|---|
| 17 | | -#include "xfs_sb.h" |
|---|
| 18 | 14 | #include "xfs_inode.h" |
|---|
| 19 | 15 | #include "xfs_icache.h" |
|---|
| 20 | | -#include "xfs_itable.h" |
|---|
| 21 | | -#include "xfs_da_format.h" |
|---|
| 22 | | -#include "xfs_da_btree.h" |
|---|
| 23 | 16 | #include "xfs_dir2.h" |
|---|
| 24 | 17 | #include "xfs_dir2_priv.h" |
|---|
| 25 | | -#include "xfs_ialloc.h" |
|---|
| 26 | | -#include "scrub/xfs_scrub.h" |
|---|
| 27 | 18 | #include "scrub/scrub.h" |
|---|
| 28 | 19 | #include "scrub/common.h" |
|---|
| 29 | | -#include "scrub/trace.h" |
|---|
| 30 | 20 | #include "scrub/dabtree.h" |
|---|
| 31 | 21 | |
|---|
| 32 | 22 | /* Set us up to scrub directories. */ |
|---|
| .. | .. |
|---|
| 123 | 113 | offset = xfs_dir2_db_to_da(mp->m_dir_geo, |
|---|
| 124 | 114 | xfs_dir2_dataptr_to_db(mp->m_dir_geo, pos)); |
|---|
| 125 | 115 | |
|---|
| 116 | + if (xchk_should_terminate(sdc->sc, &error)) |
|---|
| 117 | + return error; |
|---|
| 118 | + |
|---|
| 126 | 119 | /* Does this inode number make sense? */ |
|---|
| 127 | 120 | 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)) { |
|---|
| 128 | 127 | xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); |
|---|
| 129 | 128 | goto out; |
|---|
| 130 | 129 | } |
|---|
| .. | .. |
|---|
| 186 | 185 | STATIC int |
|---|
| 187 | 186 | xchk_dir_rec( |
|---|
| 188 | 187 | struct xchk_da_btree *ds, |
|---|
| 189 | | - int level, |
|---|
| 190 | | - void *rec) |
|---|
| 188 | + int level) |
|---|
| 191 | 189 | { |
|---|
| 190 | + struct xfs_da_state_blk *blk = &ds->state->path.blk[level]; |
|---|
| 192 | 191 | struct xfs_mount *mp = ds->state->mp; |
|---|
| 193 | | - struct xfs_dir2_leaf_entry *ent = rec; |
|---|
| 194 | 192 | struct xfs_inode *dp = ds->dargs.dp; |
|---|
| 193 | + struct xfs_da_geometry *geo = mp->m_dir_geo; |
|---|
| 195 | 194 | struct xfs_dir2_data_entry *dent; |
|---|
| 196 | 195 | struct xfs_buf *bp; |
|---|
| 197 | | - char *p, *endp; |
|---|
| 196 | + struct xfs_dir2_leaf_entry *ent; |
|---|
| 197 | + unsigned int end; |
|---|
| 198 | + unsigned int iter_off; |
|---|
| 198 | 199 | xfs_ino_t ino; |
|---|
| 199 | 200 | xfs_dablk_t rec_bno; |
|---|
| 200 | 201 | xfs_dir2_db_t db; |
|---|
| .. | .. |
|---|
| 202 | 203 | xfs_dir2_dataptr_t ptr; |
|---|
| 203 | 204 | xfs_dahash_t calc_hash; |
|---|
| 204 | 205 | xfs_dahash_t hash; |
|---|
| 206 | + struct xfs_dir3_icleaf_hdr hdr; |
|---|
| 205 | 207 | unsigned int tag; |
|---|
| 206 | 208 | 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; |
|---|
| 207 | 215 | |
|---|
| 208 | 216 | /* Check the hash of the entry. */ |
|---|
| 209 | 217 | error = xchk_da_btree_hash(ds, level, &ent->hashval); |
|---|
| .. | .. |
|---|
| 216 | 224 | return 0; |
|---|
| 217 | 225 | |
|---|
| 218 | 226 | /* 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); |
|---|
| 222 | 230 | |
|---|
| 223 | | - if (rec_bno >= mp->m_dir_geo->leafblk) { |
|---|
| 231 | + if (rec_bno >= geo->leafblk) { |
|---|
| 224 | 232 | xchk_da_set_corrupt(ds, level); |
|---|
| 225 | 233 | goto out; |
|---|
| 226 | 234 | } |
|---|
| 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); |
|---|
| 228 | 237 | if (!xchk_fblock_process_error(ds->sc, XFS_DATA_FORK, rec_bno, |
|---|
| 229 | 238 | &error)) |
|---|
| 230 | 239 | goto out; |
|---|
| .. | .. |
|---|
| 237 | 246 | if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) |
|---|
| 238 | 247 | goto out_relse; |
|---|
| 239 | 248 | |
|---|
| 240 | | - dent = (struct xfs_dir2_data_entry *)(((char *)bp->b_addr) + off); |
|---|
| 249 | + dent = bp->b_addr + off; |
|---|
| 241 | 250 | |
|---|
| 242 | 251 | /* 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) { |
|---|
| 246 | 255 | xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno); |
|---|
| 247 | 256 | goto out_relse; |
|---|
| 248 | 257 | } |
|---|
| 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; |
|---|
| 252 | 261 | |
|---|
| 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 | + |
|---|
| 254 | 267 | 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); |
|---|
| 256 | 269 | continue; |
|---|
| 257 | 270 | } |
|---|
| 258 | | - dep = (struct xfs_dir2_data_entry *)p; |
|---|
| 259 | 271 | if (dep == dent) |
|---|
| 260 | 272 | 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); |
|---|
| 266 | 274 | } |
|---|
| 267 | 275 | |
|---|
| 268 | 276 | /* Retrieve the entry, sanity check it, and compare hashes. */ |
|---|
| 269 | 277 | ino = be64_to_cpu(dent->inumber); |
|---|
| 270 | 278 | 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)); |
|---|
| 272 | 280 | if (!xfs_verify_dir_ino(mp, ino) || tag != off) |
|---|
| 273 | 281 | xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno); |
|---|
| 274 | 282 | if (dent->namelen == 0) { |
|---|
| .. | .. |
|---|
| 326 | 334 | struct xfs_buf *bp; |
|---|
| 327 | 335 | struct xfs_dir2_data_free *bf; |
|---|
| 328 | 336 | struct xfs_mount *mp = sc->mp; |
|---|
| 329 | | - const struct xfs_dir_ops *d_ops; |
|---|
| 330 | | - char *ptr; |
|---|
| 331 | | - char *endptr; |
|---|
| 332 | 337 | u16 tag; |
|---|
| 333 | 338 | unsigned int nr_bestfrees = 0; |
|---|
| 334 | 339 | unsigned int nr_frees = 0; |
|---|
| 335 | 340 | unsigned int smallest_bestfree; |
|---|
| 336 | 341 | int newlen; |
|---|
| 337 | | - int offset; |
|---|
| 342 | + unsigned int offset; |
|---|
| 343 | + unsigned int end; |
|---|
| 338 | 344 | int error; |
|---|
| 339 | | - |
|---|
| 340 | | - d_ops = sc->ip->d_ops; |
|---|
| 341 | 345 | |
|---|
| 342 | 346 | if (is_block) { |
|---|
| 343 | 347 | /* dir block format */ |
|---|
| .. | .. |
|---|
| 346 | 350 | error = xfs_dir3_block_read(sc->tp, sc->ip, &bp); |
|---|
| 347 | 351 | } else { |
|---|
| 348 | 352 | /* 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); |
|---|
| 350 | 354 | } |
|---|
| 351 | 355 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error)) |
|---|
| 352 | 356 | goto out; |
|---|
| .. | .. |
|---|
| 358 | 362 | goto out_buf; |
|---|
| 359 | 363 | |
|---|
| 360 | 364 | /* 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); |
|---|
| 362 | 366 | smallest_bestfree = UINT_MAX; |
|---|
| 363 | 367 | for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { |
|---|
| 364 | 368 | offset = be16_to_cpu(dfp->offset); |
|---|
| .. | .. |
|---|
| 368 | 372 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 369 | 373 | goto out_buf; |
|---|
| 370 | 374 | } |
|---|
| 371 | | - dup = (struct xfs_dir2_data_unused *)(bp->b_addr + offset); |
|---|
| 375 | + dup = bp->b_addr + offset; |
|---|
| 372 | 376 | tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)); |
|---|
| 373 | 377 | |
|---|
| 374 | 378 | /* bestfree doesn't match the entry it points at? */ |
|---|
| 375 | 379 | if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG) || |
|---|
| 376 | 380 | be16_to_cpu(dup->length) != be16_to_cpu(dfp->length) || |
|---|
| 377 | | - tag != ((char *)dup - (char *)bp->b_addr)) { |
|---|
| 381 | + tag != offset) { |
|---|
| 378 | 382 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 379 | 383 | goto out_buf; |
|---|
| 380 | 384 | } |
|---|
| .. | .. |
|---|
| 390 | 394 | } |
|---|
| 391 | 395 | |
|---|
| 392 | 396 | /* 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); |
|---|
| 395 | 399 | |
|---|
| 396 | 400 | /* 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 | + |
|---|
| 399 | 404 | /* Skip real entries */ |
|---|
| 400 | 405 | 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; |
|---|
| 402 | 407 | |
|---|
| 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); |
|---|
| 405 | 409 | if (newlen <= 0) { |
|---|
| 406 | 410 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, |
|---|
| 407 | 411 | lblk); |
|---|
| 408 | 412 | goto out_buf; |
|---|
| 409 | 413 | } |
|---|
| 410 | | - ptr += newlen; |
|---|
| 414 | + offset += newlen; |
|---|
| 411 | 415 | continue; |
|---|
| 412 | 416 | } |
|---|
| 413 | 417 | |
|---|
| 414 | 418 | /* Spot check this free entry */ |
|---|
| 415 | 419 | tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)); |
|---|
| 416 | | - if (tag != ((char *)dup - (char *)bp->b_addr)) { |
|---|
| 420 | + if (tag != offset) { |
|---|
| 417 | 421 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 418 | 422 | goto out_buf; |
|---|
| 419 | 423 | } |
|---|
| .. | .. |
|---|
| 432 | 436 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 433 | 437 | goto out_buf; |
|---|
| 434 | 438 | } |
|---|
| 435 | | - ptr += newlen; |
|---|
| 436 | | - if (ptr <= endptr) |
|---|
| 439 | + offset += newlen; |
|---|
| 440 | + if (offset <= end) |
|---|
| 437 | 441 | nr_frees++; |
|---|
| 438 | 442 | } |
|---|
| 439 | 443 | |
|---|
| 440 | 444 | /* We're required to fill all the space. */ |
|---|
| 441 | | - if (ptr != endptr) |
|---|
| 445 | + if (offset != end) |
|---|
| 442 | 446 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 443 | 447 | |
|---|
| 444 | 448 | /* Did we see at least as many free slots as there are bestfrees? */ |
|---|
| .. | .. |
|---|
| 465 | 469 | { |
|---|
| 466 | 470 | struct xfs_dir2_data_free *dfp; |
|---|
| 467 | 471 | |
|---|
| 468 | | - dfp = sc->ip->d_ops->data_bestfree_p(dbp->b_addr); |
|---|
| 472 | + dfp = xfs_dir2_data_bestfree_p(sc->mp, dbp->b_addr); |
|---|
| 469 | 473 | |
|---|
| 470 | 474 | if (len != be16_to_cpu(dfp->length)) |
|---|
| 471 | 475 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| .. | .. |
|---|
| 482 | 486 | xfs_dablk_t lblk) |
|---|
| 483 | 487 | { |
|---|
| 484 | 488 | struct xfs_dir3_icleaf_hdr leafhdr; |
|---|
| 485 | | - struct xfs_dir2_leaf_entry *ents; |
|---|
| 486 | 489 | struct xfs_dir2_leaf_tail *ltp; |
|---|
| 487 | 490 | struct xfs_dir2_leaf *leaf; |
|---|
| 488 | 491 | struct xfs_buf *dbp; |
|---|
| 489 | 492 | struct xfs_buf *bp; |
|---|
| 490 | | - const struct xfs_dir_ops *d_ops = sc->ip->d_ops; |
|---|
| 491 | 493 | struct xfs_da_geometry *geo = sc->mp->m_dir_geo; |
|---|
| 492 | 494 | __be16 *bestp; |
|---|
| 493 | 495 | __u16 best; |
|---|
| .. | .. |
|---|
| 499 | 501 | int error; |
|---|
| 500 | 502 | |
|---|
| 501 | 503 | /* 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); |
|---|
| 503 | 505 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error)) |
|---|
| 504 | | - goto out; |
|---|
| 506 | + return error; |
|---|
| 505 | 507 | xchk_buffer_recheck(sc, bp); |
|---|
| 506 | 508 | |
|---|
| 507 | 509 | 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); |
|---|
| 510 | 511 | ltp = xfs_dir2_leaf_tail_p(geo, leaf); |
|---|
| 511 | 512 | bestcount = be32_to_cpu(ltp->bestcount); |
|---|
| 512 | 513 | bestp = xfs_dir2_leaf_bests_p(ltp); |
|---|
| .. | .. |
|---|
| 528 | 529 | } |
|---|
| 529 | 530 | |
|---|
| 530 | 531 | /* 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) { |
|---|
| 532 | 533 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 533 | 534 | goto out; |
|---|
| 534 | 535 | } |
|---|
| 535 | 536 | |
|---|
| 536 | 537 | /* 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) { |
|---|
| 538 | 539 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 539 | 540 | goto out; |
|---|
| 540 | 541 | } |
|---|
| 541 | 542 | |
|---|
| 542 | 543 | /* Check hash value order, count stale entries. */ |
|---|
| 543 | 544 | for (i = 0; i < leafhdr.count; i++) { |
|---|
| 544 | | - hash = be32_to_cpu(ents[i].hashval); |
|---|
| 545 | + hash = be32_to_cpu(leafhdr.ents[i].hashval); |
|---|
| 545 | 546 | if (i > 0 && lasthash > hash) |
|---|
| 546 | 547 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 547 | 548 | 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)) |
|---|
| 549 | 551 | stale++; |
|---|
| 550 | 552 | } |
|---|
| 551 | 553 | if (leafhdr.stale != stale) |
|---|
| .. | .. |
|---|
| 556 | 558 | /* Check all the bestfree entries. */ |
|---|
| 557 | 559 | for (i = 0; i < bestcount; i++, bestp++) { |
|---|
| 558 | 560 | best = be16_to_cpu(*bestp); |
|---|
| 559 | | - if (best == NULLDATAOFF) |
|---|
| 560 | | - continue; |
|---|
| 561 | 561 | 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); |
|---|
| 563 | 565 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, |
|---|
| 564 | 566 | &error)) |
|---|
| 565 | 567 | 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); |
|---|
| 567 | 582 | xfs_trans_brelse(sc->tp, dbp); |
|---|
| 568 | 583 | if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) |
|---|
| 569 | | - goto out; |
|---|
| 584 | + break; |
|---|
| 570 | 585 | } |
|---|
| 571 | 586 | out: |
|---|
| 587 | + xfs_trans_brelse(sc->tp, bp); |
|---|
| 572 | 588 | return error; |
|---|
| 573 | 589 | } |
|---|
| 574 | 590 | |
|---|
| .. | .. |
|---|
| 582 | 598 | struct xfs_dir3_icfree_hdr freehdr; |
|---|
| 583 | 599 | struct xfs_buf *dbp; |
|---|
| 584 | 600 | struct xfs_buf *bp; |
|---|
| 585 | | - __be16 *bestp; |
|---|
| 586 | 601 | __u16 best; |
|---|
| 587 | 602 | unsigned int stale = 0; |
|---|
| 588 | 603 | int i; |
|---|
| .. | .. |
|---|
| 591 | 606 | /* Read the free space block */ |
|---|
| 592 | 607 | error = xfs_dir2_free_read(sc->tp, sc->ip, lblk, &bp); |
|---|
| 593 | 608 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error)) |
|---|
| 594 | | - goto out; |
|---|
| 609 | + return error; |
|---|
| 595 | 610 | xchk_buffer_recheck(sc, bp); |
|---|
| 596 | 611 | |
|---|
| 597 | 612 | if (xfs_sb_version_hascrc(&sc->mp->m_sb)) { |
|---|
| .. | .. |
|---|
| 602 | 617 | } |
|---|
| 603 | 618 | |
|---|
| 604 | 619 | /* 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]); |
|---|
| 609 | 623 | if (best == NULLDATAOFF) { |
|---|
| 610 | 624 | stale++; |
|---|
| 611 | 625 | continue; |
|---|
| 612 | 626 | } |
|---|
| 613 | 627 | error = xfs_dir3_data_read(sc->tp, sc->ip, |
|---|
| 614 | 628 | (freehdr.firstdb + i) * args->geo->fsbcount, |
|---|
| 615 | | - -1, &dbp); |
|---|
| 629 | + 0, &dbp); |
|---|
| 616 | 630 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, |
|---|
| 617 | 631 | &error)) |
|---|
| 618 | | - break; |
|---|
| 632 | + goto out; |
|---|
| 619 | 633 | xchk_directory_check_freesp(sc, lblk, dbp, best); |
|---|
| 620 | 634 | xfs_trans_brelse(sc->tp, dbp); |
|---|
| 621 | 635 | } |
|---|
| .. | .. |
|---|
| 623 | 637 | if (freehdr.nused + stale != freehdr.nvalid) |
|---|
| 624 | 638 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); |
|---|
| 625 | 639 | out: |
|---|
| 640 | + xfs_trans_brelse(sc->tp, bp); |
|---|
| 626 | 641 | return error; |
|---|
| 627 | 642 | } |
|---|
| 628 | 643 | |
|---|
| .. | .. |
|---|
| 633 | 648 | { |
|---|
| 634 | 649 | struct xfs_bmbt_irec got; |
|---|
| 635 | 650 | struct xfs_da_args args; |
|---|
| 636 | | - struct xfs_ifork *ifp; |
|---|
| 651 | + struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, XFS_DATA_FORK); |
|---|
| 637 | 652 | struct xfs_mount *mp = sc->mp; |
|---|
| 638 | 653 | xfs_fileoff_t leaf_lblk; |
|---|
| 639 | 654 | xfs_fileoff_t free_lblk; |
|---|
| .. | .. |
|---|
| 645 | 660 | int error; |
|---|
| 646 | 661 | |
|---|
| 647 | 662 | /* 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) |
|---|
| 650 | 665 | return 0; |
|---|
| 651 | 666 | |
|---|
| 652 | | - ifp = XFS_IFORK_PTR(sc->ip, XFS_DATA_FORK); |
|---|
| 653 | 667 | lblk = XFS_B_TO_FSB(mp, XFS_DIR2_DATA_OFFSET); |
|---|
| 654 | 668 | leaf_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_LEAF_OFFSET); |
|---|
| 655 | 669 | free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET); |
|---|