Skip to contentSkip to conversation

simplify udf_iget, fix race

PATCH New Christoph Hellwig 1 participant 1 message Dec 12, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 simplify udf_iget, fix race

udf_iget calls __udf_read_inode after the inode has been unlocked and other threads could access it. Switching to iget_locked() fixes this race and nicely simplifies the code.

fs/udf/inode.c +15 -69
@@ -920,30 +902,6 @@
 	unlock_kernel();
 }
 
-/*
- * udf_read_inode
- *
- * PURPOSE
- *	Read an inode.
- *
- * DESCRIPTION
- *	This routine is called by iget() [which is called by udf_iget()]
- *      (clean_inode() will have been called first)
- *	when an inode is first read into memory.
- *
- * HISTORY
- *	July 1, 1997 - Andrew E. Mileski
- *	Written, tested, and released.
- *
- * 12/19/98 dgb  Updated to fix size problems.
- */
-
-void
-udf_read_inode(struct inode *inode)
-{
-	memset(&UDF_I_LOCATION(inode), 0xFF, sizeof(kernel_lb_addr));
-}
-
 static void
 __udf_read_inode(struct inode *inode)
 {
@@ -1567,66 +1525,36 @@
 	return err;
 }
 
-/*
- * udf_iget
- *
- * PURPOSE
- *	Get an inode.
- *
- * DESCRIPTION
- *	This routine replaces iget() and read_inode().
- *
- * HISTORY
- *	October 3, 1997 - Andrew E. Mileski
- *	Written, tested, and released.
- *
- * 12/19/98 dgb  Added semaphore and changed to be a wrapper of iget
- */
 struct inode *
 udf_iget(struct super_block *sb, kernel_lb_addr ino)
 {
-	struct inode *inode;
-	unsigned long block;
-
-	block = udf_get_lb_pblock(sb, ino, 0);
-
-	/* Get the inode */
-
-	inode = iget(sb, block);
-		/* calls udf_read_inode() ! */
+	unsigned long block = udf_get_lb_pblock(sb, ino, 0);
+	struct inode *inode = iget_locked(sb, block);
 
 	if (!inode)
-	{
-		printk(KERN_ERR "udf: iget() failed\n");
 		return NULL;
-	}
-	else if (is_bad_inode(inode))
-	{
-		iput(inode);
-		return NULL;
-	}
-	else if (UDF_I_LOCATION(inode).logicalBlockNum == 0xFFFFFFFF &&
-		UDF_I_LOCATION(inode).partitionReferenceNum == 0xFFFF)
-	{
+
+	if (inode->i_state & I_NEW) {
 		memcpy(&UDF_I_LOCATION(inode), &ino, sizeof(kernel_lb_addr));
 		__udf_read_inode(inode);
-		if (is_bad_inode(inode))
-		{
-			iput(inode);
-			return NULL;
-		}
+		unlock_new_inode(inode);
 	}
 
-	if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) )
-	{
+	if (is_bad_inode(inode))
+		goto out_iput;
+
+	if (ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) {
 		udf_debug("block=%d, partition=%d out of range\n",
 			ino.logicalBlockNum, ino.partitionReferenceNum);
 		make_bad_inode(inode);
-		iput(inode);
-		return NULL;
- 	}
+		goto out_iput;
+	}
 
 	return inode;
+
+ out_iput:
+	iput(inode);
+	return NULL;
 }
 
 int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
fs/udf/super.c +0 -1
@@ -162,7 +162,6 @@
 static struct super_operations udf_sb_ops = {
 	.alloc_inode		= udf_alloc_inode,
 	.destroy_inode		= udf_destroy_inode,
-	.read_inode		= udf_read_inode,
 	.write_inode		= udf_write_inode,
 	.put_inode		= udf_put_inode,
 	.delete_inode		= udf_delete_inode,