diff -rupN linux-2.6.18-164.6.1_1//fs/ext4/ialloc.c linux-2.6.18-164.6.1_2//fs/ext4/ialloc.c --- linux-2.6.18-164.6.1_1//fs/ext4/ialloc.c 2010-03-31 17:42:50.000000000 +0530 +++ linux-2.6.18-164.6.1_2//fs/ext4/ialloc.c 2010-03-31 17:43:22.000000000 +0530 @@ -710,12 +710,15 @@ struct inode *ext4_new_inode_goal(handle sb = dir->i_sb; trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id, dir->i_ino, mode); + 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)) { diff -rupN linux-2.6.18-164.6.1_1//fs/ext4/super.c linux-2.6.18-164.6.1_2//fs/ext4/super.c --- linux-2.6.18-164.6.1_1//fs/ext4/super.c 2010-03-31 17:42:50.000000000 +0530 +++ linux-2.6.18-164.6.1_2//fs/ext4/super.c 2010-03-31 17:45:32.000000000 +0530 @@ -40,6 +40,7 @@ #include #include #include +#include #include "ext4.h" #include "ext4_jbd2.h" @@ -581,6 +582,7 @@ static void ext4_put_super(struct super_ ext4_commit_super(sb, es, 1); } if (sbi->s_proc) { + remove_proc_entry(EXT4_MAX_DIR_SIZE_NAME, sbi->s_proc); remove_proc_entry("inode_readahead_blks", sbi->s_proc); remove_proc_entry("inode_goal", sbi->s_proc); remove_proc_entry(sb->s_id, ext4_proc_root); @@ -2341,6 +2343,48 @@ static unsigned long ext4_get_stripe_siz return 0; } +#ifdef CONFIG_PROC_FS +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; +} +#endif + static int ext4_fill_super(struct super_block *sb, void *data, int silent) __releases(kernel_lock) __acquires(kernel_lock) @@ -2690,6 +2734,19 @@ static int ext4_fill_super(struct super_ p->proc_fops = &ext4_ui_proc_fops, p->data = &sbi->s_inode_goal; } + sbi->s_max_dir_size = EXT4_DEFAULT_MAX_DIR_SIZE; + p = create_proc_entry(EXT4_MAX_DIR_SIZE_NAME, + S_IFREG | S_IRUGO | S_IWUSR, sbi->s_proc); + if (p == NULL) { + printk(KERN_ERR "EXT4-fs: unable to create %s\n", + EXT4_MAX_DIR_SIZE_NAME); + ret = -ENOMEM; + goto failed_mount; + } + p->data = sbi; + p->read_proc = ext4_max_dir_size_read; + p->write_proc = ext4_max_dir_size_write; + } #endif @@ -2976,6 +3033,7 @@ failed_mount2: kfree(sbi->s_group_desc); failed_mount: if (sbi->s_proc) { + remove_proc_entry(EXT4_MAX_DIR_SIZE_NAME, sbi->s_proc); remove_proc_entry("inode_readahead_blks", sbi->s_proc); remove_proc_entry("inode_goal", sbi->s_proc); remove_proc_entry(sb->s_id, ext4_proc_root); diff -rupN linux-2.6.18-164.6.1_1//fs/ext4/ext4_sb.h linux-2.6.18-164.6.1_2//fs/ext4/ext4_sb.h --- linux-2.6.18-164.6.1_1//fs/ext4/ext4_sb.h 2010-03-31 17:42:50.000000000 +0530 +++ linux-2.6.18-164.6.1_2//fs/ext4/ext4_sb.h 2010-03-31 17:43:22.000000000 +0530 @@ -119,6 +119,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; diff -rupN linux-2.6.18-164.6.1_1//fs/ext4/ext4.h linux-2.6.18-164.6.1_2//fs/ext4/ext4.h --- linux-2.6.18-164.6.1_1//fs/ext4/ext4.h 2010-03-31 17:42:50.000000000 +0530 +++ linux-2.6.18-164.6.1_2//fs/ext4/ext4.h 2010-03-31 17:43:22.000000000 +0530 @@ -1029,6 +1029,12 @@ struct mmp_struct { #define EXT4_MMP_MIN_CHECK_INTERVAL 5 /* + * max directory size tunable + */ +#define EXT4_DEFAULT_MAX_DIR_SIZE 0 +#define EXT4_MAX_DIR_SIZE_NAME "max_dir_size" + +/* * Function prototypes */