All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH/RFC] Replacing iget4/read_inode2 with icreate
@ 2002-04-29 23:24 Jan Harkes
  2002-04-30  6:12 ` Christoph Hellwig
  2002-04-30 15:54 ` Steve Lord
  0 siblings, 2 replies; 14+ messages in thread
From: Jan Harkes @ 2002-04-29 23:24 UTC (permalink / raw)
  To: Alexander Viro, Chris Mason; +Cc: linux-fsdevel


This patch replaces iget4/read_inode2 with icreate. It is pretty much
the XFS icreate + a fix for the init race. Modified both Coda and
ReiserFS to use icreate and do their own inode initialization.

I tested it for Coda and it seems to be stable. Can't reproduce the race
on the SMP box here. I'd like to know if I made the right ReiserFS
changes.

Jan

Patch is against 2.5.11,

diff -urN orig/fs/Makefile icreate3/fs/Makefile
--- orig/fs/Makefile	Mon Apr 29 14:10:14 2002
+++ icreate3/fs/Makefile	Mon Apr 29 15:28:02 2002
@@ -7,7 +7,7 @@
 
 O_TARGET := fs.o
 
-export-objs :=	filesystems.o open.o dcache.o buffer.o bio.o
+export-objs :=	filesystems.o open.o dcache.o buffer.o bio.o inode.o
 mod-subdirs :=	nls
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
diff -urN orig/fs/coda/cnode.c icreate3/fs/coda/cnode.c
--- orig/fs/coda/cnode.c	Tue Apr  2 14:36:09 2002
+++ icreate3/fs/coda/cnode.c	Mon Apr 29 17:06:37 2002
@@ -25,7 +25,7 @@
 	return 1;
 }
 
-static int coda_inocmp(struct inode *inode, unsigned long ino, void *opaque)
+static int coda_inocmp(struct inode *inode, void *opaque)
 {
 	return (coda_fideq((ViceFid *)opaque, &(ITOC(inode)->c_fid)));
 }
@@ -55,26 +55,30 @@
                 init_special_inode(inode, inode->i_mode, attr->va_rdev);
 }
 
+int coda_init_inode(struct inode *inode, void *data)
+{
+    ITOC(inode)->c_fid = *(ViceFid *)data;
+    return 0;
+}
+
 struct inode * coda_iget(struct super_block * sb, ViceFid * fid,
 			 struct coda_vattr * attr)
 {
 	struct inode *inode;
 	struct coda_inode_info *cii;
+	struct coda_sb_info *sbi = coda_sbp(sb);
 	ino_t ino = coda_f2i(fid);
 
-	inode = iget4(sb, ino, coda_inocmp, fid);
+	inode = icreate(sb, ino, coda_inocmp, coda_init_inode, fid);
 
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 
-	/* check if the inode is already initialized */
-	cii = ITOC(inode);
-	if (coda_isnullfid(&cii->c_fid))
-		/* new, empty inode found... initializing */
-		cii->c_fid = *fid;
-
-	/* we shouldnt see inode collisions anymore */
-	if (!coda_fideq(fid, &cii->c_fid)) BUG();
+	if (inode->i_state & I_NEW) {
+		cii = ITOC(inode);
+		list_add(&cii->c_cilist, &sbi->sbi_cihead);
+		unlock_new_inode(inode);
+	}
 
 	/* always replace the attributes, type might have changed */
 	coda_fill_inode(inode, attr);
@@ -126,12 +130,16 @@
 	insert_inode_hash(inode);
 }
 
+int coda_fail_inode(struct inode *inode, void *opaque)
+{
+    return -1;
+}
+
 /* convert a fid to an inode. */
 struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) 
 {
 	ino_t nr;
 	struct inode *inode;
-	struct coda_inode_info *cii;
 
 	if ( !sb ) {
 		printk("coda_fid_to_inode: no sb!\n");
@@ -139,24 +147,13 @@
 	}
 
 	nr = coda_f2i(fid);
-	inode = iget4(sb, nr, coda_inocmp, fid);
-	if ( !inode ) {
-		printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
-		       sb, (long)nr);
-		return NULL;
-	}
-
-	cii = ITOC(inode);
-
-	/* The inode could already be purged due to memory pressure */
-	if (coda_isnullfid(&cii->c_fid)) {
-		inode->i_nlink = 0;
-		iput(inode);
+	inode = icreate(sb, nr, coda_inocmp, coda_fail_inode, fid);
+	if ( !inode )
 		return NULL;
-	}
 
-	/* we shouldn't see inode collisions anymore */
-	if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
+	/* we should never see newly created inodes because we intentionally
+	 * fail in the initialization callback */
+	BUG_ON(inode->i_state & I_NEW);
 
         return inode;
 }
