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 23f11c88afSAndy Adamson #include "nfs4_fs.h" 2449a70f27STrond Myklebust #include "internal.h" 2591d5b470SChuck Lever #include "iostat.h" 269a9fc1c0SDavid Howells #include "fscache.h" 2791d5b470SChuck Lever 281da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_PAGECACHE 291da177e4SLinus Torvalds 301751c363STrond Myklebust static const struct nfs_pageio_ops nfs_pageio_read_ops; 314db6e0b7SFred Isaman static const struct rpc_call_ops nfs_read_common_ops; 32061ae2edSFred Isaman static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops; 331da177e4SLinus Torvalds 34e18b890bSChristoph Lameter static struct kmem_cache *nfs_rdata_cachep; 351da177e4SLinus Torvalds 361385b811STrond Myklebust struct nfs_read_header *nfs_readhdr_alloc(void) 373feb2d49STrond Myklebust { 384db6e0b7SFred Isaman struct nfs_read_header *rhdr; 393feb2d49STrond Myklebust 404db6e0b7SFred Isaman rhdr = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); 414db6e0b7SFred Isaman if (rhdr) { 424db6e0b7SFred Isaman struct nfs_pgio_header *hdr = &rhdr->header; 43cd841605SFred Isaman 44cd841605SFred Isaman INIT_LIST_HEAD(&hdr->pages); 454db6e0b7SFred Isaman INIT_LIST_HEAD(&hdr->rpc_list); 464db6e0b7SFred Isaman spin_lock_init(&hdr->lock); 474db6e0b7SFred Isaman atomic_set(&hdr->refcnt, 0); 484db6e0b7SFred Isaman } 494db6e0b7SFred Isaman return rhdr; 504db6e0b7SFred Isaman } 514db6e0b7SFred Isaman 52584aa810SFred Isaman static struct nfs_read_data *nfs_readdata_alloc(struct nfs_pgio_header *hdr, 534db6e0b7SFred Isaman unsigned int pagecount) 544db6e0b7SFred Isaman { 554db6e0b7SFred Isaman struct nfs_read_data *data, *prealloc; 564db6e0b7SFred Isaman 574db6e0b7SFred Isaman prealloc = &container_of(hdr, struct nfs_read_header, header)->rpc_data; 584db6e0b7SFred Isaman if (prealloc->header == NULL) 594db6e0b7SFred Isaman data = prealloc; 604db6e0b7SFred Isaman else 614db6e0b7SFred Isaman data = kzalloc(sizeof(*data), GFP_KERNEL); 624db6e0b7SFred Isaman if (!data) 634db6e0b7SFred Isaman goto out; 644db6e0b7SFred Isaman 654db6e0b7SFred Isaman if (nfs_pgarray_set(&data->pages, pagecount)) { 66cd841605SFred Isaman data->header = hdr; 674db6e0b7SFred Isaman atomic_inc(&hdr->refcnt); 684db6e0b7SFred Isaman } else { 694db6e0b7SFred Isaman if (data != prealloc) 704db6e0b7SFred Isaman kfree(data); 714db6e0b7SFred Isaman data = NULL; 723feb2d49STrond Myklebust } 734db6e0b7SFred Isaman out: 744db6e0b7SFred Isaman return data; 753feb2d49STrond Myklebust } 763feb2d49STrond Myklebust 77cd841605SFred Isaman void nfs_readhdr_free(struct nfs_pgio_header *hdr) 783feb2d49STrond Myklebust { 79cd841605SFred Isaman struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header); 80cd841605SFred Isaman 81cd841605SFred Isaman kmem_cache_free(nfs_rdata_cachep, rhdr); 823feb2d49STrond Myklebust } 833feb2d49STrond Myklebust 84493292ddSTrond Myklebust void nfs_readdata_release(struct nfs_read_data *rdata) 851da177e4SLinus Torvalds { 864db6e0b7SFred Isaman struct nfs_pgio_header *hdr = rdata->header; 874db6e0b7SFred Isaman struct nfs_read_header *read_header = container_of(hdr, struct nfs_read_header, header); 884db6e0b7SFred Isaman 89383ba719STrond Myklebust put_nfs_open_context(rdata->args.context); 9030dd374fSFred Isaman if (rdata->pages.pagevec != rdata->pages.page_array) 9130dd374fSFred Isaman kfree(rdata->pages.pagevec); 924db6e0b7SFred Isaman if (rdata != &read_header->rpc_data) 934db6e0b7SFred Isaman kfree(rdata); 944db6e0b7SFred Isaman else 954db6e0b7SFred Isaman rdata->header = NULL; 964db6e0b7SFred Isaman if (atomic_dec_and_test(&hdr->refcnt)) 97061ae2edSFred Isaman hdr->completion_ops->completion(hdr); 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds static 1011da177e4SLinus Torvalds int nfs_return_empty_page(struct page *page) 1021da177e4SLinus Torvalds { 103eebd2aa3SChristoph Lameter zero_user(page, 0, PAGE_CACHE_SIZE); 1041da177e4SLinus Torvalds SetPageUptodate(page); 1051da177e4SLinus Torvalds unlock_page(page); 1061da177e4SLinus Torvalds return 0; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091abb5088SBryan Schumaker void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, 110061ae2edSFred Isaman struct inode *inode, 111061ae2edSFred Isaman const struct nfs_pgio_completion_ops *compl_ops) 1121751c363STrond Myklebust { 113061ae2edSFred Isaman nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, compl_ops, 1141751c363STrond Myklebust NFS_SERVER(inode)->rsize, 0); 1151751c363STrond Myklebust } 116*ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_pageio_init_read); 1171751c363STrond Myklebust 118493292ddSTrond Myklebust void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) 119493292ddSTrond Myklebust { 120493292ddSTrond Myklebust pgio->pg_ops = &nfs_pageio_read_ops; 121493292ddSTrond Myklebust pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; 122493292ddSTrond Myklebust } 1231f945357STrond Myklebust EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); 124493292ddSTrond Myklebust 125f42b293dSDavid Howells int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, 1261da177e4SLinus Torvalds struct page *page) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct nfs_page *new; 1291da177e4SLinus Torvalds unsigned int len; 130c76069bdSFred Isaman struct nfs_pageio_descriptor pgio; 1311da177e4SLinus Torvalds 13249a70f27STrond Myklebust len = nfs_page_length(page); 1331da177e4SLinus Torvalds if (len == 0) 1341da177e4SLinus Torvalds return nfs_return_empty_page(page); 1351da177e4SLinus Torvalds new = nfs_create_request(ctx, inode, page, 0, len); 1361da177e4SLinus Torvalds if (IS_ERR(new)) { 1371da177e4SLinus Torvalds unlock_page(page); 1381da177e4SLinus Torvalds return PTR_ERR(new); 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds if (len < PAGE_CACHE_SIZE) 141eebd2aa3SChristoph Lameter zero_user_segment(page, len, PAGE_CACHE_SIZE); 1421da177e4SLinus Torvalds 1431abb5088SBryan Schumaker NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops); 144d8007d4dSTrond Myklebust nfs_pageio_add_request(&pgio, new); 1451751c363STrond Myklebust nfs_pageio_complete(&pgio); 1462701d086SAndy Adamson NFS_I(inode)->read_io += pgio.pg_bytes_written; 1471da177e4SLinus Torvalds return 0; 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds static void nfs_readpage_release(struct nfs_page *req) 1511da177e4SLinus Torvalds { 1523d4ff43dSAl Viro struct inode *d_inode = req->wb_context->dentry->d_inode; 1537f8e05f6SDavid Howells 1547f8e05f6SDavid Howells if (PageUptodate(req->wb_page)) 1557f8e05f6SDavid Howells nfs_readpage_to_fscache(d_inode, req->wb_page, 0); 1567f8e05f6SDavid Howells 1571da177e4SLinus Torvalds unlock_page(req->wb_page); 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", 1603d4ff43dSAl Viro req->wb_context->dentry->d_inode->i_sb->s_id, 1613d4ff43dSAl Viro (long long)NFS_FILEID(req->wb_context->dentry->d_inode), 1621da177e4SLinus Torvalds req->wb_bytes, 1631da177e4SLinus Torvalds (long long)req_offset(req)); 16410d2c46fSNick Wilson nfs_release_request(req); 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 1674db6e0b7SFred Isaman /* Note io was page aligned */ 168061ae2edSFred Isaman static void nfs_read_completion(struct nfs_pgio_header *hdr) 1694db6e0b7SFred Isaman { 1704db6e0b7SFred Isaman unsigned long bytes = 0; 1714db6e0b7SFred Isaman 1724db6e0b7SFred Isaman if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) 1734db6e0b7SFred Isaman goto out; 1744db6e0b7SFred Isaman while (!list_empty(&hdr->pages)) { 1754db6e0b7SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 1764db6e0b7SFred Isaman struct page *page = req->wb_page; 1774db6e0b7SFred Isaman 1784db6e0b7SFred Isaman if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) { 1794db6e0b7SFred Isaman if (bytes > hdr->good_bytes) 1804db6e0b7SFred Isaman zero_user(page, 0, PAGE_SIZE); 1814db6e0b7SFred Isaman else if (hdr->good_bytes - bytes < PAGE_SIZE) 1824db6e0b7SFred Isaman zero_user_segment(page, 1834db6e0b7SFred Isaman hdr->good_bytes & ~PAGE_MASK, 1844db6e0b7SFred Isaman PAGE_SIZE); 1854db6e0b7SFred Isaman } 1864bd8b010STrond Myklebust bytes += req->wb_bytes; 1874bd8b010STrond Myklebust if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { 1884bd8b010STrond Myklebust if (bytes <= hdr->good_bytes) 1894bd8b010STrond Myklebust SetPageUptodate(page); 1904bd8b010STrond Myklebust } else 1914db6e0b7SFred Isaman SetPageUptodate(page); 1924db6e0b7SFred Isaman nfs_list_remove_request(req); 1934db6e0b7SFred Isaman nfs_readpage_release(req); 1944db6e0b7SFred Isaman } 1954db6e0b7SFred Isaman out: 1964db6e0b7SFred Isaman hdr->release(hdr); 1974db6e0b7SFred Isaman } 1984db6e0b7SFred Isaman 199c5996c4eSFred Isaman int nfs_initiate_read(struct rpc_clnt *clnt, 200c5996c4eSFred Isaman struct nfs_read_data *data, 2019f0ec176SAndy Adamson const struct rpc_call_ops *call_ops, int flags) 20264419a9bSAndy Adamson { 203cd841605SFred Isaman struct inode *inode = data->header->inode; 20464419a9bSAndy Adamson int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; 20564419a9bSAndy Adamson struct rpc_task *task; 20664419a9bSAndy Adamson struct rpc_message msg = { 20764419a9bSAndy Adamson .rpc_argp = &data->args, 20864419a9bSAndy Adamson .rpc_resp = &data->res, 209cd841605SFred Isaman .rpc_cred = data->header->cred, 21064419a9bSAndy Adamson }; 21164419a9bSAndy Adamson struct rpc_task_setup task_setup_data = { 21264419a9bSAndy Adamson .task = &data->task, 21364419a9bSAndy Adamson .rpc_client = clnt, 21464419a9bSAndy Adamson .rpc_message = &msg, 21564419a9bSAndy Adamson .callback_ops = call_ops, 21664419a9bSAndy Adamson .callback_data = data, 21764419a9bSAndy Adamson .workqueue = nfsiod_workqueue, 2189f0ec176SAndy Adamson .flags = RPC_TASK_ASYNC | swap_flags | flags, 21964419a9bSAndy Adamson }; 22064419a9bSAndy Adamson 22164419a9bSAndy Adamson /* Set up the initial task struct. */ 22264419a9bSAndy Adamson NFS_PROTO(inode)->read_setup(data, &msg); 22364419a9bSAndy Adamson 22464419a9bSAndy Adamson dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ " 22564419a9bSAndy Adamson "offset %llu)\n", 22664419a9bSAndy Adamson data->task.tk_pid, 22764419a9bSAndy Adamson inode->i_sb->s_id, 22864419a9bSAndy Adamson (long long)NFS_FILEID(inode), 22964419a9bSAndy Adamson data->args.count, 23064419a9bSAndy Adamson (unsigned long long)data->args.offset); 23164419a9bSAndy Adamson 23264419a9bSAndy Adamson task = rpc_run_task(&task_setup_data); 23364419a9bSAndy Adamson if (IS_ERR(task)) 23464419a9bSAndy Adamson return PTR_ERR(task); 23564419a9bSAndy Adamson rpc_put_task(task); 23664419a9bSAndy Adamson return 0; 23764419a9bSAndy Adamson } 238dc70d7b3SAndy Adamson EXPORT_SYMBOL_GPL(nfs_initiate_read); 23964419a9bSAndy Adamson 2401da177e4SLinus Torvalds /* 2411da177e4SLinus Torvalds * Set up the NFS read request struct 2421da177e4SLinus Torvalds */ 2434db6e0b7SFred Isaman static void nfs_read_rpcsetup(struct nfs_read_data *data, 2446e4efd56STrond Myklebust unsigned int count, unsigned int offset) 2451da177e4SLinus Torvalds { 2464db6e0b7SFred Isaman struct nfs_page *req = data->header->req; 2471da177e4SLinus Torvalds 2484db6e0b7SFred Isaman data->args.fh = NFS_FH(data->header->inode); 2491da177e4SLinus Torvalds data->args.offset = req_offset(req) + offset; 2501da177e4SLinus Torvalds data->args.pgbase = req->wb_pgbase + offset; 25130dd374fSFred Isaman data->args.pages = data->pages.pagevec; 2521da177e4SLinus Torvalds data->args.count = count; 253383ba719STrond Myklebust data->args.context = get_nfs_open_context(req->wb_context); 254f11ac8dbSTrond Myklebust data->args.lock_context = req->wb_lock_context; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds data->res.fattr = &data->fattr; 2571da177e4SLinus Torvalds data->res.count = count; 2581da177e4SLinus Torvalds data->res.eof = 0; 2590e574af1STrond Myklebust nfs_fattr_init(&data->fattr); 2606e4efd56STrond Myklebust } 2611da177e4SLinus Torvalds 2626e4efd56STrond Myklebust static int nfs_do_read(struct nfs_read_data *data, 263493292ddSTrond Myklebust const struct rpc_call_ops *call_ops) 2646e4efd56STrond Myklebust { 265cd841605SFred Isaman struct inode *inode = data->header->inode; 2666e4efd56STrond Myklebust 2679f0ec176SAndy Adamson return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops, 0); 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 270275acaafSTrond Myklebust static int 271275acaafSTrond Myklebust nfs_do_multiple_reads(struct list_head *head, 272493292ddSTrond Myklebust const struct rpc_call_ops *call_ops) 273275acaafSTrond Myklebust { 274275acaafSTrond Myklebust struct nfs_read_data *data; 275275acaafSTrond Myklebust int ret = 0; 276275acaafSTrond Myklebust 277275acaafSTrond Myklebust while (!list_empty(head)) { 278275acaafSTrond Myklebust int ret2; 279275acaafSTrond Myklebust 2804db6e0b7SFred Isaman data = list_first_entry(head, struct nfs_read_data, list); 281275acaafSTrond Myklebust list_del_init(&data->list); 282275acaafSTrond Myklebust 283493292ddSTrond Myklebust ret2 = nfs_do_read(data, call_ops); 284275acaafSTrond Myklebust if (ret == 0) 285275acaafSTrond Myklebust ret = ret2; 286275acaafSTrond Myklebust } 287275acaafSTrond Myklebust return ret; 288275acaafSTrond Myklebust } 289275acaafSTrond Myklebust 290061ae2edSFred Isaman static void 2911da177e4SLinus Torvalds nfs_async_read_error(struct list_head *head) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds struct nfs_page *req; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds while (!list_empty(head)) { 2961da177e4SLinus Torvalds req = nfs_list_entry(head->next); 2971da177e4SLinus Torvalds nfs_list_remove_request(req); 2981da177e4SLinus Torvalds nfs_readpage_release(req); 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 302061ae2edSFred Isaman static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = { 303061ae2edSFred Isaman .error_cleanup = nfs_async_read_error, 304061ae2edSFred Isaman .completion = nfs_read_completion, 305061ae2edSFred Isaman }; 306061ae2edSFred Isaman 30725b11dcdSTrond Myklebust static void nfs_pagein_error(struct nfs_pageio_descriptor *desc, 30825b11dcdSTrond Myklebust struct nfs_pgio_header *hdr) 30925b11dcdSTrond Myklebust { 31025b11dcdSTrond Myklebust set_bit(NFS_IOHDR_REDO, &hdr->flags); 31125b11dcdSTrond Myklebust while (!list_empty(&hdr->rpc_list)) { 31225b11dcdSTrond Myklebust struct nfs_read_data *data = list_first_entry(&hdr->rpc_list, 31325b11dcdSTrond Myklebust struct nfs_read_data, list); 31425b11dcdSTrond Myklebust list_del(&data->list); 31525b11dcdSTrond Myklebust nfs_readdata_release(data); 31625b11dcdSTrond Myklebust } 31725b11dcdSTrond Myklebust desc->pg_completion_ops->error_cleanup(&desc->pg_list); 31825b11dcdSTrond Myklebust } 31925b11dcdSTrond Myklebust 3201da177e4SLinus Torvalds /* 3211da177e4SLinus Torvalds * Generate multiple requests to fill a single page. 3221da177e4SLinus Torvalds * 3231da177e4SLinus Torvalds * We optimize to reduce the number of read operations on the wire. If we 3241da177e4SLinus Torvalds * detect that we're reading a page, or an area of a page, that is past the 3251da177e4SLinus Torvalds * end of file, we do not generate NFS read operations but just clear the 3261da177e4SLinus Torvalds * parts of the page that would have come back zero from the server anyway. 3271da177e4SLinus Torvalds * 3281da177e4SLinus Torvalds * We rely on the cached value of i_size to make this determination; another 3291da177e4SLinus Torvalds * client can fill pages on the server past our cached end-of-file, but we 3301da177e4SLinus Torvalds * won't see the new data until our attribute cache is updated. This is more 3311da177e4SLinus Torvalds * or less conventional NFS client behavior. 3321da177e4SLinus Torvalds */ 3334db6e0b7SFred Isaman static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, 3344db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 3351da177e4SLinus Torvalds { 3364db6e0b7SFred Isaman struct nfs_page *req = hdr->req; 3371da177e4SLinus Torvalds struct page *page = req->wb_page; 3381da177e4SLinus Torvalds struct nfs_read_data *data; 339d097971dSTrond Myklebust size_t rsize = desc->pg_bsize, nbytes; 340e9f7bee1STrond Myklebust unsigned int offset; 3411da177e4SLinus Torvalds 342275acaafSTrond Myklebust offset = 0; 343c76069bdSFred Isaman nbytes = desc->pg_count; 344e9f7bee1STrond Myklebust do { 345e9f7bee1STrond Myklebust size_t len = min(nbytes,rsize); 346e9f7bee1STrond Myklebust 3474db6e0b7SFred Isaman data = nfs_readdata_alloc(hdr, 1); 34825b11dcdSTrond Myklebust if (!data) { 34925b11dcdSTrond Myklebust nfs_pagein_error(desc, hdr); 35025b11dcdSTrond Myklebust return -ENOMEM; 35125b11dcdSTrond Myklebust } 35230dd374fSFred Isaman data->pages.pagevec[0] = page; 3534db6e0b7SFred Isaman nfs_read_rpcsetup(data, len, offset); 3544db6e0b7SFred Isaman list_add(&data->list, &hdr->rpc_list); 355e9f7bee1STrond Myklebust nbytes -= len; 356275acaafSTrond Myklebust offset += len; 357e9f7bee1STrond Myklebust } while (nbytes != 0); 35825b11dcdSTrond Myklebust 35925b11dcdSTrond Myklebust nfs_list_remove_request(req); 36025b11dcdSTrond Myklebust nfs_list_add_request(req, &hdr->pages); 3614db6e0b7SFred Isaman desc->pg_rpc_callops = &nfs_read_common_ops; 3629146ab50STrond Myklebust return 0; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds 3654db6e0b7SFred Isaman static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, 3664db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 3671da177e4SLinus Torvalds { 3681da177e4SLinus Torvalds struct nfs_page *req; 3691da177e4SLinus Torvalds struct page **pages; 3701da177e4SLinus Torvalds struct nfs_read_data *data; 371c76069bdSFred Isaman struct list_head *head = &desc->pg_list; 3721da177e4SLinus Torvalds 3734db6e0b7SFred Isaman data = nfs_readdata_alloc(hdr, nfs_page_array_len(desc->pg_base, 374c76069bdSFred Isaman desc->pg_count)); 3754db6e0b7SFred Isaman if (!data) { 37625b11dcdSTrond Myklebust nfs_pagein_error(desc, hdr); 3779146ab50STrond Myklebust return -ENOMEM; 378bae724efSFred Isaman } 3791da177e4SLinus Torvalds 38030dd374fSFred Isaman pages = data->pages.pagevec; 3811da177e4SLinus Torvalds while (!list_empty(head)) { 3821da177e4SLinus Torvalds req = nfs_list_entry(head->next); 3831da177e4SLinus Torvalds nfs_list_remove_request(req); 3844db6e0b7SFred Isaman nfs_list_add_request(req, &hdr->pages); 3851da177e4SLinus Torvalds *pages++ = req->wb_page; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3884db6e0b7SFred Isaman nfs_read_rpcsetup(data, desc->pg_count, 0); 3894db6e0b7SFred Isaman list_add(&data->list, &hdr->rpc_list); 3904db6e0b7SFred Isaman desc->pg_rpc_callops = &nfs_read_common_ops; 3919146ab50STrond Myklebust return 0; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3944db6e0b7SFred Isaman int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, 3954db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 396493292ddSTrond Myklebust { 397493292ddSTrond Myklebust if (desc->pg_bsize < PAGE_CACHE_SIZE) 3984db6e0b7SFred Isaman return nfs_pagein_multi(desc, hdr); 3994db6e0b7SFred Isaman return nfs_pagein_one(desc, hdr); 400493292ddSTrond Myklebust } 401493292ddSTrond Myklebust 402493292ddSTrond Myklebust static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) 4031751c363STrond Myklebust { 4044db6e0b7SFred Isaman struct nfs_read_header *rhdr; 4054db6e0b7SFred Isaman struct nfs_pgio_header *hdr; 406275acaafSTrond Myklebust int ret; 407275acaafSTrond Myklebust 4084db6e0b7SFred Isaman rhdr = nfs_readhdr_alloc(); 4094db6e0b7SFred Isaman if (!rhdr) { 410061ae2edSFred Isaman desc->pg_completion_ops->error_cleanup(&desc->pg_list); 4114db6e0b7SFred Isaman return -ENOMEM; 4124db6e0b7SFred Isaman } 4134db6e0b7SFred Isaman hdr = &rhdr->header; 4144db6e0b7SFred Isaman nfs_pgheader_init(desc, hdr, nfs_readhdr_free); 4154db6e0b7SFred Isaman atomic_inc(&hdr->refcnt); 4164db6e0b7SFred Isaman ret = nfs_generic_pagein(desc, hdr); 417275acaafSTrond Myklebust if (ret == 0) 4184db6e0b7SFred Isaman ret = nfs_do_multiple_reads(&hdr->rpc_list, 4194db6e0b7SFred Isaman desc->pg_rpc_callops); 4204db6e0b7SFred Isaman if (atomic_dec_and_test(&hdr->refcnt)) 421061ae2edSFred Isaman hdr->completion_ops->completion(hdr); 422275acaafSTrond Myklebust return ret; 4231751c363STrond Myklebust } 4241751c363STrond Myklebust 4251751c363STrond Myklebust static const struct nfs_pageio_ops nfs_pageio_read_ops = { 4261751c363STrond Myklebust .pg_test = nfs_generic_pg_test, 4271751c363STrond Myklebust .pg_doio = nfs_generic_pg_readpages, 4281751c363STrond Myklebust }; 4291751c363STrond Myklebust 4301da177e4SLinus Torvalds /* 4310b671301STrond Myklebust * This is the callback from RPC telling us whether a reply was 4320b671301STrond Myklebust * received or some error occurred (timeout or socket shutdown). 4330b671301STrond Myklebust */ 4340b671301STrond Myklebust int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) 4350b671301STrond Myklebust { 436cd841605SFred Isaman struct inode *inode = data->header->inode; 4370b671301STrond Myklebust int status; 4380b671301STrond Myklebust 4393110ff80SHarvey Harrison dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid, 4400b671301STrond Myklebust task->tk_status); 4410b671301STrond Myklebust 442cd841605SFred Isaman status = NFS_PROTO(inode)->read_done(task, data); 4430b671301STrond Myklebust if (status != 0) 4440b671301STrond Myklebust return status; 4450b671301STrond Myklebust 446cd841605SFred Isaman nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count); 4470b671301STrond Myklebust 4480b671301STrond Myklebust if (task->tk_status == -ESTALE) { 449cd841605SFred Isaman set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); 450cd841605SFred Isaman nfs_mark_for_revalidate(inode); 4510b671301STrond Myklebust } 4520b671301STrond Myklebust return 0; 4530b671301STrond Myklebust } 4540b671301STrond Myklebust 455fdd1e74cSTrond Myklebust static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) 4560b671301STrond Myklebust { 4570b671301STrond Myklebust struct nfs_readargs *argp = &data->args; 4580b671301STrond Myklebust struct nfs_readres *resp = &data->res; 4590b671301STrond Myklebust 4600b671301STrond Myklebust /* This is a short read! */ 461cd841605SFred Isaman nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD); 4620b671301STrond Myklebust /* Has the server at least made some progress? */ 4634db6e0b7SFred Isaman if (resp->count == 0) { 4644db6e0b7SFred Isaman nfs_set_pgio_error(data->header, -EIO, argp->offset); 465d61e612aSTrond Myklebust return; 4664db6e0b7SFred Isaman } 4670b671301STrond Myklebust /* Yes, so retry the read at the end of the data */ 468cbdabc7fSAndy Adamson data->mds_offset += resp->count; 4690b671301STrond Myklebust argp->offset += resp->count; 4700b671301STrond Myklebust argp->pgbase += resp->count; 4710b671301STrond Myklebust argp->count -= resp->count; 472d00c5d43STrond Myklebust rpc_restart_call_prepare(task); 4730b671301STrond Myklebust } 4740b671301STrond Myklebust 4754db6e0b7SFred Isaman static void nfs_readpage_result_common(struct rpc_task *task, void *calldata) 4761da177e4SLinus Torvalds { 477ec06c096STrond Myklebust struct nfs_read_data *data = calldata; 4784db6e0b7SFred Isaman struct nfs_pgio_header *hdr = data->header; 4791da177e4SLinus Torvalds 4804db6e0b7SFred Isaman /* Note the only returns of nfs_readpage_result are 0 and -EAGAIN */ 481ec06c096STrond Myklebust if (nfs_readpage_result(task, data) != 0) 482ec06c096STrond Myklebust return; 483fdd1e74cSTrond Myklebust if (task->tk_status < 0) 4844db6e0b7SFred Isaman nfs_set_pgio_error(hdr, task->tk_status, data->args.offset); 4854db6e0b7SFred Isaman else if (data->res.eof) { 4864db6e0b7SFred Isaman loff_t bound; 487fdd1e74cSTrond Myklebust 4884db6e0b7SFred Isaman bound = data->args.offset + data->res.count; 4894db6e0b7SFred Isaman spin_lock(&hdr->lock); 4904db6e0b7SFred Isaman if (bound < hdr->io_start + hdr->good_bytes) { 4914db6e0b7SFred Isaman set_bit(NFS_IOHDR_EOF, &hdr->flags); 4924db6e0b7SFred Isaman clear_bit(NFS_IOHDR_ERROR, &hdr->flags); 4934db6e0b7SFred Isaman hdr->good_bytes = bound - hdr->io_start; 4944db6e0b7SFred Isaman } 4954db6e0b7SFred Isaman spin_unlock(&hdr->lock); 4964db6e0b7SFred Isaman } else if (data->res.count != data->args.count) 497fdd1e74cSTrond Myklebust nfs_readpage_retry(task, data); 4980b671301STrond Myklebust } 499fdd1e74cSTrond Myklebust 5004db6e0b7SFred Isaman static void nfs_readpage_release_common(void *calldata) 501fdd1e74cSTrond Myklebust { 5024db6e0b7SFred Isaman nfs_readdata_release(calldata); 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 505f11c88afSAndy Adamson void nfs_read_prepare(struct rpc_task *task, void *calldata) 506f11c88afSAndy Adamson { 507f11c88afSAndy Adamson struct nfs_read_data *data = calldata; 508cd841605SFred Isaman NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data); 509f11c88afSAndy Adamson } 510f11c88afSAndy Adamson 5114db6e0b7SFred Isaman static const struct rpc_call_ops nfs_read_common_ops = { 512f11c88afSAndy Adamson .rpc_call_prepare = nfs_read_prepare, 5134db6e0b7SFred Isaman .rpc_call_done = nfs_readpage_result_common, 5144db6e0b7SFred Isaman .rpc_release = nfs_readpage_release_common, 515ec06c096STrond Myklebust }; 516ec06c096STrond Myklebust 5171da177e4SLinus Torvalds /* 5181da177e4SLinus Torvalds * Read a page over NFS. 5191da177e4SLinus Torvalds * We read the page synchronously in the following case: 5201da177e4SLinus Torvalds * - The error flag is set for this page. This happens only when a 5211da177e4SLinus Torvalds * previous async read operation failed. 5221da177e4SLinus Torvalds */ 5231da177e4SLinus Torvalds int nfs_readpage(struct file *file, struct page *page) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds struct nfs_open_context *ctx; 5261da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5271da177e4SLinus Torvalds int error; 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", 5301da177e4SLinus Torvalds page, PAGE_CACHE_SIZE, page->index); 53191d5b470SChuck Lever nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); 53291d5b470SChuck Lever nfs_add_stats(inode, NFSIOS_READPAGES, 1); 53391d5b470SChuck Lever 5341da177e4SLinus Torvalds /* 5351da177e4SLinus Torvalds * Try to flush any pending writes to the file.. 5361da177e4SLinus Torvalds * 5371da177e4SLinus Torvalds * NOTE! Because we own the page lock, there cannot 5381da177e4SLinus Torvalds * be any new pending writes generated at this point 5391da177e4SLinus Torvalds * for this page (other pages can be written to). 5401da177e4SLinus Torvalds */ 5411da177e4SLinus Torvalds error = nfs_wb_page(inode, page); 5421da177e4SLinus Torvalds if (error) 543de05a0ccSTrond Myklebust goto out_unlock; 544de05a0ccSTrond Myklebust if (PageUptodate(page)) 545de05a0ccSTrond Myklebust goto out_unlock; 5461da177e4SLinus Torvalds 5475f004cf2STrond Myklebust error = -ESTALE; 5485f004cf2STrond Myklebust if (NFS_STALE(inode)) 549de05a0ccSTrond Myklebust goto out_unlock; 5505f004cf2STrond Myklebust 5511da177e4SLinus Torvalds if (file == NULL) { 552cf1308ffSTrond Myklebust error = -EBADF; 553d530838bSTrond Myklebust ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 5541da177e4SLinus Torvalds if (ctx == NULL) 555de05a0ccSTrond Myklebust goto out_unlock; 5561da177e4SLinus Torvalds } else 557cd3758e3STrond Myklebust ctx = get_nfs_open_context(nfs_file_open_context(file)); 5581da177e4SLinus Torvalds 5599a9fc1c0SDavid Howells if (!IS_SYNC(inode)) { 5609a9fc1c0SDavid Howells error = nfs_readpage_from_fscache(ctx, inode, page); 5619a9fc1c0SDavid Howells if (error == 0) 5629a9fc1c0SDavid Howells goto out; 5639a9fc1c0SDavid Howells } 5649a9fc1c0SDavid Howells 5658e0969f0STrond Myklebust error = nfs_readpage_async(ctx, inode, page); 5668e0969f0STrond Myklebust 5679a9fc1c0SDavid Howells out: 5681da177e4SLinus Torvalds put_nfs_open_context(ctx); 5691da177e4SLinus Torvalds return error; 570de05a0ccSTrond Myklebust out_unlock: 5711da177e4SLinus Torvalds unlock_page(page); 5721da177e4SLinus Torvalds return error; 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds struct nfs_readdesc { 5768b09bee3STrond Myklebust struct nfs_pageio_descriptor *pgio; 5771da177e4SLinus Torvalds struct nfs_open_context *ctx; 5781da177e4SLinus Torvalds }; 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds static int 5811da177e4SLinus Torvalds readpage_async_filler(void *data, struct page *page) 5821da177e4SLinus Torvalds { 5831da177e4SLinus Torvalds struct nfs_readdesc *desc = (struct nfs_readdesc *)data; 5841da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5851da177e4SLinus Torvalds struct nfs_page *new; 5861da177e4SLinus Torvalds unsigned int len; 587de05a0ccSTrond Myklebust int error; 5881da177e4SLinus Torvalds 58949a70f27STrond Myklebust len = nfs_page_length(page); 5901da177e4SLinus Torvalds if (len == 0) 5911da177e4SLinus Torvalds return nfs_return_empty_page(page); 592de05a0ccSTrond Myklebust 5931da177e4SLinus Torvalds new = nfs_create_request(desc->ctx, inode, page, 0, len); 594de05a0ccSTrond Myklebust if (IS_ERR(new)) 595de05a0ccSTrond Myklebust goto out_error; 596de05a0ccSTrond Myklebust 5971da177e4SLinus Torvalds if (len < PAGE_CACHE_SIZE) 598eebd2aa3SChristoph Lameter zero_user_segment(page, len, PAGE_CACHE_SIZE); 599f8512ad0SFred Isaman if (!nfs_pageio_add_request(desc->pgio, new)) { 600f8512ad0SFred Isaman error = desc->pgio->pg_error; 601f8512ad0SFred Isaman goto out_unlock; 602f8512ad0SFred Isaman } 6031da177e4SLinus Torvalds return 0; 604de05a0ccSTrond Myklebust out_error: 605de05a0ccSTrond Myklebust error = PTR_ERR(new); 606de05a0ccSTrond Myklebust out_unlock: 607de05a0ccSTrond Myklebust unlock_page(page); 608de05a0ccSTrond Myklebust return error; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds int nfs_readpages(struct file *filp, struct address_space *mapping, 6121da177e4SLinus Torvalds struct list_head *pages, unsigned nr_pages) 6131da177e4SLinus Torvalds { 6148b09bee3STrond Myklebust struct nfs_pageio_descriptor pgio; 6151da177e4SLinus Torvalds struct nfs_readdesc desc = { 6168b09bee3STrond Myklebust .pgio = &pgio, 6171da177e4SLinus Torvalds }; 6181da177e4SLinus Torvalds struct inode *inode = mapping->host; 6198b09bee3STrond Myklebust unsigned long npages; 6205f004cf2STrond Myklebust int ret = -ESTALE; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", 6231da177e4SLinus Torvalds inode->i_sb->s_id, 6241da177e4SLinus Torvalds (long long)NFS_FILEID(inode), 6251da177e4SLinus Torvalds nr_pages); 62691d5b470SChuck Lever nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); 6271da177e4SLinus Torvalds 6285f004cf2STrond Myklebust if (NFS_STALE(inode)) 6295f004cf2STrond Myklebust goto out; 6305f004cf2STrond Myklebust 6311da177e4SLinus Torvalds if (filp == NULL) { 632d530838bSTrond Myklebust desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 6331da177e4SLinus Torvalds if (desc.ctx == NULL) 6341da177e4SLinus Torvalds return -EBADF; 6351da177e4SLinus Torvalds } else 636cd3758e3STrond Myklebust desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); 6379a9fc1c0SDavid Howells 6389a9fc1c0SDavid Howells /* attempt to read as many of the pages as possible from the cache 6399a9fc1c0SDavid Howells * - this returns -ENOBUFS immediately if the cookie is negative 6409a9fc1c0SDavid Howells */ 6419a9fc1c0SDavid Howells ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping, 6429a9fc1c0SDavid Howells pages, &nr_pages); 6439a9fc1c0SDavid Howells if (ret == 0) 6449a9fc1c0SDavid Howells goto read_complete; /* all pages were read */ 6459a9fc1c0SDavid Howells 6461abb5088SBryan Schumaker NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops); 6478b09bee3STrond Myklebust 6481da177e4SLinus Torvalds ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); 6498b09bee3STrond Myklebust 6508b09bee3STrond Myklebust nfs_pageio_complete(&pgio); 6512701d086SAndy Adamson NFS_I(inode)->read_io += pgio.pg_bytes_written; 6528b09bee3STrond Myklebust npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 6538b09bee3STrond Myklebust nfs_add_stats(inode, NFSIOS_READPAGES, npages); 6549a9fc1c0SDavid Howells read_complete: 6551da177e4SLinus Torvalds put_nfs_open_context(desc.ctx); 6565f004cf2STrond Myklebust out: 6571da177e4SLinus Torvalds return ret; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds 660f7b422b1SDavid Howells int __init nfs_init_readpagecache(void) 6611da177e4SLinus Torvalds { 6621da177e4SLinus Torvalds nfs_rdata_cachep = kmem_cache_create("nfs_read_data", 663cd841605SFred Isaman sizeof(struct nfs_read_header), 6641da177e4SLinus Torvalds 0, SLAB_HWCACHE_ALIGN, 66520c2df83SPaul Mundt NULL); 6661da177e4SLinus Torvalds if (nfs_rdata_cachep == NULL) 6671da177e4SLinus Torvalds return -ENOMEM; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds return 0; 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds 672266bee88SDavid Brownell void nfs_destroy_readpagecache(void) 6731da177e4SLinus Torvalds { 6741a1d92c1SAlexey Dobriyan kmem_cache_destroy(nfs_rdata_cachep); 6751da177e4SLinus Torvalds } 676