Commit 4c53b890 authored by Chuck Lever's avatar Chuck Lever
Browse files

xdrgen: Emit a max_arg_sz macro



struct svc_service has a .vs_xdrsize field that is filled in by
servers for each of their RPC programs. This field is supposed to
contain the size of the largest procedure argument in the RPC
program. This value is also sometimes used to size network
transport buffers.

Currently, server implementations must manually calculate and
hard-code this value, which is error-prone and requires updates
when procedure arguments change.

Update xdrgen to determine which procedure argument structure is
largest, and emit a macro with a well-known name that contains
the size of that structure. Server code then uses this macro when
initializing the .vs_xdrsize field.

For NLM version 4, xdrgen now emits:

    #define NLM4_MAX_ARGS_SZ (NLM4_nlm4_lockargs_sz)

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 63a5425f
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -5,8 +5,9 @@

from jinja2 import Environment

from generators import SourceGenerator, create_jinja2_environment
from generators import SourceGenerator, create_jinja2_environment, get_jinja2_template
from xdr_ast import _RpcProgram, _RpcVersion, excluded_apis
from xdr_ast import max_widths, get_header_name


def emit_version_definitions(
@@ -169,3 +170,35 @@ class XdrProgramGenerator(SourceGenerator):
                    emit_version_argument_encoders(
                        self.environment, program, version,
                    )

    def emit_maxsize(self, node: _RpcProgram) -> None:
        """Emit maxsize macro for maximum RPC argument size"""
        header = get_header_name().upper()

        # Find the largest argument across all versions
        max_arg_width = 0
        max_arg_name = None
        for version in node.versions:
            for procedure in version.procedures:
                if procedure.name in excluded_apis:
                    continue
                arg_name = procedure.argument.type_name
                if arg_name == "void":
                    continue
                if arg_name not in max_widths:
                    continue
                if max_widths[arg_name] > max_arg_width:
                    max_arg_width = max_widths[arg_name]
                    max_arg_name = arg_name

        if max_arg_name is None:
            return

        macro_name = header + "_MAX_ARGS_SZ"
        template = get_jinja2_template(self.environment, "maxsize", "max_args")
        print(
            template.render(
                macro=macro_name,
                width=header + "_" + max_arg_name + "_sz",
            )
        )
+2 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ def emit_header_maxsize(root: Specification, language: str, peer: str) -> None:
            gen = XdrStructGenerator(language, peer)
        elif isinstance(definition.value, _XdrUnion):
            gen = XdrUnionGenerator(language, peer)
        elif isinstance(definition.value, _RpcProgram):
            gen = XdrProgramGenerator(language, peer)
        else:
            continue
        gen.emit_maxsize(definition.value)
+3 −0
Original line number Diff line number Diff line
{# SPDX-License-Identifier: GPL-2.0 #}
#define {{ '{:<31}'.format(macro) }} \
	({{ width }})