Loading fs/nfs/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o CFLAGS_nfstrace.o += -I$(src) nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ direct.o pagelist.o read.o symlink.o unlink.o \ io.o direct.o pagelist.o read.o symlink.o unlink.o \ write.o namespace.o mount_clnt.o nfstrace.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_SYSCTL) += sysctl.o Loading fs/nfs/dir.c +31 −21 Original line number Diff line number Diff line Loading @@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st return NULL; } static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res, bool may_block) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_access_entry *cache; int err = -ENOENT; bool retry = true; int err; spin_lock(&inode->i_lock); for(;;) { if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) goto out_zap; cache = nfs_access_search_rbtree(inode, cred); err = -ENOENT; if (cache == NULL) goto out; if (!nfs_have_delegated_attributes(inode) && !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) goto out_stale; /* Found an entry, is our attribute cache valid? */ if (!nfs_attribute_cache_expired(inode) && !(nfsi->cache_validity & NFS_INO_INVALID_ATTR)) break; err = -ECHILD; if (!may_block) goto out; if (!retry) goto out_zap; spin_unlock(&inode->i_lock); err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); if (err) return err; spin_lock(&inode->i_lock); retry = false; } res->jiffies = cache->jiffies; res->cred = cache->cred; res->mask = cache->mask; Loading @@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str out: spin_unlock(&inode->i_lock); return err; out_stale: rb_erase(&cache->rb_node, &nfsi->access_cache); list_del(&cache->lru); spin_unlock(&inode->i_lock); nfs_access_free_entry(cache); return -ENOENT; out_zap: spin_unlock(&inode->i_lock); nfs_access_zap_cache(inode); Loading @@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred, cache = NULL; if (cache == NULL) goto out; if (!nfs_have_delegated_attributes(inode) && !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode); if (err) goto out; res->jiffies = cache->jiffies; res->cred = cache->cred; res->mask = cache->mask; err = 0; out: rcu_read_unlock(); return err; Loading Loading @@ -2381,18 +2390,19 @@ EXPORT_SYMBOL_GPL(nfs_access_set_mask); static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) { struct nfs_access_entry cache; bool may_block = (mask & MAY_NOT_BLOCK) == 0; int status; trace_nfs_access_enter(inode); status = nfs_access_get_cached_rcu(inode, cred, &cache); if (status != 0) status = nfs_access_get_cached(inode, cred, &cache); status = nfs_access_get_cached(inode, cred, &cache, may_block); if (status == 0) goto out_cached; status = -ECHILD; if (mask & MAY_NOT_BLOCK) if (!may_block) goto out; /* Be clever: ask server to check for all possible rights */ Loading fs/nfs/direct.c +32 −61 Original line number Diff line number Diff line Loading @@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, WARN_ON_ONCE(verfp->committed < 0); } static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1, const struct nfs_writeverf *v2) { return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier); } /* * nfs_direct_cmp_hdr_verf - compare verifier for pgio header * @dreq - direct request possibly spanning multiple servers Loading @@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, nfs_direct_set_hdr_verf(dreq, hdr); return 0; } return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); return nfs_direct_cmp_verf(verfp, &hdr->verf); } /* Loading @@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, if (verfp->committed < 0) return 1; return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); return nfs_direct_cmp_verf(verfp, &data->verf); } /** Loading Loading @@ -368,22 +374,10 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) * Synchronous I/O uses a stack-allocated iocb. Thus we can't trust * the iocb is still valid here if this is a synchronous request. */ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) static void nfs_direct_complete(struct nfs_direct_req *dreq) { struct inode *inode = dreq->inode; if (dreq->iocb && write) { loff_t pos = dreq->iocb->ki_pos + dreq->count; spin_lock(&inode->i_lock); if (i_size_read(inode) < pos) i_size_write(inode, pos); spin_unlock(&inode->i_lock); } if (write) nfs_zap_mapping(inode, inode->i_mapping); inode_dio_end(inode); if (dreq->iocb) { Loading Loading @@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) } out_put: if (put_dreq(dreq)) nfs_direct_complete(dreq, false); nfs_direct_complete(dreq); hdr->release(hdr); } Loading Loading @@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, } if (put_dreq(dreq)) nfs_direct_complete(dreq, false); nfs_direct_complete(dreq); return 0; } Loading Loading @@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) if (!count) goto out; inode_lock(inode); result = nfs_sync_mapping(mapping); if (result) goto out_unlock; task_io_account_read(count); result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (dreq == NULL) goto out_unlock; goto out; dreq->inode = inode; dreq->bytes_left = dreq->max_count = count; Loading @@ -610,10 +599,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; nfs_start_io_direct(inode); NFS_I(inode)->read_io += count; result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); inode_unlock(inode); nfs_end_io_direct(inode); if (!result) { result = nfs_direct_wait(dreq); Loading @@ -621,13 +612,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) iocb->ki_pos += result; } nfs_direct_req_release(dreq); return result; out_release: nfs_direct_req_release(dreq); out_unlock: inode_unlock(inode); out: return result; } Loading Loading @@ -659,6 +645,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); dreq->count = 0; dreq->verf.committed = NFS_INVALID_STABLE_HOW; nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo); for (i = 0; i < dreq->mirror_count; i++) dreq->mirrors[i].count = 0; get_dreq(dreq); Loading Loading @@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) nfs_direct_write_reschedule(dreq); break; default: nfs_direct_complete(dreq, true); nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping); nfs_direct_complete(dreq); } } Loading Loading @@ -993,6 +982,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) { ssize_t result = -EINVAL; size_t count; struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; Loading @@ -1003,34 +993,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", file, iov_iter_count(iter), (long long) iocb->ki_pos); nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, iov_iter_count(iter)); result = generic_write_checks(iocb, iter); if (result <= 0) return result; count = result; nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); pos = iocb->ki_pos; end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT; inode_lock(inode); result = nfs_sync_mapping(mapping); if (result) goto out_unlock; if (mapping->nrpages) { result = invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT, end); if (result) goto out_unlock; } task_io_account_write(iov_iter_count(iter)); task_io_account_write(count); result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (!dreq) goto out_unlock; goto out; dreq->inode = inode; dreq->bytes_left = dreq->max_count = iov_iter_count(iter); dreq->bytes_left = dreq->max_count = count; dreq->io_start = pos; dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); l_ctx = nfs_get_lock_context(dreq->ctx); Loading @@ -1042,6 +1022,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; nfs_start_io_direct(inode); result = nfs_direct_write_schedule_iovec(dreq, iter, pos); if (mapping->nrpages) { Loading @@ -1049,30 +1031,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) pos >> PAGE_SHIFT, end); } inode_unlock(inode); nfs_end_io_direct(inode); if (!result) { result = nfs_direct_wait(dreq); if (result > 0) { struct inode *inode = mapping->host; iocb->ki_pos = pos + result; spin_lock(&inode->i_lock); if (i_size_read(inode) < iocb->ki_pos) i_size_write(inode, iocb->ki_pos); spin_unlock(&inode->i_lock); /* XXX: should check the generic_write_sync retval */ generic_write_sync(iocb, result); } } nfs_direct_req_release(dreq); return result; out_release: nfs_direct_req_release(dreq); out_unlock: inode_unlock(inode); out: return result; } Loading fs/nfs/file.c +27 −69 Original line number Diff line number Diff line Loading @@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) iocb->ki_filp, iov_iter_count(to), (unsigned long) iocb->ki_pos); result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping); nfs_start_io_read(inode); result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); if (!result) { result = generic_file_read_iter(iocb, to); if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); } nfs_end_io_read(inode); return result; } EXPORT_SYMBOL_GPL(nfs_file_read); Loading @@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", filp, (unsigned long) count, (unsigned long long) *ppos); res = nfs_revalidate_mapping_protected(inode, filp->f_mapping); nfs_start_io_read(inode); res = nfs_revalidate_mapping(inode, filp->f_mapping); if (!res) { res = generic_file_splice_read(filp, ppos, pipe, count, flags); if (res > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res); } nfs_end_io_read(inode); return res; } EXPORT_SYMBOL_GPL(nfs_file_splice_read); Loading Loading @@ -272,16 +276,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) trace_nfs_fsync_enter(inode); inode_dio_wait(inode); do { ret = filemap_write_and_wait_range(inode->i_mapping, start, end); if (ret != 0) break; inode_lock(inode); ret = nfs_file_fsync_commit(file, start, end, datasync); if (!ret) ret = pnfs_sync_inode(inode, !!datasync); inode_unlock(inode); /* * If nfs_file_fsync_commit detected a server reboot, then * resend all dirty pages that might have been covered by Loading Loading @@ -359,19 +360,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, file, mapping->host->i_ino, len, (long long) pos); start: /* * Prevent starvation issues if someone is doing a consistency * sync-to-disk */ ret = wait_on_bit_action(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING, nfs_wait_bit_killable, TASK_KILLABLE); if (ret) return ret; /* * Wait for O_DIRECT to complete */ inode_dio_wait(mapping->host); page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; Loading Loading @@ -470,31 +458,8 @@ static void nfs_invalidate_page(struct page *page, unsigned int offset, */ static int nfs_release_page(struct page *page, gfp_t gfp) { struct address_space *mapping = page->mapping; dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); /* Always try to initiate a 'commit' if relevant, but only * wait for it if the caller allows blocking. Even then, * only wait 1 second and only if the 'bdi' is not congested. * Waiting indefinitely can cause deadlocks when the NFS * server is on this machine, when a new TCP connection is * needed and in other rare cases. There is no particular * need to wait extensively here. A short wait has the * benefit that someone else can worry about the freezer. */ if (mapping) { struct nfs_server *nfss = NFS_SERVER(mapping->host); nfs_commit_inode(mapping->host, 0); if (gfpflags_allow_blocking(gfp) && !bdi_write_congested(&nfss->backing_dev_info)) { wait_on_page_bit_killable_timeout(page, PG_private, HZ); if (PagePrivate(page)) set_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); } } /* If PagePrivate() is set, then the page is not freeable */ if (PagePrivate(page)) return 0; Loading Loading @@ -604,6 +569,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) filp, filp->f_mapping->host->i_ino, (long long)page_offset(page)); sb_start_pagefault(inode->i_sb); /* make sure the cache has finished storing the page */ nfs_fscache_wait_on_page_write(NFS_I(inode), page); Loading @@ -630,6 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) out_unlock: unlock_page(page); out: sb_end_pagefault(inode->i_sb); return ret; } Loading @@ -656,23 +624,17 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) struct inode *inode = file_inode(file); unsigned long written = 0; ssize_t result; size_t count = iov_iter_count(from); result = nfs_key_timeout_notify(file, inode); if (result) return result; if (iocb->ki_flags & IOCB_DIRECT) { result = generic_write_checks(iocb, from); if (result <= 0) return result; if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_write(iocb, from); } dprintk("NFS: write(%pD2, %zu@%Ld)\n", file, count, (long long) iocb->ki_pos); file, iov_iter_count(from), (long long) iocb->ki_pos); result = -EBUSY; if (IS_SWAPFILE(inode)) goto out_swapfile; /* Loading @@ -684,28 +646,33 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) goto out; } result = count; if (!count) nfs_start_io_write(inode); result = generic_write_checks(iocb, from); if (result > 0) { current->backing_dev_info = inode_to_bdi(inode); result = generic_perform_write(file, from, iocb->ki_pos); current->backing_dev_info = NULL; } nfs_end_io_write(inode); if (result <= 0) goto out; result = generic_file_write_iter(iocb, from); if (result > 0) written = result; written = generic_write_sync(iocb, result); iocb->ki_pos += written; /* Return error values */ if (result >= 0 && nfs_need_check_write(file, inode)) { if (nfs_need_check_write(file, inode)) { int err = vfs_fsync(file, 0); if (err < 0) result = err; } if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); out: return result; out_swapfile: printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); goto out; return -EBUSY; } EXPORT_SYMBOL_GPL(nfs_file_write); Loading Loading @@ -779,11 +746,6 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) return status; } static int is_time_granular(struct timespec *ts) { return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000)); } static int do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { Loading Loading @@ -817,12 +779,8 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) * This makes locking act as a cache coherency point. */ nfs_sync_mapping(filp->f_mapping); if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) { if (is_time_granular(&NFS_SERVER(inode)->time_delta)) __nfs_revalidate_inode(NFS_SERVER(inode), inode); else nfs_zap_caches(inode); } if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) nfs_zap_mapping(inode, filp->f_mapping); out: return status; } Loading fs/nfs/filelayout/filelayout.c +13 −5 Original line number Diff line number Diff line Loading @@ -255,13 +255,16 @@ static int filelayout_read_done_cb(struct rpc_task *task, static void filelayout_set_layoutcommit(struct nfs_pgio_header *hdr) { loff_t end_offs = 0; if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds || hdr->res.verf->committed != NFS_DATA_SYNC) hdr->res.verf->committed == NFS_FILE_SYNC) return; if (hdr->res.verf->committed == NFS_DATA_SYNC) end_offs = hdr->mds_offset + (loff_t)hdr->res.count; pnfs_set_layoutcommit(hdr->inode, hdr->lseg, hdr->mds_offset + hdr->res.count); /* Note: if the write is unstable, don't set end_offs until commit */ pnfs_set_layoutcommit(hdr->inode, hdr->lseg, end_offs); dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); } Loading Loading @@ -354,6 +357,12 @@ static int filelayout_write_done_cb(struct rpc_task *task, } filelayout_set_layoutcommit(hdr); /* zero out the fattr */ hdr->fattr.valid = 0; if (task->tk_status >= 0) nfs_writeback_update_inode(hdr); return 0; } Loading @@ -375,7 +384,6 @@ static int filelayout_commit_done_cb(struct rpc_task *task, return -EAGAIN; } if (data->verf.committed == NFS_UNSTABLE) pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb); return 0; Loading Loading
fs/nfs/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o CFLAGS_nfstrace.o += -I$(src) nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ direct.o pagelist.o read.o symlink.o unlink.o \ io.o direct.o pagelist.o read.o symlink.o unlink.o \ write.o namespace.o mount_clnt.o nfstrace.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_SYSCTL) += sysctl.o Loading
fs/nfs/dir.c +31 −21 Original line number Diff line number Diff line Loading @@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st return NULL; } static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res, bool may_block) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_access_entry *cache; int err = -ENOENT; bool retry = true; int err; spin_lock(&inode->i_lock); for(;;) { if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) goto out_zap; cache = nfs_access_search_rbtree(inode, cred); err = -ENOENT; if (cache == NULL) goto out; if (!nfs_have_delegated_attributes(inode) && !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) goto out_stale; /* Found an entry, is our attribute cache valid? */ if (!nfs_attribute_cache_expired(inode) && !(nfsi->cache_validity & NFS_INO_INVALID_ATTR)) break; err = -ECHILD; if (!may_block) goto out; if (!retry) goto out_zap; spin_unlock(&inode->i_lock); err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); if (err) return err; spin_lock(&inode->i_lock); retry = false; } res->jiffies = cache->jiffies; res->cred = cache->cred; res->mask = cache->mask; Loading @@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str out: spin_unlock(&inode->i_lock); return err; out_stale: rb_erase(&cache->rb_node, &nfsi->access_cache); list_del(&cache->lru); spin_unlock(&inode->i_lock); nfs_access_free_entry(cache); return -ENOENT; out_zap: spin_unlock(&inode->i_lock); nfs_access_zap_cache(inode); Loading @@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred, cache = NULL; if (cache == NULL) goto out; if (!nfs_have_delegated_attributes(inode) && !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode); if (err) goto out; res->jiffies = cache->jiffies; res->cred = cache->cred; res->mask = cache->mask; err = 0; out: rcu_read_unlock(); return err; Loading Loading @@ -2381,18 +2390,19 @@ EXPORT_SYMBOL_GPL(nfs_access_set_mask); static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) { struct nfs_access_entry cache; bool may_block = (mask & MAY_NOT_BLOCK) == 0; int status; trace_nfs_access_enter(inode); status = nfs_access_get_cached_rcu(inode, cred, &cache); if (status != 0) status = nfs_access_get_cached(inode, cred, &cache); status = nfs_access_get_cached(inode, cred, &cache, may_block); if (status == 0) goto out_cached; status = -ECHILD; if (mask & MAY_NOT_BLOCK) if (!may_block) goto out; /* Be clever: ask server to check for all possible rights */ Loading
fs/nfs/direct.c +32 −61 Original line number Diff line number Diff line Loading @@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, WARN_ON_ONCE(verfp->committed < 0); } static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1, const struct nfs_writeverf *v2) { return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier); } /* * nfs_direct_cmp_hdr_verf - compare verifier for pgio header * @dreq - direct request possibly spanning multiple servers Loading @@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, nfs_direct_set_hdr_verf(dreq, hdr); return 0; } return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); return nfs_direct_cmp_verf(verfp, &hdr->verf); } /* Loading @@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, if (verfp->committed < 0) return 1; return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); return nfs_direct_cmp_verf(verfp, &data->verf); } /** Loading Loading @@ -368,22 +374,10 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) * Synchronous I/O uses a stack-allocated iocb. Thus we can't trust * the iocb is still valid here if this is a synchronous request. */ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) static void nfs_direct_complete(struct nfs_direct_req *dreq) { struct inode *inode = dreq->inode; if (dreq->iocb && write) { loff_t pos = dreq->iocb->ki_pos + dreq->count; spin_lock(&inode->i_lock); if (i_size_read(inode) < pos) i_size_write(inode, pos); spin_unlock(&inode->i_lock); } if (write) nfs_zap_mapping(inode, inode->i_mapping); inode_dio_end(inode); if (dreq->iocb) { Loading Loading @@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) } out_put: if (put_dreq(dreq)) nfs_direct_complete(dreq, false); nfs_direct_complete(dreq); hdr->release(hdr); } Loading Loading @@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, } if (put_dreq(dreq)) nfs_direct_complete(dreq, false); nfs_direct_complete(dreq); return 0; } Loading Loading @@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) if (!count) goto out; inode_lock(inode); result = nfs_sync_mapping(mapping); if (result) goto out_unlock; task_io_account_read(count); result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (dreq == NULL) goto out_unlock; goto out; dreq->inode = inode; dreq->bytes_left = dreq->max_count = count; Loading @@ -610,10 +599,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; nfs_start_io_direct(inode); NFS_I(inode)->read_io += count; result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); inode_unlock(inode); nfs_end_io_direct(inode); if (!result) { result = nfs_direct_wait(dreq); Loading @@ -621,13 +612,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) iocb->ki_pos += result; } nfs_direct_req_release(dreq); return result; out_release: nfs_direct_req_release(dreq); out_unlock: inode_unlock(inode); out: return result; } Loading Loading @@ -659,6 +645,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); dreq->count = 0; dreq->verf.committed = NFS_INVALID_STABLE_HOW; nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo); for (i = 0; i < dreq->mirror_count; i++) dreq->mirrors[i].count = 0; get_dreq(dreq); Loading Loading @@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) nfs_direct_write_reschedule(dreq); break; default: nfs_direct_complete(dreq, true); nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping); nfs_direct_complete(dreq); } } Loading Loading @@ -993,6 +982,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) { ssize_t result = -EINVAL; size_t count; struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; Loading @@ -1003,34 +993,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", file, iov_iter_count(iter), (long long) iocb->ki_pos); nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, iov_iter_count(iter)); result = generic_write_checks(iocb, iter); if (result <= 0) return result; count = result; nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); pos = iocb->ki_pos; end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT; inode_lock(inode); result = nfs_sync_mapping(mapping); if (result) goto out_unlock; if (mapping->nrpages) { result = invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT, end); if (result) goto out_unlock; } task_io_account_write(iov_iter_count(iter)); task_io_account_write(count); result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (!dreq) goto out_unlock; goto out; dreq->inode = inode; dreq->bytes_left = dreq->max_count = iov_iter_count(iter); dreq->bytes_left = dreq->max_count = count; dreq->io_start = pos; dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); l_ctx = nfs_get_lock_context(dreq->ctx); Loading @@ -1042,6 +1022,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; nfs_start_io_direct(inode); result = nfs_direct_write_schedule_iovec(dreq, iter, pos); if (mapping->nrpages) { Loading @@ -1049,30 +1031,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) pos >> PAGE_SHIFT, end); } inode_unlock(inode); nfs_end_io_direct(inode); if (!result) { result = nfs_direct_wait(dreq); if (result > 0) { struct inode *inode = mapping->host; iocb->ki_pos = pos + result; spin_lock(&inode->i_lock); if (i_size_read(inode) < iocb->ki_pos) i_size_write(inode, iocb->ki_pos); spin_unlock(&inode->i_lock); /* XXX: should check the generic_write_sync retval */ generic_write_sync(iocb, result); } } nfs_direct_req_release(dreq); return result; out_release: nfs_direct_req_release(dreq); out_unlock: inode_unlock(inode); out: return result; } Loading
fs/nfs/file.c +27 −69 Original line number Diff line number Diff line Loading @@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) iocb->ki_filp, iov_iter_count(to), (unsigned long) iocb->ki_pos); result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping); nfs_start_io_read(inode); result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); if (!result) { result = generic_file_read_iter(iocb, to); if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); } nfs_end_io_read(inode); return result; } EXPORT_SYMBOL_GPL(nfs_file_read); Loading @@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", filp, (unsigned long) count, (unsigned long long) *ppos); res = nfs_revalidate_mapping_protected(inode, filp->f_mapping); nfs_start_io_read(inode); res = nfs_revalidate_mapping(inode, filp->f_mapping); if (!res) { res = generic_file_splice_read(filp, ppos, pipe, count, flags); if (res > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res); } nfs_end_io_read(inode); return res; } EXPORT_SYMBOL_GPL(nfs_file_splice_read); Loading Loading @@ -272,16 +276,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) trace_nfs_fsync_enter(inode); inode_dio_wait(inode); do { ret = filemap_write_and_wait_range(inode->i_mapping, start, end); if (ret != 0) break; inode_lock(inode); ret = nfs_file_fsync_commit(file, start, end, datasync); if (!ret) ret = pnfs_sync_inode(inode, !!datasync); inode_unlock(inode); /* * If nfs_file_fsync_commit detected a server reboot, then * resend all dirty pages that might have been covered by Loading Loading @@ -359,19 +360,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, file, mapping->host->i_ino, len, (long long) pos); start: /* * Prevent starvation issues if someone is doing a consistency * sync-to-disk */ ret = wait_on_bit_action(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING, nfs_wait_bit_killable, TASK_KILLABLE); if (ret) return ret; /* * Wait for O_DIRECT to complete */ inode_dio_wait(mapping->host); page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; Loading Loading @@ -470,31 +458,8 @@ static void nfs_invalidate_page(struct page *page, unsigned int offset, */ static int nfs_release_page(struct page *page, gfp_t gfp) { struct address_space *mapping = page->mapping; dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); /* Always try to initiate a 'commit' if relevant, but only * wait for it if the caller allows blocking. Even then, * only wait 1 second and only if the 'bdi' is not congested. * Waiting indefinitely can cause deadlocks when the NFS * server is on this machine, when a new TCP connection is * needed and in other rare cases. There is no particular * need to wait extensively here. A short wait has the * benefit that someone else can worry about the freezer. */ if (mapping) { struct nfs_server *nfss = NFS_SERVER(mapping->host); nfs_commit_inode(mapping->host, 0); if (gfpflags_allow_blocking(gfp) && !bdi_write_congested(&nfss->backing_dev_info)) { wait_on_page_bit_killable_timeout(page, PG_private, HZ); if (PagePrivate(page)) set_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); } } /* If PagePrivate() is set, then the page is not freeable */ if (PagePrivate(page)) return 0; Loading Loading @@ -604,6 +569,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) filp, filp->f_mapping->host->i_ino, (long long)page_offset(page)); sb_start_pagefault(inode->i_sb); /* make sure the cache has finished storing the page */ nfs_fscache_wait_on_page_write(NFS_I(inode), page); Loading @@ -630,6 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) out_unlock: unlock_page(page); out: sb_end_pagefault(inode->i_sb); return ret; } Loading @@ -656,23 +624,17 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) struct inode *inode = file_inode(file); unsigned long written = 0; ssize_t result; size_t count = iov_iter_count(from); result = nfs_key_timeout_notify(file, inode); if (result) return result; if (iocb->ki_flags & IOCB_DIRECT) { result = generic_write_checks(iocb, from); if (result <= 0) return result; if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_write(iocb, from); } dprintk("NFS: write(%pD2, %zu@%Ld)\n", file, count, (long long) iocb->ki_pos); file, iov_iter_count(from), (long long) iocb->ki_pos); result = -EBUSY; if (IS_SWAPFILE(inode)) goto out_swapfile; /* Loading @@ -684,28 +646,33 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) goto out; } result = count; if (!count) nfs_start_io_write(inode); result = generic_write_checks(iocb, from); if (result > 0) { current->backing_dev_info = inode_to_bdi(inode); result = generic_perform_write(file, from, iocb->ki_pos); current->backing_dev_info = NULL; } nfs_end_io_write(inode); if (result <= 0) goto out; result = generic_file_write_iter(iocb, from); if (result > 0) written = result; written = generic_write_sync(iocb, result); iocb->ki_pos += written; /* Return error values */ if (result >= 0 && nfs_need_check_write(file, inode)) { if (nfs_need_check_write(file, inode)) { int err = vfs_fsync(file, 0); if (err < 0) result = err; } if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); out: return result; out_swapfile: printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); goto out; return -EBUSY; } EXPORT_SYMBOL_GPL(nfs_file_write); Loading Loading @@ -779,11 +746,6 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) return status; } static int is_time_granular(struct timespec *ts) { return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000)); } static int do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { Loading Loading @@ -817,12 +779,8 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) * This makes locking act as a cache coherency point. */ nfs_sync_mapping(filp->f_mapping); if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) { if (is_time_granular(&NFS_SERVER(inode)->time_delta)) __nfs_revalidate_inode(NFS_SERVER(inode), inode); else nfs_zap_caches(inode); } if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) nfs_zap_mapping(inode, filp->f_mapping); out: return status; } Loading
fs/nfs/filelayout/filelayout.c +13 −5 Original line number Diff line number Diff line Loading @@ -255,13 +255,16 @@ static int filelayout_read_done_cb(struct rpc_task *task, static void filelayout_set_layoutcommit(struct nfs_pgio_header *hdr) { loff_t end_offs = 0; if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds || hdr->res.verf->committed != NFS_DATA_SYNC) hdr->res.verf->committed == NFS_FILE_SYNC) return; if (hdr->res.verf->committed == NFS_DATA_SYNC) end_offs = hdr->mds_offset + (loff_t)hdr->res.count; pnfs_set_layoutcommit(hdr->inode, hdr->lseg, hdr->mds_offset + hdr->res.count); /* Note: if the write is unstable, don't set end_offs until commit */ pnfs_set_layoutcommit(hdr->inode, hdr->lseg, end_offs); dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); } Loading Loading @@ -354,6 +357,12 @@ static int filelayout_write_done_cb(struct rpc_task *task, } filelayout_set_layoutcommit(hdr); /* zero out the fattr */ hdr->fattr.valid = 0; if (task->tk_status >= 0) nfs_writeback_update_inode(hdr); return 0; } Loading @@ -375,7 +384,6 @@ static int filelayout_commit_done_cb(struct rpc_task *task, return -EAGAIN; } if (data->verf.committed == NFS_UNSTABLE) pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb); return 0; Loading