diff options
author | Zheng Liu <wenqing.lz@taobao.com> | 2013-02-18 00:31:07 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-02-18 00:31:07 -0500 |
commit | 69eb33dc24dc44d1128aa5e82d0976c42b440c1a (patch) | |
tree | a20982f1fb23b94fe08e6034faea33ed81e4626f /fs/ext4/extents.c | |
parent | d100eef2440fea13e4f09e88b1c8bcbca64beb9f (diff) |
ext4: remove single extent cache
Single extent cache could be removed because we have extent status tree
as a extent cache, and it would be better.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: Jan kara <jack@suse.cz>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 179 |
1 files changed, 38 insertions, 141 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index b9d7a2363736..372b2cbee07e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -112,7 +112,7 @@ static int ext4_split_extent_at(handle_t *handle, | |||
112 | int flags); | 112 | int flags); |
113 | 113 | ||
114 | static int ext4_find_delayed_extent(struct inode *inode, | 114 | static int ext4_find_delayed_extent(struct inode *inode, |
115 | struct ext4_ext_cache *newex); | 115 | struct extent_status *newes); |
116 | 116 | ||
117 | static int ext4_ext_truncate_extend_restart(handle_t *handle, | 117 | static int ext4_ext_truncate_extend_restart(handle_t *handle, |
118 | struct inode *inode, | 118 | struct inode *inode, |
@@ -714,7 +714,6 @@ int ext4_ext_tree_init(handle_t *handle, struct inode *inode) | |||
714 | eh->eh_magic = EXT4_EXT_MAGIC; | 714 | eh->eh_magic = EXT4_EXT_MAGIC; |
715 | eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); | 715 | eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); |
716 | ext4_mark_inode_dirty(handle, inode); | 716 | ext4_mark_inode_dirty(handle, inode); |
717 | ext4_ext_invalidate_cache(inode); | ||
718 | return 0; | 717 | return 0; |
719 | } | 718 | } |
720 | 719 | ||
@@ -1963,7 +1962,6 @@ cleanup: | |||
1963 | ext4_ext_drop_refs(npath); | 1962 | ext4_ext_drop_refs(npath); |
1964 | kfree(npath); | 1963 | kfree(npath); |
1965 | } | 1964 | } |
1966 | ext4_ext_invalidate_cache(inode); | ||
1967 | return err; | 1965 | return err; |
1968 | } | 1966 | } |
1969 | 1967 | ||
@@ -1972,8 +1970,8 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
1972 | struct fiemap_extent_info *fieinfo) | 1970 | struct fiemap_extent_info *fieinfo) |
1973 | { | 1971 | { |
1974 | struct ext4_ext_path *path = NULL; | 1972 | struct ext4_ext_path *path = NULL; |
1975 | struct ext4_ext_cache newex; | ||
1976 | struct ext4_extent *ex; | 1973 | struct ext4_extent *ex; |
1974 | struct extent_status es; | ||
1977 | ext4_lblk_t next, next_del, start = 0, end = 0; | 1975 | ext4_lblk_t next, next_del, start = 0, end = 0; |
1978 | ext4_lblk_t last = block + num; | 1976 | ext4_lblk_t last = block + num; |
1979 | int exists, depth = 0, err = 0; | 1977 | int exists, depth = 0, err = 0; |
@@ -2047,31 +2045,31 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
2047 | BUG_ON(end <= start); | 2045 | BUG_ON(end <= start); |
2048 | 2046 | ||
2049 | if (!exists) { | 2047 | if (!exists) { |
2050 | newex.ec_block = start; | 2048 | es.es_lblk = start; |
2051 | newex.ec_len = end - start; | 2049 | es.es_len = end - start; |
2052 | newex.ec_start = 0; | 2050 | es.es_pblk = 0; |
2053 | } else { | 2051 | } else { |
2054 | newex.ec_block = le32_to_cpu(ex->ee_block); | 2052 | es.es_lblk = le32_to_cpu(ex->ee_block); |
2055 | newex.ec_len = ext4_ext_get_actual_len(ex); | 2053 | es.es_len = ext4_ext_get_actual_len(ex); |
2056 | newex.ec_start = ext4_ext_pblock(ex); | 2054 | es.es_pblk = ext4_ext_pblock(ex); |
2057 | if (ext4_ext_is_uninitialized(ex)) | 2055 | if (ext4_ext_is_uninitialized(ex)) |
2058 | flags |= FIEMAP_EXTENT_UNWRITTEN; | 2056 | flags |= FIEMAP_EXTENT_UNWRITTEN; |
2059 | } | 2057 | } |
2060 | 2058 | ||
2061 | /* | 2059 | /* |
2062 | * Find delayed extent and update newex accordingly. We call | 2060 | * Find delayed extent and update es accordingly. We call |
2063 | * it even in !exists case to find out whether newex is the | 2061 | * it even in !exists case to find out whether es is the |
2064 | * last existing extent or not. | 2062 | * last existing extent or not. |
2065 | */ | 2063 | */ |
2066 | next_del = ext4_find_delayed_extent(inode, &newex); | 2064 | next_del = ext4_find_delayed_extent(inode, &es); |
2067 | if (!exists && next_del) { | 2065 | if (!exists && next_del) { |
2068 | exists = 1; | 2066 | exists = 1; |
2069 | flags |= FIEMAP_EXTENT_DELALLOC; | 2067 | flags |= FIEMAP_EXTENT_DELALLOC; |
2070 | } | 2068 | } |
2071 | up_read(&EXT4_I(inode)->i_data_sem); | 2069 | up_read(&EXT4_I(inode)->i_data_sem); |
2072 | 2070 | ||
2073 | if (unlikely(newex.ec_len == 0)) { | 2071 | if (unlikely(es.es_len == 0)) { |
2074 | EXT4_ERROR_INODE(inode, "newex.ec_len == 0"); | 2072 | EXT4_ERROR_INODE(inode, "es.es_len == 0"); |
2075 | err = -EIO; | 2073 | err = -EIO; |
2076 | break; | 2074 | break; |
2077 | } | 2075 | } |
@@ -2102,9 +2100,9 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
2102 | 2100 | ||
2103 | if (exists) { | 2101 | if (exists) { |
2104 | err = fiemap_fill_next_extent(fieinfo, | 2102 | err = fiemap_fill_next_extent(fieinfo, |
2105 | (__u64)newex.ec_block << blksize_bits, | 2103 | (__u64)es.es_lblk << blksize_bits, |
2106 | (__u64)newex.ec_start << blksize_bits, | 2104 | (__u64)es.es_pblk << blksize_bits, |
2107 | (__u64)newex.ec_len << blksize_bits, | 2105 | (__u64)es.es_len << blksize_bits, |
2108 | flags); | 2106 | flags); |
2109 | if (err < 0) | 2107 | if (err < 0) |
2110 | break; | 2108 | break; |
@@ -2114,7 +2112,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
2114 | } | 2112 | } |
2115 | } | 2113 | } |
2116 | 2114 | ||
2117 | block = newex.ec_block + newex.ec_len; | 2115 | block = es.es_lblk + es.es_len; |
2118 | } | 2116 | } |
2119 | 2117 | ||
2120 | if (path) { | 2118 | if (path) { |
@@ -2125,21 +2123,6 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
2125 | return err; | 2123 | return err; |
2126 | } | 2124 | } |
2127 | 2125 | ||
2128 | static void | ||
2129 | ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block, | ||
2130 | __u32 len, ext4_fsblk_t start) | ||
2131 | { | ||
2132 | struct ext4_ext_cache *cex; | ||
2133 | BUG_ON(len == 0); | ||
2134 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | ||
2135 | trace_ext4_ext_put_in_cache(inode, block, len, start); | ||
2136 | cex = &EXT4_I(inode)->i_cached_extent; | ||
2137 | cex->ec_block = block; | ||
2138 | cex->ec_len = len; | ||
2139 | cex->ec_start = start; | ||
2140 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | ||
2141 | } | ||
2142 | |||
2143 | /* | 2126 | /* |
2144 | * ext4_ext_put_gap_in_cache: | 2127 | * ext4_ext_put_gap_in_cache: |
2145 | * calculate boundaries of the gap that the requested block fits into | 2128 | * calculate boundaries of the gap that the requested block fits into |
@@ -2156,9 +2139,10 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, | |||
2156 | 2139 | ||
2157 | ex = path[depth].p_ext; | 2140 | ex = path[depth].p_ext; |
2158 | if (ex == NULL) { | 2141 | if (ex == NULL) { |
2159 | /* there is no extent yet, so gap is [0;-] */ | 2142 | /* |
2160 | lblock = 0; | 2143 | * there is no extent yet, so gap is [0;-] and we |
2161 | len = EXT_MAX_BLOCKS; | 2144 | * don't cache it |
2145 | */ | ||
2162 | ext_debug("cache gap(whole file):"); | 2146 | ext_debug("cache gap(whole file):"); |
2163 | } else if (block < le32_to_cpu(ex->ee_block)) { | 2147 | } else if (block < le32_to_cpu(ex->ee_block)) { |
2164 | lblock = block; | 2148 | lblock = block; |
@@ -2192,52 +2176,6 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, | |||
2192 | } | 2176 | } |
2193 | 2177 | ||
2194 | ext_debug(" -> %u:%lu\n", lblock, len); | 2178 | ext_debug(" -> %u:%lu\n", lblock, len); |
2195 | ext4_ext_put_in_cache(inode, lblock, len, 0); | ||
2196 | } | ||
2197 | |||
2198 | /* | ||
2199 | * ext4_ext_in_cache() | ||
2200 | * Checks to see if the given block is in the cache. | ||
2201 | * If it is, the cached extent is stored in the given | ||
2202 | * cache extent pointer. | ||
2203 | * | ||
2204 | * @inode: The files inode | ||
2205 | * @block: The block to look for in the cache | ||
2206 | * @ex: Pointer where the cached extent will be stored | ||
2207 | * if it contains block | ||
2208 | * | ||
2209 | * Return 0 if cache is invalid; 1 if the cache is valid | ||
2210 | */ | ||
2211 | static int | ||
2212 | ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, | ||
2213 | struct ext4_extent *ex) | ||
2214 | { | ||
2215 | struct ext4_ext_cache *cex; | ||
2216 | int ret = 0; | ||
2217 | |||
2218 | /* | ||
2219 | * We borrow i_block_reservation_lock to protect i_cached_extent | ||
2220 | */ | ||
2221 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | ||
2222 | cex = &EXT4_I(inode)->i_cached_extent; | ||
2223 | |||
2224 | /* has cache valid data? */ | ||
2225 | if (cex->ec_len == 0) | ||
2226 | goto errout; | ||
2227 | |||
2228 | if (in_range(block, cex->ec_block, cex->ec_len)) { | ||
2229 | ex->ee_block = cpu_to_le32(cex->ec_block); | ||
2230 | ext4_ext_store_pblock(ex, cex->ec_start); | ||
2231 | ex->ee_len = cpu_to_le16(cex->ec_len); | ||
2232 | ext_debug("%u cached by %u:%u:%llu\n", | ||
2233 | block, | ||
2234 | cex->ec_block, cex->ec_len, cex->ec_start); | ||
2235 | ret = 1; | ||
2236 | } | ||
2237 | errout: | ||
2238 | trace_ext4_ext_in_cache(inode, block, ret); | ||
2239 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | ||
2240 | return ret; | ||
2241 | } | 2179 | } |
2242 | 2180 | ||
2243 | /* | 2181 | /* |
@@ -2677,8 +2615,6 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, | |||
2677 | return PTR_ERR(handle); | 2615 | return PTR_ERR(handle); |
2678 | 2616 | ||
2679 | again: | 2617 | again: |
2680 | ext4_ext_invalidate_cache(inode); | ||
2681 | |||
2682 | trace_ext4_ext_remove_space(inode, start, depth); | 2618 | trace_ext4_ext_remove_space(inode, start, depth); |
2683 | 2619 | ||
2684 | /* | 2620 | /* |
@@ -3920,35 +3856,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3920 | map->m_lblk, map->m_len, inode->i_ino); | 3856 | map->m_lblk, map->m_len, inode->i_ino); |
3921 | trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); | 3857 | trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); |
3922 | 3858 | ||
3923 | /* check in cache */ | ||
3924 | if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) { | ||
3925 | if (!newex.ee_start_lo && !newex.ee_start_hi) { | ||
3926 | if ((sbi->s_cluster_ratio > 1) && | ||
3927 | ext4_find_delalloc_cluster(inode, map->m_lblk)) | ||
3928 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; | ||
3929 | |||
3930 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { | ||
3931 | /* | ||
3932 | * block isn't allocated yet and | ||
3933 | * user doesn't want to allocate it | ||
3934 | */ | ||
3935 | goto out2; | ||
3936 | } | ||
3937 | /* we should allocate requested block */ | ||
3938 | } else { | ||
3939 | /* block is already allocated */ | ||
3940 | if (sbi->s_cluster_ratio > 1) | ||
3941 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; | ||
3942 | newblock = map->m_lblk | ||
3943 | - le32_to_cpu(newex.ee_block) | ||
3944 | + ext4_ext_pblock(&newex); | ||
3945 | /* number of remaining blocks in the extent */ | ||
3946 | allocated = ext4_ext_get_actual_len(&newex) - | ||
3947 | (map->m_lblk - le32_to_cpu(newex.ee_block)); | ||
3948 | goto out; | ||
3949 | } | ||
3950 | } | ||
3951 | |||
3952 | /* find extent for this block */ | 3859 | /* find extent for this block */ |
3953 | path = ext4_ext_find_extent(inode, map->m_lblk, NULL); | 3860 | path = ext4_ext_find_extent(inode, map->m_lblk, NULL); |
3954 | if (IS_ERR(path)) { | 3861 | if (IS_ERR(path)) { |
@@ -3995,15 +3902,9 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3995 | ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk, | 3902 | ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk, |
3996 | ee_block, ee_len, newblock); | 3903 | ee_block, ee_len, newblock); |
3997 | 3904 | ||
3998 | /* | 3905 | if (!ext4_ext_is_uninitialized(ex)) |
3999 | * Do not put uninitialized extent | ||
4000 | * in the cache | ||
4001 | */ | ||
4002 | if (!ext4_ext_is_uninitialized(ex)) { | ||
4003 | ext4_ext_put_in_cache(inode, ee_block, | ||
4004 | ee_len, ee_start); | ||
4005 | goto out; | 3906 | goto out; |
4006 | } | 3907 | |
4007 | allocated = ext4_ext_handle_uninitialized_extents( | 3908 | allocated = ext4_ext_handle_uninitialized_extents( |
4008 | handle, inode, map, path, flags, | 3909 | handle, inode, map, path, flags, |
4009 | allocated, newblock); | 3910 | allocated, newblock); |
@@ -4265,10 +4166,9 @@ got_allocated_blocks: | |||
4265 | * Cache the extent and update transaction to commit on fdatasync only | 4166 | * Cache the extent and update transaction to commit on fdatasync only |
4266 | * when it is _not_ an uninitialized extent. | 4167 | * when it is _not_ an uninitialized extent. |
4267 | */ | 4168 | */ |
4268 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) { | 4169 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) |
4269 | ext4_ext_put_in_cache(inode, map->m_lblk, allocated, newblock); | ||
4270 | ext4_update_inode_fsync_trans(handle, inode, 1); | 4170 | ext4_update_inode_fsync_trans(handle, inode, 1); |
4271 | } else | 4171 | else |
4272 | ext4_update_inode_fsync_trans(handle, inode, 0); | 4172 | ext4_update_inode_fsync_trans(handle, inode, 0); |
4273 | out: | 4173 | out: |
4274 | if (allocated > map->m_len) | 4174 | if (allocated > map->m_len) |
@@ -4327,7 +4227,6 @@ void ext4_ext_truncate(struct inode *inode) | |||
4327 | goto out_stop; | 4227 | goto out_stop; |
4328 | 4228 | ||
4329 | down_write(&EXT4_I(inode)->i_data_sem); | 4229 | down_write(&EXT4_I(inode)->i_data_sem); |
4330 | ext4_ext_invalidate_cache(inode); | ||
4331 | 4230 | ||
4332 | ext4_discard_preallocations(inode); | 4231 | ext4_discard_preallocations(inode); |
4333 | 4232 | ||
@@ -4576,42 +4475,42 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset, | |||
4576 | } | 4475 | } |
4577 | 4476 | ||
4578 | /* | 4477 | /* |
4579 | * If newex is not existing extent (newex->ec_start equals zero) find | 4478 | * If newes is not existing extent (newes->ec_pblk equals zero) find |
4580 | * delayed extent at start of newex and update newex accordingly and | 4479 | * delayed extent at start of newes and update newes accordingly and |
4581 | * return start of the next delayed extent. | 4480 | * return start of the next delayed extent. |
4582 | * | 4481 | * |
4583 | * If newex is existing extent (newex->ec_start is not equal zero) | 4482 | * If newes is existing extent (newes->ec_pblk is not equal zero) |
4584 | * return start of next delayed extent or EXT_MAX_BLOCKS if no delayed | 4483 | * return start of next delayed extent or EXT_MAX_BLOCKS if no delayed |
4585 | * extent found. Leave newex unmodified. | 4484 | * extent found. Leave newes unmodified. |
4586 | */ | 4485 | */ |
4587 | static int ext4_find_delayed_extent(struct inode *inode, | 4486 | static int ext4_find_delayed_extent(struct inode *inode, |
4588 | struct ext4_ext_cache *newex) | 4487 | struct extent_status *newes) |
4589 | { | 4488 | { |
4590 | struct extent_status es; | 4489 | struct extent_status es; |
4591 | ext4_lblk_t block, next_del; | 4490 | ext4_lblk_t block, next_del; |
4592 | 4491 | ||
4593 | ext4_es_find_delayed_extent(inode, newex->ec_block, &es); | 4492 | ext4_es_find_delayed_extent(inode, newes->es_lblk, &es); |
4594 | 4493 | ||
4595 | if (newex->ec_start == 0) { | 4494 | if (newes->es_pblk == 0) { |
4596 | /* | 4495 | /* |
4597 | * No extent in extent-tree contains block @newex->ec_start, | 4496 | * No extent in extent-tree contains block @newes->es_pblk, |
4598 | * then the block may stay in 1)a hole or 2)delayed-extent. | 4497 | * then the block may stay in 1)a hole or 2)delayed-extent. |
4599 | */ | 4498 | */ |
4600 | if (es.es_len == 0) | 4499 | if (es.es_len == 0) |
4601 | /* A hole found. */ | 4500 | /* A hole found. */ |
4602 | return 0; | 4501 | return 0; |
4603 | 4502 | ||
4604 | if (es.es_lblk > newex->ec_block) { | 4503 | if (es.es_lblk > newes->es_lblk) { |
4605 | /* A hole found. */ | 4504 | /* A hole found. */ |
4606 | newex->ec_len = min(es.es_lblk - newex->ec_block, | 4505 | newes->es_len = min(es.es_lblk - newes->es_lblk, |
4607 | newex->ec_len); | 4506 | newes->es_len); |
4608 | return 0; | 4507 | return 0; |
4609 | } | 4508 | } |
4610 | 4509 | ||
4611 | newex->ec_len = es.es_lblk + es.es_len - newex->ec_block; | 4510 | newes->es_len = es.es_lblk + es.es_len - newes->es_lblk; |
4612 | } | 4511 | } |
4613 | 4512 | ||
4614 | block = newex->ec_block + newex->ec_len; | 4513 | block = newes->es_lblk + newes->es_len; |
4615 | ext4_es_find_delayed_extent(inode, block, &es); | 4514 | ext4_es_find_delayed_extent(inode, block, &es); |
4616 | if (es.es_len == 0) | 4515 | if (es.es_len == 0) |
4617 | next_del = EXT_MAX_BLOCKS; | 4516 | next_del = EXT_MAX_BLOCKS; |
@@ -4815,14 +4714,12 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) | |||
4815 | goto out; | 4714 | goto out; |
4816 | 4715 | ||
4817 | down_write(&EXT4_I(inode)->i_data_sem); | 4716 | down_write(&EXT4_I(inode)->i_data_sem); |
4818 | ext4_ext_invalidate_cache(inode); | ||
4819 | ext4_discard_preallocations(inode); | 4717 | ext4_discard_preallocations(inode); |
4820 | 4718 | ||
4821 | err = ext4_es_remove_extent(inode, first_block, | 4719 | err = ext4_es_remove_extent(inode, first_block, |
4822 | stop_block - first_block); | 4720 | stop_block - first_block); |
4823 | err = ext4_ext_remove_space(inode, first_block, stop_block - 1); | 4721 | err = ext4_ext_remove_space(inode, first_block, stop_block - 1); |
4824 | 4722 | ||
4825 | ext4_ext_invalidate_cache(inode); | ||
4826 | ext4_discard_preallocations(inode); | 4723 | ext4_discard_preallocations(inode); |
4827 | 4724 | ||
4828 | if (IS_SYNC(inode)) | 4725 | if (IS_SYNC(inode)) |