diff options
Diffstat (limited to 'fs/ext4/extents.c')
| -rw-r--r-- | fs/ext4/extents.c | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 47929c4e3dae..42c4c0c892ed 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -92,17 +92,16 @@ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb) | |||
| 92 | ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); | 92 | ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed) | 95 | static int ext4_ext_journal_restart(handle_t *handle, int needed) |
| 96 | { | 96 | { |
| 97 | int err; | 97 | int err; |
| 98 | 98 | ||
| 99 | if (handle->h_buffer_credits > needed) | 99 | if (handle->h_buffer_credits > needed) |
| 100 | return handle; | 100 | return 0; |
| 101 | if (!ext4_journal_extend(handle, needed)) | 101 | err = ext4_journal_extend(handle, needed); |
| 102 | return handle; | 102 | if (err) |
| 103 | err = ext4_journal_restart(handle, needed); | 103 | return err; |
| 104 | 104 | return ext4_journal_restart(handle, needed); | |
| 105 | return handle; | ||
| 106 | } | 105 | } |
| 107 | 106 | ||
| 108 | /* | 107 | /* |
| @@ -180,15 +179,18 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, | |||
| 180 | return bg_start + colour + block; | 179 | return bg_start + colour + block; |
| 181 | } | 180 | } |
| 182 | 181 | ||
| 182 | /* | ||
| 183 | * Allocation for a meta data block | ||
| 184 | */ | ||
| 183 | static ext4_fsblk_t | 185 | static ext4_fsblk_t |
| 184 | ext4_ext_new_block(handle_t *handle, struct inode *inode, | 186 | ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, |
| 185 | struct ext4_ext_path *path, | 187 | struct ext4_ext_path *path, |
| 186 | struct ext4_extent *ex, int *err) | 188 | struct ext4_extent *ex, int *err) |
| 187 | { | 189 | { |
| 188 | ext4_fsblk_t goal, newblock; | 190 | ext4_fsblk_t goal, newblock; |
| 189 | 191 | ||
| 190 | goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); | 192 | goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); |
| 191 | newblock = ext4_new_block(handle, inode, goal, err); | 193 | newblock = ext4_new_meta_block(handle, inode, goal, err); |
| 192 | return newblock; | 194 | return newblock; |
| 193 | } | 195 | } |
| 194 | 196 | ||
| @@ -246,6 +248,36 @@ static int ext4_ext_space_root_idx(struct inode *inode) | |||
| 246 | return size; | 248 | return size; |
| 247 | } | 249 | } |
| 248 | 250 | ||
| 251 | /* | ||
| 252 | * Calculate the number of metadata blocks needed | ||
| 253 | * to allocate @blocks | ||
| 254 | * Worse case is one block per extent | ||
| 255 | */ | ||
| 256 | int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 257 | { | ||
| 258 | int lcap, icap, rcap, leafs, idxs, num; | ||
| 259 | int newextents = blocks; | ||
| 260 | |||
| 261 | rcap = ext4_ext_space_root_idx(inode); | ||
| 262 | lcap = ext4_ext_space_block(inode); | ||
| 263 | icap = ext4_ext_space_block_idx(inode); | ||
| 264 | |||
| 265 | /* number of new leaf blocks needed */ | ||
| 266 | num = leafs = (newextents + lcap - 1) / lcap; | ||
| 267 | |||
| 268 | /* | ||
| 269 | * Worse case, we need separate index block(s) | ||
| 270 | * to link all new leaf blocks | ||
| 271 | */ | ||
| 272 | idxs = (leafs + icap - 1) / icap; | ||
| 273 | do { | ||
| 274 | num += idxs; | ||
| 275 | idxs = (idxs + icap - 1) / icap; | ||
| 276 | } while (idxs > rcap); | ||
| 277 | |||
| 278 | return num; | ||
| 279 | } | ||
| 280 | |||
| 249 | static int | 281 | static int |
| 250 | ext4_ext_max_entries(struct inode *inode, int depth) | 282 | ext4_ext_max_entries(struct inode *inode, int depth) |
| 251 | { | 283 | { |
| @@ -524,6 +556,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
| 524 | alloc = 1; | 556 | alloc = 1; |
| 525 | } | 557 | } |
| 526 | path[0].p_hdr = eh; | 558 | path[0].p_hdr = eh; |
| 559 | path[0].p_bh = NULL; | ||
| 527 | 560 | ||
| 528 | i = depth; | 561 | i = depth; |
| 529 | /* walk through the tree */ | 562 | /* walk through the tree */ |
| @@ -552,12 +585,14 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
| 552 | } | 585 | } |
| 553 | 586 | ||
| 554 | path[ppos].p_depth = i; | 587 | path[ppos].p_depth = i; |
| 555 | path[ppos].p_hdr = eh; | ||
| 556 | path[ppos].p_ext = NULL; | 588 | path[ppos].p_ext = NULL; |
| 557 | path[ppos].p_idx = NULL; | 589 | path[ppos].p_idx = NULL; |
| 558 | 590 | ||
| 559 | /* find extent */ | 591 | /* find extent */ |
| 560 | ext4_ext_binsearch(inode, path + ppos, block); | 592 | ext4_ext_binsearch(inode, path + ppos, block); |
| 593 | /* if not an empty leaf */ | ||
| 594 | if (path[ppos].p_ext) | ||
| 595 | path[ppos].p_block = ext_pblock(path[ppos].p_ext); | ||
| 561 | 596 | ||
| 562 | ext4_ext_show_path(inode, path); | 597 | ext4_ext_show_path(inode, path); |
| 563 | 598 | ||
| @@ -688,7 +723,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
| 688 | /* allocate all needed blocks */ | 723 | /* allocate all needed blocks */ |
| 689 | ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); | 724 | ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); |
| 690 | for (a = 0; a < depth - at; a++) { | 725 | for (a = 0; a < depth - at; a++) { |
| 691 | newblock = ext4_ext_new_block(handle, inode, path, newext, &err); | 726 | newblock = ext4_ext_new_meta_block(handle, inode, path, |
| 727 | newext, &err); | ||
| 692 | if (newblock == 0) | 728 | if (newblock == 0) |
| 693 | goto cleanup; | 729 | goto cleanup; |
| 694 | ablocks[a] = newblock; | 730 | ablocks[a] = newblock; |
| @@ -884,7 +920,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, | |||
| 884 | ext4_fsblk_t newblock; | 920 | ext4_fsblk_t newblock; |
| 885 | int err = 0; | 921 | int err = 0; |
| 886 | 922 | ||
| 887 | newblock = ext4_ext_new_block(handle, inode, path, newext, &err); | 923 | newblock = ext4_ext_new_meta_block(handle, inode, path, newext, &err); |
| 888 | if (newblock == 0) | 924 | if (newblock == 0) |
| 889 | return err; | 925 | return err; |
| 890 | 926 | ||
| @@ -981,6 +1017,8 @@ repeat: | |||
| 981 | /* if we found index with free entry, then use that | 1017 | /* if we found index with free entry, then use that |
| 982 | * entry: create all needed subtree and add new leaf */ | 1018 | * entry: create all needed subtree and add new leaf */ |
| 983 | err = ext4_ext_split(handle, inode, path, newext, i); | 1019 | err = ext4_ext_split(handle, inode, path, newext, i); |
| 1020 | if (err) | ||
| 1021 | goto out; | ||
| 984 | 1022 | ||
| 985 | /* refill path */ | 1023 | /* refill path */ |
| 986 | ext4_ext_drop_refs(path); | 1024 | ext4_ext_drop_refs(path); |
| @@ -1883,11 +1921,9 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
| 1883 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | 1921 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); |
| 1884 | #endif | 1922 | #endif |
| 1885 | 1923 | ||
| 1886 | handle = ext4_ext_journal_restart(handle, credits); | 1924 | err = ext4_ext_journal_restart(handle, credits); |
| 1887 | if (IS_ERR(handle)) { | 1925 | if (err) |
| 1888 | err = PTR_ERR(handle); | ||
| 1889 | goto out; | 1926 | goto out; |
| 1890 | } | ||
| 1891 | 1927 | ||
| 1892 | err = ext4_ext_get_access(handle, inode, path + depth); | 1928 | err = ext4_ext_get_access(handle, inode, path + depth); |
| 1893 | if (err) | 1929 | if (err) |
| @@ -2529,6 +2565,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 2529 | int err = 0, depth, ret; | 2565 | int err = 0, depth, ret; |
| 2530 | unsigned long allocated = 0; | 2566 | unsigned long allocated = 0; |
| 2531 | struct ext4_allocation_request ar; | 2567 | struct ext4_allocation_request ar; |
| 2568 | loff_t disksize; | ||
| 2532 | 2569 | ||
| 2533 | __clear_bit(BH_New, &bh_result->b_state); | 2570 | __clear_bit(BH_New, &bh_result->b_state); |
| 2534 | ext_debug("blocks %u/%lu requested for inode %u\n", | 2571 | ext_debug("blocks %u/%lu requested for inode %u\n", |
| @@ -2616,8 +2653,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 2616 | */ | 2653 | */ |
| 2617 | if (allocated > max_blocks) | 2654 | if (allocated > max_blocks) |
| 2618 | allocated = max_blocks; | 2655 | allocated = max_blocks; |
| 2619 | /* mark the buffer unwritten */ | 2656 | set_buffer_unwritten(bh_result); |
| 2620 | __set_bit(BH_Unwritten, &bh_result->b_state); | ||
| 2621 | goto out2; | 2657 | goto out2; |
| 2622 | } | 2658 | } |
| 2623 | 2659 | ||
| @@ -2716,14 +2752,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 2716 | goto out2; | 2752 | goto out2; |
| 2717 | } | 2753 | } |
| 2718 | 2754 | ||
| 2719 | if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize) | ||
| 2720 | EXT4_I(inode)->i_disksize = inode->i_size; | ||
| 2721 | |||
| 2722 | /* previous routine could use block we allocated */ | 2755 | /* previous routine could use block we allocated */ |
| 2723 | newblock = ext_pblock(&newex); | 2756 | newblock = ext_pblock(&newex); |
| 2724 | allocated = ext4_ext_get_actual_len(&newex); | 2757 | allocated = ext4_ext_get_actual_len(&newex); |
| 2725 | outnew: | 2758 | outnew: |
| 2726 | __set_bit(BH_New, &bh_result->b_state); | 2759 | if (extend_disksize) { |
| 2760 | disksize = ((loff_t) iblock + ar.len) << inode->i_blkbits; | ||
| 2761 | if (disksize > i_size_read(inode)) | ||
| 2762 | disksize = i_size_read(inode); | ||
| 2763 | if (disksize > EXT4_I(inode)->i_disksize) | ||
| 2764 | EXT4_I(inode)->i_disksize = disksize; | ||
| 2765 | } | ||
| 2766 | |||
| 2767 | set_buffer_new(bh_result); | ||
| 2727 | 2768 | ||
| 2728 | /* Cache only when it is _not_ an uninitialized extent */ | 2769 | /* Cache only when it is _not_ an uninitialized extent */ |
| 2729 | if (create != EXT4_CREATE_UNINITIALIZED_EXT) | 2770 | if (create != EXT4_CREATE_UNINITIALIZED_EXT) |
| @@ -2733,7 +2774,7 @@ out: | |||
| 2733 | if (allocated > max_blocks) | 2774 | if (allocated > max_blocks) |
| 2734 | allocated = max_blocks; | 2775 | allocated = max_blocks; |
| 2735 | ext4_ext_show_leaf(inode, path); | 2776 | ext4_ext_show_leaf(inode, path); |
| 2736 | __set_bit(BH_Mapped, &bh_result->b_state); | 2777 | set_buffer_mapped(bh_result); |
| 2737 | bh_result->b_bdev = inode->i_sb->s_bdev; | 2778 | bh_result->b_bdev = inode->i_sb->s_bdev; |
| 2738 | bh_result->b_blocknr = newblock; | 2779 | bh_result->b_blocknr = newblock; |
| 2739 | out2: | 2780 | out2: |
| @@ -2744,7 +2785,7 @@ out2: | |||
| 2744 | return err ? err : allocated; | 2785 | return err ? err : allocated; |
| 2745 | } | 2786 | } |
| 2746 | 2787 | ||
| 2747 | void ext4_ext_truncate(struct inode * inode, struct page *page) | 2788 | void ext4_ext_truncate(struct inode *inode) |
| 2748 | { | 2789 | { |
| 2749 | struct address_space *mapping = inode->i_mapping; | 2790 | struct address_space *mapping = inode->i_mapping; |
| 2750 | struct super_block *sb = inode->i_sb; | 2791 | struct super_block *sb = inode->i_sb; |
| @@ -2757,18 +2798,14 @@ void ext4_ext_truncate(struct inode * inode, struct page *page) | |||
| 2757 | */ | 2798 | */ |
| 2758 | err = ext4_writepage_trans_blocks(inode) + 3; | 2799 | err = ext4_writepage_trans_blocks(inode) + 3; |
| 2759 | handle = ext4_journal_start(inode, err); | 2800 | handle = ext4_journal_start(inode, err); |
| 2760 | if (IS_ERR(handle)) { | 2801 | if (IS_ERR(handle)) |
| 2761 | if (page) { | ||
| 2762 | clear_highpage(page); | ||
| 2763 | flush_dcache_page(page); | ||
| 2764 | unlock_page(page); | ||
| 2765 | page_cache_release(page); | ||
| 2766 | } | ||
| 2767 | return; | 2802 | return; |
| 2768 | } | ||
| 2769 | 2803 | ||
| 2770 | if (page) | 2804 | if (inode->i_size & (sb->s_blocksize - 1)) |
| 2771 | ext4_block_truncate_page(handle, page, mapping, inode->i_size); | 2805 | ext4_block_truncate_page(handle, mapping, inode->i_size); |
| 2806 | |||
| 2807 | if (ext4_orphan_add(handle, inode)) | ||
| 2808 | goto out_stop; | ||
| 2772 | 2809 | ||
| 2773 | down_write(&EXT4_I(inode)->i_data_sem); | 2810 | down_write(&EXT4_I(inode)->i_data_sem); |
| 2774 | ext4_ext_invalidate_cache(inode); | 2811 | ext4_ext_invalidate_cache(inode); |
| @@ -2780,8 +2817,6 @@ void ext4_ext_truncate(struct inode * inode, struct page *page) | |||
| 2780 | * Probably we need not scan at all, | 2817 | * Probably we need not scan at all, |
| 2781 | * because page truncation is enough. | 2818 | * because page truncation is enough. |
| 2782 | */ | 2819 | */ |
| 2783 | if (ext4_orphan_add(handle, inode)) | ||
| 2784 | goto out_stop; | ||
| 2785 | 2820 | ||
| 2786 | /* we have to know where to truncate from in crash case */ | 2821 | /* we have to know where to truncate from in crash case */ |
| 2787 | EXT4_I(inode)->i_disksize = inode->i_size; | 2822 | EXT4_I(inode)->i_disksize = inode->i_size; |
| @@ -2798,6 +2833,7 @@ void ext4_ext_truncate(struct inode * inode, struct page *page) | |||
| 2798 | handle->h_sync = 1; | 2833 | handle->h_sync = 1; |
| 2799 | 2834 | ||
| 2800 | out_stop: | 2835 | out_stop: |
| 2836 | up_write(&EXT4_I(inode)->i_data_sem); | ||
| 2801 | /* | 2837 | /* |
| 2802 | * If this was a simple ftruncate() and the file will remain alive, | 2838 | * If this was a simple ftruncate() and the file will remain alive, |
| 2803 | * then we need to clear up the orphan record which we created above. | 2839 | * then we need to clear up the orphan record which we created above. |
| @@ -2808,7 +2844,6 @@ out_stop: | |||
| 2808 | if (inode->i_nlink) | 2844 | if (inode->i_nlink) |
| 2809 | ext4_orphan_del(handle, inode); | 2845 | ext4_orphan_del(handle, inode); |
| 2810 | 2846 | ||
| 2811 | up_write(&EXT4_I(inode)->i_data_sem); | ||
| 2812 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | 2847 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); |
| 2813 | ext4_mark_inode_dirty(handle, inode); | 2848 | ext4_mark_inode_dirty(handle, inode); |
| 2814 | ext4_journal_stop(handle); | 2849 | ext4_journal_stop(handle); |
| @@ -2911,7 +2946,7 @@ retry: | |||
| 2911 | } | 2946 | } |
| 2912 | ret = ext4_get_blocks_wrap(handle, inode, block, | 2947 | ret = ext4_get_blocks_wrap(handle, inode, block, |
| 2913 | max_blocks, &map_bh, | 2948 | max_blocks, &map_bh, |
| 2914 | EXT4_CREATE_UNINITIALIZED_EXT, 0); | 2949 | EXT4_CREATE_UNINITIALIZED_EXT, 0, 0); |
| 2915 | if (ret <= 0) { | 2950 | if (ret <= 0) { |
| 2916 | #ifdef EXT4FS_DEBUG | 2951 | #ifdef EXT4FS_DEBUG |
| 2917 | WARN_ON(ret <= 0); | 2952 | WARN_ON(ret <= 0); |
