18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/nfs/read.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Block I/O for NFS 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Partial copy of Linus' read cache modifications to fs/nfs/file.c 88c2ecf20Sopenharmony_ci * modified for async RPC by okir@monad.swb.de 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/time.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 158c2ecf20Sopenharmony_ci#include <linux/stat.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 198c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h> 208c2ecf20Sopenharmony_ci#include <linux/nfs_fs.h> 218c2ecf20Sopenharmony_ci#include <linux/nfs_page.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "nfs4_fs.h" 258c2ecf20Sopenharmony_ci#include "internal.h" 268c2ecf20Sopenharmony_ci#include "iostat.h" 278c2ecf20Sopenharmony_ci#include "fscache.h" 288c2ecf20Sopenharmony_ci#include "pnfs.h" 298c2ecf20Sopenharmony_ci#include "nfstrace.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_PAGECACHE 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic const struct nfs_pgio_completion_ops nfs_async_read_completion_ops; 348c2ecf20Sopenharmony_cistatic const struct nfs_rw_ops nfs_rw_read_ops; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct kmem_cache *nfs_rdata_cachep; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic struct nfs_pgio_header *nfs_readhdr_alloc(void) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct nfs_pgio_header *p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (p) 438c2ecf20Sopenharmony_ci p->rw_mode = FMODE_READ; 448c2ecf20Sopenharmony_ci return p; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void nfs_readhdr_free(struct nfs_pgio_header *rhdr) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci kmem_cache_free(nfs_rdata_cachep, rhdr); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic 538c2ecf20Sopenharmony_ciint nfs_return_empty_page(struct page *page) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci zero_user(page, 0, PAGE_SIZE); 568c2ecf20Sopenharmony_ci SetPageUptodate(page); 578c2ecf20Sopenharmony_ci unlock_page(page); 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_civoid nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, 628c2ecf20Sopenharmony_ci struct inode *inode, bool force_mds, 638c2ecf20Sopenharmony_ci const struct nfs_pgio_completion_ops *compl_ops) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct nfs_server *server = NFS_SERVER(inode); 668c2ecf20Sopenharmony_ci const struct nfs_pageio_ops *pg_ops = &nfs_pgio_rw_ops; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#ifdef CONFIG_NFS_V4_1 698c2ecf20Sopenharmony_ci if (server->pnfs_curr_ld && !force_mds) 708c2ecf20Sopenharmony_ci pg_ops = server->pnfs_curr_ld->pg_read_ops; 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci nfs_pageio_init(pgio, inode, pg_ops, compl_ops, &nfs_rw_read_ops, 738c2ecf20Sopenharmony_ci server->rsize, 0); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_pageio_init_read); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct nfs_pgio_mirror *mirror; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (pgio->pg_ops && pgio->pg_ops->pg_cleanup) 828c2ecf20Sopenharmony_ci pgio->pg_ops->pg_cleanup(pgio); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci pgio->pg_ops = &nfs_pgio_rw_ops; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* read path should never have more than one mirror */ 878c2ecf20Sopenharmony_ci WARN_ON_ONCE(pgio->pg_mirror_count != 1); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci mirror = &pgio->pg_mirrors[0]; 908c2ecf20Sopenharmony_ci mirror->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void nfs_readpage_release(struct nfs_page *req, int error) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct inode *inode = d_inode(nfs_req_openctx(req)->dentry); 978c2ecf20Sopenharmony_ci struct page *page = req->wb_page; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id, 1008c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), req->wb_bytes, 1018c2ecf20Sopenharmony_ci (long long)req_offset(req)); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (nfs_error_is_fatal_on_server(error) && error != -ETIMEDOUT) 1048c2ecf20Sopenharmony_ci SetPageError(page); 1058c2ecf20Sopenharmony_ci if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) { 1068c2ecf20Sopenharmony_ci struct address_space *mapping = page_file_mapping(page); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (PageUptodate(page)) 1098c2ecf20Sopenharmony_ci nfs_readpage_to_fscache(inode, page, 0); 1108c2ecf20Sopenharmony_ci else if (!PageError(page) && !PagePrivate(page)) 1118c2ecf20Sopenharmony_ci generic_error_remove_page(mapping, page); 1128c2ecf20Sopenharmony_ci unlock_page(page); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci nfs_release_request(req); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciint nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, 1188c2ecf20Sopenharmony_ci struct page *page) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct nfs_page *new; 1218c2ecf20Sopenharmony_ci unsigned int len; 1228c2ecf20Sopenharmony_ci struct nfs_pageio_descriptor pgio; 1238c2ecf20Sopenharmony_ci struct nfs_pgio_mirror *pgm; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci len = nfs_page_length(page); 1268c2ecf20Sopenharmony_ci if (len == 0) 1278c2ecf20Sopenharmony_ci return nfs_return_empty_page(page); 1288c2ecf20Sopenharmony_ci new = nfs_create_request(ctx, page, 0, len); 1298c2ecf20Sopenharmony_ci if (IS_ERR(new)) { 1308c2ecf20Sopenharmony_ci unlock_page(page); 1318c2ecf20Sopenharmony_ci return PTR_ERR(new); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci if (len < PAGE_SIZE) 1348c2ecf20Sopenharmony_ci zero_user_segment(page, len, PAGE_SIZE); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci nfs_pageio_init_read(&pgio, inode, false, 1378c2ecf20Sopenharmony_ci &nfs_async_read_completion_ops); 1388c2ecf20Sopenharmony_ci if (!nfs_pageio_add_request(&pgio, new)) { 1398c2ecf20Sopenharmony_ci nfs_list_remove_request(new); 1408c2ecf20Sopenharmony_ci nfs_readpage_release(new, pgio.pg_error); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci nfs_pageio_complete(&pgio); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* It doesn't make sense to do mirrored reads! */ 1458c2ecf20Sopenharmony_ci WARN_ON_ONCE(pgio.pg_mirror_count != 1); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci pgm = &pgio.pg_mirrors[0]; 1488c2ecf20Sopenharmony_ci NFS_I(inode)->read_io += pgm->pg_bytes_written; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return pgio.pg_error < 0 ? pgio.pg_error : 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void nfs_page_group_set_uptodate(struct nfs_page *req) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci if (nfs_page_group_sync_on_bit(req, PG_UPTODATE)) 1568c2ecf20Sopenharmony_ci SetPageUptodate(req->wb_page); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic void nfs_read_completion(struct nfs_pgio_header *hdr) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci unsigned long bytes = 0; 1628c2ecf20Sopenharmony_ci int error; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) 1658c2ecf20Sopenharmony_ci goto out; 1668c2ecf20Sopenharmony_ci while (!list_empty(&hdr->pages)) { 1678c2ecf20Sopenharmony_ci struct nfs_page *req = nfs_list_entry(hdr->pages.next); 1688c2ecf20Sopenharmony_ci struct page *page = req->wb_page; 1698c2ecf20Sopenharmony_ci unsigned long start = req->wb_pgbase; 1708c2ecf20Sopenharmony_ci unsigned long end = req->wb_pgbase + req->wb_bytes; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) { 1738c2ecf20Sopenharmony_ci /* note: regions of the page not covered by a 1748c2ecf20Sopenharmony_ci * request are zeroed in nfs_readpage_async / 1758c2ecf20Sopenharmony_ci * readpage_async_filler */ 1768c2ecf20Sopenharmony_ci if (bytes > hdr->good_bytes) { 1778c2ecf20Sopenharmony_ci /* nothing in this request was good, so zero 1788c2ecf20Sopenharmony_ci * the full extent of the request */ 1798c2ecf20Sopenharmony_ci zero_user_segment(page, start, end); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci } else if (hdr->good_bytes - bytes < req->wb_bytes) { 1828c2ecf20Sopenharmony_ci /* part of this request has good bytes, but 1838c2ecf20Sopenharmony_ci * not all. zero the bad bytes */ 1848c2ecf20Sopenharmony_ci start += hdr->good_bytes - bytes; 1858c2ecf20Sopenharmony_ci WARN_ON(start < req->wb_pgbase); 1868c2ecf20Sopenharmony_ci zero_user_segment(page, start, end); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci error = 0; 1908c2ecf20Sopenharmony_ci bytes += req->wb_bytes; 1918c2ecf20Sopenharmony_ci if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { 1928c2ecf20Sopenharmony_ci if (bytes <= hdr->good_bytes) 1938c2ecf20Sopenharmony_ci nfs_page_group_set_uptodate(req); 1948c2ecf20Sopenharmony_ci else { 1958c2ecf20Sopenharmony_ci error = hdr->error; 1968c2ecf20Sopenharmony_ci xchg(&nfs_req_openctx(req)->error, error); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci } else 1998c2ecf20Sopenharmony_ci nfs_page_group_set_uptodate(req); 2008c2ecf20Sopenharmony_ci nfs_list_remove_request(req); 2018c2ecf20Sopenharmony_ci nfs_readpage_release(req, error); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ciout: 2048c2ecf20Sopenharmony_ci hdr->release(hdr); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic void nfs_initiate_read(struct nfs_pgio_header *hdr, 2088c2ecf20Sopenharmony_ci struct rpc_message *msg, 2098c2ecf20Sopenharmony_ci const struct nfs_rpc_ops *rpc_ops, 2108c2ecf20Sopenharmony_ci struct rpc_task_setup *task_setup_data, int how) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct inode *inode = hdr->inode; 2138c2ecf20Sopenharmony_ci int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci task_setup_data->flags |= swap_flags; 2168c2ecf20Sopenharmony_ci rpc_ops->read_setup(hdr, msg); 2178c2ecf20Sopenharmony_ci trace_nfs_initiate_read(hdr); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void 2218c2ecf20Sopenharmony_cinfs_async_read_error(struct list_head *head, int error) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct nfs_page *req; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci while (!list_empty(head)) { 2268c2ecf20Sopenharmony_ci req = nfs_list_entry(head->next); 2278c2ecf20Sopenharmony_ci nfs_list_remove_request(req); 2288c2ecf20Sopenharmony_ci nfs_readpage_release(req, error); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = { 2338c2ecf20Sopenharmony_ci .error_cleanup = nfs_async_read_error, 2348c2ecf20Sopenharmony_ci .completion = nfs_read_completion, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * This is the callback from RPC telling us whether a reply was 2398c2ecf20Sopenharmony_ci * received or some error occurred (timeout or socket shutdown). 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_cistatic int nfs_readpage_done(struct rpc_task *task, 2428c2ecf20Sopenharmony_ci struct nfs_pgio_header *hdr, 2438c2ecf20Sopenharmony_ci struct inode *inode) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int status = NFS_PROTO(inode)->read_done(task, hdr); 2468c2ecf20Sopenharmony_ci if (status != 0) 2478c2ecf20Sopenharmony_ci return status; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, hdr->res.count); 2508c2ecf20Sopenharmony_ci trace_nfs_readpage_done(task, hdr); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (task->tk_status == -ESTALE) { 2538c2ecf20Sopenharmony_ci nfs_set_inode_stale(inode); 2548c2ecf20Sopenharmony_ci nfs_mark_for_revalidate(inode); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void nfs_readpage_retry(struct rpc_task *task, 2608c2ecf20Sopenharmony_ci struct nfs_pgio_header *hdr) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct nfs_pgio_args *argp = &hdr->args; 2638c2ecf20Sopenharmony_ci struct nfs_pgio_res *resp = &hdr->res; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* This is a short read! */ 2668c2ecf20Sopenharmony_ci nfs_inc_stats(hdr->inode, NFSIOS_SHORTREAD); 2678c2ecf20Sopenharmony_ci trace_nfs_readpage_short(task, hdr); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Has the server at least made some progress? */ 2708c2ecf20Sopenharmony_ci if (resp->count == 0) { 2718c2ecf20Sopenharmony_ci nfs_set_pgio_error(hdr, -EIO, argp->offset); 2728c2ecf20Sopenharmony_ci return; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* For non rpc-based layout drivers, retry-through-MDS */ 2768c2ecf20Sopenharmony_ci if (!task->tk_ops) { 2778c2ecf20Sopenharmony_ci hdr->pnfs_error = -EAGAIN; 2788c2ecf20Sopenharmony_ci return; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Yes, so retry the read at the end of the hdr */ 2828c2ecf20Sopenharmony_ci hdr->mds_offset += resp->count; 2838c2ecf20Sopenharmony_ci argp->offset += resp->count; 2848c2ecf20Sopenharmony_ci argp->pgbase += resp->count; 2858c2ecf20Sopenharmony_ci argp->count -= resp->count; 2868c2ecf20Sopenharmony_ci resp->count = 0; 2878c2ecf20Sopenharmony_ci resp->eof = 0; 2888c2ecf20Sopenharmony_ci rpc_restart_call_prepare(task); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void nfs_readpage_result(struct rpc_task *task, 2928c2ecf20Sopenharmony_ci struct nfs_pgio_header *hdr) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci if (hdr->res.eof) { 2958c2ecf20Sopenharmony_ci loff_t pos = hdr->args.offset + hdr->res.count; 2968c2ecf20Sopenharmony_ci unsigned int new = pos - hdr->io_start; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (hdr->good_bytes > new) { 2998c2ecf20Sopenharmony_ci hdr->good_bytes = new; 3008c2ecf20Sopenharmony_ci set_bit(NFS_IOHDR_EOF, &hdr->flags); 3018c2ecf20Sopenharmony_ci clear_bit(NFS_IOHDR_ERROR, &hdr->flags); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci } else if (hdr->res.count < hdr->args.count) 3048c2ecf20Sopenharmony_ci nfs_readpage_retry(task, hdr); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* 3088c2ecf20Sopenharmony_ci * Read a page over NFS. 3098c2ecf20Sopenharmony_ci * We read the page synchronously in the following case: 3108c2ecf20Sopenharmony_ci * - The error flag is set for this page. This happens only when a 3118c2ecf20Sopenharmony_ci * previous async read operation failed. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ciint nfs_readpage(struct file *file, struct page *page) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct nfs_open_context *ctx; 3168c2ecf20Sopenharmony_ci struct inode *inode = page_file_mapping(page)->host; 3178c2ecf20Sopenharmony_ci int error; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", 3208c2ecf20Sopenharmony_ci page, PAGE_SIZE, page_index(page)); 3218c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); 3228c2ecf20Sopenharmony_ci nfs_add_stats(inode, NFSIOS_READPAGES, 1); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Try to flush any pending writes to the file.. 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * NOTE! Because we own the page lock, there cannot 3288c2ecf20Sopenharmony_ci * be any new pending writes generated at this point 3298c2ecf20Sopenharmony_ci * for this page (other pages can be written to). 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci error = nfs_wb_page(inode, page); 3328c2ecf20Sopenharmony_ci if (error) 3338c2ecf20Sopenharmony_ci goto out_unlock; 3348c2ecf20Sopenharmony_ci if (PageUptodate(page)) 3358c2ecf20Sopenharmony_ci goto out_unlock; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci error = -ESTALE; 3388c2ecf20Sopenharmony_ci if (NFS_STALE(inode)) 3398c2ecf20Sopenharmony_ci goto out_unlock; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (file == NULL) { 3428c2ecf20Sopenharmony_ci error = -EBADF; 3438c2ecf20Sopenharmony_ci ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 3448c2ecf20Sopenharmony_ci if (ctx == NULL) 3458c2ecf20Sopenharmony_ci goto out_unlock; 3468c2ecf20Sopenharmony_ci } else 3478c2ecf20Sopenharmony_ci ctx = get_nfs_open_context(nfs_file_open_context(file)); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!IS_SYNC(inode)) { 3508c2ecf20Sopenharmony_ci error = nfs_readpage_from_fscache(ctx, inode, page); 3518c2ecf20Sopenharmony_ci if (error == 0) 3528c2ecf20Sopenharmony_ci goto out; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci xchg(&ctx->error, 0); 3568c2ecf20Sopenharmony_ci error = nfs_readpage_async(ctx, inode, page); 3578c2ecf20Sopenharmony_ci if (!error) { 3588c2ecf20Sopenharmony_ci error = wait_on_page_locked_killable(page); 3598c2ecf20Sopenharmony_ci if (!PageUptodate(page) && !error) 3608c2ecf20Sopenharmony_ci error = xchg(&ctx->error, 0); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ciout: 3638c2ecf20Sopenharmony_ci put_nfs_open_context(ctx); 3648c2ecf20Sopenharmony_ci return error; 3658c2ecf20Sopenharmony_ciout_unlock: 3668c2ecf20Sopenharmony_ci unlock_page(page); 3678c2ecf20Sopenharmony_ci return error; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistruct nfs_readdesc { 3718c2ecf20Sopenharmony_ci struct nfs_pageio_descriptor *pgio; 3728c2ecf20Sopenharmony_ci struct nfs_open_context *ctx; 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int 3768c2ecf20Sopenharmony_cireadpage_async_filler(void *data, struct page *page) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct nfs_readdesc *desc = (struct nfs_readdesc *)data; 3798c2ecf20Sopenharmony_ci struct nfs_page *new; 3808c2ecf20Sopenharmony_ci unsigned int len; 3818c2ecf20Sopenharmony_ci int error; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci len = nfs_page_length(page); 3848c2ecf20Sopenharmony_ci if (len == 0) 3858c2ecf20Sopenharmony_ci return nfs_return_empty_page(page); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci new = nfs_create_request(desc->ctx, page, 0, len); 3888c2ecf20Sopenharmony_ci if (IS_ERR(new)) 3898c2ecf20Sopenharmony_ci goto out_error; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (len < PAGE_SIZE) 3928c2ecf20Sopenharmony_ci zero_user_segment(page, len, PAGE_SIZE); 3938c2ecf20Sopenharmony_ci if (!nfs_pageio_add_request(desc->pgio, new)) { 3948c2ecf20Sopenharmony_ci nfs_list_remove_request(new); 3958c2ecf20Sopenharmony_ci error = desc->pgio->pg_error; 3968c2ecf20Sopenharmony_ci nfs_readpage_release(new, error); 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ciout_error: 4018c2ecf20Sopenharmony_ci error = PTR_ERR(new); 4028c2ecf20Sopenharmony_ci unlock_page(page); 4038c2ecf20Sopenharmony_ciout: 4048c2ecf20Sopenharmony_ci return error; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ciint nfs_readpages(struct file *filp, struct address_space *mapping, 4088c2ecf20Sopenharmony_ci struct list_head *pages, unsigned nr_pages) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct nfs_pageio_descriptor pgio; 4118c2ecf20Sopenharmony_ci struct nfs_pgio_mirror *pgm; 4128c2ecf20Sopenharmony_ci struct nfs_readdesc desc = { 4138c2ecf20Sopenharmony_ci .pgio = &pgio, 4148c2ecf20Sopenharmony_ci }; 4158c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 4168c2ecf20Sopenharmony_ci unsigned long npages; 4178c2ecf20Sopenharmony_ci int ret = -ESTALE; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci dprintk("NFS: nfs_readpages (%s/%Lu %d)\n", 4208c2ecf20Sopenharmony_ci inode->i_sb->s_id, 4218c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), 4228c2ecf20Sopenharmony_ci nr_pages); 4238c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (NFS_STALE(inode)) 4268c2ecf20Sopenharmony_ci goto out; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (filp == NULL) { 4298c2ecf20Sopenharmony_ci desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 4308c2ecf20Sopenharmony_ci if (desc.ctx == NULL) 4318c2ecf20Sopenharmony_ci return -EBADF; 4328c2ecf20Sopenharmony_ci } else 4338c2ecf20Sopenharmony_ci desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* attempt to read as many of the pages as possible from the cache 4368c2ecf20Sopenharmony_ci * - this returns -ENOBUFS immediately if the cookie is negative 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping, 4398c2ecf20Sopenharmony_ci pages, &nr_pages); 4408c2ecf20Sopenharmony_ci if (ret == 0) 4418c2ecf20Sopenharmony_ci goto read_complete; /* all pages were read */ 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci nfs_pageio_init_read(&pgio, inode, false, 4448c2ecf20Sopenharmony_ci &nfs_async_read_completion_ops); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); 4478c2ecf20Sopenharmony_ci nfs_pageio_complete(&pgio); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* It doesn't make sense to do mirrored reads! */ 4508c2ecf20Sopenharmony_ci WARN_ON_ONCE(pgio.pg_mirror_count != 1); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci pgm = &pgio.pg_mirrors[0]; 4538c2ecf20Sopenharmony_ci NFS_I(inode)->read_io += pgm->pg_bytes_written; 4548c2ecf20Sopenharmony_ci npages = (pgm->pg_bytes_written + PAGE_SIZE - 1) >> 4558c2ecf20Sopenharmony_ci PAGE_SHIFT; 4568c2ecf20Sopenharmony_ci nfs_add_stats(inode, NFSIOS_READPAGES, npages); 4578c2ecf20Sopenharmony_ciread_complete: 4588c2ecf20Sopenharmony_ci put_nfs_open_context(desc.ctx); 4598c2ecf20Sopenharmony_ciout: 4608c2ecf20Sopenharmony_ci return ret; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ciint __init nfs_init_readpagecache(void) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci nfs_rdata_cachep = kmem_cache_create("nfs_read_data", 4668c2ecf20Sopenharmony_ci sizeof(struct nfs_pgio_header), 4678c2ecf20Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, 4688c2ecf20Sopenharmony_ci NULL); 4698c2ecf20Sopenharmony_ci if (nfs_rdata_cachep == NULL) 4708c2ecf20Sopenharmony_ci return -ENOMEM; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_civoid nfs_destroy_readpagecache(void) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci kmem_cache_destroy(nfs_rdata_cachep); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic const struct nfs_rw_ops nfs_rw_read_ops = { 4818c2ecf20Sopenharmony_ci .rw_alloc_header = nfs_readhdr_alloc, 4828c2ecf20Sopenharmony_ci .rw_free_header = nfs_readhdr_free, 4838c2ecf20Sopenharmony_ci .rw_done = nfs_readpage_done, 4848c2ecf20Sopenharmony_ci .rw_result = nfs_readpage_result, 4858c2ecf20Sopenharmony_ci .rw_initiate = nfs_initiate_read, 4868c2ecf20Sopenharmony_ci}; 487