Index: linux-stage/fs/ext4/ialloc.c =================================================================== --- linux-stage.orig/fs/ext4/ialloc.c +++ linux-stage/fs/ext4/ialloc.c @@ -700,12 +700,15 @@ struct inode *ext4_new_inode(handle_t *h 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) { Index: linux-stage/fs/ext4/super.c =================================================================== --- linux-stage.orig/fs/ext4/super.c +++ linux-stage/fs/ext4/super.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "ext4.h" #include "ext4_jbd2.h" @@ -71,6 +72,8 @@ static void ext4_write_super(struct supe 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) { @@ -564,6 +567,7 @@ static void ext4_put_super(struct super_ } 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(sb->s_id, ext4_proc_root); } @@ -602,6 +606,7 @@ static void ext4_put_super(struct super_ } if (sbi->s_mmp_tsk) kthread_stop(sbi->s_mmp_tsk); + sb->s_fs_info = NULL; kfree(sbi); return; @@ -2287,6 +2292,46 @@ static unsigned long ext4_get_stripe_siz 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) @@ -2311,6 +2356,7 @@ static int ext4_fill_super(struct super_ 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 +2926,22 @@ static int ext4_fill_super(struct super_ 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; @@ -3253,7 +3315,6 @@ static void ext4_commit_super(struct sup } } - /* * 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-stage/fs/ext4/ext4_sb.h =================================================================== --- linux-stage.orig/fs/ext4/ext4_sb.h +++ linux-stage/fs/ext4/ext4_sb.h @@ -118,6 +118,7 @@ struct ext4_sb_info { /* 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-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h +++ linux-stage/fs/ext4/ext4.h @@ -1017,6 +1017,14 @@ struct mmp_struct { */ #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-stage/fs/ext4/mballoc.c =================================================================== --- linux-stage.orig/fs/ext4/mballoc.c +++ linux-stage/fs/ext4/mballoc.c @@ -2943,6 +2943,7 @@ err_out: 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 @@ static int ext4_mb_destroy_per_dev_proc( 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; }