diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7cce96a6935e..bc950562b5ba 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -508,11 +508,12 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned long blks, | |||
508 | * direct blocks | 508 | * direct blocks |
509 | */ | 509 | */ |
510 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | 510 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, |
511 | ext4_fsblk_t goal, int indirect_blks, int blks, | 511 | ext4_lblk_t iblock, ext4_fsblk_t goal, |
512 | ext4_fsblk_t new_blocks[4], int *err) | 512 | int indirect_blks, int blks, |
513 | ext4_fsblk_t new_blocks[4], int *err) | ||
513 | { | 514 | { |
514 | int target, i; | 515 | int target, i; |
515 | unsigned long count = 0; | 516 | unsigned long count = 0, blk_allocated = 0; |
516 | int index = 0; | 517 | int index = 0; |
517 | ext4_fsblk_t current_block = 0; | 518 | ext4_fsblk_t current_block = 0; |
518 | int ret = 0; | 519 | int ret = 0; |
@@ -525,12 +526,13 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
525 | * the first direct block of this branch. That's the | 526 | * the first direct block of this branch. That's the |
526 | * minimum number of blocks need to allocate(required) | 527 | * minimum number of blocks need to allocate(required) |
527 | */ | 528 | */ |
528 | target = blks + indirect_blks; | 529 | /* first we try to allocate the indirect blocks */ |
529 | 530 | target = indirect_blks; | |
530 | while (1) { | 531 | while (target > 0) { |
531 | count = target; | 532 | count = target; |
532 | /* allocating blocks for indirect blocks and direct blocks */ | 533 | /* allocating blocks for indirect blocks and direct blocks */ |
533 | current_block = ext4_new_blocks(handle,inode,goal,&count,err); | 534 | current_block = ext4_new_meta_blocks(handle, inode, |
535 | goal, &count, err); | ||
534 | if (*err) | 536 | if (*err) |
535 | goto failed_out; | 537 | goto failed_out; |
536 | 538 | ||
@@ -540,16 +542,48 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
540 | new_blocks[index++] = current_block++; | 542 | new_blocks[index++] = current_block++; |
541 | count--; | 543 | count--; |
542 | } | 544 | } |
543 | 545 | if (count > 0) { | |
544 | if (count > 0) | 546 | /* |
547 | * save the new block number | ||
548 | * for the first direct block | ||
549 | */ | ||
550 | new_blocks[index] = current_block; | ||
551 | printk(KERN_INFO "%s returned more blocks than " | ||
552 | "requested\n", __func__); | ||
553 | WARN_ON(1); | ||
545 | break; | 554 | break; |
555 | } | ||
546 | } | 556 | } |
547 | 557 | ||
548 | /* save the new block number for the first direct block */ | 558 | target = blks - count ; |
549 | new_blocks[index] = current_block; | 559 | blk_allocated = count; |
550 | 560 | if (!target) | |
561 | goto allocated; | ||
562 | /* Now allocate data blocks */ | ||
563 | count = target; | ||
564 | /* allocating blocks for indirect blocks and direct blocks */ | ||
565 | current_block = ext4_new_blocks(handle, inode, iblock, | ||
566 | goal, &count, err); | ||
567 | if (*err && (target == blks)) { | ||
568 | /* | ||
569 | * if the allocation failed and we didn't allocate | ||
570 | * any blocks before | ||
571 | */ | ||
572 | goto failed_out; | ||
573 | } | ||
574 | if (!*err) { | ||
575 | if (target == blks) { | ||
576 | /* | ||
577 | * save the new block number | ||
578 | * for the first direct block | ||
579 | */ | ||
580 | new_blocks[index] = current_block; | ||
581 | } | ||
582 | blk_allocated += count; | ||
583 | } | ||
584 | allocated: | ||
551 | /* total number of blocks allocated for direct blocks */ | 585 | /* total number of blocks allocated for direct blocks */ |
552 | ret = count; | 586 | ret = blk_allocated; |
553 | *err = 0; | 587 | *err = 0; |
554 | return ret; | 588 | return ret; |
555 | failed_out: | 589 | failed_out: |
@@ -584,8 +618,9 @@ failed_out: | |||
584 | * as described above and return 0. | 618 | * as described above and return 0. |
585 | */ | 619 | */ |
586 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | 620 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, |
587 | int indirect_blks, int *blks, ext4_fsblk_t goal, | 621 | ext4_lblk_t iblock, int indirect_blks, |
588 | ext4_lblk_t *offsets, Indirect *branch) | 622 | int *blks, ext4_fsblk_t goal, |
623 | ext4_lblk_t *offsets, Indirect *branch) | ||
589 | { | 624 | { |
590 | int blocksize = inode->i_sb->s_blocksize; | 625 | int blocksize = inode->i_sb->s_blocksize; |
591 | int i, n = 0; | 626 | int i, n = 0; |
@@ -595,7 +630,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
595 | ext4_fsblk_t new_blocks[4]; | 630 | ext4_fsblk_t new_blocks[4]; |
596 | ext4_fsblk_t current_block; | 631 | ext4_fsblk_t current_block; |
597 | 632 | ||
598 | num = ext4_alloc_blocks(handle, inode, goal, indirect_blks, | 633 | num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks, |
599 | *blks, new_blocks, &err); | 634 | *blks, new_blocks, &err); |
600 | if (err) | 635 | if (err) |
601 | return err; | 636 | return err; |
@@ -855,8 +890,9 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, | |||
855 | /* | 890 | /* |
856 | * Block out ext4_truncate while we alter the tree | 891 | * Block out ext4_truncate while we alter the tree |
857 | */ | 892 | */ |
858 | err = ext4_alloc_branch(handle, inode, indirect_blks, &count, goal, | 893 | err = ext4_alloc_branch(handle, inode, iblock, indirect_blks, |
859 | offsets + (partial - chain), partial); | 894 | &count, goal, |
895 | offsets + (partial - chain), partial); | ||
860 | 896 | ||
861 | /* | 897 | /* |
862 | * The ext4_splice_branch call will free and forget any buffers | 898 | * The ext4_splice_branch call will free and forget any buffers |