Commit 59f0e7eb authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull NFS client updates from Anna Schumaker:
 "Stable Fixes:
   - Wait for stateid updates after CLOSE/OPEN_DOWNGRADE # v5.4+
   - Fix nfs_path in case of a rename retry
   - Support EXCHID4_FLAG_SUPP_FENCE_OPS v4.2 EXCHANGE_ID flag

  New features and improvements:
   - Replace dprintk() calls with tracepoints
   - Make cache consistency bitmap dynamic
   - Added support for the NFS v4.2 READ_PLUS operation
   - Improvements to net namespace uniquifier

  Other bugfixes and cleanups:
   - Remove redundant clnt pointer
   - Don't update timeout values on connection resets
   - Remove redundant tracepoints
   - Various cleanups to comments
   - Fix oops when trying to use copy_file_range with v4.0 source server
   - Improvements to flexfiles mirrors
   - Add missing 'local_lock=posix' mount option"

* tag 'nfs-for-5.10-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (55 commits)
  NFSv4.2: support EXCHGID4_FLAG_SUPP_FENCE_OPS 4.2 EXCHANGE_ID flag
  NFSv4: Fix up RCU annotations for struct nfs_netns_client
  NFS: Only reference user namespace from nfs4idmap struct instead of cred
  nfs: add missing "posix" local_lock constant table definition
  NFSv4: Use the net namespace uniquifier if it is set
  NFSv4: Clean up initialisation of uniquified client id strings
  NFS: Decode a full READ_PLUS reply
  SUNRPC: Add an xdr_align_data() function
  NFS: Add READ_PLUS hole segment decoding
  SUNRPC: Add the ability to expand holes in data pages
  SUNRPC: Split out _shift_data_right_tail()
  SUNRPC: Split out xdr_realign_pages() from xdr_align_pages()
  NFS: Add READ_PLUS data segment support
  NFS: Use xdr_page_pos() in NFSv4 decode_getacl()
  SUNRPC: Implement a xdr_page_pos() function
  SUNRPC: Split out a function for setting current page
  NFS: fix nfs_path in case of a rename retry
  fs: nfs: return per memcg count for xattr shrinkers
  NFSv4: Wait for stateid updates after CLOSE/OPEN_DOWNGRADE
  nfs: remove incorrect fallthrough label
  ...
parents 4962a856 8c39076c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -417,7 +417,7 @@ void nsm_release(struct nsm_handle *nsm)
/*
 * XDR functions for NSM.
 *
 * See http://www.opengroup.org/ for details on the Network
 * See https://www.opengroup.org/ for details on the Network
 * Status Monitor wire protocol.
 */

+1 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ enum {
static const struct constant_table nfs_param_enums_local_lock[] = {
	{ "all",		Opt_local_lock_all },
	{ "flock",	Opt_local_lock_flock },
	{ "posix",	Opt_local_lock_posix },
	{ "none",		Opt_local_lock_none },
	{}
};
+8 −4
Original line number Diff line number Diff line
@@ -32,9 +32,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
/*
 * nfs_path - reconstruct the path given an arbitrary dentry
 * @base - used to return pointer to the end of devname part of path
 * @dentry - pointer to dentry
 * @dentry_in - pointer to dentry
 * @buffer - result buffer
 * @buflen - length of buffer
 * @buflen_in - length of buffer
 * @flags - options (see below)
 *
 * Helper function for constructing the server pathname
@@ -49,15 +49,19 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
 *		       the original device (export) name
 *		       (if unset, the original name is returned verbatim)
 */
char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen,
	       unsigned flags)
char *nfs_path(char **p, struct dentry *dentry_in, char *buffer,
	       ssize_t buflen_in, unsigned flags)
{
	char *end;
	int namelen;
	unsigned seq;
	const char *base;
	struct dentry *dentry;
	ssize_t buflen;

rename_retry:
	buflen = buflen_in;
	dentry = dentry_in;
	end = buffer+buflen;
	*--end = '\0';
	buflen--;
+2 −3
Original line number Diff line number Diff line
@@ -67,7 +67,6 @@ struct nfs4_xattr_bucket {

struct nfs4_xattr_cache {
	struct kref ref;
	spinlock_t hash_lock;	/* protects hashtable and lru */
	struct nfs4_xattr_bucket buckets[NFS4_XATTR_HASH_SIZE];
	struct list_head lru;
	struct list_head dispose;
@@ -882,7 +881,7 @@ nfs4_xattr_cache_count(struct shrinker *shrink, struct shrink_control *sc)
{
	unsigned long count;

	count = list_lru_count(&nfs4_xattr_cache_lru);
	count = list_lru_shrink_count(&nfs4_xattr_cache_lru, sc);
	return vfs_pressure_ratio(count);
}

@@ -976,7 +975,7 @@ nfs4_xattr_entry_count(struct shrinker *shrink, struct shrink_control *sc)
	lru = (shrink == &nfs4_xattr_large_entry_shrinker) ?
	    &nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;

	count = list_lru_count(lru);
	count = list_lru_shrink_count(lru, sc);
	return vfs_pressure_ratio(count);
}

+167 −0
Original line number Diff line number Diff line
@@ -45,6 +45,15 @@
#define encode_deallocate_maxsz		(op_encode_hdr_maxsz + \
					 encode_fallocate_maxsz)
#define decode_deallocate_maxsz		(op_decode_hdr_maxsz)
#define encode_read_plus_maxsz		(op_encode_hdr_maxsz + \
					 encode_stateid_maxsz + 3)
