Commit 1c9077cd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'nfs-for-5.12-1' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS Client Updates from Anna Schumaker:
 "New Features:
   - Support for eager writes, and the write=eager and write=wait mount
     options

- Other Bugfixes and Cleanups:
   - Fix typos in some comments
   - Fix up fall-through warnings for Clang
   - Cleanups to the NFS readpage codepath
   - Remove FMR support in rpcrdma_convert_iovs()
   - Various other cleanups to xprtrdma
   - Fix xprtrdma pad optimization for servers that don't support
     RFC 8797
   - Improvements to rpcrdma tracepoints
   - Fix up nfs4_bitmask_adjust()
   - Optimize sparse writes past the end of files"

* tag 'nfs-for-5.12-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (27 commits)
  NFS: Support the '-owrite=' option in /proc/self/mounts and mountinfo
  NFS: Set the stable writes flag when initialising the super block
  NFS: Add mount options supporting eager writes
  NFS: Add support for eager writes
  NFS: 'flags' field should be unsigned in struct nfs_server
  NFS: Don't set NFS_INO_INVALID_XATTR if there is no xattr cache
  NFS: Always clear an invalid mapping when attempting a buffered write
  NFS: Optimise sparse writes past the end of file
  NFS: Fix documenting comment for nfs_revalidate_file_size()
  NFSv4: Fixes for nfs4_bitmask_adjust()
  xprtrdma: Clean up rpcrdma_prepare_readch()
  rpcrdma: Capture bytes received in Receive completion tracepoints
  xprtrdma: Pad optimization, revisited
  rpcrdma: Fix comments about reverse-direction operation
  xprtrdma: Refactor invocations of offset_in_page()
  xprtrdma: Simplify rpcrdma_convert_kvec() and frwr_map()
  xprtrdma: Remove FMR support in rpcrdma_convert_iovs()
  NFS: Add nfs_pageio_complete_read() and remove nfs_readpage_async()
  NFS: Call readpage_async_filler() from nfs_readpage_async()
  NFS: Refactor nfs_readpage() and nfs_readpage_async() to use nfs_readdesc
  ...
parents 2c87f7a3 7ae017c7
Loading
Loading
Loading
Loading
+21 −6
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
EXPORT_SYMBOL_GPL(nfs_file_release);

/**
 * nfs_revalidate_size - Revalidate the file size
 * nfs_revalidate_file_size - Revalidate the file size
 * @inode: pointer to inode struct
 * @filp: pointer to struct file
 *
@@ -606,8 +606,8 @@ 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;
	unsigned int mntflags = NFS_SERVER(inode)->flags;
	ssize_t result, written;
	errseq_t since;
	int error;

@@ -626,13 +626,13 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
	/*
	 * O_APPEND implies that we must revalidate the file length.
	 */
	if (iocb->ki_flags & IOCB_APPEND) {
	if (iocb->ki_flags & IOCB_APPEND || iocb->ki_pos > i_size_read(inode)) {
		result = nfs_revalidate_file_size(inode, file);
		if (result)
			goto out;
	}
	if (iocb->ki_pos > i_size_read(inode))
		nfs_revalidate_mapping(inode, file->f_mapping);

	nfs_clear_invalid_mapping(file->f_mapping);

	since = filemap_sample_wb_err(file->f_mapping);
	nfs_start_io_write(inode);
@@ -648,6 +648,21 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)

	written = result;
	iocb->ki_pos += written;

	if (mntflags & NFS_MOUNT_WRITE_EAGER) {
		result = filemap_fdatawrite_range(file->f_mapping,
						  iocb->ki_pos - written,
						  iocb->ki_pos - 1);
		if (result < 0)
			goto out;
	}
	if (mntflags & NFS_MOUNT_WRITE_WAIT) {
		result = filemap_fdatawait_range(file->f_mapping,
						 iocb->ki_pos - written,
						 iocb->ki_pos - 1);
		if (result < 0)
			goto out;
	}
	result = generic_write_sync(iocb, written);
	if (result < 0)
		goto out;
+35 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ enum nfs_param {
	Opt_v,
	Opt_vers,
	Opt_wsize,
	Opt_write,
};