@@ -165,13 +162,14 @@
 int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
 {
     int error = 0;
+    ViceFid nullfid = {0,0,0};
 
-    *inode = iget(sb, CTL_INO);
-    if ( *inode ) {
+    *inode = icreate(sb, CTL_INO, NULL, NULL, NULL);
+    if ( *inode && ((*inode)->i_state & I_NEW) ) {
 	(*inode)->i_op = &coda_ioctl_inode_operations;
 	(*inode)->i_fop = &coda_ioctl_operations;
 	(*inode)->i_mode = 0444;
-	error = 0;
+	unlock_new_inode(*inode);
     } else { 
 	error = -ENOMEM;
     }
diff -urN orig/fs/coda/inode.c icreate3/fs/coda/inode.c
--- orig/fs/coda/inode.c	Mon Apr 29 14:09:02 2002
+++ icreate3/fs/coda/inode.c	Mon Apr 29 15:55:16 2002
@@ -229,16 +229,9 @@
 	kfree(sbi);
 }
 
-/* all filling in of inodes postponed until lookup */
 static void coda_read_inode(struct inode *inode)
 {
-	struct coda_sb_info *sbi = coda_sbp(inode->i_sb);
-	struct coda_inode_info *cii;
-
-        if (!sbi) BUG();
-
-	cii = ITOC(inode);
-	list_add(&cii->c_cilist, &sbi->sbi_cihead);
+	make_bad_inode(inode);
 }
 
 static void coda_clear_inode(struct inode *inode)
diff -urN orig/fs/inode.c icreate3/fs/inode.c
--- orig/fs/inode.c	Mon Apr 29 14:09:02 2002
+++ icreate3/fs/inode.c	Mon Apr 29 18:49:57 2002
@@ -17,6 +17,7 @@
 #include <linux/swapctl.h>
 #include <linux/prefetch.h>
 #include <linux/locks.h>
+#include <linux/module.h>
 
 /*
  * New inode.c implementation.
@@ -793,7 +794,7 @@
  * 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, find_inode_t find_actor, void *opaque)
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, int (*test)(struct inode *, void *), void *data)
 {
 	struct list_head *tmp;
 	struct inode * inode;
@@ -809,7 +810,7 @@
 			continue;
 		if (inode->i_sb != sb)
 			continue;
-		if (find_actor && !find_actor(inode, ino, opaque))
+		if (test && !test(inode, data))
 			continue;
 		break;
 	}
@@ -842,53 +843,59 @@
 	return inode;
 }
 
+void unlock_new_inode(struct inode *inode)
+{
+	BUG_ON(!(inode->i_state & I_NEW));
+	/*
+	 * This is special!  We do not need the spinlock
+	 * when clearing I_LOCK, because we're guaranteed
+	 * that nobody else tries to do anything about the
+	 * state of the inode when it is locked, as we
+	 * just created it (so there can be no old holders
+	 * that haven't tested I_LOCK).
+	 */
+	inode->i_state &= ~(I_LOCK|I_NEW);
+	wake_up(&inode->i_wait);
+}
+
+
 /*
  * This is called without the inode lock held.. Be careful.
  *
  * 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, find_inode_t find_actor, void *opaque)
+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)
 {
 	struct inode * inode;
+	int err = 0;
 
 	inode = alloc_inode(sb);
 	if (inode) {
 		struct inode * old;
+		inode->i_state = I_LOCK|I_NEW;
 
 		spin_lock(&inode_lock);
 		/* We released the lock, so.. */
-		old = find_inode(sb, ino, head, find_actor, opaque);
+		old = find_inode(sb, ino, head, test, data);
 		if (!old) {
-			inodes_stat.nr_inodes++;
-			list_add(&inode->i_list, &inode_in_use);
-			list_add(&inode->i_hash, head);
 			inode->i_ino = ino;
-			inode->i_state = I_LOCK;
+			if (!set || (err = set(inode, data)) == 0) {
+			    inodes_stat.nr_inodes++;
+			    list_add(&inode->i_list, &inode_in_use);
+			    list_add(&inode->i_hash, head);
+			}
 			spin_unlock(&inode_lock);
 
-			/* reiserfs specific hack right here.  We don't
-			** want this to last, and are looking for VFS changes
-			** that will allow us to get rid of it.
-			** -- mason@suse.com 
-			*/
-			if (sb->s_op->read_inode2) {
-				sb->s_op->read_inode2(inode, opaque) ;
-			} else {
-				sb->s_op->read_inode(inode);
+			/* failed to initialize? */
+			if (err) {
+			    destroy_inode(inode);
+			    return NULL;
 			}
 
-			/*
-			 * This is special!  We do not need the spinlock
-			 * when clearing I_LOCK, because we're guaranteed
-			 * that nobody else tries to do anything about the
-			 * state of the inode when it is locked, as we
-			 * just created it (so there can be no old holders
-			 * that haven't tested I_LOCK).
+			/* Return the locked inode with I_NEW set, the
+			 * caller is responsible for filling in the contents
 			 */
-			inode->i_state &= ~I_LOCK;
-			wake_up(&inode->i_wait);
-
 			return inode;
 		}
 
@@ -968,14 +975,18 @@
 	return inode;
 }
 
