fs/ext3/ialloc.c | 35 ++++++++++++++++++++++++++++++++++- fs/ext3/ioctl.c | 25 +++++++++++++++++++++++++ fs/ext3/namei.c | 21 +++++++++++++++++---- include/linux/dcache.h | 5 +++++ include/linux/ext3_fs.h | 5 ++++- 5 files changed, 85 insertions(+), 6 deletions(-) Index: linux-2.6.15/fs/ext3/ialloc.c =================================================================== --- linux-2.6.15.orig/fs/ext3/ialloc.c 2006-02-19 15:23:12.000000000 +0300 +++ linux-2.6.15/fs/ext3/ialloc.c 2006-02-21 00:26:52.000000000 +0300 @@ -420,7 +420,8 @@ static int find_group_other(struct super * For other inodes, search forward from the parent directory's block * group to find a free inode. */ -struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) +struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode, + unsigned long goal) { struct super_block *sb; struct buffer_head *bitmap_bh = NULL; @@ -448,6 +449,38 @@ struct inode *ext3_new_inode(handle_t *h sbi = EXT3_SB(sb); es = sbi->s_es; + if (goal) { + group = (goal - 1) / EXT3_INODES_PER_GROUP(sb); + ino = (goal - 1) % EXT3_INODES_PER_GROUP(sb); + gdp = ext3_get_group_desc(sb, group, &bh2); + + err = -EIO; + bitmap_bh = read_inode_bitmap (sb, group); + if (!bitmap_bh) + goto fail; + + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bitmap_bh); + if (err) goto fail; + + if (ext3_set_bit_atomic(sb_bgl_lock(sbi, group), + ino, bitmap_bh->b_data)) { + printk(KERN_ERR "goal inode %lu unavailable\n", goal); + /* Oh well, we tried. */ + goto continue_allocation; + } + + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (err) goto fail; + + /* We've shortcircuited the allocation system successfully, + * now finish filling in the inode. + */ + goto got; + } + +continue_allocation: if (S_ISDIR(mode)) { if (test_opt (sb, OLDALLOC)) group = find_group_dir(sb, dir); Index: linux-2.6.15/fs/ext3/ioctl.c =================================================================== --- linux-2.6.15.orig/fs/ext3/ioctl.c 2005-11-11 08:33:12.000000000 +0300 +++ linux-2.6.15/fs/ext3/ioctl.c 2006-02-21 00:26:52.000000000 +0300 @@ -25,6 +25,31 @@ int ext3_ioctl (struct inode * inode, st ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { + case EXT3_IOC_CREATE_INUM: { + char name[32]; + struct dentry *dchild, *dparent; + int rc = 0; + + dparent = list_entry(inode->i_dentry.next, struct dentry, + d_alias); + snprintf(name, sizeof name, "%lu", arg); + dchild = lookup_one_len(name, dparent, strlen(name)); + if (dchild->d_inode) { + printk(KERN_ERR "%*s/%lu already exists (ino %lu)\n", + dparent->d_name.len, dparent->d_name.name, arg, + dchild->d_inode->i_ino); + rc = -EEXIST; + } else { + dchild->d_fsdata = (void *)arg; + rc = vfs_create(inode, dchild, 0644, NULL); + if (rc) + printk(KERN_ERR "vfs_create: %d\n", rc); + else if (dchild->d_inode->i_ino != arg) + rc = -EEXIST; + } + dput(dchild); + return rc; + } case EXT3_IOC_GETFLAGS: flags = ei->i_flags & EXT3_FL_USER_VISIBLE; return put_user(flags, (int __user *) arg); Index: linux-2.6.15/fs/ext3/namei.c =================================================================== --- linux-2.6.15.orig/fs/ext3/namei.c 2006-02-19 15:23:12.000000000 +0300 +++ linux-2.6.15/fs/ext3/namei.c 2006-02-21 00:28:17.000000000 +0300 @@ -1631,6 +1631,16 @@ static int ext3_add_nondir(handle_t *han return err; } +static struct inode * ext3_new_inode_wantedi(handle_t *handle, struct inode *dir, + int mode, struct dentry *dentry) +{ + unsigned long inum = 0; + + if (dentry->d_fsdata != NULL) + inum = (unsigned long) dentry->d_fsdata; + return ext3_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 @@ -1656,7 +1666,7 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, mode); + inode = ext3_new_inode_wantedi (handle, dir, mode, dentry); err = PTR_ERR(inode); if (!IS_ERR(inode)) { inode->i_op = &ext3_file_inode_operations; @@ -1690,7 +1700,7 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, mode); + inode = ext3_new_inode_wantedi (handle, dir, mode, dentry); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); @@ -1726,7 +1736,7 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, S_IFDIR | mode); + inode = ext3_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; @@ -2131,7 +2141,7 @@ retry: if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); + inode = ext3_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.15/include/linux/ext3_fs.h =================================================================== --- linux-2.6.15.orig/include/linux/ext3_fs.h 2005-11-11 08:33:12.000000000 +0300 +++ linux-2.6.15/include/linux/ext3_fs.h 2006-02-21 00:26:52.000000000 +0300 @@ -762,7 +762,8 @@ extern int ext3fs_dirhash(const char *na dx_hash_info *hinfo); /* ialloc.c */ -extern struct inode * ext3_new_inode (handle_t *, struct inode *, int); +extern struct inode * ext3_new_inode (handle_t *, struct inode *, int, + unsigned long); 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 *); @@ -844,4 +845,6 @@ extern struct inode_operations ext3_fast #endif /* __KERNEL__ */ +/* EXT3_IOC_CREATE_INUM at bottom of file (visible to kernel and user). */ +#define EXT3_IOC_CREATE_INUM _IOW('f', 5, long) #endif /* _LINUX_EXT3_FS_H */