nvme fixes for Linux 7.3

- Harden the tcp host and target against malformed PDUs: reject C2HData
    for a non-read command, bound an over-long PDU before copying it, and
    reject unsolicited H2CData (Yehyeong, Shivam)
  - Fix circular locking on TLS queues (Xixin)
  - Fix a soft lockup when scanning sparse namespace ID space (Mohamed)
  - Fix racy access to the FDP placement id array (Kanchan)
  - RDMA host and target fixes for a double cleanup on the queue_rq
    error path and a queue leak when the connect backlog is exceeded
    (Xixin)
  - Authentication fixes: drain the target's expiry work before the SQ
    is freed, and release the DH-CHAP secret when parsing fails (Kazuki,
    Xu Rao)
  - Fix nvme-fc options double free when nvme_add_ctrl() fails (Niklas)
  - Add missing SRCU grace period to nvme_alloc_ns() error path (Tristan)
  - Skip zoned limits update when the zone info query failed (Chao)
  - Reject enabling a target namespace with no device path (Seokgyu)
  - Add opcode filtering for fault injection (Mohamed)
  - Drop the kernel-doc comments from nvme-tcp.h (Randy)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE3Fbyvv+648XNRdHTPe3zGtjzRgkFAmqZ46MACgkQPe3zGtjz
 RglHuRAAhB+37HZ4wsYuwIud6IwF4rrXMv/EU1C87Nt6ORXiTG892ECT+4G4ruZo
 GTxFl6UB+i8GRw+RivMpZAWoLtEclU1GZ/ijPpgQ4+QKva60q29/2oQQiqT+x5us
 Nhez9uuC1hywxY+HfVDfvx44ISXwPG/8ZTrGMfuEO8kbmiczY8X5LxnSicgWLTc8
 PTdXvSDw5mtinzCPozRDVuFRTcDwUhM3NzVIv7MVXgEyY1sCwcPbmj8GdCkFco1G
 WnIpWP3WplnO7yNcwMN+sSFvq8PjBFfW+LJ/25WRLQFvTpF5zwejPXNWPt90USU4
 hA9kXua1CRHuApKUeNSLMQ3PG2pbB+NjIN31ZpBnveXplmIudoQuT+wLwltBg3te
 9doRCqCGLMCNu+qPFquUOOr9+6+36pBlFTynNy5WGqen0YwY4/UEG4PEU649J3Ve
 N10KY+ttHgi3bY6JdcCVlDhdzGW/rSobNz1GL4IpqPcYdZsvMqSyLrQpZfdKfp5m
 4KWYyiVmydq6ixHpZF1yEM9y2+RZGi9AtOi6CCY5pNDt7lS257htsNSTX9T3pWcH
 IeknLIuseNEW1IgUa7RPUrEkQJsiQx7eb6wI13otJULA60T40rISshuC8yGZblni
 4zu5PQiaecjqXSWQfenEi6tvPuu9jV7YsuvK5x5qs21DnFy7pUo=
 =YJ4v
 -----END PGP SIGNATURE-----

Merge tag 'nvme-7.3-2026-09-03' of git://git.infradead.org/nvme into block-7.3

Pull NVMe fixes from Keith:

"- Harden the tcp host and target against malformed PDUs: reject C2HData
   for a non-read command, bound an over-long PDU before copying it, and
   reject unsolicited H2CData (Yehyeong, Shivam)
 - Fix circular locking on TLS queues (Xixin)
 - Fix a soft lockup when scanning sparse namespace ID space (Mohamed)
 - Fix racy access to the FDP placement id array (Kanchan)
 - RDMA host and target fixes for a double cleanup on the queue_rq
   error path and a queue leak when the connect backlog is exceeded
   (Xixin)
 - Authentication fixes: drain the target's expiry work before the SQ
   is freed, and release the DH-CHAP secret when parsing fails (Kazuki,
   Xu Rao)
 - Fix nvme-fc options double free when nvme_add_ctrl() fails (Niklas)
 - Add missing SRCU grace period to nvme_alloc_ns() error path (Tristan)
 - Skip zoned limits update when the zone info query failed (Chao)
 - Reject enabling a target namespace with no device path (Seokgyu)
 - Add opcode filtering for fault injection (Mohamed)
 - Drop the kernel-doc comments from nvme-tcp.h (Randy)"

