Async buffer wait fs/buffer.c | 33 ++++++++++++++++++++++++++++----- include/linux/buffer_head.h | 17 +++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff -puN fs/buffer.c~aio-04-buffer_wq fs/buffer.c --- 25/fs/buffer.c~aio-04-buffer_wq 2003-08-02 12:47:39.000000000 -0700 +++ 25-akpm/fs/buffer.c 2003-08-02 12:47:39.000000000 -0700 @@ -116,27 +116,50 @@ void unlock_buffer(struct buffer_head *b } /* - * Block until a buffer comes unlocked. This doesn't stop it + * Wait until a buffer comes unlocked. This doesn't stop it * from becoming locked again - you have to lock it yourself * if you want to preserve its state. + * If the wait queue parameter specifies an async i/o callback, + * then instead of blocking, we just queue up the callback + * on the wait queue for async notification when the buffer gets + * unlocked. + * A NULL wait queue parameter defaults to synchronous behaviour */ -void __wait_on_buffer(struct buffer_head * bh) +int __wait_on_buffer_wq(struct buffer_head * bh, wait_queue_t *wait) { wait_queue_head_t *wqh = bh_waitq_head(bh); - DEFINE_WAIT(wait); + DEFINE_WAIT(local_wait); + + if (!wait) + wait = &local_wait; if (atomic_read(&bh->b_count) == 0 && (!bh->b_page || !PageLocked(bh->b_page))) buffer_error(); do { - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE); if (buffer_locked(bh)) { blk_run_queues(); + if (!is_sync_wait(wait)) { + /* + * if we've queued an async wait queue + * callback do not block; just tell the + * caller to return and retry later when + * the callback is notified + */ + return -EIOCBRETRY; + } io_schedule(); } } while (buffer_locked(bh)); - finish_wait(wqh, &wait); + finish_wait(wqh, wait); + return 0; +} + +void __wait_on_buffer(struct buffer_head * bh) +{ + __wait_on_buffer_wq(bh, NULL); } static void diff -puN include/linux/buffer_head.h~aio-04-buffer_wq include/linux/buffer_head.h --- 25/include/linux/buffer_head.h~aio-04-buffer_wq 2003-08-02 12:47:39.000000000 -0700 +++ 25-akpm/include/linux/buffer_head.h 2003-08-02 12:47:39.000000000 -0700 @@ -162,6 +162,7 @@ void mark_buffer_async_write(struct buff void invalidate_bdev(struct block_device *, int); int sync_blockdev(struct block_device *bdev); void __wait_on_buffer(struct buffer_head *); +int __wait_on_buffer_wq(struct buffer_head *, wait_queue_t *wait); 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 *); @@ -283,10 +284,26 @@ static inline void wait_on_buffer(struct __wait_on_buffer(bh); } +static inline int wait_on_buffer_wq(struct buffer_head *bh, wait_queue_t *wait) +{ + if (buffer_locked(bh)) + return __wait_on_buffer_wq(bh, wait); + + return 0; +} + static inline void lock_buffer(struct buffer_head *bh) { while (test_set_buffer_locked(bh)) __wait_on_buffer(bh); } +static inline int lock_buffer_wq(struct buffer_head *bh, wait_queue_t *wait) +{ + if (test_set_buffer_locked(bh)) + return __wait_on_buffer_wq(bh, wait); + + return 0; +} + #endif /* _LINUX_BUFFER_HEAD_H */ _