From: Chuck Lever <chuck.lever@xxxxxxxxxx> 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@xxxxxxxxxx> --- fs/nfsd/nfs4xdr.c | 153 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 52 deletions(-) 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) {