aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2012-09-05 01:29:50 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-09-05 01:29:50 -0400
commit117fff10d7f140e12dd43df20d3f9fda80577460 (patch)
tree0236d1dfb77e794b1628b723f21b3c83383e0475
parent2ebd1704ded88a8ae29b5f3998b13959c715c4be (diff)
ext4: grow the s_flex_groups array as needed when resizing
Previously, we allocated the s_flex_groups array to the maximum size that the file system could be resized. There was two problems with this approach. First, it wasted memory in the common case where the file system was not resized. Secondly, once we start allowing online resizing using the meta_bg scheme, there is no maximum size that the file system can be resized. So instead, we need to grow the s_flex_groups at inline resize time. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/resize.c14
-rw-r--r--fs/ext4/super.c48
3 files changed, 47 insertions, 18 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0df5ee102b61..464cff711ed6 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1276,6 +1276,7 @@ struct ext4_sb_info {
1276 1276
1277 unsigned int s_log_groups_per_flex; 1277 unsigned int s_log_groups_per_flex;
1278 struct flex_groups *s_flex_groups; 1278 struct flex_groups *s_flex_groups;
1279 ext4_group_t s_flex_groups_allocated;
1279 1280
1280 /* workqueue for dio unwritten */ 1281 /* workqueue for dio unwritten */
1281 struct workqueue_struct *dio_unwritten_wq; 1282 struct workqueue_struct *dio_unwritten_wq;
@@ -2055,6 +2056,8 @@ extern void ext4_superblock_csum_set(struct super_block *sb,
2055extern void *ext4_kvmalloc(size_t size, gfp_t flags); 2056extern void *ext4_kvmalloc(size_t size, gfp_t flags);
2056extern void *ext4_kvzalloc(size_t size, gfp_t flags); 2057extern void *ext4_kvzalloc(size_t size, gfp_t flags);
2057extern void ext4_kvfree(void *ptr); 2058extern void ext4_kvfree(void *ptr);
2059extern int ext4_alloc_flex_bg_array(struct super_block *sb,
2060 ext4_group_t ngroup);
2058extern __printf(4, 5) 2061extern __printf(4, 5)
2059void __ext4_error(struct super_block *, const char *, unsigned int, 2062void __ext4_error(struct super_block *, const char *, unsigned int,
2060 const char *, ...); 2063 const char *, ...);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 365d800ff8c1..3f5c67bf13a2 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1503,6 +1503,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
1503 if (err) 1503 if (err)
1504 goto out; 1504 goto out;
1505 1505
1506 err = ext4_alloc_flex_bg_array(sb, input->group + 1);
1507 if (err)
1508 return err;
1509
1506 flex_gd.count = 1; 1510 flex_gd.count = 1;
1507 flex_gd.groups = input; 1511 flex_gd.groups = input;
1508 flex_gd.bg_flags = &bg_flags; 1512 flex_gd.bg_flags = &bg_flags;
@@ -1662,7 +1666,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1662 unsigned long n_desc_blocks; 1666 unsigned long n_desc_blocks;
1663 unsigned long o_desc_blocks; 1667 unsigned long o_desc_blocks;
1664 unsigned long desc_blocks; 1668 unsigned long desc_blocks;
1665 int err = 0, flexbg_size = 1; 1669 int err = 0, flexbg_size = 1 << sbi->s_log_groups_per_flex;
1666 1670
1667 o_blocks_count = ext4_blocks_count(es); 1671 o_blocks_count = ext4_blocks_count(es);
1668 1672
@@ -1721,13 +1725,13 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1721 goto out; 1725 goto out;
1722 } 1726 }
1723 1727
1724 if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
1725 es->s_log_groups_per_flex)
1726 flexbg_size = 1 << es->s_log_groups_per_flex;
1727
1728 if (ext4_blocks_count(es) == n_blocks_count) 1728 if (ext4_blocks_count(es) == n_blocks_count)
1729 goto out; 1729 goto out;
1730 1730
1731 err = ext4_alloc_flex_bg_array(sb, n_group + 1);
1732 if (err)
1733 return err;
1734
1731 flex_gd = alloc_flex_gd(flexbg_size); 1735 flex_gd = alloc_flex_gd(flexbg_size);
1732 if (flex_gd == NULL) { 1736 if (flex_gd == NULL) {
1733 err = -ENOMEM; 1737 err = -ENOMEM;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b875ff555865..b8de488889d6 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1925,15 +1925,45 @@ done:
1925 return res; 1925 return res;
1926} 1926}
1927 1927
1928int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
1929{
1930 struct ext4_sb_info *sbi = EXT4_SB(sb);
1931 struct flex_groups *new_groups;
1932 int size;
1933
1934 if (!sbi->s_log_groups_per_flex)
1935 return 0;
1936
1937 size = ext4_flex_group(sbi, ngroup - 1) + 1;
1938 if (size <= sbi->s_flex_groups_allocated)
1939 return 0;
1940
1941 size = roundup_pow_of_two(size * sizeof(struct flex_groups));
1942 new_groups = ext4_kvzalloc(size, GFP_KERNEL);
1943 if (!new_groups) {
1944 ext4_msg(sb, KERN_ERR, "not enough memory for %d flex groups",
1945 size / (int) sizeof(struct flex_groups));
1946 return -ENOMEM;
1947 }
1948
1949 if (sbi->s_flex_groups) {
1950 memcpy(new_groups, sbi->s_flex_groups,
1951 (sbi->s_flex_groups_allocated *
1952 sizeof(struct flex_groups)));
1953 ext4_kvfree(sbi->s_flex_groups);
1954 }
1955 sbi->s_flex_groups = new_groups;
1956 sbi->s_flex_groups_allocated = size / sizeof(struct flex_groups);
1957 return 0;
1958}
1959
1928static int ext4_fill_flex_info(struct super_block *sb) 1960static int ext4_fill_flex_info(struct super_block *sb)
1929{ 1961{
1930 struct ext4_sb_info *sbi = EXT4_SB(sb); 1962 struct ext4_sb_info *sbi = EXT4_SB(sb);
1931 struct ext4_group_desc *gdp = NULL; 1963 struct ext4_group_desc *gdp = NULL;
1932 ext4_group_t flex_group_count;
1933 ext4_group_t flex_group; 1964 ext4_group_t flex_group;
1934 unsigned int groups_per_flex = 0; 1965 unsigned int groups_per_flex = 0;
1935 size_t size; 1966 int i, err;
1936 int i;
1937 1967
1938 sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; 1968 sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
1939 if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) { 1969 if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) {
@@ -1942,17 +1972,9 @@ static int ext4_fill_flex_info(struct super_block *sb)
1942 } 1972 }
1943 groups_per_flex = 1 << sbi->s_log_groups_per_flex; 1973 groups_per_flex = 1 << sbi->s_log_groups_per_flex;
1944 1974
1945 /* We allocate both existing and potentially added groups */ 1975 err = ext4_alloc_flex_bg_array(sb, sbi->s_groups_count);
1946 flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + 1976 if (err)
1947 ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) <<
1948 EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex;
1949 size = flex_group_count * sizeof(struct flex_groups);
1950 sbi->s_flex_groups = ext4_kvzalloc(size, GFP_KERNEL);
1951 if (sbi->s_flex_groups == NULL) {
1952 ext4_msg(sb, KERN_ERR, "not enough memory for %u flex groups",
1953 flex_group_count);
1954 goto failed; 1977 goto failed;
1955 }
1956 1978
1957 for (i = 0; i < sbi->s_groups_count; i++) { 1979 for (i = 0; i < sbi->s_groups_count; i++) {
1958 gdp = ext4_get_group_desc(sb, i, NULL); 1980 gdp = ext4_get_group_desc(sb, i, NULL);