| From ba5d38dcdb2c6586f514be25ef7055e0aeba376f Mon Sep 17 00:00:00 2001 |
| From: Jan Kara <jack@suse.cz> |
| Date: Thu, 5 May 2011 13:59:35 +0200 |
| Subject: [PATCH] jbd: Fix forever sleeping process in do_get_write_access() |
| |
| commit 2842bb20eed2e25cde5114298edc62c8883a1d9a upstream. |
| |
| In do_get_write_access() we wait on BH_Unshadow bit for buffer to get |
| from shadow state. The waking code in journal_commit_transaction() has |
| a bug because it does not issue a memory barrier after the buffer is moved |
| from the shadow state and before wake_up_bit() is called. Thus a waitqueue |
| check can happen before the buffer is actually moved from the shadow state |
| and waiting process may never be woken. Fix the problem by issuing proper |
| barrier. |
| |
| Reported-by: Tao Ma <boyu.mt@taobao.com> |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| fs/jbd/commit.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c |
| index ecb44c9..1df9270 100644 |
| --- a/fs/jbd/commit.c |
| +++ b/fs/jbd/commit.c |
| @@ -745,8 +745,13 @@ wait_for_iobuf: |
| required. */ |
| JBUFFER_TRACE(jh, "file as BJ_Forget"); |
| journal_file_buffer(jh, commit_transaction, BJ_Forget); |
| - /* Wake up any transactions which were waiting for this |
| - IO to complete */ |
| + /* |
| + * Wake up any transactions which were waiting for this |
| + * IO to complete. The barrier must be here so that changes |
| + * by journal_file_buffer() take effect before wake_up_bit() |
| + * does the waitqueue check. |
| + */ |
| + smp_mb(); |
| wake_up_bit(&bh->b_state, BH_Unshadow); |
| JBUFFER_TRACE(jh, "brelse shadowed buffer"); |
| __brelse(bh); |
| -- |
| 1.7.9.3 |
| |