diff mbox series

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

Message ID 168808889384.7728.12019491678161370671.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:34 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).

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

Patch

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 20e09e5510c9..8335ca1e2da0 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2948,6 +2948,7 @@  struct nfsd4_fattr_args {
 	struct nfs4_acl		*acl;
 	u32			rdattr_err;
 	bool			contextsupport;
+	bool			ignore_crossmnt;
 };
 
 typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr,
@@ -3276,6 +3277,191 @@  static const nfsd4_enc_attr nfsd4_enc_fattr4_word0_ops[] = {
 	[31]		= nfsd4_encode_fattr4_maxwrite,
 };
 
+static __be32 nfsd4_encode_fattr4_mode(struct xdr_stream *xdr,
+				       struct nfsd4_fattr_args *args)
+{
+	if (xdr_stream_encode_u32(xdr, args->stat.mode & S_IALLUGO) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_numlinks(struct xdr_stream *xdr,
+					   struct nfsd4_fattr_args *args)
+{
+	if (xdr_stream_encode_u32(xdr, args->stat.nlink) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_owner(struct xdr_stream *xdr,
+					struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_user(xdr, args->rqstp, args->stat.uid);
+}
+
+static __be32 nfsd4_encode_fattr4_owner_group(struct xdr_stream *xdr,
+					      struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_group(xdr, args->rqstp, args->stat.gid);
+}
+
+static __be32 nfsd4_encode_fattr4_rawdev(struct xdr_stream *xdr,
+					 struct nfsd4_fattr_args *args)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, 8);
+	if (!p)
+		return nfserr_resource;
+	*p++ = cpu_to_be32((u32) MAJOR(args->stat.rdev));
+	*p   = cpu_to_be32((u32) MINOR(args->stat.rdev));
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_avail(struct xdr_stream *xdr,
+					      struct nfsd4_fattr_args *args)
+{
+	u64 space = (u64)args->statfs.f_bavail * (u64)args->statfs.f_bsize;
+
+	if (xdr_stream_encode_u64(xdr, space) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_free(struct xdr_stream *xdr,
+					     struct nfsd4_fattr_args *args)
+{
+	u64 space = (u64)args->statfs.f_bfree * (u64)args->statfs.f_bsize;
+
+	if (xdr_stream_encode_u64(xdr, space) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_total(struct xdr_stream *xdr,
+					      struct nfsd4_fattr_args *args)
+{
+	u64 space = (u64)args->statfs.f_blocks * (u64)args->statfs.f_bsize;
+
+	if (xdr_stream_encode_u64(xdr, space) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_used(struct xdr_stream *xdr,
+					     struct nfsd4_fattr_args *args)
+{
+	u64 space = (u64)args->stat.blocks << 9;
+
+	if (xdr_stream_encode_u64(xdr, space) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_time_access(struct xdr_stream *xdr,
+					     struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_nfstime4(xdr, &args->stat.atime);
+}
+
+static __be32 nfsd4_encode_fattr4_time_create(struct xdr_stream *xdr,
+					      struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_nfstime4(xdr, &args->stat.btime);
+}
+
+static __be32 nfsd4_encode_fattr4_time_delta(struct xdr_stream *xdr,
+					     struct nfsd4_fattr_args *args)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 3);
+	if (!p)
+		return nfserr_resource;
+
+	encode_time_delta(p, d_inode(args->dentry));
+	return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_time_metadata(struct xdr_stream *xdr,
+						struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_nfstime4(xdr, &args->stat.ctime);
+}
+
+static __be32 nfsd4_encode_fattr4_time_modify(struct xdr_stream *xdr,
+					      struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_nfstime4(xdr, &args->stat.mtime);
+}
+
+static __be32 nfsd4_encode_fattr4_mounted_on_fileid(struct xdr_stream *xdr,
+						    struct nfsd4_fattr_args *args)
+{
+	u64 ino = args->stat.ino;
+	int err;
+
+	if (!args->ignore_crossmnt &&
+	    args->dentry == args->exp->ex_path.mnt->mnt_root) {
+		err = nfsd4_get_mounted_on_ino(args->exp, &ino);
+		if (err)
+			return nfserrno(err);
+	}
+
+	if (xdr_stream_encode_u64(xdr, ino) < 0)
+		return nfserr_resource;
+	return nfs_ok;
+}
+
+#ifdef CONFIG_NFSD_PNFS
+
+static __be32 nfsd4_encode_fattr4_layout_types(struct xdr_stream *xdr,
+					       struct nfsd4_fattr_args *args)
+{
+	return nfsd4_encode_layout_types(xdr, args->exp->ex_layout_types);
+}
+
+#endif
+
+static const nfsd4_enc_attr nfsd4_enc_fattr4_word1_ops[] = {
+	[0]		= nfsd4_encode_fattr4__noop,	/* mime type */
+	[1]		= nfsd4_encode_fattr4_mode,
+	[2]		= nfsd4_encode_fattr4__true,	/* no trunc */
+	[3]		= nfsd4_encode_fattr4_numlinks,
+	[4]		= nfsd4_encode_fattr4_owner,
+	[5]		= nfsd4_encode_fattr4_owner_group,
+	[6]		= nfsd4_encode_fattr4__noop,	/* quota_hard */
+	[7]		= nfsd4_encode_fattr4__noop,	/* quota_soft */
+	[8]		= nfsd4_encode_fattr4__noop,	/* quota_used */
+	[9]		= nfsd4_encode_fattr4_rawdev,
+	[10]		= nfsd4_encode_fattr4_space_avail,
+	[11]		= nfsd4_encode_fattr4_space_free,
+	[12]		= nfsd4_encode_fattr4_space_total,
+	[13]		= nfsd4_encode_fattr4_space_used,
+	[14]		= nfsd4_encode_fattr4__noop,	/* system */
+	[15]		= nfsd4_encode_fattr4_time_access,
+	[16]		= nfsd4_encode_fattr4__noop,	/* time_access_set */
+	[17]		= nfsd4_encode_fattr4__noop,	/* time_backup */
+	[18]		= nfsd4_encode_fattr4_time_create,
+	[19]		= nfsd4_encode_fattr4_time_delta,
+	[20]		= nfsd4_encode_fattr4_time_metadata,
+	[21]		= nfsd4_encode_fattr4_time_modify,
+	[22]		= nfsd4_encode_fattr4__noop,	/* time_modify_set */
+	[23]		= nfsd4_encode_fattr4_mounted_on_fileid,
+	[24]		= nfsd4_encode_fattr4__noop,	/* dir notif delay */
+	[25]		= nfsd4_encode_fattr4__noop,	/* dirent notif delay */
+	[26]		= nfsd4_encode_fattr4__noop,	/* dacl */
+	[27]		= nfsd4_encode_fattr4__noop,	/* sacl */
+	[28]		= nfsd4_encode_fattr4__noop,	/* change policy */
+	[29]		= nfsd4_encode_fattr4__noop,	/* fs status */
+#ifdef CONFIG_NFSD_PNFS
+	[30]		= nfsd4_encode_fattr4_layout_types,
+#else
+	[30]		= nfsd4_encode_fattr4__noop,
+#endif
+	[31]		= nfsd4_encode_fattr4__noop,	/* layout hint */
+};
+
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
  * ourselves.
@@ -3292,7 +3478,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;
-	u64 dummy64;
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 	void *context = NULL;
 	int contextlen;
@@ -3312,6 +3497,7 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 	args.fhp = fhp;
 	args.exp = exp;
 	args.dentry = dentry;
+	args.ignore_crossmnt = (ignore_crossmnt != 0);
 
 	args.rdattr_err = 0;
 	if (exp->ex_fslocs.migrated) {
@@ -3399,121 +3585,14 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 			goto out;
 	}
 
-	if (bmval1 & FATTR4_WORD1_MODE) {
-		p = xdr_reserve_space(xdr, 4);
-		if (!p)
-			goto out_resource;
-		*p++ = cpu_to_be32(args.stat.mode & S_IALLUGO);
-	}
-	if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
-		p = xdr_reserve_space(xdr, 4);
-		if (!p)
-			goto out_resource;
-		*p++ = cpu_to_be32(1);
-	}
-	if (bmval1 & FATTR4_WORD1_NUMLINKS) {
-		p = xdr_reserve_space(xdr, 4);
-		if (!p)
-			goto out_resource;
-		*p++ = cpu_to_be32(args.stat.nlink);
-	}
-	if (bmval1 & FATTR4_WORD1_OWNER) {
-		status = nfsd4_encode_user(xdr, rqstp, args.stat.uid);
-		if (status)
-			goto out;
-	}
-	if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-		status = nfsd4_encode_group(xdr, rqstp, args.stat.gid);
-		if (status)
-			goto out;
-	}
-	if (bmval1 & FATTR4_WORD1_RAWDEV) {
-		p = xdr_reserve_space(xdr, 8);
-		if (!p)
-			goto out_resource;
-		*p++ = cpu_to_be32((u32) MAJOR(args.stat.rdev));
-		*p++ = cpu_to_be32((u32) MINOR(args.stat.rdev));
-	}
-	if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
-		p = xdr_reserve_space(xdr, 8);
-		if (!p)
-			goto out_resource;
-		dummy64 = (u64)args.statfs.f_bavail * (u64)args.statfs.f_bsize;
-		p = xdr_encode_hyper(p, dummy64);
-	}
-	if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
-		p = xdr_reserve_space(xdr, 8);
-		if (!p)
-			goto out_resource;
-		dummy64 = (u64)args.statfs.f_bfree * (u64)args.statfs.f_bsize;
-		p = xdr_encode_hyper(p, dummy64);
-	}
-	if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
-		p = xdr_reserve_space(xdr, 8);
-		if (!p)
-			goto out_resource;
-		dummy64 = (u64)args.statfs.f_blocks * (u64)args.statfs.f_bsize;
-		p = xdr_encode_hyper(p, dummy64);
-	}
-	if (bmval1 & FATTR4_WORD1_SPACE_USED) {
-		p = xdr_reserve_space(xdr, 8);
-		if (!p)
-			goto out_resource;
-		dummy64 = (u64)args.stat.blocks << 9;
-		p = xdr_encode_hyper(p, dummy64);
-	}
-	if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
-		status = nfsd4_encode_nfstime4(xdr, &args.stat.atime);
-		if (status)
-			goto out;
-	}
-	if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
-		p = xdr_reserve_space(xdr, 12);
-		if (!p)
-			goto out_resource;
-		p = encode_time_delta(p, d_inode(dentry));
-	}
-	if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
-		status = nfsd4_encode_nfstime4(xdr, &args.stat.ctime);
-		if (status)
-			goto out;
-	}
-	if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
-		status = nfsd4_encode_nfstime4(xdr, &args.stat.mtime);
-		if (status)
-			goto out;
-	}
-	if (bmval1 & FATTR4_WORD1_TIME_CREATE) {
-		status = nfsd4_encode_nfstime4(xdr, &args.stat.btime);
+	mask = bmval1;
+	for_each_set_bit(i, &mask, 32) {
+		status = nfsd4_enc_fattr4_word1_ops[i](xdr, &args);
 		if (status)
 			goto out;
 	}
-	if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
-		u64 ino = args.stat.ino;
 
-		p = xdr_reserve_space(xdr, 8);
-		if (!p)
-                	goto out_resource;
-		/*
-		 * Get ino of mountpoint in parent filesystem, if not ignoring
-		 * crossmount and this is the root of a cross-mounted
-		 * filesystem.
-		 */
-		if (ignore_crossmnt == 0 &&
-		    dentry == exp->ex_path.mnt->mnt_root) {
-			err = nfsd4_get_mounted_on_ino(exp, &ino);
-			if (err)
-				goto out_nfserr;
-		}
-		p = xdr_encode_hyper(p, ino);
-	}
 #ifdef CONFIG_NFSD_PNFS
-	if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
-		status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
-		if (status)
-			goto out;
-	}
-
 	if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
 		status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
 		if (status)