/* * linux/fs/nfs/file.c * * Copyright (C) 1992 Rick Sladkey * * Changes Copyright (C) 1994 by Florian La Roche * - Do not copy data too often around in the kernel. * - In nfs_file_read the return value of kmalloc wasn't checked. * - Put in a better version of read look-ahead buffering. Original idea * and implementation by Wai S Kok elekokws@ee.nus.sg. * * Expire cache on write to a file by Wai S Kok (Oct 1994). * * Total rewrite of read side for new NFS buffer cache.. Linus. * * nfs regular file handling functions */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "delegation.h" #include "internal.h" #include "iostat.h" #include "fscache.h" #include "pnfs.h" #include "nfstrace.h" #define NFSDBG_FACILITY NFSDBG_FILE static const struct vm_operations_struct nfs_file_vm_ops; /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE # define IS_SWAPFILE(inode) (0) #endif int nfs_check_flags(int flags) { if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT)) return -EINVAL; return 0; } EXPORT_SYMBOL_GPL(nfs_check_flags); /* * Open file */ static int nfs_file_open(struct inode *inode, struct file *filp) { int res; dprintk("NFS: open file(%pD2)\n", filp); nfs_inc_stats(inode, NFSIOS_VFSOPEN); res = nfs_check_flags(filp->f_flags); if (res) return res; res = nfs_open(inode, filp); return res; } int nfs_file_release(struct inode *inode, struct file *filp) { dprintk("NFS: release(%pD2)\n", filp); nfs_inc_stats(inode, NFSIOS_VFSRELEASE); nfs_file_clear_open_context(filp); return 0; } EXPORT_SYMBOL_GPL(nfs_file_release); /** * nfs_revalidate_size - Revalidate the file size * @inode - pointer to inode struct * @file - pointer to struct file * * Revalidates the file length. This is basically a wrapper around * nfs_revalidate_inode() that takes into account the fact that we may * have cached writes (in which case we don't care about the server's * idea of what the file length is), or O_DIRECT (in which case we * shouldn't trust the cache). */ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_inode *nfsi = NFS_I(inode); if (nfs_have_delegated_attributes(inode)) goto out_noreval; if (filp->f_flags & O_DIRECT) goto force_reval; if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) goto force_reval; if (nfs_attribute_timeout(inode)) goto force_reval; out_noreval: return 0; force_reval: return __nfs_revalidate_inode(server, inode); } loff_t nfs_file_llseek(struct file *filp, loff_t offset, int whence) { dprintk("NFS: llseek file(%pD2, %lld, %d)\n", filp, offset, whence); /* * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate * the cached file length */ if (whence != SEEK_SET && whence != SEEK_CUR) { struct inode *inode = filp->f_mapping->host; int retval = nfs_revalidate_file_size(inode, filp); if (retval < 0) return (loff_t)retval; } return generic_file_llseek(filp, offset, whence); } EXPORT_SYMBOL_GPL(nfs_file_llseek); /* * Flush all dirty pages, and check for write errors. */ static int nfs_file_flush(struct file *file, fl_owner_t id) { struct inode *inode = file_inode(file); dprintk("NFS: flush(%pD2)\n", file); nfs_inc_stats(inode, NFSIOS_VFSFLUSH); if ((file->f_mode & FMODE_WRITE) == 0) return 0; /* Flush writes to the server and return any errors */ return vfs_fsync(file, 0); } ssize_t nfs_file_read(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = file_inode(iocb->ki_filp); ssize_t result; if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_read(iocb, to, iocb->ki_pos); dprintk("NFS: read(%pD2, %zu@%lu)\n", iocb->ki_filp, iov_iter_count(to), (unsigned long) iocb->ki_pos); result = nfs_revalidate_mapping_protected(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); } return result; } EXPORT_SYMBOL_GPL(nfs_file_read); ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, unsigned int flags) { struct inode *inode = file_inode(filp); ssize_t res; 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); if (!res) { res = generic_file_splice_read(filp, ppos, pipe, count, flags); if (res
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
: Copyright (c) 2017 Mirantis Inc., Enea AB and others.
:
: All rights reserved. This program and the accompanying materials
: are made available under the terms of the Apache License, Version 2.0
: which accompanies this distribution, and is available at
: http://www.apache.org/licenses/LICENSE-2.0
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
From: Michael Polenchuk <mpolenchuk@mirantis.com>
Date: Mon, 28 Aug 2017 16:17:43 +0400
Subject: [PATCH] Handle file_recv option


