Linux NFS development
 help / color / mirror / Atom feed
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 v3 10/10] xdrgen: Stream optional-data aggregate lists during encode
Date: Tue,  8 Sep 2026 09:42:34 -0400	[thread overview]
Message-ID: <20260908134234.512312-11-cel@kernel.org> (raw)
In-Reply-To: <20260908134234.512312-1-cel@kernel.org>

The optional-data aggregate encoder loops cursor.count times, so the
begin hook must report the element count before the first element is
written.  A producer that reads its elements while the reply is
encoded -- NFSv2 READDIR streaming directory entries straight into the
send buffer -- does not know that count in advance, and would have to
materialize the whole list just to satisfy the loop bound.

An optional-data list carries no count on the wire, so nothing forces
one on the encoder.  Drive it from the item hook instead: a false
return ends the list, and the framing writes the terminator.

The counted-array form and its hook contract are unchanged.  No
in-tree spec marks an optional-data member yet, so no generated code
changes here.

Signed-off-by: Chuck Lever <cel@kernel.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
---
 include/linux/sunrpc/xdrgen/_defs.h           | 27 ++++++++++++-------
 tools/net/sunrpc/xdrgen/README                | 10 +++++--
 .../C/struct/encoder/aggregate_optional.j2    |  6 ++---
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/include/linux/sunrpc/xdrgen/_defs.h b/include/linux/sunrpc/xdrgen/_defs.h
index f4375d73c5ca..d767206feea4 100644
--- a/include/linux/sunrpc/xdrgen/_defs.h
+++ b/include/linux/sunrpc/xdrgen/_defs.h
@@ -30,15 +30,24 @@ typedef struct {
 } opaque;
 
 /*
- * Cursor a hook-driven aggregate codec hands to its application hooks,
- * one element at a time, in place of a materialized C array. The
- * generated framing owns it. @xdr is the RPC layer's stream; @ctx is
- * that stream's xdrgen_ctx, the svc_rqst on the server. @index is
- * the current element and @count the wire array length: a decoder
- * fills @count from the wire before the begin hook runs, an
- * encoder's begin hook sets it. @member_id selects among a type's
- * marked members. The begin/item/end contract is under "Pragma
- * aggregate" in tools/net/sunrpc/xdrgen/README.
+ * Cursor a hook-driven aggregate codec hands to its begin/item/end
+ * hooks, one element at a time, in place of a materialized C array.
+ * The generated framing owns it. @xdr is the RPC layer's stream and
+ * @ctx its xdrgen_ctx, the svc_rqst on the server. @index is the
+ * current element; @member_id selects among a type's marked members.
+ * For a counted array @count is the wire length: a decoder fills it
+ * before the begin hook runs, an encoder's begin hook sets it. The
+ * hook contract is under "Pragma aggregate" in
+ * tools/net/sunrpc/xdrgen/README.
+ *
+ * An optional-data list ("type *name") carries no count. Its encoder
+ * pulls elements until the item hook returns false. False ends the
+ * list rather than failing the encode: the framing writes the
+ * value-follows terminator, so a producer that stops early leaves a
+ * valid truncated list on the wire. A producer that stops for a
+ * mid-list error records it in the application state @ctx reaches,
+ * and either returns false from the end hook, which fails the
+ * encode, or reports it in the procedure status.
  */
 struct xdrgen_aggregate_cursor {
 	struct xdr_stream	*xdr;
diff --git a/tools/net/sunrpc/xdrgen/README b/tools/net/sunrpc/xdrgen/README
index 2e230c43de2f..9f9a4d8bc7ae 100644
--- a/tools/net/sunrpc/xdrgen/README
+++ b/tools/net/sunrpc/xdrgen/README
@@ -182,7 +182,13 @@ no count: each element is prefixed by a value-follows TRUE and the
 sequence is closed by a FALSE, which the framing writes after the
 last element. The element type must therefore be a pointer type,
 whose codec owns that framing; xdrgen rejects any other element
-type. For the optional-data form xdrgen generates a working
+type. That form has no count to loop on, so its encoder pulls
+elements until the item hook returns false. False ends the list
+rather than failing the encode: a producer stops when its source
+is exhausted or when a reply budget fills. A producer that stops
+for an error records it in its own state and either fails the
+encode from the end hook or reports it in the procedure status.
+For the optional-data form xdrgen generates a working
 encoder only; the decoder it emits fails without consuming the
 list, so xdrgen also rejects the directive when the struct is
 reachable from an RPC argument.
@@ -208,7 +214,7 @@ member:
 For a variable-length array, a decoder fills the cursor's count from
 the wire before calling the begin hook, and an encoder's begin hook
 sets that count for the framing to bound-check and emit. An
-optional-data list's encoder begin hook sets the count as well; its
+optional-data list's encoder does not read the count and its
 decoder never fills it. Once a begin hook
 has succeeded its end hook runs, so that it can release what begin
 took; the end hook receives the running success flag.
diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/aggregate_optional.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/aggregate_optional.j2
index d45b823225f7..4f35b6976109 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/aggregate_optional.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/aggregate_optional.j2
@@ -12,13 +12,11 @@
 
 		if (!{{ hook }}_encode_begin(&cursor))
 			return false;
-		for (cursor.index = 0; cursor.index < cursor.count; cursor.index++) {
+		for (cursor.index = 0; ; cursor.index++) {
 			{{ classifier }}{{ c_type }} element = {};
 
-			if (!{{ hook }}_encode(&cursor, &element)) {
-				ok = false;
+			if (!{{ hook }}_encode(&cursor, &element))
 				break;
-			}
 			if (!xdrgen_encode_{{ type }}(xdr, &element)) {
 				ok = false;
 				break;
-- 
2.55.0


      parent reply	other threads:[~2026-09-08 13:42 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-08 13:42 [PATCH v3 00/10] New pragmas for the xdrgen tool Chuck Lever
2026-09-08 13:42 ` [PATCH v3 01/10] SUNRPC: Carry a generated-codec context pointer in struct xdr_stream Chuck Lever
2026-09-09 23:31   ` NeilBrown
2026-09-08 13:42 ` [PATCH v3 02/10] SUNRPC: Bind the svc_rqst to its XDR streams Chuck Lever
2026-09-08 13:42 ` [PATCH v3 03/10] SUNRPC: Add svcxdr_encode_opaque_payload() Chuck Lever
2026-09-08 13:42 ` [PATCH v3 04/10] xdrgen: Pass the containing struct name to member codec emitters Chuck Lever
2026-09-08 13:42 ` [PATCH v3 05/10] xdrgen: Add a "pragma pages" directive Chuck Lever
2026-09-08 13:42 ` [PATCH v3 06/10] SUNRPC: Add svcxdr_decode_opaque_payload() Chuck Lever
2026-09-08 13:42 ` [PATCH v3 07/10] xdrgen: Extend the pages directive to page-resident arguments Chuck Lever
2026-09-08 13:42 ` [PATCH v3 08/10] xdrgen: Add hook-driven aggregate codec for variable-length arrays Chuck Lever
2026-09-08 13:42 ` [PATCH v3 09/10] xdrgen: Extend the aggregate codec to optional-data list members Chuck Lever
2026-09-08 13:42 ` Chuck Lever [this message]

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=20260908134234.512312-11-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