diff options
author | Eric Sandeen <esandeen@redhat.com> | 2006-09-27 04:49:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 11:26:09 -0400 |
commit | 855565e81ad8940cc645b5110ec2c7f124a76d23 (patch) | |
tree | 48b5ff0eb7bd297404b301e679d6330976e3e90d /fs/ext3/super.c | |
parent | 2aed3484695ecb03f1395bb62f1099e8b0826124 (diff) |
[PATCH] fix ext3 mounts at 16T
I need to do some actual IO testing now, but this gets things mounting for
a 16T ext3 filesystem. (patched up e2fsprogs is needed too, I'll send that
off the kernel list)
This patch fixes these issues in the kernel:
o sbi->s_groups_count overflows in ext3_fill_super()
sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
le32_to_cpu(es->s_first_data_block) +
EXT3_BLOCKS_PER_GROUP(sb) - 1) /
EXT3_BLOCKS_PER_GROUP(sb);
at 16T, s_blocks_count is already maxed out; adding
EXT3_BLOCKS_PER_GROUP(sb) overflows it and groups_count comes out to 0.
Not really what we want, and causes a failed mount.
Feel free to check my math (actually, please do!), but changing it this
way should work & avoid the overflow:
(A + B - 1)/B changed to: ((A - 1)/B) + 1
o ext3_check_descriptors() overflows range checks
ext3_check_descriptors() iterates over all block groups making sure
that various bits are within the right block ranges... on the last pass
through, it is checking the error case
[item] >= block + EXT3_BLOCKS_PER_GROUP(sb)
where "block" is the first block in the last block group. The last
block in this group (and the last one that will fit in 32 bits) is block
+ EXT3_BLOCKS_PER_GROUP(sb)- 1. block + EXT3_BLOCKS_PER_GROUP(sb) wraps
back around to 0.
so, make things clearer with "first_block" and "last_block" where those
are first and last, inclusive, and use <, > rather than <, >=.
Finally, the last block group may be smaller than the rest, so account
for this on the last pass through: last_block = sb->s_blocks_count - 1;
(a similar patch could be done for ext2; does anyone in their right mind
use ext2 at 16T? I'll send an ext2 patch doing the same thing if that's
warranted)
Signed-off-by: Eric Sandeen <esandeen@redhat.com>
Cc: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/ext3/super.c')
-rw-r--r-- | fs/ext3/super.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 4b95bfe4c8f7..762dff7b56fb 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -1174,7 +1174,8 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, | |||
1174 | static int ext3_check_descriptors (struct super_block * sb) | 1174 | static int ext3_check_descriptors (struct super_block * sb) |
1175 | { | 1175 | { |
1176 | struct ext3_sb_info *sbi = EXT3_SB(sb); | 1176 | struct ext3_sb_info *sbi = EXT3_SB(sb); |
1177 | ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block); | 1177 | ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); |
1178 | ext3_fsblk_t last_block; | ||
1178 | struct ext3_group_desc * gdp = NULL; | 1179 | struct ext3_group_desc * gdp = NULL; |
1179 | int desc_block = 0; | 1180 | int desc_block = 0; |
1180 | int i; | 1181 | int i; |
@@ -1183,12 +1184,17 @@ static int ext3_check_descriptors (struct super_block * sb) | |||
1183 | 1184 | ||
1184 | for (i = 0; i < sbi->s_groups_count; i++) | 1185 | for (i = 0; i < sbi->s_groups_count; i++) |
1185 | { | 1186 | { |
1187 | if (i == sbi->s_groups_count - 1) | ||
1188 | last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; | ||
1189 | else | ||
1190 | last_block = first_block + | ||
1191 | (EXT3_BLOCKS_PER_GROUP(sb) - 1); | ||
1192 | |||
1186 | if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) | 1193 | if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) |
1187 | gdp = (struct ext3_group_desc *) | 1194 | gdp = (struct ext3_group_desc *) |
1188 | sbi->s_group_desc[desc_block++]->b_data; | 1195 | sbi->s_group_desc[desc_block++]->b_data; |
1189 | if (le32_to_cpu(gdp->bg_block_bitmap) < block || | 1196 | if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || |
1190 | le32_to_cpu(gdp->bg_block_bitmap) >= | 1197 | le32_to_cpu(gdp->bg_block_bitmap) > last_block) |
1191 | block + EXT3_BLOCKS_PER_GROUP(sb)) | ||
1192 | { | 1198 | { |
1193 | ext3_error (sb, "ext3_check_descriptors", | 1199 | ext3_error (sb, "ext3_check_descriptors", |
1194 | "Block bitmap for group %d" | 1200 | "Block bitmap for group %d" |
@@ -1197,9 +1203,8 @@ static int ext3_check_descriptors (struct super_block * sb) | |||
1197 | le32_to_cpu(gdp->bg_block_bitmap)); | 1203 | le32_to_cpu(gdp->bg_block_bitmap)); |
1198 | return 0; | 1204 | return 0; |
1199 | } | 1205 | } |
1200 | if (le32_to_cpu(gdp->bg_inode_bitmap) < block || | 1206 | if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || |
1201 | le32_to_cpu(gdp->bg_inode_bitmap) >= | 1207 | le32_to_cpu(gdp->bg_inode_bitmap) > last_block) |
1202 | block + EXT3_BLOCKS_PER_GROUP(sb)) | ||
1203 | { | 1208 | { |
1204 | ext3_error (sb, "ext3_check_descriptors", | 1209 | ext3_error (sb, "ext3_check_descriptors", |
1205 | "Inode bitmap for group %d" | 1210 | "Inode bitmap for group %d" |
@@ -1208,9 +1213,9 @@ static int ext3_check_descriptors (struct super_block * sb) | |||
1208 | le32_to_cpu(gdp->bg_inode_bitmap)); | 1213 | le32_to_cpu(gdp->bg_inode_bitmap)); |
1209 | return 0; | 1214 | return 0; |
1210 | } | 1215 | } |
1211 | if (le32_to_cpu(gdp->bg_inode_table) < block || | 1216 | if (le32_to_cpu(gdp->bg_inode_table) < first_block || |
1212 | le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >= | 1217 | le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > |
1213 | block + EXT3_BLOCKS_PER_GROUP(sb)) | 1218 | last_block) |
1214 | { | 1219 | { |
1215 | ext3_error (sb, "ext3_check_descriptors", | 1220 | ext3_error (sb, "ext3_check_descriptors", |
1216 | "Inode table for group %d" | 1221 | "Inode table for group %d" |
@@ -1219,7 +1224,7 @@ static int ext3_check_descriptors (struct super_block * sb) | |||
1219 | le32_to_cpu(gdp->bg_inode_table)); | 1224 | le32_to_cpu(gdp->bg_inode_table)); |
1220 | return 0; | 1225 | return 0; |
1221 | } | 1226 | } |
1222 | block += EXT3_BLOCKS_PER_GROUP(sb); | 1227 | first_block += EXT3_BLOCKS_PER_GROUP(sb); |
1223 | gdp++; | 1228 | gdp++; |
1224 | } | 1229 | } |
1225 | 1230 | ||
@@ -1622,10 +1627,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
1622 | 1627 | ||
1623 | if (EXT3_BLOCKS_PER_GROUP(sb) == 0) | 1628 | if (EXT3_BLOCKS_PER_GROUP(sb) == 0) |
1624 | goto cantfind_ext3; | 1629 | goto cantfind_ext3; |
1625 | sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) - | 1630 | sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - |
1626 | le32_to_cpu(es->s_first_data_block) + | 1631 | le32_to_cpu(es->s_first_data_block) - 1) |
1627 | EXT3_BLOCKS_PER_GROUP(sb) - 1) / | 1632 | / EXT3_BLOCKS_PER_GROUP(sb)) + 1; |
1628 | EXT3_BLOCKS_PER_GROUP(sb); | ||
1629 | db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / | 1633 | db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / |
1630 | EXT3_DESC_PER_BLOCK(sb); | 1634 | EXT3_DESC_PER_BLOCK(sb); |
1631 | sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), | 1635 | sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), |