summaryrefslogtreecommitdiff
path: root/lib9p/idl.gen
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-01-17 20:30:41 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-02-12 20:55:19 -0700
commit1793bda7f3e445c5ad81cf108589f8b1edcda4eb (patch)
tree41fe1255c206a6ce8f4b02aad58fe66fa4415b8e /lib9p/idl.gen
parente9de61146146b250dd1c6977086a62435c21d771 (diff)
lib9p: idl.gen: Enforce a max WELEM for 9P2000.e
Diffstat (limited to 'lib9p/idl.gen')
-rwxr-xr-xlib9p/idl.gen80
1 files changed, 68 insertions, 12 deletions
diff --git a/lib9p/idl.gen b/lib9p/idl.gen
index ead9bc5..bf0935c 100755
--- a/lib9p/idl.gen
+++ b/lib9p/idl.gen
@@ -224,7 +224,9 @@ class BufferSize:
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
@@ -233,7 +235,9 @@ class BufferSize:
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
@@ -271,17 +275,36 @@ def get_buffer_size(typ: idl.Type, version: str) -> BufferSize:
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
- 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
+ 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
- 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
+ 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
elif not isinstance(child.typ, idl.Struct):
@@ -332,6 +355,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"""
@@ -404,7 +435,7 @@ enum {idprefix}version {{
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:,} ; max_copy = {sz.max_copy:,}"
+ 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)
@@ -478,6 +509,9 @@ enum {idprefix}version {{
ret += """
/* sizes **********************************************************************/
"""
+ 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] = {}
@@ -485,6 +519,8 @@ enum {idprefix}version {{
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:
@@ -511,9 +547,29 @@ enum {idprefix}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"
- ret += f"\t#define {idprefix.upper()}{name.upper()} {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"