patch-2.1.58 linux/fs/proc/inode.c

Next file: linux/fs/proc/root.c
Previous file: linux/fs/proc/generic.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.57/linux/fs/proc/inode.c linux/fs/proc/inode.c
@@ -17,23 +17,66 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+extern void free_proc_entry(struct proc_dir_entry *);
+
+struct proc_dir_entry * de_get(struct proc_dir_entry *de)
+{
+	if (de)
+		de->count++;
+	return de;
+}
+
+/*
+ * Decrements the use count and checks for deferred deletion.
+ */
+void de_put(struct proc_dir_entry *de)
+{
+	if (de) {
+		if (!de->count) {
+			printk("de_put: entry %s already free!\n", de->name);
+			return;
+		}
+
+		if (!--de->count) {
+			if (de->deleted) {
+				printk("de_put: deferred delete of %s\n",
+					de->name);
+				free_proc_entry(de);
+			}
+		}
+	}
+}
+
 static void proc_put_inode(struct inode *inode)
 {
 #ifdef CONFIG_SUN_OPENPROMFS_MODULE
-	if ((inode->i_ino >= PROC_OPENPROM_FIRST)
-	    && (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
-	    && proc_openprom_use)
+	if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
+	    (inode->i_ino <  PROC_OPENPROM_FIRST + PROC_NOPENPROM) &&
+	    proc_openprom_use)
 		(*proc_openprom_use)(inode, 0);
 #endif	
+	/*
+	 * Kill off unused inodes ... VFS will unhash and
+	 * delete the inode if we set i_nlink to zero.
+	 */
+	if (inode->i_count == 1)
+		inode->i_nlink = 0;
 }
 
 /*
- * Does this ever happen?
+ * Decrement the use count of the proc_dir_entry.
  */
 static void proc_delete_inode(struct inode *inode)
 {
-	printk("proc_delete_inode()?\n");
-	inode->i_size = 0;
+	struct proc_dir_entry *de = inode->u.generic_ip;
+	if (de) {
+		/*
+		 * Call the fill_inode hook to release module counts.
+		 */
+		if (de->fill_inode)
+			de->fill_inode(inode, 0);
+		de_put(de);
+	}
 }
 
 static void proc_put_super(struct super_block *sb)
@@ -47,7 +90,7 @@
 	proc_read_inode,
 	proc_write_inode,
 	proc_put_inode,
-	proc_delete_inode,
+	proc_delete_inode,	/* delete_inode(struct inode *) */
 	NULL,
 	proc_put_super,
 	NULL,
@@ -85,9 +128,24 @@
 	return 1;
 }
 
-struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
+struct inode * proc_get_inode(struct super_block * sb, int ino,
+				struct proc_dir_entry * de)
 {
-	struct inode * inode = iget(s, ino);
+	struct inode * inode;
+
+	/*
+	 * Increment the use count so the dir entry can't disappear.
+	 */
+	de_get(de);
+#if 1
+/* shouldn't ever happen */
+if (de && de->deleted)
+printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
+#endif
+
+	inode = iget(sb, ino);
+	if (!inode)
+		goto out_fail;
 	
 #ifdef CONFIG_SUN_OPENPROMFS_MODULE
 	if ((inode->i_ino >= PROC_OPENPROM_FIRST)
@@ -95,23 +153,29 @@
 	    && proc_openprom_use)
 		(*proc_openprom_use)(inode, 1);
 #endif	
-	if (inode && inode->i_sb == s) {
-		inode->u.generic_ip = (void *) de;
-		if (de) {
-			if (de->mode) {
-				inode->i_mode = de->mode;
-				inode->i_uid = de->uid;
-				inode->i_gid = de->gid;
-			}
-			if (de->size)
-				inode->i_size = de->size;
-			if (de->ops)
-				inode->i_op = de->ops;
-			if (de->nlink)
-				inode->i_nlink = de->nlink;
-			if (de->fill_inode)
-				de->fill_inode(inode);
+	/* N.B. How can this test ever fail?? */
+	if (inode->i_sb != sb)
+		printk("proc_get_inode: inode fubar\n");
+
+	inode->u.generic_ip = (void *) de;
+	if (de) {
+		if (de->mode) {
+			inode->i_mode = de->mode;
+			inode->i_uid = de->uid;
+			inode->i_gid = de->gid;
 		}
+		if (de->size)
+			inode->i_size = de->size;
+		if (de->ops)
+			inode->i_op = de->ops;
+		if (de->nlink)
+			inode->i_nlink = de->nlink;
+		/*
+		 * The fill_inode routine should use this call 
+		 * to increment module counts, if necessary.
+		 */
+		if (de->fill_inode)
+			de->fill_inode(inode, 1);
 	}
 	/*
 	 * Fixup the root inode's nlink value
@@ -126,26 +190,40 @@
 		}
 		read_unlock(&tasklist_lock);
 	}
+out:
 	return inode;
+
+out_fail:
+	de_put(de);
+	goto out;
 }			
 
 struct super_block *proc_read_super(struct super_block *s,void *data, 
 				    int silent)
 {
+	struct inode * root_inode;
+
 	lock_super(s);
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = PROC_SUPER_MAGIC;
 	s->s_op = &proc_sops;
+	root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
+	if (!root_inode)
+		goto out_no_root;
+	s->s_root = d_alloc_root(root_inode, NULL);
+	if (!s->s_root)
+		goto out_no_root;
+	parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
 	unlock_super(s);
-	s->s_root = d_alloc_root(proc_get_inode(s, PROC_ROOT_INO, &proc_root), NULL);
-	if (!s->s_root) {
-		s->s_dev = 0;
-		printk("get root inode failed\n");
-		return NULL;
-	}
-	parse_options(data, &s->s_root->d_inode->i_uid, &s->s_root->d_inode->i_gid);
 	return s;
+
+out_no_root:
+	printk("proc_read_super: get root inode failed\n");
+	iput(root_inode);
+	s->s_dev = 0;
+	unlock_super(s);
+	return NULL;
 }
 
 int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov