@@ -4412,6 +4412,15 @@ struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q,
4412
4412
}
4413
4413
EXPORT_SYMBOL (blk_mq_alloc_disk_for_queue );
4414
4414
4415
+ /*
4416
+ * Only hctx removed from cpuhp list can be reused
4417
+ */
4418
+ static bool blk_mq_hctx_is_reusable (struct blk_mq_hw_ctx * hctx )
4419
+ {
4420
+ return hlist_unhashed (& hctx -> cpuhp_online ) &&
4421
+ hlist_unhashed (& hctx -> cpuhp_dead );
4422
+ }
4423
+
4415
4424
static struct blk_mq_hw_ctx * blk_mq_alloc_and_init_hctx (
4416
4425
struct blk_mq_tag_set * set , struct request_queue * q ,
4417
4426
int hctx_idx , int node )
@@ -4421,7 +4430,7 @@ static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx(
4421
4430
/* reuse dead hctx first */
4422
4431
spin_lock (& q -> unused_hctx_lock );
4423
4432
list_for_each_entry (tmp , & q -> unused_hctx_list , hctx_list ) {
4424
- if (tmp -> numa_node == node ) {
4433
+ if (tmp -> numa_node == node && blk_mq_hctx_is_reusable ( tmp ) ) {
4425
4434
hctx = tmp ;
4426
4435
break ;
4427
4436
}
@@ -4453,8 +4462,7 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
4453
4462
unsigned long i , j ;
4454
4463
4455
4464
/* protect against switching io scheduler */
4456
- lockdep_assert_held (& q -> sysfs_lock );
4457
-
4465
+ mutex_lock (& q -> sysfs_lock );
4458
4466
for (i = 0 ; i < set -> nr_hw_queues ; i ++ ) {
4459
4467
int old_node ;
4460
4468
int node = blk_mq_get_hctx_node (set , i );
@@ -4487,6 +4495,7 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
4487
4495
4488
4496
xa_for_each_start (& q -> hctx_table , j , hctx , j )
4489
4497
blk_mq_exit_hctx (q , set , hctx , j );
4498
+ mutex_unlock (& q -> sysfs_lock );
4490
4499
4491
4500
/* unregister cpuhp callbacks for exited hctxs */
4492
4501
blk_mq_remove_hw_queues_cpuhp (q );
@@ -4518,14 +4527,10 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
4518
4527
4519
4528
xa_init (& q -> hctx_table );
4520
4529
4521
- mutex_lock (& q -> sysfs_lock );
4522
-
4523
4530
blk_mq_realloc_hw_ctxs (set , q );
4524
4531
if (!q -> nr_hw_queues )
4525
4532
goto err_hctxs ;
4526
4533
4527
- mutex_unlock (& q -> sysfs_lock );
4528
-
4529
4534
INIT_WORK (& q -> timeout_work , blk_mq_timeout_work );
4530
4535
blk_queue_rq_timeout (q , set -> timeout ? set -> timeout : 30 * HZ );
4531
4536
@@ -4544,7 +4549,6 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
4544
4549
return 0 ;
4545
4550
4546
4551
err_hctxs :
4547
- mutex_unlock (& q -> sysfs_lock );
4548
4552
blk_mq_release (q );
4549
4553
err_exit :
4550
4554
q -> mq_ops = NULL ;
@@ -4925,12 +4929,12 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
4925
4929
return false;
4926
4930
4927
4931
/* q->elevator needs protection from ->sysfs_lock */
4928
- lockdep_assert_held (& q -> sysfs_lock );
4932
+ mutex_lock (& q -> sysfs_lock );
4929
4933
4930
4934
/* the check has to be done with holding sysfs_lock */
4931
4935
if (!q -> elevator ) {
4932
4936
kfree (qe );
4933
- goto out ;
4937
+ goto unlock ;
4934
4938
}
4935
4939
4936
4940
INIT_LIST_HEAD (& qe -> node );
@@ -4940,7 +4944,9 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
4940
4944
__elevator_get (qe -> type );
4941
4945
list_add (& qe -> node , head );
4942
4946
elevator_disable (q );
4943
- out :
4947
+ unlock :
4948
+ mutex_unlock (& q -> sysfs_lock );
4949
+
4944
4950
return true;
4945
4951
}
4946
4952
@@ -4969,9 +4975,11 @@ static void blk_mq_elv_switch_back(struct list_head *head,
4969
4975
list_del (& qe -> node );
4970
4976
kfree (qe );
4971
4977
4978
+ mutex_lock (& q -> sysfs_lock );
4972
4979
elevator_switch (q , t );
4973
4980
/* drop the reference acquired in blk_mq_elv_switch_none */
4974
4981
elevator_put (t );
4982
+ mutex_unlock (& q -> sysfs_lock );
4975
4983
}
4976
4984
4977
4985
static void __blk_mq_update_nr_hw_queues (struct blk_mq_tag_set * set ,
@@ -4991,11 +4999,8 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
4991
4999
if (set -> nr_maps == 1 && nr_hw_queues == set -> nr_hw_queues )
4992
5000
return ;
4993
5001
4994
- list_for_each_entry (q , & set -> tag_list , tag_set_list ) {
4995
- mutex_lock (& q -> sysfs_dir_lock );
4996
- mutex_lock (& q -> sysfs_lock );
5002
+ list_for_each_entry (q , & set -> tag_list , tag_set_list )
4997
5003
blk_mq_freeze_queue (q );
4998
- }
4999
5004
/*
5000
5005
* Switch IO scheduler to 'none', cleaning up the data associated
5001
5006
* with the previous scheduler. We will switch back once we are done
@@ -5051,11 +5056,8 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
5051
5056
list_for_each_entry (q , & set -> tag_list , tag_set_list )
5052
5057
blk_mq_elv_switch_back (& head , q );
5053
5058
5054
- list_for_each_entry (q , & set -> tag_list , tag_set_list ) {
5059
+ list_for_each_entry (q , & set -> tag_list , tag_set_list )
5055
5060
blk_mq_unfreeze_queue (q );
5056
- mutex_unlock (& q -> sysfs_lock );
5057
- mutex_unlock (& q -> sysfs_dir_lock );
5058
- }
5059
5061
5060
5062
/* Free the excess tags when nr_hw_queues shrink. */
5061
5063
for (i = set -> nr_hw_queues ; i < prev_nr_hw_queues ; i ++ )
0 commit comments