Re: [PATCH RFC 04/20] Documentation: ctlv: Add userspace ABI

From: Sergii Dmytruk

Date: Thu Oct 29 2026 - 14:56:49 EST


On Thu, Oct 15, 2026 at 04:50:37PM +0200, Jiri Pirko wrote:
> From: Jiri Pirko <jiri@xxxxxxxxxx>
>
> Describe the CTLV transport, discovery, wire format and userspace
> compatibility rules.
>
> Assisted-by: Cursor: GPT-5.6 Sol
> Assisted-by: Cursor: Claude Opus 5.5
> Signed-off-by: Jiri Pirko <jiri@xxxxxxxxxx>
> ---
> Documentation/userspace-api/ctlv.rst | 507 ++++++++++++++++++++++++++
> Documentation/userspace-api/index.rst | 1 +
> MAINTAINERS | 1 +
> 3 files changed, 509 insertions(+)
> create mode 100644 Documentation/userspace-api/ctlv.rst
>
> diff --git a/Documentation/userspace-api/ctlv.rst b/Documentation/userspace-api/ctlv.rst
> new file mode 100644
> index 000000000000..5ebca3d4d94a
> --- /dev/null
> +++ b/Documentation/userspace-api/ctlv.rst

[...]

> +Errors
> +------
> +
> +A failed operation returns a negative errno. Where the failure is a rule the
> +message broke and the caller offered a reply buffer, CTLV also writes
> +error information there in TLV form: a ``validation-reason`` value, a
> +human-readable message, the offset of the offending attribute, the offset of
> +the nest it was in, the ID of a missing attribute, and for a stale query the
> +expected and the current generation. A buffer too small leaves it unwritten;
> +the errno is authoritative either way.
> +
> +What the transport answers with, as against a family's own callback:

It seems like this mixes results of several syscalls (e.g., `open()` and
`ioctl()`). Does it?

> +
> +``ENOTTY``
> + Not ``CTLV_IOC_OP_EXEC``; this transport has one ioctl.
> +
> +``EINVAL``
> + A reserved field was not zero, ``op_id`` was zero, ``generation`` or
> + ``cursor`` was set on something that is not a query, or the message broke
> + a rule of the format or of the schema.
> +
> +``EFAULT``
> + The structure, the request or the reply was not accessible.
> +
> +``EOPNOTSUPP``
> + The device does not publish the operation, publishes it but has it
> + disabled, or the operation is an event, which is read rather than executed.
> +
> +``EACCES``
> + The fd lacks the operation's declared authority, or an ``O_WRONLY`` open
> + was attempted.
> +
> +``EMSGSIZE``
> + ``reply_len`` is smaller than the smallest fragment the operation can
> + answer with. Nothing was executed.
> +
> +``ESTALE``
> + A continuation whose ``generation`` no longer matches. Start the query
> + again.
> +
> +``ENODEV``
> + The device was unregistered. Descriptors stay open and every operation on
> + them fails this way.
> +
> +``EBADF``, ``EIO``
> + A blob descriptor named something that is not a file, or the file refused
> + the transfer.
> +
> +``ENOMEM``
> + The kernel could not allocate what the operation needed.
> +
> +``read()`` answers ``EAGAIN`` when no record is queued on a non-blocking
> +description, ``EINTR`` when a blocking read was interrupted, ``EMSGSIZE`` when
> +the buffer cannot hold the record at the head of the queue, and ``ENODEV``
> +once a removed device's queue has been drained.

[...]