aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-04-27 22:48:48 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-04-27 22:48:48 -0400
commitc5ca7c7636fa689a9746b6032f83aa7fffec31c6 (patch)
treeeebbdd1d477b5062148ee61c9e1bf1d4da3e9e05
parent29fa89d088941d79765d60f22d5ccdd6b8696e11 (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>
-rw-r--r--fs/ext4/super.c22
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 }
2844failed_mount3: 2854failed_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);