[PATCH v5 09/18] mm/filemap: Change filemap_read_page calling conventions

From: Matthew Wilcox (Oracle)
Date: Fri Jan 22 2021 - 12:31:43 EST


Make this function more generic by passing the file instead of the iocb.
Check in the callers whether we should call readpage or not. Also make
it return an errno / 0 / AOP_TRUNCATED_PAGE, and make calling put_page()
the caller's responsibility.

Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
Reviewed-by: Kent Overstreet <kent.overstreet@xxxxxxxxx>
Reviewed-by: Christoph Hellwig <hch@xxxxxx>
---
mm/filemap.c | 89 +++++++++++++++++++++++++---------------------------
1 file changed, 42 insertions(+), 47 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index ee1255a88106f..ceb2931f5725f 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2212,56 +2212,38 @@ static void filemap_get_read_batch(struct address_space *mapping,
rcu_read_unlock();
}

-static struct page *filemap_read_page(struct kiocb *iocb, struct file *filp,
- struct address_space *mapping, struct page *page)
+static int filemap_read_page(struct file *file, struct address_space *mapping,
+ struct page *page)
{
- struct file_ra_state *ra = &filp->f_ra;
int error;

- if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ)) {
- unlock_page(page);
- put_page(page);
- return ERR_PTR(-EAGAIN);
- }
-
/*
- * A previous I/O error may have been due to temporary
- * failures, eg. multipath errors.
- * PG_error will be set again if readpage fails.
+ * A previous I/O error may have been due to temporary failures,
+ * eg. multipath errors. PG_error will be set again if readpage
+ * fails.
*/
ClearPageError(page);
/* Start the actual read. The read will unlock the page. */
- error = mapping->a_ops->readpage(filp, page);
-
- if (unlikely(error)) {
- put_page(page);
- return error != AOP_TRUNCATED_PAGE ? ERR_PTR(error) : NULL;
- }
+ error = mapping->a_ops->readpage(file, page);
+ if (error)
+ return error;
+ if (PageUptodate(page))
+ return 0;

+ error = lock_page_killable(page);
+ if (error)
+ return error;
if (!PageUptodate(page)) {
- error = lock_page_killable(page);
- if (unlikely(error)) {
- put_page(page);
- return ERR_PTR(error);
- }
- if (!PageUptodate(page)) {
- if (page->mapping == NULL) {
- /*
- * invalidate_mapping_pages got it
- */
- unlock_page(page);
- put_page(page);
- return NULL;
- }
- unlock_page(page);
- shrink_readahead_size_eio(ra);
- put_page(page);
- return ERR_PTR(-EIO);
+ if (page->mapping == NULL) {
+ /* page truncated */
+ error = AOP_TRUNCATED_PAGE;
+ } else {
+ shrink_readahead_size_eio(&file->f_ra);
+ error = -EIO;
}
- unlock_page(page);
}
-
- return page;
+ unlock_page(page);
+ return error;
}

static struct page *filemap_update_page(struct kiocb *iocb, struct file *filp,
@@ -2303,7 +2285,18 @@ static struct page *filemap_update_page(struct kiocb *iocb, struct file *filp,
return page;

readpage:
- return filemap_read_page(iocb, filp, mapping, page);
+ if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ)) {
+ unlock_page(page);
+ put_page(page);
+ return ERR_PTR(-EAGAIN);
+ }
+ error = filemap_read_page(iocb->ki_filp, mapping, page);
+ if (!error)
+ return page;
+ put_page(page);
+ if (error == AOP_TRUNCATED_PAGE)
+ return NULL;
+ return ERR_PTR(error);
truncated:
unlock_page(page);
put_page(page);
@@ -2319,7 +2312,7 @@ static struct page *filemap_create_page(struct kiocb *iocb,
struct page *page;
int error;

- if (iocb->ki_flags & IOCB_NOIO)
+ if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ))
return ERR_PTR(-EAGAIN);

page = page_cache_alloc(mapping);
@@ -2328,12 +2321,14 @@ static struct page *filemap_create_page(struct kiocb *iocb,

error = add_to_page_cache_lru(page, mapping, index,
mapping_gfp_constraint(mapping, GFP_KERNEL));
- if (error) {
- put_page(page);
- return error != -EEXIST ? ERR_PTR(error) : NULL;
- }
-
- return filemap_read_page(iocb, filp, mapping, page);
+ if (!error)
+ error = filemap_read_page(iocb->ki_filp, mapping, page);
+ if (!error)
+ return page;
+ put_page(page);
+ if (error == -EEXIST || error == AOP_TRUNCATED_PAGE)
+ return NULL;
+ return ERR_PTR(error);
}

static int filemap_get_pages(struct kiocb *iocb, struct iov_iter *iter,
--
2.29.2