Skip to content

libnvme: probe 64-bit ioctl support without submitting a command#3349

Closed
Mateusz-Nowicki-Embedded wants to merge 1 commit into
linux-nvme:masterfrom
Mateusz-Nowicki-Embedded:fix-ioctl-probe-via-enotty
Closed

libnvme: probe 64-bit ioctl support without submitting a command#3349
Mateusz-Nowicki-Embedded wants to merge 1 commit into
linux-nvme:masterfrom
Mateusz-Nowicki-Embedded:fix-ioctl-probe-via-enotty

Conversation

@Mateusz-Nowicki-Embedded
Copy link
Copy Markdown

Replace the dummy admin SQE submission used to probe NVME_IOCTL_ADMIN64_CMD availability with a NULL-argp ioctl,
which distinguishes "ioctl unknown" (ENOTTY) from "ioctl known, arg invalid" (EFAULT) without sending any
NVMe command to the controller.

Side benefits:

  • eliminates the uninitialized-ns info leak through dummy.nsid
  • removes a malformed Delete I/O SQ SQE per controller open, which would otherwise be observable in admin SQ ring memory
    and as an Invalid Queue Identifier CQE in traces

Compatible with all kernels supported by nvme-cli (>= v4.15):

  • 4.15..5.6: NVME_IOCTL_ADMIN64_CMD doesn't exist → ENOTTY, same outcome as today
  • 5.7+: copy_from_user(NULL) fails with EFAULT before the command leaves nvme_user_cmd64()

The ioctl_probing path in __nvme_transport_handle_open_direct() submits
a zero-initialised passthru command via LIBNVME_IOCTL_ADMIN64_CMD just
to detect whether the kernel recognises the ioctl number.  The dummy
reaches the admin queue, the controller rejects it with Invalid Queue
Identifier, and the return value is used to decide whether to enable
the 64-bit variants.

Every controller open therefore submits a real, intentionally malformed
admin command that the device actually fetches and completes.  It shows
up in traces, polluting the trace history with events that have nothing
to do with what the caller asked for.  That makes the path harder to
reason about while debugging.

Pass NULL instead.  The kernel returns -ENOTTY when the ioctl number
is unknown and -EFAULT (from copy_from_user(NULL)) when it is known,
so the distinction lives entirely in errno and no NVMe command is
ever submitted from the probe.

Signed-off-by: Mateusz Nowicki <mateusz.nowicki@posteo.net>
@igaw
Copy link
Copy Markdown
Collaborator

igaw commented May 12, 2026

Thanks for the fix. Ideally we don't probe at all anymore, instead we just try the CMD64 variant when we issue the first command and if this fails we use the CMD32 version. Though this is slightly difficult to implement, it would make the overhead of probing going away for modern system, which is a good thing IMO.

@igaw
Copy link
Copy Markdown
Collaborator

igaw commented May 13, 2026

I've merged the defer/lazy ioctl approach. Hopefully, this should address the issue and make it actually work also for IO. Let me know if this doesn't work as expected. Thanks!

@Mateusz-Nowicki-Embedded
Copy link
Copy Markdown
Author

I've merged the defer/lazy ioctl approach. Hopefully, this should address the issue and make it actually work also for IO. Let me know if this doesn't work as expected. Thanks!

yep, I verified it and dummy cmd is not generated anymore, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants