diff mbox series

[RFC,4/4] NFSD: Encode attributes in WORD2 using a bitmask loop

Message ID 168808890015.7728.16717581858127708439.stgit@manet.1015granger.net (mailing list archive)
State New, archived
Headers show
Series Encode NFSv4 attributes via a branch table | expand

Commit Message

Chuck Lever June 30, 2023, 1:35 a.m. UTC
From: Chuck Lever <chuck.lever@oracle.com>

Replace the current implementation with a branch table. This creates
hard function scope boundaries, limiting side effects and reducing
instruction cache footprint (uncalled encoders remain out of the
cache).

This also makes it obvious which attributes are not supported by the
Linux NFS server.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs4xdr.c |  153 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 101 insertions(+), 52 deletions(-)
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 8335ca1e2da0..31dccf6d1caa 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2946,6 +2946,10 @@  struct nfsd4_fattr_args {
 	struct kstat		stat;
 	struct kstatfs		statfs;
 	struct nfs4_acl		*acl;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	void			*context;
+	int			contextlen;
+#endif
 	u32			rdattr_err;
 	bool			contextsupport;
 	bool			ignore_crossmnt;
@@ -3421,6 +3425,14 @@  static __be32 nfsd4_encode_fattr4_layout_types(struct xdr_stream *xdr,
 	return nfsd4_encode_layout_types(xdr, args->exp->ex_layout_types);
 }
 
+static __be32 nfsd4_encode_fattr4_layout_blksize(struct xdr_stream *xdr,
+						 struct nfsd4_fattr_args *args)
+{
+	if (xdr_stream_encode_u32(xdr, args->stat.blksize) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
 #endif
 
 static const nfsd4_enc_attr nfsd4_enc_fattr4_word1_ops[] = {
@@ -3462,6 +3474,84 @@  static const nfsd4_enc_attr nfsd4_enc_fattr4_word1_ops[] = {
 	[31]		= nfsd4_encode_fattr4__noop,	/* layout hint */
 };
 
+static __be32 nfsd4_encode_fattr4_suppattr_exclcreat(struct xdr_stream *xdr,
+						     struct nfsd4_fattr_args *args)
+{
+	struct nfsd4_compoundres *resp = args->rqstp->rq_resp;
+	u32 minorversion = resp->cstate.minorversion;
+	u32 supp[3];
+
+	memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
+	supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
+	supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
+	supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
+
+	return nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
+}
+
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+static __be32 nfsd4_encode_fattr4_sec_label(struct xdr_stream *xdr,
+					    struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_security_label(xdr, args->rqstp,
+					   args->context, args->contextlen);
+}
+#endif
+
+static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr,
+						struct nfsd4_fattr_args *args)
+{
+	int err = xattr_supports_user_prefix(d_inode(args->dentry));
+
+	if (xdr_stream_encode_bool(xdr, err == 0) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static const nfsd4_enc_attr nfsd4_enc_fattr4_word2_ops[] = {
+#ifdef CONFIG_NFSD_PNFS
+	[0]		= nfsd4_encode_fattr4_layout_types,
+	[1]		= nfsd4_encode_fattr4_layout_blksize,
+#else
+	[0]		= nfsd4_encode_fattr4__noop,
+	[1]		= nfsd4_encode_fattr4__noop,
+#endif
+	[2]		= nfsd4_encode_fattr4__noop,	/* layout alignment */
+	[3]		= nfsd4_encode_fattr4__noop,	/* fslocations info */
+	[4]		= nfsd4_encode_fattr4__noop,	/* mds threshold */
+	[5]		= nfsd4_encode_fattr4__noop,	/* retention get */
+	[6]		= nfsd4_encode_fattr4__noop,	/* retention set */
+	[7]		= nfsd4_encode_fattr4__noop,	/* retentevt get */
+	[8]		= nfsd4_encode_fattr4__noop,	/* retentevt set */
+	[9]		= nfsd4_encode_fattr4__noop,	/* retention hold */
+	[10]		= nfsd4_encode_fattr4__noop,	/* mode set mask */
+	[11]		= nfsd4_encode_fattr4_suppattr_exclcreat,
+	[12]		= nfsd4_encode_fattr4__noop,	/* fs charset cap */
+	[13]		= nfsd4_encode_fattr4__noop,	/* clone blksize */
+	[14]		= nfsd4_encode_fattr4__noop,	/* space freed */
+	[15]		= nfsd4_encode_fattr4__noop,	/* change attr type */
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	[16]		= nfsd4_encode_fattr4_sec_label,
+#else
+	[16]		= nfsd4_encode_fattr4__noop,
+#endif
+	[17]		= nfsd4_encode_fattr4__noop,	/* mode_umask */
+	[18]		= nfsd4_encode_fattr4_xattr_support,
+	[19]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[20]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[21]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[22]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[23]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[24]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[25]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[26]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[27]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[28]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[29]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[30]		= nfsd4_encode_fattr4__noop,	/* reserved */
+	[31]		= nfsd4_encode_fattr4__noop,	/* reserved */
+};
+
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
  * ourselves.
@@ -3478,12 +3568,6 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 	u32 bmval2 = bmval[2];
 	struct svc_fh *tempfh = NULL;
 	int starting_len = xdr->buf->len;
-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-	void *context = NULL;
-	int contextlen;
-#endif
-	struct nfsd4_compoundres *resp = rqstp->rq_resp;
-	u32 minorversion = resp->cstate.minorversion;
 	int err, i, attrlen_offset;
 	__be32 status, *attrlen_p;
 	struct path path = {
@@ -3491,7 +3575,6 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 		.dentry	= dentry,
 	};
 	unsigned long mask;
-	__be32 *p;
 
 	args.rqstp = rqstp;
 	args.fhp = fhp;
@@ -3552,11 +3635,12 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 	args.contextsupport = false;
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	args.context = NULL;
 	if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
 	     bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
 		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
 			err = security_inode_getsecctx(d_inode(dentry),
-						&context, &contextlen);
+						&args.context, &args.contextlen);
 		else
 			err = -EOPNOTSUPP;
 		args.contextsupport = (err == 0);
@@ -3592,48 +3676,13 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 			goto out;
 	}
 
-#ifdef CONFIG_NFSD_PNFS
-	if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
-		status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
-		if (status)
-			goto out;
-	}
-
-	if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) {
-		p = xdr_reserve_space(xdr, 4);
-		if (!p)
-			goto out_resource;
-		*p++ = cpu_to_be32(args.stat.blksize);
-	}
-#endif /* CONFIG_NFSD_PNFS */
-	if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
-		u32 supp[3];
-
-		memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
-		supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
-		supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
-		supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
-
-		status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
-		if (status)
-			goto out;
-	}
-
-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-	if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
-		status = nfsd4_encode_security_label(xdr, rqstp, context,
-								contextlen);
-		if (status)
-			goto out;
-	}
-#endif
-
-	if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) {
-		p = xdr_reserve_space(xdr, 4);
-		if (!p)
-			goto out_resource;
-		err = xattr_supports_user_prefix(d_inode(dentry));
-		*p++ = cpu_to_be32(err == 0);
+	if (bmval2) {
+		mask = bmval2;
+		for_each_set_bit(i, &mask, 32) {
+			status = nfsd4_enc_fattr4_word2_ops[i](xdr, &args);
+			if (status)
+				goto out;
+		}
 	}
 
 	*attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT);
@@ -3641,8 +3690,8 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 
 out:
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-	if (context)
-		security_release_secctx(context, contextlen);
+	if (args.context)
+		security_release_secctx(args.context, args.contextlen);
 #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
 	kfree(args.acl);
 	if (tempfh) {