@@ -678,7 +678,7 @@ static void nvme_free_ns(struct kref *kref)
678
678
kfree (ns );
679
679
}
680
680
681
- static inline bool nvme_get_ns (struct nvme_ns * ns )
681
+ bool nvme_get_ns (struct nvme_ns * ns )
682
682
{
683
683
return kref_get_unless_zero (& ns -> kref );
684
684
}
@@ -3684,9 +3684,10 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
3684
3684
struct nvme_ns * nvme_find_get_ns (struct nvme_ctrl * ctrl , unsigned nsid )
3685
3685
{
3686
3686
struct nvme_ns * ns , * ret = NULL ;
3687
+ int srcu_idx ;
3687
3688
3688
- down_read (& ctrl -> namespaces_rwsem );
3689
- list_for_each_entry (ns , & ctrl -> namespaces , list ) {
3689
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
3690
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list ) {
3690
3691
if (ns -> head -> ns_id == nsid ) {
3691
3692
if (!nvme_get_ns (ns ))
3692
3693
continue ;
@@ -3696,7 +3697,7 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
3696
3697
if (ns -> head -> ns_id > nsid )
3697
3698
break ;
3698
3699
}
3699
- up_read (& ctrl -> namespaces_rwsem );
3700
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
3700
3701
return ret ;
3701
3702
}
3702
3703
EXPORT_SYMBOL_NS_GPL (nvme_find_get_ns , NVME_TARGET_PASSTHRU );
@@ -3710,7 +3711,7 @@ static void nvme_ns_add_to_ctrl_list(struct nvme_ns *ns)
3710
3711
3711
3712
list_for_each_entry_reverse (tmp , & ns -> ctrl -> namespaces , list ) {
3712
3713
if (tmp -> head -> ns_id < ns -> head -> ns_id ) {
3713
- list_add (& ns -> list , & tmp -> list );
3714
+ list_add_rcu (& ns -> list , & tmp -> list );
3714
3715
return ;
3715
3716
}
3716
3717
}
@@ -3776,17 +3777,18 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
3776
3777
if (nvme_update_ns_info (ns , info ))
3777
3778
goto out_unlink_ns ;
3778
3779
3779
- down_write (& ctrl -> namespaces_rwsem );
3780
+ mutex_lock (& ctrl -> namespaces_lock );
3780
3781
/*
3781
3782
* Ensure that no namespaces are added to the ctrl list after the queues
3782
3783
* are frozen, thereby avoiding a deadlock between scan and reset.
3783
3784
*/
3784
3785
if (test_bit (NVME_CTRL_FROZEN , & ctrl -> flags )) {
3785
- up_write (& ctrl -> namespaces_rwsem );
3786
+ mutex_unlock (& ctrl -> namespaces_lock );
3786
3787
goto out_unlink_ns ;
3787
3788
}
3788
3789
nvme_ns_add_to_ctrl_list (ns );
3789
- up_write (& ctrl -> namespaces_rwsem );
3790
+ mutex_unlock (& ctrl -> namespaces_lock );
3791
+ synchronize_srcu (& ctrl -> srcu );
3790
3792
nvme_get_ctrl (ctrl );
3791
3793
3792
3794
if (device_add_disk (ctrl -> device , ns -> disk , nvme_ns_attr_groups ))
@@ -3809,9 +3811,10 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
3809
3811
3810
3812
out_cleanup_ns_from_list :
3811
3813
nvme_put_ctrl (ctrl );
3812
- down_write (& ctrl -> namespaces_rwsem );
3813
- list_del_init (& ns -> list );
3814
- up_write (& ctrl -> namespaces_rwsem );
3814
+ mutex_lock (& ctrl -> namespaces_lock );
3815
+ list_del_rcu (& ns -> list );
3816
+ mutex_unlock (& ctrl -> namespaces_lock );
3817
+ synchronize_srcu (& ctrl -> srcu );
3815
3818
out_unlink_ns :
3816
3819
mutex_lock (& ctrl -> subsys -> lock );
3817
3820
list_del_rcu (& ns -> siblings );
@@ -3861,9 +3864,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)
3861
3864
nvme_cdev_del (& ns -> cdev , & ns -> cdev_device );
3862
3865
del_gendisk (ns -> disk );
3863
3866
3864
- down_write (& ns -> ctrl -> namespaces_rwsem );
3865
- list_del_init (& ns -> list );
3866
- up_write (& ns -> ctrl -> namespaces_rwsem );
3867
+ mutex_lock (& ns -> ctrl -> namespaces_lock );
3868
+ list_del_rcu (& ns -> list );
3869
+ mutex_unlock (& ns -> ctrl -> namespaces_lock );
3870
+ synchronize_srcu (& ns -> ctrl -> srcu );
3867
3871
3868
3872
if (last_path )
3869
3873
nvme_mpath_shutdown_disk (ns -> head );
@@ -3953,16 +3957,17 @@ static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
3953
3957
struct nvme_ns * ns , * next ;
3954
3958
LIST_HEAD (rm_list );
3955
3959
3956
- down_write (& ctrl -> namespaces_rwsem );
3960
+ mutex_lock (& ctrl -> namespaces_lock );
3957
3961
list_for_each_entry_safe (ns , next , & ctrl -> namespaces , list ) {
3958
3962
if (ns -> head -> ns_id > nsid )
3959
- list_move_tail (& ns -> list , & rm_list );
3963
+ list_splice_init_rcu (& ns -> list , & rm_list ,
3964
+ synchronize_rcu );
3960
3965
}
3961
- up_write (& ctrl -> namespaces_rwsem );
3966
+ mutex_unlock (& ctrl -> namespaces_lock );
3967
+ synchronize_srcu (& ctrl -> srcu );
3962
3968
3963
3969
list_for_each_entry_safe (ns , next , & rm_list , list )
3964
3970
nvme_ns_remove (ns );
3965
-
3966
3971
}
3967
3972
3968
3973
static int nvme_scan_ns_list (struct nvme_ctrl * ctrl )
@@ -4132,9 +4137,10 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
4132
4137
/* this is a no-op when called from the controller reset handler */
4133
4138
nvme_change_ctrl_state (ctrl , NVME_CTRL_DELETING_NOIO );
4134
4139
4135
- down_write (& ctrl -> namespaces_rwsem );
4136
- list_splice_init (& ctrl -> namespaces , & ns_list );
4137
- up_write (& ctrl -> namespaces_rwsem );
4140
+ mutex_lock (& ctrl -> namespaces_lock );
4141
+ list_splice_init_rcu (& ctrl -> namespaces , & ns_list , synchronize_rcu );
4142
+ mutex_unlock (& ctrl -> namespaces_lock );
4143
+ synchronize_srcu (& ctrl -> srcu );
4138
4144
4139
4145
list_for_each_entry_safe (ns , next , & ns_list , list )
4140
4146
nvme_ns_remove (ns );
@@ -4582,6 +4588,7 @@ static void nvme_free_ctrl(struct device *dev)
4582
4588
key_put (ctrl -> tls_key );
4583
4589
nvme_free_cels (ctrl );
4584
4590
nvme_mpath_uninit (ctrl );
4591
+ cleanup_srcu_struct (& ctrl -> srcu );
4585
4592
nvme_auth_stop (ctrl );
4586
4593
nvme_auth_free (ctrl );
4587
4594
__free_page (ctrl -> discard_page );
@@ -4614,10 +4621,15 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
4614
4621
ctrl -> passthru_err_log_enabled = false;
4615
4622
clear_bit (NVME_CTRL_FAILFAST_EXPIRED , & ctrl -> flags );
4616
4623
spin_lock_init (& ctrl -> lock );
4624
+ mutex_init (& ctrl -> namespaces_lock );
4625
+
4626
+ ret = init_srcu_struct (& ctrl -> srcu );
4627
+ if (ret )
4628
+ return ret ;
4629
+
4617
4630
mutex_init (& ctrl -> scan_lock );
4618
4631
INIT_LIST_HEAD (& ctrl -> namespaces );
4619
4632
xa_init (& ctrl -> cels );
4620
- init_rwsem (& ctrl -> namespaces_rwsem );
4621
4633
ctrl -> dev = dev ;
4622
4634
ctrl -> ops = ops ;
4623
4635
ctrl -> quirks = quirks ;
@@ -4697,6 +4709,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
4697
4709
out :
4698
4710
if (ctrl -> discard_page )
4699
4711
__free_page (ctrl -> discard_page );
4712
+ cleanup_srcu_struct (& ctrl -> srcu );
4700
4713
return ret ;
4701
4714
}
4702
4715
EXPORT_SYMBOL_GPL (nvme_init_ctrl );
@@ -4705,61 +4718,66 @@ EXPORT_SYMBOL_GPL(nvme_init_ctrl);
4705
4718
void nvme_mark_namespaces_dead (struct nvme_ctrl * ctrl )
4706
4719
{
4707
4720
struct nvme_ns * ns ;
4721
+ int srcu_idx ;
4708
4722
4709
- down_read (& ctrl -> namespaces_rwsem );
4710
- list_for_each_entry (ns , & ctrl -> namespaces , list )
4723
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
4724
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list )
4711
4725
blk_mark_disk_dead (ns -> disk );
4712
- up_read (& ctrl -> namespaces_rwsem );
4726
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
4713
4727
}
4714
4728
EXPORT_SYMBOL_GPL (nvme_mark_namespaces_dead );
4715
4729
4716
4730
void nvme_unfreeze (struct nvme_ctrl * ctrl )
4717
4731
{
4718
4732
struct nvme_ns * ns ;
4733
+ int srcu_idx ;
4719
4734
4720
- down_read (& ctrl -> namespaces_rwsem );
4721
- list_for_each_entry (ns , & ctrl -> namespaces , list )
4735
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
4736
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list )
4722
4737
blk_mq_unfreeze_queue (ns -> queue );
4723
- up_read (& ctrl -> namespaces_rwsem );
4738
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
4724
4739
clear_bit (NVME_CTRL_FROZEN , & ctrl -> flags );
4725
4740
}
4726
4741
EXPORT_SYMBOL_GPL (nvme_unfreeze );
4727
4742
4728
4743
int nvme_wait_freeze_timeout (struct nvme_ctrl * ctrl , long timeout )
4729
4744
{
4730
4745
struct nvme_ns * ns ;
4746
+ int srcu_idx ;
4731
4747
4732
- down_read (& ctrl -> namespaces_rwsem );
4733
- list_for_each_entry (ns , & ctrl -> namespaces , list ) {
4748
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
4749
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list ) {
4734
4750
timeout = blk_mq_freeze_queue_wait_timeout (ns -> queue , timeout );
4735
4751
if (timeout <= 0 )
4736
4752
break ;
4737
4753
}
4738
- up_read (& ctrl -> namespaces_rwsem );
4754
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
4739
4755
return timeout ;
4740
4756
}
4741
4757
EXPORT_SYMBOL_GPL (nvme_wait_freeze_timeout );
4742
4758
4743
4759
void nvme_wait_freeze (struct nvme_ctrl * ctrl )
4744
4760
{
4745
4761
struct nvme_ns * ns ;
4762
+ int srcu_idx ;
4746
4763
4747
- down_read (& ctrl -> namespaces_rwsem );
4748
- list_for_each_entry (ns , & ctrl -> namespaces , list )
4764
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
4765
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list )
4749
4766
blk_mq_freeze_queue_wait (ns -> queue );
4750
- up_read (& ctrl -> namespaces_rwsem );
4767
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
4751
4768
}
4752
4769
EXPORT_SYMBOL_GPL (nvme_wait_freeze );
4753
4770
4754
4771
void nvme_start_freeze (struct nvme_ctrl * ctrl )
4755
4772
{
4756
4773
struct nvme_ns * ns ;
4774
+ int srcu_idx ;
4757
4775
4758
4776
set_bit (NVME_CTRL_FROZEN , & ctrl -> flags );
4759
- down_read (& ctrl -> namespaces_rwsem );
4760
- list_for_each_entry (ns , & ctrl -> namespaces , list )
4777
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
4778
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list )
4761
4779
blk_freeze_queue_start (ns -> queue );
4762
- up_read (& ctrl -> namespaces_rwsem );
4780
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
4763
4781
}
4764
4782
EXPORT_SYMBOL_GPL (nvme_start_freeze );
4765
4783
@@ -4802,11 +4820,12 @@ EXPORT_SYMBOL_GPL(nvme_unquiesce_admin_queue);
4802
4820
void nvme_sync_io_queues (struct nvme_ctrl * ctrl )
4803
4821
{
4804
4822
struct nvme_ns * ns ;
4823
+ int srcu_idx ;
4805
4824
4806
- down_read (& ctrl -> namespaces_rwsem );
4807
- list_for_each_entry (ns , & ctrl -> namespaces , list )
4825
+ srcu_idx = srcu_read_lock (& ctrl -> srcu );
4826
+ list_for_each_entry_rcu (ns , & ctrl -> namespaces , list )
4808
4827
blk_sync_queue (ns -> queue );
4809
- up_read (& ctrl -> namespaces_rwsem );
4828
+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
4810
4829
}
4811
4830
EXPORT_SYMBOL_GPL (nvme_sync_io_queues );
4812
4831
0 commit comments