fs/ext3/ialloc.c | 40 ++++++++++++++++++++++++++++++++++++++-- fs/ext3/inode.c | 2 +- fs/ext3/ioctl.c | 25 +++++++++++++++++++++++++ fs/ext3/namei.c | 21 +++++++++++++++++---- include/linux/dcache.h | 5 +++++ include/linux/ext3_fs.h | 5 ++++- 6 files changed, 90 insertions(+), 8 deletions(-) Index: linux-2.4.24/fs/ext3/namei.c =================================================================== --- linux-2.4.24.orig/fs/ext3/namei.c 2004-05-19 13:58:43.000000000 +0400 +++ linux-2.4.24/fs/ext3/namei.c 2004-05-21 18:26:43.000000000 +0400 @@ -1533,6 +1533,23 @@ return err; } +static struct inode * ext3_new_inode_wantedi(handle_t *handle, struct inode *dir, + int mode, struct dentry *dentry) +{ + struct dentry_params *param = (struct dentry_params *) dentry->d_fsdata; + unsigned long inum = 0; + struct inode *inode; + + if (param != NULL) + inum = param->p_inum; + inode = ext3_new_inode(handle, dir, mode, inum); + if (inode && param && inum && param->p_generation) { + inode->i_generation = param->p_generation; + ext3_mark_inode_dirty(handle, inode); + } + return inode; +} + /* * By the time this is called, we already have created * the directory cache entry for the new file, but it @@ -1556,7 +1573,7 @@ if (IS_SYNC(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; @@ -1584,7 +1601,7 @@ if (IS_SYNC(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, mode, rdev); @@ -1614,7 +1631,7 @@ if (IS_SYNC(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; @@ -2041,7 +2058,7 @@ if (IS_SYNC(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.4.24/fs/ext3/ialloc.c =================================================================== --- linux-2.4.24.orig/fs/ext3/ialloc.c 2004-05-19 13:58:43.000000000 +0400 +++ linux-2.4.24/fs/ext3/ialloc.c 2004-05-19 13:58:43.000000000 +0400 @@ -330,7 +330,8 @@ * group to find a free inode. */ struct inode * ext3_new_inode (handle_t *handle, - const struct inode * dir, int mode) + const struct inode * dir, int mode, + unsigned long goal) { struct super_block * sb; struct buffer_head * bh; @@ -355,7 +356,41 @@ init_rwsem(&inode->u.ext3_i.truncate_sem); lock_super (sb); - es = sb->u.ext3_sb.s_es; + es = EXT3_SB(sb)->s_es; + + if (goal) { + i = (goal - 1) / EXT3_INODES_PER_GROUP(sb); + j = (goal - 1) % EXT3_INODES_PER_GROUP(sb); + gdp = ext3_get_group_desc(sb, i, &bh2); + + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) { + err = bitmap_nr; + goto fail; + } + + bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr]; + + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) goto fail; + + if (ext3_set_bit(j, bh->b_data)) { + printk(KERN_ERR "goal inode %lu unavailable\n", goal); + /* Oh well, we tried. */ + goto repeat; + } + + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (err) goto fail; + + /* We've shortcircuited the allocation system successfully, + * now finish filling in the inode. + */ + goto have_bit_and_group; + } + repeat: gdp = NULL; i = 0; @@ -470,6 +505,7 @@ } goto repeat; } + have_bit_and_group: j += i * EXT3_INODES_PER_GROUP(sb) + 1; if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_new_inode", Index: linux-2.4.24/fs/ext3/inode.c =================================================================== --- linux-2.4.24.orig/fs/ext3/inode.c 2004-05-19 13:58:43.000000000 +0400 +++ linux-2.4.24/fs/ext3/inode.c 2004-05-19 13:58:43.000000000 +0400 @@ -2605,7 +2605,7 @@ if (IS_ERR(handle)) goto out_truncate; - new_inode = ext3_new_inode(handle, old_inode, old_inode->i_mode); + new_inode = ext3_new_inode(handle, old_inode, old_inode->i_mode, 0); if (IS_ERR(new_inode)) { ext3_debug("truncate inode %lu directly (no new inodes)\n", old_inode->i_ino); Index: linux-2.4.24/fs/ext3/ioctl.c =================================================================== --- linux-2.4.24.orig/fs/ext3/ioctl.c 2004-01-10 17:04:42.000000000 +0300 +++ linux-2.4.24/fs/ext3/ioctl.c 2004-05-19 13:58:43.000000000 +0400 @@ -23,6 +23,31 @@ 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); + 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 = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE; return put_user(flags, (int *) arg); Index: linux-2.4.24/include/linux/ext3_fs.h =================================================================== --- linux-2.4.24.orig/include/linux/ext3_fs.h 2004-05-19 13:58:43.000000000 +0400 +++ linux-2.4.24/include/linux/ext3_fs.h 2004-05-19 13:58:43.000000000 +0400 @@ -202,6 +202,7 @@ #define EXT3_IOC_SETFLAGS _IOW('f', 2, long) #define EXT3_IOC_GETVERSION _IOR('f', 3, long) #define EXT3_IOC_SETVERSION _IOW('f', 4, long) +/* EXT3_IOC_CREATE_INUM at bottom of file (visible to kernel and user). */ #define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) #define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) #ifdef CONFIG_JBD_DEBUG @@ -674,7 +675,8 @@ dx_hash_info *hinfo); /* ialloc.c */ -extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int); +extern struct inode * ext3_new_inode (handle_t *, const 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 *); @@ -766,4 +768,5 @@ #endif /* __KERNEL__ */ +#define EXT3_IOC_CREATE_INUM _IOW('f', 5, long) #endif /* _LINUX_EXT3_FS_H */ Index: linux-2.4.24/include/linux/dcache.h =================================================================== --- linux-2.4.24.orig/include/linux/dcache.h 2004-05-19 13:58:42.000000000 +0400 +++ linux-2.4.24/include/linux/dcache.h 2004-05-21 18:20:34.000000000 +0400 @@ -63,6 +63,12 @@ #define IS_ROOT(x) ((x) == (x)->d_parent) +struct dentry_params { + unsigned long p_inum; + unsigned long p_generation; + void *p_ptr; +}; + /* * "quick string" -- eases parameter passing, but more importantly * saves "metadata" about the string (ie length and the hash).