summaryrefslogtreecommitdiff
path: root/include/linux/buffer_head.h
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-02-02 06:07:22 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2003-02-02 06:07:22 -0800
commitcd9ab8c2b002ecb84a868ba7d36eccd346952cbc (patch)
tree8bc232fcac96ce8063fbb6e400c47009c2c637ee /include/linux/buffer_head.h
parent2ef0192ceb2f9e5e28225b92886ee71676988d28 (diff)
[PATCH] ext3: fix scheduling storm and lockups
There have been sporadic sightings of ext3 causing little blips of 100,000 context switches per second when under load. At the start of do_get_write_access() we have this logic: repeat: lock_buffer(jh->bh); ... unlock_buffer(jh->bh); ... if (jh->j_list == BJ_Shadow) { sleep_on_buffer(jh->bh); goto repeat; } The problem is that the unlock_buffer() will wake up anyone who is sleeping in the sleep_on_buffer(). So if task A is asleep in sleep_on_buffer() and task B now runs do_get_write_access(), task B will wake task A by accident. Task B will then sleep on the buffer and task A will loop, will run unlock_buffer() and then wake task B. This state will continue until I/O completes against the buffer and kjournal changes jh->j_list. Unless task A and task B happen to both have realtime scheduling policy - if they do then kjournald will never run. The state is never cleared and your box locks up. The fix is to not do the `goto repeat;' until the buffer has been taken of the shadow list. So we don't go and wake up the other waiter(s) until they can actually proceed to use the buffer. The patch removes the exported sleep_on_buffer() function and simply exports an existing function which provides access to a buffer_head's waitqueue pointer. Which is a better interface anyway, because it permits the use of wait_event(). This bug was introduced introduced into 2.4.20-pre5 and was faithfully ported up.
Diffstat (limited to 'include/linux/buffer_head.h')
-rw-r--r--include/linux/buffer_head.h3
1 files changed, 2 insertions, 1 deletions
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 7fc917c13f32..aaefe4e964b7 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/linkage.h>
+#include <linux/wait.h>
#include <asm/atomic.h>
enum bh_state_bits {
@@ -154,7 +155,7 @@ void invalidate_bdev(struct block_device *, int);
void __invalidate_buffers(kdev_t dev, int);
int sync_blockdev(struct block_device *bdev);
void __wait_on_buffer(struct buffer_head *);
-void sleep_on_buffer(struct buffer_head *bh);
+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 *);
int fsync_super(struct super_block *);