mm/filemap: add filemap_range_uptodate

Move the complicated condition and the calculations out of
filemap_update_page() into its own function.

[willy@infradead.org: unlock page before dropping its refcount]
  Link: https://lkml.kernel.org/r/20210201125229.GO308988@casper.infradead.org

Link: https://lkml.kernel.org/r/20210122160140.223228-14-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:28 -08:00 committed by Linus Torvalds
parent 87d1d7b688
commit fce70da3a8
1 changed files with 39 additions and 26 deletions

View File

@ -2233,11 +2233,36 @@ static int filemap_read_page(struct file *file, struct address_space *mapping,
return error; return error;
} }
static bool filemap_range_uptodate(struct address_space *mapping,
loff_t pos, struct iov_iter *iter, struct page *page)
{
int count;
if (PageUptodate(page))
return true;
/* pipes can't handle partially uptodate pages */
if (iov_iter_is_pipe(iter))
return false;
if (!mapping->a_ops->is_partially_uptodate)
return false;
if (mapping->host->i_blkbits >= (PAGE_SHIFT + thp_order(page)))
return false;
count = iter->count;
if (page_offset(page) > pos) {
count -= page_offset(page) - pos;
pos = 0;
} else {
pos -= page_offset(page);
}
return mapping->a_ops->is_partially_uptodate(page, pos, count);
}
static int filemap_update_page(struct kiocb *iocb, static int filemap_update_page(struct kiocb *iocb,
struct address_space *mapping, struct iov_iter *iter, struct address_space *mapping, struct iov_iter *iter,
struct page *page, loff_t pos, loff_t count) struct page *page)
{ {
struct inode *inode = mapping->host;
int error; int error;
if (!trylock_page(page)) { if (!trylock_page(page)) {
@ -2254,26 +2279,15 @@ static int filemap_update_page(struct kiocb *iocb,
if (!page->mapping) if (!page->mapping)
goto truncated; goto truncated;
if (PageUptodate(page))
goto uptodate;
if (inode->i_blkbits == PAGE_SHIFT ||
!mapping->a_ops->is_partially_uptodate)
goto readpage;
/* pipes can't handle partially uptodate pages */
if (unlikely(iov_iter_is_pipe(iter)))
goto readpage;
if (!mapping->a_ops->is_partially_uptodate(page,
pos & (thp_size(page) - 1), count))
goto readpage;
uptodate:
unlock_page(page);
return 0;
readpage: error = 0;
if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ)) { if (filemap_range_uptodate(mapping, iocb->ki_pos, iter, page))
unlock_page(page); goto unlock;
return -EAGAIN;
} error = -EAGAIN;
if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ))
goto unlock;
error = filemap_read_page(iocb->ki_filp, mapping, page); error = filemap_read_page(iocb->ki_filp, mapping, page);
if (error == AOP_TRUNCATED_PAGE) if (error == AOP_TRUNCATED_PAGE)
put_page(page); put_page(page);
@ -2282,6 +2296,9 @@ static int filemap_update_page(struct kiocb *iocb,
unlock_page(page); unlock_page(page);
put_page(page); put_page(page);
return AOP_TRUNCATED_PAGE; return AOP_TRUNCATED_PAGE;
unlock:
unlock_page(page);
return error;
} }
static int filemap_create_page(struct file *file, static int filemap_create_page(struct file *file,
@ -2351,9 +2368,6 @@ static int filemap_get_pages(struct kiocb *iocb, struct iov_iter *iter,
{ {
struct page *page = pvec->pages[pvec->nr - 1]; struct page *page = pvec->pages[pvec->nr - 1];
pgoff_t pg_index = page->index; pgoff_t pg_index = page->index;
loff_t pg_pos = max(iocb->ki_pos,
(loff_t) pg_index << PAGE_SHIFT);
loff_t pg_count = iocb->ki_pos + iter->count - pg_pos;
if (PageReadahead(page)) { if (PageReadahead(page)) {
if (iocb->ki_flags & IOCB_NOIO) { if (iocb->ki_flags & IOCB_NOIO) {
@ -2370,8 +2384,7 @@ static int filemap_get_pages(struct kiocb *iocb, struct iov_iter *iter,
if ((iocb->ki_flags & IOCB_WAITQ) && if ((iocb->ki_flags & IOCB_WAITQ) &&
pagevec_count(pvec) > 1) pagevec_count(pvec) > 1)
iocb->ki_flags |= IOCB_NOWAIT; iocb->ki_flags |= IOCB_NOWAIT;
err = filemap_update_page(iocb, mapping, iter, page, err = filemap_update_page(iocb, mapping, iter, page);
pg_pos, pg_count);
if (err) { if (err) {
if (err < 0) if (err < 0)
put_page(page); put_page(page);