[PATCH] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
Maurizio Lombardi
mlombard at arkamax.eu
Tue Jul 28 00:52:44 PDT 2026
On Sat Jul 25, 2026 at 5:50 AM CEST, Zhengrong Li wrote:
> When a host sends a Reservation Register command with RREGA=Replace
> and IEKEY=1 without being previously registered, nvmet returns
> Reservation Conflict. SPDK accepts this combination and creates a
> new registrant with the provided NRKEY, with an explicit unit test
> covering this scenario (test/unit/lib/nvmf/subsystem.c).
>
> Fix nvmet_pr_replace() to add a new registrant when the host is not
> found in the registrant list and IEKEY is set with a non-zero NRKEY,
> consistent with SPDK's behavior.
>
> Tested with nvme-cli against nvmet-tcp:
>
> # no prior registration
> nvme resv-register /dev/nvmeXn1 -n 1 --rrega=2 --iekey --nrkey=0x9999
>
> Before: RESERVATION_CONFLICT (0x4083)
> After: success, registrant created with rkey 0x9999
The SPDK behaviour seems to be correct, the spec indeed says that
"A host may replace
its reservation key without regard to its registration status or current reservation key value by setting the
Ignore Existing Key (IEKEY) bit to '1' in the Reservation Register
command."
>
> Signed-off-by: Zhengrong Li <zhengrong_li at linux.alibaba.com>
> ---
> drivers/nvme/target/pr.c | 20 +++++++++++++++++++-
> 1 file changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
> index c71ae46244ff..f00de35683ca 100644
> --- a/drivers/nvme/target/pr.c
> +++ b/drivers/nvme/target/pr.c
> @@ -355,12 +355,14 @@ static u16 nvmet_pr_replace(struct nvmet_req *req,
> u16 status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR;
> struct nvmet_ctrl *ctrl = req->sq->ctrl;
> struct nvmet_pr *pr = &req->ns->pr;
> - struct nvmet_pr_registrant *reg;
> + struct nvmet_pr_registrant *reg, *new;
> u64 nrkey = le64_to_cpu(d->nrkey);
> + bool found = false;
>
> down(&pr->pr_sem);
> list_for_each_entry_rcu(reg, &pr->registrant_list, entry) {
> if (uuid_equal(®->hostid, &ctrl->hostid)) {
> + found = true;
> if (ignore_key || reg->rkey == le64_to_cpu(d->crkey))
> status = nvmet_pr_update_reg_attr(pr, reg,
> nvmet_pr_update_reg_rkey,
> @@ -368,6 +370,22 @@ static u16 nvmet_pr_replace(struct nvmet_req *req,
> break;
> }
> }
> +
> + if (!found && ignore_key && nrkey) {
> + new = kmalloc_obj(*new);
> + if (!new) {
> + status = NVME_SC_INTERNAL;
> + goto out;
> + }
> + memset(new, 0, sizeof(*new));
Just use kzalloc_obj()?
Maurizio
More information about the Linux-nvme
mailing list