aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorZheng Liu <wenqing.lz@taobao.com>2013-02-18 00:31:07 -0500
committerTheodore Ts'o <tytso@mit.edu>2013-02-18 00:31:07 -0500
commit69eb33dc24dc44d1128aa5e82d0976c42b440c1a (patch)
treea20982f1fb23b94fe08e6034faea33ed81e4626f /fs/ext4/extents.c
parentd100eef2440fea13e4f09e88b1c8bcbca64beb9f (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.c179
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
114static int ext4_find_delayed_extent(struct inode *inode, 114static int ext4_find_delayed_extent(struct inode *inode,
115 struct ext4_ext_cache *newex); 115 struct extent_status *newes);
116 116
117static int ext4_ext_truncate_extend_restart(handle_t *handle, 117static 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
2128static void
2129ext4_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 */
2211static int
2212ext4_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 }
2237errout:
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
2679again: 2617again:
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);
4273out: 4173out:
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 */
4587static int ext4_find_delayed_extent(struct inode *inode, 4486static 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))