diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 11:36:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 11:36:38 -0400 |
commit | 8d2567a620ae8c24968a2bdc1c906c724fac1f6a (patch) | |
tree | 8e228abbadbe760e3f015d30c2e1180a67eeb8f9 /fs/ext4/extents.c | |
parent | bcf559e385ba099996c90469c817d2eb38aba418 (diff) | |
parent | 49f1487b2e41bd8439ea39a4f15b4064e823cc54 (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (61 commits)
ext4: Documention update for new ordered mode and delayed allocation
ext4: do not set extents feature from the kernel
ext4: Don't allow nonextenst mount option for large filesystem
ext4: Enable delalloc by default.
ext4: delayed allocation i_blocks fix for stat
ext4: fix delalloc i_disksize early update issue
ext4: Handle page without buffers in ext4_*_writepage()
ext4: Add ordered mode support for delalloc
ext4: Invert lock ordering of page_lock and transaction start in delalloc
mm: Add range_cont mode for writeback
ext4: delayed allocation ENOSPC handling
percpu_counter: new function percpu_counter_sum_and_set
ext4: Add delayed allocation support in data=writeback mode
vfs: add hooks for ext4's delayed allocation support
jbd2: Remove data=ordered mode support using jbd buffer heads
ext4: Use new framework for data=ordered mode in JBD2
jbd2: Implement data=ordered mode handling via inodes
vfs: export filemap_fdatawrite_range()
ext4: Fix lock inversion in ext4_ext_truncate()
ext4: Invert the locking order of page_lock and transaction start
...
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); |