diff options
author | Zach Brown <zach.brown@oracle.com> | 2006-12-10 02:21:01 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-10 09:57:21 -0800 |
commit | 20258b2b397031649e4a41922fe803d57017df84 (patch) | |
tree | 9c5fc96367b4938474cee2789d3c98c5e37586bf | |
parent | 0273201e693fd62381f6b1e85b15ffc117d8a46e (diff) |
[PATCH] dio: remove duplicate bio wait code
Now that we have a single refcount and waiting path we can reuse it in the
async 'should_wait' path. It continues to rely on the fragile link between
the conditional in dio_complete_aio() which decides to complete the AIO and
the conditional in direct_io_worker() which decides to wait and free.
By waiting before dropping the reference we stop dio_bio_end_aio() from
calling dio_complete_aio() which used to wake up the waiter after seeing the
reference count drop to 0. We hoist this wake up into dio_bio_end_aio() which
now notices when it's left a single remaining reference that is held by the
waiter.
Signed-off-by: Zach Brown <zach.brown@oracle.com>
Cc: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Suparna Bhattacharya <suparna@in.ibm.com>
Acked-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/direct-io.c | 41 |
1 files changed, 12 insertions, 29 deletions
diff --git a/fs/direct-io.c b/fs/direct-io.c index bc1cbf9149f..f11f05dc9e6 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -257,7 +257,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) */ static void dio_complete_aio(struct dio *dio) { - unsigned long flags; int ret; ret = dio_complete(dio, dio->iocb->ki_pos, 0); @@ -267,14 +266,6 @@ static void dio_complete_aio(struct dio *dio) ((dio->rw == READ) && dio->result)) { aio_complete(dio->iocb, ret, 0); kfree(dio); - } else { - /* - * Falling back to buffered - */ - spin_lock_irqsave(&dio->bio_lock, flags); - if (dio->waiter) - wake_up_process(dio->waiter); - spin_unlock_irqrestore(&dio->bio_lock, flags); } } @@ -285,6 +276,8 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio); static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) { struct dio *dio = bio->bi_private; + int waiter_holds_ref = 0; + int remaining; if (bio->bi_size) return 1; @@ -292,7 +285,12 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) /* cleanup the bio */ dio_bio_complete(dio, bio); - if (atomic_dec_and_test(&dio->refcount)) + waiter_holds_ref = !!dio->waiter; + remaining = atomic_sub_return(1, (&dio->refcount)); + if (remaining == 1 && waiter_holds_ref) + wake_up_process(dio->waiter); + + if (remaining == 0) dio_complete_aio(dio); return 0; @@ -1097,30 +1095,15 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, if (ret == 0) ret = dio->result; + if (should_wait) + dio_await_completion(dio); + /* this can free the dio */ if (atomic_dec_and_test(&dio->refcount)) dio_complete_aio(dio); - if (should_wait) { - unsigned long flags; - /* - * Wait for already issued I/O to drain out and - * release its references to user-space pages - * before returning to fallback on buffered I/O - */ - - spin_lock_irqsave(&dio->bio_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - while (atomic_read(&dio->refcount)) { - spin_unlock_irqrestore(&dio->bio_lock, flags); - io_schedule(); - spin_lock_irqsave(&dio->bio_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - } - spin_unlock_irqrestore(&dio->bio_lock, flags); - set_current_state(TASK_RUNNING); + if (should_wait) kfree(dio); - } } else { dio_await_completion(dio); |