diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-04-27 22:48:48 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-04-27 22:48:48 -0400 |
commit | c5ca7c7636fa689a9746b6032f83aa7fffec31c6 (patch) | |
tree | eebbdd1d477b5062148ee61c9e1bf1d4da3e9e05 /fs/ext4/super.c | |
parent | 29fa89d088941d79765d60f22d5ccdd6b8696e11 (diff) |
ext4: Fallback to vmalloc if kmalloc can't allocate s_flex_groups array
For very large filesystems, the s_flex_groups array can get quite big.
For example, a filesystem that can be resized up to 16TB will have
8192 flex groups (assuming the default flex_bg size of 16), so the
array is 96k, which is *very* marginal for kmalloc(). On the other
hand, a 160GB filesystem without the resize_inode feature will only
require 960 bytes. So we try to allocate the array first using
kmalloc(), and if that fails, we'll try to use vmalloc() instead.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2958f4e6f222..3f4475daa66d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | #include <linux/vmalloc.h> | ||
23 | #include <linux/jbd2.h> | 24 | #include <linux/jbd2.h> |
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -586,7 +587,10 @@ static void ext4_put_super(struct super_block *sb) | |||
586 | for (i = 0; i < sbi->s_gdb_count; i++) | 587 | for (i = 0; i < sbi->s_gdb_count; i++) |
587 | brelse(sbi->s_group_desc[i]); | 588 | brelse(sbi->s_group_desc[i]); |
588 | kfree(sbi->s_group_desc); | 589 | kfree(sbi->s_group_desc); |
589 | kfree(sbi->s_flex_groups); | 590 | if (is_vmalloc_addr(sbi->s_flex_groups)) |
591 | vfree(sbi->s_flex_groups); | ||
592 | else | ||
593 | kfree(sbi->s_flex_groups); | ||
590 | percpu_counter_destroy(&sbi->s_freeblocks_counter); | 594 | percpu_counter_destroy(&sbi->s_freeblocks_counter); |
591 | percpu_counter_destroy(&sbi->s_freeinodes_counter); | 595 | percpu_counter_destroy(&sbi->s_freeinodes_counter); |
592 | percpu_counter_destroy(&sbi->s_dirs_counter); | 596 | percpu_counter_destroy(&sbi->s_dirs_counter); |
@@ -1620,6 +1624,7 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
1620 | ext4_group_t flex_group_count; | 1624 | ext4_group_t flex_group_count; |
1621 | ext4_group_t flex_group; | 1625 | ext4_group_t flex_group; |
1622 | int groups_per_flex = 0; | 1626 | int groups_per_flex = 0; |
1627 | size_t size; | ||
1623 | int i; | 1628 | int i; |
1624 | 1629 | ||
1625 | if (!sbi->s_es->s_log_groups_per_flex) { | 1630 | if (!sbi->s_es->s_log_groups_per_flex) { |
@@ -1634,8 +1639,13 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
1634 | flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + | 1639 | flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + |
1635 | ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << | 1640 | ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << |
1636 | EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex; | 1641 | EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex; |
1637 | sbi->s_flex_groups = kzalloc(flex_group_count * | 1642 | size = flex_group_count * sizeof(struct flex_groups); |
1638 | sizeof(struct flex_groups), GFP_KERNEL); | 1643 | sbi->s_flex_groups = kzalloc(size, GFP_KERNEL); |
1644 | if (sbi->s_flex_groups == NULL) { | ||
1645 | sbi->s_flex_groups = vmalloc(size); | ||
1646 | if (sbi->s_flex_groups) | ||
1647 | memset(sbi->s_flex_groups, 0, size); | ||
1648 | } | ||
1639 | if (sbi->s_flex_groups == NULL) { | 1649 | if (sbi->s_flex_groups == NULL) { |
1640 | printk(KERN_ERR "EXT4-fs: not enough memory for " | 1650 | printk(KERN_ERR "EXT4-fs: not enough memory for " |
1641 | "%u flex groups\n", flex_group_count); | 1651 | "%u flex groups\n", flex_group_count); |
@@ -2842,6 +2852,12 @@ failed_mount4: | |||
2842 | sbi->s_journal = NULL; | 2852 | sbi->s_journal = NULL; |
2843 | } | 2853 | } |
2844 | failed_mount3: | 2854 | failed_mount3: |
2855 | if (sbi->s_flex_groups) { | ||
2856 | if (is_vmalloc_addr(sbi->s_flex_groups)) | ||
2857 | vfree(sbi->s_flex_groups); | ||
2858 | else | ||
2859 | kfree(sbi->s_flex_groups); | ||
2860 | } | ||
2845 | percpu_counter_destroy(&sbi->s_freeblocks_counter); | 2861 | percpu_counter_destroy(&sbi->s_freeblocks_counter); |
2846 | percpu_counter_destroy(&sbi->s_freeinodes_counter); | 2862 | percpu_counter_destroy(&sbi->s_freeinodes_counter); |
2847 | percpu_counter_destroy(&sbi->s_dirs_counter); | 2863 | percpu_counter_destroy(&sbi->s_dirs_counter); |