mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Daejun Park <daejun7.park@samsung.com>
To: "hch@lst.de" <hch@lst.de>, "sagi@grimberg.me" <sagi@grimberg.me>,
	"kch@nvidia.com" <kch@nvidia.com>
Cc: "kbusch@kernel.org" <kbusch@kernel.org>,
	"kanie@linux.alibaba.com" <kanie@linux.alibaba.com>,
	"linux-nvme@lists.infradead.org" <linux-nvme@lists.infradead.org>,
	"linux-nfs@vger.kernel.org" <linux-nfs@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Daejun Park <daejun7.park@samsung.com>
Subject: [PATCH 2/2] nvmet: fix preempt of another registrant by the reservation holder
Date: Fri, 02 Oct 2026 16:03:41 +0900	[thread overview]
Message-ID: <20261002070341epcms2p4e1409e8fcea145562a2996ad1d1d24ea@epcms2p4> (raw)
In-Reply-To: <20261002070200epcms2p593a0aa8ac482e776e8f1de89d9f212ae@epcms2p5>

Unless the reservation is of an All Registrants type, nvmet_pr_preempt()
treats every Reservation Acquire command with the Preempt or Preempt and
Abort action that is sent by the reservation holder as the holder
preempting itself.  It updates the reservation type to RTYPE and
completes the command successfully without looking at PRKEY.

NVMe Base Specification 2.1, section 8.1.22.7 makes the action depend
on PRKEY for these reservation types, no matter which registrant sends
the command:

 - PRKEY matches the key of the reservation holder: the reservation is
   preempted.  This is how a holder preempts itself.
 - PRKEY does not match the key of the holder and is not 0h: the
   registrants whose key matches PRKEY are unregistered.
 - PRKEY does not match the key of the holder and is 0h: the command is
   aborted with Invalid Field in Command.

With the current code, a holder that preempts with the key of another
registrant leaves that registrant registered, changes the reservation
type to RTYPE and still gets a successful completion.  With hosts A, B
and C registered with the keys 0xa, 0xb and 0xc, and A holding an
Exclusive Access - Registrants Only reservation, A sends:

  # nvme resv-acquire /dev/nvme1 -n 1 --crkey=0xa --prkey=0xb \
        --rtype=4 --racqa=1
  NVME Reservation Acquire success
  # nvme resv-report /dev/nvme1 -n 1 --eds | grep '^regctl '
  regctl    : 3

and B can still write to the namespace.  Preempt and Abort (--racqa=2)
gives the same result.  When C sends the preempt instead (--crkey=0xc),
B is unregistered and its writes fail with Reservation Conflict.

This defeats fencing in the pNFS SCSI layout server.  nfsd holds the
reservation and fences a client that does not return its layout by
calling pr_preempt() with the key of that client and the abort flag,
which is the command RFC 9561 section 2.2.3 asks for.  On an nvmet
namespace the preempt succeeds, nfsd logs the client as fenced, and the
client keeps writing to the device.  In a test with an nfsd server and
two clients on an nvmet-tcp namespace, the namespace still had three
registrants after the fence and the fenced client went on writing to
it.  With this patch two registrants are left and the writes of the
fenced client fail with a reservation conflict.

Take the self preempt path only when PRKEY is the key of the holder.
Any other PRKEY sent by the holder is then handled by the code that
already serves a non-holder registrant, for Preempt and for Preempt and
Abort.  For a host that holds the reservation this changes the
following:

 - A preempt with the key of another registrant unregisters the
   registrants with that key, sends them the registration preempted
   notification and leaves the reservation type alone.
 - A preempt with PRKEY 0h fails with Invalid Field in Command.  A
   holder that changed its reservation type this way has to pass its
   own key in PRKEY, which works with and without this patch.
 - A preempt with a PRKEY that matches no registrant fails with
   Reservation Conflict.  The specification defines that status only
   for the All Registrants types.  It is what nvmet already returns to
   a non-holder registrant in this case and what the SCSI target
   returns for an unregistered key.  nfsd treats it as a successful
   fence.

Not changed: when the holder preempts itself, registrants that share
its key stay registered.

Fixes: 5a47c2080a73 ("nvmet: support reservation feature")
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
---
 drivers/nvme/target/pr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
index bfd5447f6..665cee8fc 100644
--- a/drivers/nvme/target/pr.c
+++ b/drivers/nvme/target/pr.c
@@ -585,7 +585,7 @@ static u16 nvmet_pr_preempt(struct nvmet_req *req,
 				&ctrl->hostid, abort);
 	}
 
-	if (holder == reg) {
+	if (holder == reg && prkey == holder->rkey) {
 		status = nvmet_pr_update_reg_attr(pr, holder,
 				nvmet_pr_update_holder_rtype, &rtype);
 		if (!status && original_rtype != rtype)
-- 
2.43.0


  parent reply	other threads:[~2026-10-02  7:03 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20261002065931epcms2p1cb2c16f98cf3b05f8c859ad92b0ad465@epcms2p1>
2026-10-02  6:59 ` [PATCH 0/2] nvmet: fix Reservation Acquire preempt sent by the holder Daejun Park
     [not found]   ` <CGME20261002065931epcms2p1cb2c16f98cf3b05f8c859ad92b0ad465@epcms2p5>
2026-10-02  7:02     ` [PATCH 1/2] nvmet: fix use-after-free of the old registrant in nvmet_pr_preempt() Daejun Park
2026-10-13 14:38       ` hch
     [not found]   ` <CGME20261002065931epcms2p1cb2c16f98cf3b05f8c859ad92b0ad465@epcms2p4>
2026-10-02  7:03     ` Daejun Park [this message]
2026-10-13 14:38       ` [PATCH 2/2] nvmet: fix preempt of another registrant by the reservation holder hch
2026-10-13 15:37   ` [PATCH 0/2] nvmet: fix Reservation Acquire preempt sent by the holder Keith Busch

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261002070341epcms2p4e1409e8fcea145562a2996ad1d1d24ea@epcms2p4 \
    --to=daejun7.park@samsung.com \
    --cc=hch@lst.de \
    --cc=kanie@linux.alibaba.com \
    --cc=kbusch@kernel.org \
    --cc=kch@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=sagi@grimberg.me \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®