diff options
author | Jan Kara <jack@suse.cz> | 2011-06-23 22:51:47 +0200 |
---|---|---|
committer | Joel Becker <jlbec@evilplan.org> | 2011-07-28 02:07:19 -0700 |
commit | c7e25e6e0b0486492c5faaf6312b37413642c48e (patch) | |
tree | c097a213a8eb2ad336fb2ef8046d2e71f0fa1f4a /fs/ocfs2 | |
parent | a11f7e63c59810a81494d4c4b028af707d4c7ca4 (diff) | |
download | blackbird-op-linux-c7e25e6e0b0486492c5faaf6312b37413642c48e.tar.gz blackbird-op-linux-c7e25e6e0b0486492c5faaf6312b37413642c48e.zip |
ocfs2: Avoid livelock in ocfs2_readpage()
When someone writes to an inode, readers accessing the same inode via
ocfs2_readpage() just busyloop trying to get ip_alloc_sem because
do_generic_file_read() looks up the page again and retries ->readpage()
when previous attempt failed with AOP_TRUNCATED_PAGE. When there are enough
readers, they can occupy all CPUs and in non-preempt kernel the system is
deadlocked because writer holding ip_alloc_sem is never run to release the
semaphore. Fix the problem by making reader block on ip_alloc_sem to break
the busy loop.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Joel Becker <jlbec@evilplan.org>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/aops.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 4c1ec8f2d8c1..ba3ca1e63b51 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -290,7 +290,15 @@ static int ocfs2_readpage(struct file *file, struct page *page) } if (down_read_trylock(&oi->ip_alloc_sem) == 0) { + /* + * Unlock the page and cycle ip_alloc_sem so that we don't + * busyloop waiting for ip_alloc_sem to unlock + */ ret = AOP_TRUNCATED_PAGE; + unlock_page(page); + unlock = 0; + down_read(&oi->ip_alloc_sem); + up_read(&oi->ip_alloc_sem); goto out_inode_unlock; } |