diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-12 20:55:47 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-12 20:55:47 -0700 |
commit | 4ba0b95dc825a83748b7cb2aa528411026d5bada (patch) | |
tree | 29b04d56a5bb46273676e827a152d17602b96cae /lib9p | |
parent | d148555bd86e323a51734b7881f92d09e2f08425 (diff) | |
parent | 6759a952978ea011dbc08a13b8f97a7c97572d16 (diff) |
Merge branch 'lukeshu/9p-small-pt1'
Diffstat (limited to 'lib9p')
-rw-r--r-- | lib9p/9p.c | 42 | ||||
-rw-r--r-- | lib9p/9p.generated.c | 2796 | ||||
-rwxr-xr-x | lib9p/idl.gen | 750 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.generated.h | 283 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.h | 4 | ||||
-rw-r--r-- | lib9p/internal.h | 7 | ||||
-rw-r--r-- | lib9p/srv.c | 101 |
7 files changed, 2499 insertions, 1484 deletions
@@ -204,30 +204,42 @@ void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, static bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x80], struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - uint8_t *ret_bytes) { + size_t *ret_iov_cnt, struct iovec *ret_iov, uint8_t *ret_copied) { struct _marshal_ctx subctx = { /* input */ - .ctx = ctx, + .ctx = ctx, /* ouptut */ - .net_bytes = ret_bytes, - .net_offset = 0, + .net_iov_cnt = 1, + .net_iov = ret_iov, + .net_copied_size = 0, + .net_copied = ret_copied, }; struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2]; - return tentry.marshal(&subctx, body); + bool ret_erred = tentry.marshal(&subctx, body); + if (ret_iov[subctx.net_iov_cnt-1].iov_len == 0) + subctx.net_iov_cnt--; + *ret_iov_cnt = subctx.net_iov_cnt; + return ret_erred; } bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - uint8_t *ret_bytes) { + struct lib9p_Tmsg_send_buf *ret) { assert(typ % 2 == 0); - return _lib9p_marshal(_lib9p_table_Tmsg_send, ctx, typ, body, ret_bytes); + memset(ret, 0, sizeof(*ret)); + return _lib9p_marshal(_lib9p_table_Tmsg_send, + ctx, typ, body, + &ret->iov_cnt, ret->iov, ret->copied); } bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - uint8_t *ret_bytes) { + struct lib9p_Rmsg_send_buf *ret) { assert(typ % 2 == 1); - return _lib9p_marshal(_lib9p_table_Rmsg_send, ctx, typ, body, ret_bytes); + memset(ret, 0, sizeof(*ret)); + return _lib9p_marshal(_lib9p_table_Rmsg_send, + ctx, typ, body, + &ret->iov_cnt, ret->iov, ret->copied); } /* `struct lib9p_stat` helpers ************************************************/ @@ -273,15 +285,19 @@ uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct uint8_t *ret_bytes) { struct lib9p_ctx _ctx = *ctx; _ctx.max_msg_size = max_net_size; + + struct iovec iov = {0}; struct _marshal_ctx subctx = { /* input */ - .ctx = &_ctx, + .ctx = &_ctx, /* output */ - .net_bytes = ret_bytes, - .net_offset = 0, + .net_iov_cnt = 1, + .net_iov = &iov, + .net_copied_size = 0, + .net_copied = ret_bytes, }; if (_lib9p_stat_marshal(&subctx, obj)) return 0; - return subctx.net_offset; + return subctx.net_iov[0].iov_len; } diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c index 1188c73..eca0666 100644 --- a/lib9p/9p.generated.c +++ b/lib9p/9p.generated.c @@ -431,7 +431,7 @@ LM_ALWAYS_INLINE static bool validate_s(struct _validate_ctx *ctx) { uint16_t len; return false || (validate_2(ctx) || ({ len = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || _validate_list(ctx, len, validate_1, sizeof(uint8_t)) + || _validate_size_net(ctx, len) || ({ (!is_valid_utf8_without_nul(&ctx->net_bytes[ctx->net_offset-len], len)) && lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); }) ; } @@ -561,7 +561,7 @@ LM_FLATTEN static bool validate_Rread(struct _validate_ctx *ctx) { || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) || validate_tag(ctx) || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_list(ctx, count, validate_1, sizeof(uint8_t)) + || _validate_size_net(ctx, count) || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) || ({ uint8_t exp = 117; (((uint8_t)typ) != exp) && @@ -750,7 +750,7 @@ LM_FLATTEN static bool validate_Rreaddir(struct _validate_ctx *ctx) { || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) || validate_tag(ctx) || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_list(ctx, count, validate_1, sizeof(uint8_t)) + || _validate_size_net(ctx, count) || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) || ({ uint8_t exp = 41; (((uint8_t)typ) != exp) && @@ -861,7 +861,7 @@ LM_FLATTEN static bool validate_Rsread(struct _validate_ctx *ctx) { || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) || validate_tag(ctx) || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_list(ctx, count, validate_1, sizeof(uint8_t)) + || _validate_size_net(ctx, count) || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) || ({ uint8_t exp = 153; (((uint8_t)typ) != exp) && @@ -924,7 +924,7 @@ LM_FLATTEN static bool validate_Twrite(struct _validate_ctx *ctx) { || validate_fid(ctx) || (validate_8(ctx) || ({ offset = uint64le_decode(&ctx->net_bytes[ctx->net_offset-8]); false; })) || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_list(ctx, count, validate_1, sizeof(uint8_t)) + || _validate_size_net(ctx, count) || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) || ({ uint8_t exp = 118; (((uint8_t)typ) != exp) && @@ -1353,7 +1353,7 @@ LM_FLATTEN static bool validate_Tswrite(struct _validate_ctx *ctx) { || (validate_2(ctx) || ({ nwname = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) || _validate_list(ctx, nwname, validate_s, sizeof(struct lib9p_s)) || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_list(ctx, count, validate_1, sizeof(uint8_t)) + || _validate_size_net(ctx, count) || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) || ({ uint8_t exp = 154; (((uint8_t)typ) != exp) && @@ -1972,10 +1972,8 @@ LM_ALWAYS_INLINE static void unmarshal_fid(struct _unmarshal_ctx *ctx, lib9p_fid LM_ALWAYS_INLINE static void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) { memset(out, 0, sizeof(*out)); unmarshal_2(ctx, &out->len); - out->utf8 = ctx->extra; - ctx->extra += sizeof(out->utf8[0]) * out->len; - for (typeof(out->len) i = 0; i < out->len; i++) - unmarshal_1(ctx, (uint8_t *)&out->utf8[i]); + out->utf8 = (char *)&ctx->net_bytes[ctx->net_offset]; + ctx->net_offset += out->len; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ @@ -2047,10 +2045,8 @@ LM_FLATTEN static void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_ ctx->net_offset += 1; unmarshal_tag(ctx, &out->tag); unmarshal_4(ctx, &out->count); - out->data = ctx->extra; - ctx->extra += sizeof(out->data[0]) * out->count; - for (typeof(out->count) i = 0; i < out->count; i++) - unmarshal_1(ctx, (uint8_t *)&out->data[i]); + out->data = (char *)&ctx->net_bytes[ctx->net_offset]; + ctx->net_offset += out->count; } LM_FLATTEN static void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) { @@ -2145,10 +2141,8 @@ LM_FLATTEN static void unmarshal_Rreaddir(struct _unmarshal_ctx *ctx, struct lib ctx->net_offset += 1; unmarshal_tag(ctx, &out->tag); unmarshal_4(ctx, &out->count); - out->data = ctx->extra; - ctx->extra += sizeof(out->data[0]) * out->count; - for (typeof(out->count) i = 0; i < out->count; i++) - unmarshal_1(ctx, (uint8_t *)&out->data[i]); + out->data = (char *)&ctx->net_bytes[ctx->net_offset]; + ctx->net_offset += out->count; } LM_FLATTEN static void unmarshal_Rfsync(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rfsync *out) { @@ -2202,10 +2196,8 @@ LM_FLATTEN static void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p ctx->net_offset += 1; unmarshal_tag(ctx, &out->tag); unmarshal_4(ctx, &out->count); - out->data = ctx->extra; - ctx->extra += sizeof(out->data[0]) * out->count; - for (typeof(out->count) i = 0; i < out->count; i++) - unmarshal_1(ctx, (uint8_t *)&out->data[i]); + out->data = (char *)&ctx->net_bytes[ctx->net_offset]; + ctx->net_offset += out->count; } LM_FLATTEN static void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) { @@ -2236,10 +2228,8 @@ LM_FLATTEN static void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p unmarshal_fid(ctx, &out->fid); unmarshal_8(ctx, &out->offset); unmarshal_4(ctx, &out->count); - out->data = ctx->extra; - ctx->extra += sizeof(out->data[0]) * out->count; - for (typeof(out->count) i = 0; i < out->count; i++) - unmarshal_1(ctx, (uint8_t *)&out->data[i]); + out->data = (char *)&ctx->net_bytes[ctx->net_offset]; + ctx->net_offset += out->count; } LM_FLATTEN static void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) { @@ -2483,10 +2473,8 @@ LM_FLATTEN static void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9 for (typeof(out->nwname) i = 0; i < out->nwname; i++) unmarshal_s(ctx, &out->wname[i]); unmarshal_4(ctx, &out->count); - out->data = ctx->extra; - ctx->extra += sizeof(out->data[0]) * out->count; - for (typeof(out->count) i = 0; i < out->count; i++) - unmarshal_1(ctx, (uint8_t *)&out->data[i]); + out->data = (char *)&ctx->net_bytes[ctx->net_offset]; + ctx->net_offset += out->count; } #endif /* CONFIG_9P_ENABLE_9P2000_e */ @@ -2838,1311 +2826,1777 @@ LM_FLATTEN static void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p /* marshal_* ******************************************************************/ -LM_ALWAYS_INLINE static bool _marshal_too_large(struct _marshal_ctx *ctx) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s too large to marshal into %s limit (limit=%"PRIu32")", - (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", - ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), - ctx->ctx->max_msg_size); - return true; -} +#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len) \ + if (ctx->net_iov[ctx->net_iov_cnt-1].iov_len) \ + ctx->net_iov_cnt++; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_base = data; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_len = len; \ + ctx->net_iov_cnt++; +#define MARSHAL_BYTES(ctx, data, len) \ + if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ + memcpy(&ctx->net_copied[ctx->net_copied_size], data, len); \ + ctx->net_copied_size += len; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_len += len; +#define MARSHAL_U8LE(ctx, val) \ + if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ + ctx->net_copied[ctx->net_copied_size] = val; \ + ctx->net_copied_size += 1; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 1; +#define MARSHAL_U16LE(ctx, val) \ + if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ + uint16le_encode(&ctx->net_copied[ctx->net_copied_size], val); \ + ctx->net_copied_size += 2; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 2; +#define MARSHAL_U32LE(ctx, val) \ + if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ + uint32le_encode(&ctx->net_copied[ctx->net_copied_size], val); \ + ctx->net_copied_size += 4; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 4; +#define MARSHAL_U64LE(ctx, val) \ + if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ + uint64le_encode(&ctx->net_copied[ctx->net_copied_size], val); \ + ctx->net_copied_size += 8; \ + ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 8; -LM_ALWAYS_INLINE static bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { - if (ctx->net_offset + 1 > ctx->ctx->max_msg_size) - return _marshal_too_large(ctx); - ctx->net_bytes[ctx->net_offset] = *val; - ctx->net_offset += 1; +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +static bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { + uint32_t needed_size = 49 + val->file_name.len + val->file_owner_uid.len + val->file_owner_gid.len + val->file_last_modified_uid.len; +#if CONFIG_9P_ENABLE_9P2000_u + if is_ver(ctx, 9P2000_u) { + needed_size += 14 + val->file_extension.len; + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + if (needed_size > ctx->ctx->max_msg_size) { + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_kern_type = 2; + MARSHAL_U16LE(ctx, offsetof_end - offsetof_kern_type); + MARSHAL_U16LE(ctx, val->kern_type); + MARSHAL_U32LE(ctx, val->kern_dev); + MARSHAL_U8LE(ctx, val->file_qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->file_qid.vers); + MARSHAL_U64LE(ctx, val->file_qid.path); + MARSHAL_U32LE(ctx, val->file_mode & dm_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->file_atime); + MARSHAL_U32LE(ctx, val->file_mtime); + MARSHAL_U64LE(ctx, val->file_size); + MARSHAL_U16LE(ctx, val->file_name.len); + MARSHAL_BYTES(ctx, val->file_name.utf8, val->file_name.len); + MARSHAL_U16LE(ctx, val->file_owner_uid.len); + MARSHAL_BYTES(ctx, val->file_owner_uid.utf8, val->file_owner_uid.len); + MARSHAL_U16LE(ctx, val->file_owner_gid.len); + MARSHAL_BYTES(ctx, val->file_owner_gid.utf8, val->file_owner_gid.len); + MARSHAL_U16LE(ctx, val->file_last_modified_uid.len); + MARSHAL_BYTES(ctx, val->file_last_modified_uid.utf8, val->file_last_modified_uid.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U16LE(ctx, val->file_extension.len); + MARSHAL_BYTES(ctx, val->file_extension.utf8, val->file_extension.len); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->file_owner_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->file_owner_n_gid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->file_last_modified_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; } -LM_ALWAYS_INLINE static bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { - if (ctx->net_offset + 2 > ctx->ctx->max_msg_size) - return _marshal_too_large(ctx); - uint16le_encode(&ctx->net_bytes[ctx->net_offset], *val); - ctx->net_offset += 2; +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#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 +static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) { + uint32_t needed_size = 13 + val->version.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tversion", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 100); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->max_msg_size); + MARSHAL_U16LE(ctx, val->version.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->version.utf8, val->version.len); return false; } -LM_ALWAYS_INLINE static bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { - if (ctx->net_offset + 4 > ctx->ctx->max_msg_size) +static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) { + uint32_t needed_size = 13 + val->version.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rversion", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); return true; - uint32le_encode(&ctx->net_bytes[ctx->net_offset], *val); - ctx->net_offset += 4; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 101); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->max_msg_size); + MARSHAL_U16LE(ctx, val->version.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->version.utf8, val->version.len); return false; } -LM_ALWAYS_INLINE static bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { - if (ctx->net_offset + 8 > ctx->ctx->max_msg_size) +static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) { + uint32_t needed_size = 15 + val->uname.len + val->aname.len; +#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u + if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) { + needed_size += 4; + } +#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tauth", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); return true; - uint64le_encode(&ctx->net_bytes[ctx->net_offset], *val); - ctx->net_offset += 8; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 102); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->afid); + MARSHAL_U16LE(ctx, val->uname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->uname.utf8, val->uname.len); + MARSHAL_U16LE(ctx, val->aname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len); +#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u + if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { + MARSHAL_U32LE(ctx, val->n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ return false; } -#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 -LM_ALWAYS_INLINE static bool marshal_tag(struct _marshal_ctx *ctx, lib9p_tag_t *val) { - return marshal_2(ctx, (uint16_t *)val); -} - -LM_ALWAYS_INLINE static bool marshal_fid(struct _marshal_ctx *ctx, lib9p_fid_t *val) { - return marshal_4(ctx, (uint32_t *)val); -} - -LM_ALWAYS_INLINE static bool marshal_s(struct _marshal_ctx *ctx, struct lib9p_s *val) { - return false - || marshal_2(ctx, &val->len) - || ({ bool err = false; - for (typeof(val->len) i = 0; i < val->len && !err; i++) - err = marshal_1(ctx, (uint8_t *)&val->utf8[i]); - err; }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool marshal_dm(struct _marshal_ctx *ctx, lib9p_dm_t *val) { - lib9p_dm_t masked_val = *val & dm_masks[ctx->ctx->version]; - return marshal_4(ctx, (uint32_t *)&masked_val); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#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 -LM_ALWAYS_INLINE static bool marshal_qt(struct _marshal_ctx *ctx, lib9p_qt_t *val) { - lib9p_qt_t masked_val = *val & qt_masks[ctx->ctx->version]; - return marshal_1(ctx, (uint8_t *)&masked_val); +static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) { + uint32_t needed_size = 20; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rauth", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 103); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->aqid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->aqid.vers); + MARSHAL_U64LE(ctx, val->aqid.path); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) { + uint32_t needed_size = 19 + val->uname.len + val->aname.len; #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool marshal_nuid(struct _marshal_ctx *ctx, lib9p_nuid_t *val) { - return marshal_4(ctx, (uint32_t *)val); -} - + if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) { + needed_size += 4; + } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool marshal_o(struct _marshal_ctx *ctx, lib9p_o_t *val) { - lib9p_o_t masked_val = *val & o_masks[ctx->ctx->version]; - return marshal_1(ctx, (uint8_t *)&masked_val); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_ALWAYS_INLINE static bool marshal_getattr(struct _marshal_ctx *ctx, lib9p_getattr_t *val) { - lib9p_getattr_t masked_val = *val & getattr_masks[ctx->ctx->version]; - return marshal_8(ctx, (uint64_t *)&masked_val); -} - -LM_ALWAYS_INLINE static bool marshal_setattr(struct _marshal_ctx *ctx, lib9p_setattr_t *val) { - lib9p_setattr_t masked_val = *val & setattr_masks[ctx->ctx->version]; - return marshal_4(ctx, (uint32_t *)&masked_val); -} - -LM_ALWAYS_INLINE static bool marshal_lock_type(struct _marshal_ctx *ctx, lib9p_lock_type_t *val) { - return marshal_1(ctx, (uint8_t *)val); -} - -LM_ALWAYS_INLINE static bool marshal_lock_flags(struct _marshal_ctx *ctx, lib9p_lock_flags_t *val) { - lib9p_lock_flags_t masked_val = *val & lock_flags_masks[ctx->ctx->version]; - return marshal_4(ctx, (uint32_t *)&masked_val); -} - -LM_ALWAYS_INLINE static bool marshal_lock_status(struct _marshal_ctx *ctx, lib9p_lock_status_t *val) { - return marshal_1(ctx, (uint8_t *)val); + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tattach", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 104); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->afid); + MARSHAL_U16LE(ctx, val->uname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->uname.utf8, val->uname.len); + MARSHAL_U16LE(ctx, val->aname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len); +#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u + if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { + MARSHAL_U32LE(ctx, val->n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#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 -LM_FLATTEN static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_2(ctx, &val->oldtag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 108; false; }) - ; +static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) { + uint32_t needed_size = 20; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rattach", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 105); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + return false; } -LM_FLATTEN static bool marshal_Rflush(struct _marshal_ctx *ctx, struct lib9p_msg_Rflush *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 109; false; }) - ; +static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { + uint32_t needed_size = 9 + val->ename.len; +#if CONFIG_9P_ENABLE_9P2000_u + if is_ver(ctx, 9P2000_u) { + needed_size += 4; + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rerror", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 107); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U16LE(ctx, val->ename.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->ename.utf8, val->ename.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->errno); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + return false; } -LM_FLATTEN static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->count) - || ({ bool err = false; - for (typeof(val->count) i = 0; i < val->count && !err; i++) - err = marshal_1(ctx, (uint8_t *)&val->data[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 117; false; }) - ; +static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) { + uint32_t needed_size = 9; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tflush", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 108); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U16LE(ctx, val->oldtag); + return false; } -LM_FLATTEN static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->count) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 119; false; }) - ; +static bool marshal_Rflush(struct _marshal_ctx *ctx, struct lib9p_msg_Rflush *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rflush", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 109); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Rclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Rclunk *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 121; false; }) - ; +static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) { + uint32_t needed_size = 17; + for (uint16_t i = 0; i < val->nwname; i++) { + needed_size += 2 + val->wname[i].len; + } + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Twalk", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 110); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->newfid); + MARSHAL_U16LE(ctx, val->nwname); + for (uint16_t i = 0; i < val->nwname; i++) { + MARSHAL_U16LE(ctx, val->wname[i].len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len); + } + return false; } -LM_FLATTEN static bool marshal_Rremove(struct _marshal_ctx *ctx, struct lib9p_msg_Rremove *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 123; false; }) - ; +static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) { + uint32_t needed_size = 9 + (val->nwqid)*13; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rwalk", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 111); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U16LE(ctx, val->nwqid); + for (uint16_t i = 0; i < val->nwqid; i++) { + MARSHAL_U8LE(ctx, val->wqid[i].type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->wqid[i].vers); + MARSHAL_U64LE(ctx, val->wqid[i].path); + } + return false; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool marshal_Rwstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rwstat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 127; false; }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool marshal_Rlerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rlerror *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->ecode) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 7; false; }) - ; -} - -LM_FLATTEN static bool marshal_Rstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Rstatfs *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->type) - || marshal_4(ctx, &val->bsize) - || marshal_8(ctx, &val->blocks) - || marshal_8(ctx, &val->bfree) - || marshal_8(ctx, &val->bavail) - || marshal_8(ctx, &val->files) - || marshal_8(ctx, &val->ffree) - || marshal_8(ctx, &val->fsid) - || marshal_4(ctx, &val->namelen) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 9; false; }) - ; -} - -LM_FLATTEN static bool marshal_Rrename(struct _marshal_ctx *ctx, struct lib9p_msg_Rrename *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 21; false; }) - ; +static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) { + uint32_t needed_size = 12; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Topen", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 112); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->ctx->version]); + return false; } -LM_FLATTEN static bool marshal_Rsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rsetattr *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 27; false; }) - ; +static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) { + uint32_t needed_size = 24; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Ropen", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 113); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->iounit); + return false; } -LM_FLATTEN static bool marshal_Rxattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattrwalk *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_8(ctx, &val->attr_size) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 31; false; }) - ; +static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) { + uint32_t needed_size = 18 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tcreate", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 114); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U32LE(ctx, val->perm & dm_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->ctx->version]); + return false; } -LM_FLATTEN static bool marshal_Rxattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattrcreate *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 33; false; }) - ; +static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) { + uint32_t needed_size = 24; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rcreate", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 115); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->iounit); + return false; } -LM_FLATTEN static bool marshal_Rreaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Rreaddir *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->count) - || ({ bool err = false; - for (typeof(val->count) i = 0; i < val->count && !err; i++) - err = marshal_1(ctx, (uint8_t *)&val->data[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 41; false; }) - ; +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#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 +static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) { + uint32_t needed_size = 23; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tread", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 116); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U64LE(ctx, val->offset); + MARSHAL_U32LE(ctx, val->count); + return false; } -LM_FLATTEN static bool marshal_Rfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Rfsync *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 51; false; }) - ; +static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) { + uint32_t needed_size = 11 + val->count; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rread", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 117); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->count); + MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count); + return false; } -LM_FLATTEN static bool marshal_Rlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rlink *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 71; false; }) - ; +static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) { + uint32_t needed_size = 23 + val->count; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Twrite", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 118); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U64LE(ctx, val->offset); + MARSHAL_U32LE(ctx, val->count); + MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count); + return false; } -LM_FLATTEN static bool marshal_Rrenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Rrenameat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 75; false; }) - ; +static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rwrite", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 119); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->count); + return false; } -LM_FLATTEN static bool marshal_Runlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Runlinkat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 77; false; }) - ; +static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tclunk", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 120); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -LM_FLATTEN static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_8(ctx, &val->key) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 150; false; }) - ; +static bool marshal_Rclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Rclunk *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rclunk", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 121); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Rsession(struct _marshal_ctx *ctx, struct lib9p_msg_Rsession *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 151; false; }) - ; +static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tremove", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 122); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + return false; } -LM_FLATTEN static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->count) - || ({ bool err = false; - for (typeof(val->count) i = 0; i < val->count && !err; i++) - err = marshal_1(ctx, (uint8_t *)&val->data[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 153; false; }) - ; +static bool marshal_Rremove(struct _marshal_ctx *ctx, struct lib9p_msg_Rremove *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rremove", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 123); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->count) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 155; false; }) - ; +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tstat", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 124); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_e */ -#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 -LM_FLATTEN static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_8(ctx, &val->offset) - || marshal_4(ctx, &val->count) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 116; false; }) - ; +static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) { + uint32_t needed_size = 58 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; +#if CONFIG_9P_ENABLE_9P2000_u + if is_ver(ctx, 9P2000_u) { + needed_size += 14 + val->stat.file_extension.len; + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rstat", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + uint32_t offsetof_stat = 9; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 125); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat); + uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; +#if CONFIG_9P_ENABLE_9P2000_u + if is_ver(ctx, 9P2000_u) { + offsetof_stat_end += 14 + val->stat.file_extension.len; + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + uint32_t offsetof_stat_kern_type = 2; + MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type); + MARSHAL_U16LE(ctx, val->stat.kern_type); + MARSHAL_U32LE(ctx, val->stat.kern_dev); + MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->stat.file_qid.vers); + MARSHAL_U64LE(ctx, val->stat.file_qid.path); + MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->stat.file_atime); + MARSHAL_U32LE(ctx, val->stat.file_mtime); + MARSHAL_U64LE(ctx, val->stat.file_size); + MARSHAL_U16LE(ctx, val->stat.file_name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len); + MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len); + MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len); + MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U16LE(ctx, val->stat.file_extension.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + return false; } -LM_FLATTEN static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_8(ctx, &val->offset) - || marshal_4(ctx, &val->count) - || ({ bool err = false; - for (typeof(val->count) i = 0; i < val->count && !err; i++) - err = marshal_1(ctx, (uint8_t *)&val->data[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 118; false; }) - ; +static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) { + uint32_t needed_size = 62 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; +#if CONFIG_9P_ENABLE_9P2000_u + if is_ver(ctx, 9P2000_u) { + needed_size += 14 + val->stat.file_extension.len; + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Twstat", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + uint32_t offsetof_stat = 13; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 126); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat); + uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; +#if CONFIG_9P_ENABLE_9P2000_u + if is_ver(ctx, 9P2000_u) { + offsetof_stat_end += 14 + val->stat.file_extension.len; + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + uint32_t offsetof_stat_kern_type = 2; + MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type); + MARSHAL_U16LE(ctx, val->stat.kern_type); + MARSHAL_U32LE(ctx, val->stat.kern_dev); + MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->stat.file_qid.vers); + MARSHAL_U64LE(ctx, val->stat.file_qid.path); + MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->stat.file_atime); + MARSHAL_U32LE(ctx, val->stat.file_mtime); + MARSHAL_U64LE(ctx, val->stat.file_size); + MARSHAL_U16LE(ctx, val->stat.file_name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len); + MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len); + MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len); + MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U16LE(ctx, val->stat.file_extension.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + return false; } -LM_FLATTEN static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 120; false; }) - ; +static bool marshal_Rwstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rwstat *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rwstat", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 127); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 122; false; }) - ; +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_p9p +static bool marshal_Topenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Topenfd *val) { + uint32_t needed_size = 12; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Topenfd", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 98); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->ctx->version]); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 124; false; }) - ; +static bool marshal_Ropenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Ropenfd *val) { + uint32_t needed_size = 28; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Ropenfd", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 99); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->iounit); + MARSHAL_U32LE(ctx, val->unixfd); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool marshal_Tstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Tstatfs *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 8; false; }) - ; -} - -LM_FLATTEN static bool marshal_Tlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Tlopen *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_4(ctx, &val->flags) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 12; false; }) - ; +static bool marshal_Rlerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rlerror *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rlerror", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 7); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->ecode); + return false; } -LM_FLATTEN static bool marshal_Treadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Treadlink *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 22; false; }) - ; +static bool marshal_Tstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Tstatfs *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tstatfs", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 8); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + return false; } -LM_FLATTEN static bool marshal_Treaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Treaddir *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_8(ctx, &val->offset) - || marshal_4(ctx, &val->count) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 40; false; }) - ; +static bool marshal_Rstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Rstatfs *val) { + uint32_t needed_size = 67; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rstatfs", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 9); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->type); + MARSHAL_U32LE(ctx, val->bsize); + MARSHAL_U64LE(ctx, val->blocks); + MARSHAL_U64LE(ctx, val->bfree); + MARSHAL_U64LE(ctx, val->bavail); + MARSHAL_U64LE(ctx, val->files); + MARSHAL_U64LE(ctx, val->ffree); + MARSHAL_U64LE(ctx, val->fsid); + MARSHAL_U32LE(ctx, val->namelen); + return false; } -LM_FLATTEN static bool marshal_Tfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Tfsync *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_4(ctx, &val->datasync) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 50; false; }) - ; +static bool marshal_Tlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Tlopen *val) { + uint32_t needed_size = 15; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tlopen", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 12); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->flags); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#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 -LM_FLATTEN static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->max_msg_size) - || marshal_s(ctx, &val->version) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 100; false; }) - ; +static bool marshal_Rlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Rlopen *val) { + uint32_t needed_size = 24; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rlopen", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 13); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->iounit); + return false; } -LM_FLATTEN static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->max_msg_size) - || marshal_s(ctx, &val->version) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 101; false; }) - ; +static bool marshal_Tlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tlcreate *val) { + uint32_t needed_size = 25 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tlcreate", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 14); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U32LE(ctx, val->flags); + MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->gid); + return false; } -LM_FLATTEN static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_s(ctx, &val->ename) -#if CONFIG_9P_ENABLE_9P2000_u - || ( is_ver(ctx, 9P2000_u) && marshal_4(ctx, &val->errno) ) -#endif /* CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 107; false; }) - ; +static bool marshal_Rlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rlcreate *val) { + uint32_t needed_size = 24; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rlcreate", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 15); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->iounit); + return false; } -LM_FLATTEN static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_fid(ctx, &val->newfid) - || marshal_2(ctx, &val->nwname) - || ({ bool err = false; - for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) - err = marshal_s(ctx, &val->wname[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 110; false; }) - ; +static bool marshal_Tsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tsymlink *val) { + uint32_t needed_size = 19 + val->name.len + val->symtgt.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tsymlink", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 16); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U16LE(ctx, val->symtgt.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->symtgt.utf8, val->symtgt.len); + MARSHAL_U32LE(ctx, val->gid); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool marshal_Trename(struct _marshal_ctx *ctx, struct lib9p_msg_Trename *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_fid(ctx, &val->dfid) - || marshal_s(ctx, &val->name) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 20; false; }) - ; +static bool marshal_Rsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rsymlink *val) { + uint32_t needed_size = 20; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rsymlink", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 17); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + return false; } -LM_FLATTEN static bool marshal_Rreadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rreadlink *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_s(ctx, &val->target) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 23; false; }) - ; +static bool marshal_Tmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Tmknod *val) { + uint32_t needed_size = 29 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tmknod", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 18); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->dfid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->major); + MARSHAL_U32LE(ctx, val->minor); + MARSHAL_U32LE(ctx, val->gid); + return false; } -LM_FLATTEN static bool marshal_Txattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Txattrwalk *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_fid(ctx, &val->newfid) - || marshal_s(ctx, &val->name) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 30; false; }) - ; +static bool marshal_Rmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Rmknod *val) { + uint32_t needed_size = 20; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rmknod", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 19); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + return false; } -LM_FLATTEN static bool marshal_Txattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Txattrcreate *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_s(ctx, &val->name) - || marshal_8(ctx, &val->attr_size) - || marshal_4(ctx, &val->flags) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 32; false; }) - ; +static bool marshal_Trename(struct _marshal_ctx *ctx, struct lib9p_msg_Trename *val) { + uint32_t needed_size = 17 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Trename", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 20); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->dfid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + return false; } -LM_FLATTEN static bool marshal_Tgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetlock *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_1(ctx, &val->type) - || marshal_8(ctx, &val->start) - || marshal_8(ctx, &val->length) - || marshal_4(ctx, &val->proc_id) - || marshal_s(ctx, &val->client_id) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 54; false; }) - ; +static bool marshal_Rrename(struct _marshal_ctx *ctx, struct lib9p_msg_Rrename *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rrename", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 21); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Rgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetlock *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_1(ctx, &val->type) - || marshal_8(ctx, &val->start) - || marshal_8(ctx, &val->length) - || marshal_4(ctx, &val->proc_id) - || marshal_s(ctx, &val->client_id) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 55; false; }) - ; +static bool marshal_Treadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Treadlink *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Treadlink", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 22); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + return false; } -LM_FLATTEN static bool marshal_Tlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tlink *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->dfid) - || marshal_fid(ctx, &val->fid) - || marshal_s(ctx, &val->name) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 70; false; }) - ; +static bool marshal_Rreadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rreadlink *val) { + uint32_t needed_size = 9 + val->target.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rreadlink", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 23); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U16LE(ctx, val->target.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->target.utf8, val->target.len); + return false; } -LM_FLATTEN static bool marshal_Trenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Trenameat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->olddirfid) - || marshal_s(ctx, &val->oldname) - || marshal_fid(ctx, &val->newdirfid) - || marshal_s(ctx, &val->newname) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 74; false; }) - ; +static bool marshal_Tgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetattr *val) { + uint32_t needed_size = 19; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tgetattr", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 24); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U64LE(ctx, val->request_mask & getattr_masks[ctx->ctx->version]); + return false; } -LM_FLATTEN static bool marshal_Tunlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Tunlinkat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->dirfd) - || marshal_s(ctx, &val->name) - || marshal_4(ctx, &val->flags) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 76; false; }) - ; +static bool marshal_Rgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetattr *val) { + uint32_t needed_size = 160; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rgetattr", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 25); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U64LE(ctx, val->valid); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->uid); + MARSHAL_U32LE(ctx, val->gid); + MARSHAL_U64LE(ctx, val->nlink); + MARSHAL_U64LE(ctx, val->rdev); + MARSHAL_U64LE(ctx, val->filesize); + MARSHAL_U64LE(ctx, val->blksize); + MARSHAL_U64LE(ctx, val->blocks); + MARSHAL_U64LE(ctx, val->atime_sec); + MARSHAL_U64LE(ctx, val->atime_nsec); + MARSHAL_U64LE(ctx, val->mtime_sec); + MARSHAL_U64LE(ctx, val->mtime_nsec); + MARSHAL_U64LE(ctx, val->ctime_sec); + MARSHAL_U64LE(ctx, val->ctime_nsec); + MARSHAL_U64LE(ctx, val->btime_sec); + MARSHAL_U64LE(ctx, val->btime_nsec); + MARSHAL_U64LE(ctx, val->gen); + MARSHAL_U64LE(ctx, val->data_version); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -LM_FLATTEN static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->fid) - || marshal_2(ctx, &val->nwname) - || ({ bool err = false; - for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) - err = marshal_s(ctx, &val->wname[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 152; false; }) - ; +static bool marshal_Tsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tsetattr *val) { + uint32_t needed_size = 67; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tsetattr", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 26); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->valid & setattr_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->uid); + MARSHAL_U32LE(ctx, val->gid); + MARSHAL_U64LE(ctx, val->filesize); + MARSHAL_U64LE(ctx, val->atime_sec); + MARSHAL_U64LE(ctx, val->atime_nsec); + MARSHAL_U64LE(ctx, val->mtime_sec); + MARSHAL_U64LE(ctx, val->mtime_nsec); + return false; } -LM_FLATTEN static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_4(ctx, &val->fid) - || marshal_2(ctx, &val->nwname) - || ({ bool err = false; - for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) - err = marshal_s(ctx, &val->wname[i]); - err; }) - || marshal_4(ctx, &val->count) - || ({ bool err = false; - for (typeof(val->count) i = 0; i < val->count && !err; i++) - err = marshal_1(ctx, (uint8_t *)&val->data[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 154; false; }) - ; +static bool marshal_Rsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rsetattr *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rsetattr", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 27); + MARSHAL_U16LE(ctx, val->tag); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_e */ -#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 -LM_ALWAYS_INLINE static bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid *val) { - return false - || marshal_qt(ctx, &val->type) - || marshal_4(ctx, &val->vers) - || marshal_8(ctx, &val->path) - ; +static bool marshal_Txattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Txattrwalk *val) { + uint32_t needed_size = 17 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Txattrwalk", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 30); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->newfid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + return false; } -LM_FLATTEN static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->afid) - || marshal_s(ctx, &val->uname) - || marshal_s(ctx, &val->aname) -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - || ( ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) && marshal_nuid(ctx, &val->n_uid) ) -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 102; false; }) - ; +static bool marshal_Rxattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattrwalk *val) { + uint32_t needed_size = 15; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rxattrwalk", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 31); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U64LE(ctx, val->attr_size); + return false; } -LM_FLATTEN static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_fid(ctx, &val->afid) - || marshal_s(ctx, &val->uname) - || marshal_s(ctx, &val->aname) -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - || ( ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) && marshal_nuid(ctx, &val->n_uid) ) -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 104; false; }) - ; +static bool marshal_Txattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Txattrcreate *val) { + uint32_t needed_size = 25 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Txattrcreate", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 32); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U64LE(ctx, val->attr_size); + MARSHAL_U32LE(ctx, val->flags); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool marshal_Tlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tlcreate *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_s(ctx, &val->name) - || marshal_4(ctx, &val->flags) - || marshal_4(ctx, &val->mode) - || marshal_nuid(ctx, &val->gid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 14; false; }) - ; +static bool marshal_Rxattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattrcreate *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rxattrcreate", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 33); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Tsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tsymlink *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_s(ctx, &val->name) - || marshal_s(ctx, &val->symtgt) - || marshal_nuid(ctx, &val->gid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 16; false; }) - ; +static bool marshal_Treaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Treaddir *val) { + uint32_t needed_size = 23; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Treaddir", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 40); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U64LE(ctx, val->offset); + MARSHAL_U32LE(ctx, val->count); + return false; } -LM_FLATTEN static bool marshal_Tmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Tmknod *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->dfid) - || marshal_s(ctx, &val->name) - || marshal_4(ctx, &val->mode) - || marshal_4(ctx, &val->major) - || marshal_4(ctx, &val->minor) - || marshal_nuid(ctx, &val->gid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 18; false; }) - ; +static bool marshal_Rreaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Rreaddir *val) { + uint64_t needed_size = 11 + val->count; + if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rreaddir", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = (uint32_t)needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 41); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->count); + MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count); + return false; } -LM_FLATTEN static bool marshal_Tmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Tmkdir *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->dfid) - || marshal_s(ctx, &val->name) - || marshal_4(ctx, &val->mode) - || marshal_nuid(ctx, &val->gid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 72; false; }) - ; +static bool marshal_Tfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Tfsync *val) { + uint32_t needed_size = 15; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tfsync", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 50); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U32LE(ctx, val->datasync); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_o(ctx, &val->mode) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 112; false; }) - ; +static bool marshal_Rfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Rfsync *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rfsync", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 51); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_s(ctx, &val->name) - || marshal_dm(ctx, &val->perm) - || marshal_o(ctx, &val->mode) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 114; false; }) - ; +static bool marshal_Tlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tlock *val) { + uint32_t needed_size = 38 + val->client_id.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tlock", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 52); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U8LE(ctx, val->type); + MARSHAL_U32LE(ctx, val->flags & lock_flags_masks[ctx->ctx->version]); + MARSHAL_U64LE(ctx, val->start); + MARSHAL_U64LE(ctx, val->length); + MARSHAL_U32LE(ctx, val->proc_id); + MARSHAL_U16LE(ctx, val->client_id.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_p9p -LM_FLATTEN static bool marshal_Topenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Topenfd *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_o(ctx, &val->mode) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 98; false; }) - ; +static bool marshal_Rlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rlock *val) { + uint32_t needed_size = 8; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rlock", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 53); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->status); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool marshal_Tgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetattr *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_getattr(ctx, &val->request_mask) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 24; false; }) - ; +static bool marshal_Tgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetlock *val) { + uint32_t needed_size = 34 + val->client_id.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tgetlock", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 54); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U8LE(ctx, val->type); + MARSHAL_U64LE(ctx, val->start); + MARSHAL_U64LE(ctx, val->length); + MARSHAL_U32LE(ctx, val->proc_id); + MARSHAL_U16LE(ctx, val->client_id.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len); + return false; } -LM_FLATTEN static bool marshal_Tsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tsetattr *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_setattr(ctx, &val->valid) - || marshal_4(ctx, &val->mode) - || marshal_nuid(ctx, &val->uid) - || marshal_nuid(ctx, &val->gid) - || marshal_8(ctx, &val->filesize) - || marshal_8(ctx, &val->atime_sec) - || marshal_8(ctx, &val->atime_nsec) - || marshal_8(ctx, &val->mtime_sec) - || marshal_8(ctx, &val->mtime_nsec) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 26; false; }) - ; +static bool marshal_Rgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetlock *val) { + uint32_t needed_size = 30 + val->client_id.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rgetlock", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 55); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->type); + MARSHAL_U64LE(ctx, val->start); + MARSHAL_U64LE(ctx, val->length); + MARSHAL_U32LE(ctx, val->proc_id); + MARSHAL_U16LE(ctx, val->client_id.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len); + return false; } -LM_FLATTEN static bool marshal_Tlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tlock *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || marshal_lock_type(ctx, &val->type) - || marshal_lock_flags(ctx, &val->flags) - || marshal_8(ctx, &val->start) - || marshal_8(ctx, &val->length) - || marshal_4(ctx, &val->proc_id) - || marshal_s(ctx, &val->client_id) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 52; false; }) - ; +static bool marshal_Tlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tlink *val) { + uint32_t needed_size = 17 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tlink", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 70); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->dfid); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + return false; } -LM_FLATTEN static bool marshal_Rlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rlock *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_lock_status(ctx, &val->status) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 53; false; }) - ; +static bool marshal_Rlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rlink *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rlink", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 71); + MARSHAL_U16LE(ctx, val->tag); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { - uint32_t _stat_size_offset; - uint32_t _kern_type_offset; - return false - || ({ _stat_size_offset = ctx->net_offset; ({ ctx->net_offset += 2; false; }); }) - || ({ _kern_type_offset = ctx->net_offset; marshal_2(ctx, &val->kern_type); }) - || marshal_4(ctx, &val->kern_dev) - || marshal_qid(ctx, &val->file_qid) - || marshal_dm(ctx, &val->file_mode) - || marshal_4(ctx, &val->file_atime) - || marshal_4(ctx, &val->file_mtime) - || marshal_8(ctx, &val->file_size) - || marshal_s(ctx, &val->file_name) - || marshal_s(ctx, &val->file_owner_uid) - || marshal_s(ctx, &val->file_owner_gid) - || marshal_s(ctx, &val->file_last_modified_uid) -#if CONFIG_9P_ENABLE_9P2000_u - || ( is_ver(ctx, 9P2000_u) && marshal_s(ctx, &val->file_extension) ) - || ( is_ver(ctx, 9P2000_u) && marshal_nuid(ctx, &val->file_owner_n_uid) ) - || ( is_ver(ctx, 9P2000_u) && marshal_nuid(ctx, &val->file_owner_n_gid) ) - || ( is_ver(ctx, 9P2000_u) && marshal_nuid(ctx, &val->file_last_modified_n_uid) ) -#endif /* CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint16le_encode(&ctx->net_bytes[_stat_size_offset], ctx->net_offset - _kern_type_offset); false; }) - ; +static bool marshal_Tmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Tmkdir *val) { + uint32_t needed_size = 21 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tmkdir", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 72); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->dfid); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->gid); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#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 -LM_FLATTEN static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->aqid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 103; false; }) - ; +static bool marshal_Rmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Rmkdir *val) { + uint32_t needed_size = 20; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rmkdir", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 73); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + return false; } -LM_FLATTEN static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 105; false; }) - ; +static bool marshal_Trenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Trenameat *val) { + uint32_t needed_size = 19 + val->oldname.len + val->newname.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Trenameat", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 74); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->olddirfid); + MARSHAL_U16LE(ctx, val->oldname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->oldname.utf8, val->oldname.len); + MARSHAL_U32LE(ctx, val->newdirfid); + MARSHAL_U16LE(ctx, val->newname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->newname.utf8, val->newname.len); + return false; } -LM_FLATTEN static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_2(ctx, &val->nwqid) - || ({ bool err = false; - for (typeof(val->nwqid) i = 0; i < val->nwqid && !err; i++) - err = marshal_qid(ctx, &val->wqid[i]); - err; }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 111; false; }) - ; +static bool marshal_Rrenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Rrenameat *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rrenameat", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 75); + MARSHAL_U16LE(ctx, val->tag); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || marshal_4(ctx, &val->iounit) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 113; false; }) - ; +static bool marshal_Tunlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Tunlinkat *val) { + uint32_t needed_size = 17 + val->name.len; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tunlinkat", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 76); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->dirfd); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); + MARSHAL_U32LE(ctx, val->flags); + return false; } -LM_FLATTEN static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || marshal_4(ctx, &val->iounit) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 115; false; }) - ; +static bool marshal_Runlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Runlinkat *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Runlinkat", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 77); + MARSHAL_U16LE(ctx, val->tag); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_p9p -LM_FLATTEN static bool marshal_Ropenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Ropenfd *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || marshal_4(ctx, &val->iounit) - || marshal_4(ctx, &val->unixfd) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 99; false; }) - ; +#endif /* CONFIG_9P_ENABLE_9P2000_L */ +#if CONFIG_9P_ENABLE_9P2000_e +static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) { + uint32_t needed_size = 15; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tsession", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 150); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U64LE(ctx, val->key); + return false; } -#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool marshal_Rlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Rlopen *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || marshal_4(ctx, &val->iounit) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 13; false; }) - ; +static bool marshal_Rsession(struct _marshal_ctx *ctx, struct lib9p_msg_Rsession *val) { + uint32_t needed_size = 7; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rsession", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 151); + MARSHAL_U16LE(ctx, val->tag); + return false; } -LM_FLATTEN static bool marshal_Rlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rlcreate *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || marshal_4(ctx, &val->iounit) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 15; false; }) - ; +static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) { + uint64_t needed_size = 13; + for (uint16_t i = 0; i < val->nwname; i++) { + needed_size += 2 + val->wname[i].len; + } + if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tsread", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = (uint32_t)needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 152); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->nwname); + for (uint16_t i = 0; i < val->nwname; i++) { + MARSHAL_U16LE(ctx, val->wname[i].len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len); + } + return false; } -LM_FLATTEN static bool marshal_Rsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rsymlink *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 17; false; }) - ; +static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) { + uint64_t needed_size = 11 + val->count; + if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rsread", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = (uint32_t)needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 153); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->count); + MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count); + return false; } -LM_FLATTEN static bool marshal_Rmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Rmknod *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 19; false; }) - ; +static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) { + uint64_t needed_size = 17 + val->count; + for (uint16_t i = 0; i < val->nwname; i++) { + needed_size += 2 + val->wname[i].len; + } + if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Tswrite", + ctx->ctx->version ? "negotiated" : "client", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = (uint32_t)needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 154); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->fid); + MARSHAL_U16LE(ctx, val->nwname); + for (uint16_t i = 0; i < val->nwname; i++) { + MARSHAL_U16LE(ctx, val->wname[i].len); + 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); + return false; } -LM_FLATTEN static bool marshal_Rgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetattr *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_8(ctx, &val->valid) - || marshal_qid(ctx, &val->qid) - || marshal_4(ctx, &val->mode) - || marshal_nuid(ctx, &val->uid) - || marshal_nuid(ctx, &val->gid) - || marshal_8(ctx, &val->nlink) - || marshal_8(ctx, &val->rdev) - || marshal_8(ctx, &val->filesize) - || marshal_8(ctx, &val->blksize) - || marshal_8(ctx, &val->blocks) - || marshal_8(ctx, &val->atime_sec) - || marshal_8(ctx, &val->atime_nsec) - || marshal_8(ctx, &val->mtime_sec) - || marshal_8(ctx, &val->mtime_nsec) - || marshal_8(ctx, &val->ctime_sec) - || marshal_8(ctx, &val->ctime_nsec) - || marshal_8(ctx, &val->btime_sec) - || marshal_8(ctx, &val->btime_nsec) - || marshal_8(ctx, &val->gen) - || marshal_8(ctx, &val->data_version) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 25; false; }) - ; +static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) { + uint32_t needed_size = 11; + if (needed_size > ctx->ctx->max_msg_size) { + lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + "Rswrite", + ctx->ctx->version ? "negotiated" : "server", + ctx->ctx->max_msg_size); + return true; + } + uint32_t offsetof_end = needed_size; + uint32_t offsetof_size = 0; + MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); + MARSHAL_U8LE(ctx, 155); + MARSHAL_U16LE(ctx, val->tag); + MARSHAL_U32LE(ctx, val->count); + return false; } +#endif /* CONFIG_9P_ENABLE_9P2000_e */ -LM_FLATTEN static bool marshal_Rmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Rmkdir *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_qid(ctx, &val->qid) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 73; false; }) - ; -} +/* function tables ************************************************************/ +const uint32_t _lib9p_table_msg_min_size[LIB9P_VER_NUM] = { + [LIB9P_VER_unknown] = 9, +#if CONFIG_9P_ENABLE_9P2000 + [LIB9P_VER_9P2000] = 9, +#endif /* CONFIG_9P_ENABLE_9P2000 */ +#if CONFIG_9P_ENABLE_9P2000_L + [LIB9P_VER_9P2000_L] = 9, #endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - uint32_t _nstat_offset; - uint32_t _stat_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || ({ _nstat_offset = ctx->net_offset; ({ ctx->net_offset += 2; false; }); }) - || ({ _stat_offset = ctx->net_offset; marshal_stat(ctx, &val->stat); }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 125; false; }) - || ({ uint16le_encode(&ctx->net_bytes[_nstat_offset], ctx->net_offset - _stat_offset); false; }) - ; -} - -LM_FLATTEN static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) { - uint32_t _size_offset; - uint32_t _typ_offset; - uint32_t _nstat_offset; - uint32_t _stat_offset; - return false - || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); }) - || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); }) - || marshal_tag(ctx, &val->tag) - || marshal_fid(ctx, &val->fid) - || ({ _nstat_offset = ctx->net_offset; ({ ctx->net_offset += 2; false; }); }) - || ({ _stat_offset = ctx->net_offset; marshal_stat(ctx, &val->stat); }) - || ({ uint32le_encode(&ctx->net_bytes[_size_offset], ctx->net_offset - _size_offset); false; }) - || ({ ctx->net_bytes[_typ_offset] = 126; false; }) - || ({ uint16le_encode(&ctx->net_bytes[_nstat_offset], ctx->net_offset - _stat_offset); false; }) - ; -} -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ - -/* function tables ************************************************************/ +#if CONFIG_9P_ENABLE_9P2000_e + [LIB9P_VER_9P2000_e] = 9, +#endif /* CONFIG_9P_ENABLE_9P2000_e */ +#if CONFIG_9P_ENABLE_9P2000_p9p + [LIB9P_VER_9P2000_p9p] = 9, +#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ +#if CONFIG_9P_ENABLE_9P2000_u + [LIB9P_VER_9P2000_u] = 13, +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +}; #define _MSG_RECV(typ) [LIB9P_TYP_##typ/2] = { \ .basesize = sizeof(struct lib9p_msg_##typ), \ diff --git a/lib9p/idl.gen b/lib9p/idl.gen index adb15ce..f2b4f13 100755 --- a/lib9p/idl.gen +++ b/lib9p/idl.gen @@ -5,6 +5,7 @@ # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later +import enum import graphlib import os.path import sys @@ -145,6 +146,9 @@ def ifdef_pop(n: int) -> str: return ret +# topo_sorted() ################################################################ + + def topo_sorted(typs: list[idl.Type]) -> typing.Iterable[idl.Type]: ts: graphlib.TopologicalSorter[idl.Type] = graphlib.TopologicalSorter() for typ in typs: @@ -163,6 +167,189 @@ def topo_sorted(typs: list[idl.Type]) -> typing.Iterable[idl.Type]: return ts.static_order() +# walk() ####################################################################### + + +class Path: + root: idl.Type + elems: list[idl.StructMember] + + def __init__( + self, root: idl.Type, elems: list[idl.StructMember] | None = None + ) -> None: + self.root = root + self.elems = elems if elems is not None else [] + + def add(self, elem: idl.StructMember) -> "Path": + return Path(self.root, self.elems + [elem]) + + def parent(self) -> "Path": + return Path(self.root, self.elems[:-1]) + + def c_str(self, base: str, loopdepth: int = 0) -> str: + ret = base + for i, elem in enumerate(self.elems): + if i > 0: + ret += "." + ret += elem.name + if elem.cnt: + ret += f"[{chr(ord('i')+loopdepth)}]" + loopdepth += 1 + return ret + + def __str__(self) -> str: + return self.c_str(self.root.name + "->") + + +class WalkCmd(enum.Enum): + KEEP_GOING = 1 + DONT_RECURSE = 2 + ABORT = 3 + + +type WalkHandler = typing.Callable[ + [Path], tuple[WalkCmd, typing.Callable[[], None] | None] +] + + +def _walk(path: Path, handle: WalkHandler) -> WalkCmd: + typ = path.elems[-1].typ if path.elems else path.root + + ret, atexit = handle(path) + + if isinstance(typ, idl.Struct): + match ret: + case WalkCmd.KEEP_GOING: + for member in typ.members: + if _walk(path.add(member), handle) == WalkCmd.ABORT: + ret = WalkCmd.ABORT + break + case WalkCmd.DONT_RECURSE: + ret = WalkCmd.KEEP_GOING + case WalkCmd.ABORT: + ret = WalkCmd.ABORT + case _: + assert False, f"invalid cmd: {ret}" + + if atexit: + atexit() + return ret + + +def walk(typ: idl.Type, handle: WalkHandler) -> None: + _walk(Path(typ), handle) + + +# get_buffer_size() ############################################################ + + +class BufferSize: + min_size: int # really just here to sanity-check against typ.min_size(version) + exp_size: int # "expected" or max-reasonable size + max_size: int # really just here to sanity-check against typ.max_size(version) + max_copy: int + max_copy_extra: str + max_iov: int + max_iov_extra: str + _starts_with_copy: bool + _ends_with_copy: bool + + def __init__(self) -> None: + self.min_size = 0 + self.exp_size = 0 + self.max_size = 0 + self.max_copy = 0 + self.max_copy_extra = "" + self.max_iov = 0 + self.max_iov_extra = "" + self._starts_with_copy = False + self._ends_with_copy = False + + +def get_buffer_size(typ: idl.Type, version: str) -> BufferSize: + assert isinstance(typ, idl.Primitive) or (version in typ.in_versions) + + ret = BufferSize() + + if not isinstance(typ, idl.Struct): + assert typ.static_size + ret.min_size = typ.static_size + ret.exp_size = typ.static_size + ret.max_size = typ.static_size + ret.max_copy = typ.static_size + ret.max_iov = 1 + ret._starts_with_copy = True + ret._ends_with_copy = True + return ret + + def handle(path: Path) -> tuple[WalkCmd, None]: + nonlocal ret + if path.elems: + child = path.elems[-1] + if version not in child.in_versions: + return WalkCmd.DONT_RECURSE, None + if child.cnt: + if child.typ.static_size == 1: # SPECIAL (zerocopy) + ret.max_iov += 1 + # HEURISTIC: 27 for strings (max-strlen from 9P1), 8KiB for other data + ret.exp_size += 27 if child.name == "utf8" else 8192 + ret.max_size += child.max_cnt + ret._ends_with_copy = False + return WalkCmd.DONT_RECURSE, None + sub = get_buffer_size(child.typ, version) + ret.exp_size += sub.exp_size * 16 # HEURISTIC: MAXWELEM + ret.max_size += sub.max_size * child.max_cnt + if child.name == "wname" and path.root.name in ( + "Tsread", + "Tswrite", + ): # SPECIAL (9P2000.e) + assert ret._ends_with_copy + assert sub._starts_with_copy + assert not sub._ends_with_copy + ret.max_copy_extra = ( + f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_copy})" + ) + ret.max_iov_extra = ( + f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_iov})" + ) + ret.max_iov -= 1 + else: + ret.max_copy += sub.max_copy * child.max_cnt + if sub.max_iov == 1 and sub._starts_with_copy: # is purely copy + ret.max_iov += 1 + else: # contains zero-copy segments + ret.max_iov += sub.max_iov * child.max_cnt + if ret._ends_with_copy and sub._starts_with_copy: + # we can merge this one + ret.max_iov -= 1 + if ( + sub._ends_with_copy + and sub._starts_with_copy + and sub.max_iov > 1 + ): + # we can merge these + ret.max_iov -= child.max_cnt - 1 + ret._ends_with_copy = sub._ends_with_copy + return WalkCmd.DONT_RECURSE, None + elif not isinstance(child.typ, idl.Struct): + assert child.typ.static_size + if not ret._ends_with_copy: + if ret.max_size == 0: + ret._starts_with_copy = True + ret.max_iov += 1 + ret._ends_with_copy = True + ret.min_size += child.typ.static_size + ret.exp_size += child.typ.static_size + ret.max_size += child.typ.static_size + ret.max_copy += child.typ.static_size + return WalkCmd.KEEP_GOING, None + + walk(typ, handle) + assert ret.min_size == typ.min_size(version) + assert ret.max_size == typ.max_size(version) + return ret + + # Generate .h ################################################################## @@ -177,6 +364,8 @@ def gen_h(versions: set[str], typs: list[idl.Type]) -> str: #endif #include <stdint.h> /* for uint{{n}}_t types */ + +#include <libhw/generic/net.h> /* for struct iovec */ """ id2typ: dict[int, idl.Message] = {} @@ -192,6 +381,14 @@ def gen_h(versions: set[str], typs: list[idl.Type]) -> str: ret += "\n" ret += f"#ifndef {c_ver_ifdef({ver})}\n" ret += f"\t#error config.h must define {c_ver_ifdef({ver})}\n" + if ver == "9P2000.e": # SPECIAL (9P2000.e) + ret += "#else\n" + ret += f"\t#if {c_ver_ifdef({ver})}\n" + ret += "\t\t#ifndef(CONFIG_9P_MAX_9P2000_e_WELEM)\n" + ret += f"\t\t\t#error if {c_ver_ifdef({ver})} then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM\n" + ret += "\t\t#endif\n" + ret += "\t\tstatic_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0);\n" + ret += "\t#endif\n" ret += "#endif\n" ret += f""" @@ -251,16 +448,20 @@ enum {idprefix}version {{ ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) def sum_size(typ: idl.Type, version: str) -> str: - min_size = typ.min_size(version) - max_size = typ.max_size(version) - assert min_size <= max_size and max_size < u64max + sz = get_buffer_size(typ, version) + assert ( + sz.min_size <= sz.exp_size + and sz.exp_size <= sz.max_size + and sz.max_size < u64max + ) ret = "" - if min_size == max_size: - ret += f"size = {min_size:,}" + if sz.min_size == sz.max_size: + ret += f"size = {sz.min_size:,}" else: - ret += f"min_size = {min_size:,} ; max_size = {max_size:,}" - if max_size > u32max: + ret += f"min_size = {sz.min_size:,} ; exp_size = {sz.exp_size:,} ; max_size = {sz.max_size:,}" + if sz.max_size > u32max: ret += " (warning: >UINT32_MAX)" + ret += f" ; max_iov = {sz.max_iov:,}{sz.max_iov_extra} ; max_copy = {sz.max_copy:,}{sz.max_copy_extra}" return ret ret += per_version_comment(typ, sum_size) @@ -331,6 +532,87 @@ enum {idprefix}version {{ ret += "};\n" ret += ifdef_pop(0) + ret += """ +/* containers *****************************************************************/ +""" + ret += "\n" + ret += f"#define _{idprefix.upper()}MAX(a, b) ((a) > (b)) ? (a) : (b)\n" + + tmsg_max_iov: dict[str, int] = {} + tmsg_max_copy: dict[str, int] = {} + rmsg_max_iov: dict[str, int] = {} + rmsg_max_copy: dict[str, int] = {} + for typ in typs: + if not isinstance(typ, idl.Message): + continue + if typ.name in ("Tsread", "Tswrite"): # SPECIAL (9P2000.e) + continue + max_iov = tmsg_max_iov if typ.msgid % 2 == 0 else rmsg_max_iov + max_copy = tmsg_max_copy if typ.msgid % 2 == 0 else rmsg_max_copy + for version in typ.in_versions: + if version not in max_iov: + max_iov[version] = 0 + max_copy[version] = 0 + sz = get_buffer_size(typ, version) + if sz.max_iov > max_iov[version]: + max_iov[version] = sz.max_iov + if sz.max_copy > max_copy[version]: + max_copy[version] = sz.max_copy + + for name, table in [ + ("tmsg_max_iov", tmsg_max_iov), + ("tmsg_max_copy", tmsg_max_copy), + ("rmsg_max_iov", rmsg_max_iov), + ("rmsg_max_copy", rmsg_max_copy), + ]: + inv: dict[int, set[str]] = {} + for version, maxval in table.items(): + if maxval not in inv: + inv[maxval] = set() + inv[maxval].add(version) + + ret += "\n" + directive = "if" + seen_e = False # SPECIAL (9P2000.e) + for maxval in sorted(inv, reverse=True): + ret += f"#{directive} {c_ver_ifdef(inv[maxval])}\n" + indent = 1 + if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e) + typ = next(typ for typ in typs if typ.name == "Tswrite") + sz = get_buffer_size(typ, "9P2000.e") + match name: + case "tmsg_max_iov": + maxexpr = f"{sz.max_iov}{sz.max_iov_extra}" + case "tmsg_max_copy": + maxexpr = f"{sz.max_copy}{sz.max_copy_extra}" + case _: + assert False + ret += f"\t#if {c_ver_ifdef({"9P2000.e"})}\n" + ret += f"\t\t#define {idprefix.upper()}{name.upper()} _{idprefix.upper()}MAX({maxval}, {maxexpr})\n" + ret += f"\t#else\n" + indent += 1 + ret += f"{'\t'*indent}#define {idprefix.upper()}{name.upper()} {maxval}\n" + if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e) + ret += "\t#endif\n" + if "9P2000.e" in inv[maxval]: + seen_e = True + directive = "elif" + ret += "#endif\n" + + ret += "\n" + ret += f"struct {idprefix}Tmsg_send_buf {{\n" + ret += f"\tsize_t iov_cnt;\n" + ret += f"\tstruct iovec iov[{idprefix.upper()}TMSG_MAX_IOV];\n" + ret += f"\tuint8_t copied[{idprefix.upper()}TMSG_MAX_COPY];\n" + ret += "};\n" + + ret += "\n" + ret += f"struct {idprefix}Rmsg_send_buf {{\n" + ret += f"\tsize_t iov_cnt;\n" + ret += f"\tstruct iovec iov[{idprefix.upper()}RMSG_MAX_IOV];\n" + ret += f"\tuint8_t copied[{idprefix.upper()}RMSG_MAX_COPY];\n" + ret += "};\n" + return ret @@ -549,7 +831,10 @@ LM_ALWAYS_INLINE static bool validate_8(struct _validate_ctx *ctx) { return _val if member.in_versions != typ.in_versions: ret += "( " + c_ver_cond(member.in_versions) + " && " if member.cnt is not None: - ret += f"_validate_list(ctx, {member.cnt.name}, validate_{member.typ.name}, sizeof({c_typename(member.typ)}))" + if member.typ.static_size == 1: # SPECIAL (zerocopy) + ret += f"_validate_size_net(ctx, {member.cnt.name})" + else: + ret += f"_validate_list(ctx, {member.cnt.name}, validate_{member.typ.name}, sizeof({c_typename(member.typ)}))" if typ.name == "s": # SPECIAL (string) ret += f'\n\t || ({{ (!is_valid_utf8_without_nul(&ctx->net_bytes[ctx->net_offset-len], len)) && lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); }})' else: @@ -653,13 +938,15 @@ LM_ALWAYS_INLINE static void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *o if member.in_versions != typ.in_versions: ret += "{\n" ret += prefix - ret += f"out->{member.name} = ctx->extra;\n" - ret += f"{prefix}ctx->extra += sizeof(out->{member.name}[0]) * out->{member.cnt.name};\n" - ret += f"{prefix}for (typeof(out->{member.cnt.name}) i = 0; i < out->{member.cnt.name}; i++)\n" - if member.typ.static_size == 1: # SPECIAL (string) - # Special-case is that we cast from `char` to `uint8_t`. - ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, (uint8_t *)&out->{member.name}[i]);\n" + if member.typ.static_size == 1: # SPECIAL (string, zerocopy) + ret += f"out->{member.name} = (char *)&ctx->net_bytes[ctx->net_offset];\n" + ret += ( + f"{prefix}ctx->net_offset += out->{member.cnt.name};\n" + ) else: + ret += f"out->{member.name} = ctx->extra;\n" + ret += f"{prefix}ctx->extra += sizeof(out->{member.name}[0]) * out->{member.cnt.name};\n" + ret += f"{prefix}for (typeof(out->{member.cnt.name}) i = 0; i < out->{member.cnt.name}; i++)\n" ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n" if member.in_versions != typ.in_versions: ret += "\t}\n" @@ -675,139 +962,346 @@ LM_ALWAYS_INLINE static void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *o ret += """ /* marshal_* ******************************************************************/ -LM_ALWAYS_INLINE static bool _marshal_too_large(struct _marshal_ctx *ctx) { -\tlib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s too large to marshal into %s limit (limit=%"PRIu32")", -\t\t(ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", -\t\tctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), -\t\tctx->ctx->max_msg_size); -\treturn true; -} +""" + ret += c_macro( + "#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len)\n" + "\tif (ctx->net_iov[ctx->net_iov_cnt-1].iov_len)\n" + "\t\tctx->net_iov_cnt++;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = data;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len = len;\n" + "\tctx->net_iov_cnt++;\n" + ) + ret += c_macro( + "#define MARSHAL_BYTES(ctx, data, len)\n" + "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" + "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" + "\tmemcpy(&ctx->net_copied[ctx->net_copied_size], data, len);\n" + "\tctx->net_copied_size += len;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += len;\n" + ) + ret += c_macro( + "#define MARSHAL_U8LE(ctx, val)\n" + "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" + "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" + "\tctx->net_copied[ctx->net_copied_size] = val;\n" + "\tctx->net_copied_size += 1;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 1;\n" + ) + ret += c_macro( + "#define MARSHAL_U16LE(ctx, val)\n" + "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" + "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" + "\tuint16le_encode(&ctx->net_copied[ctx->net_copied_size], val);\n" + "\tctx->net_copied_size += 2;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 2;\n" + ) + ret += c_macro( + "#define MARSHAL_U32LE(ctx, val)\n" + "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" + "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" + "\tuint32le_encode(&ctx->net_copied[ctx->net_copied_size], val);\n" + "\tctx->net_copied_size += 4;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 4;\n" + ) + ret += c_macro( + "#define MARSHAL_U64LE(ctx, val)\n" + "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" + "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" + "\tuint64le_encode(&ctx->net_copied[ctx->net_copied_size], val);\n" + "\tctx->net_copied_size += 8;\n" + "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 8;\n" + ) -LM_ALWAYS_INLINE static bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { -\tif (ctx->net_offset + 1 > ctx->ctx->max_msg_size) -\t\treturn _marshal_too_large(ctx); -\tctx->net_bytes[ctx->net_offset] = *val; -\tctx->net_offset += 1; -\treturn false; -} + class OffsetExpr: + static: int + cond: dict[frozenset[str], "OffsetExpr"] + rep: list[tuple[Path, "OffsetExpr"]] + + def __init__(self) -> None: + self.static = 0 + self.rep = [] + self.cond = {} + + def add(self, other: "OffsetExpr") -> None: + self.static += other.static + self.rep += other.rep + for k, v in other.cond.items(): + if k in self.cond: + self.cond[k].add(v) + else: + self.cond[k] = v + + def gen_c( + self, + dsttyp: str, + dstvar: str, + root: str, + indent_depth: int, + loop_depth: int, + ) -> str: + oneline: list[str] = [] + multiline = "" + if self.static: + oneline.append(str(self.static)) + for cnt, sub in self.rep: + if not sub.cond and not sub.rep: + if sub.static == 1: + oneline.append(cnt.c_str(root)) + else: + oneline.append(f"({cnt.c_str(root)})*{sub.static}") + continue + loopvar = chr(ord("i") + loop_depth) + multiline += f"{'\t'*indent_depth}for ({c_typename(cnt.elems[-1].typ)} {loopvar} = 0; {loopvar} < {cnt.c_str(root)}; {loopvar}++) {{\n" + multiline += sub.gen_c( + "", dstvar, root, indent_depth + 1, loop_depth + 1 + ) + multiline += f"{'\t'*indent_depth}}}\n" + for vers, sub in self.cond.items(): + multiline += ifdef_push(indent_depth + 1, c_ver_ifdef(vers)) + multiline += f"{'\t'*indent_depth}if {c_ver_cond(vers)} {{\n" + multiline += sub.gen_c("", dstvar, root, indent_depth + 1, loop_depth) + multiline += f"{'\t'*indent_depth}}}\n" + multiline += ifdef_pop(indent_depth) + if dsttyp: + if not oneline: + oneline.append("0") + ret = f"{'\t'*indent_depth}{dsttyp} {dstvar} = {' + '.join(oneline)};\n" + elif oneline: + ret = f"{'\t'*indent_depth}{dstvar} += {' + '.join(oneline)};\n" + ret += multiline + return ret -LM_ALWAYS_INLINE static bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { -\tif (ctx->net_offset + 2 > ctx->ctx->max_msg_size) -\t\treturn _marshal_too_large(ctx); -\tuint16le_encode(&ctx->net_bytes[ctx->net_offset], *val); -\tctx->net_offset += 2; -\treturn false; -} + type OffsetExprRecursion = typing.Callable[[Path], WalkCmd] -LM_ALWAYS_INLINE static bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { -\tif (ctx->net_offset + 4 > ctx->ctx->max_msg_size) -\t\treturn true; -\tuint32le_encode(&ctx->net_bytes[ctx->net_offset], *val); -\tctx->net_offset += 4; -\treturn false; -} + def get_offset_expr(typ: idl.Type, recurse: OffsetExprRecursion) -> OffsetExpr: + if not isinstance(typ, idl.Struct): + assert typ.static_size + ret = OffsetExpr() + ret.static = typ.static_size + return ret -LM_ALWAYS_INLINE static bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { -\tif (ctx->net_offset + 8 > ctx->ctx->max_msg_size) -\t\treturn true; -\tuint64le_encode(&ctx->net_bytes[ctx->net_offset], *val); -\tctx->net_offset += 8; -\treturn false; -} -""" - for typ in topo_sorted(typs): - inline = "LM_FLATTEN" if isinstance(typ, idl.Message) else "LM_ALWAYS_INLINE" - argfn = unused if (isinstance(typ, idl.Struct) and not typ.members) else used + stack: list[tuple[Path, OffsetExpr, typing.Callable[[], None]]] + + def pop_root() -> None: + assert False + + def pop_cond() -> None: + nonlocal stack + key = frozenset(stack[-1][0].elems[-1].in_versions) + if key in stack[-2][1].cond: + stack[-2][1].cond[key].add(stack[-1][1]) + else: + stack[-2][1].cond[key] = stack[-1][1] + stack = stack[:-1] + + def pop_rep() -> None: + nonlocal stack + member_path = stack[-1][0] + member = member_path.elems[-1] + assert member.cnt + cnt_path = member_path.parent().add(member.cnt) + stack[-2][1].rep.append((cnt_path, stack[-1][1])) + stack = stack[:-1] + + def handle(path: Path) -> tuple[WalkCmd, typing.Callable[[], None] | None]: + nonlocal recurse + + ret = recurse(path) + if ret != WalkCmd.KEEP_GOING: + return ret, None + + nonlocal stack + stack_len = len(stack) + + def pop() -> None: + nonlocal stack + nonlocal stack_len + while len(stack) > stack_len: + stack[-1][2]() + + if path.elems: + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + if child.in_versions < parent.in_versions: + stack.append((path, OffsetExpr(), pop_cond)) + if child.cnt: + stack.append((path, OffsetExpr(), pop_rep)) + if not isinstance(child.typ, idl.Struct): + assert child.typ.static_size + stack[-1][1].static += child.typ.static_size + return ret, pop + + stack = [(Path(typ), OffsetExpr(), pop_root)] + walk(typ, handle) + return stack[0][1] + + def go_to_end(path: Path) -> WalkCmd: + return WalkCmd.KEEP_GOING + + def go_to_tok(name: str) -> typing.Callable[[Path], WalkCmd]: + def ret(path: Path) -> WalkCmd: + if len(path.elems) == 1 and path.elems[0].name == name: + return WalkCmd.ABORT + return WalkCmd.KEEP_GOING + + return ret + + for typ in typs: + if not ( + isinstance(typ, idl.Message) or typ.name == "stat" + ): # SPECIAL (include stat) + continue + assert isinstance(typ, idl.Struct) ret += "\n" ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) - ret += f"{inline} static bool marshal_{typ.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(typ)} *{argfn('val')}) {{\n" - match typ: - case idl.Number(): - ret += f"\treturn marshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)val);\n" - case idl.Bitfield(): - ret += f"\t{c_typename(typ)} masked_val = *val & {typ.name}_masks[ctx->ctx->version];\n" - ret += f"\treturn marshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)&masked_val);\n" - case idl.Struct(): - if len(typ.members) == 0: - ret += "\treturn false;\n" - ret += "}\n" - continue + ret += f"static bool marshal_{typ.name}(struct _marshal_ctx *ctx, {c_typename(typ)} *val) {{\n" - # Pass 1 - declare offset variables - mark_offset = set() - for member in typ.members: - if member.val: - if member.name not in mark_offset: - ret += f"\tuint32_t _{member.name}_offset;\n" - mark_offset.add(member.name) - for tok in member.val.tokens: - if isinstance(tok, idl.ExprSym) and tok.name.startswith("&"): - if tok.name[1:] not in mark_offset: - ret += f"\tuint32_t _{tok.name[1:]}_offset;\n" - mark_offset.add(tok.name[1:]) + # Pass 1 - check size + max_size = max(typ.max_size(v) for v in typ.in_versions) - # Pass 2 - main pass - ret += "\treturn false\n" - for member in typ.members: - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += "\t || " - if member.in_versions != typ.in_versions: - ret += "( " + c_ver_cond(member.in_versions) + " && " - if member.name in mark_offset: - ret += f"({{ _{member.name}_offset = ctx->net_offset; " - if member.cnt: - ret += "({ bool err = false;\n" - ret += f"\t for (typeof(val->{member.cnt.name}) i = 0; i < val->{member.cnt.name} && !err; i++)\n" - ret += "\t \terr = " - if member.typ.static_size == 1: # SPECIAL (string) - # Special-case is that we cast from `char` to `uint8_t`. - ret += f"marshal_{member.typ.name}(ctx, (uint8_t *)&val->{member.name}[i]);\n" - else: - ret += f"marshal_{member.typ.name}(ctx, &val->{member.name}[i]);\n" - ret += f"\t err; }})" - elif member.val: - # Just increment net_offset, don't actually marshal anything (yet). - assert member.static_size - ret += ( - f"({{ ctx->net_offset += {member.static_size}; false; }})" - ) + if max_size > u32max: # SPECIAL (9P2000.e) + ret += get_offset_expr(typ, go_to_end).gen_c( + "uint64_t", "needed_size", "val->", 1, 0 + ) + ret += "\tif (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) {\n" + else: + ret += get_offset_expr(typ, go_to_end).gen_c( + "uint32_t", "needed_size", "val->", 1, 0 + ) + ret += "\tif (needed_size > ctx->ctx->max_msg_size) {\n" + if isinstance(typ, idl.Message): # SPECIAL (disable for stat) + ret += f'\t\tlib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)",\n' + ret += f'\t\t\t"{typ.name}",\n' + ret += f'\t\t\tctx->ctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n' + ret += "\t\t\tctx->ctx->max_msg_size);\n" + ret += "\t\treturn true;\n" + ret += "\t}\n" + + # Pass 2 - write data + ifdef_depth = 1 + stack: list[tuple[Path, bool]] = [(Path(typ), False)] + + def handle(path: Path) -> tuple[WalkCmd, typing.Callable[[], None]]: + nonlocal ret + nonlocal ifdef_depth + nonlocal stack + stack_len = len(stack) + + def pop() -> None: + nonlocal ret + nonlocal ifdef_depth + nonlocal stack + nonlocal stack_len + while len(stack) > stack_len: + ret += f"{'\t'*(len(stack)-1)}}}\n" + if stack[-1][1]: + ifdef_depth -= 1 + ret += ifdef_pop(ifdef_depth) + stack = stack[:-1] + + loopdepth = sum(1 for elem in path.elems if elem.cnt) + struct = path.elems[-1].typ if path.elems else path.root + if isinstance(struct, idl.Struct): + offsets: list[str] = [] + for member in struct.members: + if not member.val: + continue + for tok in member.val.tokens: + if not isinstance(tok, idl.ExprSym): + continue + if tok.name == "end" or tok.name.startswith("&"): + if tok.name not in offsets: + offsets.append(tok.name) + for name in offsets: + name_prefix = "offsetof_" + "".join( + m.name + "_" for m in path.elems + ) + if name == "end": + if not path.elems: + nonlocal max_size + if max_size > u32max: + ret += f"{'\t'*len(stack)}uint32_t {name_prefix}end = (uint32_t)needed_size;\n" + else: + ret += f"{'\t'*len(stack)}uint32_t {name_prefix}end = needed_size;\n" + continue + recurse: OffsetExprRecursion = go_to_end else: - ret += f"marshal_{member.typ.name}(ctx, &val->{member.name})" - if member.name in mark_offset: - ret += "; })" - if member.in_versions != typ.in_versions: - ret += " )" - ret += "\n" - - # Pass 3 - marshal ,val= members - for member in typ.members: - if member.val: - assert member.static_size - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) + assert name.startswith("&") + name = name[1:] + recurse = go_to_tok(name) + expr = get_offset_expr(struct, recurse) + expr_prefix = path.c_str("val->", loopdepth) + if not expr_prefix.endswith(">"): + expr_prefix += "." + ret += expr.gen_c( + "uint32_t", + name_prefix + name, + expr_prefix, + len(stack), + loopdepth, + ) + if path.elems: + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + if child.in_versions < parent.in_versions: + ret += ifdef_push(ifdef_depth + 1, c_ver_ifdef(child.in_versions)) + ifdef_depth += 1 + ret += f"{'\t'*len(stack)}if ({c_ver_cond(child.in_versions)}) {{\n" + stack.append((path, True)) + if child.cnt: + cnt_path = path.parent().add(child.cnt) + if child.typ.static_size == 1: # SPECIAL (zerocopy) + if path.root.name == "stat": # SPECIAL (stat) + ret += f"{'\t'*len(stack)}MARSHAL_BYTES(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n" + else: + ret += f"{'\t'*len(stack)}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n" + return WalkCmd.KEEP_GOING, pop + loopvar = chr(ord("i") + loopdepth - 1) + ret += f"{'\t'*len(stack)}for ({c_typename(child.cnt.typ)} {loopvar} = 0; {loopvar} < {cnt_path.c_str('val->')}; {loopvar}++) {{\n" + stack.append((path, False)) + if not isinstance(child.typ, idl.Struct): + if child.val: def lookup_sym(sym: str) -> str: - match sym: - case "end": - return "ctx->net_offset" - case _: - assert sym.startswith("&") - return f"_{sym[1:]}_offset" - - if member.static_size == 1: - ret += f"\t || ({{ ctx->net_bytes[_{member.name}_offset] = {c_expr(member.val, lookup_sym)}; false; }})\n" - else: - ret += f"\t || ({{ uint{member.static_size*8}le_encode(&ctx->net_bytes[_{member.name}_offset], {c_expr(member.val, lookup_sym)}); false; }})\n" + nonlocal path + if sym.startswith("&"): + sym = sym[1:] + return ( + "offsetof_" + + "".join(m.name + "_" for m in path.elems[:-1]) + + sym + ) + + val = c_expr(child.val, lookup_sym) + else: + val = path.c_str("val->") + if isinstance(child.typ, idl.Bitfield): + val += f" & {child.typ.name}_masks[ctx->ctx->version]" + ret += f"{'\t'*len(stack)}MARSHAL_U{child.typ.static_size*8}LE(ctx, {val});\n" + return WalkCmd.KEEP_GOING, pop - ret += ifdef_pop(1) - ret += "\t ;\n" + walk(typ, handle) + + ret += "\treturn false;\n" ret += "}\n" ret += ifdef_pop(0) # function tables ########################################################## ret += """ /* function tables ************************************************************/ - """ + + ret += "\n" + ret += f"const uint32_t _{idprefix}table_msg_min_size[{c_ver_enum('NUM')}] = {{\n" + rerror = next(typ for typ in typs if typ.name == "Rerror") + ret += f"\t[{c_ver_enum('unknown')}] = {rerror.min_size('9P2000')},\n" # SPECIAL (initialization) + for ver in sorted(versions): + ret += ifdef_push(1, c_ver_ifdef({ver})) + ret += f"\t[{c_ver_enum(ver)}] = {rerror.min_size(ver)},\n" + ret += ifdef_pop(0) + ret += "};\n" + + ret += "\n" ret += c_macro( f"#define _MSG_RECV(typ) [{idprefix.upper()}TYP_##typ/2] = {{\n" f"\t\t.basesize = sizeof(struct {idprefix}msg_##typ),\n" diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h index a5b719e..d34a0f6 100644 --- a/lib9p/include/lib9p/9p.generated.h +++ b/lib9p/include/lib9p/9p.generated.h @@ -6,6 +6,8 @@ #include <stdint.h> /* for uint{n}_t types */ +#include <libhw/generic/net.h> /* for struct iovec */ + /* config *********************************************************************/ #include "config.h" @@ -20,6 +22,13 @@ #ifndef CONFIG_9P_ENABLE_9P2000_e #error config.h must define CONFIG_9P_ENABLE_9P2000_e +#else + #if CONFIG_9P_ENABLE_9P2000_e + #ifndef(CONFIG_9P_MAX_9P2000_e_WELEM) + #error if CONFIG_9P_ENABLE_9P2000_e then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM + #endif + static_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0); + #endif #endif #ifndef CONFIG_9P_ENABLE_9P2000_p9p @@ -148,15 +157,15 @@ 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 */ +/* size = 2 ; max_iov = 1 ; max_copy = 2 */ typedef uint16_t lib9p_tag_t; #define LIB9P_TAG_NOTAG ((lib9p_tag_t)UINT16_C(~0)) -/* size = 4 */ +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_fid_t; #define LIB9P_FID_NOFID ((lib9p_fid_t)UINT32_C(~0)) -/* min_size = 2 ; max_size = 65,537 */ +/* min_size = 2 ; exp_size = 29 ; max_size = 65,537 ; max_iov = 2 ; max_copy = 2 */ struct lib9p_s { uint16_t len; [[gnu::nonstring]] char *utf8; @@ -164,7 +173,7 @@ struct lib9p_s { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 4 */ +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_dm_t; #define LIB9P_DM_DIR ((lib9p_dm_t)(1<<31)) @@ -208,7 +217,7 @@ typedef uint32_t lib9p_dm_t; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #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 = 1 */ +/* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_qt_t; #define LIB9P_QT_DIR ((lib9p_qt_t)(1<<7)) @@ -226,13 +235,13 @@ typedef uint8_t lib9p_qt_t; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u -/* size = 4 */ +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_nuid_t; #define LIB9P_NUID_NONUID ((lib9p_nuid_t)UINT32_C(~0)) #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 1 */ +/* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_o_t; /* unused ((lib9p_o_t)(1<<7)) */ @@ -253,7 +262,7 @@ typedef uint8_t lib9p_o_t; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* size = 8 */ +/* size = 8 ; max_iov = 1 ; max_copy = 8 */ typedef uint64_t lib9p_getattr_t; /* unused ((lib9p_getattr_t)(1<<63)) */ @@ -324,7 +333,7 @@ typedef uint64_t lib9p_getattr_t; #define LIB9P_GETATTR_BASIC ((lib9p_getattr_t)(0x000007ff)) #define LIB9P_GETATTR_ALL ((lib9p_getattr_t)(0x00003fff)) -/* size = 4 */ +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_setattr_t; /* unused ((lib9p_setattr_t)(1<<31)) */ @@ -360,13 +369,13 @@ typedef uint32_t lib9p_setattr_t; #define LIB9P_SETATTR_UID ((lib9p_setattr_t)(1<<1)) #define LIB9P_SETATTR_MODE ((lib9p_setattr_t)(1<<0)) -/* size = 1 */ +/* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_lock_type_t; #define LIB9P_LOCK_TYPE_RDLCK ((lib9p_lock_type_t)UINT8_C(0)) #define LIB9P_LOCK_TYPE_WRLCK ((lib9p_lock_type_t)UINT8_C(1)) #define LIB9P_LOCK_TYPE_UNLCK ((lib9p_lock_type_t)UINT8_C(2)) -/* size = 4 */ +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_lock_flags_t; /* unused ((lib9p_lock_flags_t)(1<<31)) */ @@ -402,7 +411,7 @@ typedef uint32_t lib9p_lock_flags_t; #define LIB9P_LOCK_FLAGS_RECLAIM ((lib9p_lock_flags_t)(1<<1)) #define LIB9P_LOCK_FLAGS_BLOCK ((lib9p_lock_flags_t)(1<<0)) -/* size = 1 */ +/* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_lock_status_t; #define LIB9P_LOCK_STATUS_SUCCESS ((lib9p_lock_status_t)UINT8_C(0)) #define LIB9P_LOCK_STATUS_BLOCKED ((lib9p_lock_status_t)UINT8_C(1)) @@ -411,56 +420,56 @@ typedef uint8_t lib9p_lock_status_t; #endif /* CONFIG_9P_ENABLE_9P2000_L */ #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 = 9 */ +/* size = 9 ; max_iov = 1 ; max_copy = 9 */ struct lib9p_msg_Tflush { lib9p_tag_t tag; uint16_t oldtag; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rflush { lib9p_tag_t tag; }; -/* min_size = 11 ; max_size = 2,147,483,658 */ +/* 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; }; -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Rwrite { lib9p_tag_t tag; uint32_t count; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rclunk { lib9p_tag_t tag; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rremove { lib9p_tag_t tag; }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rwstat { lib9p_tag_t tag; }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Rlerror { lib9p_tag_t tag; uint32_t ecode; }; -/* size = 67 */ +/* size = 67 ; max_iov = 1 ; max_copy = 67 */ struct lib9p_msg_Rstatfs { lib9p_tag_t tag; uint32_t type; @@ -474,75 +483,75 @@ struct lib9p_msg_Rstatfs { uint32_t namelen; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rrename { lib9p_tag_t tag; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rsetattr { lib9p_tag_t tag; }; -/* size = 15 */ +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ struct lib9p_msg_Rxattrwalk { lib9p_tag_t tag; uint64_t attr_size; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rxattrcreate { lib9p_tag_t tag; }; -/* min_size = 11 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) */ +/* 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; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rfsync { lib9p_tag_t tag; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rlink { lib9p_tag_t tag; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rrenameat { lib9p_tag_t tag; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Runlinkat { lib9p_tag_t tag; }; #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000_e -/* size = 15 */ +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ struct lib9p_msg_Tsession { lib9p_tag_t tag; uint64_t key; }; -/* size = 7 */ +/* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rsession { lib9p_tag_t tag; }; -/* min_size = 11 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) */ +/* 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; }; -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Rswrite { lib9p_tag_t tag; uint32_t count; @@ -550,7 +559,7 @@ struct lib9p_msg_Rswrite { #endif /* CONFIG_9P_ENABLE_9P2000_e */ #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 = 23 */ +/* size = 23 ; max_iov = 1 ; max_copy = 23 */ struct lib9p_msg_Tread { lib9p_tag_t tag; lib9p_fid_t fid; @@ -558,7 +567,7 @@ struct lib9p_msg_Tread { uint32_t count; }; -/* min_size = 23 ; max_size = 2,147,483,670 */ +/* 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; @@ -567,13 +576,13 @@ struct lib9p_msg_Twrite { [[gnu::nonstring]] char *data; }; -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Tclunk { lib9p_tag_t tag; lib9p_fid_t fid; }; -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Tremove { lib9p_tag_t tag; lib9p_fid_t fid; @@ -581,7 +590,7 @@ struct lib9p_msg_Tremove { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Tstat { lib9p_tag_t tag; lib9p_fid_t fid; @@ -589,26 +598,26 @@ struct lib9p_msg_Tstat { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Tstatfs { lib9p_tag_t tag; lib9p_fid_t fid; }; -/* size = 15 */ +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ struct lib9p_msg_Tlopen { lib9p_tag_t tag; lib9p_fid_t fid; uint32_t flags; }; -/* size = 11 */ +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Treadlink { lib9p_tag_t tag; lib9p_fid_t fid; }; -/* size = 23 */ +/* size = 23 ; max_iov = 1 ; max_copy = 23 */ struct lib9p_msg_Treaddir { lib9p_tag_t tag; lib9p_fid_t fid; @@ -616,7 +625,7 @@ struct lib9p_msg_Treaddir { uint32_t count; }; -/* size = 15 */ +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ struct lib9p_msg_Tfsync { lib9p_tag_t tag; lib9p_fid_t fid; @@ -625,25 +634,25 @@ struct lib9p_msg_Tfsync { #endif /* CONFIG_9P_ENABLE_9P2000_L */ #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 -/* min_size = 13 ; max_size = 65,548 */ +/* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */ struct lib9p_msg_Tversion { lib9p_tag_t tag; uint32_t max_msg_size; struct lib9p_s version; }; -/* min_size = 13 ; max_size = 65,548 */ +/* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */ struct lib9p_msg_Rversion { lib9p_tag_t tag; uint32_t max_msg_size; struct lib9p_s version; }; -/* LIB9P_VER_9P2000 : min_size = 9 ; max_size = 65,544 */ -/* LIB9P_VER_9P2000_L : min_size = 9 ; max_size = 65,544 */ -/* LIB9P_VER_9P2000_e : min_size = 9 ; max_size = 65,544 */ -/* LIB9P_VER_9P2000_p9p: min_size = 9 ; max_size = 65,544 */ -/* LIB9P_VER_9P2000_u : min_size = 13 ; max_size = 65,548 */ +/* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_L : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_p9p: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */ struct lib9p_msg_Rerror { lib9p_tag_t tag; struct lib9p_s ename; @@ -652,7 +661,7 @@ struct lib9p_msg_Rerror { #endif /* CONFIG_9P_ENABLE_9P2000_u */ }; -/* min_size = 17 ; max_size = 1,048,609 */ +/* min_size = 17 ; exp_size = 481 ; max_size = 1,048,609 ; max_iov = 32 ; max_copy = 49 */ struct lib9p_msg_Twalk { lib9p_tag_t tag; lib9p_fid_t fid; @@ -663,7 +672,7 @@ struct lib9p_msg_Twalk { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* min_size = 17 ; max_size = 65,552 */ +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ struct lib9p_msg_Trename { lib9p_tag_t tag; lib9p_fid_t fid; @@ -671,13 +680,13 @@ struct lib9p_msg_Trename { struct lib9p_s name; }; -/* min_size = 9 ; max_size = 65,544 */ +/* min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ struct lib9p_msg_Rreadlink { lib9p_tag_t tag; struct lib9p_s target; }; -/* min_size = 17 ; max_size = 65,552 */ +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ struct lib9p_msg_Txattrwalk { lib9p_tag_t tag; lib9p_fid_t fid; @@ -685,7 +694,7 @@ struct lib9p_msg_Txattrwalk { struct lib9p_s name; }; -/* min_size = 25 ; max_size = 65,560 */ +/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ struct lib9p_msg_Txattrcreate { lib9p_tag_t tag; lib9p_fid_t fid; @@ -694,7 +703,7 @@ struct lib9p_msg_Txattrcreate { uint32_t flags; }; -/* min_size = 34 ; max_size = 65,569 */ +/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */ struct lib9p_msg_Tgetlock { lib9p_tag_t tag; lib9p_fid_t fid; @@ -705,7 +714,7 @@ struct lib9p_msg_Tgetlock { struct lib9p_s client_id; }; -/* min_size = 30 ; max_size = 65,565 */ +/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */ struct lib9p_msg_Rgetlock { lib9p_tag_t tag; uint8_t type; @@ -715,7 +724,7 @@ struct lib9p_msg_Rgetlock { struct lib9p_s client_id; }; -/* min_size = 17 ; max_size = 65,552 */ +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ struct lib9p_msg_Tlink { lib9p_tag_t tag; lib9p_fid_t dfid; @@ -723,7 +732,7 @@ struct lib9p_msg_Tlink { struct lib9p_s name; }; -/* min_size = 19 ; max_size = 131,089 */ +/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ struct lib9p_msg_Trenameat { lib9p_tag_t tag; lib9p_fid_t olddirfid; @@ -732,7 +741,7 @@ struct lib9p_msg_Trenameat { struct lib9p_s newname; }; -/* min_size = 17 ; max_size = 65,552 */ +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 3 ; max_copy = 17 */ struct lib9p_msg_Tunlinkat { lib9p_tag_t tag; lib9p_fid_t dirfd; @@ -742,7 +751,7 @@ struct lib9p_msg_Tunlinkat { #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000_e -/* min_size = 13 ; max_size = 4,294,967,308 (warning: >UINT32_MAX) */ +/* min_size = 13 ; exp_size = 477 ; max_size = 4,294,967,308 (warning: >UINT32_MAX) ; max_iov = 0 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 13 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */ struct lib9p_msg_Tsread { lib9p_tag_t tag; uint32_t fid; @@ -750,7 +759,7 @@ struct lib9p_msg_Tsread { struct lib9p_s *wname; }; -/* min_size = 17 ; max_size = 8,589,934,607 (warning: >UINT32_MAX) */ +/* 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; @@ -762,18 +771,18 @@ struct lib9p_msg_Tswrite { #endif /* CONFIG_9P_ENABLE_9P2000_e */ #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 = 13 */ +/* size = 13 ; max_iov = 1 ; max_copy = 13 */ struct lib9p_qid { lib9p_qt_t type; uint32_t vers; uint64_t path; }; -/* LIB9P_VER_9P2000 : min_size = 15 ; max_size = 131,085 */ -/* LIB9P_VER_9P2000_L : min_size = 19 ; max_size = 131,089 */ -/* LIB9P_VER_9P2000_e : min_size = 15 ; max_size = 131,085 */ -/* LIB9P_VER_9P2000_p9p: min_size = 15 ; max_size = 131,085 */ -/* LIB9P_VER_9P2000_u : min_size = 19 ; max_size = 131,089 */ +/* LIB9P_VER_9P2000 : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */ +/* LIB9P_VER_9P2000_L : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ +/* LIB9P_VER_9P2000_e : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */ +/* LIB9P_VER_9P2000_p9p: min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */ +/* LIB9P_VER_9P2000_u : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ struct lib9p_msg_Tauth { lib9p_tag_t tag; lib9p_fid_t afid; @@ -784,11 +793,11 @@ struct lib9p_msg_Tauth { #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ }; -/* LIB9P_VER_9P2000 : min_size = 19 ; max_size = 131,089 */ -/* LIB9P_VER_9P2000_L : min_size = 23 ; max_size = 131,093 */ -/* LIB9P_VER_9P2000_e : min_size = 19 ; max_size = 131,089 */ -/* LIB9P_VER_9P2000_p9p: min_size = 19 ; max_size = 131,089 */ -/* LIB9P_VER_9P2000_u : min_size = 23 ; max_size = 131,093 */ +/* LIB9P_VER_9P2000 : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ +/* LIB9P_VER_9P2000_L : min_size = 23 ; exp_size = 77 ; max_size = 131,093 ; max_iov = 5 ; max_copy = 23 */ +/* LIB9P_VER_9P2000_e : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ +/* LIB9P_VER_9P2000_p9p: min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ +/* LIB9P_VER_9P2000_u : min_size = 23 ; exp_size = 77 ; max_size = 131,093 ; max_iov = 5 ; max_copy = 23 */ struct lib9p_msg_Tattach { lib9p_tag_t tag; lib9p_fid_t fid; @@ -802,7 +811,7 @@ struct lib9p_msg_Tattach { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* min_size = 25 ; max_size = 65,560 */ +/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ struct lib9p_msg_Tlcreate { lib9p_tag_t tag; lib9p_fid_t fid; @@ -812,7 +821,7 @@ struct lib9p_msg_Tlcreate { lib9p_nuid_t gid; }; -/* min_size = 19 ; max_size = 131,089 */ +/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ struct lib9p_msg_Tsymlink { lib9p_tag_t tag; lib9p_fid_t fid; @@ -821,7 +830,7 @@ struct lib9p_msg_Tsymlink { lib9p_nuid_t gid; }; -/* min_size = 29 ; max_size = 65,564 */ +/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */ struct lib9p_msg_Tmknod { lib9p_tag_t tag; lib9p_fid_t dfid; @@ -832,7 +841,7 @@ struct lib9p_msg_Tmknod { lib9p_nuid_t gid; }; -/* min_size = 21 ; max_size = 65,556 */ +/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */ struct lib9p_msg_Tmkdir { lib9p_tag_t tag; lib9p_fid_t dfid; @@ -843,14 +852,14 @@ struct lib9p_msg_Tmkdir { #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 12 */ +/* size = 12 ; max_iov = 1 ; max_copy = 12 */ struct lib9p_msg_Topen { lib9p_tag_t tag; lib9p_fid_t fid; lib9p_o_t mode; }; -/* min_size = 18 ; max_size = 65,553 */ +/* min_size = 18 ; exp_size = 45 ; max_size = 65,553 ; max_iov = 3 ; max_copy = 18 */ struct lib9p_msg_Tcreate { lib9p_tag_t tag; lib9p_fid_t fid; @@ -861,7 +870,7 @@ struct lib9p_msg_Tcreate { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_p9p -/* size = 12 */ +/* size = 12 ; max_iov = 1 ; max_copy = 12 */ struct lib9p_msg_Topenfd { lib9p_tag_t tag; lib9p_fid_t fid; @@ -870,14 +879,14 @@ struct lib9p_msg_Topenfd { #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L -/* size = 19 */ +/* size = 19 ; max_iov = 1 ; max_copy = 19 */ struct lib9p_msg_Tgetattr { lib9p_tag_t tag; lib9p_fid_t fid; lib9p_getattr_t request_mask; }; -/* size = 67 */ +/* size = 67 ; max_iov = 1 ; max_copy = 67 */ struct lib9p_msg_Tsetattr { lib9p_tag_t tag; lib9p_fid_t fid; @@ -892,7 +901,7 @@ struct lib9p_msg_Tsetattr { uint64_t mtime_nsec; }; -/* min_size = 38 ; max_size = 65,573 */ +/* min_size = 38 ; exp_size = 65 ; max_size = 65,573 ; max_iov = 2 ; max_copy = 38 */ struct lib9p_msg_Tlock { lib9p_tag_t tag; lib9p_fid_t fid; @@ -904,7 +913,7 @@ struct lib9p_msg_Tlock { struct lib9p_s client_id; }; -/* size = 8 */ +/* size = 8 ; max_iov = 1 ; max_copy = 8 */ struct lib9p_msg_Rlock { lib9p_tag_t tag; lib9p_lock_status_t status; @@ -912,10 +921,10 @@ struct lib9p_msg_Rlock { #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* LIB9P_VER_9P2000 : min_size = 49 ; max_size = 262,189 */ -/* LIB9P_VER_9P2000_e : min_size = 49 ; max_size = 262,189 */ -/* LIB9P_VER_9P2000_p9p: min_size = 49 ; max_size = 262,189 */ -/* LIB9P_VER_9P2000_u : min_size = 63 ; max_size = 327,738 */ +/* LIB9P_VER_9P2000 : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ +/* LIB9P_VER_9P2000_e : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ +/* LIB9P_VER_9P2000_p9p: min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ +/* LIB9P_VER_9P2000_u : min_size = 63 ; exp_size = 198 ; max_size = 327,738 ; max_iov = 11 ; max_copy = 63 */ struct lib9p_stat { uint16_t kern_type; uint32_t kern_dev; @@ -938,19 +947,19 @@ struct lib9p_stat { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #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 = 20 */ +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rauth { lib9p_tag_t tag; struct lib9p_qid aqid; }; -/* size = 20 */ +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rattach { lib9p_tag_t tag; struct lib9p_qid qid; }; -/* min_size = 9 ; max_size = 217 */ +/* min_size = 9 ; exp_size = 217 ; max_size = 217 ; max_iov = 1 ; max_copy = 217 */ struct lib9p_msg_Rwalk { lib9p_tag_t tag; uint16_t nwqid; @@ -959,14 +968,14 @@ struct lib9p_msg_Rwalk { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 24 */ +/* size = 24 ; max_iov = 1 ; max_copy = 24 */ struct lib9p_msg_Ropen { lib9p_tag_t tag; struct lib9p_qid qid; uint32_t iounit; }; -/* size = 24 */ +/* size = 24 ; max_iov = 1 ; max_copy = 24 */ struct lib9p_msg_Rcreate { lib9p_tag_t tag; struct lib9p_qid qid; @@ -975,7 +984,7 @@ struct lib9p_msg_Rcreate { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_p9p -/* size = 28 */ +/* size = 28 ; max_iov = 1 ; max_copy = 28 */ struct lib9p_msg_Ropenfd { lib9p_tag_t tag; struct lib9p_qid qid; @@ -985,33 +994,33 @@ struct lib9p_msg_Ropenfd { #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L -/* size = 24 */ +/* size = 24 ; max_iov = 1 ; max_copy = 24 */ struct lib9p_msg_Rlopen { lib9p_tag_t tag; struct lib9p_qid qid; uint32_t iounit; }; -/* size = 24 */ +/* size = 24 ; max_iov = 1 ; max_copy = 24 */ struct lib9p_msg_Rlcreate { lib9p_tag_t tag; struct lib9p_qid qid; uint32_t iounit; }; -/* size = 20 */ +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rsymlink { lib9p_tag_t tag; struct lib9p_qid qid; }; -/* size = 20 */ +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rmknod { lib9p_tag_t tag; struct lib9p_qid qid; }; -/* size = 160 */ +/* size = 160 ; max_iov = 1 ; max_copy = 160 */ struct lib9p_msg_Rgetattr { lib9p_tag_t tag; uint64_t valid; @@ -1036,7 +1045,7 @@ struct lib9p_msg_Rgetattr { uint64_t data_version; }; -/* size = 20 */ +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rmkdir { lib9p_tag_t tag; struct lib9p_qid qid; @@ -1044,22 +1053,78 @@ struct lib9p_msg_Rmkdir { #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* LIB9P_VER_9P2000 : min_size = 58 ; max_size = 262,198 */ -/* LIB9P_VER_9P2000_e : min_size = 58 ; max_size = 262,198 */ -/* LIB9P_VER_9P2000_p9p: min_size = 58 ; max_size = 262,198 */ -/* LIB9P_VER_9P2000_u : min_size = 72 ; max_size = 327,747 */ +/* LIB9P_VER_9P2000 : min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */ +/* LIB9P_VER_9P2000_e : min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */ +/* LIB9P_VER_9P2000_p9p: min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */ +/* LIB9P_VER_9P2000_u : min_size = 72 ; exp_size = 207 ; max_size = 327,747 ; max_iov = 11 ; max_copy = 72 */ struct lib9p_msg_Rstat { lib9p_tag_t tag; struct lib9p_stat stat; }; -/* LIB9P_VER_9P2000 : min_size = 62 ; max_size = 262,202 */ -/* LIB9P_VER_9P2000_e : min_size = 62 ; max_size = 262,202 */ -/* LIB9P_VER_9P2000_p9p: min_size = 62 ; max_size = 262,202 */ -/* LIB9P_VER_9P2000_u : min_size = 76 ; max_size = 327,751 */ +/* LIB9P_VER_9P2000 : min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */ +/* LIB9P_VER_9P2000_e : min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */ +/* LIB9P_VER_9P2000_p9p: min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */ +/* LIB9P_VER_9P2000_u : min_size = 76 ; exp_size = 211 ; max_size = 327,751 ; max_iov = 11 ; max_copy = 76 */ struct lib9p_msg_Twstat { lib9p_tag_t tag; lib9p_fid_t fid; struct lib9p_stat stat; }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ + +/* containers *****************************************************************/ + +#define _LIB9P_MAX(a, b) ((a) > (b)) ? (a) : (b) + +#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 + #if CONFIG_9P_ENABLE_9P2000_e + #define LIB9P_TMSG_MAX_IOV _LIB9P_MAX(32, 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2)) + #else + #define LIB9P_TMSG_MAX_IOV 32 + #endif +#endif + +#if CONFIG_9P_ENABLE_9P2000_u + #if CONFIG_9P_ENABLE_9P2000_e + #define LIB9P_TMSG_MAX_COPY _LIB9P_MAX(76, 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2)) + #else + #define LIB9P_TMSG_MAX_COPY 76 + #endif +#elif CONFIG_9P_ENABLE_9P2000_L + #if CONFIG_9P_ENABLE_9P2000_e + #define LIB9P_TMSG_MAX_COPY _LIB9P_MAX(67, 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2)) + #else + #define LIB9P_TMSG_MAX_COPY 67 + #endif +#elif CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p + #if CONFIG_9P_ENABLE_9P2000_e + #define LIB9P_TMSG_MAX_COPY _LIB9P_MAX(62, 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2)) + #else + #define LIB9P_TMSG_MAX_COPY 62 + #endif +#endif + +#if CONFIG_9P_ENABLE_9P2000_u + #define LIB9P_RMSG_MAX_IOV 11 +#elif CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p + #define LIB9P_RMSG_MAX_IOV 8 +#elif CONFIG_9P_ENABLE_9P2000_L + #define LIB9P_RMSG_MAX_IOV 2 +#endif + +#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 + #define LIB9P_RMSG_MAX_COPY 217 +#endif + +struct lib9p_Tmsg_send_buf { + size_t iov_cnt; + struct iovec iov[LIB9P_TMSG_MAX_IOV]; + uint8_t copied[LIB9P_TMSG_MAX_COPY]; +}; + +struct lib9p_Rmsg_send_buf { + size_t iov_cnt; + struct iovec iov[LIB9P_RMSG_MAX_IOV]; + uint8_t copied[LIB9P_RMSG_MAX_COPY]; +}; diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h index d4764a2..68e007f 100644 --- a/lib9p/include/lib9p/9p.h +++ b/lib9p/include/lib9p/9p.h @@ -118,7 +118,7 @@ void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, * @errno LINUX_ERANGE: reply does not fit in ctx->max_msg_size */ bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - uint8_t *ret_bytes); + struct lib9p_Tmsg_send_buf *ret); /* main R-message functions ***************************************************/ @@ -128,7 +128,7 @@ ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes); void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, enum lib9p_msg_type *ret_typ, void *ret_body); bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - uint8_t *ret_bytes); + struct lib9p_Rmsg_send_buf *ret); /* `struct lib9p_stat` helpers ************************************************/ diff --git a/lib9p/internal.h b/lib9p/internal.h index a648532..d27348e 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -69,8 +69,10 @@ struct _marshal_ctx { struct lib9p_ctx *ctx; /* output */ - uint8_t *net_bytes; - uint32_t net_offset; + size_t net_iov_cnt; + struct iovec *net_iov; + size_t net_copied_size; + uint8_t *net_copied; }; typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val); @@ -88,6 +90,7 @@ struct _lib9p_send_tentry { extern const char * _lib9p_table_ver_name[LIB9P_VER_NUM]; extern const char * _lib9p_table_msg_name[LIB9P_VER_NUM][0x100]; +extern const uint32_t _lib9p_table_msg_min_size[LIB9P_VER_NUM]; extern const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80]; extern const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80]; extern const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80]; diff --git a/lib9p/srv.c b/lib9p/srv.c index 9837994..c624fa8 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -131,8 +131,8 @@ struct _lib9p_srv_req { /* immutable */ struct _srv_sess *parent_sess; uint16_t tag; + uint8_t *net_bytes; /* mutable */ - uint8_t *net_bytes; /* CONFIG_9P_MAX_MSG_SIZE-sized */ struct lib9p_srv_ctx ctx; }; @@ -140,31 +140,18 @@ struct _lib9p_srv_req { #define nonrespond_errorf errorf -static uint32_t rerror_overhead_for_version(enum lib9p_version version, - uint8_t *scratch) { - struct lib9p_ctx empty_ctx = { - .version = version, - .max_msg_size = CONFIG_9P_MAX_MSG_SIZE, - }; - struct lib9p_msg_Rerror empty_error = { 0 }; - bool e; - - e = lib9p_Rmsg_marshal(&empty_ctx, LIB9P_TYP_Rerror, - &empty_error, /* host_body */ - scratch); /* net_bytes */ - assert(!e); - - uint32_t min_msg_size = uint32le_decode(scratch); - - /* Assert that min_msg_size + biggest_possible_MAX_ERR_SIZE - * won't overflow uint32... because using - * __builtin_add_overflow in respond_error() would be a bit - * much. */ - assert(min_msg_size < (UINT32_MAX - UINT16_MAX)); - /* Assert that min_msg_size doesn't overflow MAX_MSG_SIZE. */ - assert(CONFIG_9P_MAX_MSG_SIZE >= min_msg_size); - - return min_msg_size; +static ssize_t write_Rmsg(struct _lib9p_srv_req *req, struct lib9p_Rmsg_send_buf *resp) { + ssize_t r = 0, _r; + cr_mutex_lock(&req->parent_sess->parent_conn->writelock); + for (size_t i = 0; i < resp->iov_cnt; i++) { + _r = LO_CALL(req->parent_sess->parent_conn->fd, write, + resp->iov[i].iov_base, resp->iov[i].iov_len); + if (_r < 0) + return _r; + r += _r; + } + cr_mutex_unlock(&req->parent_sess->parent_conn->writelock); + return r; } static void respond_error(struct _lib9p_srv_req *req) { @@ -186,19 +173,17 @@ static void respond_error(struct _lib9p_srv_req *req) { struct _srv_sess *sess = req->parent_sess; /* Truncate the error-string if necessary to avoid needing to - * return LINUX_ERANGE. The assert() in - * rerror_overhead_for_version() has checked that this - * addition doesn't overflow. */ + * return LINUX_ERANGE. */ if (((uint32_t)host.ename.len) + sess->rerror_overhead > sess->max_msg_size) host.ename.len = sess->max_msg_size - sess->rerror_overhead; - lib9p_Rmsg_marshal(&req->ctx.basectx, LIB9P_TYP_Rerror, - &host, req->net_bytes); + struct lib9p_Rmsg_send_buf net; + + lib9p_Rmsg_marshal(&req->ctx.basectx, + LIB9P_TYP_Rerror, &host, + &net); - cr_mutex_lock(&sess->parent_conn->writelock); - r = LO_CALL(sess->parent_conn->fd, write, - req->net_bytes, uint32le_decode(req->net_bytes)); - cr_mutex_unlock(&sess->parent_conn->writelock); + r = write_Rmsg(req, &net); if (r < 0) nonrespond_errorf("write: %s", net_strerror(-r)); } @@ -227,15 +212,13 @@ static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t g static void handle_message(struct _lib9p_srv_req *ctx); [[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener) { - uint8_t buf[CONFIG_9P_MAX_MSG_SIZE]; - assert(srv); assert(srv->rootdir); assert(!LO_IS_NULL(listener)); srv->readers++; - uint32_t initial_rerror_overhead = rerror_overhead_for_version(0, buf); + uint32_t initial_rerror_overhead = _lib9p_table_msg_min_size[LIB9P_VER_unknown]; for (;;) { struct _srv_conn conn = { @@ -263,6 +246,7 @@ static void handle_message(struct _lib9p_srv_req *ctx); nextmsg: /* Read the message. */ size_t done = 0; + uint8_t buf[7]; if (read_exactly(conn.fd, buf, 4, &done)) goto close; size_t goal = uint32le_decode(buf); @@ -292,11 +276,16 @@ static void handle_message(struct _lib9p_srv_req *ctx); respond_error(&req); goto nextmsg; } - if (read_exactly(conn.fd, buf, goal, &done)) + req.net_bytes = malloc(goal); + assert(req.net_bytes); + memcpy(req.net_bytes, buf, done); + if (read_exactly(conn.fd, req.net_bytes, goal, &done)) { + free(req.net_bytes); goto close; + } /* Handle the message... */ - if (buf[4] == LIB9P_TYP_Tversion) + if (req.net_bytes[4] == LIB9P_TYP_Tversion) /* ...in this coroutine for Tversion, */ handle_message(&req); else @@ -317,7 +306,6 @@ static void handle_message(struct _lib9p_srv_req *ctx); /* write coroutine ************************************************************/ COROUTINE lib9p_srv_write_cr(void *_srv) { - uint8_t net[CONFIG_9P_MAX_MSG_SIZE]; struct _lib9p_srv_req req; _lib9p_srv_reqch_req_t rpc_handle; @@ -336,11 +324,9 @@ COROUTINE lib9p_srv_write_cr(void *_srv) { _lib9p_srv_reqch_send_resp(rpc_handle, 0); cr_exit(); } - /* Deep-copy the request from the reader coroutine's + /* Copy the request from the reader coroutine's * stack to our stack. */ req = *rpc_handle.req; - memcpy(net, req.net_bytes, uint32le_decode(req.net_bytes)); - req.net_bytes = net; /* Record that we have it. */ reqmap_store(&req.parent_sess->reqs, req.tag, &req); /* Notify the reader coroutine that we're done with @@ -408,19 +394,15 @@ static tmessage_handler tmessage_handlers[0x100] = { }; static void handle_message(struct _lib9p_srv_req *ctx) { - uint8_t host_req[CONFIG_9P_MAX_HOSTMSG_SIZE]; + uint8_t *host_req = NULL; uint8_t host_resp[CONFIG_9P_MAX_HOSTMSG_SIZE]; /* Unmarshal it. */ ssize_t host_size = lib9p_Tmsg_validate(&ctx->ctx.basectx, ctx->net_bytes); if (host_size < 0) goto write; - if ((size_t)host_size > sizeof(host_req)) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)", - host_size, sizeof(host_req)); - goto write; - } + host_req = malloc(host_size); + assert(host_req); enum lib9p_msg_type typ; lib9p_Tmsg_unmarshal(&ctx->ctx.basectx, ctx->net_bytes, &typ, host_req); @@ -432,15 +414,16 @@ static void handle_message(struct _lib9p_srv_req *ctx) { if (lib9p_ctx_has_error(&ctx->ctx.basectx)) respond_error(ctx); else { - if (lib9p_Rmsg_marshal(&ctx->ctx.basectx, typ+1, host_resp, - ctx->net_bytes)) + struct lib9p_Rmsg_send_buf net_resp; + if (lib9p_Rmsg_marshal(&ctx->ctx.basectx, + typ+1, host_resp, + &net_resp)) goto write; - - cr_mutex_lock(&ctx->parent_sess->parent_conn->writelock); - LO_CALL(ctx->parent_sess->parent_conn->fd, write, - ctx->net_bytes, uint32le_decode(ctx->net_bytes)); - cr_mutex_unlock(&ctx->parent_sess->parent_conn->writelock); + write_Rmsg(ctx, &net_resp); } + if (host_req) + free(host_req); + free(ctx->net_bytes); } #define util_handler_common(ctx, req, resp) do { \ @@ -583,7 +566,7 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx, #endif } - uint32_t min_msg_size = rerror_overhead_for_version(version, ctx->net_bytes); + uint32_t min_msg_size = _lib9p_table_msg_min_size[version]; if (req->max_msg_size < min_msg_size) { lib9p_errorf(&ctx->ctx.basectx, LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")", |