Commit 91cd0c2b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] jbd wakeup fix

Processes can sleep in do_get_write_access(), waiting for buffers to be
removed from the BJ_Shadow state.  We did this by doing a wake_up_buffer() in
the commit path and sleeping on the buffer in do_get_write_access().

With the filtered bit-level wakeup code this doesn't work properly any more -
the wake_up_buffer() accidentally wakes up tasks which are sleeping in
lock_buffer() as well.  Those tasks now implicitly assume that the buffer came
unlocked.  Net effect: Bogus I/O errors when reading journal blocks, because
the buffer isn't up to date yet.  Hence the recently spate of journal_bmap()
failure reports.

The patch creates a new jbd-private BH flag purely for this wakeup function.
So a wake_up_bit(..., BH_Unshadow) doesn't wake up someone who is waiting for
a wake_up_bit(BH_Lock).

JBD was the only user of wake_up_buffer(), so remove it altogether.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a8589849
......@@ -52,13 +52,6 @@ init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
bh->b_private = private;
}
void wake_up_buffer(struct buffer_head *bh)
{
smp_mb();
wake_up_bit(&bh->b_state, BH_Lock);
}
EXPORT_SYMBOL(wake_up_buffer);
static int sync_buffer(void *word)
{
struct block_device *bd;
......@@ -83,8 +76,8 @@ EXPORT_SYMBOL(__lock_buffer);
void fastcall unlock_buffer(struct buffer_head *bh)
{
clear_buffer_locked(bh);
smp_mb__after_clear_bit();
wake_up_buffer(bh);
smp_mb();
wake_up_bit(&bh->b_state, BH_Lock);
}
/*
......
......@@ -579,7 +579,7 @@ void journal_commit_transaction(journal_t *journal)
journal_file_buffer(jh, commit_transaction, BJ_Forget);
/* Wake up any transactions which were waiting for this
IO to complete */
wake_up_buffer(bh);
wake_up_bit(&bh->b_state, BH_Unshadow);
JBUFFER_TRACE(jh, "brelse shadowed buffer");
__brelse(bh);
}
......
......@@ -633,9 +633,10 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
* disk then we cannot do copy-out here. */
if (jh->b_jlist == BJ_Shadow) {
DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Lock);
wait_queue_head_t *wqh
= bit_waitqueue(&bh->b_state, BH_Lock);
DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Unshadow);
wait_queue_head_t *wqh;
wqh = bit_waitqueue(&bh->b_state, BH_Unshadow);
JBUFFER_TRACE(jh, "on shadow: sleep");
jbd_unlock_bh_state(bh);
......
......@@ -155,7 +155,6 @@ void invalidate_bdev(struct block_device *, int);
int sync_blockdev(struct block_device *bdev);
void __wait_on_buffer(struct buffer_head *);
wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
void wake_up_buffer(struct buffer_head *bh);
int fsync_bdev(struct block_device *);
struct super_block *freeze_bdev(struct block_device *);
void thaw_bdev(struct block_device *, struct super_block *);
......
......@@ -299,6 +299,7 @@ enum jbd_state_bits {
BH_JBDDirty, /* Is dirty but journaled */
BH_State, /* Pins most journal_head state */
BH_JournalHead, /* Pins bh->b_private and jh->b_bh */
BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */
};
BUFFER_FNS(JBD, jbd)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment