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; 33*4db6e0b7SFred Isaman static const struct rpc_call_ops nfs_read_common_ops; 341da177e4SLinus Torvalds 35e18b890bSChristoph Lameter static struct kmem_cache *nfs_rdata_cachep; 361da177e4SLinus Torvalds 37*4db6e0b7SFred Isaman struct nfs_read_header *nfs_readhdr_alloc() 383feb2d49STrond Myklebust { 39*4db6e0b7SFred Isaman struct nfs_read_header *rhdr; 403feb2d49STrond Myklebust 41*4db6e0b7SFred Isaman rhdr = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); 42*4db6e0b7SFred Isaman if (rhdr) { 43*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr = &rhdr->header; 44cd841605SFred Isaman 45cd841605SFred Isaman INIT_LIST_HEAD(&hdr->pages); 46*4db6e0b7SFred Isaman INIT_LIST_HEAD(&hdr->rpc_list); 47*4db6e0b7SFred Isaman spin_lock_init(&hdr->lock); 48*4db6e0b7SFred Isaman atomic_set(&hdr->refcnt, 0); 49*4db6e0b7SFred Isaman } 50*4db6e0b7SFred Isaman return rhdr; 51*4db6e0b7SFred Isaman } 52*4db6e0b7SFred Isaman 53*4db6e0b7SFred Isaman struct nfs_read_data *nfs_readdata_alloc(struct nfs_pgio_header *hdr, 54*4db6e0b7SFred Isaman unsigned int pagecount) 55*4db6e0b7SFred Isaman { 56*4db6e0b7SFred Isaman struct nfs_read_data *data, *prealloc; 57*4db6e0b7SFred Isaman 58*4db6e0b7SFred Isaman prealloc = &container_of(hdr, struct nfs_read_header, header)->rpc_data; 59*4db6e0b7SFred Isaman if (prealloc->header == NULL) 60*4db6e0b7SFred Isaman data = prealloc; 61*4db6e0b7SFred Isaman else 62*4db6e0b7SFred Isaman data = kzalloc(sizeof(*data), GFP_KERNEL); 63*4db6e0b7SFred Isaman if (!data) 64*4db6e0b7SFred Isaman goto out; 65*4db6e0b7SFred Isaman 66*4db6e0b7SFred Isaman if (nfs_pgarray_set(&data->pages, pagecount)) { 67cd841605SFred Isaman data->header = hdr; 68*4db6e0b7SFred Isaman atomic_inc(&hdr->refcnt); 69*4db6e0b7SFred Isaman } else { 70*4db6e0b7SFred Isaman if (data != prealloc) 71*4db6e0b7SFred Isaman kfree(data); 72*4db6e0b7SFred Isaman data = NULL; 733feb2d49STrond Myklebust } 74*4db6e0b7SFred Isaman out: 75*4db6e0b7SFred Isaman return data; 763feb2d49STrond Myklebust } 773feb2d49STrond Myklebust 78cd841605SFred Isaman void nfs_readhdr_free(struct nfs_pgio_header *hdr) 793feb2d49STrond Myklebust { 80cd841605SFred Isaman struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header); 81cd841605SFred Isaman 82cd841605SFred Isaman kmem_cache_free(nfs_rdata_cachep, rhdr); 833feb2d49STrond Myklebust } 843feb2d49STrond Myklebust 85493292ddSTrond Myklebust void nfs_readdata_release(struct nfs_read_data *rdata) 861da177e4SLinus Torvalds { 87*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr = rdata->header; 88*4db6e0b7SFred Isaman struct nfs_read_header *read_header = container_of(hdr, struct nfs_read_header, header); 89*4db6e0b7SFred Isaman 90383ba719STrond Myklebust put_nfs_open_context(rdata->args.context); 9130dd374fSFred Isaman if (rdata->pages.pagevec != rdata->pages.page_array) 9230dd374fSFred Isaman kfree(rdata->pages.pagevec); 93*4db6e0b7SFred Isaman if (rdata != &read_header->rpc_data) 94*4db6e0b7SFred Isaman kfree(rdata); 95*4db6e0b7SFred Isaman else 96*4db6e0b7SFred Isaman rdata->header = NULL; 97*4db6e0b7SFred Isaman if (atomic_dec_and_test(&hdr->refcnt)) 98*4db6e0b7SFred Isaman nfs_read_completion(hdr); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds static 1021da177e4SLinus Torvalds int nfs_return_empty_page(struct page *page) 1031da177e4SLinus Torvalds { 104eebd2aa3SChristoph Lameter zero_user(page, 0, PAGE_CACHE_SIZE); 1051da177e4SLinus Torvalds SetPageUptodate(page); 1061da177e4SLinus Torvalds unlock_page(page); 1071da177e4SLinus Torvalds return 0; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 11062e4a769STrond Myklebust void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, 1111751c363STrond Myklebust struct inode *inode) 1121751c363STrond Myklebust { 1131751c363STrond Myklebust nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, 1141751c363STrond Myklebust NFS_SERVER(inode)->rsize, 0); 1151751c363STrond Myklebust } 1161751c363STrond Myklebust 117493292ddSTrond Myklebust void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) 118493292ddSTrond Myklebust { 119493292ddSTrond Myklebust pgio->pg_ops = &nfs_pageio_read_ops; 120493292ddSTrond Myklebust pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; 121493292ddSTrond Myklebust } 1221f945357STrond Myklebust EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); 123493292ddSTrond Myklebust 1241751c363STrond Myklebust static void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, 1251751c363STrond Myklebust struct inode *inode) 1261751c363STrond Myklebust { 1271751c363STrond Myklebust if (!pnfs_pageio_init_read(pgio, inode)) 1281751c363STrond Myklebust nfs_pageio_init_read_mds(pgio, inode); 1291751c363STrond Myklebust } 1301751c363STrond Myklebust 131f42b293dSDavid Howells int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, 1321da177e4SLinus Torvalds struct page *page) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds struct nfs_page *new; 1351da177e4SLinus Torvalds unsigned int len; 136c76069bdSFred Isaman struct nfs_pageio_descriptor pgio; 1371da177e4SLinus Torvalds 13849a70f27STrond Myklebust len = nfs_page_length(page); 1391da177e4SLinus Torvalds if (len == 0) 1401da177e4SLinus Torvalds return nfs_return_empty_page(page); 1411da177e4SLinus Torvalds new = nfs_create_request(ctx, inode, page, 0, len); 1421da177e4SLinus Torvalds if (IS_ERR(new)) { 1431da177e4SLinus Torvalds unlock_page(page); 1441da177e4SLinus Torvalds return PTR_ERR(new); 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds if (len < PAGE_CACHE_SIZE) 147eebd2aa3SChristoph Lameter zero_user_segment(page, len, PAGE_CACHE_SIZE); 1481da177e4SLinus Torvalds 1491751c363STrond Myklebust nfs_pageio_init_read(&pgio, inode); 150d8007d4dSTrond Myklebust nfs_pageio_add_request(&pgio, new); 1511751c363STrond Myklebust nfs_pageio_complete(&pgio); 1521da177e4SLinus Torvalds return 0; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds static void nfs_readpage_release(struct nfs_page *req) 1561da177e4SLinus Torvalds { 1573d4ff43dSAl Viro struct inode *d_inode = req->wb_context->dentry->d_inode; 1587f8e05f6SDavid Howells 1597f8e05f6SDavid Howells if (PageUptodate(req->wb_page)) 1607f8e05f6SDavid Howells nfs_readpage_to_fscache(d_inode, req->wb_page, 0); 1617f8e05f6SDavid Howells 1621da177e4SLinus Torvalds unlock_page(req->wb_page); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", 1653d4ff43dSAl Viro req->wb_context->dentry->d_inode->i_sb->s_id, 1663d4ff43dSAl Viro (long long)NFS_FILEID(req->wb_context->dentry->d_inode), 1671da177e4SLinus Torvalds req->wb_bytes, 1681da177e4SLinus Torvalds (long long)req_offset(req)); 16910d2c46fSNick Wilson nfs_release_request(req); 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 172*4db6e0b7SFred Isaman /* Note io was page aligned */ 173*4db6e0b7SFred Isaman void nfs_read_completion(struct nfs_pgio_header *hdr) 174*4db6e0b7SFred Isaman { 175*4db6e0b7SFred Isaman unsigned long bytes = 0; 176*4db6e0b7SFred Isaman 177*4db6e0b7SFred Isaman if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) 178*4db6e0b7SFred Isaman goto out; 179*4db6e0b7SFred Isaman if (!test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { 180*4db6e0b7SFred Isaman while (!list_empty(&hdr->pages)) { 181*4db6e0b7SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 182*4db6e0b7SFred Isaman struct page *page = req->wb_page; 183*4db6e0b7SFred Isaman 184*4db6e0b7SFred Isaman if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) { 185*4db6e0b7SFred Isaman if (bytes > hdr->good_bytes) 186*4db6e0b7SFred Isaman zero_user(page, 0, PAGE_SIZE); 187*4db6e0b7SFred Isaman else if (hdr->good_bytes - bytes < PAGE_SIZE) 188*4db6e0b7SFred Isaman zero_user_segment(page, 189*4db6e0b7SFred Isaman hdr->good_bytes & ~PAGE_MASK, 190*4db6e0b7SFred Isaman PAGE_SIZE); 191*4db6e0b7SFred Isaman } 192*4db6e0b7SFred Isaman SetPageUptodate(page); 193*4db6e0b7SFred Isaman nfs_list_remove_request(req); 194*4db6e0b7SFred Isaman nfs_readpage_release(req); 195*4db6e0b7SFred Isaman bytes += PAGE_SIZE; 196*4db6e0b7SFred Isaman } 197*4db6e0b7SFred Isaman } else { 198*4db6e0b7SFred Isaman while (!list_empty(&hdr->pages)) { 199*4db6e0b7SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 200*4db6e0b7SFred Isaman 201*4db6e0b7SFred Isaman bytes += req->wb_bytes; 202*4db6e0b7SFred Isaman if (bytes <= hdr->good_bytes) 203*4db6e0b7SFred Isaman SetPageUptodate(req->wb_page); 204*4db6e0b7SFred Isaman nfs_list_remove_request(req); 205*4db6e0b7SFred Isaman nfs_readpage_release(req); 206*4db6e0b7SFred Isaman } 207*4db6e0b7SFred Isaman } 208*4db6e0b7SFred Isaman out: 209*4db6e0b7SFred Isaman hdr->release(hdr); 210*4db6e0b7SFred Isaman } 211*4db6e0b7SFred Isaman 212c5996c4eSFred Isaman int nfs_initiate_read(struct rpc_clnt *clnt, 213c5996c4eSFred Isaman struct nfs_read_data *data, 21464419a9bSAndy Adamson const struct rpc_call_ops *call_ops) 21564419a9bSAndy Adamson { 216cd841605SFred Isaman struct inode *inode = data->header->inode; 21764419a9bSAndy Adamson int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; 21864419a9bSAndy Adamson struct rpc_task *task; 21964419a9bSAndy Adamson struct rpc_message msg = { 22064419a9bSAndy Adamson .rpc_argp = &data->args, 22164419a9bSAndy Adamson .rpc_resp = &data->res, 222cd841605SFred Isaman .rpc_cred = data->header->cred, 22364419a9bSAndy Adamson }; 22464419a9bSAndy Adamson struct rpc_task_setup task_setup_data = { 22564419a9bSAndy Adamson .task = &data->task, 22664419a9bSAndy Adamson .rpc_client = clnt, 22764419a9bSAndy Adamson .rpc_message = &msg, 22864419a9bSAndy Adamson .callback_ops = call_ops, 22964419a9bSAndy Adamson .callback_data = data, 23064419a9bSAndy Adamson .workqueue = nfsiod_workqueue, 23164419a9bSAndy Adamson .flags = RPC_TASK_ASYNC | swap_flags, 23264419a9bSAndy Adamson }; 23364419a9bSAndy Adamson 23464419a9bSAndy Adamson /* Set up the initial task struct. */ 23564419a9bSAndy Adamson NFS_PROTO(inode)->read_setup(data, &msg); 23664419a9bSAndy Adamson 23764419a9bSAndy Adamson dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ " 23864419a9bSAndy Adamson "offset %llu)\n", 23964419a9bSAndy Adamson data->task.tk_pid, 24064419a9bSAndy Adamson inode->i_sb->s_id, 24164419a9bSAndy Adamson (long long)NFS_FILEID(inode), 24264419a9bSAndy Adamson data->args.count, 24364419a9bSAndy Adamson (unsigned long long)data->args.offset); 24464419a9bSAndy Adamson 24564419a9bSAndy Adamson task = rpc_run_task(&task_setup_data); 24664419a9bSAndy Adamson if (IS_ERR(task)) 24764419a9bSAndy Adamson return PTR_ERR(task); 24864419a9bSAndy Adamson rpc_put_task(task); 24964419a9bSAndy Adamson return 0; 25064419a9bSAndy Adamson } 251dc70d7b3SAndy Adamson EXPORT_SYMBOL_GPL(nfs_initiate_read); 25264419a9bSAndy Adamson 2531da177e4SLinus Torvalds /* 2541da177e4SLinus Torvalds * Set up the NFS read request struct 2551da177e4SLinus Torvalds */ 256*4db6e0b7SFred Isaman static void nfs_read_rpcsetup(struct nfs_read_data *data, 2576e4efd56STrond Myklebust unsigned int count, unsigned int offset) 2581da177e4SLinus Torvalds { 259*4db6e0b7SFred Isaman struct nfs_page *req = data->header->req; 2601da177e4SLinus Torvalds 261*4db6e0b7SFred Isaman data->args.fh = NFS_FH(data->header->inode); 2621da177e4SLinus Torvalds data->args.offset = req_offset(req) + offset; 2631da177e4SLinus Torvalds data->args.pgbase = req->wb_pgbase + offset; 26430dd374fSFred Isaman data->args.pages = data->pages.pagevec; 2651da177e4SLinus Torvalds data->args.count = count; 266383ba719STrond Myklebust data->args.context = get_nfs_open_context(req->wb_context); 267f11ac8dbSTrond Myklebust data->args.lock_context = req->wb_lock_context; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds data->res.fattr = &data->fattr; 2701da177e4SLinus Torvalds data->res.count = count; 2711da177e4SLinus Torvalds data->res.eof = 0; 2720e574af1STrond Myklebust nfs_fattr_init(&data->fattr); 2736e4efd56STrond Myklebust } 2741da177e4SLinus Torvalds 2756e4efd56STrond Myklebust static int nfs_do_read(struct nfs_read_data *data, 276493292ddSTrond Myklebust const struct rpc_call_ops *call_ops) 2776e4efd56STrond Myklebust { 278cd841605SFred Isaman struct inode *inode = data->header->inode; 2796e4efd56STrond Myklebust 280c5996c4eSFred Isaman return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 283275acaafSTrond Myklebust static int 284275acaafSTrond Myklebust nfs_do_multiple_reads(struct list_head *head, 285493292ddSTrond Myklebust const struct rpc_call_ops *call_ops) 286275acaafSTrond Myklebust { 287275acaafSTrond Myklebust struct nfs_read_data *data; 288275acaafSTrond Myklebust int ret = 0; 289275acaafSTrond Myklebust 290275acaafSTrond Myklebust while (!list_empty(head)) { 291275acaafSTrond Myklebust int ret2; 292275acaafSTrond Myklebust 293*4db6e0b7SFred Isaman data = list_first_entry(head, struct nfs_read_data, list); 294275acaafSTrond Myklebust list_del_init(&data->list); 295275acaafSTrond Myklebust 296493292ddSTrond Myklebust ret2 = nfs_do_read(data, call_ops); 297275acaafSTrond Myklebust if (ret == 0) 298275acaafSTrond Myklebust ret = ret2; 299275acaafSTrond Myklebust } 300275acaafSTrond Myklebust return ret; 301275acaafSTrond Myklebust } 302275acaafSTrond Myklebust 303*4db6e0b7SFred Isaman void 3041da177e4SLinus Torvalds nfs_async_read_error(struct list_head *head) 3051da177e4SLinus Torvalds { 3061da177e4SLinus Torvalds struct nfs_page *req; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds while (!list_empty(head)) { 3091da177e4SLinus Torvalds req = nfs_list_entry(head->next); 3101da177e4SLinus Torvalds nfs_list_remove_request(req); 3111da177e4SLinus Torvalds nfs_readpage_release(req); 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* 3161da177e4SLinus Torvalds * Generate multiple requests to fill a single page. 3171da177e4SLinus Torvalds * 3181da177e4SLinus Torvalds * We optimize to reduce the number of read operations on the wire. If we 3191da177e4SLinus Torvalds * detect that we're reading a page, or an area of a page, that is past the 3201da177e4SLinus Torvalds * end of file, we do not generate NFS read operations but just clear the 3211da177e4SLinus Torvalds * parts of the page that would have come back zero from the server anyway. 3221da177e4SLinus Torvalds * 3231da177e4SLinus Torvalds * We rely on the cached value of i_size to make this determination; another 3241da177e4SLinus Torvalds * client can fill pages on the server past our cached end-of-file, but we 3251da177e4SLinus Torvalds * won't see the new data until our attribute cache is updated. This is more 3261da177e4SLinus Torvalds * or less conventional NFS client behavior. 3271da177e4SLinus Torvalds */ 328*4db6e0b7SFred Isaman static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, 329*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 3301da177e4SLinus Torvalds { 331*4db6e0b7SFred Isaman struct nfs_page *req = hdr->req; 3321da177e4SLinus Torvalds struct page *page = req->wb_page; 3331da177e4SLinus Torvalds struct nfs_read_data *data; 334d097971dSTrond Myklebust size_t rsize = desc->pg_bsize, nbytes; 335e9f7bee1STrond Myklebust unsigned int offset; 3361da177e4SLinus Torvalds int requests = 0; 337dbae4c73STrond Myklebust int ret = 0; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds nfs_list_remove_request(req); 340*4db6e0b7SFred Isaman nfs_list_add_request(req, &hdr->pages); 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 347*4db6e0b7SFred Isaman data = nfs_readdata_alloc(hdr, 1); 348*4db6e0b7SFred Isaman if (!data) 3491da177e4SLinus Torvalds goto out_bad; 35030dd374fSFred Isaman data->pages.pagevec[0] = page; 351*4db6e0b7SFred Isaman nfs_read_rpcsetup(data, len, offset); 352*4db6e0b7SFred Isaman list_add(&data->list, &hdr->rpc_list); 3531da177e4SLinus Torvalds requests++; 354e9f7bee1STrond Myklebust nbytes -= len; 355275acaafSTrond Myklebust offset += len; 356e9f7bee1STrond Myklebust } while(nbytes != 0); 357*4db6e0b7SFred Isaman desc->pg_rpc_callops = &nfs_read_common_ops; 358dbae4c73STrond Myklebust return ret; 3591da177e4SLinus Torvalds out_bad: 360*4db6e0b7SFred Isaman while (!list_empty(&hdr->rpc_list)) { 361*4db6e0b7SFred Isaman data = list_first_entry(&hdr->rpc_list, struct nfs_read_data, list); 3626e4efd56STrond Myklebust list_del(&data->list); 36373fb7bc7SFred Isaman nfs_readdata_release(data); 3641da177e4SLinus Torvalds } 365*4db6e0b7SFred Isaman nfs_async_read_error(&hdr->pages); 3661da177e4SLinus Torvalds return -ENOMEM; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 369*4db6e0b7SFred Isaman static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, 370*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 3711da177e4SLinus Torvalds { 3721da177e4SLinus Torvalds struct nfs_page *req; 3731da177e4SLinus Torvalds struct page **pages; 3741da177e4SLinus Torvalds struct nfs_read_data *data; 375c76069bdSFred Isaman struct list_head *head = &desc->pg_list; 3763b609184SPeng Tao int ret = 0; 3771da177e4SLinus Torvalds 378*4db6e0b7SFred Isaman data = nfs_readdata_alloc(hdr, nfs_page_array_len(desc->pg_base, 379c76069bdSFred Isaman desc->pg_count)); 380*4db6e0b7SFred Isaman if (!data) { 381bae724efSFred Isaman nfs_async_read_error(head); 3823b609184SPeng Tao ret = -ENOMEM; 383bae724efSFred Isaman goto out; 384bae724efSFred Isaman } 3851da177e4SLinus Torvalds 38630dd374fSFred Isaman pages = data->pages.pagevec; 3871da177e4SLinus Torvalds while (!list_empty(head)) { 3881da177e4SLinus Torvalds req = nfs_list_entry(head->next); 3891da177e4SLinus Torvalds nfs_list_remove_request(req); 390*4db6e0b7SFred Isaman nfs_list_add_request(req, &hdr->pages); 3911da177e4SLinus Torvalds *pages++ = req->wb_page; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 394*4db6e0b7SFred Isaman nfs_read_rpcsetup(data, desc->pg_count, 0); 395*4db6e0b7SFred Isaman list_add(&data->list, &hdr->rpc_list); 396*4db6e0b7SFred Isaman desc->pg_rpc_callops = &nfs_read_common_ops; 397bae724efSFred Isaman out: 398dbae4c73STrond Myklebust return ret; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 401*4db6e0b7SFred Isaman int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, 402*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr) 403493292ddSTrond Myklebust { 404493292ddSTrond Myklebust if (desc->pg_bsize < PAGE_CACHE_SIZE) 405*4db6e0b7SFred Isaman return nfs_pagein_multi(desc, hdr); 406*4db6e0b7SFred Isaman return nfs_pagein_one(desc, hdr); 407493292ddSTrond Myklebust } 408493292ddSTrond Myklebust 409493292ddSTrond Myklebust static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) 4101751c363STrond Myklebust { 411*4db6e0b7SFred Isaman struct nfs_read_header *rhdr; 412*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr; 413275acaafSTrond Myklebust int ret; 414275acaafSTrond Myklebust 415*4db6e0b7SFred Isaman rhdr = nfs_readhdr_alloc(); 416*4db6e0b7SFred Isaman if (!rhdr) { 417*4db6e0b7SFred Isaman nfs_async_read_error(&desc->pg_list); 418*4db6e0b7SFred Isaman return -ENOMEM; 419*4db6e0b7SFred Isaman } 420*4db6e0b7SFred Isaman hdr = &rhdr->header; 421*4db6e0b7SFred Isaman nfs_pgheader_init(desc, hdr, nfs_readhdr_free); 422*4db6e0b7SFred Isaman atomic_inc(&hdr->refcnt); 423*4db6e0b7SFred Isaman ret = nfs_generic_pagein(desc, hdr); 424275acaafSTrond Myklebust if (ret == 0) 425*4db6e0b7SFred Isaman ret = nfs_do_multiple_reads(&hdr->rpc_list, 426*4db6e0b7SFred Isaman desc->pg_rpc_callops); 427*4db6e0b7SFred Isaman else 428*4db6e0b7SFred Isaman set_bit(NFS_IOHDR_REDO, &hdr->flags); 429*4db6e0b7SFred Isaman if (atomic_dec_and_test(&hdr->refcnt)) 430*4db6e0b7SFred Isaman nfs_read_completion(hdr); 431275acaafSTrond Myklebust return ret; 4321751c363STrond Myklebust } 4331751c363STrond Myklebust 4341751c363STrond Myklebust static const struct nfs_pageio_ops nfs_pageio_read_ops = { 4351751c363STrond Myklebust .pg_test = nfs_generic_pg_test, 4361751c363STrond Myklebust .pg_doio = nfs_generic_pg_readpages, 4371751c363STrond Myklebust }; 4381751c363STrond Myklebust 4391da177e4SLinus Torvalds /* 4400b671301STrond Myklebust * This is the callback from RPC telling us whether a reply was 4410b671301STrond Myklebust * received or some error occurred (timeout or socket shutdown). 4420b671301STrond Myklebust */ 4430b671301STrond Myklebust int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) 4440b671301STrond Myklebust { 445cd841605SFred Isaman struct inode *inode = data->header->inode; 4460b671301STrond Myklebust int status; 4470b671301STrond Myklebust 4483110ff80SHarvey Harrison dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid, 4490b671301STrond Myklebust task->tk_status); 4500b671301STrond Myklebust 451cd841605SFred Isaman status = NFS_PROTO(inode)->read_done(task, data); 4520b671301STrond Myklebust if (status != 0) 4530b671301STrond Myklebust return status; 4540b671301STrond Myklebust 455cd841605SFred Isaman nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count); 4560b671301STrond Myklebust 4570b671301STrond Myklebust if (task->tk_status == -ESTALE) { 458cd841605SFred Isaman set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); 459cd841605SFred Isaman nfs_mark_for_revalidate(inode); 4600b671301STrond Myklebust } 4610b671301STrond Myklebust return 0; 4620b671301STrond Myklebust } 4630b671301STrond Myklebust 464fdd1e74cSTrond Myklebust static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) 4650b671301STrond Myklebust { 4660b671301STrond Myklebust struct nfs_readargs *argp = &data->args; 4670b671301STrond Myklebust struct nfs_readres *resp = &data->res; 4680b671301STrond Myklebust 4690b671301STrond Myklebust /* This is a short read! */ 470cd841605SFred Isaman nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD); 4710b671301STrond Myklebust /* Has the server at least made some progress? */ 472*4db6e0b7SFred Isaman if (resp->count == 0) { 473*4db6e0b7SFred Isaman nfs_set_pgio_error(data->header, -EIO, argp->offset); 474d61e612aSTrond Myklebust return; 475*4db6e0b7SFred Isaman } 4760b671301STrond Myklebust /* Yes, so retry the read at the end of the data */ 477cbdabc7fSAndy Adamson data->mds_offset += resp->count; 4780b671301STrond Myklebust argp->offset += resp->count; 4790b671301STrond Myklebust argp->pgbase += resp->count; 4800b671301STrond Myklebust argp->count -= resp->count; 481d00c5d43STrond Myklebust rpc_restart_call_prepare(task); 4820b671301STrond Myklebust } 4830b671301STrond Myklebust 484*4db6e0b7SFred Isaman static void nfs_readpage_result_common(struct rpc_task *task, void *calldata) 4851da177e4SLinus Torvalds { 486ec06c096STrond Myklebust struct nfs_read_data *data = calldata; 487*4db6e0b7SFred Isaman struct nfs_pgio_header *hdr = data->header; 4881da177e4SLinus Torvalds 489*4db6e0b7SFred Isaman /* Note the only returns of nfs_readpage_result are 0 and -EAGAIN */ 490ec06c096STrond Myklebust if (nfs_readpage_result(task, data) != 0) 491ec06c096STrond Myklebust return; 492fdd1e74cSTrond Myklebust if (task->tk_status < 0) 493*4db6e0b7SFred Isaman nfs_set_pgio_error(hdr, task->tk_status, data->args.offset); 494*4db6e0b7SFred Isaman else if (data->res.eof) { 495*4db6e0b7SFred Isaman loff_t bound; 496fdd1e74cSTrond Myklebust 497*4db6e0b7SFred Isaman bound = data->args.offset + data->res.count; 498*4db6e0b7SFred Isaman spin_lock(&hdr->lock); 499*4db6e0b7SFred Isaman if (bound < hdr->io_start + hdr->good_bytes) { 500*4db6e0b7SFred Isaman set_bit(NFS_IOHDR_EOF, &hdr->flags); 501*4db6e0b7SFred Isaman clear_bit(NFS_IOHDR_ERROR, &hdr->flags); 502*4db6e0b7SFred Isaman hdr->good_bytes = bound - hdr->io_start; 503*4db6e0b7SFred Isaman } 504*4db6e0b7SFred Isaman spin_unlock(&hdr->lock); 505*4db6e0b7SFred Isaman } else if (data->res.count != data->args.count) 506fdd1e74cSTrond Myklebust nfs_readpage_retry(task, data); 5070b671301STrond Myklebust } 508fdd1e74cSTrond Myklebust 509*4db6e0b7SFred Isaman static void nfs_readpage_release_common(void *calldata) 510fdd1e74cSTrond Myklebust { 511*4db6e0b7SFred Isaman nfs_readdata_release(calldata); 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 514f11c88afSAndy Adamson void nfs_read_prepare(struct rpc_task *task, void *calldata) 515f11c88afSAndy Adamson { 516f11c88afSAndy Adamson struct nfs_read_data *data = calldata; 517cd841605SFred Isaman NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data); 518f11c88afSAndy Adamson } 519f11c88afSAndy Adamson 520*4db6e0b7SFred Isaman static const struct rpc_call_ops nfs_read_common_ops = { 521f11c88afSAndy Adamson .rpc_call_prepare = nfs_read_prepare, 522*4db6e0b7SFred Isaman .rpc_call_done = nfs_readpage_result_common, 523*4db6e0b7SFred Isaman .rpc_release = nfs_readpage_release_common, 524ec06c096STrond Myklebust }; 525ec06c096STrond Myklebust 5261da177e4SLinus Torvalds /* 5271da177e4SLinus Torvalds * Read a page over NFS. 5281da177e4SLinus Torvalds * We read the page synchronously in the following case: 5291da177e4SLinus Torvalds * - The error flag is set for this page. This happens only when a 5301da177e4SLinus Torvalds * previous async read operation failed. 5311da177e4SLinus Torvalds */ 5321da177e4SLinus Torvalds int nfs_readpage(struct file *file, struct page *page) 5331da177e4SLinus Torvalds { 5341da177e4SLinus Torvalds struct nfs_open_context *ctx; 5351da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5361da177e4SLinus Torvalds int error; 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", 5391da177e4SLinus Torvalds page, PAGE_CACHE_SIZE, page->index); 54091d5b470SChuck Lever nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); 54191d5b470SChuck Lever nfs_add_stats(inode, NFSIOS_READPAGES, 1); 54291d5b470SChuck Lever 5431da177e4SLinus Torvalds /* 5441da177e4SLinus Torvalds * Try to flush any pending writes to the file.. 5451da177e4SLinus Torvalds * 5461da177e4SLinus Torvalds * NOTE! Because we own the page lock, there cannot 5471da177e4SLinus Torvalds * be any new pending writes generated at this point 5481da177e4SLinus Torvalds * for this page (other pages can be written to). 5491da177e4SLinus Torvalds */ 5501da177e4SLinus Torvalds error = nfs_wb_page(inode, page); 5511da177e4SLinus Torvalds if (error) 552de05a0ccSTrond Myklebust goto out_unlock; 553de05a0ccSTrond Myklebust if (PageUptodate(page)) 554de05a0ccSTrond Myklebust goto out_unlock; 5551da177e4SLinus Torvalds 5565f004cf2STrond Myklebust error = -ESTALE; 5575f004cf2STrond Myklebust if (NFS_STALE(inode)) 558de05a0ccSTrond Myklebust goto out_unlock; 5595f004cf2STrond Myklebust 5601da177e4SLinus Torvalds if (file == NULL) { 561cf1308ffSTrond Myklebust error = -EBADF; 562d530838bSTrond Myklebust ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 5631da177e4SLinus Torvalds if (ctx == NULL) 564de05a0ccSTrond Myklebust goto out_unlock; 5651da177e4SLinus Torvalds } else 566cd3758e3STrond Myklebust ctx = get_nfs_open_context(nfs_file_open_context(file)); 5671da177e4SLinus Torvalds 5689a9fc1c0SDavid Howells if (!IS_SYNC(inode)) { 5699a9fc1c0SDavid Howells error = nfs_readpage_from_fscache(ctx, inode, page); 5709a9fc1c0SDavid Howells if (error == 0) 5719a9fc1c0SDavid Howells goto out; 5729a9fc1c0SDavid Howells } 5739a9fc1c0SDavid Howells 5748e0969f0STrond Myklebust error = nfs_readpage_async(ctx, inode, page); 5758e0969f0STrond Myklebust 5769a9fc1c0SDavid Howells out: 5771da177e4SLinus Torvalds put_nfs_open_context(ctx); 5781da177e4SLinus Torvalds return error; 579de05a0ccSTrond Myklebust out_unlock: 5801da177e4SLinus Torvalds unlock_page(page); 5811da177e4SLinus Torvalds return error; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds struct nfs_readdesc { 5858b09bee3STrond Myklebust struct nfs_pageio_descriptor *pgio; 5861da177e4SLinus Torvalds struct nfs_open_context *ctx; 5871da177e4SLinus Torvalds }; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds static int 5901da177e4SLinus Torvalds readpage_async_filler(void *data, struct page *page) 5911da177e4SLinus Torvalds { 5921da177e4SLinus Torvalds struct nfs_readdesc *desc = (struct nfs_readdesc *)data; 5931da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5941da177e4SLinus Torvalds struct nfs_page *new; 5951da177e4SLinus Torvalds unsigned int len; 596de05a0ccSTrond Myklebust int error; 5971da177e4SLinus Torvalds 59849a70f27STrond Myklebust len = nfs_page_length(page); 5991da177e4SLinus Torvalds if (len == 0) 6001da177e4SLinus Torvalds return nfs_return_empty_page(page); 601de05a0ccSTrond Myklebust 6021da177e4SLinus Torvalds new = nfs_create_request(desc->ctx, inode, page, 0, len); 603de05a0ccSTrond Myklebust if (IS_ERR(new)) 604de05a0ccSTrond Myklebust goto out_error; 605de05a0ccSTrond Myklebust 6061da177e4SLinus Torvalds if (len < PAGE_CACHE_SIZE) 607eebd2aa3SChristoph Lameter zero_user_segment(page, len, PAGE_CACHE_SIZE); 608f8512ad0SFred Isaman if (!nfs_pageio_add_request(desc->pgio, new)) { 609f8512ad0SFred Isaman error = desc->pgio->pg_error; 610f8512ad0SFred Isaman goto out_unlock; 611f8512ad0SFred Isaman } 6121da177e4SLinus Torvalds return 0; 613de05a0ccSTrond Myklebust out_error: 614de05a0ccSTrond Myklebust error = PTR_ERR(new); 615de05a0ccSTrond Myklebust out_unlock: 616de05a0ccSTrond Myklebust unlock_page(page); 617de05a0ccSTrond Myklebust return error; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds int nfs_readpages(struct file *filp, struct address_space *mapping, 6211da177e4SLinus Torvalds struct list_head *pages, unsigned nr_pages) 6221da177e4SLinus Torvalds { 6238b09bee3STrond Myklebust struct nfs_pageio_descriptor pgio; 6241da177e4SLinus Torvalds struct nfs_readdesc desc = { 6258b09bee3STrond Myklebust .pgio = &pgio, 6261da177e4SLinus Torvalds }; 6271da177e4SLinus Torvalds struct inode *inode = mapping->host; 6288b09bee3STrond Myklebust unsigned long npages; 6295f004cf2STrond Myklebust int ret = -ESTALE; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", 6321da177e4SLinus Torvalds inode->i_sb->s_id, 6331da177e4SLinus Torvalds (long long)NFS_FILEID(inode), 6341da177e4SLinus Torvalds nr_pages); 63591d5b470SChuck Lever nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); 6361da177e4SLinus Torvalds 6375f004cf2STrond Myklebust if (NFS_STALE(inode)) 6385f004cf2STrond Myklebust goto out; 6395f004cf2STrond Myklebust 6401da177e4SLinus Torvalds if (filp == NULL) { 641d530838bSTrond Myklebust desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); 6421da177e4SLinus Torvalds if (desc.ctx == NULL) 6431da177e4SLinus Torvalds return -EBADF; 6441da177e4SLinus Torvalds } else 645cd3758e3STrond Myklebust desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); 6469a9fc1c0SDavid Howells 6479a9fc1c0SDavid Howells /* attempt to read as many of the pages as possible from the cache 6489a9fc1c0SDavid Howells * - this returns -ENOBUFS immediately if the cookie is negative 6499a9fc1c0SDavid Howells */ 6509a9fc1c0SDavid Howells ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping, 6519a9fc1c0SDavid Howells pages, &nr_pages); 6529a9fc1c0SDavid Howells if (ret == 0) 6539a9fc1c0SDavid Howells goto read_complete; /* all pages were read */ 6549a9fc1c0SDavid Howells 6551751c363STrond Myklebust nfs_pageio_init_read(&pgio, inode); 6568b09bee3STrond Myklebust 6571da177e4SLinus Torvalds ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); 6588b09bee3STrond Myklebust 6598b09bee3STrond Myklebust nfs_pageio_complete(&pgio); 6608b09bee3STrond Myklebust npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 6618b09bee3STrond Myklebust nfs_add_stats(inode, NFSIOS_READPAGES, npages); 6629a9fc1c0SDavid Howells read_complete: 6631da177e4SLinus Torvalds put_nfs_open_context(desc.ctx); 6645f004cf2STrond Myklebust out: 6651da177e4SLinus Torvalds return ret; 6661da177e4SLinus Torvalds } 6671da177e4SLinus Torvalds 668f7b422b1SDavid Howells int __init nfs_init_readpagecache(void) 6691da177e4SLinus Torvalds { 6701da177e4SLinus Torvalds nfs_rdata_cachep = kmem_cache_create("nfs_read_data", 671cd841605SFred Isaman sizeof(struct nfs_read_header), 6721da177e4SLinus Torvalds 0, SLAB_HWCACHE_ALIGN, 67320c2df83SPaul Mundt NULL); 6741da177e4SLinus Torvalds if (nfs_rdata_cachep == NULL) 6751da177e4SLinus Torvalds return -ENOMEM; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds return 0; 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds 680266bee88SDavid Brownell void nfs_destroy_readpagecache(void) 6811da177e4SLinus Torvalds { 6821a1d92c1SAlexey Dobriyan kmem_cache_destroy(nfs_rdata_cachep); 6831da177e4SLinus Torvalds } 684