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

Pull block fixes from Jens Axboe:

 - Limit blk_hctx_poll() to one jiffy. Prevents buggy drivers from
   spinning for too long, hence triggering a stalled RCU read section
   warning

 - Avoid a potential deadlock on zone revalidation failure, which could
   otherwise trigger a lockdep circular locking splat during a SCSI disk
   rescan

 - Remove a redundant GD_NEED_PART_SCAN set in add_disk_final()

 - Make writes to queue/wbt_lat_usec honor the WBT enable state

 - ublk fix to snapshot the batch commands before preparing IO, so that
   userspace can't change an already processed tag and trip the
   WARN_ON_ONCE() in the rollback path

 - xen-blkfront fix for a double completion of split requests on resume

 - drbd fix to reject data replies with an out-of-range payload size

* tag 'block-7.2-20260710' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux:
  block: remove redundant GD_NEED_PART_SCAN in add_disk_final()
  drbd: reject data replies with an out-of-range payload size
  xen-blkfront: fix double completion of split requests on resume
  ublk: snapshot batch commands before preparing I/O
  block: Make WBT latency writes honor enable state
  block: avoid potential deadlock on zone revalidation failure
  blk-mq: bound blk_hctx_poll() to one jiffy
This commit is contained in:
Linus Torvalds
2026-07-11 09:35:33 -07:00
8 changed files with 79 additions and 24 deletions

View File

@@ -5218,6 +5218,7 @@ static int blk_hctx_poll(struct request_queue *q, struct blk_mq_hw_ctx *hctx,
struct io_comp_batch *iob, unsigned int flags)
{
int ret;
unsigned long timeout = jiffies + 2;
do {
ret = q->mq_ops->poll(hctx, iob);
@@ -5228,7 +5229,7 @@ static int blk_hctx_poll(struct request_queue *q, struct blk_mq_hw_ctx *hctx,
if (ret < 0 || (flags & BLK_POLL_ONESHOT))
break;
cpu_relax();
} while (!need_resched());
} while (!need_resched() && time_before(jiffies, timeout));
return 0;
}

View File

