All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.