@@ -678,7 +678,7 @@ static void nvme_free_ns(struct kref *kref)
678678 kfree (ns );
679679}
680680
681- static inline bool nvme_get_ns (struct nvme_ns * ns )
681+ bool nvme_get_ns (struct nvme_ns * ns )
682682{
683683 return kref_get_unless_zero (& ns -> kref );
684684}
@@ -3684,9 +3684,10 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
36843684struct nvme_ns * nvme_find_get_ns (struct nvme_ctrl * ctrl , unsigned nsid )
36853685{
36863686 struct nvme_ns * ns , * ret = NULL ;
3687+ int srcu_idx ;
36873688
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 ) {
36903691 if (ns -> head -> ns_id == nsid ) {
36913692 if (!nvme_get_ns (ns ))
36923693 continue ;
@@ -3696,7 +3697,7 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
36963697 if (ns -> head -> ns_id > nsid )
36973698 break ;
36983699 }
3699- up_read (& ctrl -> namespaces_rwsem );
3700+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
37003701 return ret ;
37013702}
37023703EXPORT_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)
37103711
37113712 list_for_each_entry_reverse (tmp , & ns -> ctrl -> namespaces , list ) {
37123713 if (tmp -> head -> ns_id < ns -> head -> ns_id ) {
3713- list_add (& ns -> list , & tmp -> list );
3714+ list_add_rcu (& ns -> list , & tmp -> list );
37143715 return ;
37153716 }
37163717 }
@@ -3776,17 +3777,18 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
37763777 if (nvme_update_ns_info (ns , info ))
37773778 goto out_unlink_ns ;
37783779
3779- down_write (& ctrl -> namespaces_rwsem );
3780+ mutex_lock (& ctrl -> namespaces_lock );
37803781 /*
37813782 * Ensure that no namespaces are added to the ctrl list after the queues
37823783 * are frozen, thereby avoiding a deadlock between scan and reset.
37833784 */
37843785 if (test_bit (NVME_CTRL_FROZEN , & ctrl -> flags )) {
3785- up_write (& ctrl -> namespaces_rwsem );
3786+ mutex_unlock (& ctrl -> namespaces_lock );
37863787 goto out_unlink_ns ;
37873788 }
37883789 nvme_ns_add_to_ctrl_list (ns );
3789- up_write (& ctrl -> namespaces_rwsem );
3790+ mutex_unlock (& ctrl -> namespaces_lock );
3791+ synchronize_srcu (& ctrl -> srcu );
37903792 nvme_get_ctrl (ctrl );
37913793
37923794 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)
38093811
38103812 out_cleanup_ns_from_list :
38113813 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 );
38153818 out_unlink_ns :
38163819 mutex_lock (& ctrl -> subsys -> lock );
38173820 list_del_rcu (& ns -> siblings );
@@ -3861,9 +3864,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)
38613864 nvme_cdev_del (& ns -> cdev , & ns -> cdev_device );
38623865 del_gendisk (ns -> disk );
38633866
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 );
38673871
38683872 if (last_path )
38693873 nvme_mpath_shutdown_disk (ns -> head );
@@ -3953,16 +3957,17 @@ static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
39533957 struct nvme_ns * ns , * next ;
39543958 LIST_HEAD (rm_list );
39553959
3956- down_write (& ctrl -> namespaces_rwsem );
3960+ mutex_lock (& ctrl -> namespaces_lock );
39573961 list_for_each_entry_safe (ns , next , & ctrl -> namespaces , list ) {
39583962 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 );
39603965 }
3961- up_write (& ctrl -> namespaces_rwsem );
3966+ mutex_unlock (& ctrl -> namespaces_lock );
3967+ synchronize_srcu (& ctrl -> srcu );
39623968
39633969 list_for_each_entry_safe (ns , next , & rm_list , list )
39643970 nvme_ns_remove (ns );
3965-
39663971}
39673972
39683973static int nvme_scan_ns_list (struct nvme_ctrl * ctrl )
@@ -4132,9 +4137,10 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
41324137 /* this is a no-op when called from the controller reset handler */
41334138 nvme_change_ctrl_state (ctrl , NVME_CTRL_DELETING_NOIO );
41344139
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 );
41384144
41394145 list_for_each_entry_safe (ns , next , & ns_list , list )
41404146 nvme_ns_remove (ns );
@@ -4582,6 +4588,7 @@ static void nvme_free_ctrl(struct device *dev)
45824588 key_put (ctrl -> tls_key );
45834589 nvme_free_cels (ctrl );
45844590 nvme_mpath_uninit (ctrl );
4591+ cleanup_srcu_struct (& ctrl -> srcu );
45854592 nvme_auth_stop (ctrl );
45864593 nvme_auth_free (ctrl );
45874594 __free_page (ctrl -> discard_page );
@@ -4614,10 +4621,15 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
46144621 ctrl -> passthru_err_log_enabled = false;
46154622 clear_bit (NVME_CTRL_FAILFAST_EXPIRED , & ctrl -> flags );
46164623 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+
46174630 mutex_init (& ctrl -> scan_lock );
46184631 INIT_LIST_HEAD (& ctrl -> namespaces );
46194632 xa_init (& ctrl -> cels );
4620- init_rwsem (& ctrl -> namespaces_rwsem );
46214633 ctrl -> dev = dev ;
46224634 ctrl -> ops = ops ;
46234635 ctrl -> quirks = quirks ;
@@ -4697,6 +4709,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
46974709out :
46984710 if (ctrl -> discard_page )
46994711 __free_page (ctrl -> discard_page );
4712+ cleanup_srcu_struct (& ctrl -> srcu );
47004713 return ret ;
47014714}
47024715EXPORT_SYMBOL_GPL (nvme_init_ctrl );
@@ -4705,61 +4718,66 @@ EXPORT_SYMBOL_GPL(nvme_init_ctrl);
47054718void nvme_mark_namespaces_dead (struct nvme_ctrl * ctrl )
47064719{
47074720 struct nvme_ns * ns ;
4721+ int srcu_idx ;
47084722
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 )
47114725 blk_mark_disk_dead (ns -> disk );
4712- up_read (& ctrl -> namespaces_rwsem );
4726+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
47134727}
47144728EXPORT_SYMBOL_GPL (nvme_mark_namespaces_dead );
47154729
47164730void nvme_unfreeze (struct nvme_ctrl * ctrl )
47174731{
47184732 struct nvme_ns * ns ;
4733+ int srcu_idx ;
47194734
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 )
47224737 blk_mq_unfreeze_queue (ns -> queue );
4723- up_read (& ctrl -> namespaces_rwsem );
4738+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
47244739 clear_bit (NVME_CTRL_FROZEN , & ctrl -> flags );
47254740}
47264741EXPORT_SYMBOL_GPL (nvme_unfreeze );
47274742
47284743int nvme_wait_freeze_timeout (struct nvme_ctrl * ctrl , long timeout )
47294744{
47304745 struct nvme_ns * ns ;
4746+ int srcu_idx ;
47314747
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 ) {
47344750 timeout = blk_mq_freeze_queue_wait_timeout (ns -> queue , timeout );
47354751 if (timeout <= 0 )
47364752 break ;
47374753 }
4738- up_read (& ctrl -> namespaces_rwsem );
4754+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
47394755 return timeout ;
47404756}
47414757EXPORT_SYMBOL_GPL (nvme_wait_freeze_timeout );
47424758
47434759void nvme_wait_freeze (struct nvme_ctrl * ctrl )
47444760{
47454761 struct nvme_ns * ns ;
4762+ int srcu_idx ;
47464763
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 )
47494766 blk_mq_freeze_queue_wait (ns -> queue );
4750- up_read (& ctrl -> namespaces_rwsem );
4767+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
47514768}
47524769EXPORT_SYMBOL_GPL (nvme_wait_freeze );
47534770
47544771void nvme_start_freeze (struct nvme_ctrl * ctrl )
47554772{
47564773 struct nvme_ns * ns ;
4774+ int srcu_idx ;
47574775
47584776 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 )
47614779 blk_freeze_queue_start (ns -> queue );
4762- up_read (& ctrl -> namespaces_rwsem );
4780+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
47634781}
47644782EXPORT_SYMBOL_GPL (nvme_start_freeze );
47654783
@@ -4802,11 +4820,12 @@ EXPORT_SYMBOL_GPL(nvme_unquiesce_admin_queue);
48024820void nvme_sync_io_queues (struct nvme_ctrl * ctrl )
48034821{
48044822 struct nvme_ns * ns ;
4823+ int srcu_idx ;
48054824
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 )
48084827 blk_sync_queue (ns -> queue );
4809- up_read (& ctrl -> namespaces_rwsem );
4828+ srcu_read_unlock (& ctrl -> srcu , srcu_idx );
48104829}
48114830EXPORT_SYMBOL_GPL (nvme_sync_io_queues );
48124831
0 commit comments