* tag 'nvme-7.3-2026-09-03' of git://git.infradead.org/nvme: (21 commits)
  nvme-tcp.h: drop kernel-doc comments, fix a few descriptions
  nvme-fc: fix double free of fabrics options when nvme_add_ctrl() fails
  nvmet: reject namespace enable without device path
  nvmet-auth: Synchronize timeout work during SQ teardown
  MAINTAINERS: update nvme entry
  nvmet-tcp: reject unsolicited H2CData PDUs
  nvme-tcp: defer TLS inline send to io_work
  nvmet-tcp: fix out-of-bounds write when receiving an over-long PDU
  nvme-tcp: return -EPROTO for a C2HData on a write
  nvmet: print namespace IDs as unsigned 32bit value
  nvme: print namespace IDs as unsigned 32bit value
  nvme: remove stale namespaces by NSID range during scan
  nvme: add missing SRCU grace period in error path
  nvme-fabrics: fix DHCHAP secret leak on parse failure
  nvmet-rdma: fix queue leak when connect backlog is exceeded
  nvme: add opcode filtering for fault injection
  nvme: fix racy access to FDP placement id array
  nvme: set ns->head in nvme_alloc_ns_head
  nvme-rdma: fix -EIO cleanup order in queue_rq
  nvme: skip the zoned limits update if the zone info query failed
  ...
This commit is contained in:
Jens Axboe 2026-09-03 19:48:07 -06:00
commit 00ef2248c5
19 changed files with 228 additions and 84 deletions

View File

@ -176,3 +176,68 @@ Message from dmesg::
secondary_startup_64+0xa4/0xb0
nvme nvme0: Could not set queue count (16385)
nvme nvme0: IO queues not created
Example 4: Inject an error into the first write command
-------------------------------------------------------
::
echo 0x01 > /sys/kernel/debug/nvme0n1/fault_inject/opcode
echo 1 > /sys/kernel/debug/nvme0n1/fault_inject/times
echo 100 > /sys/kernel/debug/nvme0n1/fault_inject/probability
dd if=/dev/zero of=/dev/nvme0n1 oflag=direct bs=512 count=1
Expected Result::
The first write command sent to nvme0n1 fails
Message from dmesg::
FAULT_INJECTION: forcing a failure.
name fault_inject, interval 1, probability 100, space 0, times 1
CPU: 4 UID: 0 PID: 0 Comm: swapper/4 Not tainted 7.1.0+ #5 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-20240910_120124-localhost 04/01/2014
Call Trace:
<IRQ>
dump_stack_lvl+0x6e/0xa0
dump_stack+0x10/0x16
should_fail_ex+0x461/0x510
should_fail+0xb/0x20
nvme_should_fail+0x11b/0x240 [nvme_core]
nvme_poll_cq+0x6ad/0xb30 [nvme]
nvme_irq+0x84/0xe0 [nvme]
? __pfx_nvme_irq+0x10/0x10 [nvme]
? rcu_core+0xa40/0xa90
? __pfx_sched_balance_softirq+0x10/0x10
? debug_smp_processor_id+0x17/0x20
? rcu_is_watching+0x13/0xa0
__handle_irq_event_percpu+0x396/0x610
handle_irq_event_percpu+0xf/0x90
handle_irq_event+0xab/0x110
handle_edge_irq+0x1a3/0x210
__common_interrupt+0xff/0x170
common_interrupt+0x90/0xc0
</IRQ>
<TASK>
asm_common_interrupt+0x27/0x40
RIP: 0010:pv_native_safe_halt+0x13/0x20
Code: 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 8b 05 0a 2a 58 01 85 c0 7e 07 0f 00 2d ff cc 0d 00 fb f4 <c3> cc 0
RSP: 0018:ffff888100a67e40 EFLAGS: 00000242
RAX: 0000000000000001 RBX: ffff888100a49c40 RCX: ffffed102b6c645b
RDX: ffffed102b6c645b RSI: ffffffff82a0d3c0 RDI: ffffffff81428b9b
RBP: ffff888100a67e48 R08: ffffed102b6c645b R09: 0000000000000004
R10: ffffed102b6c645a R11: 0000000000000001 R12: 0000000000000000
R13: 0000000000000000 R14: ffffed1020149388 R15: dffffc0000000000
? do_idle+0x19b/0x2c0
? default_idle+0x9/0x20
arch_cpu_idle+0x9/0x10
default_idle_call+0x6b/0xa0
do_idle+0x19b/0x2c0
? __pfx_do_idle+0x10/0x10
? complete_with_flags+0x63/0x70
cpu_startup_entry+0x55/0x60
start_secondary+0x1df/0x1e0
common_startup_64+0x13e/0x158
</TASK>
nvme0n1: Write(0x1) @ LBA 0, 1 blocks, Invalid Command Opcode (sct 0x0 / sc 0x1) DNR
operation not supported error, dev nvme0n1, sector 0 op 0x1:(WRITE) flags 0x8800 phys_seg 1 prio class 2