enum {
@@ -113,6 +114,19 @@ static const struct constant_table nfs_param_enums_lookupcache[] = {
	{}
};

enum {
	Opt_write_lazy,
	Opt_write_eager,
	Opt_write_wait,
};

static const struct constant_table nfs_param_enums_write[] = {
	{ "lazy",		Opt_write_lazy },
	{ "eager",		Opt_write_eager },
	{ "wait",		Opt_write_wait },
	{}
};

static const struct fs_parameter_spec nfs_fs_parameters[] = {
	fsparam_flag_no("ac",		Opt_ac),
	fsparam_u32   ("acdirmax",	Opt_acdirmax),
@@ -171,6 +185,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
	fsparam_flag  ("v4.1",		Opt_v),
	fsparam_flag  ("v4.2",		Opt_v),
	fsparam_string("vers",		Opt_vers),
	fsparam_enum  ("write",		Opt_write, nfs_param_enums_write),
	fsparam_u32   ("wsize",		Opt_wsize),
	{}
};
@@ -770,6 +785,24 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
			goto out_invalid_value;
		}
		break;
	case Opt_write:
		switch (result.uint_32) {
		case Opt_write_lazy:
			ctx->flags &=
				~(NFS_MOUNT_WRITE_EAGER | NFS_MOUNT_WRITE_WAIT);
			break;
		case Opt_write_eager:
			ctx->flags |= NFS_MOUNT_WRITE_EAGER;
			ctx->flags &= ~NFS_MOUNT_WRITE_WAIT;
			break;
		case Opt_write_wait:
			ctx->flags |=
				NFS_MOUNT_WRITE_EAGER | NFS_MOUNT_WRITE_WAIT;
			break;
		default:
			goto out_invalid_value;
		}
		break;

		/*
		 * Special options
@@ -1479,6 +1512,8 @@ static int nfs_init_fs_context(struct fs_context *fc)
		ctx->selected_flavor	= RPC_AUTH_MAXFLAVOR;
		ctx->minorversion	= 0;
		ctx->need_mount		= true;

		fc->s_iflags		|= SB_I_STABLE_WRITES;
	}
	fc->fs_private = ctx;
	fc->ops = &nfs_fs_context_ops;
+0 −4
Original line number Diff line number Diff line
@@ -390,10 +390,6 @@ static void nfs_readpage_from_fscache_complete(struct page *page,
	if (!error) {
		SetPageUptodate(page);
		unlock_page(page);
	} else {
		error = nfs_readpage_async(context, page->mapping->host, page);
		if (error)
			unlock_page(page);
	}
}

+68 −43
Original line number Diff line number Diff line
@@ -195,6 +195,18 @@ bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)
}
EXPORT_SYMBOL_GPL(nfs_check_cache_invalid);

#ifdef CONFIG_NFS_V4_2
static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
{
	return nfsi->xattr_cache != NULL;
}
#else
static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
{
	return false;
}
#endif

static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
{
	struct nfs_inode *nfsi = NFS_I(inode);
@@ -209,6 +221,8 @@ static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
				| NFS_INO_INVALID_XATTR);
	}

	if (!nfs_has_xattr_cache(nfsi))
		flags &= ~NFS_INO_INVALID_XATTR;
	if (inode->i_mapping->nrpages == 0)
		flags &= ~(NFS_INO_INVALID_DATA|NFS_INO_DATA_INVAL_DEFER);
	nfsi->cache_validity |= flags;
@@ -1258,55 +1272,19 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
	return 0;
}

bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
	return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) ||
		NFS_STALE(inode);
}

int nfs_revalidate_mapping_rcu(struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	unsigned long *bitlock = &nfsi->flags;
	int ret = 0;

	if (IS_SWAPFILE(inode))
		goto out;
	if (nfs_mapping_need_revalidate_inode(inode)) {
		ret = -ECHILD;
		goto out;
	}
	spin_lock(&inode->i_lock);
	if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
	    (nfsi->cache_validity & NFS_INO_INVALID_DATA))
		ret = -ECHILD;
	spin_unlock(&inode->i_lock);
out:
	return ret;
}

/**
 * nfs_revalidate_mapping - Revalidate the pagecache
 * @inode: pointer to host inode
 * nfs_clear_invalid_mapping - Conditionally clear a mapping
 * @mapping: pointer to mapping
 *
 * If the NFS_INO_INVALID_DATA inode flag is set, clear the mapping.
 */
int nfs_revalidate_mapping(struct inode *inode,
		struct address_space *mapping)
int nfs_clear_invalid_mapping(struct address_space *mapping)
{
	struct inode *inode = mapping->host;
	struct nfs_inode *nfsi = NFS_I(inode);
	unsigned long *bitlock = &nfsi->flags;
	int ret = 0;

	/* swapfiles are not supposed to be shared. */
	if (IS_SWAPFILE(inode))
		goto out;

	if (nfs_mapping_need_revalidate_inode(inode)) {
		ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
		if (ret < 0)
			goto out;
	}

	/*
	 * We must clear NFS_INO_INVALID_DATA first to ensure that
	 * invalidations that come in while we're shooting down the mappings
@@ -1337,8 +1315,8 @@ int nfs_revalidate_mapping(struct inode *inode,

	set_bit(NFS_INO_INVALIDATING, bitlock);
	smp_wmb();
	nfsi->cache_validity &= ~(NFS_INO_INVALID_DATA|
			NFS_INO_DATA_INVAL_DEFER);
	nfsi->cache_validity &=
		~(NFS_INO_INVALID_DATA | NFS_INO_DATA_INVAL_DEFER);
	spin_unlock(&inode->i_lock);
	trace_nfs_invalidate_mapping_enter(inode);
	ret = nfs_invalidate_mapping(inode, mapping);
@@ -1351,6 +1329,53 @@ int nfs_revalidate_mapping(struct inode *inode,
	return ret;
}

bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
	return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) ||
		NFS_STALE(inode);
}

int nfs_revalidate_mapping_rcu(struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	unsigned long *bitlock = &nfsi->flags;
	int ret = 0;

	if (IS_SWAPFILE(inode))
		goto out;
	if (nfs_mapping_need_revalidate_inode(inode)) {
		ret = -ECHILD;
		goto out;
	}
	spin_lock(&inode->i_lock);
	if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
	    (nfsi->cache_validity & NFS_INO_INVALID_DATA))
		ret = -ECHILD;
	spin_unlock(&inode->i_lock);
out:
	return ret;
}

/**
 * nfs_revalidate_mapping - Revalidate the pagecache
 * @inode: pointer to host inode
 * @mapping: pointer to mapping
 */
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{
	/* swapfiles are not supposed to be shared. */
	if (IS_SWAPFILE(inode))
		return 0;

	if (nfs_mapping_need_revalidate_inode(inode)) {
		int ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
		if (ret < 0)
			return ret;
	}

	return nfs_clear_invalid_mapping(mapping);
}

static bool nfs_file_has_writers(struct nfs_inode *nfsi)
{
	struct inode *inode = &nfsi->vfs_inode;
+1 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
			fallthrough;
		case -ENOTSUPP:
			status = -EOPNOTSUPP;
			goto getout;
		default:
			goto getout;
	}
Loading