summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-18 10:53:12 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-26 22:17:22 -0600
commite7f3db0679e5d37970a06f428208c3f5b51db5d2 (patch)
tree607b6716d89fb1615dda1bc27e582bed23043f68
parent865bb702f828784a0225b5eae9ed8803094140d5 (diff)
-rw-r--r--lib9p/9p.generated.c45
-rw-r--r--lib9p/include/lib9p/9p.generated.h46
-rw-r--r--lib9p/include/lib9p/srv.h5
-rw-r--r--lib9p/protogen/c9util.py2
-rw-r--r--lib9p/protogen/c_marshal.py9
-rw-r--r--lib9p/protogen/c_unmarshal.py14
-rw-r--r--lib9p/protogen/h.py14
-rw-r--r--lib9p/srv.c19
8 files changed, 112 insertions, 42 deletions
diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c
index 6726084..868d936 100644
--- a/lib9p/9p.generated.c
+++ b/lib9p/9p.generated.c
@@ -2259,7 +2259,11 @@ static void unmarshal_Rread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
UNMARSHAL_U32LE(ctx, out->count);
- UNMARSHAL_BYTES(ctx, out->data, out->count);
+ out->data.iov = ctx->extra;
+ ctx->extra += sizeof(out->data.iov[0]);
+ out->data.iov->iov_base = &ctx->net_bytes[ctx->net_offset];
+ out->data.iov->iov_len = out->count;
+ out->data.iovcnt = 1;
}
static void unmarshal_Twrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
@@ -2272,7 +2276,11 @@ static void unmarshal_Twrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->fid);
UNMARSHAL_U64LE(ctx, out->offset);
UNMARSHAL_U32LE(ctx, out->count);
- UNMARSHAL_BYTES(ctx, out->data, out->count);
+ out->data.iov = ctx->extra;
+ ctx->extra += sizeof(out->data.iov[0]);
+ out->data.iov->iov_base = &ctx->net_bytes[ctx->net_offset];
+ out->data.iov->iov_len = out->count;
+ out->data.iovcnt = 1;
}
static void unmarshal_Rwrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
@@ -2772,7 +2780,11 @@ static void unmarshal_Rreaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
UNMARSHAL_U32LE(ctx, out->count);
- UNMARSHAL_BYTES(ctx, out->data, out->count);
+ out->data.iov = ctx->extra;
+ ctx->extra += sizeof(out->data.iov[0]);
+ out->data.iov->iov_base = &ctx->net_bytes[ctx->net_offset];
+ out->data.iov->iov_len = out->count;
+ out->data.iovcnt = 1;
}
static void unmarshal_Tfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
@@ -2993,7 +3005,11 @@ static void unmarshal_Rsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
UNMARSHAL_U32LE(ctx, out->count);
- UNMARSHAL_BYTES(ctx, out->data, out->count);
+ out->data.iov = ctx->extra;
+ ctx->extra += sizeof(out->data.iov[0]);
+ out->data.iov->iov_base = &ctx->net_bytes[ctx->net_offset];
+ out->data.iov->iov_len = out->count;
+ out->data.iovcnt = 1;
}
static void unmarshal_Tswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
@@ -3012,7 +3028,11 @@ static void unmarshal_Tswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len);
}
UNMARSHAL_U32LE(ctx, out->count);
- UNMARSHAL_BYTES(ctx, out->data, out->count);
+ out->data.iov = ctx->extra;
+ ctx->extra += sizeof(out->data.iov[0]);
+ out->data.iov->iov_base = &ctx->net_bytes[ctx->net_offset];
+ out->data.iov->iov_len = out->count;
+ out->data.iovcnt = 1;
}
static void unmarshal_Rswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
@@ -3491,7 +3511,8 @@ static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, st
MARSHAL_U8LE(ctx, 117);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ for (int iov_i = 0; iov_i < val->data->iovcnt; iov_i++)
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data->iov[iov_i].iov_base, val->data->iov[iov_i].iov_len);
return false;
}
@@ -3512,7 +3533,8 @@ static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val,
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U64LE(ctx, val->offset);
MARSHAL_U32LE(ctx, val->count);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ for (int iov_i = 0; iov_i < val->data->iovcnt; iov_i++)
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data->iov[iov_i].iov_base, val->data->iov[iov_i].iov_len);
return false;
}
@@ -4326,7 +4348,8 @@ static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *v
MARSHAL_U8LE(ctx, 41);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ for (int iov_i = 0; iov_i < val->data->iovcnt; iov_i++)
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data->iov[iov_i].iov_base, val->data->iov[iov_i].iov_len);
return false;
}
@@ -4692,7 +4715,8 @@ static bool marshal_Rsread(struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *val,
MARSHAL_U8LE(ctx, 153);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ for (int iov_i = 0; iov_i < val->data->iovcnt; iov_i++)
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data->iov[iov_i].iov_base, val->data->iov[iov_i].iov_len);
return false;
}
@@ -4720,7 +4744,8 @@ static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val
MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len);
}
MARSHAL_U32LE(ctx, val->count);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ for (int iov_i = 0; iov_i < val->data->iovcnt; iov_i++)
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data->iov[iov_i].iov_base, val->data->iov[iov_i].iov_len);
return false;
}
diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h
index 7a50537..e28b1d3 100644
--- a/lib9p/include/lib9p/9p.generated.h
+++ b/lib9p/include/lib9p/9p.generated.h
@@ -8,6 +8,11 @@
#include <libhw/generic/net.h> /* for struct iovec */
+struct _lib9p_iovec_list {
+ struct iovec *iov;
+ int iovcnt;
+};
+
/* config *********************************************************************/
#include "config.h"
@@ -156,6 +161,7 @@ enum lib9p_msg_type { /* uint8_t */
/* payload types **************************************************************/
+
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
/* size = 2 ; max_iov = 1 ; max_copy = 2 */
typedef uint16_t lib9p_tag_t;
@@ -549,9 +555,9 @@ struct lib9p_msg_Rflush {
/* min_size = 11 ; exp_size = 8,203 ; max_size = 2,147,483,658 ; max_iov = 2 ; max_copy = 11 */
struct lib9p_msg_Rread {
- lib9p_tag_t tag;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ struct _lib9p_iovec data;
};
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
@@ -602,9 +608,9 @@ struct lib9p_msg_Rxattrcreate {
/* min_size = 11 ; exp_size = 8,203 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) ; max_iov = 2 ; max_copy = 11 */
struct lib9p_msg_Rreaddir {
- lib9p_tag_t tag;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ struct _lib9p_iovec data;
};
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
@@ -642,9 +648,9 @@ struct lib9p_msg_Rsession {
/* min_size = 11 ; exp_size = 8,203 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) ; max_iov = 2 ; max_copy = 11 */
struct lib9p_msg_Rsread {
- lib9p_tag_t tag;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ struct _lib9p_iovec data;
};
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
@@ -665,11 +671,11 @@ struct lib9p_msg_Tread {
/* min_size = 23 ; exp_size = 8,215 ; max_size = 2,147,483,670 ; max_iov = 2 ; max_copy = 23 */
struct lib9p_msg_Twrite {
- lib9p_tag_t tag;
- lib9p_fid_t fid;
- uint64_t offset;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ uint64_t offset;
+ uint32_t count;
+ struct _lib9p_iovec data;
};
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
@@ -809,12 +815,12 @@ struct lib9p_msg_Tsread {
/* min_size = 17 ; exp_size = 8,673 ; max_size = 8,589,934,607 (warning: >UINT32_MAX) ; max_iov = 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */
struct lib9p_msg_Tswrite {
- lib9p_tag_t tag;
- uint32_t fid;
- uint16_t nwname;
- struct lib9p_s *wname;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t fid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+ uint32_t count;
+ struct _lib9p_iovec data;
};
#endif /* CONFIG_9P_ENABLE_9P2000_e */
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index ff5ebdc..ad209b8 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -43,8 +43,6 @@ lo_interface lib9p_srv_dio;
/* FIXME: I don't like that the pointers returned by stat() and
* pread() have to remain live after they return. Perhaps a
* `respond()`-callback? But that just reads as gross in C.
- *
- * FIXME: It would be nice if pread() could return more than 1 iovec.
*/
#define lib9p_srv_file_LO_IFACE \
/* resource management **********************************************/ \
@@ -99,7 +97,8 @@ LO_INTERFACE(lib9p_srv_file);
LO_FUNC(void , pread , struct lib9p_srv_ctx *, \
uint32_t byte_count, \
uint64_t byte_offset, \
- struct iovec *ret) \
+ struct iovec *ret_iov, \
+ int *ret_iovcnt) \
LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
void *buf, \
uint32_t byte_count, \
diff --git a/lib9p/protogen/c9util.py b/lib9p/protogen/c9util.py
index e7ad999..10d1c8c 100644
--- a/lib9p/protogen/c9util.py
+++ b/lib9p/protogen/c9util.py
@@ -76,6 +76,8 @@ def typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str:
match typ:
case idl.Primitive():
if typ.value == 1 and parent and parent.cnt: # SPECIAL (string)
+ if parent.membname == "data": # SPECIAL (zerocopy)
+ return f"struct {ident('_iovec')}"
return "[[gnu::nonstring]] char"
return f"uint{typ.value*8}_t"
case idl.Number():
diff --git a/lib9p/protogen/c_marshal.py b/lib9p/protogen/c_marshal.py
index 74b64f5..87ba50b 100644
--- a/lib9p/protogen/c_marshal.py
+++ b/lib9p/protogen/c_marshal.py
@@ -318,7 +318,14 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
if path.root.typname == "stat": # SPECIAL (stat)
ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n"
else:
- ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n"
+ if (
+ c9util.typename(child.typ, child)
+ == f"struct {c9util.ident("_iovec")}"
+ ):
+ ret += f"{'\t'*indent_lvl()}for (int iov_i = 0; iov_i < {path.c_str('val->')[:-3]}->iovcnt; iov_i++)\n"
+ ret += f"{'\t'*(indent_lvl()+1)}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}->iov[iov_i].iov_base, {path.c_str('val->')[:-3]}->iov[iov_i].iov_len);\n"
+ else:
+ ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n"
return idlutil.WalkCmd.KEEP_GOING, pop
loopvar = chr(ord("i") + loopdepth - 1)
ret += f"{'\t'*indent_lvl()}for ({c9util.typename(child.cnt.typ)} {loopvar} = 0; {loopvar} < {cnt_path.c_str('val->')}; {loopvar}++) {{\n"
diff --git a/lib9p/protogen/c_unmarshal.py b/lib9p/protogen/c_unmarshal.py
index 018d750..f14fb55 100644
--- a/lib9p/protogen/c_unmarshal.py
+++ b/lib9p/protogen/c_unmarshal.py
@@ -95,7 +95,19 @@ def gen_c_unmarshal(versions: set[str], typs: list[idl.UserType]) -> str:
if child.cnt:
cnt_path = path.parent().add(child.cnt)
if child.typ.static_size == 1: # SPECIAL (zerocopy)
- ret += f"{'\t'*indent_lvl()}UNMARSHAL_BYTES(ctx, {path.c_str('out->')[:-3]}, {cnt_path.c_str('out->')});\n"
+ if (
+ c9util.typename(child.typ, child)
+ == f"struct {c9util.ident('_iovec')}"
+ ): # SPECIAL(zerocopy)
+ ret += (
+ f"{'\t'*indent_lvl()}out->{child.membname}.iov = ctx->extra;\n"
+ )
+ ret += f"{'\t'*indent_lvl()}ctx->extra += sizeof(out->{child.membname}.iov[0]);\n"
+ ret += f"{'\t'*indent_lvl()}out->{child.membname}.iov->iov_base = &ctx->net_bytes[ctx->net_offset];\n"
+ ret += f"{'\t'*indent_lvl()}out->{child.membname}.iov->iov_len = out->{child.cnt.membname};\n"
+ ret += f"{'\t'*indent_lvl()}out->{child.membname}.iovcnt = 1;\n"
+ else:
+ ret += f"{'\t'*indent_lvl()}UNMARSHAL_BYTES(ctx, {path.c_str('out->')[:-3]}, {cnt_path.c_str('out->')});\n"
return idlutil.WalkCmd.KEEP_GOING, pop
ret += f"{'\t'*indent_lvl()}{path.c_str('out->')[:-3]} = extra;\n"
ret += f"{'\t'*indent_lvl()}extra += sizeof({path.c_str('out->')[:-3]}[0]) * {cnt_path.c_str('out->')};\n"
diff --git a/lib9p/protogen/h.py b/lib9p/protogen/h.py
index 7785ca1..3e743e9 100644
--- a/lib9p/protogen/h.py
+++ b/lib9p/protogen/h.py
@@ -166,6 +166,11 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str:
#include <stdint.h> /* for uint{{n}}_t types */
#include <libhw/generic/net.h> /* for struct iovec */
+
+struct {c9util.ident('_iovec_list')} {{
+\tstruct iovec *iov;
+\tint iovcnt;
+}};
"""
id2typ: dict[int, idl.Message] = {}
@@ -224,6 +229,7 @@ enum {c9util.ident('version')} {{
ret += """
/* payload types **************************************************************/
+
"""
def per_version_comment(
@@ -357,7 +363,13 @@ enum {c9util.ident('version')} {{
if member.val:
continue
ret += cutil.ifdef_push(2, c9util.ver_ifdef(member.in_versions))
- ret += f"\t{c9util.typename(member.typ, member):<{typewidth}} {'*' if member.cnt else ' '}{member.membname};\n"
+ ptr = bool(member.cnt)
+ if (
+ c9util.typename(member.typ, member)
+ == f"struct {c9util.ident('_iovec')}"
+ ): # SPECIAL (zerocopy)
+ ptr = False
+ ret += f"\t{c9util.typename(member.typ, member):<{typewidth}} {'*' if ptr else ' '}{member.membname};\n"
ret += cutil.ifdef_pop(1)
ret += "};\n"
del typ
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 50d0b78..2c26ffe 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -980,13 +980,20 @@ static void handle_Tread(struct _lib9p_srv_req *ctx,
fidinfo->dir.idx = idx+num;
fidinfo->dir.off = req->offset + len;
} else {
- struct iovec iov;
- LO_CALL(fidinfo->file.io, pread, &ctx->ctx, req->count, req->offset, &iov);
+ LO_CALL(fidinfo->file.io, pread, &ctx->ctx, req->count, req->offset,
+ &resp->iov, &resp->iovcnt);
if (!lib9p_ctx_has_error(&ctx->ctx.basectx)) {
- resp->count = iov.iov_len;
- resp->data = iov.iov_base;
- if (resp->count > req->count)
- resp->count = req->count;
+ resp->count = 0;
+ assert(resp->iovcnt >= 0);
+ if (resp->iovcnt) {
+ assert(resp->iov);
+ for (int i = 0; i < resp->iovcnt; i++) {
+ assert(resp->iov[i].iov_len == 0 || resp->iov[i].iov_base);
+ bool overflowed = __builtin_add_overflow(resp->count, resp->iov[i].iov_len, &resp->count);
+ assert(!overflowed);
+ }
+ }
+ assert(resp->count <= req->count);
}
}
}