Whamcloud - gitweb
Branch b1_6
authorbwzhou <bwzhou>
Fri, 16 Nov 2007 07:10:51 +0000 (07:10 +0000)
committerbwzhou <bwzhou>
Fri, 16 Nov 2007 07:10:51 +0000 (07:10 +0000)
b=14138
r=adilger, johann

resolve deadlock on i_size_read() introduced by race condition of i_size_write()

lustre/llite/dir.c
lustre/llite/llite_lib.c
lustre/llite/llite_mmap.c

index b78bbb5..b8d9702 100644 (file)
@@ -105,7 +105,12 @@ static int ll_dir_readpage(struct file *file, struct page *page)
                 /* swabbed by mdc_readpage() */
                 LASSERT(lustre_rep_swabbed(request, REPLY_REC_OFF));
 
-                i_size_write(inode, body->size);
+                if (body->size != i_size_read(inode)) {
+                        ll_inode_size_lock(inode, 0);
+                        i_size_write(inode, body->size);
+                        ll_inode_size_unlock(inode, 0);
+                }
+
                 SetPageUptodate(page);
         }
         ptlrpc_req_finished(request);
index da1716f..e36bf75 100644 (file)
@@ -1738,8 +1738,11 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md)
 #else
                 inode->i_rdev = old_decode_dev(body->rdev);
 #endif
-        if (body->valid & OBD_MD_FLSIZE)
+        if (body->valid & OBD_MD_FLSIZE) {
+                ll_inode_size_lock(inode, 0);
                 i_size_write(inode, body->size);
+                ll_inode_size_unlock(inode, 0);
+        }
         if (body->valid & OBD_MD_FLBLOCKS)
                 inode->i_blocks = body->blocks;
 
index 6fe8e04..bd85590 100644 (file)
@@ -414,15 +414,21 @@ struct page *ll_nopage(struct vm_area_struct *vma, unsigned long address,
                 /* XXX change inode size without ll_inode_size_lock() held!
                  *     there is a race condition with truncate path. (see
                  *     ll_extent_lock) */
-               /* region is within kms and, hence, within real file size (A).
+                /* XXX i_size_write() is not used because it is not safe to
+                 *     take the ll_inode_size_lock() due to a potential lock
+                 *     inversion (bug 6077).  And since it's not safe to use
+                 *     i_size_write() without a covering mutex we do the
+                 *     assignment directly.  It is not critical that the
+                 *     size be correct. */
+                /* NOTE: region is within kms and, hence, within real file size (A).
                  * We need to increase i_size to cover the read region so that
                  * generic_file_read() will do its job, but that doesn't mean
                  * the kms size is _correct_, it is only the _minimum_ size.
                  * If someone does a stat they will get the correct size which
                  * will always be >= the kms value here.  b=11081 */
                 if (i_size_read(inode) < kms) {
-                        i_size_write(inode, kms);
-                        CDEBUG(D_INODE, "ino=%lu, updating i_size %llu\n",
+                        inode->i_size = kms;
+                        CDEBUG(D_INODE, "ino=%lu, updating i_size %llu\n",
                                inode->i_ino, i_size_read(inode));
                 }
                 lov_stripe_unlock(lsm);