@@ -813,6 +813,21 @@ static void wbt_queue_depth_changed(struct rq_qos *rqos)
wbt_update_limits(RQWB(rqos));
}
static bool wbt_set_lat_changed(struct request_queue *q, u64 val)
{
struct rq_qos *rqos = wbt_rq_qos(q);
struct rq_wb *rwb;
if (!rqos)
return true;
rwb = RQWB(rqos);
if (rwb->min_lat_nsec != val)
return true;
return rwb_enabled(rwb) != !!val;
}
static void wbt_exit(struct rq_qos *rqos)
{
struct rq_wb *rwb = RQWB(rqos);
@@ -1005,8 +1020,12 @@ int wbt_set_lat(struct gendisk *disk, s64 val)
else if (val >= 0)
val *= 1000ULL;
if (wbt_get_min_lat(q) == val)
mutex_lock(&disk->rqos_state_mutex);
if (!wbt_set_lat_changed(q, val)) {
mutex_unlock(&disk->rqos_state_mutex);
goto out;
}
mutex_unlock(&disk->rqos_state_mutex);
blk_mq_quiesce_queue(q);

View File

@@ -1923,11 +1923,20 @@ static int disk_alloc_zone_resources(struct gendisk *disk,
if (!disk->zone_wplugs_pool)
goto free_hash;
disk->zone_wplugs_wq =
alloc_workqueue("%s_zwplugs", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
pool_size, disk->disk_name);
if (!disk->zone_wplugs_wq)
goto destroy_pool;
/*
* We may already have a zone write plug workqueue as this function may
* be called after disk_free_zone_resources(), which does not destroy
* the workqueue (the zone write plugs workqueue is destroyed at
* disk_release() time).
*/
if (!disk->zone_wplugs_wq) {
disk->zone_wplugs_wq =
alloc_workqueue("%s_zwplugs",
WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
pool_size, disk->disk_name);
if (!disk->zone_wplugs_wq)
goto destroy_pool;
}
disk->zone_wplugs_worker =
kthread_create(disk_zone_wplugs_worker, disk,
@@ -1935,15 +1944,12 @@ static int disk_alloc_zone_resources(struct gendisk *disk,
if (IS_ERR(disk->zone_wplugs_worker)) {
ret = PTR_ERR(disk->zone_wplugs_worker);
disk->zone_wplugs_worker = NULL;
goto destroy_wq;
goto destroy_pool;
}
wake_up_process(disk->zone_wplugs_worker);
return 0;
destroy_wq:
destroy_workqueue(disk->zone_wplugs_wq);
disk->zone_wplugs_wq = NULL;
destroy_pool:
mempool_destroy(disk->zone_wplugs_pool);
disk->zone_wplugs_pool = NULL;
@@ -1999,7 +2005,7 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond)
kfree_rcu_mightsleep(zones_cond);
}
void disk_free_zone_resources(struct gendisk *disk)
static void disk_free_zone_resources(struct gendisk *disk)
{
if (disk->zone_wplugs_worker) {
kthread_stop(disk->zone_wplugs_worker);
@@ -2007,10 +2013,8 @@ void disk_free_zone_resources(struct gendisk *disk)
}
WARN_ON_ONCE(!list_empty(&disk->zone_wplugs_list));
if (disk->zone_wplugs_wq) {
destroy_workqueue(disk->zone_wplugs_wq);
disk->zone_wplugs_wq = NULL;
}
if (disk->zone_wplugs_wq)
drain_workqueue(disk->zone_wplugs_wq);
disk_destroy_zone_wplugs_hash_table(disk);
@@ -2020,6 +2024,16 @@ void disk_free_zone_resources(struct gendisk *disk)
disk->nr_zones = 0;
}
void disk_release_zone_resources(struct gendisk *disk)
{
if (disk->zone_wplugs_wq) {
destroy_workqueue(disk->zone_wplugs_wq);
disk->zone_wplugs_wq = NULL;
}
disk_free_zone_resources(disk);
}
struct blk_revalidate_zone_args {
struct gendisk *disk;
u8 *zones_cond;

View File

@@ -528,7 +528,7 @@ static inline void ioc_clear_queue(struct request_queue *q)
#ifdef CONFIG_BLK_DEV_ZONED
void disk_init_zone_resources(struct gendisk *disk);
void disk_free_zone_resources(struct gendisk *disk);
void disk_release_zone_resources(struct gendisk *disk);
static inline bool bio_zone_write_plugging(struct bio *bio)
{
return bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING);
@@ -581,7 +581,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
static inline void disk_init_zone_resources(struct gendisk *disk)
{
}
static inline void disk_free_zone_resources(struct gendisk *disk)
static inline void disk_release_zone_resources(struct gendisk *disk)
{
}
static inline bool bio_zone_write_plugging(struct bio *bio)

View File

@@ -407,10 +407,6 @@ static void add_disk_final(struct gendisk *disk)
struct device *ddev = disk_to_dev(disk);
if (!(disk->flags & GENHD_FL_HIDDEN)) {
/* Make sure the first partition scan will be proceed */
if (get_capacity(disk) && disk_has_partscan(disk))
set_bit(GD_NEED_PART_SCAN, &disk->state);
bdev_add(disk->part0, ddev->devt);
if (get_capacity(disk))
disk_scan_partitions(disk, BLK_OPEN_READ);
@@ -1300,7 +1296,7 @@ static void disk_release(struct device *dev)
disk_release_events(disk);
kfree(disk->random);
disk_free_zone_resources(disk);
disk_release_zone_resources(disk);
xa_destroy(&disk->part_tbl);
kobject_put(&disk->queue_kobj);

View File

@@ -1810,6 +1810,11 @@ static int recv_dless_read(struct drbd_peer_device *peer_device, struct drbd_req
data_size -= digest_size;
}
if (data_size < 0) {
drbd_err(peer_device, "Invalid data reply size\n");
return -EIO;
}
/* optimistically update recv_cnt. if receiving fails below,
* we disconnect anyways, and counters will be reset. */
peer_device->device->recv_cnt += data_size>>9;

View File

@@ -3584,6 +3584,7 @@ ublk_batch_auto_buf_reg(const struct ublk_batch_io *uc,
#define UBLK_CMD_BATCH_TMP_BUF_SZ (48 * 10)
struct ublk_batch_io_iter {
void __user *uaddr;
const u8 *kaddr;
unsigned done, total;
unsigned char elem_bytes;
/* copy to this buffer from user space */
@@ -3632,7 +3633,10 @@ static int ublk_walk_cmd_buf(struct ublk_batch_io_iter *iter,
while (iter->done < iter->total) {
unsigned int len = min(sizeof(iter->buf), iter->total - iter->done);
if (copy_from_user(iter->buf, iter->uaddr + iter->done, len)) {
if (iter->kaddr) {
memcpy(iter->buf, iter->kaddr + iter->done, len);
} else if (copy_from_user(iter->buf, iter->uaddr + iter->done,
len)) {
pr_warn("ublk%d: read batch cmd buffer failed\n",
data->ub->dev_info.dev_id);
return -EFAULT;
@@ -3723,14 +3727,21 @@ static int ublk_handle_batch_prep_cmd(const struct ublk_batch_io_data *data)
.total = uc->nr_elem * uc->elem_bytes,
.elem_bytes = uc->elem_bytes,
};
void *cmd_buf;
int ret;
cmd_buf = vmemdup_user(iter.uaddr, iter.total);
if (IS_ERR(cmd_buf))
return PTR_ERR(cmd_buf);
iter.kaddr = cmd_buf;
mutex_lock(&data->ub->mutex);
ret = ublk_walk_cmd_buf(&iter, data, ublk_batch_prep_io);
if (ret && iter.done)
ublk_batch_revert_prep_cmd(&iter, data);
mutex_unlock(&data->ub->mutex);
kvfree(cmd_buf);
return ret;
}

View File

@@ -2079,6 +2079,15 @@ static int blkfront_resume(struct xenbus_device *dev)
if (!shadow[j].request)
continue;
/*
* For requests split across multiple slots, process the
* underlying request only once: skip the linked, sg-less
* secondary slot.
*/
if (shadow[j].associated_id != NO_ASSOCIATED_ID &&
shadow[j].num_sg == 0)
continue;
/*
* Get the bios in the request so we can re-queue them.
*/