diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-18 10:53:12 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-26 22:17:22 -0600 |
commit | e7f3db0679e5d37970a06f428208c3f5b51db5d2 (patch) | |
tree | 607b6716d89fb1615dda1bc27e582bed23043f68 | |
parent | 865bb702f828784a0225b5eae9ed8803094140d5 (diff) |
-rw-r--r-- | lib9p/9p.generated.c | 45 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.generated.h | 46 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 5 | ||||
-rw-r--r-- | lib9p/protogen/c9util.py | 2 | ||||
-rw-r--r-- | lib9p/protogen/c_marshal.py | 9 | ||||
-rw-r--r-- | lib9p/protogen/c_unmarshal.py | 14 | ||||
-rw-r--r-- | lib9p/protogen/h.py | 14 | ||||
-rw-r--r-- | lib9p/srv.c | 19 |
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); } } } |