Commit ba512c1b authored by Dave Wysochanski's avatar Dave Wysochanski Committed by Trond Myklebust
Browse files

NFS: Fix fscache read from NFS after cache error

Earlier commits refactored some NFS read code and removed
nfs_readpage_async(), but neglected to properly fixup
nfs_readpage_from_fscache_complete().  The code path is
only hit when something unusual occurs with the cachefiles
backing filesystem, such as an IO error or while a cookie
is being invalidated.

Mark page with PG_checked if fscache IO completes in error,
unlock the page, and let the VM decide to re-issue based on
PG_uptodate.  When the VM reissues the readpage, PG_checked
allows us to skip over fscache and read from the server.

Link: https://marc.info/?l=linux-nfs&m=162498209518739


Fixes: 1e83b173 ("NFS: Add nfs_pageio_complete_read() and remove nfs_readpage_async()")
Signed-off-by: default avatarDave Wysochanski <dwysocha@redhat.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent e0340f16
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -385,13 +385,16 @@ static void nfs_readpage_from_fscache_complete(struct page *page,
		 "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
		 page, context, error);

	/* if the read completes with an error, we just unlock the page and let
	 * the VM reissue the readpage */
	if (!error) {
	/*
	 * If the read completes with an error, mark the page with PG_checked,
	 * unlock the page, and let the VM reissue the readpage.
	 */
	if (!error)
		SetPageUptodate(page);
	else
		SetPageChecked(page);
	unlock_page(page);
}
}

/*
 * Retrieve a page from fscache
@@ -405,6 +408,11 @@ int __nfs_readpage_from_fscache(struct nfs_open_context *ctx,
		 "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n",
		 nfs_i_fscache(inode), page, page->index, page->flags, inode);

	if (PageChecked(page)) {
		ClearPageChecked(page);
		return 1;
	}

	ret = fscache_read_or_alloc_page(nfs_i_fscache(inode),
					 page,
					 nfs_readpage_from_fscache_complete,
+3 −2
Original line number Diff line number Diff line
@@ -362,13 +362,13 @@ int nfs_readpage(struct file *file, struct page *page)
	} else
		desc.ctx = get_nfs_open_context(nfs_file_open_context(file));

	xchg(&desc.ctx->error, 0);
	if (!IS_SYNC(inode)) {
		ret = nfs_readpage_from_fscache(desc.ctx, inode, page);
		if (ret == 0)
			goto out;
			goto out_wait;
	}

	xchg(&desc.ctx->error, 0);
	nfs_pageio_init_read(&desc.pgio, inode, false,
			     &nfs_async_read_completion_ops);

@@ -378,6 +378,7 @@ int nfs_readpage(struct file *file, struct page *page)

	nfs_pageio_complete_read(&desc.pgio);
	ret = desc.pgio.pg_error < 0 ? desc.pgio.pg_error : 0;
out_wait:
	if (!ret) {
		ret = wait_on_page_locked_killable(page);
		if (!PageUptodate(page) && !ret)