projects/linux·commit d0fc310b

Merge tag 'block-7.3-20260905' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

d0fc310b · Linus Torvalds <[email protected]> · 2026-09-05 08:58:55 -07:00

Pull block fixes from Jens Axboe:

 - NVMe fixes via Keith:
     - nvme-tcp fixes for an out-of-bounds write on an over-long PDU
     - nvmet-tcp, nvmet-rdma and nvme-rdma leak and cleanup-ordering
       fixes
     - FDP placement id array racy access fix
     - nvme-fc double free of fabrics options on nvme_add_ctrl()
       failure, and a secret leak failure
     - Fault injection opcode filtering
     - stale namespace removal during scan
     - Various other smaller fixes and cleanups

 - Flag zoned disks with GENHD_FL_NO_PART

 - Save the page offset gaps in a cloned bio

 - Fix dma_alignment for large or unreported limits in loop and zloop

 - Clear VM_MAYWRITE on a read-only ublk char device mmap

* tag 'block-7.3-20260905' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (25 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
  ublk: clear VM_MAYWRITE on read-only ublk char device mmap
  loop, zloop: fix dma_alignment for large or unreported limits
  block: save page offset gaps in cloned bio
  block: flag zoned disks with GENHD_FL_NO_PART
  nvmet-rdma: fix queue leak when connect backlog is exceeded
  nvme: add opcode filtering for fault injection
  ...
Commit
d0fc310b4dfd334023b90d2423818044190c0f68
Parents
4d7d9486 · 00ef2248

Merge commit. Changes below are compared with the first parent: 4d7d9486.

Changes

24 files changed · +260 −90

Only the first 600 diff lines are shown. Download the complete patch.

Documentation/fault-injection/nvme-fault-injection.rst

View file
diff --git a/Documentation/fault-injection/nvme-fault-injection.rst b/Documentation/fault-injection/nvme-fault-injection.rst
index 1d44278..09730ac 100644
--- a/Documentation/fault-injection/nvme-fault-injection.rst
+++ b/Documentation/fault-injection/nvme-fault-injection.rst
@@ -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

MAINTAINERS

View file
diff --git a/MAINTAINERS b/MAINTAINERS
index 9fb50c3..c9f866d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19563,7 +19563,7 @@ F: include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
NVM EXPRESS DRIVER
M: Keith Busch <[email protected]>
-M: Jens Axboe <[email protected]>
+M: Jens Axboe <[email protected]>
M: Christoph Hellwig <[email protected]>
M: Sagi Grimberg <[email protected]>

block/bio.c

View file
diff --git a/block/bio.c b/block/bio.c
index 898b2f5..f95b63c 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -859,6 +859,7 @@ static int __bio_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp)
bio->bi_ioprio = bio_src->bi_ioprio;
bio->bi_write_hint = bio_src->bi_write_hint;
bio->bi_write_stream = bio_src->bi_write_stream;
+ bio->bi_bvec_gap_bit = bio_src->bi_bvec_gap_bit;
bio->bi_iter = bio_src->bi_iter;
bio->bi_io_vec = bio_src->bi_io_vec;
@@ -1972,6 +1973,14 @@ struct bio *bio_split(struct bio *bio, int sectors,
bio_advance(bio, split->bi_iter.bi_size);
+ /*
+ * The gap bit is set when splitting to limits and only applies to the
+ * front bio that was split off. The remaining bio will calcualte its
+ * gap value when it is subsequently split to limits, so it is safe to
+ * re-initialize the value back to 0.
+ */
+ bio->bi_bvec_gap_bit = 0;
+
if (bio_flagged(bio, BIO_TRACE_COMPLETION))
bio_set_flag(split, BIO_TRACE_COMPLETION);

block/genhd.c

View file
diff --git a/block/genhd.c b/block/genhd.c
index f1990c7..10ca8b4 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -448,6 +448,13 @@ static int __add_disk(struct device *parent, struct gendisk *disk,
}
/*
+ * We do not support partitions with zoned block devices, so do not try
+ * to scan the partitions table.
+ */
+ if (blk_queue_is_zoned(disk->queue))
+ disk->flags |= GENHD_FL_NO_PART;
+
+ /*
* If the driver provides an explicit major number it also must provide
* the number of minors numbers supported, and those will be used to
* setup the gendisk.

drivers/block/loop.c

View file
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6f12976..758c206 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -458,12 +458,14 @@ static void loop_update_dio_alignment(struct loop_device *lo)
* Use the dio alignment of the file system if provided. The incomoing
* request's bio_vec is forwarded to the backing file unchanged, so its
* required memory alignment becomes the device's dma_alignment when
- * used for direct-io.
+ * used for direct-io. The file system reports zeroed alignments if the
+ * file can't be used for direct-io at all, so fall back to the block
+ * device limits in that case.
*/
if (!vfs_getattr(&file->f_path, &st, STATX_DIOALIGN, 0) &&
- (st.result_mask & STATX_DIOALIGN)) {
+ (st.result_mask & STATX_DIOALIGN) && st.dio_mem_align) {
lo->lo_min_dio_size = st.dio_offset_align;
- lo->lo_dio_mem_align = st.dio_mem_align - 1;
+ lo->lo_dio_mem_align = min(st.dio_mem_align - 1, PAGE_SIZE - 1);
return;
}

drivers/block/ublk_drv.c

View file
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 6c5bec7..e5ba07d 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -2653,6 +2653,12 @@ static int ublk_ch_mmap(struct file *filp, struct vm_area_struct *vma)
if (vma->vm_flags & VM_WRITE)
return -EPERM;
+ /*
+ * The per-queue command buffer is kernel-written ABI; prevent
+ * the daemon from upgrading to writable via mprotect().
+ */
+ vm_flags_clear(vma, VM_MAYWRITE);
+
end = UBLKSRV_CMD_BUF_OFFSET + ub->dev_info.nr_hw_queues * max_sz;
if (phys_off < UBLKSRV_CMD_BUF_OFFSET || phys_off >= end)
return -EINVAL;

drivers/block/zloop.c

View file
diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c
index 4323ac1..f0ca221 100644
--- a/drivers/block/zloop.c
+++ b/drivers/block/zloop.c
@@ -1042,12 +1042,14 @@ static int zloop_get_block_size(struct zloop_device *zlo,
* Use the dio alignment of the file system if provided. The incoming
* request's bio_vec is forwarded to the backing file unchanged, so its
* required memory alignment becomes the device's dma_alignment when
- * used for direct-io.
+ * used for direct-io. The file system reports zeroed alignments if the
+ * file can't be used for direct-io at all, so fall back to the block
+ * device limits in that case.
*/
if (!vfs_getattr(&zone->file->f_path, &st, STATX_DIOALIGN, 0) &&
- (st.result_mask & STATX_DIOALIGN)) {
+ (st.result_mask & STATX_DIOALIGN) && st.dio_mem_align) {
zlo->block_size = st.dio_offset_align;
- zlo->dio_mem_align = st.dio_mem_align - 1;
+ zlo->dio_mem_align = min(st.dio_mem_align - 1, PAGE_SIZE - 1);
} else if (sb_bdev) {
zlo->block_size = bdev_physical_block_size(sb_bdev);
zlo->dio_mem_align = bdev_dma_alignment(sb_bdev);

drivers/nvme/host/core.c

View file
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 1322c67..758245c 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -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)

drivers/nvme/host/fabrics.c

View file
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index fd5abd0..59f823d 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -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;
}

drivers/nvme/host/fault_inject.c

View file
diff --git a/drivers/nvme/host/fault_inject.c b/drivers/nvme/host/fault_inject.c
index 105d6cb..783e199 100644
--- a/drivers/nvme/host/fault_inject.c
+++ b/drivers/nvme/host/fault_inject.c
@@ -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)

drivers/nvme/host/fc.c

View file
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 023710e..48454cb 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -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);

This diff is incomplete. Download the complete patch.

drivers/nvme/host/nvme.h

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/host/rdma.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/host/sysfs.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/host/tcp.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/host/zns.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/auth.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/configfs.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/core.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/nvmet.h

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/pr.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/rdma.c

View file

This diff is incomplete. Download the complete patch.

drivers/nvme/target/tcp.c

View file

This diff is incomplete. Download the complete patch.

include/linux/nvme-tcp.h

View file

This diff is incomplete. Download the complete patch.