From: Chuck Lever <cel@kernel.org>
To: NeilBrown <neil@brown.name>, Jeff Layton <jlayton@kernel.org>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <dai.ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: <linux-nfs@vger.kernel.org>
Subject: [PATCH v1 06/13] NFSD: Implement NFS-ACL v3 ACL encoding and decoding with xdrgen
Date: Sun, 25 Oct 2026 11:16:15 -0400 [thread overview]
Message-ID: <20261025151622.141025-7-cel@kernel.org> (raw)
In-Reply-To: <20261025151622.141025-1-cel@kernel.org>
The NFS-ACL v3 GETACL result encoder and SETACL argument decoder
cannot be generated the way the other procedures' codecs are: the
wire secattr is a Solaris projection of the kernel's struct
posix_acl, and the per-entry transformation between them -- tag and
id mapping, the canonical four-entry expansion that Solaris VxFS
interoperability requires, and counts gated by the request mask --
is application logic that xdrgen cannot synthesize. Keeping those two
codecs hand-rolled would force the generated NFSv3 types they call,
nfs_fh3, fattr3, and post_op_attr, to keep external linkage, and
those symbols would collide at link time with the public
definitions that nfs3xdr_gen.c already emits for NFSv3 proper.
Supply the nfsd side of xdrgen's hook-driven aggregate codec
mechanism. "pragma aggregate" markers on secattr's two aclent<>
members select the streaming codec, whose generated framing owns
the wire representation and drives per-element application hooks. The
hooks hold the posix_acl logic factored from
nfs_stream_encode_acl() and nfs_stream_decode_acl(); both arrays
share one hook set, with the cursor's member_id distinguishing the
access list from the default list. Wrapper structures pair each
generated argument or result type with the legacy application state
(svc_fh, posix_acl pointers, kstat), placing the generated type at
offset zero so rq_argp or rq_resp addresses both the generated type
the codec fills and the wrapper the hooks read. The hooks reach
that wrapper by way of the svc_rqst, which svcxdr_init_decode() and
svcxdr_init_encode() leave in the xdr_stream's application-private
pointer.
On decode, the begin hook validates the declared count and the
request mask, allocates the posix_acl at its known size, and
publishes it into the argument wrapper before any fallible
per-entry decode runs, so a mid-list failure leaves the ACL
reachable by pc_release rather than leaked. A zero-length published
default list stays NULL, which set_posix_acl() treats as ACL
removal.
A well-formed request that is nonetheless invalid -- an undefined
request mask bit, an empty access ACL, a perm bit outside rwx, an
undefined entry type, a user or group id with no kernel mapping, a
list whose declared count differs from its length, or more entries
than NFS_ACL_MAX_ENTRIES -- instead marks the argument wrapper and
lets the decode succeed, so nfsd3_proc_setacl() can report
ACL3ERR_INVAL rather than GARBAGE_ARGS (draft-ietf-nfsv4-nfs-acl
Section 3.4.4.2). The pre-conversion decoder rejected most of these
cases with GARBAGE_ARGS. It accepted an empty access ACL as a request
to remove the object's access ACL, an operation the protocol does not
define, and it cleared perm bits outside rwx in an NA_CLASS_OBJ entry
without complaint because Solaris clients were seen to set them. The
draft makes both invalid, so the NFS_ACLv3 server now reports
ACL3ERR_INVAL for them as well. These are deliberate, minor changes to
the SETACL wire behavior.
Because the containing codecs are fully generated, the NFSv3 types
the ACL specification re-declares stay static in nfs_acl3xdr_gen.c,
and no public pragma is needed.
Subsequent patches convert the GETACL and SETACL procedures to the
generated codecs.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
Documentation/sunrpc/xdr/nfs_acl3.x | 2 +
fs/nfsd/nfs3acl.c | 271 +++++++++++++++++++++++++
fs/nfsd/nfs_acl3xdr_gen.c | 138 ++++++++++---
fs/nfsd/nfs_acl3xdr_gen.h | 14 +-
include/linux/sunrpc/xdrgen/nfs_acl3.h | 2 +-
5 files changed, 400 insertions(+), 27 deletions(-)
diff --git a/Documentation/sunrpc/xdr/nfs_acl3.x b/Documentation/sunrpc/xdr/nfs_acl3.x
index b355705bf970..931a7d629603 100644
--- a/Documentation/sunrpc/xdr/nfs_acl3.x
+++ b/Documentation/sunrpc/xdr/nfs_acl3.x
@@ -91,6 +91,8 @@ struct secattr {
int dfaclcnt;
aclent dfaclent<NFS_ACL_MAX_ENTRIES>;
};
+pragma aggregate secattr aclent;
+pragma aggregate secattr dfaclent;
/*
* The values for the mask element of the secattr struct as well
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 048046af15c0..1fb9d265bc03 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -18,6 +18,52 @@
#define NFS_ACL_MASK (NA_ACL | NA_ACLCNT | NA_DFACL | NA_DFACLCNT)
+/*
+ * Wrapper structures combine xdrgen types with legacy structures.
+ * The xdrgen field must be first so the structure can be cast
+ * to its XDR type for the RPC dispatch layer.
+ */
+struct GETACL3args_wrapper {
+ struct GETACL3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct GETACL3args_wrapper, xdrgen) == 0);
+
+/*
+ * The ACL is encoded from the posix_acl fields below, so the
+ * generated secattr (xdrgen.u.resok.acl) is left unused.
+ */
+struct GETACL3res_wrapper {
+ struct GETACL3res xdrgen;
+ int mask;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+ struct kstat stat;
+};
+
+static_assert(offsetof(struct GETACL3res_wrapper, xdrgen) == 0);
+
+/*
+ * The ACLs are decoded by hand into the posix_acl fields below, so
+ * the generated aclent arrays (xdrgen.acl) are left unused.
+ */
+struct SETACL3args_wrapper {
+ struct SETACL3args xdrgen;
+ struct svc_fh fh;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+ /*
+ * Set when the wire ACL is well-formed XDR but semantically
+ * invalid. The decoder accepts the request so that
+ * nfsd3_proc_setacl can return ACL3ERR_INVAL rather than RPC
+ * GARBAGE_ARGS. See draft-ietf-nfsv4-nfs-acl Section 3.4.4.2.
+ */
+ bool invalid;
+};
+
+static_assert(offsetof(struct SETACL3args_wrapper, xdrgen) == 0);
+
struct nfsd3_getaclargs {
struct svc_fh fh;
__u32 mask;
@@ -110,6 +156,19 @@ static __be32 nfsd3_map_status(__be32 status)
return status;
}
+/*
+ * A minimal (three-entry) ACL travels as four wire entries: the
+ * POSIX entries plus a synthesized NA_CLASS_OBJ mask. The wire
+ * element count is thus max(a_count, 4) when the ACL has at least
+ * three entries, and zero otherwise. An ACL with fewer than three
+ * entries has no minimal set to expand, so it travels as empty.
+ * See draft-ietf-nfsv4-nfs-acl Section 3.4.4.2.
+ */
+static u32 nfs3acl_acl_entries(const struct posix_acl *acl)
+{
+ return (acl && acl->a_count >= 3) ? max_t(int, acl->a_count, 4) : 0;
+}
+
/**
* nfsd3_proc_null - NULL: Do nothing
* @rqstp: RPC transaction context
@@ -318,6 +377,218 @@ nfs3svc_encode_setaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh);
}
+/*
+ * Aggregate codec hooks for the generated secattr codec.
+ *
+ * The generated codec owns the wire framing and drives these hooks
+ * once per element; the hooks hold all posix_acl application logic. The
+ * application context (@c->ctx) is the svc_rqst, bound to the stream by
+ * svcxdr_init_{decode,encode}(); each hook reaches the proc's arg or
+ * result wrapper through rq_{argp,resp}.
+ * The cursor's member_id selects the member: it is
+ * NFS_ACL3_SECATTR_ACLENT or NFS_ACL3_SECATTR_DFACLENT.
+ */
+
+/* GETACL reply: stream the wire entries out of the source posix_acl. */
+
+bool nfs_acl3_secattr_encode_begin(struct xdrgen_aggregate_cursor *c)
+{
+ struct svc_rqst *rqstp = c->ctx;
+ struct GETACL3res_wrapper *resp = rqstp->rq_resp;
+ bool dfacl = c->member_id == NFS_ACL3_SECATTR_DFACLENT;
+ struct posix_acl *acl = dfacl ? resp->acl_default : resp->acl_access;
+ int gate = dfacl ? (resp->mask & NA_DFACL) : (resp->mask & NA_ACL);
+
+ c->count = gate ? nfs3acl_acl_entries(acl) : 0;
+ return true;
+}
+
+bool nfs_acl3_secattr_encode(struct xdrgen_aggregate_cursor *c,
+ struct aclent *out)
+{
+ struct svc_rqst *rqstp = c->ctx;
+ struct GETACL3res_wrapper *resp = rqstp->rq_resp;
+ bool dfacl = c->member_id == NFS_ACL3_SECATTR_DFACLENT;
+ struct posix_acl *acl = dfacl ? resp->acl_default : resp->acl_access;
+ int typeflag = dfacl ? NA_ACL_DEFAULT : 0;
+ const struct posix_acl_entry *entry;
+ int tag;
+
+ /*
+ * A three-entry ACL expands to four wire entries in ascending
+ * type order (USER_OBJ, GROUP_OBJ, a NA_CLASS_OBJ mask cloned
+ * from GROUP_OBJ, OTHER). Some receivers depend on this ordering.
+ * See draft-ietf-nfsv4-nfs-acl Section 3.4.4.2.
+ */
+ if (acl->a_count == 3) {
+ static const u8 map[4] = { 0, 1, 1, 2 };
+
+ entry = &acl->a_entries[map[c->index]];
+ tag = (c->index == 2) ? ACL_MASK : entry->e_tag;
+ } else {
+ entry = &acl->a_entries[c->index];
+ tag = entry->e_tag;
+ }
+
+ out->type = tag | typeflag;
+ switch (tag) {
+ case ACL_USER_OBJ:
+ out->id = from_kuid(&init_user_ns, resp->stat.uid);
+ break;
+ case ACL_GROUP_OBJ:
+ out->id = from_kgid(&init_user_ns, resp->stat.gid);
+ break;
+ case ACL_USER:
+ out->id = from_kuid(&init_user_ns, entry->e_uid);
+ break;
+ case ACL_GROUP:
+ out->id = from_kgid(&init_user_ns, entry->e_gid);
+ break;
+ default:
+ /*
+ * The id field is undefined for these entry types;
+ * emit zero per draft-ietf-nfsv4-nfs-acl Section 3.4.4.2.
+ */
+ out->id = 0;
+ break;
+ }
+ out->perm = entry->e_perm & (ACL_READ | ACL_WRITE | ACL_EXECUTE);
+ return true;
+}
+
+bool nfs_acl3_secattr_encode_end(struct xdrgen_aggregate_cursor *c, bool ok)
+{
+ return true;
+}
+
+/* SETACL args: consume the decoded wire entries into the target posix_acl. */
+
+bool nfs_acl3_secattr_decode_begin(struct xdrgen_aggregate_cursor *c)
+{
+ struct svc_rqst *rqstp = c->ctx;
+ struct SETACL3args_wrapper *argp = rqstp->rq_argp;
+ bool dfacl = c->member_id == NFS_ACL3_SECATTR_DFACLENT;
+ struct posix_acl **pacl = dfacl ? &argp->acl_default : &argp->acl_access;
+ u32 mask = argp->xdrgen.acl.mask;
+ u32 declared = dfacl ? (u32)argp->xdrgen.acl.dfaclcnt :
+ (u32)argp->xdrgen.acl.aclcnt;
+ int gate = dfacl ? (mask & NA_DFACL) : (mask & NA_ACL);
+
+ /* Already rejected: consume the list. */
+ if (argp->invalid)
+ return true;
+ /* The access list is decoded first, so the mask is checked once. */
+ if (!dfacl && (mask & ~NFS_ACL_MASK)) {
+ argp->invalid = true;
+ return true;
+ }
+ /* Too many ACEs is an invalid ACL, not a malformed request. */
+ if (declared > NFS_ACL_MAX_ENTRIES) {
+ argp->invalid = true;
+ return true;
+ }
+
+ if (gate) {
+ /*
+ * A published list whose declared count differs from its
+ * length is an invalid ACL, not a malformed request.
+ */
+ if (c->count != declared) {
+ argp->invalid = true;
+ return true;
+ }
+ if (!dfacl && !c->count) {
+ argp->invalid = true;
+ return true;
+ }
+ /* An empty default list publishes NULL: default ACL removal. */
+ if (c->count) {
+ *pacl = posix_acl_alloc(c->count, GFP_KERNEL);
+ if (!*pacl)
+ return false;
+ }
+ } else if (c->count > declared) {
+ argp->invalid = true;
+ return true;
+ }
+ return true;
+}
+
+bool nfs_acl3_secattr_decode(struct xdrgen_aggregate_cursor *c,
+ const struct aclent *in)
+{
+ struct svc_rqst *rqstp = c->ctx;
+ struct SETACL3args_wrapper *argp = rqstp->rq_argp;
+ bool dfacl = c->member_id == NFS_ACL3_SECATTR_DFACLENT;
+ struct posix_acl *acl = dfacl ? argp->acl_default : argp->acl_access;
+ struct posix_acl_entry *entry;
+
+ /* Already rejected, or list gated out by mask: consume it. */
+ if (argp->invalid || !acl)
+ return true;
+
+ /* A perm bit outside rwx makes the ACL invalid. */
+ if (in->perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) {
+ argp->invalid = true;
+ return true;
+ }
+
+ /* A type bit the protocol does not define makes the ACL invalid. */
+ if (in->type & ~(NA_USER_OBJ | NA_USER | NA_GROUP_OBJ | NA_GROUP |
+ NA_CLASS_OBJ | NA_OTHER_OBJ | NA_ACL_DEFAULT)) {
+ argp->invalid = true;
+ return true;
+ }
+
+ entry = &acl->a_entries[c->index];
+ entry->e_tag = in->type & ~NA_ACL_DEFAULT;
+ entry->e_perm = in->perm;
+ switch (entry->e_tag) {
+ case ACL_USER:
+ /* An id with no kernel mapping makes the ACL invalid. */
+ entry->e_uid = make_kuid(&init_user_ns, in->id);
+ if (!uid_valid(entry->e_uid)) {
+ argp->invalid = true;
+ return true;
+ }
+ break;
+ case ACL_GROUP:
+ entry->e_gid = make_kgid(&init_user_ns, in->id);
+ if (!gid_valid(entry->e_gid)) {
+ argp->invalid = true;
+ return true;
+ }
+ break;
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_OTHER:
+ case ACL_MASK:
+ break;
+ default:
+ /* An undefined entry type makes the ACL invalid. */
+ argp->invalid = true;
+ return true;
+ }
+
+ return true;
+}
+
+bool nfs_acl3_secattr_decode_end(struct xdrgen_aggregate_cursor *c, bool ok)
+{
+ struct svc_rqst *rqstp = c->ctx;
+ struct SETACL3args_wrapper *argp = rqstp->rq_argp;
+ bool dfacl = c->member_id == NFS_ACL3_SECATTR_DFACLENT;
+ struct posix_acl *acl = dfacl ? argp->acl_default : argp->acl_access;
+
+ /*
+ * On failure the published ACL stays reachable through the arg
+ * wrapper and is freed by pc_release; nothing to do here.
+ */
+ if (!ok || argp->invalid)
+ return true;
+ return posix_acl_from_nfsacl(acl) == 0;
+}
+
/*
* XDR release functions
*/
diff --git a/fs/nfsd/nfs_acl3xdr_gen.c b/fs/nfsd/nfs_acl3xdr_gen.c
index 05e35653a0fc..bbd8bb7d79d3 100644
--- a/fs/nfsd/nfs_acl3xdr_gen.c
+++ b/fs/nfsd/nfs_acl3xdr_gen.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Generated by xdrgen. Manual edits will be lost.
// XDR specification file: ../../Documentation/sunrpc/xdr/nfs_acl3.x
-// XDR specification modification time: Fri Jul 10 20:12:08 2026
+// XDR specification modification time: Fri Jul 10 20:12:44 2026
#include <linux/sunrpc/svc.h>
@@ -38,22 +38,66 @@ xdrgen_decode_secattr(struct xdr_stream *xdr, struct secattr *ptr)
return false;
if (!xdrgen_decode_int(xdr, &ptr->aclcnt))
return false;
- if (xdr_stream_decode_u32(xdr, &ptr->aclent.count) < 0)
- return false;
- if (ptr->aclent.count > NFS_ACL_MAX_ENTRIES)
- return false;
- for (u32 i = 0; i < ptr->aclent.count; i++)
- if (!xdrgen_decode_aclent(xdr, &ptr->aclent.element[i]))
+ {
+ struct xdrgen_aggregate_cursor cursor = {
+ .xdr = xdr,
+ .member_id = NFS_ACL3_SECATTR_ACLENT,
+ .ctx = xdr->xdrgen_ctx,
+ };
+ bool ok = true;
+
+ if (xdr_stream_decode_u32(xdr, &cursor.count) < 0)
return false;
+ if (cursor.count > NFS_ACL_MAX_ENTRIES)
+ return false;
+ if (!nfs_acl3_secattr_decode_begin(&cursor))
+ return false;
+ for (cursor.index = 0; cursor.index < cursor.count; cursor.index++) {
+ struct aclent element = {};
+
+ if (!xdrgen_decode_aclent(xdr, &element)) {
+ ok = false;
+ break;
+ }
+ if (!nfs_acl3_secattr_decode(&cursor, &element)) {
+ ok = false;
+ break;
+ }
+ }
+ if (!nfs_acl3_secattr_decode_end(&cursor, ok) || !ok)
+ return false;
+ }
if (!xdrgen_decode_int(xdr, &ptr->dfaclcnt))
return false;
- if (xdr_stream_decode_u32(xdr, &ptr->dfaclent.count) < 0)
- return false;
- if (ptr->dfaclent.count > NFS_ACL_MAX_ENTRIES)
- return false;
- for (u32 i = 0; i < ptr->dfaclent.count; i++)
- if (!xdrgen_decode_aclent(xdr, &ptr->dfaclent.element[i]))
+ {
+ struct xdrgen_aggregate_cursor cursor = {
+ .xdr = xdr,
+ .member_id = NFS_ACL3_SECATTR_DFACLENT,
+ .ctx = xdr->xdrgen_ctx,
+ };
+ bool ok = true;
+
+ if (xdr_stream_decode_u32(xdr, &cursor.count) < 0)
return false;
+ if (cursor.count > NFS_ACL_MAX_ENTRIES)
+ return false;
+ if (!nfs_acl3_secattr_decode_begin(&cursor))
+ return false;
+ for (cursor.index = 0; cursor.index < cursor.count; cursor.index++) {
+ struct aclent element = {};
+
+ if (!xdrgen_decode_aclent(xdr, &element)) {
+ ok = false;
+ break;
+ }
+ if (!nfs_acl3_secattr_decode(&cursor, &element)) {
+ ok = false;
+ break;
+ }
+ }
+ if (!nfs_acl3_secattr_decode_end(&cursor, ok) || !ok)
+ return false;
+ }
return true;
}
@@ -431,22 +475,66 @@ xdrgen_encode_secattr(struct xdr_stream *xdr, const struct secattr *value)
return false;
if (!xdrgen_encode_int(xdr, value->aclcnt))
return false;
- if (value->aclent.count > NFS_ACL_MAX_ENTRIES)
- return false;
- if (xdr_stream_encode_u32(xdr, value->aclent.count) != XDR_UNIT)
- return false;
- for (u32 i = 0; i < value->aclent.count; i++)
- if (!xdrgen_encode_aclent(xdr, &value->aclent.element[i]))
+ {
+ struct xdrgen_aggregate_cursor cursor = {
+ .xdr = xdr,
+ .member_id = NFS_ACL3_SECATTR_ACLENT,
+ .ctx = xdr->xdrgen_ctx,
+ };
+ bool ok = true;
+
+ if (!nfs_acl3_secattr_encode_begin(&cursor))
return false;
+ if (cursor.count > NFS_ACL_MAX_ENTRIES)
+ ok = false;
+ if (ok && xdr_stream_encode_u32(xdr, cursor.count) != XDR_UNIT)
+ ok = false;
+ for (cursor.index = 0; ok && cursor.index < cursor.count; cursor.index++) {
+ struct aclent element = {};
+
+ if (!nfs_acl3_secattr_encode(&cursor, &element)) {
+ ok = false;
+ break;
+ }
+ if (!xdrgen_encode_aclent(xdr, &element)) {
+ ok = false;
+ break;
+ }
+ }
+ if (!nfs_acl3_secattr_encode_end(&cursor, ok) || !ok)
+ return false;
+ }
if (!xdrgen_encode_int(xdr, value->dfaclcnt))
return false;
- if (value->dfaclent.count > NFS_ACL_MAX_ENTRIES)
- return false;
- if (xdr_stream_encode_u32(xdr, value->dfaclent.count) != XDR_UNIT)
- return false;
- for (u32 i = 0; i < value->dfaclent.count; i++)
- if (!xdrgen_encode_aclent(xdr, &value->dfaclent.element[i]))
+ {
+ struct xdrgen_aggregate_cursor cursor = {
+ .xdr = xdr,
+ .member_id = NFS_ACL3_SECATTR_DFACLENT,
+ .ctx = xdr->xdrgen_ctx,
+ };
+ bool ok = true;
+
+ if (!nfs_acl3_secattr_encode_begin(&cursor))
return false;
+ if (cursor.count > NFS_ACL_MAX_ENTRIES)
+ ok = false;
+ if (ok && xdr_stream_encode_u32(xdr, cursor.count) != XDR_UNIT)
+ ok = false;
+ for (cursor.index = 0; ok && cursor.index < cursor.count; cursor.index++) {
+ struct aclent element = {};
+
+ if (!nfs_acl3_secattr_encode(&cursor, &element)) {
+ ok = false;
+ break;
+ }
+ if (!xdrgen_encode_aclent(xdr, &element)) {
+ ok = false;
+ break;
+ }
+ }
+ if (!nfs_acl3_secattr_encode_end(&cursor, ok) || !ok)
+ return false;
+ }
return true;
}
diff --git a/fs/nfsd/nfs_acl3xdr_gen.h b/fs/nfsd/nfs_acl3xdr_gen.h
index 8d960c0506db..629a06566ca7 100644
--- a/fs/nfsd/nfs_acl3xdr_gen.h
+++ b/fs/nfsd/nfs_acl3xdr_gen.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Generated by xdrgen. Manual edits will be lost. */
/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs_acl3.x */
-/* XDR specification modification time: Fri Jul 10 20:12:08 2026 */
+/* XDR specification modification time: Fri Jul 10 20:12:44 2026 */
#ifndef _LINUX_XDRGEN_NFS_ACL3_DECL_H
#define _LINUX_XDRGEN_NFS_ACL3_DECL_H
@@ -13,6 +13,18 @@
#include <linux/sunrpc/xdrgen/_builtins.h>
#include <linux/sunrpc/xdrgen/nfs_acl3.h>
+enum {
+ NFS_ACL3_SECATTR_ACLENT,
+ NFS_ACL3_SECATTR_DFACLENT,
+};
+
+bool nfs_acl3_secattr_encode_begin(struct xdrgen_aggregate_cursor *c);
+bool nfs_acl3_secattr_encode(struct xdrgen_aggregate_cursor *c, struct aclent *out);
+bool nfs_acl3_secattr_encode_end(struct xdrgen_aggregate_cursor *c, bool ok);
+bool nfs_acl3_secattr_decode_begin(struct xdrgen_aggregate_cursor *c);
+bool nfs_acl3_secattr_decode(struct xdrgen_aggregate_cursor *c, const struct aclent *in);
+bool nfs_acl3_secattr_decode_end(struct xdrgen_aggregate_cursor *c, bool ok);
+
bool nfs_acl_svc_decode_GETACL3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs_acl_svc_decode_SETACL3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs_acl_svc_decode_GETXATTRDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
diff --git a/include/linux/sunrpc/xdrgen/nfs_acl3.h b/include/linux/sunrpc/xdrgen/nfs_acl3.h
index 4d71e4907261..92c0d1e0b0a8 100644
--- a/include/linux/sunrpc/xdrgen/nfs_acl3.h
+++ b/include/linux/sunrpc/xdrgen/nfs_acl3.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Generated by xdrgen. Manual edits will be lost. */
/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs_acl3.x */
-/* XDR specification modification time: Fri Jul 10 20:12:08 2026 */
+/* XDR specification modification time: Fri Jul 10 20:12:44 2026 */
#ifndef _LINUX_XDRGEN_NFS_ACL3_DEF_H
#define _LINUX_XDRGEN_NFS_ACL3_DEF_H
--
2.56.0
next prev parent reply other threads:[~2026-10-26 21:36 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-25 15:16 [PATCH v1 00/13] Convert server-side NFS_ACLv3 XDR to use xdrgen Chuck Lever
2026-10-25 15:16 ` [PATCH v1 01/13] Documentation: Add the RPC language description of NFS_ACLv3 Chuck Lever
2026-10-25 15:16 ` [PATCH v1 02/13] NFSD: Add infrastructure for generating NFS_ACLv3 XDR encoders and decoders Chuck Lever
2026-10-25 15:16 ` [PATCH v1 03/13] NFSD: Remove '#include "xdr3.h"' from nfs3acl.c Chuck Lever
2026-10-25 15:16 ` [PATCH v1 04/13] NFSD: New NFS_ACLv3 status codes Chuck Lever
2026-10-25 15:16 ` [PATCH v1 05/13] NFSD: Use xdrgen XDR functions for the NFS-ACL v3 NULL procedure Chuck Lever
2026-10-25 15:16 ` Chuck Lever [this message]
2026-10-25 15:16 ` [PATCH v1 07/13] NFSD: Use xdrgen XDR functions for the NFS-ACL v3 GETACL procedure Chuck Lever
2026-10-25 15:16 ` [PATCH v1 08/13] NFSD: Use xdrgen XDR functions for the NFS-ACL v3 SETACL procedure Chuck Lever
2026-10-25 15:16 ` [PATCH v1 09/13] NFSD: Map every NFS_ACLv3 reply status into aclstat3 Chuck Lever
2026-10-25 15:16 ` [PATCH v1 10/13] NFSD: Remove the hand-coded XDR helpers for the NFS_ACLv3 procedures Chuck Lever
2026-10-25 15:16 ` [PATCH v1 11/13] NFS: Move NFSACL_MAXPAGES into fs/nfs/nfs3_fs.h Chuck Lever
2026-10-26 22:50 ` Anna Schumaker
2026-10-25 15:16 ` [PATCH v1 12/13] NFSD: Share the attribute conversion helpers with the NFS_ACL procs Chuck Lever
2026-10-25 15:16 ` [PATCH v1 13/13] nfs_common: Remove the unused NFS ACL stream codecs Chuck Lever
2026-10-27 10:56 ` [PATCH v1 00/13] Convert server-side NFS_ACLv3 XDR to use xdrgen Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261025151622.141025-7-cel@kernel.org \
--to=cel@kernel.org \
--cc=dai.ngo@oracle.com \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox