* Re: [PATCH] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-25 3:50 [PATCH] nvmet: fix Reservation Register Replace for unregistered host with IEKEY Zhengrong Li
@ 2026-07-28 7:52 ` Maurizio Lombardi
2026-07-28 8:26 ` [PATCH v4] " Zhengrong Li
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Maurizio Lombardi @ 2026-07-28 7:52 UTC (permalink / raw)
To: Zhengrong Li, linux-nvme; +Cc: hch, sagi, kch
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@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
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v4] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-25 3:50 [PATCH] nvmet: fix Reservation Register Replace for unregistered host with IEKEY Zhengrong Li
2026-07-28 7:52 ` Maurizio Lombardi
@ 2026-07-28 8:26 ` Zhengrong Li
2026-07-30 4:36 ` Guixin Liu
2026-08-04 16:29 ` Christoph Hellwig
2026-07-28 8:26 ` [PATCH v3] " Zhengrong Li
2026-07-28 8:26 ` [PATCH v2] " Zhengrong Li
3 siblings, 2 replies; 8+ messages in thread
From: Zhengrong Li @ 2026-07-28 8:26 UTC (permalink / raw)
To: linux-nvme; +Cc: hch, sagi, kch, mlombard, kanie, zhengrong_li
When a host sends a Reservation Register command with RREGA=Replace
and IEKEY=1 without being previously registered, nvmet returns
Reservation Conflict.
The NVMe specification states:
"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."
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.
If IEKEY is set but NRKEY is zero, return Invalid Field since there
is no valid reservation key to register.
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
Fixes: 5a47c2080a73 ("nvmet: support reservation feature")
Signed-off-by: Zhengrong Li <zhengrong_li@linux.alibaba.com>
---
Changes since v3:
- Use explicit goto free_data/out cleanup labels instead of the
NULL-pointer kfree trick, consistent with the rest of pr.c.
- Remove the redundant 'found' bool variable.
Changes since v2:
- Quote the NVMe specification instead of referencing SPDK (Guixin).
- Add the Fixes tag (Guixin).
- Return NVME_SC_INVALID_FIELD when IEKEY is set but NRKEY is zero
for an unregistered host (Guixin).
- Allocate the new registrant before taking pr_sem and free it if
unused (Guixin).
---
drivers/nvme/target/pr.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
index c71ae46244ff..7d937093b226 100644
--- a/drivers/nvme/target/pr.c
+++ b/drivers/nvme/target/pr.c
@@ -355,9 +355,15 @@ 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 = NULL;
u64 nrkey = le64_to_cpu(d->nrkey);
+ if (ignore_key && nrkey) {
+ new = kzalloc_obj(*new);
+ if (!new)
+ return NVME_SC_INTERNAL;
+ }
+
down(&pr->pr_sem);
list_for_each_entry_rcu(reg, &pr->registrant_list, entry) {
if (uuid_equal(®->hostid, &ctrl->hostid)) {
@@ -365,9 +371,26 @@ static u16 nvmet_pr_replace(struct nvmet_req *req,
status = nvmet_pr_update_reg_attr(pr, reg,
nvmet_pr_update_reg_rkey,
&nrkey);
- break;
+ goto free_data;
+ }
+ }
+
+ if (ignore_key) {
+ if (!nrkey) {
+ status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+ goto free_data;
}
+ INIT_LIST_HEAD(&new->entry);
+ new->rkey = nrkey;
+ uuid_copy(&new->hostid, &ctrl->hostid);
+ list_add_tail_rcu(&new->entry, &pr->registrant_list);
+ status = NVME_SC_SUCCESS;
+ goto out;
}
+
+free_data:
+ kfree(new);
+out:
up(&pr->pr_sem);
return status;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v4] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-28 8:26 ` [PATCH v4] " Zhengrong Li
@ 2026-07-30 4:36 ` Guixin Liu
2026-08-04 16:29 ` Christoph Hellwig
1 sibling, 0 replies; 8+ messages in thread
From: Guixin Liu @ 2026-07-30 4:36 UTC (permalink / raw)
To: Zhengrong Li, linux-nvme; +Cc: hch, sagi, kch, mlombard
LGTM.
Reviewed-by: Guixin Liu <kanie@linux.alibaba.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-28 8:26 ` [PATCH v4] " Zhengrong Li
2026-07-30 4:36 ` Guixin Liu
@ 2026-08-04 16:29 ` Christoph Hellwig
1 sibling, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2026-08-04 16:29 UTC (permalink / raw)
To: Zhengrong Li; +Cc: linux-nvme, hch, sagi, kch, mlombard, kanie
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-25 3:50 [PATCH] nvmet: fix Reservation Register Replace for unregistered host with IEKEY Zhengrong Li
2026-07-28 7:52 ` Maurizio Lombardi
2026-07-28 8:26 ` [PATCH v4] " Zhengrong Li
@ 2026-07-28 8:26 ` Zhengrong Li
2026-07-28 8:26 ` [PATCH v2] " Zhengrong Li
3 siblings, 0 replies; 8+ messages in thread
From: Zhengrong Li @ 2026-07-28 8:26 UTC (permalink / raw)
To: linux-nvme; +Cc: hch, sagi, kch, mlombard, kanie, zhengrong_li
When a host sends a Reservation Register command with RREGA=Replace
and IEKEY=1 without being previously registered, nvmet returns
Reservation Conflict.
The NVMe specification states:
"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."
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.
If IEKEY is set but NRKEY is zero, return Invalid Field since there
is no valid reservation key to register.
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
Fixes: 5a47c2080a73 ("nvmet: support reservation feature")
Signed-off-by: Zhengrong Li <zhengrong_li@linux.alibaba.com>
---
Changes since v2:
- Quote the NVMe specification instead of referencing SPDK (Guixin).
- Add the Fixes tag (Guixin).
- Return NVME_SC_INVALID_FIELD when IEKEY is set but NRKEY is zero
for an unregistered host (Guixin).
- Allocate the new registrant before taking pr_sem and free it if
unused (Guixin).
---
drivers/nvme/target/pr.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
index c71ae46244ff..61fafc08297b 100644
--- a/drivers/nvme/target/pr.c
+++ b/drivers/nvme/target/pr.c
@@ -355,12 +355,20 @@ 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 = NULL;
u64 nrkey = le64_to_cpu(d->nrkey);
+ bool found = false;
+
+ if (ignore_key && nrkey) {
+ new = kzalloc_obj(*new);
+ if (!new)
+ return NVME_SC_INTERNAL;
+ }
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,7 +376,23 @@ static u16 nvmet_pr_replace(struct nvmet_req *req,
break;
}
}
+
+ if (!found && ignore_key) {
+ if (!nrkey) {
+ status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+ goto out;
+ }
+ INIT_LIST_HEAD(&new->entry);
+ new->rkey = nrkey;
+ uuid_copy(&new->hostid, &ctrl->hostid);
+ list_add_tail_rcu(&new->entry, &pr->registrant_list);
+ status = NVME_SC_SUCCESS;
+ new = NULL;
+ }
+
+out:
up(&pr->pr_sem);
+ kfree(new);
return status;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-25 3:50 [PATCH] nvmet: fix Reservation Register Replace for unregistered host with IEKEY Zhengrong Li
` (2 preceding siblings ...)
2026-07-28 8:26 ` [PATCH v3] " Zhengrong Li
@ 2026-07-28 8:26 ` Zhengrong Li
2026-07-28 12:44 ` Guixin Liu
3 siblings, 1 reply; 8+ messages in thread
From: Zhengrong Li @ 2026-07-28 8:26 UTC (permalink / raw)
To: linux-nvme; +Cc: hch, sagi, kch, mlombard, zhengrong_li
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
Signed-off-by: Zhengrong Li <zhengrong_li@linux.alibaba.com>
---
Changes since v1:
- Use kzalloc_obj() instead of kmalloc_obj() + memset() (Maurizio).
---
drivers/nvme/target/pr.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
index c71ae46244ff..944e3d3947d0 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,21 @@ static u16 nvmet_pr_replace(struct nvmet_req *req,
break;
}
}
+
+ if (!found && ignore_key && nrkey) {
+ new = kzalloc_obj(*new);
+ if (!new) {
+ status = NVME_SC_INTERNAL;
+ goto out;
+ }
+ INIT_LIST_HEAD(&new->entry);
+ new->rkey = nrkey;
+ uuid_copy(&new->hostid, &ctrl->hostid);
+ list_add_tail_rcu(&new->entry, &pr->registrant_list);
+ status = NVME_SC_SUCCESS;
+ }
+
+out:
up(&pr->pr_sem);
return status;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v2] nvmet: fix Reservation Register Replace for unregistered host with IEKEY
2026-07-28 8:26 ` [PATCH v2] " Zhengrong Li
@ 2026-07-28 12:44 ` Guixin Liu
0 siblings, 0 replies; 8+ messages in thread
From: Guixin Liu @ 2026-07-28 12:44 UTC (permalink / raw)
To: Zhengrong Li, linux-nvme; +Cc: hch, sagi, kch, mlombard
Hi Zhengrong:
在 2026/7/28 16:26, Zhengrong Li 写道:
> 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.
Just quote the NVMe spec rather than mentioning SPDK.
>
> 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
Here need add: Fixes: 5a47c2080a73 ("nvmet: support reservation feature").
> Signed-off-by: Zhengrong Li <zhengrong_li@linux.alibaba.com>
> ---
> Changes since v1:
> - Use kzalloc_obj() instead of kmalloc_obj() + memset() (Maurizio).
> ---
> drivers/nvme/target/pr.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
> index c71ae46244ff..944e3d3947d0 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,21 @@ static u16 nvmet_pr_replace(struct nvmet_req *req,
> break;
> }
> }
> +
> + if (!found && ignore_key && nrkey) {
> + new = kzalloc_obj(*new);
Nit: you can alloc new before down(&pr->pr_sem).
> + if (!new) {
> + status = NVME_SC_INTERNAL;
> + goto out;
> + }
> + INIT_LIST_HEAD(&new->entry);
> + new->rkey = nrkey;
> + uuid_copy(&new->hostid, &ctrl->hostid);
> + list_add_tail_rcu(&new->entry, &pr->registrant_list);
> + status = NVME_SC_SUCCESS;
> + }
> +
If the nrkey==0, should return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR
instead of
NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR;
> +out:
> up(&pr->pr_sem);
> return status;
> }
Others looks good, thanks.
Best Regards,
Guixin Liu
^ permalink raw reply [flat|nested] 8+ messages in thread