Index: linux-stage/fs/ext3/ialloc.c =================================================================== --- linux-stage.orig/fs/ext3/ialloc.c +++ linux-stage/fs/ext3/ialloc.c @@ -521,12 +521,15 @@ struct inode *ext3_new_inode(handle_t return ERR_PTR(-EPERM); sb = dir->i_sb; + sbi = EXT3_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 = EXT3_I(inode); - sbi = EXT3_SB(sb); es = sbi->s_es; if (goal) { group = (goal - 1) / EXT3_INODES_PER_GROUP(sb); Index: linux-stage/fs/ext3/super.c =================================================================== --- linux-stage.orig/fs/ext3/super.c +++ linux-stage/fs/ext3/super.c @@ -45,6 +45,12 @@ #include "namei.h" #include "group.h" +/* + * max directory size tunable + */ +#define EXT3_DEFAULT_MAX_DIR_SIZE 0 +#define EXT3_MAX_DIR_SIZE_NAME "max_dir_size" + static int ext3_load_journal(struct super_block *, struct ext3_super_block *, unsigned long journal_devnum); static int ext3_create_journal(struct super_block *, struct ext3_super_block *, @@ -444,6 +450,7 @@ static void ext3_put_super (struct su } if (sbi->s_mmp_tsk) kthread_stop(sbi->s_mmp_tsk); + remove_proc_entry(EXT3_MAX_DIR_SIZE_NAME, sbi->s_dev_proc); if (sbi->s_dev_proc) { remove_proc_entry(sbi->s_dev_proc->name, proc_root_ext3); sbi->s_dev_proc = NULL; @@ -703,7 +710,7 @@ enum { Opt_iopen, Opt_noiopen, Opt_iopen_nopriv, Opt_grpquota, Opt_extents, Opt_noextents, Opt_extdebug, - Opt_mballoc, Opt_nomballoc, Opt_stripe, + Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_maxdirsize }; static match_table_t tokens = { @@ -762,8 +769,9 @@ static match_table_t tokens = { {Opt_mballoc, "mballoc"}, {Opt_nomballoc, "nomballoc"}, {Opt_stripe, "stripe=%u"}, - {Opt_err, NULL}, {Opt_resize, "resize"}, + {Opt_maxdirsize, "maxdirsize=%u"}, + {Opt_err, NULL} }; static ext3_fsblk_t get_sb_block(void **data) @@ -1128,6 +1136,13 @@ clear_qf_name: return 0; sbi->s_stripe = option; break; + case Opt_maxdirsize: + if (match_int(&args[0], &option)) + return 0; + if (option <= 0) + return 0; + sbi->s_max_dir_size = option; + break; default: printk (KERN_ERR "EXT3-fs: Unrecognized mount option \"%s\" " @@ -1875,6 +1890,45 @@ failed: return 1; } +static int ext3_max_dir_size_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct ext3_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 ext3_max_dir_size_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct ext3_sb_info *sbi = data; + char str[32]; + unsigned long value; + char *end; + + if (count >= sizeof(str)) { + printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n", + EXT3_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 ext3_fill_super (struct super_block *sb, void *data, int silent) { @@ -1896,6 +1950,7 @@ static int ext3_fill_super (struct su int i; int needs_recovery; __le32 features; + struct proc_dir_entry *proc; sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -1924,6 +1979,23 @@ static int ext3_fill_super (struct su unlock_kernel(); + sbi->s_max_dir_size = EXT3_DEFAULT_MAX_DIR_SIZE; + proc = create_proc_entry(EXT3_MAX_DIR_SIZE_NAME, + S_IFREG | S_IRUGO | S_IWUSR, sbi->s_dev_proc); + if (proc == NULL) { + printk(KERN_ERR "EXT3-fs: unable to create %s\n", + EXT3_MAX_DIR_SIZE_NAME); + remove_proc_entry(EXT3_MAX_DIR_SIZE_NAME, sbi->s_dev_proc); + remove_proc_entry(sb->s_id, proc_root_ext3); + sbi->s_dev_proc = NULL; + sb->s_fs_info = NULL; + kfree(sbi); + return -ENOMEM; + } + proc->data = sbi; + proc->read_proc = ext3_max_dir_size_read; + proc->write_proc = ext3_max_dir_size_write; + blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); if (!blocksize) { printk(KERN_ERR "EXT3-fs: unable to set blocksize\n"); @@ -2361,6 +2433,7 @@ failed_mount: ext3_blkdev_remove(sbi); brelse(bh); out_fail: + remove_proc_entry(EXT3_MAX_DIR_SIZE_NAME, sbi->s_dev_proc); if (sbi->s_dev_proc) { remove_proc_entry(sbi->s_dev_proc->name, proc_root_ext3); sbi->s_dev_proc = NULL; Index: linux-stage/include/linux/ext3_fs_sb.h =================================================================== --- linux-stage.orig/include/linux/ext3_fs_sb.h +++ linux-stage/include/linux/ext3_fs_sb.h @@ -132,6 +132,8 @@ struct ext3_sb_info { unsigned long s_mb_last_group; unsigned long s_mb_last_start; + unsigned long s_max_dir_size; + /* history to debug policy */ struct ext3_mb_history *s_mb_history; int s_mb_history_cur;