diff --git a/salt/files/master.conf b/salt/files/master.conf
index 329ae0d..a9d9656 100644
--- a/salt/files/master.conf
+++ b/salt/files/master.conf
@@ -95,6 +95,8 @@ logstash_zmq_handler:
 order_masters: True
 {%- endif %}

+file_recv: {{ master.get('file_recv', False) }}
+
 {#-
 vim: syntax=jinja
 -#}
e_page, .releasepage = nfs_release_page, .direct_IO = nfs_direct_IO, .migratepage = nfs_migrate_page, .launder_page = nfs_launder_page, .is_dirty_writeback = nfs_check_dirty_writeback, .error_remove_page = generic_error_remove_page, .swap_activate = nfs_swap_activate, .swap_deactivate = nfs_swap_deactivate, }; /* * Notification that a PTE pointing to an NFS page is about to be made * writable, implying that someone is about to modify the page through a * shared-writable mapping */ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *page = vmf->page; struct file *filp = vma->vm_file; struct inode *inode = file_inode(filp); unsigned pagelen; int ret = VM_FAULT_NOPAGE; struct address_space *mapping; dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n", filp, filp->f_mapping->host->i_ino, (long long)page_offset(page)); /* make sure the cache has finished storing the page */ nfs_fscache_wait_on_page_write(NFS_I(inode), page); wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING, nfs_wait_bit_killable, TASK_KILLABLE); lock_page(page); mapping = page_file_mapping(page); if (mapping != inode->i_mapping) goto out_unlock; wait_on_page_writeback(page); pagelen = nfs_page_length(page); if (pagelen == 0) goto out_unlock; ret = VM_FAULT_LOCKED; if (nfs_flush_incompatible(filp, page) == 0 && nfs_updatepage(filp, page, 0, pagelen) == 0) goto out; ret = VM_FAULT_SIGBUS; out_unlock: unlock_page(page); out: return ret; } static const struct vm_operations_struct nfs_file_vm_ops = { .fault = filemap_fault, .map_pages = filemap_map_pages, .page_mkwrite = nfs_vm_page_mkwrite, }; static int nfs_need_check_write(struct file *filp, struct inode *inode) { struct nfs_open_context *ctx; ctx = nfs_file_open_context(filp); if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags) || nfs_ctx_key_to_expire(ctx)) return 1; return 0; } ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; 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; return nfs_file_direct_write(iocb, from); } dprintk("NFS: write(%pD2, %zu@%Ld)\n", file, count, (long long) iocb->ki_pos); result = -EBUSY; if (IS_SWAPFILE(inode)) goto out_swapfile; /* * O_APPEND implies that we must revalidate the file length. */ if (iocb->ki_flags & IOCB_APPEND) { result = nfs_revalidate_file_size(inode, file); if (result) goto out; } result = count; if (!count) goto out; result = generic_file_write_iter(iocb, from); if (result > 0) written = result; /* Return error values */ if (result >= 0 && 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; } EXPORT_SYMBOL_GPL(nfs_file_write); static int do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { struct inode *inode = filp->f_mapping->host; int status = 0; unsigned int saved_type = fl->fl_type; /* Try local locking first */ posix_test_lock(filp, fl); if (fl->fl_type != F_UNLCK) { /* found a conflict */ goto out; } fl->fl_type = saved_type; if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) goto out_noconflict; if (is_local) goto out_noconflict; status = NFS_PROTO(inode)->lock(filp, cmd, fl); out: return status; out_noconflict: fl->fl_type = F_UNLCK; goto out; } static int do_vfs_lock(struct file *file, struct file_lock *fl) { return locks_lock_file_wait(file, fl); } static int do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { struct inode *inode = filp->f_mapping->host; struct nfs_lock_context *l_ctx; int status; /* * Flush all pending writes before doing anything * with locks.. */ vfs_fsync(filp, 0); l_ctx = nfs_get_lock_context(nfs_file_open_context(filp)); if (!IS_ERR(l_ctx)) { status = nfs_iocounter_wait(&l_ctx->io_count); nfs_put_lock_context(l_ctx); if (status < 0) return status; } /* NOTE: special case * If we're signalled while cleaning up locks on process exit, we * still need to complete the unlock. */ /* * Use local locking if mounted with "-onolock" or with appropriate * "-olocal_lock=" */ if (!is_local) status = NFS_PROTO(inode)->lock(filp, cmd, fl); else status = do_vfs_lock(filp, fl); 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) { struct inode *inode = filp->f_mapping->host; int status; /* * Flush all pending writes before doing anything * with locks.. */ status = nfs_sync_mapping(filp->f_mapping); if (status != 0) goto out; /* * Use local locking if mounted with "-onolock" or with appropriate * "-olocal_lock=" */ if (!is_local) status = NFS_PROTO(inode)->lock(filp, cmd, fl); else status = do_vfs_lock(filp, fl); if (status < 0) goto out; /* * Revalidate the cache if the server has time stamps granular * enough to detect subsecond changes. Otherwise, clear the * cache to prevent missing any changes. * * 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); } out: return status; } /* * Lock a (portion of) a file */ int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) { struct inode *inode = filp->f_mapping->host; int ret = -ENOLCK; int is_local = 0; dprintk("NFS: lock(%pD2, t=%x, fl=%x, r=%lld:%lld)\n", filp, fl->fl_type, fl->fl_flags, (long long)fl->fl_start, (long long)fl->fl_end); nfs_inc_stats(inode, NFSIOS_VFSLOCK); /* No mandatory locks over NFS */ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) goto out_err; if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL) is_local = 1; if (NFS_PROTO(inode)->lock_check_bounds != NULL) { ret = NFS_PROTO(inode)->lock_check_bounds(fl); if (ret < 0) goto out_err; } if (IS_GETLK(cmd)) ret = do_getlk(filp, cmd, fl, is_local); else if (fl->fl_type == F_UNLCK) ret = do_unlk(filp, cmd, fl, is_local); else ret = do_setlk(filp, cmd, fl, is_local); out_err: return ret; } EXPORT_SYMBOL_GPL(nfs_lock); /* * Lock a (portion of) a file */ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) { struct inode *inode = filp->f_mapping->host; int is_local = 0; dprintk("NFS: flock(%pD2, t=%x, fl=%x)\n", filp, fl->fl_type, fl->fl_flags); if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; /* * The NFSv4 protocol doesn't support LOCK_MAND, which is not part of * any standard. In principle we might be able to support LOCK_MAND * on NFSv2/3 since NLMv3/4 support DOS share modes, but for now the * NFS code is not set up for it. */ if (fl->fl_type & LOCK_MAND) return -EINVAL; if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK) is_local = 1; /* We're simulating flock() locks using posix locks on the server */ if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl, is_local); return do_setlk(filp, cmd, fl, is_local); } EXPORT_SYMBOL_GPL(nfs_flock); const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, .read_iter = nfs_file_read, .write_iter = nfs_file_write, .mmap = nfs_file_mmap, .open = nfs_file_open, .flush = nfs_file_flush, .release = nfs_file_release, .fsync = nfs_file_fsync, .lock = nfs_lock, .flock = nfs_flock, .splice_read = nfs_file_splice_read, .splice_write = iter_file_splice_write, .check_flags = nfs_check_flags, .setlease = simple_nosetlease, }; EXPORT_SYMBOL_GPL(nfs_file_operations);