summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-07-31 16:42:34 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-07-31 16:42:34 -0700
commitf01618fd7915bd2acf945e47bf987383a60c4c45 (patch)
tree1565c9a12e7aeaeccd7667bed7267781022d6db4
parent5d0c32d6ec00cf155d2263b82ec255faa3888c9f (diff)
parent7f40b346462f563a0d6e841a77b5163d2a882a04 (diff)
Merge tag 'block-7.2-20260731' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux
Pull block fixes from Jens Axboe: - A set of fixes for s390/dasd, via Stefan - Fix for a missing stop of the timeout timer, if a disk has never been added - Clear kernel owned fields on ublk setup by default * tag 'block-7.2-20260731' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: s390/dasd: Fix undersized format-check buffer s390/dasd: Fix potential NULL pointer dereference s390/dasd: Fix path verification interrupted by concurrent dasd_sleep_on_immediatly block: stop the timeout timer when releasing a never added disk ublk: reset kernel-owned dev_info fields in ublk_ctrl_add_dev()
-rw-r--r--block/genhd.c12
-rw-r--r--drivers/block/ublk_drv.c9
-rw-r--r--drivers/s390/block/dasd.c14
-rw-r--r--drivers/s390/block/dasd_eckd.c11
-rw-r--r--drivers/s390/block/dasd_ioctl.c2
5 files changed, 38 insertions, 10 deletions
diff --git a/block/genhd.c b/block/genhd.c
index df2c3c69b467..e8ce0cabf392 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1281,14 +1281,18 @@ static void disk_release(struct device *dev)
/*
* To undo the all initialization from blk_mq_init_allocated_queue in
* case of a probe failure where add_disk is never called we have to
- * call blk_mq_exit_queue here. We can't do this for the more common
- * teardown case (yet) as the tagset can be gone by the time the disk
- * is released once it was added.
+ * call blk_mq_exit_queue here, after stopping the timer and work items
+ * that I/O issued before add_disk may have left pending. We can't do
+ * this for the more common teardown case (yet) as the tagset can be
+ * gone by the time the disk is released once it was added.
*/
if (queue_is_mq(disk->queue) &&
test_bit(GD_OWNS_QUEUE, &disk->state) &&
- !test_bit(GD_ADDED, &disk->state))
+ !test_bit(GD_ADDED, &disk->state)) {
+ blk_sync_queue(disk->queue);
+ blk_mq_cancel_work_sync(disk->queue);
blk_mq_exit_queue(disk->queue);
+ }
blkcg_exit_disk(disk);
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 4ca6ec738c93..2a22f9dc1f2f 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -4765,6 +4765,15 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
ub->dev_info.dev_id = ub->ub_number;
/*
+ * ->state and ->ublksrv_pid are owned by the driver and only read back
+ * by userspace, but they come from the copied-in dev_info, so reset
+ * them. Otherwise a device added with ->state != DEAD looks live while
+ * ->ub_disk is still NULL.
+ */
+ ub->dev_info.state = UBLK_S_DEV_DEAD;
+ ub->dev_info.ublksrv_pid = -1;
+
+ /*
* 64bit flags will be copied back to userspace as feature
* negotiation result, so have to clear flags which driver
* doesn't support yet, then userspace can get correct flags
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 3181c06d91ce..d8d912a3b3fe 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -21,6 +21,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
+#include <linux/delay.h>
#include <asm/machine.h>
#include <asm/ccwdev.h>
@@ -2511,6 +2512,13 @@ static inline int _dasd_term_running_cqr(struct dasd_device *device)
if (list_empty(&device->ccw_queue))
return 0;
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
+ /*
+ * Path verification requests must not be terminated. They are critical
+ * for bringing paths back online. Terminating them would cause rc=-EIO
+ * because CLEARED requests skip the retry path.
+ */
+ if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
+ return -EAGAIN;
rc = device->discipline->term_IO(cqr);
if (!rc)
/*
@@ -2535,7 +2543,11 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
return -EIO;
}
spin_lock_irq(get_ccwdev_lock(device->cdev));
- rc = _dasd_term_running_cqr(device);
+ while ((rc = _dasd_term_running_cqr(device)) == -EAGAIN) {
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ msleep(1);
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ }
if (rc) {
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 74fe73b5738a..d356a9f8f016 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -20,6 +20,7 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/overflow.h>
#include <asm/css_chars.h>
#include <asm/machine.h>
@@ -3475,11 +3476,11 @@ static int dasd_eckd_check_device_format(struct dasd_device *base,
{
struct dasd_eckd_private *private = base->private;
struct eckd_count *fmt_buffer;
- struct irb irb;
+ size_t fmt_buffer_size;
+ unsigned int trkcount;
int rpt_max, rpt_exp;
- int fmt_buffer_size;
+ struct irb irb;
int trk_per_cyl;
- int trkcount;
int tpm = 0;
int rc;
@@ -3490,7 +3491,9 @@ static int dasd_eckd_check_device_format(struct dasd_device *base,
rpt_exp = recs_per_track(&private->rdc_data, 0, cdata->expect.blksize);
trkcount = cdata->expect.stop_unit - cdata->expect.start_unit + 1;
- fmt_buffer_size = trkcount * rpt_max * sizeof(struct eckd_count);
+ if (check_mul_overflow(trkcount, rpt_max, &fmt_buffer_size) ||
+ check_mul_overflow(fmt_buffer_size, sizeof(struct eckd_count), &fmt_buffer_size))
+ return -EINVAL;
fmt_buffer = kzalloc(fmt_buffer_size, GFP_KERNEL | GFP_DMA);
if (!fmt_buffer)
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index c85ee42732a3..e5b8b413f5ab 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -324,7 +324,7 @@ out_err:
static int dasd_release_space(struct dasd_device *device,
struct format_data_t *rdata)
{
- if (!device->discipline->is_ese && !device->discipline->is_ese(device))
+ if (!device->discipline->is_ese || !device->discipline->is_ese(device))
return -ENOTSUPP;
if (!device->discipline->release_space)
return -ENOTSUPP;