Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Zheng Liu and committed by
Theodore Ts'o
69eb33dc d100eef2

+38 -163
-12
fs/ext4/ext4.h
··· 809 809 810 810 #endif /* defined(__KERNEL__) || defined(__linux__) */ 811 811 812 - /* 813 - * storage for cached extent 814 - * If ec_len == 0, then the cache is invalid. 815 - * If ec_start == 0, then the cache represents a gap (null mapping) 816 - */ 817 - struct ext4_ext_cache { 818 - ext4_fsblk_t ec_start; 819 - ext4_lblk_t ec_block; 820 - __u32 ec_len; /* must be 32bit to return holes */ 821 - }; 822 - 823 812 #include "extents_status.h" 824 813 825 814 /* ··· 875 886 struct inode vfs_inode; 876 887 struct jbd2_inode *jinode; 877 888 878 - struct ext4_ext_cache i_cached_extent; 879 889 /* 880 890 * File creation time. Its function is same as that of 881 891 * struct timespec i_{a,c,m}time in the generic inode.
-6
fs/ext4/ext4_extents.h
··· 193 193 return le16_to_cpu(ext_inode_hdr(inode)->eh_depth); 194 194 } 195 195 196 - static inline void 197 - ext4_ext_invalidate_cache(struct inode *inode) 198 - { 199 - EXT4_I(inode)->i_cached_extent.ec_len = 0; 200 - } 201 - 202 196 static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext) 203 197 { 204 198 /* We can not have an uninitialized extent of zero length! */
+38 -141
fs/ext4/extents.c
··· 112 112 int flags); 113 113 114 114 static int ext4_find_delayed_extent(struct inode *inode, 115 - struct ext4_ext_cache *newex); 115 + struct extent_status *newes); 116 116 117 117 static int ext4_ext_truncate_extend_restart(handle_t *handle, 118 118 struct inode *inode, ··· 714 714 eh->eh_magic = EXT4_EXT_MAGIC; 715 715 eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); 716 716 ext4_mark_inode_dirty(handle, inode); 717 - ext4_ext_invalidate_cache(inode); 718 717 return 0; 719 718 } 720 719 ··· 1962 1963 ext4_ext_drop_refs(npath); 1963 1964 kfree(npath); 1964 1965 } 1965 - ext4_ext_invalidate_cache(inode); 1966 1966 return err; 1967 1967 } 1968 1968 ··· 1970 1972 struct fiemap_extent_info *fieinfo) 1971 1973 { 1972 1974 struct ext4_ext_path *path = NULL; 1973 - struct ext4_ext_cache newex; 1974 1975 struct ext4_extent *ex; 1976 + struct extent_status es; 1975 1977 ext4_lblk_t next, next_del, start = 0, end = 0; 1976 1978 ext4_lblk_t last = block + num; 1977 1979 int exists, depth = 0, err = 0; ··· 2045 2047 BUG_ON(end <= start); 2046 2048 2047 2049 if (!exists) { 2048 - newex.ec_block = start; 2049 - newex.ec_len = end - start; 2050 - newex.ec_start = 0; 2050 + es.es_lblk = start; 2051 + es.es_len = end - start; 2052 + es.es_pblk = 0; 2051 2053 } else { 2052 - newex.ec_block = le32_to_cpu(ex->ee_block); 2053 - newex.ec_len = ext4_ext_get_actual_len(ex); 2054 - newex.ec_start = ext4_ext_pblock(ex); 2054 + es.es_lblk = le32_to_cpu(ex->ee_block); 2055 + es.es_len = ext4_ext_get_actual_len(ex); 2056 + es.es_pblk = ext4_ext_pblock(ex); 2055 2057 if (ext4_ext_is_uninitialized(ex)) 2056 2058 flags |= FIEMAP_EXTENT_UNWRITTEN; 2057 2059 } 2058 2060 2059 2061 /* 2060 - * Find delayed extent and update newex accordingly. We call 2061 - * it even in !exists case to find out whether newex is the 2062 + * Find delayed extent and update es accordingly. We call 2063 + * it even in !exists case to find out whether es is the 2062 2064 * last existing extent or not. 2063 2065 */ 2064 - next_del = ext4_find_delayed_extent(inode, &newex); 2066 + next_del = ext4_find_delayed_extent(inode, &es); 2065 2067 if (!exists && next_del) { 2066 2068 exists = 1; 2067 2069 flags |= FIEMAP_EXTENT_DELALLOC; 2068 2070 } 2069 2071 up_read(&EXT4_I(inode)->i_data_sem); 2070 2072 2071 - if (unlikely(newex.ec_len == 0)) { 2072 - EXT4_ERROR_INODE(inode, "newex.ec_len == 0"); 2073 + if (unlikely(es.es_len == 0)) { 2074 + EXT4_ERROR_INODE(inode, "es.es_len == 0"); 2073 2075 err = -EIO; 2074 2076 break; 2075 2077 } ··· 2100 2102 2101 2103 if (exists) { 2102 2104 err = fiemap_fill_next_extent(fieinfo, 2103 - (__u64)newex.ec_block << blksize_bits, 2104 - (__u64)newex.ec_start << blksize_bits, 2105 - (__u64)newex.ec_len << blksize_bits, 2105 + (__u64)es.es_lblk << blksize_bits, 2106 + (__u64)es.es_pblk << blksize_bits, 2107 + (__u64)es.es_len << blksize_bits, 2106 2108 flags); 2107 2109 if (err < 0) 2108 2110 break; ··· 2112 2114 } 2113 2115 } 2114 2116 2115 - block = newex.ec_block + newex.ec_len; 2117 + block = es.es_lblk + es.es_len; 2116 2118 } 2117 2119 2118 2120 if (path) { ··· 2121 2123 } 2122 2124 2123 2125 return err; 2124 - } 2125 - 2126 - static void 2127 - ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block, 2128 - __u32 len, ext4_fsblk_t start) 2129 - { 2130 - struct ext4_ext_cache *cex; 2131 - BUG_ON(len == 0); 2132 - spin_lock(&EXT4_I(inode)->i_block_reservation_lock); 2133 - trace_ext4_ext_put_in_cache(inode, block, len, start); 2134 - cex = &EXT4_I(inode)->i_cached_extent; 2135 - cex->ec_block = block; 2136 - cex->ec_len = len; 2137 - cex->ec_start = start; 2138 - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); 2139 2126 } 2140 2127 2141 2128 /* ··· 2139 2156 2140 2157 ex = path[depth].p_ext; 2141 2158 if (ex == NULL) { 2142 - /* there is no extent yet, so gap is [0;-] */ 2143 - lblock = 0; 2144 - len = EXT_MAX_BLOCKS; 2159 + /* 2160 + * there is no extent yet, so gap is [0;-] and we 2161 + * don't cache it 2162 + */ 2145 2163 ext_debug("cache gap(whole file):"); 2146 2164 } else if (block < le32_to_cpu(ex->ee_block)) { 2147 2165 lblock = block; ··· 2176 2192 } 2177 2193 2178 2194 ext_debug(" -> %u:%lu\n", lblock, len); 2179 - ext4_ext_put_in_cache(inode, lblock, len, 0); 2180 - } 2181 - 2182 - /* 2183 - * ext4_ext_in_cache() 2184 - * Checks to see if the given block is in the cache. 2185 - * If it is, the cached extent is stored in the given 2186 - * cache extent pointer. 2187 - * 2188 - * @inode: The files inode 2189 - * @block: The block to look for in the cache 2190 - * @ex: Pointer where the cached extent will be stored 2191 - * if it contains block 2192 - * 2193 - * Return 0 if cache is invalid; 1 if the cache is valid 2194 - */ 2195 - static int 2196 - ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, 2197 - struct ext4_extent *ex) 2198 - { 2199 - struct ext4_ext_cache *cex; 2200 - int ret = 0; 2201 - 2202 - /* 2203 - * We borrow i_block_reservation_lock to protect i_cached_extent 2204 - */ 2205 - spin_lock(&EXT4_I(inode)->i_block_reservation_lock); 2206 - cex = &EXT4_I(inode)->i_cached_extent; 2207 - 2208 - /* has cache valid data? */ 2209 - if (cex->ec_len == 0) 2210 - goto errout; 2211 - 2212 - if (in_range(block, cex->ec_block, cex->ec_len)) { 2213 - ex->ee_block = cpu_to_le32(cex->ec_block); 2214 - ext4_ext_store_pblock(ex, cex->ec_start); 2215 - ex->ee_len = cpu_to_le16(cex->ec_len); 2216 - ext_debug("%u cached by %u:%u:%llu\n", 2217 - block, 2218 - cex->ec_block, cex->ec_len, cex->ec_start); 2219 - ret = 1; 2220 - } 2221 - errout: 2222 - trace_ext4_ext_in_cache(inode, block, ret); 2223 - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); 2224 - return ret; 2225 2195 } 2226 2196 2227 2197 /* ··· 2615 2677 return PTR_ERR(handle); 2616 2678 2617 2679 again: 2618 - ext4_ext_invalidate_cache(inode); 2619 - 2620 2680 trace_ext4_ext_remove_space(inode, start, depth); 2621 2681 2622 2682 /* ··· 3856 3920 map->m_lblk, map->m_len, inode->i_ino); 3857 3921 trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); 3858 3922 3859 - /* check in cache */ 3860 - if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) { 3861 - if (!newex.ee_start_lo && !newex.ee_start_hi) { 3862 - if ((sbi->s_cluster_ratio > 1) && 3863 - ext4_find_delalloc_cluster(inode, map->m_lblk)) 3864 - map->m_flags |= EXT4_MAP_FROM_CLUSTER; 3865 - 3866 - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { 3867 - /* 3868 - * block isn't allocated yet and 3869 - * user doesn't want to allocate it 3870 - */ 3871 - goto out2; 3872 - } 3873 - /* we should allocate requested block */ 3874 - } else { 3875 - /* block is already allocated */ 3876 - if (sbi->s_cluster_ratio > 1) 3877 - map->m_flags |= EXT4_MAP_FROM_CLUSTER; 3878 - newblock = map->m_lblk 3879 - - le32_to_cpu(newex.ee_block) 3880 - + ext4_ext_pblock(&newex); 3881 - /* number of remaining blocks in the extent */ 3882 - allocated = ext4_ext_get_actual_len(&newex) - 3883 - (map->m_lblk - le32_to_cpu(newex.ee_block)); 3884 - goto out; 3885 - } 3886 - } 3887 - 3888 3923 /* find extent for this block */ 3889 3924 path = ext4_ext_find_extent(inode, map->m_lblk, NULL); 3890 3925 if (IS_ERR(path)) { ··· 3902 3995 ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk, 3903 3996 ee_block, ee_len, newblock); 3904 3997 3905 - /* 3906 - * Do not put uninitialized extent 3907 - * in the cache 3908 - */ 3909 - if (!ext4_ext_is_uninitialized(ex)) { 3910 - ext4_ext_put_in_cache(inode, ee_block, 3911 - ee_len, ee_start); 3998 + if (!ext4_ext_is_uninitialized(ex)) 3912 3999 goto out; 3913 - } 4000 + 3914 4001 allocated = ext4_ext_handle_uninitialized_extents( 3915 4002 handle, inode, map, path, flags, 3916 4003 allocated, newblock); ··· 4166 4265 * Cache the extent and update transaction to commit on fdatasync only 4167 4266 * when it is _not_ an uninitialized extent. 4168 4267 */ 4169 - if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) { 4170 - ext4_ext_put_in_cache(inode, map->m_lblk, allocated, newblock); 4268 + if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) 4171 4269 ext4_update_inode_fsync_trans(handle, inode, 1); 4172 - } else 4270 + else 4173 4271 ext4_update_inode_fsync_trans(handle, inode, 0); 4174 4272 out: 4175 4273 if (allocated > map->m_len) ··· 4227 4327 goto out_stop; 4228 4328 4229 4329 down_write(&EXT4_I(inode)->i_data_sem); 4230 - ext4_ext_invalidate_cache(inode); 4231 4330 4232 4331 ext4_discard_preallocations(inode); 4233 4332 ··· 4475 4576 } 4476 4577 4477 4578 /* 4478 - * If newex is not existing extent (newex->ec_start equals zero) find 4479 - * delayed extent at start of newex and update newex accordingly and 4579 + * If newes is not existing extent (newes->ec_pblk equals zero) find 4580 + * delayed extent at start of newes and update newes accordingly and 4480 4581 * return start of the next delayed extent. 4481 4582 * 4482 - * If newex is existing extent (newex->ec_start is not equal zero) 4583 + * If newes is existing extent (newes->ec_pblk is not equal zero) 4483 4584 * return start of next delayed extent or EXT_MAX_BLOCKS if no delayed 4484 - * extent found. Leave newex unmodified. 4585 + * extent found. Leave newes unmodified. 4485 4586 */ 4486 4587 static int ext4_find_delayed_extent(struct inode *inode, 4487 - struct ext4_ext_cache *newex) 4588 + struct extent_status *newes) 4488 4589 { 4489 4590 struct extent_status es; 4490 4591 ext4_lblk_t block, next_del; 4491 4592 4492 - ext4_es_find_delayed_extent(inode, newex->ec_block, &es); 4593 + ext4_es_find_delayed_extent(inode, newes->es_lblk, &es); 4493 4594 4494 - if (newex->ec_start == 0) { 4595 + if (newes->es_pblk == 0) { 4495 4596 /* 4496 - * No extent in extent-tree contains block @newex->ec_start, 4597 + * No extent in extent-tree contains block @newes->es_pblk, 4497 4598 * then the block may stay in 1)a hole or 2)delayed-extent. 4498 4599 */ 4499 4600 if (es.es_len == 0) 4500 4601 /* A hole found. */ 4501 4602 return 0; 4502 4603 4503 - if (es.es_lblk > newex->ec_block) { 4604 + if (es.es_lblk > newes->es_lblk) { 4504 4605 /* A hole found. */ 4505 - newex->ec_len = min(es.es_lblk - newex->ec_block, 4506 - newex->ec_len); 4606 + newes->es_len = min(es.es_lblk - newes->es_lblk, 4607 + newes->es_len); 4507 4608 return 0; 4508 4609 } 4509 4610 4510 - newex->ec_len = es.es_lblk + es.es_len - newex->ec_block; 4611 + newes->es_len = es.es_lblk + es.es_len - newes->es_lblk; 4511 4612 } 4512 4613 4513 - block = newex->ec_block + newex->ec_len; 4614 + block = newes->es_lblk + newes->es_len; 4514 4615 ext4_es_find_delayed_extent(inode, block, &es); 4515 4616 if (es.es_len == 0) 4516 4617 next_del = EXT_MAX_BLOCKS; ··· 4714 4815 goto out; 4715 4816 4716 4817 down_write(&EXT4_I(inode)->i_data_sem); 4717 - ext4_ext_invalidate_cache(inode); 4718 4818 ext4_discard_preallocations(inode); 4719 4819 4720 4820 err = ext4_es_remove_extent(inode, first_block, 4721 4821 stop_block - first_block); 4722 4822 err = ext4_ext_remove_space(inode, first_block, stop_block - 1); 4723 4823 4724 - ext4_ext_invalidate_cache(inode); 4725 4824 ext4_discard_preallocations(inode); 4726 4825 4727 4826 if (IS_SYNC(inode))
-3
fs/ext4/move_extent.c
··· 764 764 kfree(donor_path); 765 765 } 766 766 767 - ext4_ext_invalidate_cache(orig_inode); 768 - ext4_ext_invalidate_cache(donor_inode); 769 - 770 767 return replaced_count; 771 768 } 772 769
-1
fs/ext4/super.c
··· 836 836 return NULL; 837 837 838 838 ei->vfs_inode.i_version = 1; 839 - memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); 840 839 INIT_LIST_HEAD(&ei->i_prealloc_list); 841 840 spin_lock_init(&ei->i_prealloc_lock); 842 841 ext4_es_init_tree(&ei->i_es_tree);