diff -Nrpu /tmp/linux-stage/fs/ext3/ialloc.c linux-stage/fs/ext3/ialloc.c --- /tmp/linux-stage/fs/ext3/ialloc.c 2009-05-09 06:44:02.000000000 +0400 +++ linux-stage/fs/ext3/ialloc.c 2009-05-09 06:45:33.000000000 +0400 @@ -822,6 +822,36 @@ fail_drop: return ERR_PTR(err); } +unsigned long ext3_find_reverse(struct super_block *sb) +{ + struct ext3_group_desc *desc; + struct buffer_head *bitmap_bh = NULL; + int group; + unsigned long ino, offset; + + for (offset = (EXT3_INODES_PER_GROUP(sb) >> 1); offset >= 0; + offset >>= 1) { + for (group = EXT3_SB(sb)->s_groups_count - 1; group >= 0; + --group) { + desc = ext3_get_group_desc(sb, group, NULL); + if (desc->bg_free_inodes_count == 0) + continue; + + bitmap_bh = read_inode_bitmap(sb, group); + if (!bitmap_bh) + continue; + + ino = ext3_find_next_zero_bit((unsigned long *) + bitmap_bh->b_data, + EXT3_INODES_PER_GROUP(sb), offset); + if (ino < EXT3_INODES_PER_GROUP(sb)) + return(group * EXT3_INODES_PER_GROUP(sb) + + ino + 1); + } + } + return 0; +} + /* Verify that we are loading a valid orphan from disk */ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) { diff -Nrpu /tmp/linux-stage/fs/ext3/namei.c linux-stage/fs/ext3/namei.c --- /tmp/linux-stage/fs/ext3/namei.c 2009-05-09 06:44:02.000000000 +0400 +++ linux-stage/fs/ext3/namei.c 2009-05-09 06:45:33.000000000 +0400 @@ -145,14 +145,25 @@ struct dx_map_entry u32 offs; }; +/* + * dentry_param used by ext3_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; + +#define LDP_FLAGS_RANGE 0x07 + #ifdef CONFIG_EXT3_INDEX static inline unsigned dx_get_block (struct dx_entry *entry); static void dx_set_block (struct dx_entry *entry, unsigned value); @@ -1718,8 +1727,13 @@ static struct inode * ext3_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 & LDP_FLAGS_RANGE) == + DP_LASTGROUP_REVERSE) + inum = ext3_find_reverse(dir->i_sb); + else /* DP_GOAL_POLICY */ + inum = param->ldp_inum; + } } return ext3_new_inode(handle, dir, mode, inum); } diff -Nrpu /tmp/linux-stage/include/linux/ext3_fs.h linux-stage/include/linux/ext3_fs.h --- /tmp/linux-stage/include/linux/ext3_fs.h 2009-05-09 06:44:02.000000000 +0400 +++ linux-stage/include/linux/ext3_fs.h 2009-05-09 06:45:33.000000000 +0400 @@ -973,6 +973,7 @@ extern int ext3fs_dirhash(const char *na /* ialloc.c */ extern struct inode * ext3_new_inode (handle_t *, struct inode *, int, unsigned long); +extern unsigned long ext3_find_reverse(struct super_block *); extern void ext3_free_inode (handle_t *, struct inode *); extern struct inode * ext3_orphan_get (struct super_block *, unsigned long); extern unsigned long ext3_count_free_inodes (struct super_block *);