162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/fs/nfs/read.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Block I/O for NFS
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Partial copy of Linus' read cache modifications to fs/nfs/file.c
862306a36Sopenharmony_ci * modified for async RPC by okir@monad.swb.de
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/time.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/fcntl.h>
1562306a36Sopenharmony_ci#include <linux/stat.h>
1662306a36Sopenharmony_ci#include <linux/mm.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/task_io_accounting_ops.h>
1962306a36Sopenharmony_ci#include <linux/pagemap.h>
2062306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
2162306a36Sopenharmony_ci#include <linux/nfs_fs.h>
2262306a36Sopenharmony_ci#include <linux/nfs_page.h>
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "nfs4_fs.h"
2662306a36Sopenharmony_ci#include "internal.h"
2762306a36Sopenharmony_ci#include "iostat.h"
2862306a36Sopenharmony_ci#include "fscache.h"
2962306a36Sopenharmony_ci#include "pnfs.h"
3062306a36Sopenharmony_ci#include "nfstrace.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define NFSDBG_FACILITY		NFSDBG_PAGECACHE
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciconst struct nfs_pgio_completion_ops nfs_async_read_completion_ops;
3562306a36Sopenharmony_cistatic const struct nfs_rw_ops nfs_rw_read_ops;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct kmem_cache *nfs_rdata_cachep;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct nfs_pgio_header *nfs_readhdr_alloc(void)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	struct nfs_pgio_header *p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (p)
4462306a36Sopenharmony_ci		p->rw_mode = FMODE_READ;
4562306a36Sopenharmony_ci	return p;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic void nfs_readhdr_free(struct nfs_pgio_header *rhdr)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	if (rhdr->res.scratch != NULL)
5162306a36Sopenharmony_ci		kfree(rhdr->res.scratch);
5262306a36Sopenharmony_ci	kmem_cache_free(nfs_rdata_cachep, rhdr);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int nfs_return_empty_folio(struct folio *folio)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	folio_zero_segment(folio, 0, folio_size(folio));
5862306a36Sopenharmony_ci	folio_mark_uptodate(folio);
5962306a36Sopenharmony_ci	folio_unlock(folio);
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
6462306a36Sopenharmony_ci			      struct inode *inode, bool force_mds,
6562306a36Sopenharmony_ci			      const struct nfs_pgio_completion_ops *compl_ops)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct nfs_server *server = NFS_SERVER(inode);
6862306a36Sopenharmony_ci	const struct nfs_pageio_ops *pg_ops = &nfs_pgio_rw_ops;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_1
7162306a36Sopenharmony_ci	if (server->pnfs_curr_ld && !force_mds)
7262306a36Sopenharmony_ci		pg_ops = server->pnfs_curr_ld->pg_read_ops;
7362306a36Sopenharmony_ci#endif
7462306a36Sopenharmony_ci	nfs_pageio_init(pgio, inode, pg_ops, compl_ops, &nfs_rw_read_ops,
7562306a36Sopenharmony_ci			server->rsize, 0);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_pageio_init_read);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_civoid nfs_pageio_complete_read(struct nfs_pageio_descriptor *pgio)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct nfs_pgio_mirror *pgm;
8262306a36Sopenharmony_ci	unsigned long npages;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	nfs_pageio_complete(pgio);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* It doesn't make sense to do mirrored reads! */
8762306a36Sopenharmony_ci	WARN_ON_ONCE(pgio->pg_mirror_count != 1);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	pgm = &pgio->pg_mirrors[0];
9062306a36Sopenharmony_ci	NFS_I(pgio->pg_inode)->read_io += pgm->pg_bytes_written;
9162306a36Sopenharmony_ci	npages = (pgm->pg_bytes_written + PAGE_SIZE - 1) >> PAGE_SHIFT;
9262306a36Sopenharmony_ci	nfs_add_stats(pgio->pg_inode, NFSIOS_READPAGES, npages);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_civoid nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct nfs_pgio_mirror *mirror;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (pgio->pg_ops && pgio->pg_ops->pg_cleanup)
10162306a36Sopenharmony_ci		pgio->pg_ops->pg_cleanup(pgio);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	pgio->pg_ops = &nfs_pgio_rw_ops;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* read path should never have more than one mirror */
10662306a36Sopenharmony_ci	WARN_ON_ONCE(pgio->pg_mirror_count != 1);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	mirror = &pgio->pg_mirrors[0];
10962306a36Sopenharmony_ci	mirror->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cibool nfs_read_alloc_scratch(struct nfs_pgio_header *hdr, size_t size)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	WARN_ON(hdr->res.scratch != NULL);
11662306a36Sopenharmony_ci	hdr->res.scratch = kmalloc(size, GFP_KERNEL);
11762306a36Sopenharmony_ci	return hdr->res.scratch != NULL;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_read_alloc_scratch);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void nfs_readpage_release(struct nfs_page *req, int error)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct folio *folio = nfs_page_to_folio(req);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (nfs_error_is_fatal_on_server(error) && error != -ETIMEDOUT)
12662306a36Sopenharmony_ci		folio_set_error(folio);
12762306a36Sopenharmony_ci	if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE))
12862306a36Sopenharmony_ci		if (nfs_netfs_folio_unlock(folio))
12962306a36Sopenharmony_ci			folio_unlock(folio);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	nfs_release_request(req);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void nfs_page_group_set_uptodate(struct nfs_page *req)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	if (nfs_page_group_sync_on_bit(req, PG_UPTODATE))
13762306a36Sopenharmony_ci		folio_mark_uptodate(nfs_page_to_folio(req));
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic void nfs_read_completion(struct nfs_pgio_header *hdr)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	unsigned long bytes = 0;
14362306a36Sopenharmony_ci	int error;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
14662306a36Sopenharmony_ci		goto out;
14762306a36Sopenharmony_ci	while (!list_empty(&hdr->pages)) {
14862306a36Sopenharmony_ci		struct nfs_page *req = nfs_list_entry(hdr->pages.next);
14962306a36Sopenharmony_ci		struct folio *folio = nfs_page_to_folio(req);
15062306a36Sopenharmony_ci		unsigned long start = req->wb_pgbase;
15162306a36Sopenharmony_ci		unsigned long end = req->wb_pgbase + req->wb_bytes;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) {
15462306a36Sopenharmony_ci			/* note: regions of the page not covered by a
15562306a36Sopenharmony_ci			 * request are zeroed in nfs_read_add_folio
15662306a36Sopenharmony_ci			 */
15762306a36Sopenharmony_ci			if (bytes > hdr->good_bytes) {
15862306a36Sopenharmony_ci				/* nothing in this request was good, so zero
15962306a36Sopenharmony_ci				 * the full extent of the request */
16062306a36Sopenharmony_ci				folio_zero_segment(folio, start, end);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci			} else if (hdr->good_bytes - bytes < req->wb_bytes) {
16362306a36Sopenharmony_ci				/* part of this request has good bytes, but
16462306a36Sopenharmony_ci				 * not all. zero the bad bytes */
16562306a36Sopenharmony_ci				start += hdr->good_bytes - bytes;
16662306a36Sopenharmony_ci				WARN_ON(start < req->wb_pgbase);
16762306a36Sopenharmony_ci				folio_zero_segment(folio, start, end);
16862306a36Sopenharmony_ci			}
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci		error = 0;
17162306a36Sopenharmony_ci		bytes += req->wb_bytes;
17262306a36Sopenharmony_ci		if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
17362306a36Sopenharmony_ci			if (bytes <= hdr->good_bytes)
17462306a36Sopenharmony_ci				nfs_page_group_set_uptodate(req);
17562306a36Sopenharmony_ci			else {
17662306a36Sopenharmony_ci				error = hdr->error;
17762306a36Sopenharmony_ci				xchg(&nfs_req_openctx(req)->error, error);
17862306a36Sopenharmony_ci			}
17962306a36Sopenharmony_ci		} else
18062306a36Sopenharmony_ci			nfs_page_group_set_uptodate(req);
18162306a36Sopenharmony_ci		nfs_list_remove_request(req);
18262306a36Sopenharmony_ci		nfs_readpage_release(req, error);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	nfs_netfs_read_completion(hdr);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ciout:
18762306a36Sopenharmony_ci	hdr->release(hdr);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic void nfs_initiate_read(struct nfs_pgio_header *hdr,
19162306a36Sopenharmony_ci			      struct rpc_message *msg,
19262306a36Sopenharmony_ci			      const struct nfs_rpc_ops *rpc_ops,
19362306a36Sopenharmony_ci			      struct rpc_task_setup *task_setup_data, int how)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	rpc_ops->read_setup(hdr, msg);
19662306a36Sopenharmony_ci	nfs_netfs_initiate_read(hdr);
19762306a36Sopenharmony_ci	trace_nfs_initiate_read(hdr);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void
20162306a36Sopenharmony_cinfs_async_read_error(struct list_head *head, int error)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct nfs_page	*req;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	while (!list_empty(head)) {
20662306a36Sopenharmony_ci		req = nfs_list_entry(head->next);
20762306a36Sopenharmony_ci		nfs_list_remove_request(req);
20862306a36Sopenharmony_ci		nfs_readpage_release(req, error);
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciconst struct nfs_pgio_completion_ops nfs_async_read_completion_ops = {
21362306a36Sopenharmony_ci	.error_cleanup = nfs_async_read_error,
21462306a36Sopenharmony_ci	.completion = nfs_read_completion,
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci * This is the callback from RPC telling us whether a reply was
21962306a36Sopenharmony_ci * received or some error occurred (timeout or socket shutdown).
22062306a36Sopenharmony_ci */
22162306a36Sopenharmony_cistatic int nfs_readpage_done(struct rpc_task *task,
22262306a36Sopenharmony_ci			     struct nfs_pgio_header *hdr,
22362306a36Sopenharmony_ci			     struct inode *inode)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	int status = NFS_PROTO(inode)->read_done(task, hdr);
22662306a36Sopenharmony_ci	if (status != 0)
22762306a36Sopenharmony_ci		return status;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, hdr->res.count);
23062306a36Sopenharmony_ci	trace_nfs_readpage_done(task, hdr);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (task->tk_status == -ESTALE) {
23362306a36Sopenharmony_ci		nfs_set_inode_stale(inode);
23462306a36Sopenharmony_ci		nfs_mark_for_revalidate(inode);
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void nfs_readpage_retry(struct rpc_task *task,
24062306a36Sopenharmony_ci			       struct nfs_pgio_header *hdr)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct nfs_pgio_args *argp = &hdr->args;
24362306a36Sopenharmony_ci	struct nfs_pgio_res  *resp = &hdr->res;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* This is a short read! */
24662306a36Sopenharmony_ci	nfs_inc_stats(hdr->inode, NFSIOS_SHORTREAD);
24762306a36Sopenharmony_ci	trace_nfs_readpage_short(task, hdr);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Has the server at least made some progress? */
25062306a36Sopenharmony_ci	if (resp->count == 0) {
25162306a36Sopenharmony_ci		nfs_set_pgio_error(hdr, -EIO, argp->offset);
25262306a36Sopenharmony_ci		return;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* For non rpc-based layout drivers, retry-through-MDS */
25662306a36Sopenharmony_ci	if (!task->tk_ops) {
25762306a36Sopenharmony_ci		hdr->pnfs_error = -EAGAIN;
25862306a36Sopenharmony_ci		return;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* Yes, so retry the read at the end of the hdr */
26262306a36Sopenharmony_ci	hdr->mds_offset += resp->count;
26362306a36Sopenharmony_ci	argp->offset += resp->count;
26462306a36Sopenharmony_ci	argp->pgbase += resp->count;
26562306a36Sopenharmony_ci	argp->count -= resp->count;
26662306a36Sopenharmony_ci	resp->count = 0;
26762306a36Sopenharmony_ci	resp->eof = 0;
26862306a36Sopenharmony_ci	rpc_restart_call_prepare(task);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void nfs_readpage_result(struct rpc_task *task,
27262306a36Sopenharmony_ci				struct nfs_pgio_header *hdr)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	if (hdr->res.eof) {
27562306a36Sopenharmony_ci		loff_t pos = hdr->args.offset + hdr->res.count;
27662306a36Sopenharmony_ci		unsigned int new = pos - hdr->io_start;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		if (hdr->good_bytes > new) {
27962306a36Sopenharmony_ci			hdr->good_bytes = new;
28062306a36Sopenharmony_ci			set_bit(NFS_IOHDR_EOF, &hdr->flags);
28162306a36Sopenharmony_ci			clear_bit(NFS_IOHDR_ERROR, &hdr->flags);
28262306a36Sopenharmony_ci		}
28362306a36Sopenharmony_ci	} else if (hdr->res.count < hdr->args.count)
28462306a36Sopenharmony_ci		nfs_readpage_retry(task, hdr);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciint nfs_read_add_folio(struct nfs_pageio_descriptor *pgio,
28862306a36Sopenharmony_ci		       struct nfs_open_context *ctx,
28962306a36Sopenharmony_ci		       struct folio *folio)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct inode *inode = folio_file_mapping(folio)->host;
29262306a36Sopenharmony_ci	struct nfs_server *server = NFS_SERVER(inode);
29362306a36Sopenharmony_ci	size_t fsize = folio_size(folio);
29462306a36Sopenharmony_ci	unsigned int rsize = server->rsize;
29562306a36Sopenharmony_ci	struct nfs_page *new;
29662306a36Sopenharmony_ci	unsigned int len, aligned_len;
29762306a36Sopenharmony_ci	int error;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	len = nfs_folio_length(folio);
30062306a36Sopenharmony_ci	if (len == 0)
30162306a36Sopenharmony_ci		return nfs_return_empty_folio(folio);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	aligned_len = min_t(unsigned int, ALIGN(len, rsize), fsize);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	new = nfs_page_create_from_folio(ctx, folio, 0, aligned_len);
30662306a36Sopenharmony_ci	if (IS_ERR(new)) {
30762306a36Sopenharmony_ci		error = PTR_ERR(new);
30862306a36Sopenharmony_ci		if (nfs_netfs_folio_unlock(folio))
30962306a36Sopenharmony_ci			folio_unlock(folio);
31062306a36Sopenharmony_ci		goto out;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (len < fsize)
31462306a36Sopenharmony_ci		folio_zero_segment(folio, len, fsize);
31562306a36Sopenharmony_ci	if (!nfs_pageio_add_request(pgio, new)) {
31662306a36Sopenharmony_ci		nfs_list_remove_request(new);
31762306a36Sopenharmony_ci		error = pgio->pg_error;
31862306a36Sopenharmony_ci		nfs_readpage_release(new, error);
31962306a36Sopenharmony_ci		goto out;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci	return 0;
32262306a36Sopenharmony_ciout:
32362306a36Sopenharmony_ci	return error;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/*
32762306a36Sopenharmony_ci * Read a page over NFS.
32862306a36Sopenharmony_ci * We read the page synchronously in the following case:
32962306a36Sopenharmony_ci *  -	The error flag is set for this page. This happens only when a
33062306a36Sopenharmony_ci *	previous async read operation failed.
33162306a36Sopenharmony_ci */
33262306a36Sopenharmony_ciint nfs_read_folio(struct file *file, struct folio *folio)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
33562306a36Sopenharmony_ci	struct nfs_pageio_descriptor pgio;
33662306a36Sopenharmony_ci	struct nfs_open_context *ctx;
33762306a36Sopenharmony_ci	int ret;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	trace_nfs_aop_readpage(inode, folio);
34062306a36Sopenharmony_ci	nfs_inc_stats(inode, NFSIOS_VFSREADPAGE);
34162306a36Sopenharmony_ci	task_io_account_read(folio_size(folio));
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/*
34462306a36Sopenharmony_ci	 * Try to flush any pending writes to the file..
34562306a36Sopenharmony_ci	 *
34662306a36Sopenharmony_ci	 * NOTE! Because we own the folio lock, there cannot
34762306a36Sopenharmony_ci	 * be any new pending writes generated at this point
34862306a36Sopenharmony_ci	 * for this folio (other folios can be written to).
34962306a36Sopenharmony_ci	 */
35062306a36Sopenharmony_ci	ret = nfs_wb_folio(inode, folio);
35162306a36Sopenharmony_ci	if (ret)
35262306a36Sopenharmony_ci		goto out_unlock;
35362306a36Sopenharmony_ci	if (folio_test_uptodate(folio))
35462306a36Sopenharmony_ci		goto out_unlock;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ret = -ESTALE;
35762306a36Sopenharmony_ci	if (NFS_STALE(inode))
35862306a36Sopenharmony_ci		goto out_unlock;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ret = nfs_netfs_read_folio(file, folio);
36162306a36Sopenharmony_ci	if (!ret)
36262306a36Sopenharmony_ci		goto out;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ctx = get_nfs_open_context(nfs_file_open_context(file));
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	xchg(&ctx->error, 0);
36762306a36Sopenharmony_ci	nfs_pageio_init_read(&pgio, inode, false,
36862306a36Sopenharmony_ci			     &nfs_async_read_completion_ops);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = nfs_read_add_folio(&pgio, ctx, folio);
37162306a36Sopenharmony_ci	if (ret)
37262306a36Sopenharmony_ci		goto out_put;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	nfs_pageio_complete_read(&pgio);
37562306a36Sopenharmony_ci	ret = pgio.pg_error < 0 ? pgio.pg_error : 0;
37662306a36Sopenharmony_ci	if (!ret) {
37762306a36Sopenharmony_ci		ret = folio_wait_locked_killable(folio);
37862306a36Sopenharmony_ci		if (!folio_test_uptodate(folio) && !ret)
37962306a36Sopenharmony_ci			ret = xchg(&ctx->error, 0);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ciout_put:
38262306a36Sopenharmony_ci	put_nfs_open_context(ctx);
38362306a36Sopenharmony_ciout:
38462306a36Sopenharmony_ci	trace_nfs_aop_readpage_done(inode, folio, ret);
38562306a36Sopenharmony_ci	return ret;
38662306a36Sopenharmony_ciout_unlock:
38762306a36Sopenharmony_ci	folio_unlock(folio);
38862306a36Sopenharmony_ci	goto out;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_civoid nfs_readahead(struct readahead_control *ractl)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct nfs_pageio_descriptor pgio;
39462306a36Sopenharmony_ci	struct nfs_open_context *ctx;
39562306a36Sopenharmony_ci	unsigned int nr_pages = readahead_count(ractl);
39662306a36Sopenharmony_ci	struct file *file = ractl->file;
39762306a36Sopenharmony_ci	struct inode *inode = ractl->mapping->host;
39862306a36Sopenharmony_ci	struct folio *folio;
39962306a36Sopenharmony_ci	int ret;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	trace_nfs_aop_readahead(inode, readahead_pos(ractl), nr_pages);
40262306a36Sopenharmony_ci	nfs_inc_stats(inode, NFSIOS_VFSREADPAGES);
40362306a36Sopenharmony_ci	task_io_account_read(readahead_length(ractl));
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = -ESTALE;
40662306a36Sopenharmony_ci	if (NFS_STALE(inode))
40762306a36Sopenharmony_ci		goto out;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	ret = nfs_netfs_readahead(ractl);
41062306a36Sopenharmony_ci	if (!ret)
41162306a36Sopenharmony_ci		goto out;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (file == NULL) {
41462306a36Sopenharmony_ci		ret = -EBADF;
41562306a36Sopenharmony_ci		ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
41662306a36Sopenharmony_ci		if (ctx == NULL)
41762306a36Sopenharmony_ci			goto out;
41862306a36Sopenharmony_ci	} else
41962306a36Sopenharmony_ci		ctx = get_nfs_open_context(nfs_file_open_context(file));
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	nfs_pageio_init_read(&pgio, inode, false,
42262306a36Sopenharmony_ci			     &nfs_async_read_completion_ops);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	while ((folio = readahead_folio(ractl)) != NULL) {
42562306a36Sopenharmony_ci		ret = nfs_read_add_folio(&pgio, ctx, folio);
42662306a36Sopenharmony_ci		if (ret)
42762306a36Sopenharmony_ci			break;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	nfs_pageio_complete_read(&pgio);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	put_nfs_open_context(ctx);
43362306a36Sopenharmony_ciout:
43462306a36Sopenharmony_ci	trace_nfs_aop_readahead_done(inode, nr_pages, ret);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ciint __init nfs_init_readpagecache(void)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
44062306a36Sopenharmony_ci					     sizeof(struct nfs_pgio_header),
44162306a36Sopenharmony_ci					     0, SLAB_HWCACHE_ALIGN,
44262306a36Sopenharmony_ci					     NULL);
44362306a36Sopenharmony_ci	if (nfs_rdata_cachep == NULL)
44462306a36Sopenharmony_ci		return -ENOMEM;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return 0;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_civoid nfs_destroy_readpagecache(void)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	kmem_cache_destroy(nfs_rdata_cachep);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic const struct nfs_rw_ops nfs_rw_read_ops = {
45562306a36Sopenharmony_ci	.rw_alloc_header	= nfs_readhdr_alloc,
45662306a36Sopenharmony_ci	.rw_free_header		= nfs_readhdr_free,
45762306a36Sopenharmony_ci	.rw_done		= nfs_readpage_done,
45862306a36Sopenharmony_ci	.rw_result		= nfs_readpage_result,
45962306a36Sopenharmony_ci	.rw_initiate		= nfs_initiate_read,
46062306a36Sopenharmony_ci};
461