Index: linux-2.6.27.21-0.1/fs/ext4/ialloc.c =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/ialloc.c 2009-07-07 14:35:55.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/ialloc.c 2009-07-07 14:38:17.000000000 +0530 @@ -700,12 +700,15 @@ return ERR_PTR(-EPERM); sb = dir->i_sb; + sbi = EXT4_SB(sb); + if (sbi->s_max_dir_size > 0 && i_size_read(dir) >= sbi->s_max_dir_size) + return ERR_PTR(-EFBIG); + inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); ei = EXT4_I(inode); - sbi = EXT4_SB(sb); es = sbi->s_es; if (goal && goal < le32_to_cpu(es->s_inodes_count)) { Index: linux-2.6.27.21-0.1/fs/ext4/super.c =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/super.c 2009-07-07 14:38:06.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/super.c 2009-07-07 14:38:41.000000000 +0530 @@ -41,6 +41,7 @@ #include #include #include +#include #include "ext4.h" #include "ext4_jbd2.h" @@ -71,6 +72,8 @@ static void ext4_write_super_lockfs(struct super_block *sb); +struct proc_dir_entry *proc_root_ext4; + ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg) { @@ -603,6 +606,7 @@ } if (sbi->s_mmp_tsk) kthread_stop(sbi->s_mmp_tsk); + sb->s_fs_info = NULL; kfree(sbi); return; @@ -2283,6 +2287,46 @@ return 0; } +static int ext4_max_dir_size_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct ext4_sb_info *sbi = data; + int len; + + *eof = 1; + if (off != 0) + return 0; + + len = sprintf(page, "%lu\n", sbi->s_max_dir_size); + *start = page; + return len; +} + +static int ext4_max_dir_size_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct ext4_sb_info *sbi = data; + char str[32]; + unsigned long value; + char *end; + + if (count >= sizeof(str)) { + printk(KERN_ERR "EXT4-fs: %s string too long, max %u bytes\n", + EXT4_MAX_DIR_SIZE_NAME, (int)sizeof(str)); + return -EOVERFLOW; + } + + if (copy_from_user(str, buffer, count)) + return -EFAULT; + + value = simple_strtol(str, &end, 0); + if (value < 0) + return -ERANGE; + + sbi->s_max_dir_size = value; + return count; +} + static int ext4_fill_super(struct super_block *sb, void *data, int silent) __releases(kernel_lock) __acquires(kernel_lock) @@ -2307,6 +2351,7 @@ int needs_recovery, has_huge_files; int features; __u64 blocks_count; + struct proc_dir_entry *proc; int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); @@ -2880,6 +2925,22 @@ test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": "writeback"); + sbi->s_max_dir_size = EXT4_DEFAULT_MAX_DIR_SIZE; + proc = create_proc_entry(EXT4_MAX_DIR_SIZE_NAME, + S_IFREG | S_IRUGO | S_IWUSR, sbi->s_proc); + if (proc == NULL) { + printk(KERN_ERR "EXT4-fs: unable to create %s\n", + EXT4_MAX_DIR_SIZE_NAME); + remove_proc_entry(EXT4_MAX_DIR_SIZE_NAME, sbi->s_proc); + remove_proc_entry(sbi->s_proc->name, proc_root_ext4); + sbi->s_proc = NULL; + ret = -ENOMEM; + goto failed_mount4; + } + proc->data = sbi; + proc->read_proc = ext4_max_dir_size_read; + proc->write_proc = ext4_max_dir_size_write; + lock_kernel(); return 0; @@ -2906,6 +2967,7 @@ failed_mount: if (sbi->s_proc) { remove_proc_entry("inode_readahead_blks", sbi->s_proc); + remove_proc_entry(EXT4_MAX_DIR_SIZE_NAME, sbi->s_proc); remove_proc_entry("inode_goal", sbi->s_proc); remove_proc_entry(sb->s_id, ext4_proc_root); } @@ -3254,7 +3316,6 @@ } } - /* * Have we just finished recovery? If so, and if we are mounting (or * remounting) the filesystem readonly, then we will end up with a Index: linux-2.6.27.21-0.1/fs/ext4/ext4_sb.h =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/ext4_sb.h 2009-07-07 14:36:58.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/ext4_sb.h 2009-07-07 14:38:17.000000000 +0530 @@ -119,6 +119,7 @@ /* where last allocation was done - for stream allocation */ unsigned long s_mb_last_group; unsigned long s_mb_last_start; + unsigned long s_max_dir_size; /* history to debug policy */ struct ext4_mb_history *s_mb_history; Index: linux-2.6.27.21-0.1/fs/ext4/ext4.h =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/ext4.h 2009-07-07 14:38:12.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/ext4.h 2009-07-07 14:38:17.000000000 +0530 @@ -1017,6 +1017,14 @@ */ #define EXT4_MMP_MIN_CHECK_INTERVAL 5 +extern struct proc_dir_entry *proc_root_ext4; + +/* + * max directory size tunable + */ +#define EXT4_DEFAULT_MAX_DIR_SIZE 0 +#define EXT4_MAX_DIR_SIZE_NAME "max_dir_size" + /* * Function prototypes */ Index: linux-2.6.27.21-0.1/fs/ext4/mballoc.c =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/mballoc.c 2009-07-07 14:08:21.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/mballoc.c 2009-07-07 14:38:17.000000000 +0530 @@ -2943,6 +2943,7 @@ remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc); remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc); remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc); + remove_proc_entry(EXT4_MAX_DIR_SIZE_NAME, sbi->s_proc); return -ENOMEM; #else return 0; @@ -2963,6 +2964,7 @@ remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc); remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc); remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc); + remove_proc_entry(EXT4_MAX_DIR_SIZE_NAME, sbi->s_proc); #endif return 0; }