Commit 1a0a7853 authored by Jens Axboe's avatar Jens Axboe

mm: support async buffered reads in generic_file_buffered_read()

Use the async page locking infrastructure, if IOCB_WAITQ is set in the
passed in iocb. The caller must expect an -EIOCBQUEUED return value,
which means that IO is started but not done yet. This is similar to how
O_DIRECT signals the same operation. Once the callback is received by
the caller for IO completion, the caller must retry the operation.
Acked-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent dd3e6d50
...@@ -1210,6 +1210,14 @@ static int __wait_on_page_locked_async(struct page *page, ...@@ -1210,6 +1210,14 @@ static int __wait_on_page_locked_async(struct page *page,
return ret; return ret;
} }
static int wait_on_page_locked_async(struct page *page,
struct wait_page_queue *wait)
{
if (!PageLocked(page))
return 0;
return __wait_on_page_locked_async(compound_head(page), wait, false);
}
/** /**
* put_and_wait_on_page_locked - Drop a reference and wait for it to be unlocked * put_and_wait_on_page_locked - Drop a reference and wait for it to be unlocked
* @page: The page to wait for. * @page: The page to wait for.
...@@ -2049,17 +2057,25 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb, ...@@ -2049,17 +2057,25 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
index, last_index - index); index, last_index - index);
} }
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
if (iocb->ki_flags & IOCB_NOWAIT) {
put_page(page);
goto would_block;
}
/* /*
* See comment in do_read_cache_page on why * See comment in do_read_cache_page on why
* wait_on_page_locked is used to avoid unnecessarily * wait_on_page_locked is used to avoid unnecessarily
* serialisations and why it's safe. * serialisations and why it's safe.
*/ */
error = wait_on_page_locked_killable(page); if (iocb->ki_flags & IOCB_WAITQ) {
if (written) {
put_page(page);
goto out;
}
error = wait_on_page_locked_async(page,
iocb->ki_waitq);
} else {
if (iocb->ki_flags & IOCB_NOWAIT) {
put_page(page);
goto would_block;
}
error = wait_on_page_locked_killable(page);
}
if (unlikely(error)) if (unlikely(error))
goto readpage_error; goto readpage_error;
if (PageUptodate(page)) if (PageUptodate(page))
...@@ -2147,7 +2163,10 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb, ...@@ -2147,7 +2163,10 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
page_not_up_to_date: page_not_up_to_date:
/* Get exclusive access to the page ... */ /* Get exclusive access to the page ... */
error = lock_page_killable(page); if (iocb->ki_flags & IOCB_WAITQ)
error = lock_page_async(page, iocb->ki_waitq);
else
error = lock_page_killable(page);
if (unlikely(error)) if (unlikely(error))
goto readpage_error; goto readpage_error;
...@@ -2190,10 +2209,7 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb, ...@@ -2190,10 +2209,7 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
} }
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
if (iocb->ki_flags & IOCB_WAITQ) error = lock_page_killable(page);
error = lock_page_async(page, iocb->ki_waitq);
else
error = lock_page_killable(page);
if (unlikely(error)) if (unlikely(error))
goto readpage_error; goto readpage_error;
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
......
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