Commit d77147ff authored by harshads's avatar harshads Committed by Theodore Ts'o

ext4: add support for online resizing with bigalloc

This patch adds support for online resizing on bigalloc file system by
implementing EXT4_IOC_RESIZE_FS ioctl. Old resize interfaces (add
block groups and extend last block group) are left untouched. Tests
performed with cluster sizes of 1, 2, 4 and 8 blocks (of size 4k) per
cluster. I will add these tests to xfstests.
Signed-off-by: default avatarHarshad Shirwadkar <harshads@google.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent d98bf8cd
...@@ -545,8 +545,8 @@ struct ext4_new_group_data { ...@@ -545,8 +545,8 @@ struct ext4_new_group_data {
__u64 inode_table; __u64 inode_table;
__u32 blocks_count; __u32 blocks_count;
__u16 reserved_blocks; __u16 reserved_blocks;
__u16 unused; __u16 mdata_blocks;
__u32 free_blocks_count; __u32 free_clusters_count;
}; };
/* Indexes used to index group tables in ext4_new_group_data */ /* Indexes used to index group tables in ext4_new_group_data */
......
...@@ -871,12 +871,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -871,12 +871,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int err = 0, err2 = 0; int err = 0, err2 = 0;
ext4_group_t o_group = EXT4_SB(sb)->s_groups_count; ext4_group_t o_group = EXT4_SB(sb)->s_groups_count;
if (ext4_has_feature_bigalloc(sb)) {
ext4_msg(sb, KERN_ERR,
"Online resizing not (yet) supported with bigalloc");
return -EOPNOTSUPP;
}
if (copy_from_user(&n_blocks_count, (__u64 __user *)arg, if (copy_from_user(&n_blocks_count, (__u64 __user *)arg,
sizeof(__u64))) { sizeof(__u64))) {
return -EFAULT; return -EFAULT;
......
...@@ -4994,8 +4994,11 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ...@@ -4994,8 +4994,11 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
struct ext4_group_desc *desc; struct ext4_group_desc *desc;
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_buddy e4b; struct ext4_buddy e4b;
int err = 0, ret, blk_free_count; int err = 0, ret, free_clusters_count;
ext4_grpblk_t blocks_freed; ext4_grpblk_t clusters_freed;
ext4_fsblk_t first_cluster = EXT4_B2C(sbi, block);
ext4_fsblk_t last_cluster = EXT4_B2C(sbi, block + count - 1);
unsigned long cluster_count = last_cluster - first_cluster + 1;
ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1); ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1);
...@@ -5007,8 +5010,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ...@@ -5007,8 +5010,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
* Check to see if we are freeing blocks across a group * Check to see if we are freeing blocks across a group
* boundary. * boundary.
*/ */
if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) { if (bit + cluster_count > EXT4_CLUSTERS_PER_GROUP(sb)) {
ext4_warning(sb, "too much blocks added to group %u", ext4_warning(sb, "too many blocks added to group %u",
block_group); block_group);
err = -EINVAL; err = -EINVAL;
goto error_return; goto error_return;
...@@ -5054,14 +5057,14 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ...@@ -5054,14 +5057,14 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
if (err) if (err)
goto error_return; goto error_return;
for (i = 0, blocks_freed = 0; i < count; i++) { for (i = 0, clusters_freed = 0; i < cluster_count; i++) {
BUFFER_TRACE(bitmap_bh, "clear bit"); BUFFER_TRACE(bitmap_bh, "clear bit");
if (!mb_test_bit(bit + i, bitmap_bh->b_data)) { if (!mb_test_bit(bit + i, bitmap_bh->b_data)) {
ext4_error(sb, "bit already cleared for block %llu", ext4_error(sb, "bit already cleared for block %llu",
(ext4_fsblk_t)(block + i)); (ext4_fsblk_t)(block + i));
BUFFER_TRACE(bitmap_bh, "bit already cleared"); BUFFER_TRACE(bitmap_bh, "bit already cleared");
} else { } else {
blocks_freed++; clusters_freed++;
} }
} }
...@@ -5075,19 +5078,20 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ...@@ -5075,19 +5078,20 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
* them with group lock_held * them with group lock_held
*/ */
ext4_lock_group(sb, block_group); ext4_lock_group(sb, block_group);
mb_clear_bits(bitmap_bh->b_data, bit, count); mb_clear_bits(bitmap_bh->b_data, bit, cluster_count);
mb_free_blocks(NULL, &e4b, bit, count); mb_free_blocks(NULL, &e4b, bit, cluster_count);
blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); free_clusters_count = clusters_freed +
ext4_free_group_clusters_set(sb, desc, blk_free_count); ext4_free_group_clusters(sb, desc);
ext4_free_group_clusters_set(sb, desc, free_clusters_count);
ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh); ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh);
ext4_group_desc_csum_set(sb, block_group, desc); ext4_group_desc_csum_set(sb, block_group, desc);
ext4_unlock_group(sb, block_group); ext4_unlock_group(sb, block_group);
percpu_counter_add(&sbi->s_freeclusters_counter, percpu_counter_add(&sbi->s_freeclusters_counter,
EXT4_NUM_B2C(sbi, blocks_freed)); clusters_freed);
if (sbi->s_log_groups_per_flex) { if (sbi->s_log_groups_per_flex) {
ext4_group_t flex_group = ext4_flex_group(sbi, block_group); ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
atomic64_add(EXT4_NUM_B2C(sbi, blocks_freed), atomic64_add(clusters_freed,
&sbi->s_flex_groups[flex_group].free_clusters); &sbi->s_flex_groups[flex_group].free_clusters);
} }
......
This diff is collapsed.
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