Index: linux-stage/fs/ext4/ialloc.c =================================================================== --- linux-stage.orig/fs/ext4/ialloc.c +++ linux-stage/fs/ext4/ialloc.c @@ -675,7 +675,8 @@ err_ret: * For other inodes, search forward from the parent directory's block * group to find a free inode. */ -struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) +struct inode *ext4_new_inode_goal(handle_t *handle, struct inode *dir, + int mode, unsigned goal) { struct super_block *sb; struct buffer_head *inode_bitmap_bh = NULL; @@ -706,6 +707,14 @@ struct inode *ext4_new_inode(handle_t *h sbi = EXT4_SB(sb); es = sbi->s_es; + if (goal && goal <= le32_to_cpu(es->s_inodes_count)) { + group = (goal - 1) / EXT4_INODES_PER_GROUP(sb); + ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb); + + ret2 = 0; + goto got_group; + } + if (sbi->s_log_groups_per_flex) { ret2 = find_group_flex(sb, dir, &group); goto got_group; @@ -724,7 +733,7 @@ got_group: if (ret2 == -1) goto out; - for (i = 0; i < sbi->s_groups_count; i++) { + for (i = 0; i < sbi->s_groups_count; i++, ino = 0) { err = -EIO; gdp = ext4_get_group_desc(sb, group, &group_desc_bh); @@ -736,8 +745,6 @@ got_group: if (!inode_bitmap_bh) goto fail; - ino = 0; - repeat_in_this_group: ino = ext4_find_next_zero_bit((unsigned long *) inode_bitmap_bh->b_data, Index: linux-stage/fs/ext4/namei.c =================================================================== --- linux-stage.orig/fs/ext4/namei.c +++ linux-stage/fs/ext4/namei.c @@ -149,6 +149,17 @@ struct dx_map_entry u16 size; }; +/* + * dentry_param used by ext4_new_inode_wantedi() + */ +#define LVFS_DENTRY_PARAM_MAGIC 20070216UL +struct lvfs_dentry_params +{ + unsigned long ldp_inum; + unsigned long ldp_flags; + u32 ldp_magic; +}; + static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); static inline unsigned dx_get_hash(struct dx_entry *entry); @@ -1716,6 +1727,19 @@ static int ext4_add_nondir(handle_t *han return err; } +static unsigned ext4_dentry_goal(struct super_block *sb, struct dentry *dentry) +{ + unsigned inum = EXT4_SB(sb)->s_inode_goal; + + if (dentry->d_fsdata != NULL) { + struct lvfs_dentry_params *param = dentry->d_fsdata; + + if (param->ldp_magic == LVFS_DENTRY_PARAM_MAGIC) + inum = param->ldp_inum; + } + return inum; +} + /* * By the time this is called, we already have created * the directory cache entry for the new file, but it @@ -1741,7 +1766,8 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode (handle, dir, mode); + inode = ext4_new_inode_goal(handle, dir, mode, + ext4_dentry_goal(dir->i_sb, dentry)); err = PTR_ERR(inode); if (!IS_ERR(inode)) { inode->i_op = &ext4_file_inode_operations; @@ -1775,7 +1800,8 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode(handle, dir, mode); + inode = ext4_new_inode_goal(handle, dir, mode, + ext4_dentry_goal(dir->i_sb, dentry)); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); @@ -1811,7 +1836,8 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode(handle, dir, S_IFDIR | mode); + inode = ext4_new_inode_goal(handle, dir, S_IFDIR | mode, + ext4_dentry_goal(dir->i_sb, dentry)); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; @@ -2211,7 +2236,8 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO); + inode = ext4_new_inode_goal(handle, dir, S_IFLNK|S_IRWXUGO, + ext4_dentry_goal(dir->i_sb, dentry)); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; Index: linux-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h +++ linux-stage/fs/ext4/ext4.h @@ -1032,7 +1032,14 @@ extern int ext4fs_dirhash(const char *na dx_hash_info *hinfo); /* ialloc.c */ -extern struct inode * ext4_new_inode(handle_t *, struct inode *, int); +extern struct inode *ext4_new_inode_goal(handle_t *handle, struct inode *dir, + int mode, unsigned goal); +static inline struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, + int mode) +{ + return ext4_new_inode_goal(handle, dir, mode, + EXT4_SB(dir->i_sb)->s_inode_goal); +} extern void ext4_free_inode(handle_t *, struct inode *); extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); extern unsigned long ext4_count_free_inodes(struct super_block *); Index: linux-stage/fs/ext4/super.c =================================================================== --- linux-stage.orig/fs/ext4/super.c +++ linux-stage/fs/ext4/super.c @@ -560,6 +560,7 @@ static void ext4_put_super(struct super_ } if (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); } @@ -2274,10 +2275,14 @@ static int ext4_fill_super(struct super_ if (ext4_proc_root) sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); - if (sbi->s_proc) + if (sbi->s_proc) { proc_create_data("inode_readahead_blks", 0644, sbi->s_proc, &ext4_ui_proc_fops, &sbi->s_inode_readahead_blks); + proc_create_data("inode_goal", 0644, sbi->s_proc, + &ext4_ui_proc_fops, + &sbi->s_inode_goal); + } #endif bgl_lock_init(&sbi->s_blockgroup_lock); @@ -2553,6 +2558,7 @@ failed_mount2: failed_mount: if (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); } #ifdef CONFIG_QUOTA Index: linux-stage/fs/ext4/ext4_sb.h =================================================================== --- linux-stage.orig/fs/ext4/ext4_sb.h +++ linux-stage/fs/ext4/ext4_sb.h @@ -53,6 +53,7 @@ struct ext4_sb_info { int s_inode_size; int s_first_ino; unsigned int s_inode_readahead_blks; + unsigned int s_inode_goal; spinlock_t s_next_gen_lock; u32 s_next_generation; u32 s_hash_seed[4];