aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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