diff options
-rw-r--r-- | fs/xfs/xfs_dir2_node.c | 358 |
1 files changed, 202 insertions, 156 deletions
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 8dade711f099..e29b7c63e198 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c | |||
@@ -387,28 +387,26 @@ xfs_dir2_leafn_lasthash( | |||
387 | } | 387 | } |
388 | 388 | ||
389 | /* | 389 | /* |
390 | * Look up a leaf entry in a node-format leaf block. | 390 | * Look up a leaf entry for space to add a name in a node-format leaf block. |
391 | * If this is an addname then the extrablk in state is a freespace block, | 391 | * The extrablk in state is a freespace block. |
392 | * otherwise it's a data block. | ||
393 | */ | 392 | */ |
394 | int | 393 | STATIC int |
395 | xfs_dir2_leafn_lookup_int( | 394 | xfs_dir2_leafn_lookup_for_addname( |
396 | xfs_dabuf_t *bp, /* leaf buffer */ | 395 | xfs_dabuf_t *bp, /* leaf buffer */ |
397 | xfs_da_args_t *args, /* operation arguments */ | 396 | xfs_da_args_t *args, /* operation arguments */ |
398 | int *indexp, /* out: leaf entry index */ | 397 | int *indexp, /* out: leaf entry index */ |
399 | xfs_da_state_t *state) /* state to fill in */ | 398 | xfs_da_state_t *state) /* state to fill in */ |
400 | { | 399 | { |
401 | xfs_dabuf_t *curbp; /* current data/free buffer */ | 400 | xfs_dabuf_t *curbp = NULL; /* current data/free buffer */ |
402 | xfs_dir2_db_t curdb; /* current data block number */ | 401 | xfs_dir2_db_t curdb = -1; /* current data block number */ |
403 | xfs_dir2_db_t curfdb; /* current free block number */ | 402 | xfs_dir2_db_t curfdb = -1; /* current free block number */ |
404 | xfs_dir2_data_entry_t *dep; /* data block entry */ | ||
405 | xfs_inode_t *dp; /* incore directory inode */ | 403 | xfs_inode_t *dp; /* incore directory inode */ |
406 | int error; /* error return value */ | 404 | int error; /* error return value */ |
407 | int fi; /* free entry index */ | 405 | int fi; /* free entry index */ |
408 | xfs_dir2_free_t *free=NULL; /* free block structure */ | 406 | xfs_dir2_free_t *free = NULL; /* free block structure */ |
409 | int index; /* leaf entry index */ | 407 | int index; /* leaf entry index */ |
410 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 408 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
411 | int length=0; /* length of new data entry */ | 409 | int length; /* length of new data entry */ |
412 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | 410 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ |
413 | xfs_mount_t *mp; /* filesystem mount point */ | 411 | xfs_mount_t *mp; /* filesystem mount point */ |
414 | xfs_dir2_db_t newdb; /* new data block number */ | 412 | xfs_dir2_db_t newdb; /* new data block number */ |
@@ -431,33 +429,20 @@ xfs_dir2_leafn_lookup_int( | |||
431 | /* | 429 | /* |
432 | * Do we have a buffer coming in? | 430 | * Do we have a buffer coming in? |
433 | */ | 431 | */ |
434 | if (state->extravalid) | 432 | if (state->extravalid) { |
433 | /* If so, it's a free block buffer, get the block number. */ | ||
435 | curbp = state->extrablk.bp; | 434 | curbp = state->extrablk.bp; |
436 | else | 435 | curfdb = state->extrablk.blkno; |
437 | curbp = NULL; | 436 | free = curbp->data; |
438 | /* | 437 | ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC); |
439 | * For addname, it's a free block buffer, get the block number. | ||
440 | */ | ||
441 | if (args->addname) { | ||
442 | curfdb = curbp ? state->extrablk.blkno : -1; | ||
443 | curdb = -1; | ||
444 | length = xfs_dir2_data_entsize(args->namelen); | ||
445 | if ((free = (curbp ? curbp->data : NULL))) | ||
446 | ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC); | ||
447 | } | ||
448 | /* | ||
449 | * For others, it's a data block buffer, get the block number. | ||
450 | */ | ||
451 | else { | ||
452 | curfdb = -1; | ||
453 | curdb = curbp ? state->extrablk.blkno : -1; | ||
454 | } | 438 | } |
439 | length = xfs_dir2_data_entsize(args->namelen); | ||
455 | /* | 440 | /* |
456 | * Loop over leaf entries with the right hash value. | 441 | * Loop over leaf entries with the right hash value. |
457 | */ | 442 | */ |
458 | for (lep = &leaf->ents[index]; | 443 | for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && |
459 | index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; | 444 | be32_to_cpu(lep->hashval) == args->hashval; |
460 | lep++, index++) { | 445 | lep++, index++) { |
461 | /* | 446 | /* |
462 | * Skip stale leaf entries. | 447 | * Skip stale leaf entries. |
463 | */ | 448 | */ |
@@ -471,158 +456,218 @@ xfs_dir2_leafn_lookup_int( | |||
471 | * For addname, we're looking for a place to put the new entry. | 456 | * For addname, we're looking for a place to put the new entry. |
472 | * We want to use a data block with an entry of equal | 457 | * We want to use a data block with an entry of equal |
473 | * hash value to ours if there is one with room. | 458 | * hash value to ours if there is one with room. |
459 | * | ||
460 | * If this block isn't the data block we already have | ||
461 | * in hand, take a look at it. | ||
474 | */ | 462 | */ |
475 | if (args->addname) { | 463 | if (newdb != curdb) { |
464 | curdb = newdb; | ||
476 | /* | 465 | /* |
477 | * If this block isn't the data block we already have | 466 | * Convert the data block to the free block |
478 | * in hand, take a look at it. | 467 | * holding its freespace information. |
479 | */ | 468 | */ |
480 | if (newdb != curdb) { | 469 | newfdb = xfs_dir2_db_to_fdb(mp, newdb); |
481 | curdb = newdb; | ||
482 | /* | ||
483 | * Convert the data block to the free block | ||
484 | * holding its freespace information. | ||
485 | */ | ||
486 | newfdb = xfs_dir2_db_to_fdb(mp, newdb); | ||
487 | /* | ||
488 | * If it's not the one we have in hand, | ||
489 | * read it in. | ||
490 | */ | ||
491 | if (newfdb != curfdb) { | ||
492 | /* | ||
493 | * If we had one before, drop it. | ||
494 | */ | ||
495 | if (curbp) | ||
496 | xfs_da_brelse(tp, curbp); | ||
497 | /* | ||
498 | * Read the free block. | ||
499 | */ | ||
500 | if ((error = xfs_da_read_buf(tp, dp, | ||
501 | xfs_dir2_db_to_da(mp, | ||
502 | newfdb), | ||
503 | -1, &curbp, | ||
504 | XFS_DATA_FORK))) { | ||
505 | return error; | ||
506 | } | ||
507 | free = curbp->data; | ||
508 | ASSERT(be32_to_cpu(free->hdr.magic) == | ||
509 | XFS_DIR2_FREE_MAGIC); | ||
510 | ASSERT((be32_to_cpu(free->hdr.firstdb) % | ||
511 | XFS_DIR2_MAX_FREE_BESTS(mp)) == | ||
512 | 0); | ||
513 | ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb); | ||
514 | ASSERT(curdb < | ||
515 | be32_to_cpu(free->hdr.firstdb) + | ||
516 | be32_to_cpu(free->hdr.nvalid)); | ||
517 | } | ||
518 | /* | ||
519 | * Get the index for our entry. | ||
520 | */ | ||
521 | fi = xfs_dir2_db_to_fdindex(mp, curdb); | ||
522 | /* | ||
523 | * If it has room, return it. | ||
524 | */ | ||
525 | if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) { | ||
526 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", | ||
527 | XFS_ERRLEVEL_LOW, mp); | ||
528 | if (curfdb != newfdb) | ||
529 | xfs_da_brelse(tp, curbp); | ||
530 | return XFS_ERROR(EFSCORRUPTED); | ||
531 | } | ||
532 | curfdb = newfdb; | ||
533 | if (be16_to_cpu(free->bests[fi]) >= length) { | ||
534 | *indexp = index; | ||
535 | state->extravalid = 1; | ||
536 | state->extrablk.bp = curbp; | ||
537 | state->extrablk.blkno = curfdb; | ||
538 | state->extrablk.index = fi; | ||
539 | state->extrablk.magic = | ||
540 | XFS_DIR2_FREE_MAGIC; | ||
541 | ASSERT(args->oknoent); | ||
542 | return XFS_ERROR(ENOENT); | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | /* | ||
547 | * Not adding a new entry, so we really want to find | ||
548 | * the name given to us. | ||
549 | */ | ||
550 | else { | ||
551 | /* | 470 | /* |
552 | * If it's a different data block, go get it. | 471 | * If it's not the one we have in hand, read it in. |
553 | */ | 472 | */ |
554 | if (newdb != curdb) { | 473 | if (newfdb != curfdb) { |
555 | /* | 474 | /* |
556 | * If we had a block before, drop it. | 475 | * If we had one before, drop it. |
557 | */ | 476 | */ |
558 | if (curbp) | 477 | if (curbp) |
559 | xfs_da_brelse(tp, curbp); | 478 | xfs_da_brelse(tp, curbp); |
560 | /* | 479 | /* |
561 | * Read the data block. | 480 | * Read the free block. |
562 | */ | 481 | */ |
563 | if ((error = | 482 | error = xfs_da_read_buf(tp, dp, |
564 | xfs_da_read_buf(tp, dp, | 483 | xfs_dir2_db_to_da(mp, newfdb), |
565 | xfs_dir2_db_to_da(mp, newdb), -1, | 484 | -1, &curbp, XFS_DATA_FORK); |
566 | &curbp, XFS_DATA_FORK))) { | 485 | if (error) |
567 | return error; | 486 | return error; |
568 | } | 487 | free = curbp->data; |
569 | xfs_dir2_data_check(dp, curbp); | 488 | ASSERT(be32_to_cpu(free->hdr.magic) == |
570 | curdb = newdb; | 489 | XFS_DIR2_FREE_MAGIC); |
490 | ASSERT((be32_to_cpu(free->hdr.firstdb) % | ||
491 | XFS_DIR2_MAX_FREE_BESTS(mp)) == 0); | ||
492 | ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb); | ||
493 | ASSERT(curdb < be32_to_cpu(free->hdr.firstdb) + | ||
494 | be32_to_cpu(free->hdr.nvalid)); | ||
571 | } | 495 | } |
572 | /* | 496 | /* |
573 | * Point to the data entry. | 497 | * Get the index for our entry. |
574 | */ | 498 | */ |
575 | dep = (xfs_dir2_data_entry_t *) | 499 | fi = xfs_dir2_db_to_fdindex(mp, curdb); |
576 | ((char *)curbp->data + | ||
577 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); | ||
578 | /* | 500 | /* |
579 | * Compare the entry, return it if it matches. | 501 | * If it has room, return it. |
580 | */ | 502 | */ |
581 | if (dep->namelen == args->namelen && | 503 | if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) { |
582 | dep->name[0] == args->name[0] && | 504 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", |
583 | memcmp(dep->name, args->name, args->namelen) == 0) { | 505 | XFS_ERRLEVEL_LOW, mp); |
584 | args->inumber = be64_to_cpu(dep->inumber); | 506 | if (curfdb != newfdb) |
585 | *indexp = index; | 507 | xfs_da_brelse(tp, curbp); |
586 | state->extravalid = 1; | 508 | return XFS_ERROR(EFSCORRUPTED); |
587 | state->extrablk.bp = curbp; | ||
588 | state->extrablk.blkno = curdb; | ||
589 | state->extrablk.index = | ||
590 | (int)((char *)dep - | ||
591 | (char *)curbp->data); | ||
592 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | ||
593 | return XFS_ERROR(EEXIST); | ||
594 | } | 509 | } |
510 | curfdb = newfdb; | ||
511 | if (be16_to_cpu(free->bests[fi]) >= length) | ||
512 | goto out; | ||
595 | } | 513 | } |
596 | } | 514 | } |
515 | /* Didn't find any space */ | ||
516 | fi = -1; | ||
517 | out: | ||
518 | ASSERT(args->oknoent); | ||
519 | if (curbp) { | ||
520 | /* Giving back a free block. */ | ||
521 | state->extravalid = 1; | ||
522 | state->extrablk.bp = curbp; | ||
523 | state->extrablk.index = fi; | ||
524 | state->extrablk.blkno = curfdb; | ||
525 | state->extrablk.magic = XFS_DIR2_FREE_MAGIC; | ||
526 | } else { | ||
527 | state->extravalid = 0; | ||
528 | } | ||
597 | /* | 529 | /* |
598 | * Didn't find a match. | 530 | * Return the index, that will be the insertion point. |
599 | * If we are holding a buffer, give it back in case our caller | ||
600 | * finds it useful. | ||
601 | */ | 531 | */ |
602 | if ((state->extravalid = (curbp != NULL))) { | 532 | *indexp = index; |
603 | state->extrablk.bp = curbp; | 533 | return XFS_ERROR(ENOENT); |
604 | state->extrablk.index = -1; | 534 | } |
535 | |||
536 | /* | ||
537 | * Look up a leaf entry in a node-format leaf block. | ||
538 | * The extrablk in state a data block. | ||
539 | */ | ||
540 | STATIC int | ||
541 | xfs_dir2_leafn_lookup_for_entry( | ||
542 | xfs_dabuf_t *bp, /* leaf buffer */ | ||
543 | xfs_da_args_t *args, /* operation arguments */ | ||
544 | int *indexp, /* out: leaf entry index */ | ||
545 | xfs_da_state_t *state) /* state to fill in */ | ||
546 | { | ||
547 | xfs_dabuf_t *curbp = NULL; /* current data/free buffer */ | ||
548 | xfs_dir2_db_t curdb = -1; /* current data block number */ | ||
549 | xfs_dir2_data_entry_t *dep; /* data block entry */ | ||
550 | xfs_inode_t *dp; /* incore directory inode */ | ||
551 | int error; /* error return value */ | ||
552 | int di; /* data entry index */ | ||
553 | int index; /* leaf entry index */ | ||
554 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | ||
555 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | ||
556 | xfs_mount_t *mp; /* filesystem mount point */ | ||
557 | xfs_dir2_db_t newdb; /* new data block number */ | ||
558 | xfs_trans_t *tp; /* transaction pointer */ | ||
559 | |||
560 | dp = args->dp; | ||
561 | tp = args->trans; | ||
562 | mp = dp->i_mount; | ||
563 | leaf = bp->data; | ||
564 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); | ||
565 | #ifdef __KERNEL__ | ||
566 | ASSERT(be16_to_cpu(leaf->hdr.count) > 0); | ||
567 | #endif | ||
568 | xfs_dir2_leafn_check(dp, bp); | ||
569 | /* | ||
570 | * Look up the hash value in the leaf entries. | ||
571 | */ | ||
572 | index = xfs_dir2_leaf_search_hash(args, bp); | ||
573 | /* | ||
574 | * Do we have a buffer coming in? | ||
575 | */ | ||
576 | if (state->extravalid) { | ||
577 | curbp = state->extrablk.bp; | ||
578 | curdb = state->extrablk.blkno; | ||
579 | } | ||
580 | /* | ||
581 | * Loop over leaf entries with the right hash value. | ||
582 | */ | ||
583 | for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && | ||
584 | be32_to_cpu(lep->hashval) == args->hashval; | ||
585 | lep++, index++) { | ||
586 | /* | ||
587 | * Skip stale leaf entries. | ||
588 | */ | ||
589 | if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) | ||
590 | continue; | ||
591 | /* | ||
592 | * Pull the data block number from the entry. | ||
593 | */ | ||
594 | newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); | ||
605 | /* | 595 | /* |
606 | * For addname, giving back a free block. | 596 | * Not adding a new entry, so we really want to find |
597 | * the name given to us. | ||
598 | * | ||
599 | * If it's a different data block, go get it. | ||
607 | */ | 600 | */ |
608 | if (args->addname) { | 601 | if (newdb != curdb) { |
609 | state->extrablk.blkno = curfdb; | 602 | /* |
610 | state->extrablk.magic = XFS_DIR2_FREE_MAGIC; | 603 | * If we had a block before, drop it. |
604 | */ | ||
605 | if (curbp) | ||
606 | xfs_da_brelse(tp, curbp); | ||
607 | /* | ||
608 | * Read the data block. | ||
609 | */ | ||
610 | error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, | ||
611 | newdb), -1, &curbp, XFS_DATA_FORK); | ||
612 | if (error) | ||
613 | return error; | ||
614 | xfs_dir2_data_check(dp, curbp); | ||
615 | curdb = newdb; | ||
611 | } | 616 | } |
612 | /* | 617 | /* |
613 | * For other callers, giving back a data block. | 618 | * Point to the data entry. |
614 | */ | 619 | */ |
615 | else { | 620 | dep = (xfs_dir2_data_entry_t *)((char *)curbp->data + |
616 | state->extrablk.blkno = curdb; | 621 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); |
617 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | 622 | /* |
623 | * Compare the entry, return it if it matches. | ||
624 | */ | ||
625 | if (dep->namelen == args->namelen && memcmp(dep->name, | ||
626 | args->name, args->namelen) == 0) { | ||
627 | args->inumber = be64_to_cpu(dep->inumber); | ||
628 | di = (int)((char *)dep - (char *)curbp->data); | ||
629 | error = EEXIST; | ||
630 | goto out; | ||
618 | } | 631 | } |
619 | } | 632 | } |
633 | /* Didn't find a match. */ | ||
634 | error = ENOENT; | ||
635 | di = -1; | ||
636 | ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent); | ||
637 | out: | ||
638 | if (curbp) { | ||
639 | /* Giving back a data block. */ | ||
640 | state->extravalid = 1; | ||
641 | state->extrablk.bp = curbp; | ||
642 | state->extrablk.index = di; | ||
643 | state->extrablk.blkno = curdb; | ||
644 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | ||
645 | } else { | ||
646 | state->extravalid = 0; | ||
647 | } | ||
620 | /* | 648 | /* |
621 | * Return the final index, that will be the insertion point. | 649 | * Return the index, that will be the insertion point. |
622 | */ | 650 | */ |
623 | *indexp = index; | 651 | *indexp = index; |
624 | ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent); | 652 | return XFS_ERROR(error); |
625 | return XFS_ERROR(ENOENT); | 653 | } |
654 | |||
655 | /* | ||
656 | * Look up a leaf entry in a node-format leaf block. | ||
657 | * If this is an addname then the extrablk in state is a freespace block, | ||
658 | * otherwise it's a data block. | ||
659 | */ | ||
660 | int | ||
661 | xfs_dir2_leafn_lookup_int( | ||
662 | xfs_dabuf_t *bp, /* leaf buffer */ | ||
663 | xfs_da_args_t *args, /* operation arguments */ | ||
664 | int *indexp, /* out: leaf entry index */ | ||
665 | xfs_da_state_t *state) /* state to fill in */ | ||
666 | { | ||
667 | if (args->addname) | ||
668 | return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, | ||
669 | state); | ||
670 | return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); | ||
626 | } | 671 | } |
627 | 672 | ||
628 | /* | 673 | /* |
@@ -823,9 +868,10 @@ xfs_dir2_leafn_rebalance( | |||
823 | */ | 868 | */ |
824 | if (!state->inleaf) | 869 | if (!state->inleaf) |
825 | blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); | 870 | blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); |
826 | 871 | ||
827 | /* | 872 | /* |
828 | * Finally sanity check just to make sure we are not returning a negative index | 873 | * Finally sanity check just to make sure we are not returning a |
874 | * negative index | ||
829 | */ | 875 | */ |
830 | if(blk2->index < 0) { | 876 | if(blk2->index < 0) { |
831 | state->inleaf = 1; | 877 | state->inleaf = 1; |