View File

@ -19569,7 +19569,7 @@ F: include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
NVM EXPRESS DRIVER
M: Keith Busch <kbusch@kernel.org>
M: Jens Axboe <axboe@fb.com>
M: Jens Axboe <axboe@kernel.dk>
M: Christoph Hellwig <hch@lst.de>
M: Sagi Grimberg <sagi@grimberg.me>
L: linux-nvme@lists.infradead.org

View File

@ -155,8 +155,6 @@ static const struct class nvme_ns_chr_class = {
};
static void nvme_put_subsystem(struct nvme_subsystem *subsys);
static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
unsigned nsid);
static void nvme_update_keep_alive(struct nvme_ctrl *ctrl,
struct nvme_command *cmd);
static int nvme_get_log_lsi(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page,
@ -1612,7 +1610,7 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl,
}
if (nvme_multi_css(ctrl) && !csi_seen) {
dev_warn(ctrl->device, "Command set not reported for nsid:%d\n",
dev_warn(ctrl->device, "Command set not reported for nsid:%u\n",
info->nsid);
status = -EINVAL;
}
@ -2341,14 +2339,6 @@ static int nvme_query_fdp_info(struct nvme_ns *ns, struct nvme_ns_info *info)
size_t size;
int i, ret;
/*
* The FDP configuration is static for the lifetime of the namespace,
* so return immediately if we've already registered this namespace's
* streams.
*/
if (head->nr_plids)
return 0;
ret = nvme_get_features(ctrl, NVME_FEAT_FDP, info->endgid, NULL, 0,
&fdp);
if (ret) {
@ -2395,6 +2385,7 @@ static int nvme_query_fdp_info(struct nvme_ns *ns, struct nvme_ns_info *info)
for (i = 0; i < head->nr_plids; i++)
head->plids[i] = le16_to_cpu(ruhs->ruhsd[i].pid);
head->write_stream_granularity = min(info->runs, U32_MAX);
free:
kfree(ruhs);
return ret;
@ -2442,12 +2433,6 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
goto out;
}
if (ns->ctrl->ctratt & NVME_CTRL_ATTR_FDPS) {
ret = nvme_query_fdp_info(ns, info);
if (ret < 0)
goto out;
}
if (nvme_invalid_lba_sz(le64_to_cpu(id->nsze),
id->lbaf[lbaf].ds - SECTOR_SHIFT, &capacity)) {
dev_warn_once(ns->ctrl->device,
@ -2468,9 +2453,26 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
if (!nvme_update_disk_info(ns, id, nvm, &lim))
capacity = 0;
/*
* A failed zone info query leaves zi zero-initialized, so skip the
* zoned limits update instead of configuring the queue from it.
* During a revalidation that keeps the zone geometry the queue was
* last validated with; on a first scan the namespace is registered
* without zoned limits, so that it is still available as a handle
* for admin commands.
*/
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
ns->head->ids.csi == NVME_CSI_ZNS)
nvme_update_zone_info(ns, &lim, &zi);
ns->head->ids.csi == NVME_CSI_ZNS) {
if (zi.zone_size)
nvme_update_zone_info(ns, &lim, &zi);
else
dev_warn(ns->ctrl->device,
"zone info query failed for nsid %u, %s\n",
ns->head->ns_id,
blk_queue_is_zoned(ns->disk->queue) ?
"keeping the previous zone limits" :
"not enabling zoned mode");
}
if ((ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT) && !info->no_vwc)
lim.features |= BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA;
@ -2490,10 +2492,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
capacity = 0;
lim.max_write_streams = ns->head->nr_plids;
if (lim.max_write_streams)
lim.write_stream_granularity = min(info->runs, U32_MAX);
else
lim.write_stream_granularity = 0;
lim.write_stream_granularity = ns->head->write_stream_granularity;
/*
* Only set the DEAC bit if the device guarantees that reads from
@ -4001,10 +4000,11 @@ static void nvme_add_ns_cdev(struct nvme_ns *ns)
set_bit(NVME_NS_CDEV_LIVE, &ns->flags);
}
static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns,
struct nvme_ns_info *info)
__must_hold(&ctrl->subsys->lock)
__must_hold(&ns->ctrl->subsys->lock)
{
struct nvme_ctrl *ctrl = ns->ctrl;
struct nvme_ns_head *head;
size_t size = sizeof(*head);
int ret = -ENOMEM;
@ -4032,6 +4032,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
ratelimit_state_init(&head->rs_nuse, 5 * HZ, 1);
ratelimit_set_flags(&head->rs_nuse, RATELIMIT_MSG_ON_RELEASE);
kref_init(&head->ref);
ns->head = head;
if (head->ids.csi) {
ret = nvme_get_effects_log(ctrl, head->ids.csi, &head->effects);
@ -4040,21 +4041,30 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
} else
head->effects = ctrl->effects;
if (ctrl->ctratt & NVME_CTRL_ATTR_FDPS) {
ret = nvme_query_fdp_info(ns, info);
if (ret < 0)
goto out_cleanup_srcu;
}
ret = nvme_mpath_alloc_disk(ctrl, head);
if (ret)
goto out_cleanup_srcu;
goto out_cleanup_fdp;
list_add_tail(&head->entry, &ctrl->subsys->nsheads);
kref_get(&ctrl->subsys->ref);
return head;
out_cleanup_fdp:
kfree(head->plids);
out_cleanup_srcu:
cleanup_srcu_struct(&head->srcu);
out_ida_remove:
ida_free(&ctrl->subsys->ns_ida, head->instance);
out_free_head:
kfree(head);
ns->head = NULL;
out:
if (ret > 0)
ret = blk_status_to_errno(nvme_error_status(ret));
@ -4116,13 +4126,13 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
((ns->ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) &&
info->is_shared)) {
dev_err(ctrl->device,
"ignoring nsid %d because of duplicate IDs\n",
"ignoring nsid %u because of duplicate IDs\n",
info->nsid);
return ret;
}
dev_err(ctrl->device,
"clearing duplicate IDs for nsid %d\n", info->nsid);
"clearing duplicate IDs for nsid %u\n", info->nsid);
dev_err(ctrl->device,
"use of /dev/disk/by-id/ may cause data corruption\n");
memset(&info->ids.nguid, 0, sizeof(info->ids.nguid));
@ -4137,11 +4147,11 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, &info->ids);
if (ret) {
dev_err(ctrl->device,
"duplicate IDs in subsystem for nsid %d\n",
"duplicate IDs in subsystem for nsid %u\n",
info->nsid);
goto out_unlock;
}
head = nvme_alloc_ns_head(ctrl, info);
head = nvme_alloc_ns_head(ns, info);
if (IS_ERR(head)) {
ret = PTR_ERR(head);
goto out_unlock;
@ -4151,20 +4161,20 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
if ((!info->is_shared || !head->shared) &&
!list_empty(&head->list)) {
dev_err(ctrl->device,
"Duplicate unshared namespace %d\n",
"Duplicate unshared namespace %u\n",
info->nsid);
goto out_put_ns_head;
}
if (!nvme_ns_ids_equal(&head->ids, &info->ids)) {
dev_err(ctrl->device,
"IDs don't match for shared namespace %d\n",
"IDs don't match for shared namespace %u\n",
info->nsid);
goto out_put_ns_head;
}
if (!multipath) {
dev_warn(ctrl->device,
"Found shared namespace %d, but multipathing not supported.\n",
"Found shared namespace %u, but multipathing not supported.\n",
info->nsid);
dev_warn_once(ctrl->device,
"Shared namespace support requires core_nvme.multipath=Y.\n");
@ -4333,6 +4343,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
last_path = true;
}
mutex_unlock(&ctrl->subsys->lock);
/* guarantee not available in head->list */
synchronize_srcu(&ns->head->srcu);
if (last_path)
nvme_put_ns_head(ns->head);
nvme_put_ns_head(ns->head);
@ -4410,7 +4423,7 @@ static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_info *info)
if (!nvme_ns_ids_equal(&ns->head->ids, &info->ids)) {
dev_err(ns->ctrl->device,
"identifiers changed for nsid %d\n", ns->head->ns_id);
"identifiers changed for nsid %u\n", ns->head->ns_id);
goto out;
}
@ -4437,7 +4450,7 @@ static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid)
if (info.ids.csi != NVME_CSI_NVM && !nvme_multi_css(ctrl)) {
dev_warn(ctrl->device,
"command set not reported for nsid: %d\n", nsid);
"command set not reported for nsid: %u\n", nsid);
return;
}
@ -4501,15 +4514,16 @@ static void nvme_scan_ns_async(void *data, async_cookie_t cookie)
nvme_scan_ns(scan_info->ctrl, nsid);
}
static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
unsigned nsid)
static void nvme_remove_nsid_range(struct nvme_ctrl *ctrl, u32 start, u32 end)
{
struct nvme_ns *ns, *next;
LIST_HEAD(rm_list);
mutex_lock(&ctrl->namespaces_lock);
list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) {
if (ns->head->ns_id > nsid) {
if (ns->head->ns_id >= end)
break;
if (ns->head->ns_id > start) {
list_del_rcu(&ns->list);
synchronize_srcu(&ctrl->srcu);
list_add_tail_rcu(&ns->list, &rm_list);
@ -4559,13 +4573,14 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl)
goto out;
async_schedule_domain(nvme_scan_ns_async, &scan_info,
&domain);
while (++prev < nsid)
nvme_ns_remove_by_nsid(ctrl, prev);
if (prev + 1 < nsid)
nvme_remove_nsid_range(ctrl, prev, nsid);
prev = max(prev + 1, nsid);
}
async_synchronize_full_domain(&domain);
}
out:
nvme_remove_invalid_namespaces(ctrl, prev);
nvme_remove_nsid_range(ctrl, prev, UINT_MAX);
free:
async_synchronize_full_domain(&domain);
kfree(ns_list);
@ -4585,7 +4600,7 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl)
for (i = 1; i <= nn; i++)
nvme_scan_ns(ctrl, i);
nvme_remove_invalid_namespaces(ctrl, nn);
nvme_remove_nsid_range(ctrl, nn, UINT_MAX);
}
static void nvme_clear_changed_ns_log(struct nvme_ctrl *ctrl)

