patch-2.3.47 linux/fs/inode.c

Next file: linux/fs/lockd/Makefile
Previous file: linux/fs/ext2/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.46/linux/fs/inode.c linux/fs/inode.c
@@ -156,11 +156,26 @@
 		inode->i_sb->s_op->write_inode(inode);
 }
 
+static inline void __iget(struct inode * inode)
+{
+	if (!inode->i_count++)
+	{
+		if (!(inode->i_state & I_DIRTY))
+		{
+			list_del(&inode->i_list);
+			list_add(&inode->i_list, &inode_in_use);
+		}
+		inodes_stat.nr_unused--;
+	}
+}
+
 static inline void sync_one(struct inode *inode)
 {
 	if (inode->i_state & I_LOCK) {
+		__iget(inode);
 		spin_unlock(&inode_lock);
 		__wait_on_inode(inode);
+		iput(inode);
 		spin_lock(&inode_lock);
 	} else {
 		list_del(&inode->i_list);
@@ -253,6 +268,8 @@
 		BUG();
 	if (!(inode->i_state & I_FREEING))
 		BUG();
+	if (inode->i_state & I_CLEAR)
+		BUG();
 	wait_on_inode(inode);
 	if (IS_QUOTAINIT(inode))
 		DQUOT_DROP(inode);
@@ -262,7 +279,7 @@
 		bdput(inode->i_bdev);
 		inode->i_bdev = NULL;
 	}
-	inode->i_state = 0;
+	inode->i_state = I_CLEAR;
 }
 
 /*
@@ -377,6 +394,8 @@
 
 		entry = entry->prev;
 		inode = INODE(tmp);
+		if (inode->i_state & (I_FREEING|I_CLEAR))
+			BUG();
 		if (!CAN_UNUSE(inode))
 			continue;
 		if (inode->i_count)
@@ -413,19 +432,6 @@
 	return 0;
 }
 
-static inline void __iget(struct inode * inode)
-{
-	if (!inode->i_count++)
-	{
-		if (!(inode->i_state & I_DIRTY))
-		{
-			list_del(&inode->i_list);
-			list_add(&inode->i_list, &inode_in_use);
-		}
-		inodes_stat.nr_unused--;
-	}
-}
-
 /*
  * Called with the inode lock held.
  * NOTE: we are not increasing the inode-refcount, you must call __iget()
@@ -603,6 +609,11 @@
 	if (!(inode->i_state & I_FREEING))
 		__iget(inode);
 	else
+		/*
+		 * Handle the case where s_op->clear_inode is not been
+		 * called yet, and somebody is calling igrab
+		 * while the inode is getting freed.
+		 */
 		inode = NULL;
 	spin_unlock(&inode_lock);
 	if (inode)
@@ -669,32 +680,39 @@
 				list_del(&inode->i_list);
 				INIT_LIST_HEAD(&inode->i_list);
 				inode->i_state|=I_FREEING;
+				spin_unlock(&inode_lock);
+
+				destroy = 1;
 				if (op && op->delete_inode) {
 					void (*delete)(struct inode *) = op->delete_inode;
-					spin_unlock(&inode_lock);
 					if (inode->i_data.nrpages)
 						truncate_inode_pages(&inode->i_data, 0);
+					/* s_op->delete_inode internally recalls clear_inode() */
 					delete(inode);
-					spin_lock(&inode_lock);
-				}
-			}
-			if (list_empty(&inode->i_hash)) {
-				list_del(&inode->i_list);
-				INIT_LIST_HEAD(&inode->i_list);
-				inode->i_state|=I_FREEING;
-				spin_unlock(&inode_lock);
-				clear_inode(inode);
-				destroy = 1;
+				} else
+					clear_inode(inode);
+				if (inode->i_state != I_CLEAR)
+					BUG();
+
 				spin_lock(&inode_lock);
-			}
-			else
-			{
-				if (!(inode->i_state & I_DIRTY)) {
+			} else {
+				if (!list_empty(&inode->i_hash)) {
+					if (!(inode->i_state & I_DIRTY)) {
+						list_del(&inode->i_list);
+						list_add(&inode->i_list,
+							 &inode_unused);
+					}
+					inodes_stat.nr_unused++;
+				} else {
+					/* magic nfs path */
 					list_del(&inode->i_list);
-					list_add(&inode->i_list,
-						 &inode_unused);
+					INIT_LIST_HEAD(&inode->i_list);
+					inode->i_state|=I_FREEING;
+					spin_unlock(&inode_lock);
+					clear_inode(inode);
+					destroy = 1;
+					spin_lock(&inode_lock);
 				}
-				inodes_stat.nr_unused++;
 			}
 #ifdef INODE_PARANOIA
 if (inode->i_flock)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)