@@ -4412,6 +4412,15 @@ struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q,
44124412}
44134413EXPORT_SYMBOL (blk_mq_alloc_disk_for_queue );
44144414
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+
44154424static struct blk_mq_hw_ctx * blk_mq_alloc_and_init_hctx (
44164425 struct blk_mq_tag_set * set , struct request_queue * q ,
44174426 int hctx_idx , int node )
@@ -4421,7 +4430,7 @@ static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx(
44214430 /* reuse dead hctx first */
44224431 spin_lock (& q -> unused_hctx_lock );
44234432 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 ) ) {
44254434 hctx = tmp ;
44264435 break ;
44274436 }
@@ -4453,8 +4462,7 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
44534462 unsigned long i , j ;
44544463
44554464 /* protect against switching io scheduler */
4456- lockdep_assert_held (& q -> sysfs_lock );
4457-
4465+ mutex_lock (& q -> sysfs_lock );
44584466 for (i = 0 ; i < set -> nr_hw_queues ; i ++ ) {
44594467 int old_node ;
44604468 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,
44874495
44884496 xa_for_each_start (& q -> hctx_table , j , hctx , j )
44894497 blk_mq_exit_hctx (q , set , hctx , j );
4498+ mutex_unlock (& q -> sysfs_lock );
44904499
44914500 /* unregister cpuhp callbacks for exited hctxs */
44924501 blk_mq_remove_hw_queues_cpuhp (q );
@@ -4518,14 +4527,10 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
45184527
45194528 xa_init (& q -> hctx_table );
45204529
4521- mutex_lock (& q -> sysfs_lock );
4522-
45234530 blk_mq_realloc_hw_ctxs (set , q );
45244531 if (!q -> nr_hw_queues )
45254532 goto err_hctxs ;
45264533
4527- mutex_unlock (& q -> sysfs_lock );
4528-
45294534 INIT_WORK (& q -> timeout_work , blk_mq_timeout_work );
45304535 blk_queue_rq_timeout (q , set -> timeout ? set -> timeout : 30 * HZ );
45314536
@@ -4544,7 +4549,6 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
45444549 return 0 ;
45454550
45464551err_hctxs :
4547- mutex_unlock (& q -> sysfs_lock );
45484552 blk_mq_release (q );
45494553err_exit :
45504554 q -> mq_ops = NULL ;
@@ -4925,12 +4929,12 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
49254929 return false;
49264930
49274931 /* q->elevator needs protection from ->sysfs_lock */
4928- lockdep_assert_held (& q -> sysfs_lock );
4932+ mutex_lock (& q -> sysfs_lock );
49294933
49304934 /* the check has to be done with holding sysfs_lock */
49314935 if (!q -> elevator ) {
49324936 kfree (qe );
4933- goto out ;
4937+ goto unlock ;
49344938 }
49354939
49364940 INIT_LIST_HEAD (& qe -> node );
@@ -4940,7 +4944,9 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
49404944 __elevator_get (qe -> type );
49414945 list_add (& qe -> node , head );
49424946 elevator_disable (q );
4943- out :
4947+ unlock :
4948+ mutex_unlock (& q -> sysfs_lock );
4949+
49444950 return true;
49454951}
49464952
@@ -4969,9 +4975,11 @@ static void blk_mq_elv_switch_back(struct list_head *head,
49694975 list_del (& qe -> node );
49704976 kfree (qe );
49714977
4978+ mutex_lock (& q -> sysfs_lock );
49724979 elevator_switch (q , t );
49734980 /* drop the reference acquired in blk_mq_elv_switch_none */
49744981 elevator_put (t );
4982+ mutex_unlock (& q -> sysfs_lock );
49754983}
49764984
49774985static 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,
49914999 if (set -> nr_maps == 1 && nr_hw_queues == set -> nr_hw_queues )
49925000 return ;
49935001
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 )
49975003 blk_mq_freeze_queue (q );
4998- }
49995004 /*
50005005 * Switch IO scheduler to 'none', cleaning up the data associated
50015006 * 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,
50515056 list_for_each_entry (q , & set -> tag_list , tag_set_list )
50525057 blk_mq_elv_switch_back (& head , q );
50535058
5054- list_for_each_entry (q , & set -> tag_list , tag_set_list ) {
5059+ list_for_each_entry (q , & set -> tag_list , tag_set_list )
50555060 blk_mq_unfreeze_queue (q );
5056- mutex_unlock (& q -> sysfs_lock );
5057- mutex_unlock (& q -> sysfs_dir_lock );
5058- }
50595061
50605062 /* Free the excess tags when nr_hw_queues shrink. */
50615063 for (i = set -> nr_hw_queues ; i < prev_nr_hw_queues ; i ++ )
0 commit comments