View File

@ -1028,6 +1028,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
}
if (strlen(p) < 11 || strncmp(p, "DHHC-1:", 7)) {
pr_err("Invalid DH-CHAP secret %s\n", p);
kfree_sensitive(p);
ret = -EINVAL;
goto out;
}
@ -1042,6 +1043,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
}
if (strlen(p) < 11 || strncmp(p, "DHHC-1:", 7)) {
pr_err("Invalid DH-CHAP secret %s\n", p);
kfree_sensitive(p);
ret = -EINVAL;
goto out;
}

View File

@ -42,9 +42,11 @@ void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj,
}
fault_inj->parent = parent;
/* create debugfs for status code and dont_retry */
/* create debugfs for opcode, status code, and dont_retry */
fault_inj->opcode = 0xffff;
fault_inj->status = NVME_SC_INVALID_OPCODE;
fault_inj->dont_retry = true;
debugfs_create_x16("opcode", 0600, dir, &fault_inj->opcode);
debugfs_create_x16("status", 0600, dir, &fault_inj->status);
debugfs_create_bool("dont_retry", 0600, dir, &fault_inj->dont_retry);
}
@ -59,6 +61,7 @@ void nvme_should_fail(struct request *req)
{
struct gendisk *disk = req->q->disk;
struct nvme_fault_inject *fault_inject = NULL;
struct nvme_command *cmd = nvme_req(req)->cmd;
u16 status;
if (disk) {
@ -72,7 +75,14 @@ void nvme_should_fail(struct request *req)
fault_inject = &nvme_req(req)->ctrl->fault_inject;
}
if (fault_inject && should_fail(&fault_inject->attr, 1)) {
if (!fault_inject)
return;
if (fault_inject->opcode <= 0xff &&
fault_inject->opcode != cmd->common.opcode)
return;
if (should_fail(&fault_inject->attr, 1)) {
/* inject status code and DNR bit */
status = fault_inject->status;
if (fault_inject->dont_retry)

View File

@ -2364,9 +2364,15 @@ nvme_fc_ctrl_free(struct kref *ref)
struct nvme_fc_ctrl *ctrl =
container_of(ref, struct nvme_fc_ctrl, ref);
unsigned long flags;
bool owns_opts;
/* remove from rport list */
/*
* Presence on the rport list means nvme_fc_init_ctrl() completed,
* and with it ownership of the fabrics options passed to it. If it
* failed instead, the options still belong to nvmf_create_ctrl().
*/
spin_lock_irqsave(&ctrl->rport->lock, flags);
owns_opts = !list_empty(&ctrl->ctrl_list);
list_del(&ctrl->ctrl_list);
spin_unlock_irqrestore(&ctrl->rport->lock, flags);
@ -2376,7 +2382,7 @@ nvme_fc_ctrl_free(struct kref *ref)
nvme_fc_rport_put(ctrl->rport);
ida_free(&nvme_fc_ctrl_cnt, ctrl->cnum);
if (ctrl->ctrl.opts)
if (owns_opts)
nvmf_free_options(ctrl->ctrl.opts);
kfree(ctrl);
}
@ -3575,14 +3581,14 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
dev_err(ctrl->ctrl.device,
"NVME-FC{%d}: failed to init ctrl state\n", ctrl->cnum);
goto fail_ctrl;
goto fail_unlist;
}
if (!queue_delayed_work(nvme_wq, &ctrl->connect_work, 0)) {
dev_err(ctrl->ctrl.device,
"NVME-FC{%d}: failed to schedule initial connect\n",
ctrl->cnum);
goto fail_ctrl;
goto fail_unlist;
}
flush_delayed_work(&ctrl->connect_work);
@ -3593,14 +3599,22 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
return &ctrl->ctrl;
fail_unlist:
/*
* Leaving the list hands the options back to nvmf_create_ctrl();
* see nvme_fc_ctrl_free(). Re-init so that list_empty() there
* reports the controller as unlisted.
*/
spin_lock_irqsave(&rport->lock, flags);
list_del_init(&ctrl->ctrl_list);
spin_unlock_irqrestore(&rport->lock, flags);
fail_ctrl:
nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING);
cancel_work_sync(&ctrl->ioerr_work);
cancel_work_sync(&ctrl->ctrl.reset_work);
cancel_delayed_work_sync(&ctrl->connect_work);
ctrl->ctrl.opts = NULL;
if (ctrl->ctrl.admin_tagset)
nvme_remove_admin_tag_set(&ctrl->ctrl);
/* initiate nvme ctrl ref counting teardown */

