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