Index: linux-2.6.18-128.1.6/fs/ext4/ialloc.c =================================================================== --- linux-2.6.18-128.1.6.orig/fs/ext4/ialloc.c +++ linux-2.6.18-128.1.6/fs/ext4/ialloc.c @@ -946,6 +946,36 @@ fail_drop: return ERR_PTR(err); } +unsigned long ext4_find_reverse(struct super_block *sb) +{ + struct ext4_group_desc *desc; + struct buffer_head *bitmap_bh = NULL; + int group; + unsigned long ino, offset; + + for (offset = (EXT4_INODES_PER_GROUP(sb) >> 1); offset >= 0; + offset >>= 1) { + for (group = EXT4_SB(sb)->s_groups_count - 1; group >= 0; + --group) { + desc = ext4_get_group_desc(sb, group, NULL); + if (desc->bg_free_inodes_count == 0) + continue; + + bitmap_bh = ext4_read_inode_bitmap(sb, group); + if (!bitmap_bh) + continue; + + ino = ext4_find_next_zero_bit((unsigned long *) + bitmap_bh->b_data, + EXT4_INODES_PER_GROUP(sb), offset); + if (ino < EXT4_INODES_PER_GROUP(sb)) + return (group * EXT4_INODES_PER_GROUP(sb) + + ino + 1); + } + } + return 0; +} + /* Verify that we are loading a valid orphan from disk */ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) { Index: linux-2.6.18-128.1.6/fs/ext4/namei.c =================================================================== --- linux-2.6.18-128.1.6.orig/fs/ext4/namei.c +++ linux-2.6.18-128.1.6/fs/ext4/namei.c @@ -151,14 +151,24 @@ 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 p_inum; - void *p_ptr; - u32 magic; + unsigned long ldp_inum; + long ldp_flags; + u32 ldp_magic; }; +/* Only use the least 3 bits of ldp_flags for goal policy */ +typedef enum { + DP_GOAL_POLICY = 0, + DP_LASTGROUP_REVERSE = 1, +} dp_policy_t; + + 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); @@ -1762,8 +1772,13 @@ static struct inode * ext4_new_inode_wan if (dentry->d_fsdata != NULL) { struct lvfs_dentry_params *param = dentry->d_fsdata; - if (param->magic == LVFS_DENTRY_PARAM_MAGIC) - inum = param->p_inum; + if (param->ldp_magic == LVFS_DENTRY_PARAM_MAGIC) { + if ((dp_policy_t)(param->ldp_flags & 0x7) == + DP_LASTGROUP_REVERSE) + inum = ext4_find_reverse(dir->i_sb); + else /* DP_GOAL_POLICY */ + inum = param->ldp_inum; + } } return ext4_new_inode(handle, dir, mode, inum); } Index: linux-2.6.18-128.1.6/fs/ext4/ext4.h =================================================================== --- linux-2.6.18-128.1.6.orig/fs/ext4/ext4.h +++ linux-2.6.18-128.1.6/fs/ext4/ext4.h @@ -1071,6 +1071,7 @@ extern int ext4fs_dirhash(const char *na /* ialloc.c */ extern struct inode * ext4_new_inode (handle_t *, struct inode *, int, unsigned long); +extern unsigned long ext4_find_reverse(struct super_block *); 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 *);