#define NFS42_READ_PLUS_SEGMENT_SIZE	(1 /* data_content4 */ + \
					 2 /* data_info4.di_offset */ + \
					 2 /* data_info4.di_length */)
#define decode_read_plus_maxsz		(op_decode_hdr_maxsz + \
					 1 /* rpr_eof */ + \
					 1 /* rpr_contents count */ + \
					 2 * NFS42_READ_PLUS_SEGMENT_SIZE)
#define encode_seek_maxsz		(op_encode_hdr_maxsz + \
					 encode_stateid_maxsz + \
					 2 /* offset */ + \
@@ -128,6 +137,14 @@
					 decode_putfh_maxsz + \
					 decode_deallocate_maxsz + \
					 decode_getattr_maxsz)
#define NFS4_enc_read_plus_sz		(compound_encode_hdr_maxsz + \
					 encode_sequence_maxsz + \
					 encode_putfh_maxsz + \
					 encode_read_plus_maxsz)
#define NFS4_dec_read_plus_sz		(compound_decode_hdr_maxsz + \
					 decode_sequence_maxsz + \
					 decode_putfh_maxsz + \
					 decode_read_plus_maxsz)
#define NFS4_enc_seek_sz		(compound_encode_hdr_maxsz + \
					 encode_sequence_maxsz + \
					 encode_putfh_maxsz + \
@@ -324,6 +341,16 @@ static void encode_deallocate(struct xdr_stream *xdr,
	encode_fallocate(xdr, args);
}

static void encode_read_plus(struct xdr_stream *xdr,
			     const struct nfs_pgio_args *args,
			     struct compound_hdr *hdr)
{
	encode_op_hdr(xdr, OP_READ_PLUS, decode_read_plus_maxsz, hdr);
	encode_nfs4_stateid(xdr, &args->stateid);
	encode_uint64(xdr, args->offset);
	encode_uint32(xdr, args->count);
}

static void encode_seek(struct xdr_stream *xdr,
			const struct nfs42_seek_args *args,
			struct compound_hdr *hdr)
@@ -722,6 +749,28 @@ static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
	encode_nops(&hdr);
}

/*
 * Encode READ_PLUS request
 */
static void nfs4_xdr_enc_read_plus(struct rpc_rqst *req,
				   struct xdr_stream *xdr,
				   const void *data)
{
	const struct nfs_pgio_args *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_read_plus(xdr, args, &hdr);

	rpc_prepare_reply_pages(req, args->pages, args->pgbase,
				args->count, hdr.replen);
	encode_nops(&hdr);
}

/*
 * Encode SEEK request
 */
@@ -970,6 +1019,97 @@ static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *re
	return decode_op_hdr(xdr, OP_DEALLOCATE);
}

static int decode_read_plus_data(struct xdr_stream *xdr, struct nfs_pgio_res *res,
				 uint32_t *eof)
{
	uint32_t count, recvd;
	uint64_t offset;
	__be32 *p;

	p = xdr_inline_decode(xdr, 8 + 4);
	if (unlikely(!p))
		return -EIO;

	p = xdr_decode_hyper(p, &offset);
	count = be32_to_cpup(p);
	recvd = xdr_align_data(xdr, res->count, count);
	res->count += recvd;

	if (count > recvd) {
		dprintk("NFS: server cheating in read reply: "
				"count %u > recvd %u\n", count, recvd);
		*eof = 0;
		return 1;
	}

	return 0;
}

static int decode_read_plus_hole(struct xdr_stream *xdr, struct nfs_pgio_res *res,
				 uint32_t *eof)
{
	uint64_t offset, length, recvd;
	__be32 *p;

	p = xdr_inline_decode(xdr, 8 + 8);
	if (unlikely(!p))
		return -EIO;

	p = xdr_decode_hyper(p, &offset);
	p = xdr_decode_hyper(p, &length);
	recvd = xdr_expand_hole(xdr, res->count, length);
	res->count += recvd;

	if (recvd < length) {
		*eof = 0;
		return 1;
	}
	return 0;
}

static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res)
{
	uint32_t eof, segments, type;
	int status, i;
	__be32 *p;

	status = decode_op_hdr(xdr, OP_READ_PLUS);
	if (status)
		return status;

	p = xdr_inline_decode(xdr, 4 + 4);
	if (unlikely(!p))
		return -EIO;

	eof = be32_to_cpup(p++);
	segments = be32_to_cpup(p++);
	if (segments == 0)
		goto out;

	for (i = 0; i < segments; i++) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;

		type = be32_to_cpup(p++);
		if (type == NFS4_CONTENT_DATA)
			status = decode_read_plus_data(xdr, res, &eof);
		else if (type == NFS4_CONTENT_HOLE)
			status = decode_read_plus_hole(xdr, res, &eof);
		else
			return -EINVAL;

		if (status < 0)
			return status;
		if (status > 0)
			break;
	}

out:
	res->eof = eof;
	return 0;
}

static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res)
{
	int status;
@@ -1146,6 +1286,33 @@ out:
	return status;
}

/*
 * Decode READ_PLUS request
 */
static int nfs4_xdr_dec_read_plus(struct rpc_rqst *rqstp,
				  struct xdr_stream *xdr,
				  void *data)
{
	struct nfs_pgio_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_read_plus(xdr, res);
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode SEEK request
 */
Loading