mm/filemap: change filemap_read_page calling conventions

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.

Link: https://lkml.kernel.org/r/20210122160140.223228-10-willy@infradead.org
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Kent Overstreet <kent.overstreet@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Matthew Wilcox (Oracle) 2021-02-24 12:02:15 -08:00 committed by Linus Torvalds
parent 33a0f5c6b3
commit 68430303c8
1 changed files with 42 additions and 47 deletions

View File

@ -2199,56 +2199,38 @@ retry:
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 (page->mapping == NULL) {
/* page truncated */
error = AOP_TRUNCATED_PAGE;
} else {
shrink_readahead_size_eio(&file->f_ra);
error = -EIO;
}
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);
}
unlock_page(page);
}
return page;
unlock_page(page);
return error;
}
static struct page *filemap_update_page(struct kiocb *iocb, struct file *filp,
@ -2290,7 +2272,18 @@ uptodate:
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);
@ -2306,7 +2299,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);
@ -2315,12 +2308,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,