diff options
-rw-r--r-- | fs/ext2/inode.c | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index b43b95563663..acf678831103 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -590,9 +590,8 @@ static int ext2_get_blocks(struct inode *inode, | |||
590 | 590 | ||
591 | if (depth == 0) | 591 | if (depth == 0) |
592 | return (err); | 592 | return (err); |
593 | reread: | ||
594 | partial = ext2_get_branch(inode, depth, offsets, chain, &err); | ||
595 | 593 | ||
594 | partial = ext2_get_branch(inode, depth, offsets, chain, &err); | ||
596 | /* Simplest case - block found, no allocation needed */ | 595 | /* Simplest case - block found, no allocation needed */ |
597 | if (!partial) { | 596 | if (!partial) { |
598 | first_block = le32_to_cpu(chain[depth - 1].key); | 597 | first_block = le32_to_cpu(chain[depth - 1].key); |
@@ -602,15 +601,16 @@ reread: | |||
602 | while (count < maxblocks && count <= blocks_to_boundary) { | 601 | while (count < maxblocks && count <= blocks_to_boundary) { |
603 | ext2_fsblk_t blk; | 602 | ext2_fsblk_t blk; |
604 | 603 | ||
605 | if (!verify_chain(chain, partial)) { | 604 | if (!verify_chain(chain, chain + depth - 1)) { |
606 | /* | 605 | /* |
607 | * Indirect block might be removed by | 606 | * Indirect block might be removed by |
608 | * truncate while we were reading it. | 607 | * truncate while we were reading it. |
609 | * Handling of that case: forget what we've | 608 | * Handling of that case: forget what we've |
610 | * got now, go to reread. | 609 | * got now, go to reread. |
611 | */ | 610 | */ |
611 | err = -EAGAIN; | ||
612 | count = 0; | 612 | count = 0; |
613 | goto changed; | 613 | break; |
614 | } | 614 | } |
615 | blk = le32_to_cpu(*(chain[depth-1].p + count)); | 615 | blk = le32_to_cpu(*(chain[depth-1].p + count)); |
616 | if (blk == first_block + count) | 616 | if (blk == first_block + count) |
@@ -618,7 +618,8 @@ reread: | |||
618 | else | 618 | else |
619 | break; | 619 | break; |
620 | } | 620 | } |
621 | goto got_it; | 621 | if (err != -EAGAIN) |
622 | goto got_it; | ||
622 | } | 623 | } |
623 | 624 | ||
624 | /* Next simple case - plain lookup or failed read of indirect block */ | 625 | /* Next simple case - plain lookup or failed read of indirect block */ |
@@ -626,6 +627,33 @@ reread: | |||
626 | goto cleanup; | 627 | goto cleanup; |
627 | 628 | ||
628 | mutex_lock(&ei->truncate_mutex); | 629 | mutex_lock(&ei->truncate_mutex); |
630 | /* | ||
631 | * If the indirect block is missing while we are reading | ||
632 | * the chain(ext3_get_branch() returns -EAGAIN err), or | ||
633 | * if the chain has been changed after we grab the semaphore, | ||
634 | * (either because another process truncated this branch, or | ||
635 | * another get_block allocated this branch) re-grab the chain to see if | ||
636 | * the request block has been allocated or not. | ||
637 | * | ||
638 | * Since we already block the truncate/other get_block | ||
639 | * at this point, we will have the current copy of the chain when we | ||
640 | * splice the branch into the tree. | ||
641 | */ | ||
642 | if (err == -EAGAIN || !verify_chain(chain, partial)) { | ||
643 | while (partial > chain) { | ||
644 | brelse(partial->bh); | ||
645 | partial--; | ||
646 | } | ||
647 | partial = ext2_get_branch(inode, depth, offsets, chain, &err); | ||
648 | if (!partial) { | ||
649 | count++; | ||
650 | mutex_unlock(&ei->truncate_mutex); | ||
651 | if (err) | ||
652 | goto cleanup; | ||
653 | clear_buffer_new(bh_result); | ||
654 | goto got_it; | ||
655 | } | ||
656 | } | ||
629 | 657 | ||
630 | /* | 658 | /* |
631 | * Okay, we need to do block allocation. Lazily initialize the block | 659 | * Okay, we need to do block allocation. Lazily initialize the block |
@@ -683,12 +711,6 @@ cleanup: | |||
683 | partial--; | 711 | partial--; |
684 | } | 712 | } |
685 | return err; | 713 | return err; |
686 | changed: | ||
687 | while (partial > chain) { | ||
688 | brelse(partial->bh); | ||
689 | partial--; | ||
690 | } | ||
691 | goto reread; | ||
692 | } | 714 | } |
693 | 715 | ||
694 | int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) | 716 | int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) |