mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 14:30:06 -04:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user