Skip to content

libnvmf: various fixes - #4157

Merged
igaw merged 3 commits into
linux-nvme:masterfrom
igaw:fixes-from-libblockdev
Oct 12, 2026
Merged

igaw merged 3 commits into
linux-nvme:masterfrom
igaw:fixes-from-libblockdev

Conversation

@igaw

@igaw igaw commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

While porting libblockdev to libnvme3 a bunch of bugs were discovered. Fix them.

See storaged-project/libblockdev#1213

@igaw igaw changed the title libnvme: do not merge identical controllers when scanning the topology libnvmf: various fixes Oct 11, 2026
@igaw
igaw requested review from martin-belanger and a balanced review from Copilot October 11, 2026 17:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The public API documentation incorrectly guarantees a seqnum stamp that the implementation explicitly treats as best-effort.

1 open finding
What changed in this PR

Fixes libnvmf registry ownership, duplicate loop-controller discovery, and JSON output handling.

Changes:

  • Preserves ownership when reusing existing connections.
  • Atomically creates registry entries with tests.
  • Correctly represents duplicate loop controllers and missing addresses.
File Description
tests/​cli/​nvme_fabrics_mock_test.py Tests reused-controller ownership.
src/​nvme-print-json.c Handles missing controller addresses.
libnvme/​tests/​test-fabrics.c Updates ownership action tests.
libnvme/​tests/​sysfs/​meson.build Registers duplicate-loop fixture.
libnvme/​tests/​sysfs/​data/​tree-loop-duplicate.tar.xz Provides duplicate-loop sysfs data.
libnvme/​tests/​sysfs/​data/​tree-loop-duplicate.out Defines expected topology.
libnvme/​tests/​sysfs/​data/​tree-loop-duplicate-hostnqn.out Defines expected host resolution.
libnvme/​tests/​registry.c Tests atomic registry creation.
libnvme/​src/​nvme/​tree.c Prevents incorrect controller reuse.
libnvme/​src/​nvme/​registry.h Documents update semantics.
libnvme/​src/​nvme/​registry.c Implements atomic entry creation.
libnvme/​src/​nvme/​fabrics.c Preserves ownership on reconnect.
libnvme/​design/​REGISTRY.md Updates registry design guidance.
Documentation/​nvme-connect.txt Updates connect ownership documentation.
Documentation/​nvme-connect-all.txt Updates connect-all ownership documentation.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread libnvme/src/nvme/registry.h Outdated
@martin-belanger

Copy link
Copy Markdown
Collaborator

Commits 1 and 3 look good to me. Two points on the others.

Commit 2 and #4156

#4156 is merged. obj_add_str() is now json_object_add_value_string() and takes no format. This PR still merges without a conflict, but the result does not build: obj_add_ctrl_address() passes 4 arguments. It needs:

obj_add_str(o, "Address", address ? address : "");

Commit 4 breaks what nvme-discoverd relies on

nvme-discoverd has no other way to claim a controller. Its units run nvme connect --idempotent --owner=discoverd. When the controller already exists and is unowned, that connect is what writes owner=discoverd. With this commit, these controllers stay unowned, although nvme-discoverd tracks them. It has a unit for each controller. It reconnects the controller when it drops, and the unit disconnects the controller when the unit stops. This applies to:

  • a controller connected by hand that is also in nvme-fabrics.conf
  • a controller nvme-discoverd released and then wants again (a config change or a new DLP)

nvme disconnect-all then removes them, and nvme-discoverd reconnects them. The wringer does not cover these cases, so CI does not show it.

libblockdev #1213 does not need this commit. It does not call libnvme_set_owner(). It writes the owner in the connected hook, which runs only for a new controller. That path needs commit 3, not commit 4.

nvme-discoverd and nvme-stas both claim an existing controller only when it has no owner. Neither takes a controller from another owner. Only an explicit --owner on a connect does that, and REGISTRY.md documents it as a deliberate claim.

Could you drop commit 4? If the rule for an explicit --owner should change, we can discuss that separately.

igaw added 3 commits October 12, 2026 15:56
libnvme_ctrl_alloc() looks for an existing controller object matching
the transport parameters of the controller being scanned. Controllers
which match but carry a different name are skipped and the search
continues. When the search ends without a result, the last skipped
controller was used anyway:

	if (!c)
		c = p;

This was harmless as long as the lookup created a new controller when
no match was found, so that c was never NULL. Since the lookup only
finds existing controllers, the fallback reuses and renames the object
of a different controller and the create path below is never reached.

As a result, multiple connections with identical parameters, e.g.
loop controllers or controllers connected with --duplicate-connect,
collapse into a single controller object. Only one of them is visible
in the tree and 'nvme disconnect -n <nqn>' leaves the others connected.

Drop the fallback so that a new controller object is created instead.
Add a sysfs fixture with two identical loop controllers.

Signed-off-by: Daniel Wagner <wagi@monom.org>
Controllers which do not report an address, e.g. loop controllers,
return NULL from libnvme_ctrl_get_address() and the JSON printers emit

  "Address":null,

while other missing sysfs attributes are printed as an empty string.

Add obj_add_ctrl_address() which prints an empty string in this case
and use it for all controller addresses.

Signed-off-by: Daniel Wagner <wagi@monom.org>
Entries written on connect are built in a temporary directory together
with the seqnum stamp the udev REMOVE rule relies on and renamed into
place. libnvmf_registry_update() created a missing entry with a plain
mkdir() instead, so the entry had no stamp and was briefly visible
without any attribute. An orchestrator registering a controller it
connected through the public API therefore lost the protection against
a recycled instance number.

Factor out the creation of an entry from
libnvmf_registry_create_instance() and use it in
libnvmf_registry_update() when the entry does not exist yet. Removing an
attribute of a missing entry no longer creates an empty entry.

Signed-off-by: Daniel Wagner <wagi@monom.org>
@igaw
igaw force-pushed the fixes-from-libblockdev branch from fe8d2b0 to bad2691 Compare October 12, 2026 16:07
@igaw
igaw merged commit cd1449b into linux-nvme:master Oct 12, 2026
32 of 33 checks passed
@igaw
igaw deleted the fixes-from-libblockdev branch October 12, 2026 16:14
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.

3 participants