diff options
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 144 |
1 files changed, 61 insertions, 83 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 040eb288bb1c..ea5888688f94 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -455,12 +455,11 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind) | |||
455 | * @goal: place to store the result. | 455 | * @goal: place to store the result. |
456 | * | 456 | * |
457 | * Normally this function find the prefered place for block allocation, | 457 | * Normally this function find the prefered place for block allocation, |
458 | * stores it in *@goal and returns zero. If the branch had been changed | 458 | * stores it in *@goal and returns zero. |
459 | * under us we return -EAGAIN. | ||
460 | */ | 459 | */ |
461 | 460 | ||
462 | static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4], | 461 | static unsigned long ext3_find_goal(struct inode *inode, long block, |
463 | Indirect *partial, unsigned long *goal) | 462 | Indirect chain[4], Indirect *partial) |
464 | { | 463 | { |
465 | struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info; | 464 | struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info; |
466 | 465 | ||
@@ -470,15 +469,10 @@ static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4], | |||
470 | */ | 469 | */ |
471 | if (block_i && (block == block_i->last_alloc_logical_block + 1) | 470 | if (block_i && (block == block_i->last_alloc_logical_block + 1) |
472 | && (block_i->last_alloc_physical_block != 0)) { | 471 | && (block_i->last_alloc_physical_block != 0)) { |
473 | *goal = block_i->last_alloc_physical_block + 1; | 472 | return block_i->last_alloc_physical_block + 1; |
474 | return 0; | ||
475 | } | 473 | } |
476 | 474 | ||
477 | if (verify_chain(chain, partial)) { | 475 | return ext3_find_near(inode, partial); |
478 | *goal = ext3_find_near(inode, partial); | ||
479 | return 0; | ||
480 | } | ||
481 | return -EAGAIN; | ||
482 | } | 476 | } |
483 | 477 | ||
484 | /** | 478 | /** |
@@ -582,12 +576,9 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, | |||
582 | * @where: location of missing link | 576 | * @where: location of missing link |
583 | * @num: number of blocks we are adding | 577 | * @num: number of blocks we are adding |
584 | * | 578 | * |
585 | * This function verifies that chain (up to the missing link) had not | 579 | * This function fills the missing link and does all housekeeping needed in |
586 | * changed, fills the missing link and does all housekeeping needed in | ||
587 | * inode (->i_blocks, etc.). In case of success we end up with the full | 580 | * inode (->i_blocks, etc.). In case of success we end up with the full |
588 | * chain to new block and return 0. Otherwise (== chain had been changed) | 581 | * chain to new block and return 0. |
589 | * we free the new blocks (forgetting their buffer_heads, indeed) and | ||
590 | * return -EAGAIN. | ||
591 | */ | 582 | */ |
592 | 583 | ||
593 | static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, | 584 | static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, |
@@ -608,12 +599,6 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, | |||
608 | if (err) | 599 | if (err) |
609 | goto err_out; | 600 | goto err_out; |
610 | } | 601 | } |
611 | /* Verify that place we are splicing to is still there and vacant */ | ||
612 | |||
613 | if (!verify_chain(chain, where-1) || *where->p) | ||
614 | /* Writer: end */ | ||
615 | goto changed; | ||
616 | |||
617 | /* That's it */ | 602 | /* That's it */ |
618 | 603 | ||
619 | *where->p = where->key; | 604 | *where->p = where->key; |
@@ -657,26 +642,11 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, | |||
657 | } | 642 | } |
658 | return err; | 643 | return err; |
659 | 644 | ||
660 | changed: | ||
661 | /* | ||
662 | * AKPM: if where[i].bh isn't part of the current updating | ||
663 | * transaction then we explode nastily. Test this code path. | ||
664 | */ | ||
665 | jbd_debug(1, "the chain changed: try again\n"); | ||
666 | err = -EAGAIN; | ||
667 | |||
668 | err_out: | 645 | err_out: |
669 | for (i = 1; i < num; i++) { | 646 | for (i = 1; i < num; i++) { |
670 | BUFFER_TRACE(where[i].bh, "call journal_forget"); | 647 | BUFFER_TRACE(where[i].bh, "call journal_forget"); |
671 | ext3_journal_forget(handle, where[i].bh); | 648 | ext3_journal_forget(handle, where[i].bh); |
672 | } | 649 | } |
673 | /* For the normal collision cleanup case, we free up the blocks. | ||
674 | * On genuine filesystem errors we don't even think about doing | ||
675 | * that. */ | ||
676 | if (err == -EAGAIN) | ||
677 | for (i = 0; i < num; i++) | ||
678 | ext3_free_blocks(handle, inode, | ||
679 | le32_to_cpu(where[i].key), 1); | ||
680 | return err; | 650 | return err; |
681 | } | 651 | } |
682 | 652 | ||
@@ -708,7 +678,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, | |||
708 | unsigned long goal; | 678 | unsigned long goal; |
709 | int left; | 679 | int left; |
710 | int boundary = 0; | 680 | int boundary = 0; |
711 | int depth = ext3_block_to_path(inode, iblock, offsets, &boundary); | 681 | const int depth = ext3_block_to_path(inode, iblock, offsets, &boundary); |
712 | struct ext3_inode_info *ei = EXT3_I(inode); | 682 | struct ext3_inode_info *ei = EXT3_I(inode); |
713 | 683 | ||
714 | J_ASSERT(handle != NULL || create == 0); | 684 | J_ASSERT(handle != NULL || create == 0); |
@@ -716,54 +686,55 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, | |||
716 | if (depth == 0) | 686 | if (depth == 0) |
717 | goto out; | 687 | goto out; |
718 | 688 | ||
719 | reread: | ||
720 | partial = ext3_get_branch(inode, depth, offsets, chain, &err); | 689 | partial = ext3_get_branch(inode, depth, offsets, chain, &err); |
721 | 690 | ||
722 | /* Simplest case - block found, no allocation needed */ | 691 | /* Simplest case - block found, no allocation needed */ |
723 | if (!partial) { | 692 | if (!partial) { |
724 | clear_buffer_new(bh_result); | 693 | clear_buffer_new(bh_result); |
725 | got_it: | 694 | goto got_it; |
726 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); | ||
727 | if (boundary) | ||
728 | set_buffer_boundary(bh_result); | ||
729 | /* Clean up and exit */ | ||
730 | partial = chain+depth-1; /* the whole chain */ | ||
731 | goto cleanup; | ||
732 | } | 695 | } |
733 | 696 | ||
734 | /* Next simple case - plain lookup or failed read of indirect block */ | 697 | /* Next simple case - plain lookup or failed read of indirect block */ |
735 | if (!create || err == -EIO) { | 698 | if (!create || err == -EIO) |
736 | cleanup: | 699 | goto cleanup; |
700 | |||
701 | down(&ei->truncate_sem); | ||
702 | |||
703 | /* | ||
704 | * If the indirect block is missing while we are reading | ||
705 | * the chain(ext3_get_branch() returns -EAGAIN err), or | ||
706 | * if the chain has been changed after we grab the semaphore, | ||
707 | * (either because another process truncated this branch, or | ||
708 | * another get_block allocated this branch) re-grab the chain to see if | ||
709 | * the request block has been allocated or not. | ||
710 | * | ||
711 | * Since we already block the truncate/other get_block | ||
712 | * at this point, we will have the current copy of the chain when we | ||
713 | * splice the branch into the tree. | ||
714 | */ | ||
715 | if (err == -EAGAIN || !verify_chain(chain, partial)) { | ||
737 | while (partial > chain) { | 716 | while (partial > chain) { |
738 | BUFFER_TRACE(partial->bh, "call brelse"); | ||
739 | brelse(partial->bh); | 717 | brelse(partial->bh); |
740 | partial--; | 718 | partial--; |
741 | } | 719 | } |
742 | BUFFER_TRACE(bh_result, "returned"); | 720 | partial = ext3_get_branch(inode, depth, offsets, chain, &err); |
743 | out: | 721 | if (!partial) { |
744 | return err; | 722 | up(&ei->truncate_sem); |
723 | if (err) | ||
724 | goto cleanup; | ||
725 | clear_buffer_new(bh_result); | ||
726 | goto got_it; | ||
727 | } | ||
745 | } | 728 | } |
746 | 729 | ||
747 | /* | 730 | /* |
748 | * Indirect block might be removed by truncate while we were | 731 | * Okay, we need to do block allocation. Lazily initialize the block |
749 | * reading it. Handling of that case (forget what we've got and | 732 | * allocation info here if necessary |
750 | * reread) is taken out of the main path. | 733 | */ |
751 | */ | 734 | if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) |
752 | if (err == -EAGAIN) | ||
753 | goto changed; | ||
754 | |||
755 | goal = 0; | ||
756 | down(&ei->truncate_sem); | ||
757 | |||
758 | /* lazy initialize the block allocation info here if necessary */ | ||
759 | if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) { | ||
760 | ext3_init_block_alloc_info(inode); | 735 | ext3_init_block_alloc_info(inode); |
761 | } | ||
762 | 736 | ||
763 | if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) { | 737 | goal = ext3_find_goal(inode, iblock, chain, partial); |
764 | up(&ei->truncate_sem); | ||
765 | goto changed; | ||
766 | } | ||
767 | 738 | ||
768 | left = (chain + depth) - partial; | 739 | left = (chain + depth) - partial; |
769 | 740 | ||
@@ -771,38 +742,45 @@ out: | |||
771 | * Block out ext3_truncate while we alter the tree | 742 | * Block out ext3_truncate while we alter the tree |
772 | */ | 743 | */ |
773 | err = ext3_alloc_branch(handle, inode, left, goal, | 744 | err = ext3_alloc_branch(handle, inode, left, goal, |
774 | offsets+(partial-chain), partial); | 745 | offsets + (partial - chain), partial); |
775 | 746 | ||
776 | /* The ext3_splice_branch call will free and forget any buffers | 747 | /* |
748 | * The ext3_splice_branch call will free and forget any buffers | ||
777 | * on the new chain if there is a failure, but that risks using | 749 | * on the new chain if there is a failure, but that risks using |
778 | * up transaction credits, especially for bitmaps where the | 750 | * up transaction credits, especially for bitmaps where the |
779 | * credits cannot be returned. Can we handle this somehow? We | 751 | * credits cannot be returned. Can we handle this somehow? We |
780 | * may need to return -EAGAIN upwards in the worst case. --sct */ | 752 | * may need to return -EAGAIN upwards in the worst case. --sct |
753 | */ | ||
781 | if (!err) | 754 | if (!err) |
782 | err = ext3_splice_branch(handle, inode, iblock, chain, | 755 | err = ext3_splice_branch(handle, inode, iblock, chain, |
783 | partial, left); | 756 | partial, left); |
784 | /* i_disksize growing is protected by truncate_sem | 757 | /* |
785 | * don't forget to protect it if you're about to implement | 758 | * i_disksize growing is protected by truncate_sem. Don't forget to |
786 | * concurrent ext3_get_block() -bzzz */ | 759 | * protect it if you're about to implement concurrent |
760 | * ext3_get_block() -bzzz | ||
761 | */ | ||
787 | if (!err && extend_disksize && inode->i_size > ei->i_disksize) | 762 | if (!err && extend_disksize && inode->i_size > ei->i_disksize) |
788 | ei->i_disksize = inode->i_size; | 763 | ei->i_disksize = inode->i_size; |
789 | up(&ei->truncate_sem); | 764 | up(&ei->truncate_sem); |
790 | if (err == -EAGAIN) | ||
791 | goto changed; | ||
792 | if (err) | 765 | if (err) |
793 | goto cleanup; | 766 | goto cleanup; |
794 | 767 | ||
795 | set_buffer_new(bh_result); | 768 | set_buffer_new(bh_result); |
796 | goto got_it; | 769 | got_it: |
797 | 770 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); | |
798 | changed: | 771 | if (boundary) |
772 | set_buffer_boundary(bh_result); | ||
773 | /* Clean up and exit */ | ||
774 | partial = chain + depth - 1; /* the whole chain */ | ||
775 | cleanup: | ||
799 | while (partial > chain) { | 776 | while (partial > chain) { |
800 | jbd_debug(1, "buffer chain changed, retrying\n"); | 777 | BUFFER_TRACE(partial->bh, "call brelse"); |
801 | BUFFER_TRACE(partial->bh, "brelsing"); | ||
802 | brelse(partial->bh); | 778 | brelse(partial->bh); |
803 | partial--; | 779 | partial--; |
804 | } | 780 | } |
805 | goto reread; | 781 | BUFFER_TRACE(bh_result, "returned"); |
782 | out: | ||
783 | return err; | ||
806 | } | 784 | } |
807 | 785 | ||
808 | static int ext3_get_block(struct inode *inode, sector_t iblock, | 786 | static int ext3_get_block(struct inode *inode, sector_t iblock, |