View File

@ -323,6 +323,7 @@ struct nvme_fault_inject {
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
struct fault_attr attr;
struct dentry *parent;
u16 opcode;
bool dont_retry; /* DNR, do not retry */
u16 status; /* status code */
#endif
@ -571,6 +572,7 @@ struct nvme_ns_head {
u16 nr_plids;
u16 *plids;
u32 write_stream_granularity;
#ifdef CONFIG_NVME_MULTIPATH
struct bio_list requeue_list
__guarded_by(&requeue_lock);

View File

@ -2036,7 +2036,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
struct ib_device *dev;
bool queue_ready = test_bit(NVME_RDMA_Q_LIVE, &queue->flags);
blk_status_t ret;
int err;
int err = 0;
WARN_ON_ONCE(rq->tag < 0);
@ -2092,16 +2092,18 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
err_unmap:
nvme_rdma_unmap_data(queue, rq);
err:
if (err == -EIO)
ret = nvme_host_path_error(rq);
else if (err == -ENOMEM || err == -EAGAIN)
ret = BLK_STS_RESOURCE;
else
ret = BLK_STS_IOERR;
nvme_cleanup_cmd(rq);
if (err != -EIO) {
nvme_cleanup_cmd(rq);
if (err == -ENOMEM || err == -EAGAIN)
ret = BLK_STS_RESOURCE;
else
ret = BLK_STS_IOERR;
}
unmap_qe:
ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
DMA_TO_DEVICE);
if (err == -EIO)
return nvme_host_path_error(rq);
return ret;
}

