summaryrefslogtreecommitdiff
path: root/lib9p
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p')
-rw-r--r--lib9p/core_gen/c9util.py2
-rw-r--r--lib9p/core_gen/c_marshal.py3
-rw-r--r--lib9p/core_gen/c_unmarshal.py9
-rw-r--r--lib9p/core_gen/h.py13
-rw-r--r--lib9p/core_generated.c45
-rw-r--r--lib9p/core_include/lib9p/_core_generated.h45
-rw-r--r--lib9p/srv.c15
-rw-r--r--lib9p/srv_include/lib9p/srv.h4
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) \
/** \