From be888a21fc5e58201fd7e059c480820f2fad06e9 Mon Sep 17 00:00:00 2001 From: bwzhou Date: Fri, 16 Nov 2007 07:10:51 +0000 Subject: [PATCH] Branch b1_6 b=14138 r=adilger, johann resolve deadlock on i_size_read() introduced by race condition of i_size_write() --- lustre/llite/dir.c | 7 ++++++- lustre/llite/llite_lib.c | 5 ++++- lustre/llite/llite_mmap.c | 12 +++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index b78bbb5..b8d9702 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -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); diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index da1716f..e36bf75 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -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; diff --git a/lustre/llite/llite_mmap.c b/lustre/llite/llite_mmap.c index 6fe8e04..bd85590 100644 --- a/lustre/llite/llite_mmap.c +++ b/lustre/llite/llite_mmap.c @@ -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); -- 1.8.3.1