1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/nfs/direct.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2003 by Chuck Lever <cel@netapp.com> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * High-performance uncached I/O for the Linux NFS client 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * There are important applications whose performance or correctness 101da177e4SLinus Torvalds * depends on uncached access to file data. Database clusters 111da177e4SLinus Torvalds * (multiple copies of the same instance running on separate hosts) 121da177e4SLinus Torvalds * implement their own cache coherency protocol that subsumes file 131da177e4SLinus Torvalds * system cache protocols. Applications that process datasets 141da177e4SLinus Torvalds * considerably larger than the client's memory do not always benefit 151da177e4SLinus Torvalds * from a local cache. A streaming video server, for instance, has no 161da177e4SLinus Torvalds * need to cache the contents of a file. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * When an application requests uncached I/O, all read and write requests 191da177e4SLinus Torvalds * are made directly to the server; data stored or fetched via these 201da177e4SLinus Torvalds * requests is not cached in the Linux page cache. The client does not 211da177e4SLinus Torvalds * correct unaligned requests from applications. All requested bytes are 221da177e4SLinus Torvalds * held on permanent storage before a direct write system call returns to 231da177e4SLinus Torvalds * an application. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * Solaris implements an uncached I/O facility called directio() that 261da177e4SLinus Torvalds * is used for backups and sequential I/O to very large files. Solaris 271da177e4SLinus Torvalds * also supports uncaching whole NFS partitions with "-o forcedirectio," 281da177e4SLinus Torvalds * an undocumented mount option. 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust, with 311da177e4SLinus Torvalds * help from Andrew Morton. 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * 18 Dec 2001 Initial implementation for 2.4 --cel 341da177e4SLinus Torvalds * 08 Jul 2002 Version for 2.4.19, with bug fixes --trondmy 351da177e4SLinus Torvalds * 08 Jun 2003 Port to 2.5 APIs --cel 361da177e4SLinus Torvalds * 31 Mar 2004 Handle direct I/O without VFS support --cel 371da177e4SLinus Torvalds * 15 Sep 2004 Parallel async reads --cel 3888467055SChuck Lever * 04 May 2005 support O_DIRECT with aio --cel 391da177e4SLinus Torvalds * 401da177e4SLinus Torvalds */ 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #include <linux/errno.h> 431da177e4SLinus Torvalds #include <linux/sched.h> 441da177e4SLinus Torvalds #include <linux/kernel.h> 451da177e4SLinus Torvalds #include <linux/file.h> 461da177e4SLinus Torvalds #include <linux/pagemap.h> 471da177e4SLinus Torvalds #include <linux/kref.h> 485a0e3ad6STejun Heo #include <linux/slab.h> 497ec10f26SKonstantin Khlebnikov #include <linux/task_io_accounting_ops.h> 506296556fSPeng Tao #include <linux/module.h> 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds #include <linux/nfs_fs.h> 531da177e4SLinus Torvalds #include <linux/nfs_page.h> 541da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 551da177e4SLinus Torvalds 567c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 5760063497SArun Sharma #include <linux/atomic.h> 581da177e4SLinus Torvalds 598d5658c9STrond Myklebust #include "internal.h" 6091d5b470SChuck Lever #include "iostat.h" 611763da12SFred Isaman #include "pnfs.h" 62a6b5a28eSDave Wysochanski #include "fscache.h" 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_VFS 651da177e4SLinus Torvalds 66e18b890bSChristoph Lameter static struct kmem_cache *nfs_direct_cachep; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds struct nfs_direct_req { 691da177e4SLinus Torvalds struct kref kref; /* release manager */ 7015ce4a0cSChuck Lever 7115ce4a0cSChuck Lever /* I/O parameters */ 72a8881f5aSTrond Myklebust struct nfs_open_context *ctx; /* file open context info */ 73f11ac8dbSTrond Myklebust struct nfs_lock_context *l_ctx; /* Lock context info */ 7499514f8fSChuck Lever struct kiocb * iocb; /* controlling i/o request */ 7588467055SChuck Lever struct inode * inode; /* target file of i/o */ 7615ce4a0cSChuck Lever 7715ce4a0cSChuck Lever /* completion state */ 78607f31e8STrond Myklebust atomic_t io_count; /* i/os we're waiting for */ 7915ce4a0cSChuck Lever spinlock_t lock; /* protect completion state */ 800a00b77bSWeston Andros Adamson 81d9ee6553STrond Myklebust loff_t io_start; /* Start offset for I/O */ 8215ce4a0cSChuck Lever ssize_t count, /* bytes actually processed */ 83ed3743a6SWeston Andros Adamson max_count, /* max expected count */ 8435754bc0SPeng Tao bytes_left, /* bytes left to be sent */ 851da177e4SLinus Torvalds error; /* any reported error */ 86d72b7a6bSTrond Myklebust struct completion completion; /* wait for i/o completion */ 87fad61490STrond Myklebust 88fad61490STrond Myklebust /* commit state */ 891763da12SFred Isaman struct nfs_mds_commit_info mds_cinfo; /* Storage for cinfo */ 901763da12SFred Isaman struct pnfs_ds_commit_info ds_cinfo; /* Storage for cinfo */ 911763da12SFred Isaman struct work_struct work; 92fad61490STrond Myklebust int flags; 93ad3cba22SDave Kleikamp /* for write */ 94fad61490STrond Myklebust #define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */ 95fad61490STrond Myklebust #define NFS_ODIRECT_RESCHED_WRITES (2) /* write verification failed */ 96ad3cba22SDave Kleikamp /* for read */ 97ad3cba22SDave Kleikamp #define NFS_ODIRECT_SHOULD_DIRTY (3) /* dirty user-space page after read */ 98fb5f7f20STrond Myklebust #define NFS_ODIRECT_DONE INT_MAX /* write verification failed */ 991da177e4SLinus Torvalds }; 1001da177e4SLinus Torvalds 1011763da12SFred Isaman static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops; 1021763da12SFred Isaman static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops; 1034d3b55d3SAnna Schumaker static void nfs_direct_write_complete(struct nfs_direct_req *dreq); 1041763da12SFred Isaman static void nfs_direct_write_schedule_work(struct work_struct *work); 105607f31e8STrond Myklebust 106607f31e8STrond Myklebust static inline void get_dreq(struct nfs_direct_req *dreq) 107607f31e8STrond Myklebust { 108607f31e8STrond Myklebust atomic_inc(&dreq->io_count); 109607f31e8STrond Myklebust } 110607f31e8STrond Myklebust 111607f31e8STrond Myklebust static inline int put_dreq(struct nfs_direct_req *dreq) 112607f31e8STrond Myklebust { 113607f31e8STrond Myklebust return atomic_dec_and_test(&dreq->io_count); 114607f31e8STrond Myklebust } 115607f31e8STrond Myklebust 1160a00b77bSWeston Andros Adamson static void 117031d73edSTrond Myklebust nfs_direct_handle_truncated(struct nfs_direct_req *dreq, 118031d73edSTrond Myklebust const struct nfs_pgio_header *hdr, 119031d73edSTrond Myklebust ssize_t dreq_len) 1200a00b77bSWeston Andros Adamson { 121031d73edSTrond Myklebust if (!(test_bit(NFS_IOHDR_ERROR, &hdr->flags) || 122031d73edSTrond Myklebust test_bit(NFS_IOHDR_EOF, &hdr->flags))) 123031d73edSTrond Myklebust return; 124031d73edSTrond Myklebust if (dreq->max_count >= dreq_len) { 125031d73edSTrond Myklebust dreq->max_count = dreq_len; 126031d73edSTrond Myklebust if (dreq->count > dreq_len) 127031d73edSTrond Myklebust dreq->count = dreq_len; 128ed3743a6SWeston Andros Adamson 129031d73edSTrond Myklebust if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) 130031d73edSTrond Myklebust dreq->error = hdr->error; 131031d73edSTrond Myklebust else /* Clear outstanding error if this is EOF */ 132031d73edSTrond Myklebust dreq->error = 0; 1335fadeb47SPeng Tao } 1340a00b77bSWeston Andros Adamson } 135031d73edSTrond Myklebust 136031d73edSTrond Myklebust static void 137031d73edSTrond Myklebust nfs_direct_count_bytes(struct nfs_direct_req *dreq, 138031d73edSTrond Myklebust const struct nfs_pgio_header *hdr) 139031d73edSTrond Myklebust { 140031d73edSTrond Myklebust loff_t hdr_end = hdr->io_start + hdr->good_bytes; 141031d73edSTrond Myklebust ssize_t dreq_len = 0; 142031d73edSTrond Myklebust 143031d73edSTrond Myklebust if (hdr_end > dreq->io_start) 144031d73edSTrond Myklebust dreq_len = hdr_end - dreq->io_start; 145031d73edSTrond Myklebust 146031d73edSTrond Myklebust nfs_direct_handle_truncated(dreq, hdr, dreq_len); 147031d73edSTrond Myklebust 148031d73edSTrond Myklebust if (dreq_len > dreq->max_count) 149031d73edSTrond Myklebust dreq_len = dreq->max_count; 150031d73edSTrond Myklebust 151031d73edSTrond Myklebust if (dreq->count < dreq_len) 152031d73edSTrond Myklebust dreq->count = dreq_len; 1531ccbad9fSPeng Tao } 1540a00b77bSWeston Andros Adamson 1551da177e4SLinus Torvalds /** 156*eb79f3afSNeilBrown * nfs_swap_rw - NFS address space operation for swap I/O 157b8a32e2bSChuck Lever * @iocb: target I/O control block 15890090ae6SAl Viro * @iter: I/O buffer 159b8a32e2bSChuck Lever * 160*eb79f3afSNeilBrown * Perform IO to the swap-file. This is much like direct IO. 1611da177e4SLinus Torvalds */ 162*eb79f3afSNeilBrown int nfs_swap_rw(struct kiocb *iocb, struct iov_iter *iter) 163b8a32e2bSChuck Lever { 164*eb79f3afSNeilBrown ssize_t ret; 165ee8a1a8bSPeng Tao 16666ee59afSChristoph Hellwig VM_BUG_ON(iov_iter_count(iter) != PAGE_SIZE); 167a564b8f0SMel Gorman 1686f673763SOmar Sandoval if (iov_iter_rw(iter) == READ) 169*eb79f3afSNeilBrown ret = nfs_file_direct_read(iocb, iter, true); 170*eb79f3afSNeilBrown else 171*eb79f3afSNeilBrown ret = nfs_file_direct_write(iocb, iter, true); 172*eb79f3afSNeilBrown if (ret < 0) 173*eb79f3afSNeilBrown return ret; 174*eb79f3afSNeilBrown return 0; 175b8a32e2bSChuck Lever } 176b8a32e2bSChuck Lever 177749e146eSChuck Lever static void nfs_direct_release_pages(struct page **pages, unsigned int npages) 1789c93ab7dSChuck Lever { 179749e146eSChuck Lever unsigned int i; 180607f31e8STrond Myklebust for (i = 0; i < npages; i++) 18109cbfeafSKirill A. Shutemov put_page(pages[i]); 1826b45d858STrond Myklebust } 1836b45d858STrond Myklebust 1841763da12SFred Isaman void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, 1851763da12SFred Isaman struct nfs_direct_req *dreq) 1861763da12SFred Isaman { 187fe238e60SDave Wysochanski cinfo->inode = dreq->inode; 1881763da12SFred Isaman cinfo->mds = &dreq->mds_cinfo; 1891763da12SFred Isaman cinfo->ds = &dreq->ds_cinfo; 1901763da12SFred Isaman cinfo->dreq = dreq; 1911763da12SFred Isaman cinfo->completion_ops = &nfs_direct_commit_completion_ops; 1921763da12SFred Isaman } 1931763da12SFred Isaman 19493619e59SChuck Lever static inline struct nfs_direct_req *nfs_direct_req_alloc(void) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds struct nfs_direct_req *dreq; 1971da177e4SLinus Torvalds 198292f3eeeSTrond Myklebust dreq = kmem_cache_zalloc(nfs_direct_cachep, GFP_KERNEL); 1991da177e4SLinus Torvalds if (!dreq) 2001da177e4SLinus Torvalds return NULL; 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds kref_init(&dreq->kref); 203607f31e8STrond Myklebust kref_get(&dreq->kref); 204d72b7a6bSTrond Myklebust init_completion(&dreq->completion); 2051763da12SFred Isaman INIT_LIST_HEAD(&dreq->mds_cinfo.list); 206c21e7168STrond Myklebust pnfs_init_ds_commit_info(&dreq->ds_cinfo); 2071763da12SFred Isaman INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); 20815ce4a0cSChuck Lever spin_lock_init(&dreq->lock); 20993619e59SChuck Lever 21093619e59SChuck Lever return dreq; 21193619e59SChuck Lever } 21293619e59SChuck Lever 213b4946ffbSTrond Myklebust static void nfs_direct_req_free(struct kref *kref) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); 216a8881f5aSTrond Myklebust 21718f41296STrond Myklebust pnfs_release_ds_info(&dreq->ds_cinfo, dreq->inode); 218f11ac8dbSTrond Myklebust if (dreq->l_ctx != NULL) 219f11ac8dbSTrond Myklebust nfs_put_lock_context(dreq->l_ctx); 220a8881f5aSTrond Myklebust if (dreq->ctx != NULL) 221a8881f5aSTrond Myklebust put_nfs_open_context(dreq->ctx); 2221da177e4SLinus Torvalds kmem_cache_free(nfs_direct_cachep, dreq); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 225b4946ffbSTrond Myklebust static void nfs_direct_req_release(struct nfs_direct_req *dreq) 226b4946ffbSTrond Myklebust { 227b4946ffbSTrond Myklebust kref_put(&dreq->kref, nfs_direct_req_free); 228b4946ffbSTrond Myklebust } 229b4946ffbSTrond Myklebust 2306296556fSPeng Tao ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq) 2316296556fSPeng Tao { 2326296556fSPeng Tao return dreq->bytes_left; 2336296556fSPeng Tao } 2346296556fSPeng Tao EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left); 2356296556fSPeng Tao 236d4cc948bSChuck Lever /* 237bc0fb201SChuck Lever * Collects and returns the final error value/byte-count. 238bc0fb201SChuck Lever */ 239bc0fb201SChuck Lever static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) 240bc0fb201SChuck Lever { 24115ce4a0cSChuck Lever ssize_t result = -EIOCBQUEUED; 242bc0fb201SChuck Lever 243bc0fb201SChuck Lever /* Async requests don't wait here */ 244bc0fb201SChuck Lever if (dreq->iocb) 245bc0fb201SChuck Lever goto out; 246bc0fb201SChuck Lever 247150030b7SMatthew Wilcox result = wait_for_completion_killable(&dreq->completion); 248bc0fb201SChuck Lever 249d2a7de0bSTrond Myklebust if (!result) { 250d2a7de0bSTrond Myklebust result = dreq->count; 251d2a7de0bSTrond Myklebust WARN_ON_ONCE(dreq->count < 0); 252d2a7de0bSTrond Myklebust } 253bc0fb201SChuck Lever if (!result) 25415ce4a0cSChuck Lever result = dreq->error; 255bc0fb201SChuck Lever 256bc0fb201SChuck Lever out: 257bc0fb201SChuck Lever return (ssize_t) result; 258bc0fb201SChuck Lever } 259bc0fb201SChuck Lever 260bc0fb201SChuck Lever /* 261607f31e8STrond Myklebust * Synchronous I/O uses a stack-allocated iocb. Thus we can't trust 262607f31e8STrond Myklebust * the iocb is still valid here if this is a synchronous request. 26363ab46abSChuck Lever */ 264f7b5c340STrond Myklebust static void nfs_direct_complete(struct nfs_direct_req *dreq) 26563ab46abSChuck Lever { 2669811cd57SChristoph Hellwig struct inode *inode = dreq->inode; 2679811cd57SChristoph Hellwig 26865caafd0SOlga Kornievskaia inode_dio_end(inode); 26965caafd0SOlga Kornievskaia 2702a009ec9SChristoph Hellwig if (dreq->iocb) { 2712a009ec9SChristoph Hellwig long res = (long) dreq->error; 272d2a7de0bSTrond Myklebust if (dreq->count != 0) { 2732a009ec9SChristoph Hellwig res = (long) dreq->count; 274d2a7de0bSTrond Myklebust WARN_ON_ONCE(dreq->count < 0); 275d2a7de0bSTrond Myklebust } 2766b19b766SJens Axboe dreq->iocb->ki_complete(dreq->iocb, res); 277d72b7a6bSTrond Myklebust } 2782a009ec9SChristoph Hellwig 279024de8f1SDaniel Wagner complete(&dreq->completion); 28063ab46abSChuck Lever 281b4946ffbSTrond Myklebust nfs_direct_req_release(dreq); 28263ab46abSChuck Lever } 28363ab46abSChuck Lever 284584aa810SFred Isaman static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) 285fdd1e74cSTrond Myklebust { 286584aa810SFred Isaman unsigned long bytes = 0; 287584aa810SFred Isaman struct nfs_direct_req *dreq = hdr->dreq; 288fdd1e74cSTrond Myklebust 28915ce4a0cSChuck Lever spin_lock(&dreq->lock); 290eb2c50daSTrond Myklebust if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) { 291eb2c50daSTrond Myklebust spin_unlock(&dreq->lock); 292eb2c50daSTrond Myklebust goto out_put; 293eb2c50daSTrond Myklebust } 294eb2c50daSTrond Myklebust 295031d73edSTrond Myklebust nfs_direct_count_bytes(dreq, hdr); 29615ce4a0cSChuck Lever spin_unlock(&dreq->lock); 2971da177e4SLinus Torvalds 298584aa810SFred Isaman while (!list_empty(&hdr->pages)) { 299584aa810SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 300584aa810SFred Isaman struct page *page = req->wb_page; 301584aa810SFred Isaman 302ad3cba22SDave Kleikamp if (!PageCompound(page) && bytes < hdr->good_bytes && 303ad3cba22SDave Kleikamp (dreq->flags == NFS_ODIRECT_SHOULD_DIRTY)) 3044bd8b010STrond Myklebust set_page_dirty(page); 305584aa810SFred Isaman bytes += req->wb_bytes; 306584aa810SFred Isaman nfs_list_remove_request(req); 307beeb5338SAnna Schumaker nfs_release_request(req); 308584aa810SFred Isaman } 309584aa810SFred Isaman out_put: 310607f31e8STrond Myklebust if (put_dreq(dreq)) 311f7b5c340STrond Myklebust nfs_direct_complete(dreq); 312584aa810SFred Isaman hdr->release(hdr); 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 315df3accb8STrond Myklebust static void nfs_read_sync_pgio_error(struct list_head *head, int error) 316cd841605SFred Isaman { 317584aa810SFred Isaman struct nfs_page *req; 318cd841605SFred Isaman 319584aa810SFred Isaman while (!list_empty(head)) { 320584aa810SFred Isaman req = nfs_list_entry(head->next); 321584aa810SFred Isaman nfs_list_remove_request(req); 322584aa810SFred Isaman nfs_release_request(req); 323cd841605SFred Isaman } 324584aa810SFred Isaman } 325584aa810SFred Isaman 326584aa810SFred Isaman static void nfs_direct_pgio_init(struct nfs_pgio_header *hdr) 327584aa810SFred Isaman { 328584aa810SFred Isaman get_dreq(hdr->dreq); 329584aa810SFred Isaman } 330584aa810SFred Isaman 331584aa810SFred Isaman static const struct nfs_pgio_completion_ops nfs_direct_read_completion_ops = { 3323e9e0ca3STrond Myklebust .error_cleanup = nfs_read_sync_pgio_error, 333584aa810SFred Isaman .init_hdr = nfs_direct_pgio_init, 334584aa810SFred Isaman .completion = nfs_direct_read_completion, 335584aa810SFred Isaman }; 336cd841605SFred Isaman 337d4cc948bSChuck Lever /* 338607f31e8STrond Myklebust * For each rsize'd chunk of the user's buffer, dispatch an NFS READ 339607f31e8STrond Myklebust * operation. If nfs_readdata_alloc() or get_user_pages() fails, 340607f31e8STrond Myklebust * bail and stop sending more reads. Read length accounting is 341607f31e8STrond Myklebust * handled automatically by nfs_direct_read_result(). Otherwise, if 342607f31e8STrond Myklebust * no requests have been sent, just return an error. 3431da177e4SLinus Torvalds */ 34491f79c43SAl Viro 34591f79c43SAl Viro static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, 34691f79c43SAl Viro struct iov_iter *iter, 34791f79c43SAl Viro loff_t pos) 3481da177e4SLinus Torvalds { 34991f79c43SAl Viro struct nfs_pageio_descriptor desc; 35091f79c43SAl Viro struct inode *inode = dreq->inode; 35191f79c43SAl Viro ssize_t result = -EINVAL; 35291f79c43SAl Viro size_t requested_bytes = 0; 35391f79c43SAl Viro size_t rsize = max_t(size_t, NFS_SERVER(inode)->rsize, PAGE_SIZE); 35482b145c5SChuck Lever 35516b90578SLinus Torvalds nfs_pageio_init_read(&desc, dreq->inode, false, 35691f79c43SAl Viro &nfs_direct_read_completion_ops); 35791f79c43SAl Viro get_dreq(dreq); 35891f79c43SAl Viro desc.pg_dreq = dreq; 359fe0f07d0SJens Axboe inode_dio_begin(inode); 36091f79c43SAl Viro 36191f79c43SAl Viro while (iov_iter_count(iter)) { 36291f79c43SAl Viro struct page **pagevec; 3635dd602f2SChuck Lever size_t bytes; 36491f79c43SAl Viro size_t pgbase; 36591f79c43SAl Viro unsigned npages, i; 3661da177e4SLinus Torvalds 36791f79c43SAl Viro result = iov_iter_get_pages_alloc(iter, &pagevec, 36891f79c43SAl Viro rsize, &pgbase); 369584aa810SFred Isaman if (result < 0) 370749e146eSChuck Lever break; 371a564b8f0SMel Gorman 37291f79c43SAl Viro bytes = result; 37391f79c43SAl Viro iov_iter_advance(iter, bytes); 37491f79c43SAl Viro npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE; 375584aa810SFred Isaman for (i = 0; i < npages; i++) { 376584aa810SFred Isaman struct nfs_page *req; 377bf5fc402STrond Myklebust unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); 378584aa810SFred Isaman /* XXX do we need to do the eof zeroing found in async_filler? */ 37928b1d3f5STrond Myklebust req = nfs_create_request(dreq->ctx, pagevec[i], 380584aa810SFred Isaman pgbase, req_len); 381584aa810SFred Isaman if (IS_ERR(req)) { 382584aa810SFred Isaman result = PTR_ERR(req); 383dbae4c73STrond Myklebust break; 384584aa810SFred Isaman } 385584aa810SFred Isaman req->wb_index = pos >> PAGE_SHIFT; 386584aa810SFred Isaman req->wb_offset = pos & ~PAGE_MASK; 38791f79c43SAl Viro if (!nfs_pageio_add_request(&desc, req)) { 38891f79c43SAl Viro result = desc.pg_error; 389584aa810SFred Isaman nfs_release_request(req); 390584aa810SFred Isaman break; 391584aa810SFred Isaman } 392584aa810SFred Isaman pgbase = 0; 393584aa810SFred Isaman bytes -= req_len; 39491f79c43SAl Viro requested_bytes += req_len; 395584aa810SFred Isaman pos += req_len; 39635754bc0SPeng Tao dreq->bytes_left -= req_len; 397584aa810SFred Isaman } 3986d74743bSTrond Myklebust nfs_direct_release_pages(pagevec, npages); 39991f79c43SAl Viro kvfree(pagevec); 40019f73787SChuck Lever if (result < 0) 40119f73787SChuck Lever break; 40219f73787SChuck Lever } 40319f73787SChuck Lever 404584aa810SFred Isaman nfs_pageio_complete(&desc); 405584aa810SFred Isaman 406839f7ad6SChuck Lever /* 407839f7ad6SChuck Lever * If no bytes were started, return the error, and let the 408839f7ad6SChuck Lever * generic layer handle the completion. 409839f7ad6SChuck Lever */ 410839f7ad6SChuck Lever if (requested_bytes == 0) { 411d03727b2SOlga Kornievskaia inode_dio_end(inode); 41265caafd0SOlga Kornievskaia nfs_direct_req_release(dreq); 413839f7ad6SChuck Lever return result < 0 ? result : -EIO; 414839f7ad6SChuck Lever } 415839f7ad6SChuck Lever 41619f73787SChuck Lever if (put_dreq(dreq)) 417f7b5c340STrond Myklebust nfs_direct_complete(dreq); 41885128b2bSAl Viro return requested_bytes; 41919f73787SChuck Lever } 42019f73787SChuck Lever 42114a3ec79SChristoph Hellwig /** 42214a3ec79SChristoph Hellwig * nfs_file_direct_read - file direct read operation for NFS files 42314a3ec79SChristoph Hellwig * @iocb: target I/O control block 424619d30b4SAl Viro * @iter: vector of user buffers into which to read data 42564158668SNeilBrown * @swap: flag indicating this is swap IO, not O_DIRECT IO 42614a3ec79SChristoph Hellwig * 42714a3ec79SChristoph Hellwig * We use this function for direct reads instead of calling 42814a3ec79SChristoph Hellwig * generic_file_aio_read() in order to avoid gfar's check to see if 42914a3ec79SChristoph Hellwig * the request starts before the end of the file. For that check 43014a3ec79SChristoph Hellwig * to work, we must generate a GETATTR before each direct read, and 43114a3ec79SChristoph Hellwig * even then there is a window between the GETATTR and the subsequent 43214a3ec79SChristoph Hellwig * READ where the file size could change. Our preference is simply 43314a3ec79SChristoph Hellwig * to do all reads the application wants, and the server will take 43414a3ec79SChristoph Hellwig * care of managing the end of file boundary. 43514a3ec79SChristoph Hellwig * 43614a3ec79SChristoph Hellwig * This function also eliminates unnecessarily updating the file's 43714a3ec79SChristoph Hellwig * atime locally, as the NFS server sets the file's atime, and this 43814a3ec79SChristoph Hellwig * client must read the updated atime from the server back into its 43914a3ec79SChristoph Hellwig * cache. 44014a3ec79SChristoph Hellwig */ 44164158668SNeilBrown ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, 44264158668SNeilBrown bool swap) 4431da177e4SLinus Torvalds { 44414a3ec79SChristoph Hellwig struct file *file = iocb->ki_filp; 44514a3ec79SChristoph Hellwig struct address_space *mapping = file->f_mapping; 44614a3ec79SChristoph Hellwig struct inode *inode = mapping->host; 4471da177e4SLinus Torvalds struct nfs_direct_req *dreq; 448b3c54de6STrond Myklebust struct nfs_lock_context *l_ctx; 44986b93667SColin Ian King ssize_t result, requested; 450a6cbcd4aSAl Viro size_t count = iov_iter_count(iter); 45114a3ec79SChristoph Hellwig nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); 45214a3ec79SChristoph Hellwig 45314a3ec79SChristoph Hellwig dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n", 454c8b8e32dSChristoph Hellwig file, count, (long long) iocb->ki_pos); 45514a3ec79SChristoph Hellwig 45614a3ec79SChristoph Hellwig result = 0; 45714a3ec79SChristoph Hellwig if (!count) 45814a3ec79SChristoph Hellwig goto out; 45914a3ec79SChristoph Hellwig 46014a3ec79SChristoph Hellwig task_io_account_read(count); 46114a3ec79SChristoph Hellwig 46214a3ec79SChristoph Hellwig result = -ENOMEM; 463607f31e8STrond Myklebust dreq = nfs_direct_req_alloc(); 464f11ac8dbSTrond Myklebust if (dreq == NULL) 465a5864c99STrond Myklebust goto out; 4661da177e4SLinus Torvalds 46791d5b470SChuck Lever dreq->inode = inode; 468ed3743a6SWeston Andros Adamson dreq->bytes_left = dreq->max_count = count; 469c8b8e32dSChristoph Hellwig dreq->io_start = iocb->ki_pos; 470cd3758e3STrond Myklebust dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); 471b3c54de6STrond Myklebust l_ctx = nfs_get_lock_context(dreq->ctx); 472b3c54de6STrond Myklebust if (IS_ERR(l_ctx)) { 473b3c54de6STrond Myklebust result = PTR_ERR(l_ctx); 4748605cf0eSMisono Tomohiro nfs_direct_req_release(dreq); 475f11ac8dbSTrond Myklebust goto out_release; 476b3c54de6STrond Myklebust } 477b3c54de6STrond Myklebust dreq->l_ctx = l_ctx; 478487b8372SChuck Lever if (!is_sync_kiocb(iocb)) 479487b8372SChuck Lever dreq->iocb = iocb; 4801da177e4SLinus Torvalds 481ad3cba22SDave Kleikamp if (iter_is_iovec(iter)) 482ad3cba22SDave Kleikamp dreq->flags = NFS_ODIRECT_SHOULD_DIRTY; 483ad3cba22SDave Kleikamp 48464158668SNeilBrown if (!swap) 485a5864c99STrond Myklebust nfs_start_io_direct(inode); 486a5864c99STrond Myklebust 487619d30b4SAl Viro NFS_I(inode)->read_io += count; 48885128b2bSAl Viro requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); 489d0b9875dSChristoph Hellwig 49064158668SNeilBrown if (!swap) 491a5864c99STrond Myklebust nfs_end_io_direct(inode); 492d0b9875dSChristoph Hellwig 49385128b2bSAl Viro if (requested > 0) { 494bc0fb201SChuck Lever result = nfs_direct_wait(dreq); 49585128b2bSAl Viro if (result > 0) { 49685128b2bSAl Viro requested -= result; 497c8b8e32dSChristoph Hellwig iocb->ki_pos += result; 49814a3ec79SChristoph Hellwig } 49985128b2bSAl Viro iov_iter_revert(iter, requested); 50085128b2bSAl Viro } else { 50185128b2bSAl Viro result = requested; 50285128b2bSAl Viro } 503d0b9875dSChristoph Hellwig 504f11ac8dbSTrond Myklebust out_release: 505b4946ffbSTrond Myklebust nfs_direct_req_release(dreq); 506f11ac8dbSTrond Myklebust out: 5071da177e4SLinus Torvalds return result; 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds 510085d1e33STom Haynes static void 511ed5d588fSTrond Myklebust nfs_direct_join_group(struct list_head *list, struct inode *inode) 512ed5d588fSTrond Myklebust { 513ed5d588fSTrond Myklebust struct nfs_page *req, *next; 514ed5d588fSTrond Myklebust 515ed5d588fSTrond Myklebust list_for_each_entry(req, list, wb_list) { 516ed5d588fSTrond Myklebust if (req->wb_head != req || req->wb_this_page == req) 517ed5d588fSTrond Myklebust continue; 518ed5d588fSTrond Myklebust for (next = req->wb_this_page; 519ed5d588fSTrond Myklebust next != req->wb_head; 520ed5d588fSTrond Myklebust next = next->wb_this_page) { 521ed5d588fSTrond Myklebust nfs_list_remove_request(next); 522ed5d588fSTrond Myklebust nfs_release_request(next); 523ed5d588fSTrond Myklebust } 524ed5d588fSTrond Myklebust nfs_join_page_group(req, inode); 525ed5d588fSTrond Myklebust } 526ed5d588fSTrond Myklebust } 527ed5d588fSTrond Myklebust 528ed5d588fSTrond Myklebust static void 529085d1e33STom Haynes nfs_direct_write_scan_commit_list(struct inode *inode, 530085d1e33STom Haynes struct list_head *list, 531085d1e33STom Haynes struct nfs_commit_info *cinfo) 532085d1e33STom Haynes { 533e824f99aSTrond Myklebust mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); 5349c455a8cSTrond Myklebust pnfs_recover_commit_reqs(list, cinfo); 535085d1e33STom Haynes nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0); 536e824f99aSTrond Myklebust mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); 537085d1e33STom Haynes } 538085d1e33STom Haynes 539fad61490STrond Myklebust static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) 5401da177e4SLinus Torvalds { 5411763da12SFred Isaman struct nfs_pageio_descriptor desc; 5421763da12SFred Isaman struct nfs_page *req, *tmp; 5431763da12SFred Isaman LIST_HEAD(reqs); 5441763da12SFred Isaman struct nfs_commit_info cinfo; 5451763da12SFred Isaman LIST_HEAD(failed); 5461763da12SFred Isaman 5471763da12SFred Isaman nfs_init_cinfo_from_dreq(&cinfo, dreq); 548085d1e33STom Haynes nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); 5491da177e4SLinus Torvalds 550ed5d588fSTrond Myklebust nfs_direct_join_group(&reqs, dreq->inode); 551ed5d588fSTrond Myklebust 552fad61490STrond Myklebust dreq->count = 0; 553031d73edSTrond Myklebust dreq->max_count = 0; 554031d73edSTrond Myklebust list_for_each_entry(req, &reqs, wb_list) 555031d73edSTrond Myklebust dreq->max_count += req->wb_bytes; 556a5314a74STrond Myklebust nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo); 557607f31e8STrond Myklebust get_dreq(dreq); 5581da177e4SLinus Torvalds 559a20c93e3SChristoph Hellwig nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false, 5601763da12SFred Isaman &nfs_direct_write_completion_ops); 5611763da12SFred Isaman desc.pg_dreq = dreq; 562607f31e8STrond Myklebust 5631763da12SFred Isaman list_for_each_entry_safe(req, tmp, &reqs, wb_list) { 56433344e0fSTrond Myklebust /* Bump the transmission count */ 56533344e0fSTrond Myklebust req->wb_nio++; 5661763da12SFred Isaman if (!nfs_pageio_add_request(&desc, req)) { 567078b5fd9STrond Myklebust nfs_list_move_request(req, &failed); 568fe238e60SDave Wysochanski spin_lock(&cinfo.inode->i_lock); 5691763da12SFred Isaman dreq->flags = 0; 570d600ad1fSPeng Tao if (desc.pg_error < 0) 571d600ad1fSPeng Tao dreq->error = desc.pg_error; 572d600ad1fSPeng Tao else 5731763da12SFred Isaman dreq->error = -EIO; 574fe238e60SDave Wysochanski spin_unlock(&cinfo.inode->i_lock); 5751763da12SFred Isaman } 5765a695da2STrond Myklebust nfs_release_request(req); 5771763da12SFred Isaman } 5781763da12SFred Isaman nfs_pageio_complete(&desc); 579607f31e8STrond Myklebust 5804035c248STrond Myklebust while (!list_empty(&failed)) { 5814035c248STrond Myklebust req = nfs_list_entry(failed.next); 5824035c248STrond Myklebust nfs_list_remove_request(req); 5831d1afcbcSTrond Myklebust nfs_unlock_and_release_request(req); 5844035c248STrond Myklebust } 585607f31e8STrond Myklebust 586607f31e8STrond Myklebust if (put_dreq(dreq)) 5874d3b55d3SAnna Schumaker nfs_direct_write_complete(dreq); 588fad61490STrond Myklebust } 5891da177e4SLinus Torvalds 5901763da12SFred Isaman static void nfs_direct_commit_complete(struct nfs_commit_data *data) 591fad61490STrond Myklebust { 5921f28476dSTrond Myklebust const struct nfs_writeverf *verf = data->res.verf; 5930b7c0153SFred Isaman struct nfs_direct_req *dreq = data->dreq; 5941763da12SFred Isaman struct nfs_commit_info cinfo; 5951763da12SFred Isaman struct nfs_page *req; 596c9d8f89dSTrond Myklebust int status = data->task.tk_status; 597c9d8f89dSTrond Myklebust 598fb5f7f20STrond Myklebust if (status < 0) { 599fb5f7f20STrond Myklebust /* Errors in commit are fatal */ 600fb5f7f20STrond Myklebust dreq->error = status; 601fb5f7f20STrond Myklebust dreq->max_count = 0; 602fb5f7f20STrond Myklebust dreq->count = 0; 603fb5f7f20STrond Myklebust dreq->flags = NFS_ODIRECT_DONE; 604fb5f7f20STrond Myklebust } else if (dreq->flags == NFS_ODIRECT_DONE) 605fb5f7f20STrond Myklebust status = dreq->error; 606fb5f7f20STrond Myklebust 6071763da12SFred Isaman nfs_init_cinfo_from_dreq(&cinfo, dreq); 608fad61490STrond Myklebust 6091763da12SFred Isaman while (!list_empty(&data->pages)) { 6101763da12SFred Isaman req = nfs_list_entry(data->pages.next); 6111763da12SFred Isaman nfs_list_remove_request(req); 6121f28476dSTrond Myklebust if (status >= 0 && !nfs_write_match_verf(verf, req)) { 6131f28476dSTrond Myklebust dreq->flags = NFS_ODIRECT_RESCHED_WRITES; 61433344e0fSTrond Myklebust /* 61533344e0fSTrond Myklebust * Despite the reboot, the write was successful, 61633344e0fSTrond Myklebust * so reset wb_nio. 61733344e0fSTrond Myklebust */ 61833344e0fSTrond Myklebust req->wb_nio = 0; 619b57ff130SWeston Andros Adamson nfs_mark_request_commit(req, NULL, &cinfo, 0); 6201f28476dSTrond Myklebust } else /* Error or match */ 621906369e4SFred Isaman nfs_release_request(req); 6221d1afcbcSTrond Myklebust nfs_unlock_and_release_request(req); 623fad61490STrond Myklebust } 624fad61490STrond Myklebust 625133a48abSTrond Myklebust if (nfs_commit_end(cinfo.mds)) 6264d3b55d3SAnna Schumaker nfs_direct_write_complete(dreq); 6271763da12SFred Isaman } 6281763da12SFred Isaman 629b20135d0STrond Myklebust static void nfs_direct_resched_write(struct nfs_commit_info *cinfo, 630b20135d0STrond Myklebust struct nfs_page *req) 6311763da12SFred Isaman { 632b20135d0STrond Myklebust struct nfs_direct_req *dreq = cinfo->dreq; 633b20135d0STrond Myklebust 634b20135d0STrond Myklebust spin_lock(&dreq->lock); 635fb5f7f20STrond Myklebust if (dreq->flags != NFS_ODIRECT_DONE) 636b20135d0STrond Myklebust dreq->flags = NFS_ODIRECT_RESCHED_WRITES; 637b20135d0STrond Myklebust spin_unlock(&dreq->lock); 638b20135d0STrond Myklebust nfs_mark_request_commit(req, NULL, cinfo, 0); 6391763da12SFred Isaman } 6401763da12SFred Isaman 6411763da12SFred Isaman static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = { 6421763da12SFred Isaman .completion = nfs_direct_commit_complete, 643b20135d0STrond Myklebust .resched_write = nfs_direct_resched_write, 644fad61490STrond Myklebust }; 645fad61490STrond Myklebust 646fad61490STrond Myklebust static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) 647fad61490STrond Myklebust { 6481763da12SFred Isaman int res; 6491763da12SFred Isaman struct nfs_commit_info cinfo; 6501763da12SFred Isaman LIST_HEAD(mds_list); 651fad61490STrond Myklebust 6521763da12SFred Isaman nfs_init_cinfo_from_dreq(&cinfo, dreq); 6531763da12SFred Isaman nfs_scan_commit(dreq->inode, &mds_list, &cinfo); 6541763da12SFred Isaman res = nfs_generic_commit_list(dreq->inode, &mds_list, 0, &cinfo); 6551763da12SFred Isaman if (res < 0) /* res == -ENOMEM */ 6561763da12SFred Isaman nfs_direct_write_reschedule(dreq); 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 659fb5f7f20STrond Myklebust static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq) 660fb5f7f20STrond Myklebust { 661fb5f7f20STrond Myklebust struct nfs_commit_info cinfo; 662fb5f7f20STrond Myklebust struct nfs_page *req; 663fb5f7f20STrond Myklebust LIST_HEAD(reqs); 664fb5f7f20STrond Myklebust 665fb5f7f20STrond Myklebust nfs_init_cinfo_from_dreq(&cinfo, dreq); 666fb5f7f20STrond Myklebust nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); 667fb5f7f20STrond Myklebust 668fb5f7f20STrond Myklebust while (!list_empty(&reqs)) { 669fb5f7f20STrond Myklebust req = nfs_list_entry(reqs.next); 670fb5f7f20STrond Myklebust nfs_list_remove_request(req); 671f02cec9dSTrond Myklebust nfs_release_request(req); 672fb5f7f20STrond Myklebust nfs_unlock_and_release_request(req); 673fb5f7f20STrond Myklebust } 674fb5f7f20STrond Myklebust } 675fb5f7f20STrond Myklebust 6761763da12SFred Isaman static void nfs_direct_write_schedule_work(struct work_struct *work) 6771da177e4SLinus Torvalds { 6781763da12SFred Isaman struct nfs_direct_req *dreq = container_of(work, struct nfs_direct_req, work); 679fad61490STrond Myklebust int flags = dreq->flags; 6801da177e4SLinus Torvalds 681fad61490STrond Myklebust dreq->flags = 0; 682fad61490STrond Myklebust switch (flags) { 683fad61490STrond Myklebust case NFS_ODIRECT_DO_COMMIT: 684fad61490STrond Myklebust nfs_direct_commit_schedule(dreq); 6851da177e4SLinus Torvalds break; 686fad61490STrond Myklebust case NFS_ODIRECT_RESCHED_WRITES: 687fad61490STrond Myklebust nfs_direct_write_reschedule(dreq); 6881da177e4SLinus Torvalds break; 6891da177e4SLinus Torvalds default: 690fb5f7f20STrond Myklebust nfs_direct_write_clear_reqs(dreq); 691f7b5c340STrond Myklebust nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping); 692f7b5c340STrond Myklebust nfs_direct_complete(dreq); 6931da177e4SLinus Torvalds } 694fad61490STrond Myklebust } 695fad61490STrond Myklebust 6964d3b55d3SAnna Schumaker static void nfs_direct_write_complete(struct nfs_direct_req *dreq) 697fad61490STrond Myklebust { 69846483c2eSNeilBrown queue_work(nfsiod_workqueue, &dreq->work); /* Calls nfs_direct_write_schedule_work */ 699fad61490STrond Myklebust } 7001763da12SFred Isaman 7011763da12SFred Isaman static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) 7021763da12SFred Isaman { 7031763da12SFred Isaman struct nfs_direct_req *dreq = hdr->dreq; 7041763da12SFred Isaman struct nfs_commit_info cinfo; 7051763da12SFred Isaman struct nfs_page *req = nfs_list_entry(hdr->pages.next); 7063731d44bSTrond Myklebust int flags = NFS_ODIRECT_DONE; 7071763da12SFred Isaman 7081763da12SFred Isaman nfs_init_cinfo_from_dreq(&cinfo, dreq); 7091763da12SFred Isaman 7101763da12SFred Isaman spin_lock(&dreq->lock); 711eb2c50daSTrond Myklebust if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) { 712eb2c50daSTrond Myklebust spin_unlock(&dreq->lock); 713eb2c50daSTrond Myklebust goto out_put; 714eb2c50daSTrond Myklebust } 715eb2c50daSTrond Myklebust 716031d73edSTrond Myklebust nfs_direct_count_bytes(dreq, hdr); 7171f28476dSTrond Myklebust if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) { 7183731d44bSTrond Myklebust if (!dreq->flags) 7191763da12SFred Isaman dreq->flags = NFS_ODIRECT_DO_COMMIT; 7203731d44bSTrond Myklebust flags = dreq->flags; 7211763da12SFred Isaman } 7221763da12SFred Isaman spin_unlock(&dreq->lock); 7231763da12SFred Isaman 7241763da12SFred Isaman while (!list_empty(&hdr->pages)) { 7252bfc6e56SWeston Andros Adamson 7261763da12SFred Isaman req = nfs_list_entry(hdr->pages.next); 7271763da12SFred Isaman nfs_list_remove_request(req); 7283731d44bSTrond Myklebust if (flags == NFS_ODIRECT_DO_COMMIT) { 72904277086STrond Myklebust kref_get(&req->wb_kref); 730ba838a75SChuck Lever memcpy(&req->wb_verf, &hdr->verf.verifier, 731ba838a75SChuck Lever sizeof(req->wb_verf)); 732b57ff130SWeston Andros Adamson nfs_mark_request_commit(req, hdr->lseg, &cinfo, 733b57ff130SWeston Andros Adamson hdr->ds_commit_idx); 7343731d44bSTrond Myklebust } else if (flags == NFS_ODIRECT_RESCHED_WRITES) { 7353731d44bSTrond Myklebust kref_get(&req->wb_kref); 7363731d44bSTrond Myklebust nfs_mark_request_commit(req, NULL, &cinfo, 0); 7371763da12SFred Isaman } 7381d1afcbcSTrond Myklebust nfs_unlock_and_release_request(req); 7391763da12SFred Isaman } 7401763da12SFred Isaman 7411763da12SFred Isaman out_put: 7421763da12SFred Isaman if (put_dreq(dreq)) 7434d3b55d3SAnna Schumaker nfs_direct_write_complete(dreq); 7441763da12SFred Isaman hdr->release(hdr); 7451763da12SFred Isaman } 7461763da12SFred Isaman 747df3accb8STrond Myklebust static void nfs_write_sync_pgio_error(struct list_head *head, int error) 7483e9e0ca3STrond Myklebust { 7493e9e0ca3STrond Myklebust struct nfs_page *req; 7503e9e0ca3STrond Myklebust 7513e9e0ca3STrond Myklebust while (!list_empty(head)) { 7523e9e0ca3STrond Myklebust req = nfs_list_entry(head->next); 7533e9e0ca3STrond Myklebust nfs_list_remove_request(req); 7541d1afcbcSTrond Myklebust nfs_unlock_and_release_request(req); 7553e9e0ca3STrond Myklebust } 7563e9e0ca3STrond Myklebust } 7573e9e0ca3STrond Myklebust 758dc602dd7STrond Myklebust static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr) 759dc602dd7STrond Myklebust { 760dc602dd7STrond Myklebust struct nfs_direct_req *dreq = hdr->dreq; 761dc602dd7STrond Myklebust 762dc602dd7STrond Myklebust spin_lock(&dreq->lock); 763dc602dd7STrond Myklebust if (dreq->error == 0) { 764dc602dd7STrond Myklebust dreq->flags = NFS_ODIRECT_RESCHED_WRITES; 765dc602dd7STrond Myklebust /* fake unstable write to let common nfs resend pages */ 766dc602dd7STrond Myklebust hdr->verf.committed = NFS_UNSTABLE; 7674daaeba9STrond Myklebust hdr->good_bytes = hdr->args.offset + hdr->args.count - 7684daaeba9STrond Myklebust hdr->io_start; 769dc602dd7STrond Myklebust } 770dc602dd7STrond Myklebust spin_unlock(&dreq->lock); 771dc602dd7STrond Myklebust } 772dc602dd7STrond Myklebust 7731763da12SFred Isaman static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { 7743e9e0ca3STrond Myklebust .error_cleanup = nfs_write_sync_pgio_error, 7751763da12SFred Isaman .init_hdr = nfs_direct_pgio_init, 7761763da12SFred Isaman .completion = nfs_direct_write_completion, 777dc602dd7STrond Myklebust .reschedule_io = nfs_direct_write_reschedule_io, 7781763da12SFred Isaman }; 7791763da12SFred Isaman 78091f79c43SAl Viro 78191f79c43SAl Viro /* 78291f79c43SAl Viro * NB: Return the value of the first error return code. Subsequent 78391f79c43SAl Viro * errors after the first one are ignored. 78491f79c43SAl Viro */ 78591f79c43SAl Viro /* 78691f79c43SAl Viro * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE 78791f79c43SAl Viro * operation. If nfs_writedata_alloc() or get_user_pages() fails, 78891f79c43SAl Viro * bail and stop sending more writes. Write length accounting is 78991f79c43SAl Viro * handled automatically by nfs_direct_write_result(). Otherwise, if 79091f79c43SAl Viro * no requests have been sent, just return an error. 79191f79c43SAl Viro */ 79219f73787SChuck Lever static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, 793619d30b4SAl Viro struct iov_iter *iter, 794c265de25SNeilBrown loff_t pos, int ioflags) 79519f73787SChuck Lever { 7961763da12SFred Isaman struct nfs_pageio_descriptor desc; 7971d59d61fSTrond Myklebust struct inode *inode = dreq->inode; 79819f73787SChuck Lever ssize_t result = 0; 79919f73787SChuck Lever size_t requested_bytes = 0; 80091f79c43SAl Viro size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE); 80119f73787SChuck Lever 802c265de25SNeilBrown nfs_pageio_init_write(&desc, inode, ioflags, false, 8031763da12SFred Isaman &nfs_direct_write_completion_ops); 8041763da12SFred Isaman desc.pg_dreq = dreq; 80519f73787SChuck Lever get_dreq(dreq); 806fe0f07d0SJens Axboe inode_dio_begin(inode); 80719f73787SChuck Lever 80891f79c43SAl Viro NFS_I(inode)->write_io += iov_iter_count(iter); 80991f79c43SAl Viro while (iov_iter_count(iter)) { 81091f79c43SAl Viro struct page **pagevec; 81191f79c43SAl Viro size_t bytes; 81291f79c43SAl Viro size_t pgbase; 81391f79c43SAl Viro unsigned npages, i; 81491f79c43SAl Viro 81591f79c43SAl Viro result = iov_iter_get_pages_alloc(iter, &pagevec, 81691f79c43SAl Viro wsize, &pgbase); 81719f73787SChuck Lever if (result < 0) 81819f73787SChuck Lever break; 81991f79c43SAl Viro 82091f79c43SAl Viro bytes = result; 82191f79c43SAl Viro iov_iter_advance(iter, bytes); 82291f79c43SAl Viro npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE; 82391f79c43SAl Viro for (i = 0; i < npages; i++) { 82491f79c43SAl Viro struct nfs_page *req; 82591f79c43SAl Viro unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); 82691f79c43SAl Viro 82728b1d3f5STrond Myklebust req = nfs_create_request(dreq->ctx, pagevec[i], 82891f79c43SAl Viro pgbase, req_len); 82991f79c43SAl Viro if (IS_ERR(req)) { 83091f79c43SAl Viro result = PTR_ERR(req); 83119f73787SChuck Lever break; 83291f79c43SAl Viro } 8330a00b77bSWeston Andros Adamson 834d600ad1fSPeng Tao if (desc.pg_error < 0) { 835d600ad1fSPeng Tao nfs_free_request(req); 836d600ad1fSPeng Tao result = desc.pg_error; 837d600ad1fSPeng Tao break; 838d600ad1fSPeng Tao } 8390a00b77bSWeston Andros Adamson 84091f79c43SAl Viro nfs_lock_request(req); 84191f79c43SAl Viro req->wb_index = pos >> PAGE_SHIFT; 84291f79c43SAl Viro req->wb_offset = pos & ~PAGE_MASK; 84391f79c43SAl Viro if (!nfs_pageio_add_request(&desc, req)) { 84491f79c43SAl Viro result = desc.pg_error; 84591f79c43SAl Viro nfs_unlock_and_release_request(req); 84691f79c43SAl Viro break; 84791f79c43SAl Viro } 84891f79c43SAl Viro pgbase = 0; 84991f79c43SAl Viro bytes -= req_len; 85091f79c43SAl Viro requested_bytes += req_len; 85191f79c43SAl Viro pos += req_len; 85291f79c43SAl Viro dreq->bytes_left -= req_len; 85391f79c43SAl Viro } 85491f79c43SAl Viro nfs_direct_release_pages(pagevec, npages); 85591f79c43SAl Viro kvfree(pagevec); 85691f79c43SAl Viro if (result < 0) 85791f79c43SAl Viro break; 85819f73787SChuck Lever } 8591763da12SFred Isaman nfs_pageio_complete(&desc); 86019f73787SChuck Lever 861839f7ad6SChuck Lever /* 862839f7ad6SChuck Lever * If no bytes were started, return the error, and let the 863839f7ad6SChuck Lever * generic layer handle the completion. 864839f7ad6SChuck Lever */ 865839f7ad6SChuck Lever if (requested_bytes == 0) { 866d03727b2SOlga Kornievskaia inode_dio_end(inode); 86765caafd0SOlga Kornievskaia nfs_direct_req_release(dreq); 868839f7ad6SChuck Lever return result < 0 ? result : -EIO; 869839f7ad6SChuck Lever } 870839f7ad6SChuck Lever 87119f73787SChuck Lever if (put_dreq(dreq)) 8724d3b55d3SAnna Schumaker nfs_direct_write_complete(dreq); 87385128b2bSAl Viro return requested_bytes; 87419f73787SChuck Lever } 87519f73787SChuck Lever 8761da177e4SLinus Torvalds /** 8771da177e4SLinus Torvalds * nfs_file_direct_write - file direct write operation for NFS files 8781da177e4SLinus Torvalds * @iocb: target I/O control block 879619d30b4SAl Viro * @iter: vector of user buffers from which to write data 88064158668SNeilBrown * @swap: flag indicating this is swap IO, not O_DIRECT IO 8811da177e4SLinus Torvalds * 8821da177e4SLinus Torvalds * We use this function for direct writes instead of calling 8831da177e4SLinus Torvalds * generic_file_aio_write() in order to avoid taking the inode 8841da177e4SLinus Torvalds * semaphore and updating the i_size. The NFS server will set 8851da177e4SLinus Torvalds * the new i_size and this client must read the updated size 8861da177e4SLinus Torvalds * back into its cache. We let the server do generic write 8871da177e4SLinus Torvalds * parameter checking and report problems. 8881da177e4SLinus Torvalds * 8891da177e4SLinus Torvalds * We eliminate local atime updates, see direct read above. 8901da177e4SLinus Torvalds * 8911da177e4SLinus Torvalds * We avoid unnecessary page cache invalidations for normal cached 8921da177e4SLinus Torvalds * readers of this file. 8931da177e4SLinus Torvalds * 8941da177e4SLinus Torvalds * Note that O_APPEND is not supported for NFS direct writes, as there 8951da177e4SLinus Torvalds * is no atomic O_APPEND write facility in the NFS protocol. 8961da177e4SLinus Torvalds */ 89764158668SNeilBrown ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, 89864158668SNeilBrown bool swap) 8991da177e4SLinus Torvalds { 9009a74a2b8SColin Ian King ssize_t result, requested; 90189698b24STrond Myklebust size_t count; 9021da177e4SLinus Torvalds struct file *file = iocb->ki_filp; 9031da177e4SLinus Torvalds struct address_space *mapping = file->f_mapping; 90422cd1bf1SChristoph Hellwig struct inode *inode = mapping->host; 90522cd1bf1SChristoph Hellwig struct nfs_direct_req *dreq; 90622cd1bf1SChristoph Hellwig struct nfs_lock_context *l_ctx; 90765a4a1caSAl Viro loff_t pos, end; 908c216fd70SChuck Lever 9096de1472fSAl Viro dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", 9103309dd04SAl Viro file, iov_iter_count(iter), (long long) iocb->ki_pos); 911027445c3SBadari Pulavarty 91264158668SNeilBrown if (swap) 91364158668SNeilBrown /* bypass generic checks */ 91464158668SNeilBrown result = iov_iter_count(iter); 91564158668SNeilBrown else 91689698b24STrond Myklebust result = generic_write_checks(iocb, iter); 91789698b24STrond Myklebust if (result <= 0) 91889698b24STrond Myklebust return result; 91989698b24STrond Myklebust count = result; 92089698b24STrond Myklebust nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); 9213309dd04SAl Viro 9223309dd04SAl Viro pos = iocb->ki_pos; 92309cbfeafSKirill A. Shutemov end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT; 924ce1a8e67SChuck Lever 92589698b24STrond Myklebust task_io_account_write(count); 9267ec10f26SKonstantin Khlebnikov 92722cd1bf1SChristoph Hellwig result = -ENOMEM; 92822cd1bf1SChristoph Hellwig dreq = nfs_direct_req_alloc(); 92922cd1bf1SChristoph Hellwig if (!dreq) 930a5864c99STrond Myklebust goto out; 93122cd1bf1SChristoph Hellwig 93222cd1bf1SChristoph Hellwig dreq->inode = inode; 93389698b24STrond Myklebust dreq->bytes_left = dreq->max_count = count; 9345fadeb47SPeng Tao dreq->io_start = pos; 93522cd1bf1SChristoph Hellwig dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); 93622cd1bf1SChristoph Hellwig l_ctx = nfs_get_lock_context(dreq->ctx); 93722cd1bf1SChristoph Hellwig if (IS_ERR(l_ctx)) { 93822cd1bf1SChristoph Hellwig result = PTR_ERR(l_ctx); 9398605cf0eSMisono Tomohiro nfs_direct_req_release(dreq); 94022cd1bf1SChristoph Hellwig goto out_release; 94122cd1bf1SChristoph Hellwig } 94222cd1bf1SChristoph Hellwig dreq->l_ctx = l_ctx; 94322cd1bf1SChristoph Hellwig if (!is_sync_kiocb(iocb)) 94422cd1bf1SChristoph Hellwig dreq->iocb = iocb; 9459c455a8cSTrond Myklebust pnfs_init_ds_commit_info_ops(&dreq->ds_cinfo, inode); 94622cd1bf1SChristoph Hellwig 94764158668SNeilBrown if (swap) { 948c265de25SNeilBrown requested = nfs_direct_write_schedule_iovec(dreq, iter, pos, 949c265de25SNeilBrown FLUSH_STABLE); 95064158668SNeilBrown } else { 951a5864c99STrond Myklebust nfs_start_io_direct(inode); 952a5864c99STrond Myklebust 953c265de25SNeilBrown requested = nfs_direct_write_schedule_iovec(dreq, iter, pos, 954c265de25SNeilBrown FLUSH_COND_STABLE); 955a9ab5e84SChristoph Hellwig 956a9ab5e84SChristoph Hellwig if (mapping->nrpages) { 957a9ab5e84SChristoph Hellwig invalidate_inode_pages2_range(mapping, 95809cbfeafSKirill A. Shutemov pos >> PAGE_SHIFT, end); 959a9ab5e84SChristoph Hellwig } 960a9ab5e84SChristoph Hellwig 961a5864c99STrond Myklebust nfs_end_io_direct(inode); 96264158668SNeilBrown } 963a9ab5e84SChristoph Hellwig 96485128b2bSAl Viro if (requested > 0) { 96522cd1bf1SChristoph Hellwig result = nfs_direct_wait(dreq); 96622cd1bf1SChristoph Hellwig if (result > 0) { 96785128b2bSAl Viro requested -= result; 96822cd1bf1SChristoph Hellwig iocb->ki_pos = pos + result; 969e2592217SChristoph Hellwig /* XXX: should check the generic_write_sync retval */ 970e2592217SChristoph Hellwig generic_write_sync(iocb, result); 9711763da12SFred Isaman } 97285128b2bSAl Viro iov_iter_revert(iter, requested); 97385128b2bSAl Viro } else { 97485128b2bSAl Viro result = requested; 97522cd1bf1SChristoph Hellwig } 976a6b5a28eSDave Wysochanski nfs_fscache_invalidate(inode, FSCACHE_INVAL_DIO_WRITE); 97722cd1bf1SChristoph Hellwig out_release: 97822cd1bf1SChristoph Hellwig nfs_direct_req_release(dreq); 979a5864c99STrond Myklebust out: 98022cd1bf1SChristoph Hellwig return result; 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds 98388467055SChuck Lever /** 98488467055SChuck Lever * nfs_init_directcache - create a slab cache for nfs_direct_req structures 98588467055SChuck Lever * 98688467055SChuck Lever */ 987f7b422b1SDavid Howells int __init nfs_init_directcache(void) 9881da177e4SLinus Torvalds { 9891da177e4SLinus Torvalds nfs_direct_cachep = kmem_cache_create("nfs_direct_cache", 9901da177e4SLinus Torvalds sizeof(struct nfs_direct_req), 991fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 992fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 99320c2df83SPaul Mundt NULL); 9941da177e4SLinus Torvalds if (nfs_direct_cachep == NULL) 9951da177e4SLinus Torvalds return -ENOMEM; 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds return 0; 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds 100088467055SChuck Lever /** 1001f7b422b1SDavid Howells * nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures 100288467055SChuck Lever * 100388467055SChuck Lever */ 1004266bee88SDavid Brownell void nfs_destroy_directcache(void) 10051da177e4SLinus Torvalds { 10061a1d92c1SAlexey Dobriyan kmem_cache_destroy(nfs_direct_cachep); 10071da177e4SLinus Torvalds } 1008