Commit fce70da3 authored by Matthew Wilcox (Oracle)'s avatar Matthew Wilcox (Oracle) Committed by Linus Torvalds
Browse files

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: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 87d1d7b6
Loading
Loading
Loading
Loading
+39 −26
Original line number Diff line number Diff line
@@ -2233,11 +2233,36 @@ static int filemap_read_page(struct file *file, struct address_space *mapping,
	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,
		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;

	if (!trylock_page(page)) {
@@ -2254,26 +2279,15 @@ static int filemap_update_page(struct kiocb *iocb,

	if (!page->mapping)
		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:
	if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ)) {
		unlock_page(page);
		return -EAGAIN;
	}
	error = 0;
	if (filemap_range_uptodate(mapping, iocb->ki_pos, iter, page))
		goto unlock;

	error = -EAGAIN;
	if (iocb->ki_flags & (IOCB_NOIO | IOCB_NOWAIT | IOCB_WAITQ))
		goto unlock;

	error = filemap_read_page(iocb->ki_filp, mapping, page);
	if (error == AOP_TRUNCATED_PAGE)
		put_page(page);
@@ -2282,6 +2296,9 @@ static int filemap_update_page(struct kiocb *iocb,
	unlock_page(page);
	put_page(page);
	return AOP_TRUNCATED_PAGE;
unlock:
	unlock_page(page);
	return error;
}

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];
		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 (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) &&
			    pagevec_count(pvec) > 1)
				iocb->ki_flags |= IOCB_NOWAIT;
			err = filemap_update_page(iocb, mapping, iter, page,
					pg_pos, pg_count);
			err = filemap_update_page(iocb, mapping, iter, page);
			if (err) {
				if (err < 0)
					put_page(page);