From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoph Hellwig Subject: [PATCH] simplify udf_iget, fix race Date: Sun, 12 Dec 2004 14:34:51 +0100 Message-ID: <20041212133451.GA6425@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: linux-fsdevel@vger.kernel.org Return-path: Received: from verein.lst.de ([213.95.11.210]:26522 "EHLO mail.lst.de") by vger.kernel.org with ESMTP id S262070AbULLNe5 (ORCPT ); Sun, 12 Dec 2004 08:34:57 -0500 To: akpm@osdl.org Content-Disposition: inline Sender: linux-fsdevel-owner@vger.kernel.org List-Id: linux-fsdevel.vger.kernel.org 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. --- 1.42/fs/udf/inode.c 2004-09-17 08:58:42 +02:00 +++ edited/fs/udf/inode.c 2004-12-12 14:00:57 +01:00 @@ -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, --- 1.45/fs/udf/super.c 2004-09-09 20:49:06 +02:00 +++ edited/fs/udf/super.c 2004-12-12 14:02:19 +01:00 @@ -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,