diff options
Diffstat (limited to 'lib9p')
-rw-r--r-- | lib9p/core_gen/c9util.py | 2 | ||||
-rw-r--r-- | lib9p/core_gen/c_marshal.py | 3 | ||||
-rw-r--r-- | lib9p/core_gen/c_unmarshal.py | 9 | ||||
-rw-r--r-- | lib9p/core_gen/h.py | 13 | ||||
-rw-r--r-- | lib9p/core_generated.c | 45 | ||||
-rw-r--r-- | lib9p/core_include/lib9p/_core_generated.h | 45 | ||||
-rw-r--r-- | lib9p/srv.c | 15 | ||||
-rw-r--r-- | lib9p/srv_include/lib9p/srv.h | 4 |
8 files changed, 97 insertions, 39 deletions
diff --git a/lib9p/core_gen/c9util.py b/lib9p/core_gen/c9util.py index 84fdee4..a304ff4 100644 --- a/lib9p/core_gen/c9util.py +++ b/lib9p/core_gen/c9util.py @@ -91,6 +91,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 (iovec) + return f"struct {ident('_iovec')}" return "[[gnu::nonstring]] char" return f"uint{typ.value*8}_t" case idl.Number(): diff --git a/lib9p/core_gen/c_marshal.py b/lib9p/core_gen/c_marshal.py index 86d82e4..af8d582 100644 --- a/lib9p/core_gen/c_marshal.py +++ b/lib9p/core_gen/c_marshal.py @@ -334,6 +334,9 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str: if child.typ.static_size == 1: # SPECIAL (zerocopy) if path.root.typname == "stat": # SPECIAL (stat) ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES(ctx, {path.c_str('val->')[:-3]}, {cnt_str});\n" + elif c9util.typename(child.typ, child) == f"struct {c9util.ident("_iovec")}": # SPECIAL (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_str});\n" return idlutil.WalkCmd.KEEP_GOING, pop diff --git a/lib9p/core_gen/c_unmarshal.py b/lib9p/core_gen/c_unmarshal.py index 206a85b..c510e44 100644 --- a/lib9p/core_gen/c_unmarshal.py +++ b/lib9p/core_gen/c_unmarshal.py @@ -100,7 +100,14 @@ def gen_c_unmarshal(versions: set[str], typs: list[idl.UserType]) -> str: cnt_str = path.parent().add(child.cnt).c_str("out->") cnt_typ = c9util.typename(child.cnt.typ) if child.typ.static_size == 1: # SPECIAL (zerocopy) - ret += f"{'\t'*indent_lvl()}UNMARSHAL_BYTES(ctx, {path.c_str('out->')[:-3]}, {cnt_str});\n" + if c9util.typename(child.typ, child) == f"struct {c9util.ident('_iovec')}": # SPECIAL (iovec) + 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_str});\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_str};\n" diff --git a/lib9p/core_gen/h.py b/lib9p/core_gen/h.py index 8c381f8..6ead5ba 100644 --- a/lib9p/core_gen/h.py +++ b/lib9p/core_gen/h.py @@ -162,6 +162,11 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str: #ifndef _LIB9P_CORE_H_ \t#error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead #endif + +struct {c9util.ident('_iovec_list')} {{ +\tstruct iovec *iov; +\tint iovcnt; +}}; """ id2typ: dict[int, idl.Message] = {} for msg in [msg for msg in typs if isinstance(msg, idl.Message)]: @@ -523,7 +528,13 @@ def gen_struct(typ: idl.Struct) -> str: # and idl.Message 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" return ret diff --git a/lib9p/core_generated.c b/lib9p/core_generated.c index 08ab4f0..49cb8d9 100644 --- a/lib9p/core_generated.c +++ b/lib9p/core_generated.c @@ -1915,7 +1915,11 @@ static void unmarshal_Rread([[maybe_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([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { @@ -1928,7 +1932,11 @@ static void unmarshal_Twrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *ne 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([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { @@ -2428,7 +2436,11 @@ static void unmarshal_Rreaddir([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t * 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([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { @@ -2649,7 +2661,11 @@ static void unmarshal_Rsread([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *ne 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([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { @@ -2668,7 +2684,11 @@ static void unmarshal_Tswrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *n 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([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { @@ -3119,7 +3139,8 @@ static error marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, s 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 ERROR_NULL; } @@ -3138,7 +3159,8 @@ static error 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 ERROR_NULL; } @@ -3880,7 +3902,8 @@ static error marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir * 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 ERROR_NULL; } @@ -4210,7 +4233,8 @@ static error 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 ERROR_NULL; } @@ -4236,7 +4260,8 @@ static error marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *va 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 ERROR_NULL; } diff --git a/lib9p/core_include/lib9p/_core_generated.h b/lib9p/core_include/lib9p/_core_generated.h index de7795a..905f1f0 100644 --- a/lib9p/core_include/lib9p/_core_generated.h +++ b/lib9p/core_include/lib9p/_core_generated.h @@ -4,6 +4,11 @@ #error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead #endif +struct _lib9p_iovec_list { + struct iovec *iov; + int iovcnt; +}; + /* config *********************************************************************/ #ifndef CONFIG_9P_ENABLE_9P2000 @@ -715,18 +720,18 @@ struct lib9p_msg_Tread { /* 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; }; /* 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 */ @@ -873,9 +878,9 @@ struct lib9p_msg_Treaddir { /* 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 = 15 ; max_iov = 1 ; max_copy = 15 */ @@ -926,9 +931,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 */ @@ -1291,12 +1296,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/srv.c b/lib9p/srv.c index 085cc8b..f4b904e 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -1301,10 +1301,17 @@ static void handle_Tread(struct srv_req *ctx, if (iov.is_err) { err = iov.err; } else { - resp.count = iov.iovec.iov_len; - resp.data = iov.iovec.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); } break; case SRV_FILETYPE_AUTH: diff --git a/lib9p/srv_include/lib9p/srv.h b/lib9p/srv_include/lib9p/srv.h index ce82e59..0f1c88b 100644 --- a/lib9p/srv_include/lib9p/srv.h +++ b/lib9p/srv_include/lib9p/srv.h @@ -112,14 +112,12 @@ DECLARE_ERROR_OR(lib9p_srv_dirent); /* FIXME: I don't like that the pointer returned by pread() has to * remain live after it returns. 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_fio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \ LO_FUNC(struct lib9p_qid , qid ) \ LO_FUNC(void , iofree ) \ LO_FUNC(uint32_t , iounit ) \ - LO_FUNC(iovec_or_error , pread , struct lib9p_srv_ctx *, \ + LO_FUNC(iovec_list__or_error , pread , struct lib9p_srv_ctx *, \ uint32_t byte_count, \ uint64_t byte_offset) \ /** \ |