diff options
Diffstat (limited to 'fs/nfs/file.c')
| -rw-r--r-- | fs/nfs/file.c | 471 | 
1 files changed, 253 insertions, 218 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 60677f9f131..4042ff58fe3 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -16,6 +16,7 @@   *  nfs regular file handling functions   */ +#include <linux/module.h>  #include <linux/time.h>  #include <linux/kernel.h>  #include <linux/errno.h> @@ -30,88 +31,31 @@  #include <linux/swap.h>  #include <asm/uaccess.h> -#include <asm/system.h>  #include "delegation.h"  #include "internal.h"  #include "iostat.h"  #include "fscache.h" -#include "pnfs.h" -#define NFSDBG_FACILITY		NFSDBG_FILE +#include "nfstrace.h" -static int nfs_file_open(struct inode *, struct file *); -static int nfs_file_release(struct inode *, struct file *); -static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin); -static int  nfs_file_mmap(struct file *, struct vm_area_struct *); -static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos, -					struct pipe_inode_info *pipe, -					size_t count, unsigned int flags); -static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, -				unsigned long nr_segs, loff_t pos); -static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, -					struct file *filp, loff_t *ppos, -					size_t count, unsigned int flags); -static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, -				unsigned long nr_segs, loff_t pos); -static int  nfs_file_flush(struct file *, fl_owner_t id); -static int  nfs_file_fsync(struct file *, int datasync); -static int nfs_check_flags(int flags); -static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); -static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); -static int nfs_setlease(struct file *file, long arg, struct file_lock **fl); +#define NFSDBG_FACILITY		NFSDBG_FILE  static const struct vm_operations_struct nfs_file_vm_ops; -const struct file_operations nfs_file_operations = { -	.llseek		= nfs_file_llseek, -	.read		= do_sync_read, -	.write		= do_sync_write, -	.aio_read	= nfs_file_read, -	.aio_write	= 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	= nfs_file_splice_write, -	.check_flags	= nfs_check_flags, -	.setlease	= nfs_setlease, -}; - -const struct inode_operations nfs_file_inode_operations = { -	.permission	= nfs_permission, -	.getattr	= nfs_getattr, -	.setattr	= nfs_setattr, -}; - -#ifdef CONFIG_NFS_V3 -const struct inode_operations nfs3_file_inode_operations = { -	.permission	= nfs_permission, -	.getattr	= nfs_getattr, -	.setattr	= nfs_setattr, -	.listxattr	= nfs3_listxattr, -	.getxattr	= nfs3_getxattr, -	.setxattr	= nfs3_setxattr, -	.removexattr	= nfs3_removexattr, -}; -#endif  /* CONFIG_NFS_v3 */ -  /* Hack for future NFS swap support */  #ifndef IS_SWAPFILE  # define IS_SWAPFILE(inode)	(0)  #endif -static int nfs_check_flags(int flags) +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 @@ -121,9 +65,7 @@ nfs_file_open(struct inode *inode, struct file *filp)  {  	int res; -	dprintk("NFS: open file(%s/%s)\n", -			filp->f_path.dentry->d_parent->d_name.name, -			filp->f_path.dentry->d_name.name); +	dprintk("NFS: open file(%pD2)\n", filp);  	nfs_inc_stats(inode, NFSIOS_VFSOPEN);  	res = nfs_check_flags(filp->f_flags); @@ -134,18 +76,15 @@ nfs_file_open(struct inode *inode, struct file *filp)  	return res;  } -static int +int  nfs_file_release(struct inode *inode, struct file *filp)  { -	struct dentry *dentry = filp->f_path.dentry; - -	dprintk("NFS: release(%s/%s)\n", -			dentry->d_parent->d_name.name, -			dentry->d_name.name); +	dprintk("NFS: release(%pD2)\n", filp);  	nfs_inc_stats(inode, NFSIOS_VFSRELEASE);  	return nfs_release(inode, filp);  } +EXPORT_SYMBOL_GPL(nfs_file_release);  /**   * nfs_revalidate_size - Revalidate the file size @@ -178,89 +117,86 @@ force_reval:  	return __nfs_revalidate_inode(server, inode);  } -static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) +loff_t nfs_file_llseek(struct file *filp, loff_t offset, int whence)  { -	loff_t loff; +	dprintk("NFS: llseek file(%pD2, %lld, %d)\n", +			filp, offset, whence); -	dprintk("NFS: llseek file(%s/%s, %lld, %d)\n", -			filp->f_path.dentry->d_parent->d_name.name, -			filp->f_path.dentry->d_name.name, -			offset, origin); - -	/* origin == SEEK_END => we must revalidate the cached file length */ -	if (origin == SEEK_END) { +	/* +	 * 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; +	} -		spin_lock(&inode->i_lock); -		loff = generic_file_llseek_unlocked(filp, offset, origin); -		spin_unlock(&inode->i_lock); -	} else -		loff = generic_file_llseek_unlocked(filp, offset, origin); -	return loff; +	return generic_file_llseek(filp, offset, whence);  } +EXPORT_SYMBOL_GPL(nfs_file_llseek);  /*   * Flush all dirty pages, and check for write errors.   */ -static int +int  nfs_file_flush(struct file *file, fl_owner_t id)  { -	struct dentry	*dentry = file->f_path.dentry; -	struct inode	*inode = dentry->d_inode; +	struct inode	*inode = file_inode(file); -	dprintk("NFS: flush(%s/%s)\n", -			dentry->d_parent->d_name.name, -			dentry->d_name.name); +	dprintk("NFS: flush(%pD2)\n", file);  	nfs_inc_stats(inode, NFSIOS_VFSFLUSH);  	if ((file->f_mode & FMODE_WRITE) == 0)  		return 0; +	/* +	 * If we're holding a write delegation, then just start the i/o +	 * but don't wait for completion (or send a commit). +	 */ +	if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) +		return filemap_fdatawrite(file->f_mapping); +  	/* Flush writes to the server and return any errors */  	return vfs_fsync(file, 0);  } +EXPORT_SYMBOL_GPL(nfs_file_flush); -static ssize_t -nfs_file_read(struct kiocb *iocb, const struct iovec *iov, -		unsigned long nr_segs, loff_t pos) +ssize_t +nfs_file_read(struct kiocb *iocb, struct iov_iter *to)  { -	struct dentry * dentry = iocb->ki_filp->f_path.dentry; -	struct inode * inode = dentry->d_inode; +	struct inode *inode = file_inode(iocb->ki_filp);  	ssize_t result; -	size_t count = iov_length(iov, nr_segs);  	if (iocb->ki_filp->f_flags & O_DIRECT) -		return nfs_file_direct_read(iocb, iov, nr_segs, pos); +		return nfs_file_direct_read(iocb, to, iocb->ki_pos, true); -	dprintk("NFS: read(%s/%s, %lu@%lu)\n", -		dentry->d_parent->d_name.name, dentry->d_name.name, -		(unsigned long) count, (unsigned long) pos); +	dprintk("NFS: read(%pD2, %zu@%lu)\n", +		iocb->ki_filp, +		iov_iter_count(to), (unsigned long) iocb->ki_pos);  	result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);  	if (!result) { -		result = generic_file_aio_read(iocb, iov, nr_segs, pos); +		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); -static ssize_t +ssize_t  nfs_file_splice_read(struct file *filp, loff_t *ppos,  		     struct pipe_inode_info *pipe, size_t count,  		     unsigned int flags)  { -	struct dentry *dentry = filp->f_path.dentry; -	struct inode *inode = dentry->d_inode; +	struct inode *inode = file_inode(filp);  	ssize_t res; -	dprintk("NFS: splice_read(%s/%s, %lu@%Lu)\n", -		dentry->d_parent->d_name.name, dentry->d_name.name, -		(unsigned long) count, (unsigned long long) *ppos); +	dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", +		filp, (unsigned long) count, (unsigned long long) *ppos);  	res = nfs_revalidate_mapping(inode, filp->f_mapping);  	if (!res) { @@ -270,16 +206,15 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,  	}  	return res;  } +EXPORT_SYMBOL_GPL(nfs_file_splice_read); -static int +int  nfs_file_mmap(struct file * file, struct vm_area_struct * vma)  { -	struct dentry *dentry = file->f_path.dentry; -	struct inode *inode = dentry->d_inode; +	struct inode *inode = file_inode(file);  	int	status; -	dprintk("NFS: mmap(%s/%s)\n", -		dentry->d_parent->d_name.name, dentry->d_name.name); +	dprintk("NFS: mmap(%pD2)\n", file);  	/* Note: generic_file_mmap() returns ENOSYS on nommu systems  	 *       so we call that before revalidating the mapping @@ -291,6 +226,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)  	}  	return status;  } +EXPORT_SYMBOL_GPL(nfs_file_mmap);  /*   * Flush any dirty pages for this process, and check for write errors. @@ -301,31 +237,66 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)   * disk, but it retrieves and clears ctx->error after synching, despite   * the two being set at the same time in nfs_context_set_write_error().   * This is because the former is used to notify the _next_ call to - * nfs_file_write() that a write error occured, and hence cause it to + * nfs_file_write() that a write error occurred, and hence cause it to   * fall back to doing a synchronous write.   */ -static int -nfs_file_fsync(struct file *file, int datasync) +int +nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)  { -	struct dentry *dentry = file->f_path.dentry;  	struct nfs_open_context *ctx = nfs_file_open_context(file); -	struct inode *inode = dentry->d_inode; -	int have_error, status; +	struct inode *inode = file_inode(file); +	int have_error, do_resend, status;  	int ret = 0; - -	dprintk("NFS: fsync file(%s/%s) datasync %d\n", -			dentry->d_parent->d_name.name, dentry->d_name.name, -			datasync); +	dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync);  	nfs_inc_stats(inode, NFSIOS_VFSFSYNC); +	do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);  	have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);  	status = nfs_commit_inode(inode, FLUSH_SYNC);  	have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); -	if (have_error) +	if (have_error) {  		ret = xchg(&ctx->error, 0); -	if (!ret && status < 0) +		if (ret) +			goto out; +	} +	if (status < 0) {  		ret = status; +		goto out; +	} +	do_resend |= test_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags); +	if (do_resend) +		ret = -EAGAIN; +out: +	return ret; +} +EXPORT_SYMBOL_GPL(nfs_file_fsync_commit); + +static int +nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) +{ +	int ret; +	struct inode *inode = file_inode(file); + +	trace_nfs_fsync_enter(inode); + +	do { +		ret = filemap_write_and_wait_range(inode->i_mapping, start, end); +		if (ret != 0) +			break; +		mutex_lock(&inode->i_mutex); +		ret = nfs_file_fsync_commit(file, start, end, datasync); +		mutex_unlock(&inode->i_mutex); +		/* +		 * If nfs_file_fsync_commit detected a server reboot, then +		 * resend all dirty pages that might have been covered by +		 * the NFS_CONTEXT_RESEND_WRITES flag +		 */ +		start = 0; +		end = LLONG_MAX; +	} while (ret == -EAGAIN); + +	trace_nfs_fsync_exit(inode, ret);  	return ret;  } @@ -382,14 +353,8 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,  	struct page *page;  	int once_thru = 0; -	dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", -		file->f_path.dentry->d_parent->d_name.name, -		file->f_path.dentry->d_name.name, -		mapping->host->i_ino, len, (long long) pos); - -	pnfs_update_layout(mapping->host, -			   nfs_file_open_context(file), -			   IOMODE_RW); +	dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n", +		file, mapping->host->i_ino, len, (long long) pos);  start:  	/* @@ -426,12 +391,11 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,  			struct page *page, void *fsdata)  {  	unsigned offset = pos & (PAGE_CACHE_SIZE - 1); +	struct nfs_open_context *ctx = nfs_file_open_context(file);  	int status; -	dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n", -		file->f_path.dentry->d_parent->d_name.name, -		file->f_path.dentry->d_name.name, -		mapping->host->i_ino, len, (long long) pos); +	dfprintk(PAGECACHE, "NFS: write_end(%pD2(%lu), %u@%lld)\n", +		file, mapping->host->i_ino, len, (long long) pos);  	/*  	 * Zero any uninitialised parts of the page, and then mark the page @@ -460,6 +424,14 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,  	if (status < 0)  		return status; +	NFS_I(mapping->host)->write_io += copied; + +	if (nfs_ctx_key_to_expire(ctx)) { +		status = nfs_wb_all(mapping->host); +		if (status < 0) +			return status; +	} +  	return copied;  } @@ -470,14 +442,16 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,   * - Called if either PG_private or PG_fscache is set on the page   * - Caller holds page lock   */ -static void nfs_invalidate_page(struct page *page, unsigned long offset) +static void nfs_invalidate_page(struct page *page, unsigned int offset, +				unsigned int length)  { -	dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset); +	dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %u, %u)\n", +		 page, offset, length); -	if (offset != 0) +	if (offset != 0 || length < PAGE_CACHE_SIZE)  		return;  	/* Cancel any unstarted writes on this page */ -	nfs_wb_page_cancel(page->mapping->host, page); +	nfs_wb_page_cancel(page_file_mapping(page)->host, page);  	nfs_fscache_invalidate_page(page, page->mapping->host);  } @@ -494,8 +468,11 @@ static int nfs_release_page(struct page *page, gfp_t gfp)  	dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); -	/* Only do I/O if gfp is a superset of GFP_KERNEL */ -	if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) { +	/* Only do I/O if gfp is a superset of GFP_KERNEL, and we're not +	 * doing this memory reclaim for a fs-related allocation. +	 */ +	if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL && +	    !(current->flags & PF_FSTRANS)) {  		int how = FLUSH_SYNC;  		/* Don't let kswapd deadlock waiting for OOM RPC calls */ @@ -509,6 +486,35 @@ static int nfs_release_page(struct page *page, gfp_t gfp)  	return nfs_fscache_release_page(page, gfp);  } +static void nfs_check_dirty_writeback(struct page *page, +				bool *dirty, bool *writeback) +{ +	struct nfs_inode *nfsi; +	struct address_space *mapping = page_file_mapping(page); + +	if (!mapping || PageSwapCache(page)) +		return; + +	/* +	 * Check if an unstable page is currently being committed and +	 * if so, have the VM treat it as if the page is under writeback +	 * so it will not block due to pages that will shortly be freeable. +	 */ +	nfsi = NFS_I(mapping->host); +	if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) { +		*writeback = true; +		return; +	} + +	/* +	 * If PagePrivate() is set, then the page is not freeable and as the +	 * inode is not being committed, it's not going to be cleaned in the +	 * near future so treat it as dirty +	 */ +	if (PagePrivate(page)) +		*dirty = true; +} +  /*   * Attempt to clear the private state associated with a page when an error   * occurs that requires the cached contents of an inode to be written back or @@ -519,7 +525,7 @@ static int nfs_release_page(struct page *page, gfp_t gfp)   */  static int nfs_launder_page(struct page *page)  { -	struct inode *inode = page->mapping->host; +	struct inode *inode = page_file_mapping(page)->host;  	struct nfs_inode *nfsi = NFS_I(inode);  	dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", @@ -529,6 +535,20 @@ static int nfs_launder_page(struct page *page)  	return nfs_wb_page(inode, page);  } +#ifdef CONFIG_NFS_SWAP +static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file, +						sector_t *span) +{ +	*span = sis->pages; +	return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 1); +} + +static void nfs_swap_deactivate(struct file *file) +{ +	xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 0); +} +#endif +  const struct address_space_operations nfs_file_aops = {  	.readpage = nfs_readpage,  	.readpages = nfs_readpages, @@ -542,7 +562,12 @@ const struct address_space_operations nfs_file_aops = {  	.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, +#ifdef CONFIG_NFS_SWAP +	.swap_activate = nfs_swap_activate, +	.swap_deactivate = nfs_swap_deactivate, +#endif  };  /* @@ -554,24 +579,25 @@ 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 dentry *dentry = filp->f_path.dentry; +	struct inode *inode = file_inode(filp);  	unsigned pagelen;  	int ret = VM_FAULT_NOPAGE;  	struct address_space *mapping; -	dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n", -		dentry->d_parent->d_name.name, dentry->d_name.name, -		filp->f_mapping->host->i_ino, +	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(dentry->d_inode), page); +	nfs_fscache_wait_on_page_write(NFS_I(inode), page);  	lock_page(page); -	mapping = page->mapping; -	if (mapping != dentry->d_inode->i_mapping) +	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; @@ -590,7 +616,9 @@ out:  static const struct vm_operations_struct nfs_file_vm_ops = {  	.fault = filemap_fault, +	.map_pages = filemap_map_pages,  	.page_mkwrite = nfs_vm_page_mkwrite, +	.remap_pages = generic_file_remap_pages,  };  static int nfs_need_sync_write(struct file *filp, struct inode *inode) @@ -600,26 +628,30 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode)  	if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC))  		return 1;  	ctx = nfs_file_open_context(filp); -	if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) +	if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags) || +	    nfs_ctx_key_to_expire(ctx))  		return 1;  	return 0;  } -static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, -				unsigned long nr_segs, loff_t pos) +ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)  { -	struct dentry * dentry = iocb->ki_filp->f_path.dentry; -	struct inode * inode = dentry->d_inode; +	struct file *file = iocb->ki_filp; +	struct inode *inode = file_inode(file);  	unsigned long written = 0;  	ssize_t result; -	size_t count = iov_length(iov, nr_segs); +	size_t count = iov_iter_count(from); +	loff_t pos = iocb->ki_pos; -	if (iocb->ki_filp->f_flags & O_DIRECT) -		return nfs_file_direct_write(iocb, iov, nr_segs, pos); +	result = nfs_key_timeout_notify(file, inode); +	if (result) +		return result; + +	if (file->f_flags & O_DIRECT) +		return nfs_file_direct_write(iocb, from, pos, true); -	dprintk("NFS: write(%s/%s, %lu@%Ld)\n", -		dentry->d_parent->d_name.name, dentry->d_name.name, -		(unsigned long) count, (long long) pos); +	dprintk("NFS: write(%pD2, %zu@%Ld)\n", +		file, count, (long long) pos);  	result = -EBUSY;  	if (IS_SWAPFILE(inode)) @@ -627,8 +659,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,  	/*  	 * O_APPEND implies that we must revalidate the file length.  	 */ -	if (iocb->ki_filp->f_flags & O_APPEND) { -		result = nfs_revalidate_file_size(inode, iocb->ki_filp); +	if (file->f_flags & O_APPEND) { +		result = nfs_revalidate_file_size(inode, file);  		if (result)  			goto out;  	} @@ -637,13 +669,13 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,  	if (!count)  		goto out; -	result = generic_file_aio_write(iocb, iov, nr_segs, pos); +	result = generic_file_write_iter(iocb, from);  	if (result > 0)  		written = result;  	/* Return error values for O_DSYNC and IS_SYNC() */ -	if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { -		int err = vfs_fsync(iocb->ki_filp, 0); +	if (result >= 0 && nfs_need_sync_write(file, inode)) { +		int err = vfs_fsync(file, 0);  		if (err < 0)  			result = err;  	} @@ -656,43 +688,14 @@ out_swapfile:  	printk(KERN_INFO "NFS: attempt to write to active swap file!\n");  	goto out;  } - -static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, -				     struct file *filp, loff_t *ppos, -				     size_t count, unsigned int flags) -{ -	struct dentry *dentry = filp->f_path.dentry; -	struct inode *inode = dentry->d_inode; -	unsigned long written = 0; -	ssize_t ret; - -	dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", -		dentry->d_parent->d_name.name, dentry->d_name.name, -		(unsigned long) count, (unsigned long long) *ppos); - -	/* -	 * The combination of splice and an O_APPEND destination is disallowed. -	 */ - -	ret = generic_file_splice_write(pipe, filp, ppos, count, flags); -	if (ret > 0) -		written = ret; - -	if (ret >= 0 && nfs_need_sync_write(filp, inode)) { -		int err = vfs_fsync(filp, 0); -		if (err < 0) -			ret = err; -	} -	if (ret > 0) -		nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); -	return ret; -} +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); @@ -700,8 +703,9 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)  		/* found a conflict */  		goto out;  	} +	fl->fl_type = saved_type; -	if (nfs_have_delegation(inode, FMODE_READ)) +	if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))  		goto out_noconflict;  	if (is_local) @@ -735,6 +739,7 @@ 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;  	/* @@ -743,6 +748,14 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)  	 */  	nfs_sync_mapping(filp->f_mapping); +	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. @@ -796,7 +809,7 @@ 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_have_delegation(inode, FMODE_READ)) { +	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 @@ -809,16 +822,14 @@ out:  /*   * Lock a (portion of) a file   */ -static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) +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(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n", -			filp->f_path.dentry->d_parent->d_name.name, -			filp->f_path.dentry->d_name.name, -			fl->fl_type, fl->fl_flags, +	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); @@ -845,44 +856,68 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)  out_err:  	return ret;  } +EXPORT_SYMBOL_GPL(nfs_lock);  /*   * Lock a (portion of) a file   */ -static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) +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(%s/%s, t=%x, fl=%x)\n", -			filp->f_path.dentry->d_parent->d_name.name, -			filp->f_path.dentry->d_name.name, -			fl->fl_type, fl->fl_flags); +	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 */ -	fl->fl_owner = (fl_owner_t)filp; -	fl->fl_start = 0; -	fl->fl_end = OFFSET_MAX; -  	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);  /*   * There is no protocol support for leases, so we have no way to implement   * them correctly in the face of opens by other clients.   */ -static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) +int nfs_setlease(struct file *file, long arg, struct file_lock **fl)  { -	dprintk("NFS: setlease(%s/%s, arg=%ld)\n", -			file->f_path.dentry->d_parent->d_name.name, -			file->f_path.dentry->d_name.name, arg); +	dprintk("NFS: setlease(%pD2, arg=%ld)\n", file, arg);  	return -EINVAL;  } +EXPORT_SYMBOL_GPL(nfs_setlease); + +const struct file_operations nfs_file_operations = { +	.llseek		= nfs_file_llseek, +	.read		= new_sync_read, +	.write		= new_sync_write, +	.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	= nfs_setlease, +}; +EXPORT_SYMBOL_GPL(nfs_file_operations);  | 
