diff options
-rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 79 | ||||
-rw-r--r-- | fs/ext4/resize.c | 8 |
3 files changed, 50 insertions, 40 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 464cff711ed6..8b6902c4d7be 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1233,6 +1233,7 @@ struct ext4_sb_info { | |||
1233 | spinlock_t s_md_lock; | 1233 | spinlock_t s_md_lock; |
1234 | unsigned short *s_mb_offsets; | 1234 | unsigned short *s_mb_offsets; |
1235 | unsigned int *s_mb_maxs; | 1235 | unsigned int *s_mb_maxs; |
1236 | unsigned int s_group_info_size; | ||
1236 | 1237 | ||
1237 | /* tunables */ | 1238 | /* tunables */ |
1238 | unsigned long s_stripe; | 1239 | unsigned long s_stripe; |
@@ -1971,6 +1972,8 @@ extern void ext4_exit_mballoc(void); | |||
1971 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, | 1972 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, |
1972 | struct buffer_head *bh, ext4_fsblk_t block, | 1973 | struct buffer_head *bh, ext4_fsblk_t block, |
1973 | unsigned long count, int flags); | 1974 | unsigned long count, int flags); |
1975 | extern int ext4_mb_alloc_groupinfo(struct super_block *sb, | ||
1976 | ext4_group_t ngroups); | ||
1974 | extern int ext4_mb_add_groupinfo(struct super_block *sb, | 1977 | extern int ext4_mb_add_groupinfo(struct super_block *sb, |
1975 | ext4_group_t i, struct ext4_group_desc *desc); | 1978 | ext4_group_t i, struct ext4_group_desc *desc); |
1976 | extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, | 1979 | extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 6873571c9f44..2102c20f7e98 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "ext4_jbd2.h" | 24 | #include "ext4_jbd2.h" |
25 | #include "mballoc.h" | 25 | #include "mballoc.h" |
26 | #include <linux/debugfs.h> | 26 | #include <linux/debugfs.h> |
27 | #include <linux/log2.h> | ||
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <trace/events/ext4.h> | 29 | #include <trace/events/ext4.h> |
29 | 30 | ||
@@ -2163,6 +2164,39 @@ static struct kmem_cache *get_groupinfo_cache(int blocksize_bits) | |||
2163 | return cachep; | 2164 | return cachep; |
2164 | } | 2165 | } |
2165 | 2166 | ||
2167 | /* | ||
2168 | * Allocate the top-level s_group_info array for the specified number | ||
2169 | * of groups | ||
2170 | */ | ||
2171 | int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups) | ||
2172 | { | ||
2173 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
2174 | unsigned size; | ||
2175 | struct ext4_group_info ***new_groupinfo; | ||
2176 | |||
2177 | size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >> | ||
2178 | EXT4_DESC_PER_BLOCK_BITS(sb); | ||
2179 | if (size <= sbi->s_group_info_size) | ||
2180 | return 0; | ||
2181 | |||
2182 | size = roundup_pow_of_two(sizeof(*sbi->s_group_info) * size); | ||
2183 | new_groupinfo = ext4_kvzalloc(size, GFP_KERNEL); | ||
2184 | if (!new_groupinfo) { | ||
2185 | ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group"); | ||
2186 | return -ENOMEM; | ||
2187 | } | ||
2188 | if (sbi->s_group_info) { | ||
2189 | memcpy(new_groupinfo, sbi->s_group_info, | ||
2190 | sbi->s_group_info_size * sizeof(*sbi->s_group_info)); | ||
2191 | ext4_kvfree(sbi->s_group_info); | ||
2192 | } | ||
2193 | sbi->s_group_info = new_groupinfo; | ||
2194 | sbi->s_group_info_size = size / sizeof(*sbi->s_group_info); | ||
2195 | ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", | ||
2196 | sbi->s_group_info_size); | ||
2197 | return 0; | ||
2198 | } | ||
2199 | |||
2166 | /* Create and initialize ext4_group_info data for the given group. */ | 2200 | /* Create and initialize ext4_group_info data for the given group. */ |
2167 | int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, | 2201 | int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, |
2168 | struct ext4_group_desc *desc) | 2202 | struct ext4_group_desc *desc) |
@@ -2252,49 +2286,14 @@ static int ext4_mb_init_backend(struct super_block *sb) | |||
2252 | ext4_group_t ngroups = ext4_get_groups_count(sb); | 2286 | ext4_group_t ngroups = ext4_get_groups_count(sb); |
2253 | ext4_group_t i; | 2287 | ext4_group_t i; |
2254 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2288 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
2255 | struct ext4_super_block *es = sbi->s_es; | 2289 | int err; |
2256 | int num_meta_group_infos; | ||
2257 | int num_meta_group_infos_max; | ||
2258 | int array_size; | ||
2259 | struct ext4_group_desc *desc; | 2290 | struct ext4_group_desc *desc; |
2260 | struct kmem_cache *cachep; | 2291 | struct kmem_cache *cachep; |
2261 | 2292 | ||
2262 | /* This is the number of blocks used by GDT */ | 2293 | err = ext4_mb_alloc_groupinfo(sb, ngroups); |
2263 | num_meta_group_infos = (ngroups + EXT4_DESC_PER_BLOCK(sb) - | 2294 | if (err) |
2264 | 1) >> EXT4_DESC_PER_BLOCK_BITS(sb); | 2295 | return err; |
2265 | |||
2266 | /* | ||
2267 | * This is the total number of blocks used by GDT including | ||
2268 | * the number of reserved blocks for GDT. | ||
2269 | * The s_group_info array is allocated with this value | ||
2270 | * to allow a clean online resize without a complex | ||
2271 | * manipulation of pointer. | ||
2272 | * The drawback is the unused memory when no resize | ||
2273 | * occurs but it's very low in terms of pages | ||
2274 | * (see comments below) | ||
2275 | * Need to handle this properly when META_BG resizing is allowed | ||
2276 | */ | ||
2277 | num_meta_group_infos_max = num_meta_group_infos + | ||
2278 | le16_to_cpu(es->s_reserved_gdt_blocks); | ||
2279 | 2296 | ||
2280 | /* | ||
2281 | * array_size is the size of s_group_info array. We round it | ||
2282 | * to the next power of two because this approximation is done | ||
2283 | * internally by kmalloc so we can have some more memory | ||
2284 | * for free here (e.g. may be used for META_BG resize). | ||
2285 | */ | ||
2286 | array_size = 1; | ||
2287 | while (array_size < sizeof(*sbi->s_group_info) * | ||
2288 | num_meta_group_infos_max) | ||
2289 | array_size = array_size << 1; | ||
2290 | /* An 8TB filesystem with 64-bit pointers requires a 4096 byte | ||
2291 | * kmalloc. A 128kb malloc should suffice for a 256TB filesystem. | ||
2292 | * So a two level scheme suffices for now. */ | ||
2293 | sbi->s_group_info = ext4_kvzalloc(array_size, GFP_KERNEL); | ||
2294 | if (sbi->s_group_info == NULL) { | ||
2295 | ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group"); | ||
2296 | return -ENOMEM; | ||
2297 | } | ||
2298 | sbi->s_buddy_cache = new_inode(sb); | 2297 | sbi->s_buddy_cache = new_inode(sb); |
2299 | if (sbi->s_buddy_cache == NULL) { | 2298 | if (sbi->s_buddy_cache == NULL) { |
2300 | ext4_msg(sb, KERN_ERR, "can't get new inode"); | 2299 | ext4_msg(sb, KERN_ERR, "can't get new inode"); |
@@ -2322,7 +2321,7 @@ err_freebuddy: | |||
2322 | cachep = get_groupinfo_cache(sb->s_blocksize_bits); | 2321 | cachep = get_groupinfo_cache(sb->s_blocksize_bits); |
2323 | while (i-- > 0) | 2322 | while (i-- > 0) |
2324 | kmem_cache_free(cachep, ext4_get_group_info(sb, i)); | 2323 | kmem_cache_free(cachep, ext4_get_group_info(sb, i)); |
2325 | i = num_meta_group_infos; | 2324 | i = sbi->s_group_info_size; |
2326 | while (i-- > 0) | 2325 | while (i-- > 0) |
2327 | kfree(sbi->s_group_info[i]); | 2326 | kfree(sbi->s_group_info[i]); |
2328 | iput(sbi->s_buddy_cache); | 2327 | iput(sbi->s_buddy_cache); |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3f5c67bf13a2..f288933bf4c0 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -1507,6 +1507,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
1507 | if (err) | 1507 | if (err) |
1508 | return err; | 1508 | return err; |
1509 | 1509 | ||
1510 | err = ext4_mb_alloc_groupinfo(sb, input->group + 1); | ||
1511 | if (err) | ||
1512 | goto out; | ||
1513 | |||
1510 | flex_gd.count = 1; | 1514 | flex_gd.count = 1; |
1511 | flex_gd.groups = input; | 1515 | flex_gd.groups = input; |
1512 | flex_gd.bg_flags = &bg_flags; | 1516 | flex_gd.bg_flags = &bg_flags; |
@@ -1732,6 +1736,10 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1732 | if (err) | 1736 | if (err) |
1733 | return err; | 1737 | return err; |
1734 | 1738 | ||
1739 | err = ext4_mb_alloc_groupinfo(sb, n_group + 1); | ||
1740 | if (err) | ||
1741 | goto out; | ||
1742 | |||
1735 | flex_gd = alloc_flex_gd(flexbg_size); | 1743 | flex_gd = alloc_flex_gd(flexbg_size); |
1736 | if (flex_gd == NULL) { | 1744 | if (flex_gd == NULL) { |
1737 | err = -ENOMEM; | 1745 | err = -ENOMEM; |