patch-2.0.32 linux/fs/inode.c

Next file: linux/fs/locks.c
Previous file: linux/fs/exec.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.31/linux/fs/inode.c linux/fs/inode.c
@@ -173,7 +173,25 @@
 {
 	struct wait_queue * wait;
 
+	/*
+	 * We can clear inodes either when a last deref to the inode 
+	 * causes it to be deleted (reference count==1), or when we want to 
+	 * reuse it (reference count==0).  Any other count is an error.
+	 */
+	if (inode->i_count > 1)
+		panic ("clear_inode: Inode still has references");
+
+	/*
+	 * We are about to zap this inode.  This operation may block,
+	 * and it's imperative that we don't allow another process to
+	 * grab it before it is completely pulled down.  The i_count
+	 * will prevent reuse of the inode by get_empty_inode(), but the
+	 * i_condemned flag will also prevent __iget() from finding the
+	 * inode until it is completely dead. 
+	 */
+	inode->i_condemned = 1;
 	inode->i_count++;
+	
 	truncate_inode_pages(inode, 0);
 	wait_on_inode(inode);
 	if (IS_WRITABLE(inode)) {
@@ -188,6 +206,11 @@
 	memset(inode,0,sizeof(*inode));
 	((volatile struct inode *) inode)->i_wait = wait;
 	insert_inode_free(inode);
+	/*
+	 * The inode is now reusable again, and the condemned flag is
+	 * clear.  Wake up anybody who is waiting on the condemned flag. 
+	 */
+	wake_up(&inode->i_wait);
 }
 
 int fs_may_mount(kdev_t dev)
@@ -428,6 +451,7 @@
 	}
 	if (inode->i_pipe)
 		wake_up_interruptible(&PIPE_WAIT(*inode));
+
 repeat:
 	if (inode->i_count>1) {
 		inode->i_count--;
@@ -501,7 +525,7 @@
 	for (i = nr_inodes/2; i > 0; i--,inode = inode->i_next) {
 		if (!inode->i_count) {
 			unsigned long i = 999;
-			if (!(inode->i_lock | inode->i_dirt))
+			if (!(inode->i_lock || inode->i_dirt))
 				i = inode->i_nrpages;
 			if (i < badness) {
 				best = inode;
@@ -615,6 +639,15 @@
 	goto return_it;
 
 found_it:
+	/*
+	 * The inode may currently be being pulled down by
+	 * clear_inode().  Avoid it if so.  If we get past this, then
+	 * the increment of i_count will prevent the inode's reuse.
+	 */
+	if (inode->i_condemned) {
+		sleep_on(&inode->i_wait);
+		goto repeat;
+	}
 	if (!inode->i_count)
 		nr_free_inodes--;
 	inode->i_count++;

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