Commit bd81d8ee authored by Laurent Vivier's avatar Laurent Vivier Committed by Linus Torvalds

[PATCH] ext4: 64bit metadata

In-kernel super block changes to support >32 bit free blocks numbers.
Signed-off-by: default avatarLaurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: default avatarDave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: default avatarAlexandre Ratchov <alexandre.ratchov@bull.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a1ddeb7e
...@@ -99,12 +99,13 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) ...@@ -99,12 +99,13 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
desc = ext4_get_group_desc (sb, block_group, NULL); desc = ext4_get_group_desc (sb, block_group, NULL);
if (!desc) if (!desc)
goto error_out; goto error_out;
bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); bh = sb_bread(sb, ext4_block_bitmap(desc));
if (!bh) if (!bh)
ext4_error (sb, "read_block_bitmap", ext4_error (sb, "read_block_bitmap",
"Cannot read block bitmap - " "Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u", "block_group = %d, block_bitmap = "E3FSBLK,
block_group, le32_to_cpu(desc->bg_block_bitmap)); block_group,
ext4_block_bitmap(desc));
error_out: error_out:
return bh; return bh;
} }
...@@ -432,14 +433,14 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, ...@@ -432,14 +433,14 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
es = sbi->s_es; es = sbi->s_es;
if (block < le32_to_cpu(es->s_first_data_block) || if (block < le32_to_cpu(es->s_first_data_block) ||
block + count < block || block + count < block ||
block + count > le32_to_cpu(es->s_blocks_count)) { block + count > ext4_blocks_count(es)) {
ext4_error (sb, "ext4_free_blocks", ext4_error (sb, "ext4_free_blocks",
"Freeing blocks not in datazone - " "Freeing blocks not in datazone - "
"block = "E3FSBLK", count = %lu", block, count); "block = "E3FSBLK", count = %lu", block, count);
goto error_return; goto error_return;
} }
ext4_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1);
do_more: do_more:
overflow = 0; overflow = 0;
...@@ -460,12 +461,11 @@ do_more: ...@@ -460,12 +461,11 @@ do_more:
if (!desc) if (!desc)
goto error_return; goto error_return;
if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) || if (in_range(ext4_block_bitmap(desc), block, count) ||
in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) || in_range(ext4_inode_bitmap(desc), block, count) ||
in_range (block, le32_to_cpu(desc->bg_inode_table), in_range(block, ext4_inode_table(desc), sbi->s_itb_per_group) ||
sbi->s_itb_per_group) || in_range(block + count - 1, ext4_inode_table(desc),
in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), sbi->s_itb_per_group))
sbi->s_itb_per_group))
ext4_error (sb, "ext4_free_blocks", ext4_error (sb, "ext4_free_blocks",
"Freeing blocks in system zones - " "Freeing blocks in system zones - "
"Block = "E3FSBLK", count = %lu", "Block = "E3FSBLK", count = %lu",
...@@ -552,8 +552,8 @@ do_more: ...@@ -552,8 +552,8 @@ do_more:
bit + i, bitmap_bh->b_data)) { bit + i, bitmap_bh->b_data)) {
jbd_unlock_bh_state(bitmap_bh); jbd_unlock_bh_state(bitmap_bh);
ext4_error(sb, __FUNCTION__, ext4_error(sb, __FUNCTION__,
"bit already cleared for block "E3FSBLK, "bit already cleared for block "E3FSBLK,
block + i); (ext4_fsblk_t)(block + i));
jbd_lock_bh_state(bitmap_bh); jbd_lock_bh_state(bitmap_bh);
BUFFER_TRACE(bitmap_bh, "bit already cleared"); BUFFER_TRACE(bitmap_bh, "bit already cleared");
} else { } else {
...@@ -1351,7 +1351,7 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi) ...@@ -1351,7 +1351,7 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi)
ext4_fsblk_t free_blocks, root_blocks; ext4_fsblk_t free_blocks, root_blocks;
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); root_blocks = ext4_r_blocks_count(sbi->s_es);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
sbi->s_resuid != current->fsuid && sbi->s_resuid != current->fsuid &&
(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
...@@ -1462,7 +1462,7 @@ ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, ...@@ -1462,7 +1462,7 @@ ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
* First, test whether the goal block is free. * First, test whether the goal block is free.
*/ */
if (goal < le32_to_cpu(es->s_first_data_block) || if (goal < le32_to_cpu(es->s_first_data_block) ||
goal >= le32_to_cpu(es->s_blocks_count)) goal >= ext4_blocks_count(es))
goal = le32_to_cpu(es->s_first_data_block); goal = le32_to_cpu(es->s_first_data_block);
ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk); ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk);
goal_group = group_no; goal_group = group_no;
...@@ -1561,12 +1561,12 @@ allocated: ...@@ -1561,12 +1561,12 @@ allocated:
ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no); ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || if (in_range(ext4_block_bitmap(gdp), ret_block, num) ||
in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || in_range(ext4_block_bitmap(gdp), ret_block, num) ||
in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), in_range(ret_block, ext4_inode_table(gdp),
EXT4_SB(sb)->s_itb_per_group) || EXT4_SB(sb)->s_itb_per_group) ||
in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), in_range(ret_block + num - 1, ext4_inode_table(gdp),
EXT4_SB(sb)->s_itb_per_group)) EXT4_SB(sb)->s_itb_per_group))
ext4_error(sb, "ext4_new_block", ext4_error(sb, "ext4_new_block",
"Allocating block in system zone - " "Allocating block in system zone - "
"blocks from "E3FSBLK", length %lu", "blocks from "E3FSBLK", length %lu",
...@@ -1604,11 +1604,11 @@ allocated: ...@@ -1604,11 +1604,11 @@ allocated:
jbd_unlock_bh_state(bitmap_bh); jbd_unlock_bh_state(bitmap_bh);
#endif #endif
if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { if (ret_block + num - 1 >= ext4_blocks_count(es)) {
ext4_error(sb, "ext4_new_block", ext4_error(sb, "ext4_new_block",
"block("E3FSBLK") >= blocks count(%d) - " "block("E3FSBLK") >= blocks count("E3FSBLK") - "
"block_group = %lu, es == %p ", ret_block, "block_group = %lu, es == %p ", ret_block,
le32_to_cpu(es->s_blocks_count), group_no, es); ext4_blocks_count(es), group_no, es);
goto out; goto out;
} }
...@@ -1707,7 +1707,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) ...@@ -1707,7 +1707,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
brelse(bitmap_bh); brelse(bitmap_bh);
printk("ext4_count_free_blocks: stored = "E3FSBLK printk("ext4_count_free_blocks: stored = "E3FSBLK
", computed = "E3FSBLK", "E3FSBLK"\n", ", computed = "E3FSBLK", "E3FSBLK"\n",
le32_to_cpu(es->s_free_blocks_count), EXT4_FREE_BLOCKS_COUNT(es),
desc_count, bitmap_count); desc_count, bitmap_count);
return bitmap_count; return bitmap_count;
#else #else
......
...@@ -60,12 +60,12 @@ read_inode_bitmap(struct super_block * sb, unsigned long block_group) ...@@ -60,12 +60,12 @@ read_inode_bitmap(struct super_block * sb, unsigned long block_group)
if (!desc) if (!desc)
goto error_out; goto error_out;
bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); bh = sb_bread(sb, ext4_inode_bitmap(desc));
if (!bh) if (!bh)
ext4_error(sb, "read_inode_bitmap", ext4_error(sb, "read_inode_bitmap",
"Cannot read inode bitmap - " "Cannot read inode bitmap - "
"block_group = %lu, inode_bitmap = %u", "block_group = %lu, inode_bitmap = %llu",
block_group, le32_to_cpu(desc->bg_inode_bitmap)); block_group, ext4_inode_bitmap(desc));
error_out: error_out:
return bh; return bh;
} }
...@@ -304,7 +304,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ...@@ -304,7 +304,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
goto fallback; goto fallback;
} }
blocks_per_dir = le32_to_cpu(es->s_blocks_count) - freeb; blocks_per_dir = ext4_blocks_count(es) - freeb;
sector_div(blocks_per_dir, ndirs); sector_div(blocks_per_dir, ndirs);
max_dirs = ndirs / ngroups + inodes_per_group / 16; max_dirs = ndirs / ngroups + inodes_per_group / 16;
......
...@@ -2438,8 +2438,8 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, ...@@ -2438,8 +2438,8 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
*/ */
offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) * offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
EXT4_INODE_SIZE(sb); EXT4_INODE_SIZE(sb);
block = le32_to_cpu(gdp[desc].bg_inode_table) + block = ext4_inode_table(gdp + desc) +
(offset >> EXT4_BLOCK_SIZE_BITS(sb)); (offset >> EXT4_BLOCK_SIZE_BITS(sb));
iloc->block_group = block_group; iloc->block_group = block_group;
iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1); iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1);
...@@ -2506,7 +2506,7 @@ static int __ext4_get_inode_loc(struct inode *inode, ...@@ -2506,7 +2506,7 @@ static int __ext4_get_inode_loc(struct inode *inode,
goto make_io; goto make_io;
bitmap_bh = sb_getblk(inode->i_sb, bitmap_bh = sb_getblk(inode->i_sb,
le32_to_cpu(desc->bg_inode_bitmap)); ext4_inode_bitmap(desc));
if (!bitmap_bh) if (!bitmap_bh)
goto make_io; goto make_io;
......
...@@ -27,7 +27,7 @@ static int verify_group_input(struct super_block *sb, ...@@ -27,7 +27,7 @@ static int verify_group_input(struct super_block *sb,
{ {
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es; struct ext4_super_block *es = sbi->s_es;
ext4_fsblk_t start = le32_to_cpu(es->s_blocks_count); ext4_fsblk_t start = ext4_blocks_count(es);
ext4_fsblk_t end = start + input->blocks_count; ext4_fsblk_t end = start + input->blocks_count;
unsigned group = input->group; unsigned group = input->group;
ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
...@@ -68,43 +68,43 @@ static int verify_group_input(struct super_block *sb, ...@@ -68,43 +68,43 @@ static int verify_group_input(struct super_block *sb,
end - 1); end - 1);
else if (outside(input->block_bitmap, start, end)) else if (outside(input->block_bitmap, start, end))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Block bitmap not in group (block %u)", "Block bitmap not in group (block %llu)",
input->block_bitmap); input->block_bitmap);
else if (outside(input->inode_bitmap, start, end)) else if (outside(input->inode_bitmap, start, end))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Inode bitmap not in group (block %u)", "Inode bitmap not in group (block %llu)",
input->inode_bitmap); input->inode_bitmap);
else if (outside(input->inode_table, start, end) || else if (outside(input->inode_table, start, end) ||
outside(itend - 1, start, end)) outside(itend - 1, start, end))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Inode table not in group (blocks %u-"E3FSBLK")", "Inode table not in group (blocks %llu-%llu)",
input->inode_table, itend - 1); input->inode_table, itend - 1);
else if (input->inode_bitmap == input->block_bitmap) else if (input->inode_bitmap == input->block_bitmap)
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Block bitmap same as inode bitmap (%u)", "Block bitmap same as inode bitmap (%llu)",
input->block_bitmap); input->block_bitmap);
else if (inside(input->block_bitmap, input->inode_table, itend)) else if (inside(input->block_bitmap, input->inode_table, itend))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Block bitmap (%u) in inode table (%u-"E3FSBLK")", "Block bitmap (%llu) in inode table (%llu-%llu)",
input->block_bitmap, input->inode_table, itend-1); input->block_bitmap, input->inode_table, itend-1);
else if (inside(input->inode_bitmap, input->inode_table, itend)) else if (inside(input->inode_bitmap, input->inode_table, itend))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Inode bitmap (%u) in inode table (%u-"E3FSBLK")", "Inode bitmap (%llu) in inode table (%llu-%llu)",
input->inode_bitmap, input->inode_table, itend-1); input->inode_bitmap, input->inode_table, itend-1);
else if (inside(input->block_bitmap, start, metaend)) else if (inside(input->block_bitmap, start, metaend))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Block bitmap (%u) in GDT table" "Block bitmap (%llu) in GDT table"
" ("E3FSBLK"-"E3FSBLK")", " ("E3FSBLK"-"E3FSBLK")",
input->block_bitmap, start, metaend - 1); input->block_bitmap, start, metaend - 1);
else if (inside(input->inode_bitmap, start, metaend)) else if (inside(input->inode_bitmap, start, metaend))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Inode bitmap (%u) in GDT table" "Inode bitmap (%llu) in GDT table"
" ("E3FSBLK"-"E3FSBLK")", " ("E3FSBLK"-"E3FSBLK")",
input->inode_bitmap, start, metaend - 1); input->inode_bitmap, start, metaend - 1);
else if (inside(input->inode_table, start, metaend) || else if (inside(input->inode_table, start, metaend) ||
inside(itend - 1, start, metaend)) inside(itend - 1, start, metaend))
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"Inode table (%u-"E3FSBLK") overlaps" "Inode table ("E3FSBLK"-"E3FSBLK") overlaps"
"GDT table ("E3FSBLK"-"E3FSBLK")", "GDT table ("E3FSBLK"-"E3FSBLK")",
input->inode_table, itend - 1, start, metaend - 1); input->inode_table, itend - 1, start, metaend - 1);
else else
...@@ -286,6 +286,7 @@ exit_journal: ...@@ -286,6 +286,7 @@ exit_journal:
return err; return err;
} }
/* /*
* Iterate through the groups which hold BACKUP superblock/GDT copies in an * Iterate through the groups which hold BACKUP superblock/GDT copies in an
* ext4 filesystem. The counters should be initialized to 1, 5, and 7 before * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before
...@@ -340,12 +341,15 @@ static int verify_reserved_gdb(struct super_block *sb, ...@@ -340,12 +341,15 @@ static int verify_reserved_gdb(struct super_block *sb,
int gdbackups = 0; int gdbackups = 0;
while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) { while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) {
if (le32_to_cpu(*p++) != grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ if (le32_to_cpu(*p++) !=
grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"reserved GDT "E3FSBLK "reserved GDT "E3FSBLK
" missing grp %d ("E3FSBLK")", " missing grp %d ("E3FSBLK")",
blk, grp, blk, grp,
grp * EXT4_BLOCKS_PER_GROUP(sb) + blk); grp *
(ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +
blk);
return -EINVAL; return -EINVAL;
} }
if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb)) if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb))
...@@ -731,8 +735,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ...@@ -731,8 +735,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
return -EPERM; return -EPERM;
} }
if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < if (ext4_blocks_count(es) + input->blocks_count <
le32_to_cpu(es->s_blocks_count)) { ext4_blocks_count(es)) {
ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n"); ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n");
return -EINVAL; return -EINVAL;
} }
...@@ -830,9 +834,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ...@@ -830,9 +834,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
/* Update group descriptor block for new group */ /* Update group descriptor block for new group */
gdp = (struct ext4_group_desc *)primary->b_data + gdb_off; gdp = (struct ext4_group_desc *)primary->b_data + gdb_off;
gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); ext4_block_bitmap_set(gdp, input->block_bitmap); /* LV FIXME */
gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); ext4_inode_bitmap_set(gdp, input->inode_bitmap); /* LV FIXME */
gdp->bg_inode_table = cpu_to_le32(input->inode_table); ext4_inode_table_set(gdp, input->inode_table); /* LV FIXME */
gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb));
...@@ -846,7 +850,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ...@@ -846,7 +850,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
* blocks/inodes before the group is live won't actually let us * blocks/inodes before the group is live won't actually let us
* allocate the new space yet. * allocate the new space yet.
*/ */
es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) + ext4_blocks_count_set(es, ext4_blocks_count(es) +
input->blocks_count); input->blocks_count);
es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +
EXT4_INODES_PER_GROUP(sb)); EXT4_INODES_PER_GROUP(sb));
...@@ -882,7 +886,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ...@@ -882,7 +886,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
/* Update the reserved block counts only once the new group is /* Update the reserved block counts only once the new group is
* active. */ * active. */
es->s_r_blocks_count = cpu_to_le32(le32_to_cpu(es->s_r_blocks_count) + ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
input->reserved_blocks); input->reserved_blocks);
/* Update the free space counts */ /* Update the free space counts */
...@@ -933,7 +937,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ...@@ -933,7 +937,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
/* We don't need to worry about locking wrt other resizers just /* We don't need to worry about locking wrt other resizers just
* yet: we're going to revalidate es->s_blocks_count after * yet: we're going to revalidate es->s_blocks_count after
* taking lock_super() below. */ * taking lock_super() below. */
o_blocks_count = le32_to_cpu(es->s_blocks_count); o_blocks_count = ext4_blocks_count(es);
o_groups_count = EXT4_SB(sb)->s_groups_count; o_groups_count = EXT4_SB(sb)->s_groups_count;
if (test_opt(sb, DEBUG)) if (test_opt(sb, DEBUG))
...@@ -1004,7 +1008,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ...@@ -1004,7 +1008,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
} }
lock_super(sb); lock_super(sb);
if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { if (o_blocks_count != ext4_blocks_count(es)) {
ext4_warning(sb, __FUNCTION__, ext4_warning(sb, __FUNCTION__,
"multiple resizers run on filesystem!"); "multiple resizers run on filesystem!");
unlock_super(sb); unlock_super(sb);
...@@ -1020,7 +1024,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ...@@ -1020,7 +1024,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
ext4_journal_stop(handle); ext4_journal_stop(handle);
goto exit_put; goto exit_put;
} }
es->s_blocks_count = cpu_to_le32(o_blocks_count + add); ext4_blocks_count_set(es, o_blocks_count + add);
ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
sb->s_dirt = 1; sb->s_dirt = 1;
unlock_super(sb); unlock_super(sb);
...@@ -1032,8 +1036,8 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ...@@ -1032,8 +1036,8 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
if ((err = ext4_journal_stop(handle))) if ((err = ext4_journal_stop(handle)))
goto exit_put; goto exit_put;
if (test_opt(sb, DEBUG)) if (test_opt(sb, DEBUG))
printk(KERN_DEBUG "EXT4-fs: extended group to %u blocks\n", printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n",
le32_to_cpu(es->s_blocks_count)); ext4_blocks_count(es));
update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es, update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es,
sizeof(struct ext4_super_block)); sizeof(struct ext4_super_block));
exit_put: exit_put:
......
...@@ -62,6 +62,43 @@ static void ext4_unlockfs(struct super_block *sb); ...@@ -62,6 +62,43 @@ static void ext4_unlockfs(struct super_block *sb);
static void ext4_write_super (struct super_block * sb); static void ext4_write_super (struct super_block * sb);
static void ext4_write_super_lockfs(struct super_block *sb); static void ext4_write_super_lockfs(struct super_block *sb);
ext4_fsblk_t ext4_block_bitmap(struct ext4_group_desc *bg)
{
return le32_to_cpu(bg->bg_block_bitmap) |
((ext4_fsblk_t)le16_to_cpu(bg->bg_block_bitmap_hi) << 32);
}
ext4_fsblk_t ext4_inode_bitmap(struct ext4_group_desc *bg)
{
return le32_to_cpu(bg->bg_inode_bitmap) |
((ext4_fsblk_t)le16_to_cpu(bg->bg_inode_bitmap_hi) << 32);
}
ext4_fsblk_t ext4_inode_table(struct ext4_group_desc *bg)
{
return le32_to_cpu(bg->bg_inode_table) |
((ext4_fsblk_t)le16_to_cpu(bg->bg_inode_table_hi) << 32);
}
void ext4_block_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk)
{
bg->bg_block_bitmap = cpu_to_le32((u32)blk);
bg->bg_block_bitmap_hi = cpu_to_le16(blk >> 32);
}
void ext4_inode_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk)
{
bg->bg_inode_bitmap = cpu_to_le32((u32)blk);
bg->bg_inode_bitmap_hi = cpu_to_le16(blk >> 32);
}
void ext4_inode_table_set(struct ext4_group_desc *bg, ext4_fsblk_t blk)
{
bg->bg_inode_table = cpu_to_le32((u32)blk);
bg->bg_inode_table_hi = cpu_to_le16(blk >> 32);
}
/* /*
* Wrappers for jbd2_journal_start/end. * Wrappers for jbd2_journal_start/end.
* *
...@@ -1182,6 +1219,9 @@ static int ext4_check_descriptors (struct super_block * sb) ...@@ -1182,6 +1219,9 @@ static int ext4_check_descriptors (struct super_block * sb)
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
ext4_fsblk_t last_block; ext4_fsblk_t last_block;
ext4_fsblk_t block_bitmap;
ext4_fsblk_t inode_bitmap;
ext4_fsblk_t inode_table;
struct ext4_group_desc * gdp = NULL; struct ext4_group_desc * gdp = NULL;
int desc_block = 0; int desc_block = 0;
int i; int i;
...@@ -1191,7 +1231,7 @@ static int ext4_check_descriptors (struct super_block * sb) ...@@ -1191,7 +1231,7 @@ static int ext4_check_descriptors (struct super_block * sb)
for (i = 0; i < sbi->s_groups_count; i++) for (i = 0; i < sbi->s_groups_count; i++)
{ {
if (i == sbi->s_groups_count - 1) if (i == sbi->s_groups_count - 1)
last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; last_block = ext4_blocks_count(sbi->s_es) - 1;
else else
last_block = first_block + last_block = first_block +
(EXT4_BLOCKS_PER_GROUP(sb) - 1); (EXT4_BLOCKS_PER_GROUP(sb) - 1);
...@@ -1199,42 +1239,39 @@ static int ext4_check_descriptors (struct super_block * sb) ...@@ -1199,42 +1239,39 @@ static int ext4_check_descriptors (struct super_block * sb)
if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0) if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
gdp = (struct ext4_group_desc *) gdp = (struct ext4_group_desc *)
sbi->s_group_desc[desc_block++]->b_data; sbi->s_group_desc[desc_block++]->b_data;
if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || block_bitmap = ext4_block_bitmap(gdp);
le32_to_cpu(gdp->bg_block_bitmap) > last_block) if (block_bitmap < first_block || block_bitmap > last_block)
{ {
ext4_error (sb, "ext4_check_descriptors", ext4_error (sb, "ext4_check_descriptors",
"Block bitmap for group %d" "Block bitmap for group %d"
" not in group (block %lu)!", " not in group (block "E3FSBLK")!",
i, (unsigned long) i, block_bitmap);
le32_to_cpu(gdp->bg_block_bitmap));
return 0; return 0;
} }
if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || inode_bitmap = ext4_inode_bitmap(gdp);
le32_to_cpu(gdp->bg_inode_bitmap) > last_block) if (inode_bitmap < first_block || inode_bitmap > last_block)
{ {
ext4_error (sb, "ext4_check_descriptors", ext4_error (sb, "ext4_check_descriptors",
"Inode bitmap for group %d" "Inode bitmap for group %d"
" not in group (block %lu)!", " not in group (block "E3FSBLK")!",
i, (unsigned long) i, inode_bitmap);
le32_to_cpu(gdp->bg_inode_bitmap));
return 0; return 0;
} }
if (le32_to_cpu(gdp->bg_inode_table) < first_block || inode_table = ext4_inode_table(gdp);
le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > if (inode_table < first_block ||
last_block) inode_table + sbi->s_itb_per_group > last_block)
{ {
ext4_error (sb, "ext4_check_descriptors", ext4_error (sb, "ext4_check_descriptors",
"Inode table for group %d" "Inode table for group %d"
" not in group (block %lu)!", " not in group (block "E3FSBLK")!",
i, (unsigned long) i, inode_table);
le32_to_cpu(gdp->bg_inode_table));
return 0; return 0;
} }
first_block += EXT4_BLOCKS_PER_GROUP(sb); first_block += EXT4_BLOCKS_PER_GROUP(sb);
gdp++; gdp++;
} }
sbi->s_es->s_free_blocks_count=cpu_to_le32(ext4_count_free_blocks(sb)); ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb)); sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb));
return 1; return 1;
} }
...@@ -1411,6 +1448,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) ...@@ -1411,6 +1448,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
int i; int i;
int needs_recovery; int needs_recovery;
__le32 features; __le32 features;
__u64 blocks_count;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi) if (!sbi)
...@@ -1620,7 +1658,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) ...@@ -1620,7 +1658,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
} }
if (le32_to_cpu(es->s_blocks_count) > if (ext4_blocks_count(es) >
(sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
printk(KERN_ERR "EXT4-fs: filesystem on %s:" printk(KERN_ERR "EXT4-fs: filesystem on %s:"
" too large to mount safely\n", sb->s_id); " too large to mount safely\n", sb->s_id);
...@@ -1632,9 +1670,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) ...@@ -1632,9 +1670,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
if (EXT4_BLOCKS_PER_GROUP(sb) == 0) if (EXT4_BLOCKS_PER_GROUP(sb) == 0)
goto cantfind_ext4; goto cantfind_ext4;
sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - blocks_count = (ext4_blocks_count(es) -
le32_to_cpu(es->s_first_data_block) - 1) le32_to_cpu(es->s_first_data_block) +
/ EXT4_BLOCKS_PER_GROUP(sb)) + 1; EXT4_BLOCKS_PER_GROUP(sb) - 1);
do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
sbi->s_groups_count = blocks_count;
db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
EXT4_DESC_PER_BLOCK(sb); EXT4_DESC_PER_BLOCK(sb);
sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
...@@ -1949,7 +1989,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, ...@@ -1949,7 +1989,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
goto out_bdev; goto out_bdev;
} }
len = le32_to_cpu(es->s_blocks_count); len = ext4_blocks_count(es);
start = sb_block + 1; start = sb_block + 1;
brelse(bh); /* we're done with the superblock */ brelse(bh); /* we're done with the superblock */
...@@ -2119,7 +2159,7 @@ static void ext4_commit_super (struct super_block * sb, ...@@ -2119,7 +2159,7 @@ static void ext4_commit_super (struct super_block * sb,
if (!sbh) if (!sbh)
return; return;
es->s_wtime = cpu_to_le32(get_seconds()); es->s_wtime = cpu_to_le32(get_seconds());
es->s_free_blocks_count = cpu_to_le32(ext4_count_free_blocks(sb)); ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb));
es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
BUFFER_TRACE(sbh, "marking dirty"); BUFFER_TRACE(sbh, "marking dirty");
mark_buffer_dirty(sbh); mark_buffer_dirty(sbh);
...@@ -2312,7 +2352,7 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) ...@@ -2312,7 +2352,7 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data)
ext4_init_journal_params(sb, sbi->s_journal); ext4_init_journal_params(sb, sbi->s_journal);
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
n_blocks_count > le32_to_cpu(es->s_blocks_count)) { n_blocks_count > ext4_blocks_count(es)) {
if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) { if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) {
err = -EROFS; err = -EROFS;
goto restore_opts; goto restore_opts;
...@@ -2431,10 +2471,10 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) ...@@ -2431,10 +2471,10 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
buf->f_type = EXT4_SUPER_MAGIC; buf->f_type = EXT4_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; buf->f_blocks = ext4_blocks_count(es) - overhead;
buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) if (buf->f_bfree < ext4_r_blocks_count(es))
buf->f_bavail = 0; buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count); buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
......
...@@ -128,10 +128,17 @@ struct ext4_group_desc ...@@ -128,10 +128,17 @@ struct ext4_group_desc
__le16 bg_free_blocks_count; /* Free blocks count */ __le16 bg_free_blocks_count; /* Free blocks count */
__le16 bg_free_inodes_count; /* Free inodes count */ __le16 bg_free_inodes_count; /* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */ __le16 bg_used_dirs_count; /* Directories count */
__u16 bg_pad; __u16 bg_flags;
__le32 bg_reserved[3]; __le16 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
__le16 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
__le16 bg_inode_table_hi; /* Inodes table block MSB */
__u16 bg_reserved[3];
}; };
#ifdef __KERNEL__
#include <linux/ext4_fs_i.h>
#include <linux/ext4_fs_sb.h>
#endif
/* /*
* Macro-instructions used to manage group descriptors * Macro-instructions used to manage group descriptors
*/ */
...@@ -194,9 +201,9 @@ struct ext4_group_desc ...@@ -194,9 +201,9 @@ struct ext4_group_desc
/* Used to pass group descriptor data when online resize is done */ /* Used to pass group descriptor data when online resize is done */
struct ext4_new_group_input { struct ext4_new_group_input {
__u32 group; /* Group number for this data */ __u32 group; /* Group number for this data */
__u32 block_bitmap; /* Absolute block number of block bitmap */ __u64 block_bitmap; /* Absolute block number of block bitmap */
__u32 inode_bitmap; /* Absolute block number of inode bitmap */ __u64 inode_bitmap; /* Absolute block number of inode bitmap */
__u32 inode_table; /* Absolute block number of inode table start */ __u64 inode_table; /* Absolute block number of inode table start */
__u32 blocks_count; /* Total number of blocks in this group */ __u32 blocks_count; /* Total number of blocks in this group */
__u16 reserved_blocks; /* Number of reserved blocks in this group */ __u16 reserved_blocks; /* Number of reserved blocks in this group */
__u16 unused; __u16 unused;
...@@ -205,9 +212,9 @@ struct ext4_new_group_input { ...@@ -205,9 +212,9 @@ struct ext4_new_group_input {
/* The struct ext4_new_group_input in kernel space, with free_blocks_count */ /* The struct ext4_new_group_input in kernel space, with free_blocks_count */
struct ext4_new_group_data { struct ext4_new_group_data {
__u32 group; __u32 group;
__u32 block_bitmap; __u64 block_bitmap;
__u32 inode_bitmap; __u64 inode_bitmap;
__u32 inode_table; __u64 inode_table;
__u32 blocks_count; __u32 blocks_count;
__u16 reserved_blocks; __u16 reserved_blocks;
__u16 unused; __u16 unused;
...@@ -494,14 +501,18 @@ struct ext4_super_block { ...@@ -494,14 +501,18 @@ struct ext4_super_block {
__u8 s_def_hash_version; /* Default hash version to use */ __u8 s_def_hash_version; /* Default hash version to use */
__u8 s_reserved_char_pad; __u8 s_reserved_char_pad;
__u16 s_reserved_word_pad; __u16 s_reserved_word_pad;
__le32 s_default_mount_opts; /*100*/ __le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */ __le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */ __le32 s_mkfs_time; /* When the filesystem was created */
__le32 s_jnl_blocks[17]; /* Backup of the journal inode */
/* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
/*150*/ __le32 s_blocks_count_hi; /* Blocks count */
__le32 s_r_blocks_count_hi; /* Reserved blocks count */
__le32 s_free_blocks_count_hi; /* Free blocks count */
__u32 s_reserved[169]; /* Padding to the end of the block */
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/ext4_fs_i.h>
#include <linux/ext4_fs_sb.h>
static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb) static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb)
{ {
return sb->s_fs_info; return sb->s_fs_info;
...@@ -588,12 +599,14 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) ...@@ -588,12 +599,14 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ #define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR #define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ #define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
EXT4_FEATURE_INCOMPAT_RECOVER| \ EXT4_FEATURE_INCOMPAT_RECOVER| \
EXT4_FEATURE_INCOMPAT_META_BG| \ EXT4_FEATURE_INCOMPAT_META_BG| \
EXT4_FEATURE_INCOMPAT_EXTENTS) EXT4_FEATURE_INCOMPAT_EXTENTS| \
EXT4_FEATURE_INCOMPAT_64BIT)
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT4_FEATURE_RO_COMPAT_BTREE_DIR) EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
...@@ -888,6 +901,53 @@ extern void ext4_abort (struct super_block *, const char *, const char *, ...) ...@@ -888,6 +901,53 @@ extern void ext4_abort (struct super_block *, const char *, const char *, ...)
extern void ext4_warning (struct super_block *, const char *, const char *, ...) extern void ext4_warning (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4))); __attribute__ ((format (printf, 3, 4)));
extern void ext4_update_dynamic_rev (struct super_block *sb); extern void ext4_update_dynamic_rev (struct super_block *sb);
extern ext4_fsblk_t ext4_block_bitmap(struct ext4_group_desc *bg);
extern ext4_fsblk_t ext4_inode_bitmap(struct ext4_group_desc *bg);
extern ext4_fsblk_t ext4_inode_table(struct ext4_group_desc *bg);
extern void ext4_block_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk);
extern void ext4_inode_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk);
extern void ext4_inode_table_set(struct ext4_group_desc *bg, ext4_fsblk_t blk);
static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
{
return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
le32_to_cpu(es->s_blocks_count);
}
static inline ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
{
return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
le32_to_cpu(es->s_r_blocks_count);
}
static inline ext4_fsblk_t ext4_free_blocks_count(struct ext4_super_block *es)
{
return ((ext4_fsblk_t)le32_to_cpu(es->s_free_blocks_count_hi) << 32) |
le32_to_cpu(es->s_free_blocks_count);
}
static inline void ext4_blocks_count_set(struct ext4_super_block *es,
ext4_fsblk_t blk)
{
es->s_blocks_count = cpu_to_le32((u32)blk);
es->s_blocks_count_hi = cpu_to_le32(blk >> 32);
}
static inline void ext4_free_blocks_count_set(struct ext4_super_block *es,
ext4_fsblk_t blk)
{
es->s_free_blocks_count = cpu_to_le32((u32)blk);
es->s_free_blocks_count_hi = cpu_to_le32(blk >> 32);
}
static inline void ext4_r_blocks_count_set(struct ext4_super_block *es,
ext4_fsblk_t blk)
{
es->s_r_blocks_count = cpu_to_le32((u32)blk);
es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32);
}
#define ext4_std_error(sb, errno) \ #define ext4_std_error(sb, errno) \
do { \ do { \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment