[PATCH] 2.5.16 iget_locked [5/6]

Jan Harkes (jaharkes@cs.cmu.edu)
Mon, 20 May 2002 09:10:51 -0400


This patch starts taking i_ino dependencies out of the VFS. The FS
provided test and set callbacks become responsible for testing and
setting inode->i_ino.

Because most filesystems are based on 32-bit unique inode numbers
several functions are duplicated to keep iget_locked as a fast path. We
can avoid unnecessary pointer dereferences and function calls for this
specific case.

diff -urN iget_locked-4/Documentation/filesystems/porting iget_locked-5/Documentation/filesystems/porting
--- iget_locked-4/Documentation/filesystems/porting Sun May 19 18:12:14 2002
+++ iget_locked-5/Documentation/filesystems/porting Sun May 19 18:15:11 2002
@@ -175,8 +175,10 @@
called so the file system still has to finalize the initialization. Once
the inode is initialized it must be unlocked by calling unlock_new_inode().

-There is also a simpler iget_locked function that just takes the
-superblock and inode number as arguments.
+The filesystem is responsible for setting (and possibly testing) i_ino
+when appropriate. There is also a simpler iget_locked function that
+just takes the superblock and inode number as arguments and does the
+test and set for you.

e.g.
inode = iget_locked(sb, ino);
diff -urN iget_locked-4/fs/coda/cnode.c iget_locked-5/fs/coda/cnode.c
--- iget_locked-4/fs/coda/cnode.c Sun May 19 18:07:01 2002
+++ iget_locked-5/fs/coda/cnode.c Sun May 19 18:15:11 2002
@@ -83,6 +83,7 @@

if (inode->i_state & I_NEW) {
cii = ITOC(inode);
+ inode->i_ino = ino;
list_add(&cii->c_cilist, &sbi->sbi_cihead);
unlock_new_inode(inode);
}
diff -urN iget_locked-4/fs/inode.c iget_locked-5/fs/inode.c
--- iget_locked-4/fs/inode.c Sun May 19 18:11:28 2002
+++ iget_locked-5/fs/inode.c Sun May 19 18:21:19 2002
@@ -453,7 +453,32 @@
* by hand after calling find_inode now! This simplifies iunique and won't
* add any additional branch in the common code.
*/
-static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, int (*test)(struct inode *, void *), void *data)
+static struct inode * find_inode(struct super_block * sb, struct list_head *head, int (*test)(struct inode *, void *), void *data)
+{
+ struct list_head *tmp;
+ struct inode * inode;
+
+ tmp = head;
+ for (;;) {
+ tmp = tmp->next;
+ inode = NULL;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_hash);
+ if (inode->i_sb != sb)
+ continue;
+ if (!test(inode, data))
+ continue;
+ break;
+ }
+ return inode;
+}
+
+/*
+ * find_inode_fast is the fast path version of find_inode, see the comment at
+ * iget_locked for details.
+ */
+static struct inode * find_inode_fast(struct super_block * sb, struct list_head *head, unsigned long ino)
{
struct list_head *tmp;
struct inode * inode;
@@ -469,8 +494,6 @@
continue;
if (inode->i_sb != sb)
continue;
- if (test && !test(inode, data))
- continue;
break;
}
return inode;
@@ -523,10 +546,9 @@
* We no longer cache the sb_flags in i_flags - see fs.h
* -- rmk@arm.uk.linux.org
*/
-static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data)
+static struct inode * get_new_inode(struct super_block *sb, struct list_head *head, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data)
{
struct inode * inode;
- int err = 0;

inode = alloc_inode(sb);
if (inode) {
@@ -534,10 +556,9 @@

spin_lock(&inode_lock);
/* We released the lock, so.. */
- old = find_inode(sb, ino, head, test, data);
+ old = find_inode(sb, head, test, data);
if (!old) {
- inode->i_ino = ino;
- if (set && set(inode, data))
+ if (set(inode, data))
goto set_failed;

inodes_stat.nr_inodes++;
@@ -571,6 +592,49 @@
return NULL;
}

+/*
+ * get_new_inode_fast is the fast path version of get_new_inode, see the
+ * comment at iget_locked for details.
+ */
+static struct inode * get_new_inode_fast(struct super_block *sb, struct list_head *head, unsigned long ino)
+{
+ struct inode * inode;
+
+ inode = alloc_inode(sb);
+ if (inode) {
+ struct inode * old;
+
+ spin_lock(&inode_lock);
+ /* We released the lock, so.. */
+ old = find_inode_fast(sb, head, ino);
+ if (!old) {
+ inode->i_ino = ino;
+ inodes_stat.nr_inodes++;
+ list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_hash, head);
+ inode->i_state = I_LOCK|I_NEW;
+ spin_unlock(&inode_lock);
+
+ /* Return the locked inode with I_NEW set, the
+ * caller is responsible for filling in the contents
+ */
+ return inode;
+ }
+
+ /*
+ * Uhhuh, somebody else created the same inode under
+ * us. Use the old inode instead of the one we just
+ * allocated.
+ */
+ __iget(old);
+ spin_unlock(&inode_lock);
+ destroy_inode(inode);
+ inode = old;
+ wait_on_inode(inode);
+ }
+ return inode;
+}
+
static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
{
unsigned long tmp = i_ino + ((unsigned long) sb / L1_CACHE_BYTES);
@@ -605,7 +669,8 @@
retry:
if (counter > max_reserved) {
head = inode_hashtable + hash(sb,counter);
- inode = find_inode(sb, res = counter++, head, NULL, NULL);
+ res = counter++;
+ inode = find_inode_fast(sb, head, res);
if (!inode) {
spin_unlock(&inode_lock);
return res;
@@ -644,7 +709,7 @@
struct inode * inode;

spin_lock(&inode_lock);
- inode = find_inode(sb, ino, head, test, data);
+ inode = find_inode(sb, head, test, data);
if (inode) {
__iget(inode);
spin_unlock(&inode_lock);
@@ -657,12 +722,36 @@
* get_new_inode() will do the right thing, re-trying the search
* in case it had to block at any point.
*/
- return get_new_inode(sb, ino, head, test, set, data);
+ return get_new_inode(sb, head, test, set, data);
}

+/*
+ * Because most filesystems are based on 32-bit unique inode numbers some
+ * functions are duplicated to keep iget_locked as a fast path. We can avoid
+ * unnecessary pointer dereferences and function calls for this specific
+ * case. The duplicated functions (find_inode_fast and get_new_inode_fast)
+ * have the same pre- and post-conditions as their original counterparts.
+ */
struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{
- return iget5_locked(sb, ino, NULL, NULL, NULL);
+ struct list_head * head = inode_hashtable + hash(sb, ino);
+ struct inode * inode;
+
+ spin_lock(&inode_lock);
+ inode = find_inode_fast(sb, head, ino);
+ if (inode) {
+ __iget(inode);
+ spin_unlock(&inode_lock);
+ wait_on_inode(inode);
+ return inode;
+ }
+ spin_unlock(&inode_lock);
+
+ /*
+ * get_new_inode_fast() will do the right thing, re-trying the search
+ * in case it had to block at any point.
+ */
+ return get_new_inode_fast(sb, head, ino);
}

EXPORT_SYMBOL(iget5_locked);
diff -urN iget_locked-4/fs/nfs/inode.c iget_locked-5/fs/nfs/inode.c
--- iget_locked-4/fs/nfs/inode.c Sun May 19 18:09:14 2002
+++ iget_locked-5/fs/nfs/inode.c Sun May 19 18:15:11 2002
@@ -661,6 +661,8 @@
loff_t new_isize;
time_t new_atime;

+ inode->i_ino = ino;
+
/* We can't support UPDATE_ATIME(), since the server will reset it */
inode->i_flags |= S_NOATIME;
inode->i_mode = fattr->mode;
diff -urN iget_locked-4/fs/reiserfs/inode.c iget_locked-5/fs/reiserfs/inode.c
--- iget_locked-4/fs/reiserfs/inode.c Sun May 19 18:10:06 2002
+++ iget_locked-5/fs/reiserfs/inode.c Sun May 19 18:15:11 2002
@@ -1136,7 +1136,8 @@
int reiserfs_init_locked_inode (struct inode * inode, void *p)
{
struct reiserfs_iget_args *args = (struct reiserfs_iget_args *)p ;
- INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->objectid);
+ inode->i_ino = args->objectid;
+ INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->dirid);
return 0;
}

@@ -1149,7 +1150,7 @@
unsigned long dirino;
int retval;

- dirino = args->objectid ;
+ dirino = args->dirid ;

/* set version 1, version 2 could be used too, because stat data
key is the same in both versions */
@@ -1223,7 +1224,8 @@

args = opaque;
/* args is already in CPU order */
- return le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args -> objectid;
+ return (inode->i_ino == args->objectid) &&
+ (le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args->dirid);
}

struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key)
@@ -1231,7 +1233,8 @@
struct inode * inode;
struct reiserfs_iget_args args ;

- args.objectid = key->on_disk_key.k_dir_id ;
+ args.objectid = key->on_disk_key.k_objectid ;
+ args.dirid = key->on_disk_key.k_dir_id ;
inode = iget5_locked (s, key->on_disk_key.k_objectid,
reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args));
if (!inode)
diff -urN iget_locked-4/fs/reiserfs/super.c iget_locked-5/fs/reiserfs/super.c
--- iget_locked-4/fs/reiserfs/super.c Sun May 19 18:10:31 2002
+++ iget_locked-5/fs/reiserfs/super.c Sun May 19 18:15:11 2002
@@ -1067,7 +1067,8 @@
printk("clm-7000: Detected readonly device, marking FS readonly\n") ;
s->s_flags |= MS_RDONLY ;
}
- args.objectid = REISERFS_ROOT_PARENT_OBJECTID ;
+ args.objectid = REISERFS_ROOT_OBJECTID ;
+ args.dirid = REISERFS_ROOT_PARENT_OBJECTID ;
root_inode = iget5_locked (s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args));
if (!root_inode) {
printk ("reiserfs_fill_super: get root inode failed\n");
diff -urN iget_locked-4/include/linux/reiserfs_fs.h iget_locked-5/include/linux/reiserfs_fs.h
--- iget_locked-4/include/linux/reiserfs_fs.h Sun May 19 18:10:42 2002
+++ iget_locked-5/include/linux/reiserfs_fs.h Sun May 19 18:15:11 2002
@@ -1566,6 +1566,7 @@

struct reiserfs_iget_args {
__u32 objectid ;
+ __u32 dirid ;
} ;

/***************************************************************************/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/