aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-08-02 18:51:32 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-08-02 18:51:32 -0400
commitd03856bd5e5abac717da137dc60fe4a691769bd0 (patch)
tree7de3649a2b48e36744aae72d5905bede2e28b6ca /fs
parent6e86841d05f371b5b9b86ce76c02aaee83352298 (diff)
ext4: Fix data corruption when writing to prealloc area
Inserting an extent can cause a new entry in the already existing index block. That doesn't increase the depth of the instead. Instead it adds a new leaf block. Now with the new leaf block the path information corresponding to the logical block should be fetched from the new block. The old path will be pointing to the old leaf block. We need to recalucate the path information on extent insert even if depth doesn't change. Without this change, the extent merge after converting an unwritten extent to initialized extent takes the wrong extent and cause data corruption. 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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c41
1 files changed, 23 insertions, 18 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 42c4c0c892ed..8ee1fa54a4e1 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2323,7 +2323,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2323 unsigned int newdepth; 2323 unsigned int newdepth;
2324 /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */ 2324 /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
2325 if (allocated <= EXT4_EXT_ZERO_LEN) { 2325 if (allocated <= EXT4_EXT_ZERO_LEN) {
2326 /* Mark first half uninitialized. 2326 /*
2327 * iblock == ee_block is handled by the zerouout
2328 * at the beginning.
2329 * Mark first half uninitialized.
2327 * Mark second half initialized and zero out the 2330 * Mark second half initialized and zero out the
2328 * initialized extent 2331 * initialized extent
2329 */ 2332 */
@@ -2346,7 +2349,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2346 ex->ee_len = orig_ex.ee_len; 2349 ex->ee_len = orig_ex.ee_len;
2347 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); 2350 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2348 ext4_ext_dirty(handle, inode, path + depth); 2351 ext4_ext_dirty(handle, inode, path + depth);
2349 /* zeroed the full extent */ 2352 /* blocks available from iblock */
2350 return allocated; 2353 return allocated;
2351 2354
2352 } else if (err) 2355 } else if (err)
@@ -2374,6 +2377,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2374 err = PTR_ERR(path); 2377 err = PTR_ERR(path);
2375 return err; 2378 return err;
2376 } 2379 }
2380 /* get the second half extent details */
2377 ex = path[depth].p_ext; 2381 ex = path[depth].p_ext;
2378 err = ext4_ext_get_access(handle, inode, 2382 err = ext4_ext_get_access(handle, inode,
2379 path + depth); 2383 path + depth);
@@ -2403,6 +2407,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2403 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); 2407 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2404 ext4_ext_dirty(handle, inode, path + depth); 2408 ext4_ext_dirty(handle, inode, path + depth);
2405 /* zeroed the full extent */ 2409 /* zeroed the full extent */
2410 /* blocks available from iblock */
2406 return allocated; 2411 return allocated;
2407 2412
2408 } else if (err) 2413 } else if (err)
@@ -2418,23 +2423,22 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2418 */ 2423 */
2419 orig_ex.ee_len = cpu_to_le16(ee_len - 2424 orig_ex.ee_len = cpu_to_le16(ee_len -
2420 ext4_ext_get_actual_len(ex3)); 2425 ext4_ext_get_actual_len(ex3));
2421 if (newdepth != depth) { 2426 depth = newdepth;
2422 depth = newdepth; 2427 ext4_ext_drop_refs(path);
2423 ext4_ext_drop_refs(path); 2428 path = ext4_ext_find_extent(inode, iblock, path);
2424 path = ext4_ext_find_extent(inode, iblock, path); 2429 if (IS_ERR(path)) {
2425 if (IS_ERR(path)) { 2430 err = PTR_ERR(path);
2426 err = PTR_ERR(path); 2431 goto out;
2427 goto out;
2428 }
2429 eh = path[depth].p_hdr;
2430 ex = path[depth].p_ext;
2431 if (ex2 != &newex)
2432 ex2 = ex;
2433
2434 err = ext4_ext_get_access(handle, inode, path + depth);
2435 if (err)
2436 goto out;
2437 } 2432 }
2433 eh = path[depth].p_hdr;
2434 ex = path[depth].p_ext;
2435 if (ex2 != &newex)
2436 ex2 = ex;
2437
2438 err = ext4_ext_get_access(handle, inode, path + depth);
2439 if (err)
2440 goto out;
2441
2438 allocated = max_blocks; 2442 allocated = max_blocks;
2439 2443
2440 /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying 2444 /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
@@ -2452,6 +2456,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2452 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); 2456 ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
2453 ext4_ext_dirty(handle, inode, path + depth); 2457 ext4_ext_dirty(handle, inode, path + depth);
2454 /* zero out the first half */ 2458 /* zero out the first half */
2459 /* blocks available from iblock */
2455 return allocated; 2460 return allocated;
2456 } 2461 }
2457 } 2462 }