Skip to content

Commit 9869d3a

Browse files
Ming Leiaxboe
authored andcommitted
block: fix race between wbt_enable_default and IO submission
When wbt_enable_default() is moved out of queue freezing in elevator_change(), it can cause the wbt inflight counter to become negative (-1), leading to hung tasks in the writeback path. Tasks get stuck in wbt_wait() because the counter is in an inconsistent state. The issue occurs because wbt_enable_default() could race with IO submission, allowing the counter to be decremented before proper initialization. This manifests as: rq_wait[0]: inflight: -1 has_waiters: True rwb_enabled() checks the state, which can be updated exactly between wbt_wait() (rq_qos_throttle()) and wbt_track()(rq_qos_track()), then the inflight counter will become negative. And results in hung task warnings like: task:kworker/u24:39 state:D stack:0 pid:14767 Call Trace: rq_qos_wait+0xb4/0x150 wbt_wait+0xa9/0x100 __rq_qos_throttle+0x24/0x40 blk_mq_submit_bio+0x672/0x7b0 ... Fix this by: 1. Splitting wbt_enable_default() into: - __wbt_enable_default(): Returns true if wbt_init() should be called - wbt_enable_default(): Wrapper for existing callers (no init) - wbt_init_enable_default(): New function that checks and inits WBT 2. Using wbt_init_enable_default() in blk_register_queue() to ensure proper initialization during queue registration 3. Move wbt_init() out of wbt_enable_default() which is only for enabling disabled wbt from bfq and iocost, and wbt_init() isn't needed. Then the original lock warning can be avoided. 4. Removing the ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT flag and its handling code since it's no longer needed This ensures WBT is properly initialized before any IO can be submitted, preventing the counter from going negative. Cc: Nilay Shroff <nilay@linux.ibm.com> Cc: Yu Kuai <yukuai@fnnas.com> Cc: Guangwu Zhang <guazhang@redhat.com> Fixes: 78c2713 ("block: move wbt_enable_default() out of queue freezing from sched ->exit()") Signed-off-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Nilay Shroff <nilay@linux.ibm.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 6327618 commit 9869d3a

6 files changed

Lines changed: 23 additions & 11 deletions

File tree

block/bfq-iosched.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7181,7 +7181,7 @@ static void bfq_exit_queue(struct elevator_queue *e)
71817181

71827182
blk_stat_disable_accounting(bfqd->queue);
71837183
blk_queue_flag_clear(QUEUE_FLAG_DISABLE_WBT_DEF, bfqd->queue);
7184-
set_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT, &e->flags);
7184+
wbt_enable_default(bfqd->queue->disk);
71857185

71867186
kfree(bfqd);
71877187
}

block/blk-sysfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ int blk_register_queue(struct gendisk *disk)
932932
elevator_set_default(q);
933933

934934
blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q);
935-
wbt_enable_default(disk);
935+
wbt_init_enable_default(disk);
936936

937937
/* Now everything is ready and send out KOBJ_ADD uevent */
938938
kobject_uevent(&disk->queue_kobj, KOBJ_ADD);

block/blk-wbt.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ static void wbt_requeue(struct rq_qos *rqos, struct request *rq)
699699
/*
700700
* Enable wbt if defaults are configured that way
701701
*/
702-
void wbt_enable_default(struct gendisk *disk)
702+
static bool __wbt_enable_default(struct gendisk *disk)
703703
{
704704
struct request_queue *q = disk->queue;
705705
struct rq_qos *rqos;
@@ -716,19 +716,31 @@ void wbt_enable_default(struct gendisk *disk)
716716
if (enable && RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT)
717717
RQWB(rqos)->enable_state = WBT_STATE_ON_DEFAULT;
718718
mutex_unlock(&disk->rqos_state_mutex);
719-
return;
719+
return false;
720720
}
721721
mutex_unlock(&disk->rqos_state_mutex);
722722

723723
/* Queue not registered? Maybe shutting down... */
724724
if (!blk_queue_registered(q))
725-
return;
725+
return false;
726726

727727
if (queue_is_mq(q) && enable)
728-
wbt_init(disk);
728+
return true;
729+
return false;
730+
}
731+
732+
void wbt_enable_default(struct gendisk *disk)
733+
{
734+
__wbt_enable_default(disk);
729735
}
730736
EXPORT_SYMBOL_GPL(wbt_enable_default);
731737

738+
void wbt_init_enable_default(struct gendisk *disk)
739+
{
740+
if (__wbt_enable_default(disk))
741+
WARN_ON_ONCE(wbt_init(disk));
742+
}
743+
732744
u64 wbt_default_latency_nsec(struct request_queue *q)
733745
{
734746
/*

block/blk-wbt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifdef CONFIG_BLK_WBT
66

77
int wbt_init(struct gendisk *disk);
8+
void wbt_init_enable_default(struct gendisk *disk);
89
void wbt_disable_default(struct gendisk *disk);
910
void wbt_enable_default(struct gendisk *disk);
1011

@@ -16,6 +17,10 @@ u64 wbt_default_latency_nsec(struct request_queue *);
1617

1718
#else
1819

20+
static inline void wbt_init_enable_default(struct gendisk *disk)
21+
{
22+
}
23+
1924
static inline void wbt_disable_default(struct gendisk *disk)
2025
{
2126
}

block/elevator.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -633,14 +633,10 @@ static int elevator_change_done(struct request_queue *q,
633633
.et = ctx->old->et,
634634
.data = ctx->old->elevator_data
635635
};
636-
bool enable_wbt = test_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT,
637-
&ctx->old->flags);
638636

639637
elv_unregister_queue(q, ctx->old);
640638
blk_mq_free_sched_res(&res, ctx->old->type, q->tag_set);
641639
kobject_put(&ctx->old->kobj);
642-
if (enable_wbt)
643-
wbt_enable_default(q->disk);
644640
}
645641
if (ctx->new) {
646642
ret = elv_register_queue(q, ctx->new, !ctx->no_uevent);

block/elevator.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ struct elevator_queue
156156

157157
#define ELEVATOR_FLAG_REGISTERED 0
158158
#define ELEVATOR_FLAG_DYING 1
159-
#define ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT 2
160159

161160
/*
162161
* block elevator interface

0 commit comments

Comments
 (0)