diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2008-01-28 23:58:27 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-01-28 23:58:27 -0500 |
commit | b939e3766ec19eb556cb784c2faace253c6e1560 (patch) | |
tree | 0e088db3593d032ce9ee7090ae82b8ed213ccb23 | |
parent | dbf9d7da33f79302fb1e4d7c6b2f6598e8608e72 (diff) |
ext4: Use the ext4_ext_actual_len() helper function
ext4 uses the high bit of the extent length to encode whether the extent
is intialized or not. The helper function ext4_ext_get_actual_len should
be used to get the actual length of the extent.
This addresses the kernel bug documented here:
http://bugzilla.kernel.org/show_bug.cgi?id=9732
kernel BUG at fs/ext4/extents.c:1056!
....
Call Trace:
[<ffffffff88366073>] :ext4dev:ext4_ext_get_blocks+0x5ba/0x8c1
[<ffffffff81053c91>] lock_release_holdtime+0x27/0x49
[<ffffffff812748f6>] _spin_unlock+0x17/0x20
[<ffffffff883400a6>] :jbd2:start_this_handle+0x4e0/0x4fe
[<ffffffff88366564>] :ext4dev:ext4_fallocate+0x175/0x39a
[<ffffffff81053c91>] lock_release_holdtime+0x27/0x49
[<ffffffff81056480>] __lock_acquire+0x4e7/0xc4d
[<ffffffff81053c91>] lock_release_holdtime+0x27/0x49
[<ffffffff810a8de7>] sys_fallocate+0xe4/0x10d
[<ffffffff8100c043>] tracesys+0xd5/0xda
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/ext4/extents.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index ce9aa5860569..bc7081f1fbe8 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1029,7 +1029,7 @@ ext4_ext_search_left(struct inode *inode, struct ext4_ext_path *path, | |||
1029 | { | 1029 | { |
1030 | struct ext4_extent_idx *ix; | 1030 | struct ext4_extent_idx *ix; |
1031 | struct ext4_extent *ex; | 1031 | struct ext4_extent *ex; |
1032 | int depth; | 1032 | int depth, ee_len; |
1033 | 1033 | ||
1034 | BUG_ON(path == NULL); | 1034 | BUG_ON(path == NULL); |
1035 | depth = path->p_depth; | 1035 | depth = path->p_depth; |
@@ -1043,6 +1043,7 @@ ext4_ext_search_left(struct inode *inode, struct ext4_ext_path *path, | |||
1043 | * first one in the file */ | 1043 | * first one in the file */ |
1044 | 1044 | ||
1045 | ex = path[depth].p_ext; | 1045 | ex = path[depth].p_ext; |
1046 | ee_len = ext4_ext_get_actual_len(ex); | ||
1046 | if (*logical < le32_to_cpu(ex->ee_block)) { | 1047 | if (*logical < le32_to_cpu(ex->ee_block)) { |
1047 | BUG_ON(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex); | 1048 | BUG_ON(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex); |
1048 | while (--depth >= 0) { | 1049 | while (--depth >= 0) { |
@@ -1052,10 +1053,10 @@ ext4_ext_search_left(struct inode *inode, struct ext4_ext_path *path, | |||
1052 | return 0; | 1053 | return 0; |
1053 | } | 1054 | } |
1054 | 1055 | ||
1055 | BUG_ON(*logical < le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)); | 1056 | BUG_ON(*logical < (le32_to_cpu(ex->ee_block) + ee_len)); |
1056 | 1057 | ||
1057 | *logical = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1; | 1058 | *logical = le32_to_cpu(ex->ee_block) + ee_len - 1; |
1058 | *phys = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - 1; | 1059 | *phys = ext_pblock(ex) + ee_len - 1; |
1059 | return 0; | 1060 | return 0; |
1060 | } | 1061 | } |
1061 | 1062 | ||
@@ -1075,7 +1076,7 @@ ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path, | |||
1075 | struct ext4_extent_idx *ix; | 1076 | struct ext4_extent_idx *ix; |
1076 | struct ext4_extent *ex; | 1077 | struct ext4_extent *ex; |
1077 | ext4_fsblk_t block; | 1078 | ext4_fsblk_t block; |
1078 | int depth; | 1079 | int depth, ee_len; |
1079 | 1080 | ||
1080 | BUG_ON(path == NULL); | 1081 | BUG_ON(path == NULL); |
1081 | depth = path->p_depth; | 1082 | depth = path->p_depth; |
@@ -1089,6 +1090,7 @@ ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path, | |||
1089 | * first one in the file */ | 1090 | * first one in the file */ |
1090 | 1091 | ||
1091 | ex = path[depth].p_ext; | 1092 | ex = path[depth].p_ext; |
1093 | ee_len = ext4_ext_get_actual_len(ex); | ||
1092 | if (*logical < le32_to_cpu(ex->ee_block)) { | 1094 | if (*logical < le32_to_cpu(ex->ee_block)) { |
1093 | BUG_ON(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex); | 1095 | BUG_ON(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex); |
1094 | while (--depth >= 0) { | 1096 | while (--depth >= 0) { |
@@ -1100,7 +1102,7 @@ ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path, | |||
1100 | return 0; | 1102 | return 0; |
1101 | } | 1103 | } |
1102 | 1104 | ||
1103 | BUG_ON(*logical < le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)); | 1105 | BUG_ON(*logical < (le32_to_cpu(ex->ee_block) + ee_len)); |
1104 | 1106 | ||
1105 | if (ex != EXT_LAST_EXTENT(path[depth].p_hdr)) { | 1107 | if (ex != EXT_LAST_EXTENT(path[depth].p_hdr)) { |
1106 | /* next allocated block in this leaf */ | 1108 | /* next allocated block in this leaf */ |
@@ -1316,7 +1318,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | |||
1316 | if (ext1_ee_len + ext2_ee_len > max_len) | 1318 | if (ext1_ee_len + ext2_ee_len > max_len) |
1317 | return 0; | 1319 | return 0; |
1318 | #ifdef AGGRESSIVE_TEST | 1320 | #ifdef AGGRESSIVE_TEST |
1319 | if (le16_to_cpu(ex1->ee_len) >= 4) | 1321 | if (ext1_ee_len >= 4) |
1320 | return 0; | 1322 | return 0; |
1321 | #endif | 1323 | #endif |
1322 | 1324 | ||
@@ -2313,7 +2315,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2313 | - le32_to_cpu(newex.ee_block) | 2315 | - le32_to_cpu(newex.ee_block) |
2314 | + ext_pblock(&newex); | 2316 | + ext_pblock(&newex); |
2315 | /* number of remaining blocks in the extent */ | 2317 | /* number of remaining blocks in the extent */ |
2316 | allocated = le16_to_cpu(newex.ee_len) - | 2318 | allocated = ext4_ext_get_actual_len(&newex) - |
2317 | (iblock - le32_to_cpu(newex.ee_block)); | 2319 | (iblock - le32_to_cpu(newex.ee_block)); |
2318 | goto out; | 2320 | goto out; |
2319 | } else { | 2321 | } else { |
@@ -2429,7 +2431,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2429 | newex.ee_len = cpu_to_le16(max_blocks); | 2431 | newex.ee_len = cpu_to_le16(max_blocks); |
2430 | err = ext4_ext_check_overlap(inode, &newex, path); | 2432 | err = ext4_ext_check_overlap(inode, &newex, path); |
2431 | if (err) | 2433 | if (err) |
2432 | allocated = le16_to_cpu(newex.ee_len); | 2434 | allocated = ext4_ext_get_actual_len(&newex); |
2433 | else | 2435 | else |
2434 | allocated = max_blocks; | 2436 | allocated = max_blocks; |
2435 | 2437 | ||
@@ -2461,7 +2463,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2461 | * but otherwise we'd need to call it every free() */ | 2463 | * but otherwise we'd need to call it every free() */ |
2462 | ext4_mb_discard_inode_preallocations(inode); | 2464 | ext4_mb_discard_inode_preallocations(inode); |
2463 | ext4_free_blocks(handle, inode, ext_pblock(&newex), | 2465 | ext4_free_blocks(handle, inode, ext_pblock(&newex), |
2464 | le16_to_cpu(newex.ee_len), 0); | 2466 | ext4_ext_get_actual_len(&newex), 0); |
2465 | goto out2; | 2467 | goto out2; |
2466 | } | 2468 | } |
2467 | 2469 | ||
@@ -2470,7 +2472,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2470 | 2472 | ||
2471 | /* previous routine could use block we allocated */ | 2473 | /* previous routine could use block we allocated */ |
2472 | newblock = ext_pblock(&newex); | 2474 | newblock = ext_pblock(&newex); |
2473 | allocated = le16_to_cpu(newex.ee_len); | 2475 | allocated = ext4_ext_get_actual_len(&newex); |
2474 | outnew: | 2476 | outnew: |
2475 | __set_bit(BH_New, &bh_result->b_state); | 2477 | __set_bit(BH_New, &bh_result->b_state); |
2476 | 2478 | ||