aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_address.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2008-02-22 11:07:18 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2008-03-31 05:41:12 -0400
commit7afd88d9166a752b52517648bcbe923e05d393fc (patch)
tree2fb945189e3cb1be7ad007088f8ec86e9f67ece6 /fs/gfs2/ops_address.c
parent60b779cfc1fa52034a996ee12a23b62d32e86000 (diff)
[GFS2] Fix a page lock / glock deadlock
We've previously been using a "try lock" in readpage on the basis that it would prevent deadlocks due to the inverted lock ordering (our normal lock ordering is glock first and then page lock). Unfortunately tests have shown that this isn't enough. If the glock has a demote request queued such that run_queue() in the glock code tries to do a demote when its called under readpage then it will try and write out all the dirty pages which requires locking them. This then deadlocks with the page locked by readpage. The solution is to always require two calls into readpage. The first unlocks the page, gets the glock and returns AOP_TRUNCATED_PAGE, the second does the actual readpage and unlocks the glock & page as required. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_address.c')
-rw-r--r--fs/gfs2/ops_address.c27
1 files changed, 15 insertions, 12 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 7523999afc53..fbb4a6aa1583 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -508,23 +508,26 @@ static int __gfs2_readpage(void *file, struct page *page)
508static int gfs2_readpage(struct file *file, struct page *page) 508static int gfs2_readpage(struct file *file, struct page *page)
509{ 509{
510 struct gfs2_inode *ip = GFS2_I(page->mapping->host); 510 struct gfs2_inode *ip = GFS2_I(page->mapping->host);
511 struct gfs2_holder gh; 511 struct gfs2_holder *gh;
512 int error; 512 int error;
513 513
514 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); 514 gh = gfs2_glock_is_locked_by_me(ip->i_gl);
515 error = gfs2_glock_nq_atime(&gh); 515 if (!gh) {
516 if (unlikely(error)) { 516 gh = kmalloc(sizeof(struct gfs2_holder), GFP_NOFS);
517 if (!gh)
518 return -ENOBUFS;
519 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, gh);
517 unlock_page(page); 520 unlock_page(page);
518 goto out; 521 error = gfs2_glock_nq_atime(gh);
522 if (likely(error != 0))
523 goto out;
524 return AOP_TRUNCATED_PAGE;
519 } 525 }
520 error = __gfs2_readpage(file, page); 526 error = __gfs2_readpage(file, page);
521 gfs2_glock_dq(&gh); 527 gfs2_glock_dq(gh);
522out: 528out:
523 gfs2_holder_uninit(&gh); 529 gfs2_holder_uninit(gh);
524 if (error == GLR_TRYFAILED) { 530 kfree(gh);
525 yield();
526 return AOP_TRUNCATED_PAGE;
527 }
528 return error; 531 return error;
529} 532}
530 533
@@ -826,7 +829,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
826 unsigned int to = from + len; 829 unsigned int to = from + len;
827 int ret; 830 int ret;
828 831
829 BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == 0); 832 BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == NULL);
830 833
831 ret = gfs2_meta_inode_buffer(ip, &dibh); 834 ret = gfs2_meta_inode_buffer(ip, &dibh);
832 if (unlikely(ret)) { 835 if (unlikely(ret)) {