aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-04-17 10:38:59 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-04-17 10:38:59 -0400
commit3977c965ec35ce1a7eac988ad313f0fc9aee9660 (patch)
tree86c799189a7888d6ebd02f9394fd0c2bd4eb2317
parent093a088b76352e0a6fdca84eb78b3aa65fbe6dd1 (diff)
ext4: zero out small extents when writing to prealloc area.
If the preallocated area is small zero out the full extent instead of splitting them. This should avoid the "write every alternate block" problem that could grow the number of extents dramatically. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/extents.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index d279ea8c4661..668d82e494dd 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2212,6 +2212,8 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
2212 return ret; 2212 return ret;
2213} 2213}
2214 2214
2215#define EXT4_EXT_ZERO_LEN 7
2216
2215/* 2217/*
2216 * This function is called by ext4_ext_get_blocks() if someone tries to write 2218 * This function is called by ext4_ext_get_blocks() if someone tries to write
2217 * to an uninitialized extent. It may result in splitting the uninitialized 2219 * to an uninitialized extent. It may result in splitting the uninitialized
@@ -2254,6 +2256,18 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2254 err = ext4_ext_get_access(handle, inode, path + depth); 2256 err = ext4_ext_get_access(handle, inode, path + depth);
2255 if (err) 2257 if (err)
2256 goto out; 2258 goto out;
2259 /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
2260 if (ee_len <= 2*EXT4_EXT_ZERO_LEN) {
2261 err = ext4_ext_zeroout(inode, &orig_ex);
2262 if (err)
2263 goto fix_extent_len;
2264 /* update the extent length and mark as initialized */
2265 ex->ee_block = orig_ex.ee_block;
2266 ex->ee_len = orig_ex.ee_len;
2267 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2268 ext4_ext_dirty(handle, inode, path + depth);
2269 return le16_to_cpu(ex->ee_len);
2270 }
2257 2271
2258 /* ex1: ee_block to iblock - 1 : uninitialized */ 2272 /* ex1: ee_block to iblock - 1 : uninitialized */
2259 if (iblock > ee_block) { 2273 if (iblock > ee_block) {
@@ -2272,6 +2286,38 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2272 /* ex3: to ee_block + ee_len : uninitialised */ 2286 /* ex3: to ee_block + ee_len : uninitialised */
2273 if (allocated > max_blocks) { 2287 if (allocated > max_blocks) {
2274 unsigned int newdepth; 2288 unsigned int newdepth;
2289 /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
2290 if (allocated <= EXT4_EXT_ZERO_LEN) {
2291 /* Mark first half uninitialized.
2292 * Mark second half initialized and zero out the
2293 * initialized extent
2294 */
2295 ex->ee_block = orig_ex.ee_block;
2296 ex->ee_len = cpu_to_le16(ee_len - allocated);
2297 ext4_ext_mark_uninitialized(ex);
2298 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2299 ext4_ext_dirty(handle, inode, path + depth);
2300
2301 ex3 = &newex;
2302 ex3->ee_block = cpu_to_le32(iblock);
2303 ext4_ext_store_pblock(ex3, newblock);
2304 ex3->ee_len = cpu_to_le16(allocated);
2305 err = ext4_ext_insert_extent(handle, inode, path, ex3);
2306 if (err == -ENOSPC) {
2307 err = ext4_ext_zeroout(inode, &orig_ex);
2308 if (err)
2309 goto fix_extent_len;
2310 ex->ee_block = orig_ex.ee_block;
2311 ex->ee_len = orig_ex.ee_len;
2312 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2313 ext4_ext_dirty(handle, inode, path + depth);
2314 return le16_to_cpu(ex->ee_len);
2315
2316 } else if (err)
2317 goto fix_extent_len;
2318
2319 return allocated;
2320 }
2275 ex3 = &newex; 2321 ex3 = &newex;
2276 ex3->ee_block = cpu_to_le32(iblock + max_blocks); 2322 ex3->ee_block = cpu_to_le32(iblock + max_blocks);
2277 ext4_ext_store_pblock(ex3, newblock + max_blocks); 2323 ext4_ext_store_pblock(ex3, newblock + max_blocks);
@@ -2320,6 +2366,23 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2320 goto out; 2366 goto out;
2321 } 2367 }
2322 allocated = max_blocks; 2368 allocated = max_blocks;
2369
2370 /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
2371 * to insert a extent in the middle zerout directly
2372 * otherwise give the extent a chance to merge to left
2373 */
2374 if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
2375 iblock != ee_block) {
2376 err = ext4_ext_zeroout(inode, &orig_ex);
2377 if (err)
2378 goto fix_extent_len;
2379 /* update the extent length and mark as initialized */
2380 ex->ee_block = orig_ex.ee_block;
2381 ex->ee_len = orig_ex.ee_len;
2382 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2383 ext4_ext_dirty(handle, inode, path + depth);
2384 return le16_to_cpu(ex->ee_len);
2385 }
2323 } 2386 }
2324 /* 2387 /*
2325 * If there was a change of depth as part of the 2388 * If there was a change of depth as part of the