diff -urNp 2.5.47/drivers/block/ll_rw_blk.c hangs-2.5/drivers/block/ll_rw_blk.c --- 2.5.47/drivers/block/ll_rw_blk.c Tue Nov 12 01:59:41 2002 +++ hangs-2.5/drivers/block/ll_rw_blk.c Tue Nov 12 02:37:42 2002 @@ -1281,12 +1281,13 @@ static struct request *get_request_wait( spin_lock_prefetch(q->queue_lock); - generic_unplug_device(q); do { prepare_to_wait_exclusive(&rl->wait, &wait, TASK_UNINTERRUPTIBLE); - if (!rl->count) + if (!rl->count){ + generic_unplug_device(q); io_schedule(); + } finish_wait(&rl->wait, &wait); spin_lock_irq(q->queue_lock); rq = get_request(q, rw); @@ -1487,8 +1488,11 @@ void __blk_put_request(request_queue_t * rl->count++; if (rl->count >= queue_congestion_off_threshold()) clear_queue_congested(q, rw); - if (rl->count >= batch_requests && waitqueue_active(&rl->wait)) - wake_up(&rl->wait); + if (rl->count >= batch_requests) { + smp_mb(); + if (waitqueue_active(&rl->wait)) + wake_up(&rl->wait); + } } } diff -urNp 2.5.47/fs/buffer.c hangs-2.5/fs/buffer.c --- 2.5.47/fs/buffer.c Tue Nov 12 01:59:42 2002 +++ hangs-2.5/fs/buffer.c Tue Nov 12 02:47:46 2002 @@ -135,9 +135,10 @@ void __wait_on_buffer(struct buffer_head get_bh(bh); do { prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - blk_run_queues(); - if (buffer_locked(bh)) + if (buffer_locked(bh)) { + blk_run_queues(); schedule(); + } } while (buffer_locked(bh)); put_bh(bh); finish_wait(wqh, &wait); @@ -1727,7 +1728,8 @@ done: if (uptodate) SetPageUptodate(page); end_page_writeback(page); - } + } else + wakeup_page_waiters(page); if (err == 0) return ret; return err; @@ -2011,6 +2013,7 @@ int block_read_full_page(struct page *pa else submit_bh(READ, bh); } + wakeup_page_waiters(page); return 0; } @@ -2315,6 +2318,8 @@ static int end_bio_bh_io_sync(struct bio int submit_bh(int rw, struct buffer_head * bh) { struct bio *bio; + int ret; + wait_queue_head_t *wqh = bh_waitq_head(bh); BUG_ON(!buffer_locked(bh)); BUG_ON(!buffer_mapped(bh)); @@ -2348,7 +2353,13 @@ int submit_bh(int rw, struct buffer_head bio->bi_end_io = end_bio_bh_io_sync; bio->bi_private = bh; - return submit_bio(rw, bio); + ret = submit_bio(rw, bio); + + smp_mb(); /* spin_unlock may have inclusive semantics */ + if (waitqueue_active(wqh)) + wake_up(wqh); + + return ret; } /** diff -urNp 2.5.47/fs/reiserfs/inode.c hangs-2.5/fs/reiserfs/inode.c --- 2.5.47/fs/reiserfs/inode.c Thu Oct 31 01:42:25 2002 +++ hangs-2.5/fs/reiserfs/inode.c Tue Nov 12 02:50:47 2002 @@ -1987,6 +1987,7 @@ static int reiserfs_write_full_page(stru */ if (nr) { submit_bh_for_writepage(arr, nr) ; + wakeup_page_waiters(page); } else { end_page_writeback(page) ; } diff -urNp 2.5.47/include/linux/pagemap.h hangs-2.5/include/linux/pagemap.h --- 2.5.47/include/linux/pagemap.h Tue Nov 12 01:59:43 2002 +++ hangs-2.5/include/linux/pagemap.h Tue Nov 12 02:45:27 2002 @@ -122,4 +122,7 @@ static inline void wait_on_page_writebac } extern void end_page_writeback(struct page *page); + +extern void wakeup_page_waiters(struct page * page); + #endif /* _LINUX_PAGEMAP_H */ diff -urNp 2.5.47/mm/filemap.c hangs-2.5/mm/filemap.c --- 2.5.47/mm/filemap.c Tue Nov 12 01:59:43 2002 +++ hangs-2.5/mm/filemap.c Tue Nov 12 02:44:59 2002 @@ -272,9 +272,10 @@ void wait_on_page_bit(struct page *page, do { prepare_to_wait(waitqueue, &wait, TASK_UNINTERRUPTIBLE); - sync_page(page); - if (test_bit(bit_nr, &page->flags)) + if (test_bit(bit_nr, &page->flags)) { + sync_page(page); io_schedule(); + } } while (test_bit(bit_nr, &page->flags)); finish_wait(waitqueue, &wait); } @@ -336,15 +337,30 @@ void __lock_page(struct page *page) while (TestSetPageLocked(page)) { prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - sync_page(page); - if (PageLocked(page)) + if (PageLocked(page)) { + sync_page(page); io_schedule(); + } } finish_wait(wqh, &wait); } EXPORT_SYMBOL(__lock_page); /* + * This must be called after every submit_bh with end_io + * callbacks that would result into the blkdev layer waking + * up the page after a queue unplug. + */ +void wakeup_page_waiters(struct page * page) +{ + wait_queue_head_t * wqh; + + wqh = page_waitqueue(page); + if (waitqueue_active(wqh)) + wake_up(wqh); +} + +/* * a rather lightweight function, finding and getting a reference to a * hashed page atomically. */ diff -urNp 2.5.47/mm/page_io.c hangs-2.5/mm/page_io.c --- 2.5.47/mm/page_io.c Thu Oct 31 01:41:56 2002 +++ hangs-2.5/mm/page_io.c Tue Nov 12 02:50:12 2002 @@ -104,6 +104,7 @@ int swap_writepage(struct page *page) SetPageWriteback(page); unlock_page(page); submit_bio(WRITE, bio); + wakeup_page_waiters(page); out: return ret; } @@ -121,6 +122,7 @@ int swap_readpage(struct file *file, str } inc_page_state(pswpin); submit_bio(READ, bio); + wakeup_page_waiters(page); out: return ret; } --- hangs-2.5/kernel/ksyms.c.~1~ Tue Nov 12 01:59:43 2002 +++ hangs-2.5/kernel/ksyms.c Tue Nov 12 04:36:37 2002 @@ -336,6 +336,7 @@ EXPORT_SYMBOL(filemap_fdatawrite); EXPORT_SYMBOL(filemap_fdatawait); EXPORT_SYMBOL(lock_page); EXPORT_SYMBOL(unlock_page); +EXPORT_SYMBOL(wakeup_page_waiters); /* device registration */ EXPORT_SYMBOL(register_chrdev);