View File

@ -166,7 +166,7 @@ static DEVICE_ATTR_RO(eui);
static ssize_t nsid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "%d\n", dev_to_ns_head(dev)->ns_id);
return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ns_id);
}
static DEVICE_ATTR_RO(nsid);

View File

@ -413,8 +413,13 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
* if we're the first on the send_list and we can try to send
* directly, otherwise queue io_work. Also, only do that if we
* are on the same cpu, so we don't introduce contention.
*
* TLS kTLS send takes ctx->tx_lock while blk_mq holds set->srcu.
* lockdep reports circular locking via elevator_lock. Defer TLS
* sends to the io workqueue instead of inline from this path.
*/
if (queue->io_cpu == raw_smp_processor_id() &&
!nvme_tcp_queue_tls(queue) &&
empty && mutex_trylock(&queue->send_mutex)) {
nvme_tcp_send_all(queue);
mutex_unlock(&queue->send_mutex);
@ -684,6 +689,13 @@ static int nvme_tcp_handle_c2h_data(struct nvme_tcp_queue *queue,
return -ENOENT;
}
if (rq_data_dir(rq) != READ) {
dev_err(queue->ctrl->ctrl.device,
"queue %d tag %#x unexpected data for a write\n",
nvme_tcp_queue_id(queue), rq->tag);
return -EPROTO;
}
req = blk_mq_rq_to_pdu(rq);
if (!blk_rq_payload_bytes(rq) || !req->curr_bio || !req->data_len) {
dev_err(queue->ctrl->ctrl.device,

View File

@ -48,12 +48,12 @@ int nvme_query_zone_info(struct nvme_ns *ns, unsigned lbaf,
NVME_CMD_EFFECTS_CSUPP)) {
if (test_and_clear_bit(NVME_NS_FORCE_RO, &ns->flags))
dev_warn(ns->ctrl->device,
"Zone Append supported for zoned namespace:%d. Remove read-only mode\n",
"Zone Append supported for zoned namespace:%u. Remove read-only mode\n",
ns->head->ns_id);
} else {
set_bit(NVME_NS_FORCE_RO, &ns->flags);
dev_warn(ns->ctrl->device,
"Zone Append not supported for zoned namespace:%d. Forcing to read-only mode\n",
"Zone Append not supported for zoned namespace:%u. Forcing to read-only mode\n",
ns->head->ns_id);
}

View File

@ -238,6 +238,12 @@ void nvmet_auth_sq_free(struct nvmet_sq *sq)
sq->dhchap_skey = NULL;
}
void nvmet_auth_sq_destroy(struct nvmet_sq *sq)
{
cancel_delayed_work_sync(&sq->auth_expired_work);
nvmet_auth_sq_free(sq);
}
void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
{
ctrl->shash_id = 0;

View File

@ -814,7 +814,7 @@ static ssize_t nvmet_ns_resv_enable_store(struct config_item *item,
mutex_lock(&ns->subsys->lock);
if (ns->enabled) {
pr_err("the ns:%d is already enabled.\n", ns->nsid);
pr_err("the ns:%u is already enabled.\n", ns->nsid);
mutex_unlock(&ns->subsys->lock);
return -EINVAL;
}
@ -880,7 +880,7 @@ static struct config_group *nvmet_ns_make(struct config_group *group,
goto out;
config_group_init_type_name(&ns->group, name, &nvmet_ns_type);
pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn);
pr_info("adding nsid %u to subsystem %s\n", nsid, subsys->subsysnqn);
return &ns->group;
out:

View File

@ -558,7 +558,7 @@ static void nvmet_p2pmem_ns_add_p2p(struct nvmet_ctrl *ctrl,
if (ret < 0)
pci_dev_put(p2p_dev);
pr_info("using p2pmem on %s for nsid %d\n", pci_name(p2p_dev),
pr_info("using p2pmem on %s for nsid %u\n", pci_name(p2p_dev),
ns->nsid);
}
@ -591,6 +591,11 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
if (ns->enabled)
goto out_unlock;
if (!ns->device_path) {
ret = -EINVAL;
goto out_unlock;
}
ret = nvmet_bdev_ns_enable(ns);
if (ret == -ENOTBLK)
ret = nvmet_file_ns_enable(ns);
@ -980,7 +985,7 @@ void nvmet_sq_destroy(struct nvmet_sq *sq)
wait_for_completion(&sq->confirm_done);
wait_for_completion(&sq->free_done);
percpu_ref_exit(&sq->ref);
nvmet_auth_sq_free(sq);
nvmet_auth_sq_destroy(sq);
nvmet_cq_put(sq->cq);
/*

View File

@ -924,6 +924,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset);
void nvmet_auth_sq_init(struct nvmet_sq *sq);
void nvmet_destroy_auth(struct nvmet_ctrl *ctrl);
void nvmet_auth_sq_free(struct nvmet_sq *sq);
void nvmet_auth_sq_destroy(struct nvmet_sq *sq);
int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id);
bool nvmet_check_auth_status(struct nvmet_req *req);
int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
@ -950,6 +951,7 @@ static inline void nvmet_auth_sq_init(struct nvmet_sq *sq)
}
static inline void nvmet_destroy_auth(struct nvmet_ctrl *ctrl) {};
static inline void nvmet_auth_sq_free(struct nvmet_sq *sq) {};
static inline void nvmet_auth_sq_destroy(struct nvmet_sq *sq) {};
static inline bool nvmet_check_auth_status(struct nvmet_req *req)
{
return true;

View File

@ -145,7 +145,7 @@ static void nvmet_pr_add_resv_log(struct nvmet_ctrl *ctrl, u8 log_type,
log.nsid = cpu_to_le32(nsid);
if (!kfifo_put(&log_mgr->log_queue, log)) {
pr_info("a reservation log lost, cntlid:%d, log_type:%d, nsid:%d\n",
pr_info("a reservation log lost, cntlid:%d, log_type:%d, nsid:%u\n",
ctrl->cntlid, log_type, nsid);
log_mgr->lost_count++;
}

View File

@ -1631,19 +1631,13 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
mutex_unlock(&nvmet_rdma_queue_mutex);
if (pending > NVMET_RDMA_BACKLOG) {
ret = NVME_SC_CONNECT_CTRL_BUSY;
goto put_device;
goto free_queue;
}
}
ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
if (ret) {
/*
* Don't destroy the cm_id in free path, as we implicitly
* destroy the cm_id here with non-zero ret code.
*/
queue->cm_id = NULL;
if (ret)
goto free_queue;
}
mutex_lock(&nvmet_rdma_queue_mutex);
list_add_tail(&queue->queue_list, &nvmet_rdma_queue_list);
@ -1652,6 +1646,11 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
return 0;
free_queue:
/*
* Don't destroy the cm_id in free path, as we implicitly
* destroy the cm_id here with non-zero ret code.
*/
queue->cm_id = NULL;
nvmet_rdma_free_queue(queue);
put_device:
kref_put(&ndev->ref, nvmet_rdma_free_dev);

View File

@ -103,6 +103,7 @@ enum nvmet_tcp_recv_state {
enum {
NVMET_TCP_F_INIT_FAILED = (1 << 0),
NVMET_TCP_F_R2T_SENT = (1 << 1),
};
struct nvmet_tcp_cmd {
@ -776,6 +777,7 @@ static int nvmet_try_send_r2t(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
return -EAGAIN;
cmd->queue->snd_cmd = NULL;
cmd->flags |= NVMET_TCP_F_R2T_SENT;
return 1;
}
@ -1009,6 +1011,12 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
cmd = &queue->connect;
}
if (unlikely(!(cmd->flags & NVMET_TCP_F_R2T_SENT))) {
pr_err("queue %d: unsolicited H2CData (ttag %u)\n",
queue->idx, data->ttag);
goto err_proto;
}
if (le32_to_cpu(data->data_offset) != cmd->rbytes_done) {
pr_err("ttag %u unexpected data offset %u (expected %u)\n",
data->ttag, le32_to_cpu(data->data_offset),
@ -1244,6 +1252,8 @@ static int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue)
}
queue->left = hdr->hlen - queue->offset + hdgst;
if (queue->left > sizeof(queue->pdu) - queue->offset)
return -EPROTO;
goto recv;
}

View File

@ -77,7 +77,7 @@ struct nvme_tcp_hdr {
__le32 plen;
};
/**
/*
* struct nvme_tcp_icreq_pdu - nvme tcp initialize connection request pdu
*
* @hdr: pdu generic header
@ -95,7 +95,7 @@ struct nvme_tcp_icreq_pdu {
__u8 rsvd2[112];
};
/**
/*
* struct nvme_tcp_icresp_pdu - nvme tcp initialize connection response pdu
*
* @hdr: pdu common header
@ -113,12 +113,13 @@ struct nvme_tcp_icresp_pdu {
__u8 rsvd[112];
};
/**
/*
* struct nvme_tcp_term_pdu - nvme tcp terminate connection pdu
*
* @hdr: pdu common header
* @fes: fatal error status
* @fei: fatal error information
* @feil: fatal error information (low 16 bits)
* @feih: fatal error information (high 16 bits)
*/
struct nvme_tcp_term_pdu {
struct nvme_tcp_hdr hdr;
@ -128,7 +129,7 @@ struct nvme_tcp_term_pdu {
__u8 rsvd[10];
};
/**
/*
* struct nvme_tcp_cmd_pdu - nvme tcp command capsule pdu
*
* @hdr: pdu common header
@ -139,10 +140,9 @@ struct nvme_tcp_cmd_pdu {
struct nvme_command cmd;
};
/**
/*
* struct nvme_tcp_rsp_pdu - nvme tcp response capsule pdu
*
* @hdr: pdu common header
* @hdr: nvme-tcp generic header
* @cqe: nvme completion queue entry
*/
@ -151,7 +151,7 @@ struct nvme_tcp_rsp_pdu {
struct nvme_completion cqe;
};
/**
/*
* struct nvme_tcp_r2t_pdu - nvme tcp ready-to-transfer pdu
*
* @hdr: pdu common header
@ -169,7 +169,7 @@ struct nvme_tcp_r2t_pdu {
__u8 rsvd[4];
};
/**
/*
* struct nvme_tcp_data_pdu - nvme tcp data pdu
*
* @hdr: pdu common header