-
-struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
+/*
+ * This is iget4 without the read_inode portion of get_new_inode
+ * the filesystem gets back a new locked and hashed inode and gets
+ * to fill it in before unlocking it via unlock_new_inode().
+ */
+struct inode *icreate(struct super_block *sb, unsigned long ino, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data)
 {
 	struct list_head * head = inode_hashtable + hash(sb,ino);
 	struct inode * inode;
 
 	spin_lock(&inode_lock);
-	inode = find_inode(sb, ino, head, find_actor, opaque);
+	inode = find_inode(sb, ino, head, test, data);
 	if (inode) {
 		__iget(inode);
 		spin_unlock(&inode_lock);
@@ -984,12 +995,11 @@
 	}
 	spin_unlock(&inode_lock);
 
-	/*
-	 * 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, find_actor, opaque);
+	return get_new_inode(sb, ino, head, test, set, data);
 }
+
+EXPORT_SYMBOL(icreate);
+EXPORT_SYMBOL(unlock_new_inode);
 
 /**
  *	insert_inode_hash - hash an inode
diff -urN orig/fs/reiserfs/inode.c icreate3/fs/reiserfs/inode.c
--- orig/fs/reiserfs/inode.c	Mon Apr 29 14:10:15 2002
+++ icreate3/fs/reiserfs/inode.c	Mon Apr 29 17:15:22 2002
@@ -33,7 +33,7 @@
     lock_kernel() ; 
 
     /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
-    if (INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
+    if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
 	down (&inode->i_sem); 
 
 	journal_begin(&th, inode->i_sb, jbegin_count) ;
@@ -1134,19 +1134,20 @@
 
 /* looks for stat data in the tree, and fills up the fields of in-core
    inode stat data fields */
-void reiserfs_read_inode2 (struct inode * inode, void *p)
+int reiserfs_init_inode (struct inode * inode, void *p)
+{
+    struct reiserfs_iget4_args *args = (struct reiserfs_iget4_args *)p ;
+    INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->objectid);
+    return 0;
+}
+
+void reiserfs_init_inode2 (struct inode * inode, struct reiserfs_iget4_args *args)
 {
     INITIALIZE_PATH (path_to_sd);
     struct cpu_key key;
-    struct reiserfs_iget4_args *args = (struct reiserfs_iget4_args *)p ;
     unsigned long dirino;
     int retval;
 
-    if (!p) {
-	reiserfs_make_bad_inode(inode) ;
-	return;
-    }
-
     dirino = args->objectid ;
 
     /* set version 1, version 2 could be used too, because stat data
@@ -1216,8 +1217,7 @@
  * inode numbers (objectids) are distinguished by parent directory ids.
  *
  */
-static int reiserfs_find_actor( struct inode *inode, 
-				unsigned long inode_no, void *opaque )
+static int reiserfs_find_actor( struct inode *inode, void *opaque )
 {
     struct reiserfs_iget4_args *args;
 
@@ -1232,10 +1232,15 @@
     struct reiserfs_iget4_args args ;
 
     args.objectid = key->on_disk_key.k_dir_id ;
-    inode = iget4 (s, key->on_disk_key.k_objectid, 
-		   reiserfs_find_actor, (void *)(&args));
+    inode = icreate (s, key->on_disk_key.k_objectid, 
+		     reiserfs_find_actor, reiserfs_init_inode, (void *)(&args));
     if (!inode) 
 	return ERR_PTR(-ENOMEM) ;
+
+    if (inode->i_state & I_NEW) {
+	reiserfs_init_inode2(inode, &args);
+	unlock_new_inode(inode);
+    }
 
     if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
 	/* either due to i/o error or a stale NFS handle */
diff -urN orig/fs/reiserfs/super.c icreate3/fs/reiserfs/super.c
--- orig/fs/reiserfs/super.c	Mon Apr 29 14:09:03 2002
+++ icreate3/fs/reiserfs/super.c	Mon Apr 29 16:18:28 2002
@@ -485,7 +485,6 @@
   alloc_inode: reiserfs_alloc_inode,
   destroy_inode: reiserfs_destroy_inode,
   read_inode: reiserfs_read_inode,
-  read_inode2: reiserfs_read_inode2,
   write_inode: reiserfs_write_inode,
   dirty_inode: reiserfs_dirty_inode,
   delete_inode: reiserfs_delete_inode,
@@ -1065,10 +1064,15 @@
 	s->s_flags |= MS_RDONLY ;
     }
     args.objectid = REISERFS_ROOT_PARENT_OBJECTID ;
-    root_inode = iget4 (s, REISERFS_ROOT_OBJECTID, 0, (void *)(&args));
+    root_inode = icreate (s, REISERFS_ROOT_OBJECTID, 0, reiserfs_init_inode, (void *)(&args));
     if (!root_inode) {
 	printk ("reiserfs_fill_super: get root inode failed\n");
 	goto error;
+    }
+
+    if (root_inode->i_state & I_NEW) {
+	reiserfs_init_inode2(root_inode, &args);
+	unlock_new_inode(root_inode);
     }
 
     s->s_root = d_alloc_root(root_inode);  
diff -urN orig/include/linux/fs.h icreate3/include/linux/fs.h
--- orig/include/linux/fs.h	Mon Apr 29 14:11:21 2002
+++ icreate3/include/linux/fs.h	Mon Apr 29 18:52:01 2002
@@ -852,13 +852,6 @@
 
 	void (*read_inode) (struct inode *);
   
-  	/* reiserfs kludge.  reiserfs needs 64 bits of information to
-    	** find an inode.  We are using the read_inode2 call to get
-   	** that information.  We don't like this, and are waiting on some
-   	** VFS changes for the real solution.
-   	** iget4 calls read_inode2, iff it is defined
-   	*/
-    	void (*read_inode2) (struct inode *, void *) ;
    	void (*dirty_inode) (struct inode *);
 	void (*write_inode) (struct inode *, int);
 	void (*put_inode) (struct inode *);
@@ -906,6 +899,7 @@
 #define I_LOCK			8
 #define I_FREEING		16
 #define I_CLEAR			32
+#define I_NEW			64
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 
@@ -1442,11 +1436,21 @@
 extern struct inode * igrab(struct inode *);
 extern ino_t iunique(struct super_block *, ino_t);
 
-typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
-extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+extern struct inode * icreate(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data);
+extern void unlock_new_inode(struct inode *);
+
 static inline struct inode *iget(struct super_block *sb, unsigned long ino)
 {
-	return iget4(sb, ino, NULL, NULL);
+	struct inode *inode;
+
+	inode = icreate(sb, ino, NULL, NULL, NULL);
+
+	if (inode && (inode->i_state & I_NEW)) {
+		sb->s_op->read_inode(inode);
+		unlock_new_inode(inode);
+	}
+
+	return inode;
 }
 
 extern void clear_inode(struct inode *);
diff -urN orig/include/linux/reiserfs_fs.h icreate3/include/linux/reiserfs_fs.h
--- orig/include/linux/reiserfs_fs.h	Mon Apr 29 14:10:33 2002
+++ icreate3/include/linux/reiserfs_fs.h	Mon Apr 29 16:17:31 2002
@@ -1819,7 +1819,8 @@
 /* inode.c */
 
 void reiserfs_read_inode (struct inode * inode) ;
-void reiserfs_read_inode2(struct inode * inode, void *p) ;
+int reiserfs_init_inode(struct inode * inode, void *p) ;
+void reiserfs_init_inode2(struct inode * inode, struct reiserfs_iget4_args *args) ;
 void reiserfs_delete_inode (struct inode * inode);
 void reiserfs_write_inode (struct inode * inode, int) ;
 struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data,
diff -urN orig/kernel/ksyms.c icreate3/kernel/ksyms.c
--- orig/kernel/ksyms.c	Mon Apr 29 14:11:22 2002
+++ icreate3/kernel/ksyms.c	Mon Apr 29 16:02:01 2002
@@ -137,7 +137,6 @@
 EXPORT_SYMBOL(fget);
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
-EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2002-05-01 16:17 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-04-29 23:24 [PATCH/RFC] Replacing iget4/read_inode2 with icreate Jan Harkes
2002-04-30  6:12 ` Christoph Hellwig
2002-04-30 14:52   ` Jan Harkes
2002-04-30 15:50     ` Jan Harkes
2002-04-30 15:54 ` Steve Lord
2002-04-30 16:05   ` Steve Lord
2002-04-30 16:14   ` Jan Harkes
2002-04-30 16:29     ` Steve Lord
2002-04-30 16:40     ` Chris Mason
2002-04-30 17:03       ` Jan Harkes
2002-05-01  2:42         ` Jan Harkes
2002-05-01  3:25           ` Alexander Viro
2002-05-01  3:47             ` Jan Harkes
2002-05-01 16:17           ` Kai Henningsen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.