11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/nfs/read.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Block I/O for NFS 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Partial copy of Linus' read cache modifications to fs/nfs/file.c 71da177e4SLinus Torvalds * modified for async RPC by okir@monad.swb.de 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/time.h> 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/errno.h> 131da177e4SLinus Torvalds #include <linux/fcntl.h> 141da177e4SLinus Torvalds #include <linux/stat.h> 151da177e4SLinus Torvalds #include <linux/mm.h> 161da177e4SLinus Torvalds #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/pagemap.h> 181da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 191da177e4SLinus Torvalds #include <linux/nfs_fs.h> 201da177e4SLinus Torvalds #include <linux/nfs_page.h> 2164419a9bSAndy Adamson #include <linux/module.h> 221da177e4SLinus Torvalds 23bae724efSFred Isaman #include "pnfs.h" 241da177e4SLinus Torvalds 25f11c88afSAndy Adamson #include "nfs4_fs.h" 2649a70f27STrond Myklebust #include "internal.h" 2791d5b470SChuck Lever #include "iostat.h" 289a9fc1c0SDavid Howells #include "fscache.h" 2991d5b470SChuck Lever 301da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_PAGECACHE 311da177e4SLinus Torvalds 321751c363STrond Myklebust static const struct nfs_pageio_ops nfs_pageio_read_ops; 334db6e0b7SFred Isaman static const struct rpc_call_ops nfs_read_common_ops; 34*061ae2edSFred Isaman static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops; 351da177e4SLinus Torvalds 36e18b890bSChristoph Lameter static struct kmem_cache *nfs_rdata_cachep; 371da177e4SLinus Torvalds 384db6e0b7SFred Isaman struct nfs_read_header *nfs_readhdr_alloc() 393feb2d49STrond Myklebust { 404db6e0b7SFred Isaman struct nfs_read_header *rhdr; 413feb2d49STrond Myklebust 424db6e0b7SFred Isaman rhdr = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); 434db6e0b7SFred Isaman if (rhdr) { 444db6e0b7SFred Isaman struct nfs_pgio_header *hdr = &rhdr->header; 45cd841605SFred Isaman 46cd841605SFred Isaman INIT_LIST_HEAD(&hdr->pages); 474db6e0b7SFred Isaman INIT_LIST_HEAD(&hdr->rpc_list); 484db6e0b7SFred Isaman spin_lock_init(&hdr->lock); 494db6e0b7SFred Isaman atomic_set(&hdr->refcnt, 0); 504db6e0b7SFred Isaman } 514db6e0b7SFred Isaman return rhdr; 524db6e0b7SFred Isaman } 534db6e0b7SFred Isaman 544db6e0b7SFred Isaman struct nfs_read_data *nfs_readdata_alloc(struct nfs_pgio_header *hdr, 554db6e0b7SFred Isaman unsigned int pagecount) 564db6e0b7SFred Isaman { 574db6e0b7SFred Isaman struct nfs_read_data *data, *prealloc; 584db6e0b7SFred Isaman 594db6e0b7SFred Isaman prealloc = &container_of(hdr, struct nfs_read_header, header)->rpc_data; 604db6e0b7SFred Isaman if (prealloc->header == NULL) 614db6e0b7SFred Isaman data = prealloc; 624db6e0b7SFred Isaman else 634db6e0b7SFred Isaman data = kzalloc(sizeof(*data), GFP_KERNEL); 644db6e0b7SFred Isaman if (!data) 654db6e0b7SFred Isaman goto out; 664db6e0b7SFred Isaman 674db6e0b7SFred Isaman if (nfs_pgarray_set(&data->pages, pagecount)) { 68cd841605SFred Isaman data->header = hdr; 694db6e0b7SFred Isaman atomic_inc(&hdr->refcnt); 704db6e0b7SFred Isaman } else { 714db6e0b7SFred Isaman if (data != prealloc) 724db6e0b7SFred Isaman kfree(data); 734db6e0b7SFred Isaman data = NULL; 743feb2d49STrond Myklebust } 754db6e0b7SFred Isaman out: 764db6e0b7SFred Isaman return data; 773feb2d49STrond Myklebust } 783feb2d49STrond Myklebust 79cd841605SFred Isaman void nfs_readhdr_free(struct nfs_pgio_header *hdr) 803feb2d49STrond Myklebust { 81cd841605SFred Isaman struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header); 82cd841605SFred Isaman 83cd841605SFred Isaman kmem_cache_free(nfs_rdata_cachep, rhdr); 843feb2d49STrond Myklebust } 853feb2d49STrond Myklebust 86493292ddSTrond Myklebust void nfs_readdata_release(struct nfs_read_data *rdata) 871da177e4SLinus Torvalds { 884db6e0b7SFred Isaman struct nfs_pgio_header *hdr = rdata->header; 894db6e0b7SFred Isaman struct nfs_read_header *read_header = container_of(hdr, struct nfs_read_header, header); 904db6e0b7SFred Isaman 91383ba719STrond Myklebust put_nfs_open_context(rdata->args.context); 9230dd374fSFred Isaman if (rdata->pages.pagevec != rdata->pages.page_array) 9330dd374fSFred Isaman kfree(rdata->pages.pagevec); 944db6e0b7SFred Isaman if (rdata != &read_header->rpc_data) 954db6e0b7SFred Isaman kfree(rdata); 964db6e0b7SFred Isaman else 974db6e0b7SFred Isaman rdata->header = NULL; 984db6e0b7SFred Isaman if (atomic_dec_and_test(&hdr->refcnt)) 99*061ae2edSFred Isaman hdr->completion_ops->completion(hdr); 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds static 1031da177e4SLinus Torvalds int nfs_return_empty_page(struct page *page) 1041da177e4SLinus Torvalds { 105eebd2aa3SChristoph Lameter zero_user(page, 0, PAGE_CACHE_SIZE); 1061da177e4SLinus Torvalds SetPageUptodate(page); 1071da177e4SLinus Torvalds unlock_page(page); 1081da177e4SLinus Torvalds return 0; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 11162e4a769STrond Myklebust void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, 112*061ae2edSFred Isaman struct inode *inode, 113*061ae2edSFred Isaman const struct nfs_pgio_completion_ops *compl_ops) 1141751c363STrond Myklebust { 115*061ae2edSFred Isaman nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, compl_ops, 1161751c363STrond Myklebust NFS_SERVER(inode)->rsize, 0); 1171751c363STrond Myklebust } 1181751c363STrond Myklebust 119493292ddSTrond Myklebust void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) 120493292ddSTrond Myklebust { 121493292ddSTrond Myklebust pgio->pg_ops = &nfs_pageio_read_ops; 122493292ddSTrond Myklebust pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; 123493292ddSTrond Myklebust } 1241f945357STrond Myklebust EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); 125493292ddSTrond Myklebust 1261751c363STrond Myklebust static void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, 127*061ae2edSFred Isaman struct inode *inode, 128*061ae2edSFred Isaman const struct nfs_pgio_completion_ops *compl_ops) 1291751c363STrond Myklebust { 130*061ae2edSFred Isaman if (!pnfs_pageio_init_read(pgio, inode, compl_ops)) 131*061ae2edSFred Isaman nfs_pageio_init_read_mds(pgio, inode, compl_ops); 1321751c363STrond Myklebust } 1331751c363STrond Myklebust 134f42b293dSDavid Howells int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, 1351da177e4SLinus Torvalds struct page *page) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds struct nfs_page *new; 1381da177e4SLinus Torvalds unsigned int len; 139c76069bdSFred Isaman struct nfs_pageio_descriptor pgio; 1401da177e4SLinus Torvalds 14149a70f27STrond Myklebust len = nfs_page_length(page); 1421da177e4SLinus Torvalds if (len == 0) 1431da177e4SLinus Torvalds return nfs_return_empty_page(page); 1441da177e4SLinus Torvalds new = nfs_create_request(ctx, inode, page, 0, len); 1451da177e4SLinus Torvalds if (IS_ERR(new)) { 1461da177e4SLinus Torvalds unlock_page(page); 1471da177e4SLinus Torvalds return PTR_ERR(new); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds if (len < PAGE_CACHE_SIZE) 150eebd2aa3SChristoph Lameter zero_user_segment(page, len, PAGE_CACHE_SIZE); 1511da177e4SLinus Torvalds 152*061ae2edSFred Isaman nfs_pageio_init_read(&pgio, inode, &nfs_async_read_completion_ops); 153d8007d4dSTrond Myklebust nfs_pageio_add_request(&pgio, new); 1541751c363STrond Myklebust nfs_pageio_complete(&pgio); 1551da177e4SLinus Torvalds return 0; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds static void nfs_readpage_release(struct nfs_page *req) 1591da177e4SLinus Torvalds { 1603d4ff43dSAl Viro struct inode *d_inode = req->wb_context->dentry->d_inode; 1617f8e05f6SDavid Howells 1627f8e05f6SDavid Howells if (PageUptodate(req->wb_page)) 1637f8e05f6SDavid Howells nfs_readpage_to_fscache(d_inode, req->wb_page, 0); 1647f8e05f6SDavid Howells 1651da177e4SLinus Torvalds unlock_page(req->wb_page); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", 1683d4ff43dSAl Viro req->wb_context->dentry->d_inode->i_sb->s_id, 1693d4ff43dSAl Viro (long long)NFS_FILEID(req->wb_context->dentry->d_inode), 1701da177e4SLinus Torvalds req->wb_bytes, 1711da177e4SLinus Torvalds (long long)req_offset(req)); 17210d2c46fSNick Wilson nfs_release_request(req); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1754db6e0b7SFred Isaman /* Note io was page aligned */ 176*061ae2edSFred Isaman static void nfs_read_completion(struct nfs_pgio_header *hdr) 1774db6e0b7SFred Isaman { 1784db6e0b7SFred Isaman unsigned long bytes = 0; 1794db6e0b7SFred Isaman 1804db6e0b7SFred Isaman if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) 1814db6e0b7SFred Isaman goto out; 1824db6e0b7SFred Isaman if (!test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { 1834db6e0b7SFred Isaman while (!list_empty(&hdr->pages)) { 1844db6e0b7SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 1854db6e0b7SFred Isaman struct page *page = req->wb_page; 1864db6e0b7SFred Isaman 1874db6e0b7SFred Isaman if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) { 1884db6e0b7SFred Isaman if (bytes > hdr->good_bytes) 1894db6e0b7SFred Isaman zero_user(page, 0, PAGE_SIZE); 1904db6e0b7SFred Isaman else if (hdr->good_bytes - bytes < PAGE_SIZE) 1914db6e0b7SFred Isaman zero_user_segment(page, 1924db6e0b7SFred Isaman hdr->good_bytes & ~PAGE_MASK, 1934db6e0b7SFred Isaman PAGE_SIZE); 1944db6e0b7SFred Isaman } 1954db6e0b7SFred Isaman SetPageUptodate(page); 1964db6e0b7SFred Isaman nfs_list_remove_request(req); 1974db6e0b7SFred Isaman nfs_readpage_release(req); 1984db6e0b7SFred Isaman bytes += PAGE_SIZE; 1994db6e0b7SFred Isaman } 2004db6e0b7SFred Isaman } else { 2014db6e0b7SFred Isaman while (!list_empty(&hdr->pages)) { 2024db6e0b7SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 2034db6e0b7SFred Isaman 2044db6e0b7SFred Isaman bytes += req->wb_bytes; 2054db6e0b7SFred Isaman if (bytes <= hdr->good_bytes) 2064db6e0b7SFred Isaman SetPageUptodate(req->wb_page); 2074db6e0b7SFred Isaman nfs_list_remove_request(req); 2084db6e0b7SFred Isaman nfs_readpage_release(req); 2094db6e0b7SFred Isaman } 2104db6e0b7SFred Isaman } 2114db6e0b7SFred Isaman out: 2124db6e0b7SFred Isaman hdr->release(hdr); 2134db6e0b7SFred Isaman } 2144db6e0b7SFred Isaman 215c5996c4eSFred Isaman int nfs_initiate_read(struct rpc_clnt *clnt, 216c5996c4eSFred Isaman struct nfs_read_data *data, 21764419a9bSAndy Adamson const struct rpc_call_ops *call_ops) 21864419a9bSAndy Adamson { 219cd841605SFred Isaman struct inode *inode = data->header->inode; 22064419a9bSAndy Adamson int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; 22164419a9bSAndy Adamson struct rpc_task *task; 22264419a9bSAndy Adamson struct rpc_message msg = { 22364419a9bSAndy Adamson .rpc_argp = &data->args, 22464419a9bSAndy Adamson .rpc_resp = &data->res, 225cd841605SFred Isaman .rpc_cred = data->header->cred, 22664419a9bSAndy Adamson }; 22764419a9bSAndy Adamson struct rpc_task_setup task_setup_data = { 22864419a9bSAndy Adamson .task = &data->task, 22964419a9bSAndy Adamson .rpc_client = clnt, 23064419a9bSAndy Adamson .rpc_message = &msg, 23164419a9bSAndy Adamson .callback_ops = call_ops, 23264419a9bSAndy Adamson .callback_data = data, 23364419a9bSAndy Adamson .workqueue = nfsiod_workqueue, 23464419a9bSAndy Adamson .flags = RPC_TASK_ASYNC | swap_flags, 23564419a9bSAndy Adamson }; 23664419a9bSAndy Adamson 23764419a9bSAndy Adamson /* Set up the initial task struct. */ 23864419a9bSAndy Adamson NFS_PROTO(inode)->read_setup(data, &msg); 23964419a9bSAndy Adamson 24064419a9bSAndy Adamson dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ " 24164419a9bSAndy Adamson "offset %llu)\n", 24264419a9bSAndy Adamson data->task.tk_pid, 24364419a9bSAndy Adamson inode->i_sb->s_id, 24464419a9bSAndy Adamson (long long)NFS_FILEID(inode), 24564419a9bSAndy Adamson data->args.count, 24664419a9bSAndy Adamson (unsigned long long)data->args.offset); 24764419a9bSAndy Adamson 24864419a9bSAndy Adamson task = rpc_run_task(&task_setup_data); 24964419a9bSAndy Adamson if (IS_ERR(task)) 25064419a9bSAndy Adamson return PTR_ERR(task); 25164419a9bSAndy Adamson rpc_put_task(task); 25264419a9bSAndy Adamson return 0; 25364419a9bSAndy Adamson } 254dc70d7b3SAndy Adamson EXPORT_SYMBOL_GPL(nfs_initiate_read); 25564419a9bSAndy Adamson 2561da177e4SLinus Torvalds /* 2571da177e4SLinus Torvalds * Set up the NFS read request struct 2581da177e4SLinus Torvalds */ 2594db6e0b7SFred Isaman static void nfs_read_rpcsetup(struct nfs_read_data *data, 2606e4efd56STrond Myklebust unsigned int count, unsigned int offset) 2611da177e4SLinus Torvalds { 2624db6e0b7SFred Isaman struct nfs_page *req = data->header->req; 2631da177e4SLinus Torvalds 2644db6e0b7SFred Isaman data->args.fh = NFS_FH(data->header->inode); 2651da177e4SLinus Torvalds data->args.offset = req_offset(req) + offset; 2661da177e4SLinus Torvalds data->args.pgbase = req->wb_pgbase + offset; 26730dd374fSFred Isaman data->args.pages = data->pages.pagevec; 2681da177e4SLinus Torvalds data->args.count = count; 269383ba719STrond Myklebust data->args.context = get_nfs_open_context(req->wb_context); 270f11ac8dbSTrond Myklebust data->args.lock_context = req->wb_lock_context; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds data->res.fattr = &data->fattr; 2731da177e4SLinus Torvalds data->res.count = count; 2741da177e4SLinus Torvalds data->res.eof = 0; 2750e574af1STrond Myklebust nfs_fattr_init(&data->fattr); 2766e4efd56STrond Myklebust } 2771da177e4SLinus Torvalds 2786e4efd56STrond Myklebust static int nfs_do_read(struct nfs_read_data *data, 279493292ddSTrond Myklebust const struct rpc_call_ops *call_ops) 2806e4efd56STrond Myklebust { 281cd841605SFred Isaman struct inode *inode = data->header->inode; 2826e4efd56STrond Myklebust 283c5996c4eSFred Isaman return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops); 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds 286275acaafSTrond Myklebust static int 287275acaafSTrond Myklebust nfs_do_multiple_reads(struct list_head *head, 288493292ddSTrond Myklebust const struct rpc_call_ops *call_ops) 289275acaafSTrond Myklebust { 290275acaafSTrond Myklebust struct nfs_read_data *data; 291275acaafSTrond Myklebust int ret = 0; 292275acaafSTrond Myklebust 293275acaafSTrond Myklebust while (!list_empty(head)) { 294275acaafSTrond Myklebust int ret2; 295275acaafSTrond Myklebust 2964db6e0b7SFred Isaman data = list_first_entry(head, struct nfs_read_data, list); 297275acaafSTrond Myklebust list_del_init(&data->list); 298275acaafSTrond Myklebust 299493292ddSTrond Myklebust ret2 = nfs_do_read(data, call_ops); 300275acaafSTrond Myklebust if (ret == 0) 301275acaafSTrond Myklebust ret = ret2; 302275acaafSTrond Myklebust } 303275acaafSTrond Myklebust return ret; 304275acaafSTrond Myklebust } 305275acaafSTrond Myklebust 306*061ae2edSFred Isaman static void 3071da177e4SLinus Torvalds nfs_async_read_error(struct list_head *head) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds struct nfs_page *req; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds while (!list_empty(head)) { 3121da177e4SLinus Torvalds req = nfs_list_entry(head->next); 3131da177e4SLinus Torvalds nfs_list_remove_request(req); 3141da177e4SLinus Torvalds nfs_readpage_release(req); 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 318*061ae2edSFred Isaman static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = { 319*061ae2edSFred Isaman .error_cleanup = nfs_async_read_error, 320*061ae2edSFred Isaman .completion = nfs_read_completion, 321*061ae2edSFred Isaman }; 322*061ae2edSFred Isaman 3231da177e4SLinus Torvalds /* 3241da177e4SLinus Torvalds * Generate multiple requests to fill a single page. 3251da177e4SLinus Torvalds * 3261da177e4SLinus Torvalds * We optimize to reduce the number of read operations on the wire. If we 3271da177e4SLinus Torvalds * detect that we're reading a page, or an area of a page, that is past the 3281da177e4SLinus Torvalds * end of file, we do not generate NFS read operations but just clear the 3291da177e4SLinus Torvalds * parts of the page that would have come back zero from the server anyway. 3301da177e4SLinus Torvalds * 3311da177e4SLinus Torvalds * We rely on the cached value of i_size to make this determination; another 3321da177e4SLinus Torvalds * client can fill pages on the server past our cached end-of-file, but we 3331da177e4SLinus Torvalds * won't see the new data until our attribute cache is updated. This is more 3341da177e4SLinus Torvalds * or less conventional NFS client behavior. 3351da177e4SLinus Torvalds */ 3364db6e0b7SFred Isaman static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, 3374db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 3381da177e4SLinus Torvalds { 3394db6e0b7SFred Isaman struct nfs_page *req = hdr->req; 3401da177e4SLinus Torvalds struct page *page = req->wb_page; 3411da177e4SLinus Torvalds struct nfs_read_data *data; 342d097971dSTrond Myklebust size_t rsize = desc->pg_bsize, nbytes; 343e9f7bee1STrond Myklebust unsigned int offset; 3441da177e4SLinus Torvalds int requests = 0; 345dbae4c73STrond Myklebust int ret = 0; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds nfs_list_remove_request(req); 3484db6e0b7SFred Isaman nfs_list_add_request(req, &hdr->pages); 3491da177e4SLinus Torvalds 350275acaafSTrond Myklebust offset = 0; 351c76069bdSFred Isaman nbytes = desc->pg_count; 352e9f7bee1STrond Myklebust do { 353e9f7bee1STrond Myklebust size_t len = min(nbytes,rsize); 354e9f7bee1STrond Myklebust 3554db6e0b7SFred Isaman data = nfs_readdata_alloc(hdr, 1); 3564db6e0b7SFred Isaman if (!data) 3571da177e4SLinus Torvalds goto out_bad; 35830dd374fSFred Isaman data->pages.pagevec[0] = page; 3594db6e0b7SFred Isaman nfs_read_rpcsetup(data, len, offset); 3604db6e0b7SFred Isaman list_add(&data->list, &hdr->rpc_list); 3611da177e4SLinus Torvalds requests++; 362e9f7bee1STrond Myklebust nbytes -= len; 363275acaafSTrond Myklebust offset += len; 364e9f7bee1STrond Myklebust } while(nbytes != 0); 3654db6e0b7SFred Isaman desc->pg_rpc_callops = &nfs_read_common_ops; 366dbae4c73STrond Myklebust return ret; 3671da177e4SLinus Torvalds out_bad: 3684db6e0b7SFred Isaman while (!list_empty(&hdr->rpc_list)) { 3694db6e0b7SFred Isaman data = list_first_entry(&hdr->rpc_list, struct nfs_read_data, list); 3706e4efd56STrond Myklebust list_del(&data->list); 37173fb7bc7SFred Isaman nfs_readdata_release(data); 3721da177e4SLinus Torvalds } 373*061ae2edSFred Isaman desc->pg_completion_ops->error_cleanup(&hdr->pages); 3741da177e4SLinus Torvalds return -ENOMEM; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3774db6e0b7SFred Isaman static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, 3784db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 3791da177e4SLinus Torvalds { 3801da177e4SLinus Torvalds struct nfs_page *req; 3811da177e4SLinus Torvalds struct page **pages; 3821da177e4SLinus Torvalds struct nfs_read_data *data; 383c76069bdSFred Isaman struct list_head *head = &desc->pg_list; 3843b609184SPeng Tao int ret = 0; 3851da177e4SLinus Torvalds 3864db6e0b7SFred Isaman data = nfs_readdata_alloc(hdr, nfs_page_array_len(desc->pg_base, 387c76069bdSFred Isaman desc->pg_count)); 3884db6e0b7SFred Isaman if (!data) { 389*061ae2edSFred Isaman desc->pg_completion_ops->error_cleanup(head); 3903b609184SPeng Tao ret = -ENOMEM; 391bae724efSFred Isaman goto out; 392bae724efSFred Isaman } 3931da177e4SLinus Torvalds 39430dd374fSFred Isaman pages = data->pages.pagevec; 3951da177e4SLinus Torvalds while (!list_empty(head)) { 3961da177e4SLinus Torvalds req = nfs_list_entry(head->next); 3971da177e4SLinus Torvalds nfs_list_remove_request(req); 3984db6e0b7SFred Isaman nfs_list_add_request(req, &hdr->pages); 3991da177e4SLinus Torvalds *pages++ = req->wb_page; 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 4024db6e0b7SFred Isaman nfs_read_rpcsetup(data, desc->pg_count, 0); 4034db6e0b7SFred Isaman list_add(&data->list, &hdr->rpc_list); 4044db6e0b7SFred Isaman desc->pg_rpc_callops = &nfs_read_common_ops; 405bae724efSFred Isaman out: 406dbae4c73STrond Myklebust return ret; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4094db6e0b7SFred Isaman int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, 4104db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 411493292ddSTrond Myklebust { 412493292ddSTrond Myklebust if (desc->pg_bsize < PAGE_CACHE_SIZE) 4134db6e0b7SFred Isaman return nfs_pagein_multi(desc, hdr); 4144db6e0b7SFred Isaman return nfs_pagein_one(desc, hdr); 415493292ddSTrond Myklebust } 416493292ddSTrond Myklebust 417493292ddSTrond Myklebust static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) 4181751c363STrond Myklebust { 4194db6e0b7SFred Isaman struct nfs_read_header *rhdr; 4204db6e0b7SFred Isaman struct nfs_pgio_header *hdr; 421275acaafSTrond Myklebust int ret; 422275acaafSTrond Myklebust 4234db6e0b7SFred Isaman rhdr = nfs_readhdr_alloc(); 4244db6e0b7SFred Isaman if (!rhdr) { 425*061ae2edSFred Isaman desc->pg_completion_ops->error_cleanup(&desc->pg_list); 4264db6e0b7SFred Isaman return -ENOMEM; 4274db6e0b7SFred Isaman } 4284db6e0b7SFred Isaman hdr = &rhdr->header; 4294db6e0b7SFred Isaman nfs_pgheader_init(desc, hdr, nfs_readhdr_free); 4304db6e0b7SFred Isaman atomic_inc(&hdr->refcnt); 4314db6e0b7SFred Isaman ret = nfs_generic_pagein(desc, hdr); 432275acaafSTrond Myklebust if (ret == 0) 4334db6e0b7SFred Isaman ret = nfs_do_multiple_reads(&hdr->rpc_list, 4344db6e0b7SFred Isaman desc->pg_rpc_callops); 4354db6e0b7SFred Isaman else 4364db6e0b7SFred Isaman set_bit(NFS_IOHDR_REDO, &hdr->flags); 4374db6e0b7SFred Isaman if (atomic_dec_and_test(&hdr->refcnt)) 438*061ae2edSFred Isaman hdr->completion_ops->completion(hdr); 439275acaafSTrond Myklebust return ret; 4401751c363STrond Myklebust } 4411751c363STrond Myklebust 4421751c363STrond Myklebust static const struct nfs_pageio_ops nfs_pageio_read_ops = { 4431751c363STrond Myklebust .pg_test = nfs_generic_pg_test, 4441751c363STrond Myklebust .pg_doio = nfs_generic_pg_readpages, 4451751c363STrond Myklebust }; 4461751c363STrond Myklebust 4471da177e4SLinus Torvalds /* 4480b671301STrond Myklebust * This is the callback from RPC telling us whether a reply was 4490b671301STrond Myklebust * received or some error occurred (timeout or socket shutdown). 4500b671301STrond Myklebust */ 4510b671301STrond Myklebust int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) 4520b671301STrond Myklebust { 453cd841605SFred Isaman struct inode *inode = data->header->inode; 4540b671301STrond Myklebust int status; 4550b671301STrond Myklebust 4563110ff80SHarvey Harrison dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid, 4570b671301STrond Myklebust task->tk_status); 4580b671301STrond Myklebust 459cd841605SFred Isaman status = NFS_PROTO(inode)->read_done(task, data); 4600b671301STrond Myklebust if (status != 0) 4610b671301STrond Myklebust return status; 4620b671301STrond Myklebust 463cd841605SFred Isaman nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count); 4640b671301STrond Myklebust 4650b671301STrond Myklebust if (task->tk_status == -ESTALE) { 466cd841605SFred Isaman set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); 467cd841605SFred Isaman nfs_mark_for_revalidate(inode); 4680b671301STrond Myklebust } 4690b671301STrond Myklebust return 0; 4700b671301STrond Myklebust } 4710b671301STrond Myklebust 472fdd1e74cSTrond Myklebust static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) 4730b671301STrond Myklebust { 4740b671301STrond Myklebust struct nfs_readargs *argp = &data->args; 4750b671301STrond Myklebust struct nfs_readres *resp = &data->res; 4760b671301STrond Myklebust 4770b671301STrond Myklebust /* This is a short read! */ 478cd841605SFred Isaman nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD); 4790b671301STrond Myklebust /* Has the server at least made some progress? */ 4804db6e0b7SFred Isaman if (resp->count == 0) { 4814db6e0b7SFred Isaman nfs_set_pgio_error(data->header, -EIO, argp->offset); 482d61e612aSTrond Myklebust return; 4834db6e0b7SFred Isaman } 4840b671301STrond Myklebust /* Yes, so retry the read at the end of the data */ 485cbdabc7fSAndy Adamson data->mds_offset += resp->count; 4860b671301STrond Myklebust argp->offset += resp->count; 4870b671301STrond Myklebust argp->pgbase += resp->count; 4880b671301STrond Myklebust argp->count -= resp->count; 489d00c5d43STrond Myklebust rpc_restart_call_prepare(task); 4900b671301STrond Myklebust } 4910b671301STrond Myklebust 4924db6e0b7SFred Isaman static void nfs_readpage_result_common(struct rpc_task *task, void *calldata) 4931da177e4SLinus Torvalds { 494ec06c096STrond Myklebust struct nfs_read_data *data = calldata; 4954db6e0b7SFred Isaman struct nfs_pgio_header *hdr = data->header; 4961da177e4SLinus Torvalds 4974db6e0b7SFred Isaman /* Note the only returns of nfs_readpage_result are 0 and -EAGAIN */ 498ec06c096STrond Myklebust if (nfs_readpage_result(task, data) != 0) 499ec06c096STrond Myklebust return; 500fdd1e74cSTrond Myklebust if (task->tk_status < 0) 5014db6e0b7SFred Isaman nfs_set_pgio_error(hdr, task->tk_status, data->args.offset); 5024db6e0b7SFred Isaman else if (data->res.eof) { 5034db6e0b7SFred Isaman loff_t bound; 504fdd1e74cSTrond Myklebust 5054db6e0b7SFred Isaman bound = data->args.offset + data->res.count; 5064db6e0b7SFred Isaman spin_lock(&hdr->lock); 5074db6e0b7SFred Isaman if (bound < hdr->io_start + hdr->good_bytes) { 5084db6e0b7SFred Isaman set_bit(NFS_IOHDR_EOF, &hdr->flags); 5094db6e0b7SFred Isaman clear_bit(NFS_IOHDR_ERROR, &hdr->flags); 5104db6e0b7SFred Isaman hdr->good_bytes = bound - hdr->io_start; 5114db6e0b7SFred Isaman } 5124db6e0b7SFred Isaman spin_unlock(&hdr->lock); 5134db6e0b7SFred Isaman } else if (data->res.count != data->args.count) 514fdd1e74cSTrond Myklebust nfs_readpage_retry(task, data); 5150b671301STrond Myklebust } 516fdd1e74cSTrond Myklebust 5174db6e0b7SFred Isaman static void nfs_readpage_release_common(void *calldata) 518fdd1e74cSTrond Myklebust { 5194db6e0b7SFred Isaman nfs_readdata_release(calldata); 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 522f11c88afSAndy Adamson void nfs_read_prepare(struct rpc_task *task, void *calldata) 523f11c88afSAndy Adamson { 524f11c88afSAndy Adamson struct nfs_read_data *data = calldata; 525cd841605SFred Isaman NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data); 526f11c88afSAndy Adamson } 527f11c88afSAndy Adamson 5284db6e0b7SFred Isaman static const struct rpc_call_ops nfs_read_common_ops = { 529f11c88afSAndy Adamson .rpc_call_prepare = nfs_read_prepare, 5304db6e0b7SFred Isaman .rpc_call_done = nfs_readpage_result_common, 5314db6e0b7SFred Isaman .rpc_release = nfs_readpage_release_common, 532ec06c096STrond Myklebust }; 533ec06c096STrond Myklebust 5341da177e4SLinus Torvalds /* 5351da177e4SLinus Torvalds * Read a page over NFS. 5361da177e4SLinus Torvalds * We read the page synchronously in the following case: 5371da177e4SLinus Torvalds * - The error flag is set for this page. This happens only when a 5381da177e4SLinus Torvalds * previous async read operation failed. 5391da177e4SLinus Torvalds */ 5401da177e4SLinus Torvalds int nfs_readpage(struct file *file, struct page *page) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds struct nfs_open_context *ctx; 5431da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5441da177e4SLinus Torvalds int error; 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", 5471da177e4SLinus Torvalds page, PAGE_CACHE_SIZE, page->index); 54891d5b470SChuck Lever nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); 54991d5b470SChuck Lever nfs_add_stats(inode, NFSIOS_READPAGES, 1); 55091d5b470SChuck Lever 5511da177e4SLinus Torvalds /* 5521da177e4SLinus Torvalds * Try to flush any pending writes to the file.. 5531da177e4SLinus Torvalds * 5541da177e4SLinus Torvalds * NOTE! Because we own the page lock, there cannot 5551da177e4SLinus Torvalds * be any new pending writes generated at this point 5561da177e4SLinus Torvalds * for this page (other pages can be written to). 5571da177e4SLinus Torvalds */ 5581da177e4SLinus Torvalds error = nfs_wb_page(inode, page); 5591da177e4SLinus Torvalds if (error) 560de05a0ccSTrond Myklebust goto out_unlock; 561de05a0ccSTrond Myklebust if (PageUptodate(page)) 562de05a0ccSTrond Myklebust goto out_unlock; 5631da177e4SLinus Torvalds 5645f004cf2STrond Myklebust error = -ESTALE; 5655f004cf2STrond Myklebust if (NFS_STALE(inode)) 566de05a0ccSTrond Myklebust goto out_unlock; 5675f004cf2STrond Myklebust 5681da177e4SLinus Torvalds if (file == NULL) { 569cf1308ffSTrond Myklebust error = -EBADF; 570d530838bSTrond Myklebust ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 5711da177e4SLinus Torvalds if (ctx == NULL) 572de05a0ccSTrond Myklebust goto out_unlock; 5731da177e4SLinus Torvalds } else 574cd3758e3STrond Myklebust ctx = get_nfs_open_context(nfs_file_open_context(file)); 5751da177e4SLinus Torvalds 5769a9fc1c0SDavid Howells if (!IS_SYNC(inode)) { 5779a9fc1c0SDavid Howells error = nfs_readpage_from_fscache(ctx, inode, page); 5789a9fc1c0SDavid Howells if (error == 0) 5799a9fc1c0SDavid Howells goto out; 5809a9fc1c0SDavid Howells } 5819a9fc1c0SDavid Howells 5828e0969f0STrond Myklebust error = nfs_readpage_async(ctx, inode, page); 5838e0969f0STrond Myklebust 5849a9fc1c0SDavid Howells out: 5851da177e4SLinus Torvalds put_nfs_open_context(ctx); 5861da177e4SLinus Torvalds return error; 587de05a0ccSTrond Myklebust out_unlock: 5881da177e4SLinus Torvalds unlock_page(page); 5891da177e4SLinus Torvalds return error; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds struct nfs_readdesc { 5938b09bee3STrond Myklebust struct nfs_pageio_descriptor *pgio; 5941da177e4SLinus Torvalds struct nfs_open_context *ctx; 5951da177e4SLinus Torvalds }; 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds static int 5981da177e4SLinus Torvalds readpage_async_filler(void *data, struct page *page) 5991da177e4SLinus Torvalds { 6001da177e4SLinus Torvalds struct nfs_readdesc *desc = (struct nfs_readdesc *)data; 6011da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 6021da177e4SLinus Torvalds struct nfs_page *new; 6031da177e4SLinus Torvalds unsigned int len; 604de05a0ccSTrond Myklebust int error; 6051da177e4SLinus Torvalds 60649a70f27STrond Myklebust len = nfs_page_length(page); 6071da177e4SLinus Torvalds if (len == 0) 6081da177e4SLinus Torvalds return nfs_return_empty_page(page); 609de05a0ccSTrond Myklebust 6101da177e4SLinus Torvalds new = nfs_create_request(desc->ctx, inode, page, 0, len); 611de05a0ccSTrond Myklebust if (IS_ERR(new)) 612de05a0ccSTrond Myklebust goto out_error; 613de05a0ccSTrond Myklebust 6141da177e4SLinus Torvalds if (len < PAGE_CACHE_SIZE) 615eebd2aa3SChristoph Lameter zero_user_segment(page, len, PAGE_CACHE_SIZE); 616f8512ad0SFred Isaman if (!nfs_pageio_add_request(desc->pgio, new)) { 617f8512ad0SFred Isaman error = desc->pgio->pg_error; 618f8512ad0SFred Isaman goto out_unlock; 619f8512ad0SFred Isaman } 6201da177e4SLinus Torvalds return 0; 621de05a0ccSTrond Myklebust out_error: 622de05a0ccSTrond Myklebust error = PTR_ERR(new); 623de05a0ccSTrond Myklebust out_unlock: 624de05a0ccSTrond Myklebust unlock_page(page); 625de05a0ccSTrond Myklebust return error; 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds int nfs_readpages(struct file *filp, struct address_space *mapping, 6291da177e4SLinus Torvalds struct list_head *pages, unsigned nr_pages) 6301da177e4SLinus Torvalds { 6318b09bee3STrond Myklebust struct nfs_pageio_descriptor pgio; 6321da177e4SLinus Torvalds struct nfs_readdesc desc = { 6338b09bee3STrond Myklebust .pgio = &pgio, 6341da177e4SLinus Torvalds }; 6351da177e4SLinus Torvalds struct inode *inode = mapping->host; 6368b09bee3STrond Myklebust unsigned long npages; 6375f004cf2STrond Myklebust int ret = -ESTALE; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", 6401da177e4SLinus Torvalds inode->i_sb->s_id, 6411da177e4SLinus Torvalds (long long)NFS_FILEID(inode), 6421da177e4SLinus Torvalds nr_pages); 64391d5b470SChuck Lever nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); 6441da177e4SLinus Torvalds 6455f004cf2STrond Myklebust if (NFS_STALE(inode)) 6465f004cf2STrond Myklebust goto out; 6475f004cf2STrond Myklebust 6481da177e4SLinus Torvalds if (filp == NULL) { 649d530838bSTrond Myklebust desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 6501da177e4SLinus Torvalds if (desc.ctx == NULL) 6511da177e4SLinus Torvalds return -EBADF; 6521da177e4SLinus Torvalds } else 653cd3758e3STrond Myklebust desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); 6549a9fc1c0SDavid Howells 6559a9fc1c0SDavid Howells /* attempt to read as many of the pages as possible from the cache 6569a9fc1c0SDavid Howells * - this returns -ENOBUFS immediately if the cookie is negative 6579a9fc1c0SDavid Howells */ 6589a9fc1c0SDavid Howells ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping, 6599a9fc1c0SDavid Howells pages, &nr_pages); 6609a9fc1c0SDavid Howells if (ret == 0) 6619a9fc1c0SDavid Howells goto read_complete; /* all pages were read */ 6629a9fc1c0SDavid Howells 663*061ae2edSFred Isaman nfs_pageio_init_read(&pgio, inode, &nfs_async_read_completion_ops); 6648b09bee3STrond Myklebust 6651da177e4SLinus Torvalds ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); 6668b09bee3STrond Myklebust 6678b09bee3STrond Myklebust nfs_pageio_complete(&pgio); 6688b09bee3STrond Myklebust npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 6698b09bee3STrond Myklebust nfs_add_stats(inode, NFSIOS_READPAGES, npages); 6709a9fc1c0SDavid Howells read_complete: 6711da177e4SLinus Torvalds put_nfs_open_context(desc.ctx); 6725f004cf2STrond Myklebust out: 6731da177e4SLinus Torvalds return ret; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 676f7b422b1SDavid Howells int __init nfs_init_readpagecache(void) 6771da177e4SLinus Torvalds { 6781da177e4SLinus Torvalds nfs_rdata_cachep = kmem_cache_create("nfs_read_data", 679cd841605SFred Isaman sizeof(struct nfs_read_header), 6801da177e4SLinus Torvalds 0, SLAB_HWCACHE_ALIGN, 68120c2df83SPaul Mundt NULL); 6821da177e4SLinus Torvalds if (nfs_rdata_cachep == NULL) 6831da177e4SLinus Torvalds return -ENOMEM; 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds return 0; 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 688266bee88SDavid Brownell void nfs_destroy_readpagecache(void) 6891da177e4SLinus Torvalds { 6901a1d92c1SAlexey Dobriyan kmem_cache_destroy(nfs_rdata_cachep); 6911da177e4SLinus Torvalds } 692