Skip to content

libnvme: fix persistent discovery ctrl disconnect decisions - #3811

Merged
igaw merged 1 commit into
linux-nvme:masterfrom
martin-belanger:fix-persistent-dc-disconnect
Aug 11, 2026
Merged

libnvme: fix persistent discovery ctrl disconnect decisions#3811
igaw merged 1 commit into
linux-nvme:masterfrom
martin-belanger:fix-persistent-dc-disconnect

Conversation

@martin-belanger

Copy link
Copy Markdown

Follow-on fix to #3776. nvme discover/nvme connect-all sit at the same level as orchestrators like nvme-discoverd and nvme-stas: they're convenience helpers that combine several decisions (lookup, connect, walk referrals, disconnect) rather than a single primitive operation like connect/disconnect. As orchestrators, they must not interfere with connections owned by another orchestrator -- if they find an existing connection while walking, they may reuse it to fetch its Discovery Log Page, but they must never disconnect it afterward, even under --persistent=no. --persistent describes what this invocation should do with the connections it creates; it says nothing about a connection it merely found already in place, which another orchestrator may be relying on to persist.

Two related bugs violated that boundary. First, discover_lookup_ctrl_by_device() and discover_lookup_ctrl() silently forced fctx->persistent to FORCE whenever they found an already-connected discovery controller, regardless of what --persistent actually requested. Since libnvmf_discover() copies fctx wholesale into every referral it walks (nfctx = *fctx), that override also poisoned persistence for every referral discovered in the same walk, not just the reused connection -- so a plain -p=no against a target with an already-connected discovery controller silently forced everything downstream to persist too.

Second, the primary discovery connection (ie. primary = the first DC) itself never got a disconnect decision at all. Referrals get one from their parent, computed from the referral's own entry in the parent's log before ever connecting. The primary has no parent to do this for it, and every discovery controller's own EPCSD is only ever reported in its own Discovery Log Page, as a SUBTYPE=03h ("current discovery subsystem") entry describing itself -- _nvmf_discover() discarded that entry as an ordinary already-connected match, without ever reading it. Fixed by extracting it and deciding, at the point the connection processes its own log, using the same FORCE/AUTO/NO logic already used for referrals. An absent self entry is treated as EPCSD=0, matching the spec's own definition of the bit: "not reported". This new decision only ever applies to a primary connection we created in this call -- if it was already connected when we found it, per the orchestrator-coexistence rule above, we never touch it.

Verified via build (-Dwerror=true), meson test, and make checkpatch-diff, all clean.

Not yet verified live -- @Mr-Bossman, would you mind testing this. Thanks.

discover_lookup_ctrl_by_device() and discover_lookup_ctrl() forced
fctx->persistent to FORCE whenever they found an already-connected
discovery controller, regardless of what --persistent requested.
This also poisoned persistence for every referral discovered in the
same walk, not just the reused connection.

Signed-off-by: Martin Belanger <martin.belanger@dell.com>
Comment thread libnvme/src/nvme/fabrics.c
@Mr-Bossman

Copy link
Copy Markdown
Contributor

LGTM this fixes the issue i brought up.

@igaw
igaw merged commit ae45f0c into linux-nvme:master Aug 11, 2026
33 checks passed
@igaw

igaw commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

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.

3 participants