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-06-02 18:39:22.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/ialloc.c 2009-06-04 17:01:26.000000000 +0530 @@ -675,7 +675,8 @@ * 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(handle_t *handle, struct inode *dir, int mode, + unsigned long goal) { struct super_block *sb; struct buffer_head *inode_bitmap_bh = NULL; @@ -706,6 +707,48 @@ sbi = EXT4_SB(sb); es = sbi->s_es; + if (goal) { + group = (goal - 1) / EXT4_INODES_PER_GROUP(sb); + ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb); + err = -EIO; + + gdp = ext4_get_group_desc(sb, group, &group_desc_bh); + if (!gdp) + goto fail; + + inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); + if (!inode_bitmap_bh) + goto fail; + + BUFFER_TRACE(bh, "get_write_access"); + err = ext4_journal_get_write_access(handle, inode_bitmap_bh); + if (err) + goto fail; + + if (ext4_set_bit_atomic(sb_bgl_lock(sbi, group), + ino, inode_bitmap_bh->b_data)) { + printk(KERN_ERR "goal inode %lu unavailable\n", goal); + /* Oh well, we tried. */ + goto continue_allocation; + } + + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, inode_bitmap_bh); + if (err) + goto fail; + + /* We've shortcircuited the allocation system successfully, + * now finish filling in the inode. + */ + BUFFER_TRACE(group_desc_bh, "get_write_access"); + err = ext4_journal_get_write_access(handle, group_desc_bh); + if (err) + goto fail; + + goto got; + } + +continue_allocation: if (sbi->s_log_groups_per_flex) { ret2 = find_group_flex(sb, dir, &group); goto got_group; Index: linux-2.6.27.21-0.1/fs/ext4/namei.c =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/namei.c 2009-06-02 18:39:22.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/namei.c 2009-06-04 17:00:38.000000000 +0530 @@ -104,6 +104,7 @@ __le32 block; }; + /* * dx_root_info is laid out so that if it should somehow get overlaid by a * dirent the two low bits of the hash version will be zero. Therefore, the @@ -149,6 +150,14 @@ u16 size; }; +#define LVFS_DENTRY_PARAM_MAGIC 20070216UL +struct lvfs_dentry_params +{ + unsigned long p_inum; + void *p_ptr; + u32 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 +1725,20 @@ return err; } +static struct inode * ext4_new_inode_wantedi(handle_t *handle, struct inode *dir, + int mode, struct dentry *dentry) +{ + unsigned long inum = 0; + + if (dentry->d_fsdata != NULL) { + struct lvfs_dentry_params *param = dentry->d_fsdata; + + if (param->magic == LVFS_DENTRY_PARAM_MAGIC) + inum = param->p_inum; + } + return ext4_new_inode(handle, dir, mode, inum); +} + /* * By the time this is called, we already have created * the directory cache entry for the new file, but it @@ -1741,7 +1764,7 @@ if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode (handle, dir, mode); + inode = ext4_new_inode_wantedi(handle, dir, mode, dentry); err = PTR_ERR(inode); if (!IS_ERR(inode)) { inode->i_op = &ext4_file_inode_operations; @@ -1775,7 +1798,7 @@ if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode(handle, dir, mode); + inode = ext4_new_inode_wantedi(handle, dir, mode, dentry); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); @@ -1811,7 +1834,7 @@ if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode(handle, dir, S_IFDIR | mode); + inode = ext4_new_inode_wantedi(handle, dir, S_IFDIR | mode, dentry); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; @@ -2211,7 +2234,7 @@ if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO); + inode = ext4_new_inode_wantedi(handle, dir, S_IFLNK|S_IRWXUGO, dentry); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; 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-06-02 18:39:22.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/ext4.h 2009-06-04 17:00:38.000000000 +0530 @@ -1032,7 +1032,8 @@ dx_hash_info *hinfo); /* ialloc.c */ -extern struct inode * ext4_new_inode(handle_t *, struct inode *, int); +extern struct inode * ext4_new_inode(handle_t *, struct inode *, int, + unsigned long); 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-2.6.27.21-0.1/fs/ext4/migrate.c =================================================================== --- linux-2.6.27.21-0.1.orig/fs/ext4/migrate.c 2009-06-02 18:39:22.000000000 +0530 +++ linux-2.6.27.21-0.1/fs/ext4/migrate.c 2009-06-04 17:00:38.000000000 +0530 @@ -484,7 +484,7 @@ } tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, - S_IFREG); + S_IFREG, 0); if (IS_ERR(tmp_inode)) { retval = -ENOMEM; ext4_journal_stop(handle);