aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2008-06-02 04:14:54 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2008-06-27 04:39:37 -0400
commit01b7c7ae88a6376c508b35a22bb61e04cb1b37f0 (patch)
tree01276b4382270285375540682d1eddf2a167103d
parent80274737220f8c5ea75696dde4c5c7feba39456f (diff)
[GFS2] Revise readpage locking
The previous attempt to fix the locking in readpage failed due to the use of a "try lock" which resulted in occasional high cpu usage during testing (due to repeated tries) and also it did not resolve all the ordering problems wrt the transaction lock (although it did solve all the inode lock ordering problems). This patch avoids the problem by unlocking the page and getting the locks in the correct order. This means that we have to retest the page to ensure that it hasn't changed when we relock the page. This now passes the tests which were previously failing. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/ops_address.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 2b556dd034bb..e64a1b04117a 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -499,31 +499,34 @@ static int __gfs2_readpage(void *file, struct page *page)
499 * @file: The file to read 499 * @file: The file to read
500 * @page: The page of the file 500 * @page: The page of the file
501 * 501 *
502 * This deals with the locking required. We use a trylock in order to 502 * This deals with the locking required. We have to unlock and
503 * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE 503 * relock the page in order to get the locking in the right
504 * in the event that we are unable to get the lock. 504 * order.
505 */ 505 */
506 506
507static int gfs2_readpage(struct file *file, struct page *page) 507static int gfs2_readpage(struct file *file, struct page *page)
508{ 508{
509 struct gfs2_inode *ip = GFS2_I(page->mapping->host); 509 struct address_space *mapping = page->mapping;
510 struct gfs2_inode *ip = GFS2_I(mapping->host);
510 struct gfs2_holder gh; 511 struct gfs2_holder gh;
511 int error; 512 int error;
512 513
513 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); 514 unlock_page(page);
515 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
514 error = gfs2_glock_nq_atime(&gh); 516 error = gfs2_glock_nq_atime(&gh);
515 if (unlikely(error)) { 517 if (unlikely(error))
516 unlock_page(page);
517 goto out; 518 goto out;
518 } 519 error = AOP_TRUNCATED_PAGE;
519 error = __gfs2_readpage(file, page); 520 lock_page(page);
521 if (page->mapping == mapping && !PageUptodate(page))
522 error = __gfs2_readpage(file, page);
523 else
524 unlock_page(page);
520 gfs2_glock_dq(&gh); 525 gfs2_glock_dq(&gh);
521out: 526out:
522 gfs2_holder_uninit(&gh); 527 gfs2_holder_uninit(&gh);
523 if (error == GLR_TRYFAILED) { 528 if (error && error != AOP_TRUNCATED_PAGE)
524 yield(); 529 lock_page(page);
525 return AOP_TRUNCATED_PAGE;
526 }
527 return error; 530 return error;
528} 531}
529 532