Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

reset: protect struct reset_controller_dev with its own mutex

Currently we use a single, global mutex - misleadingly names
reset_list_mutex - to protect the global list of reset devices,
per-controller list of reset control handles and also internal fields of
struct reset_control. Locking can be made a lot more fine-grained if we
use a separate mutex for serializing operations on the list AND
accessing the reset controller device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Bartosz Golaszewski and committed by
Philipp Zabel
44a0acb2 78ebbff6

+30 -17
+27 -17
drivers/reset/core.c
··· 131 131 } 132 132 133 133 INIT_LIST_HEAD(&rcdev->reset_control_head); 134 + mutex_init(&rcdev->lock); 134 135 135 136 guard(mutex)(&reset_list_mutex); 136 137 ··· 144 143 static void reset_controller_remove(struct reset_controller_dev *rcdev, 145 144 struct reset_control *rstc) 146 145 { 146 + lockdep_assert_held(&rcdev->lock); 147 + 147 148 list_del(&rstc->list); 148 149 module_put(rcdev->owner); 149 150 put_device(rcdev->dev); ··· 159 156 { 160 157 struct reset_control *rstc, *pos; 161 158 162 - guard(mutex)(&reset_list_mutex); 159 + scoped_guard(mutex, &reset_list_mutex) 160 + list_del(&rcdev->list); 163 161 164 - list_del(&rcdev->list); 165 - 166 - /* 167 - * Numb but don't free the remaining reset control handles that are 168 - * still held by consumers. 169 - */ 170 - list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) { 171 - rcu_assign_pointer(rstc->rcdev, NULL); 172 - synchronize_srcu(&rstc->srcu); 173 - reset_controller_remove(rcdev, rstc); 162 + scoped_guard(mutex, &rcdev->lock) { 163 + /* 164 + * Numb but don't free the remaining reset control handles that are 165 + * still held by consumers. 166 + */ 167 + list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) { 168 + rcu_assign_pointer(rstc->rcdev, NULL); 169 + synchronize_srcu(&rstc->srcu); 170 + reset_controller_remove(rcdev, rstc); 171 + } 174 172 } 173 + 174 + mutex_destroy(&rcdev->lock); 175 175 } 176 176 EXPORT_SYMBOL_GPL(reset_controller_unregister); 177 177 ··· 718 712 if (!rcdev) 719 713 return -ENODEV; 720 714 721 - list_for_each_entry(rc, &rcdev->reset_control_head, list) { 722 - if (rstc != rc && rstc->id == rc->id) { 723 - if (rc->acquired) 724 - return -EBUSY; 715 + scoped_guard(mutex, &rcdev->lock) { 716 + list_for_each_entry(rc, &rcdev->reset_control_head, list) { 717 + if (rstc != rc && rstc->id == rc->id) { 718 + if (rc->acquired) 719 + return -EBUSY; 720 + } 725 721 } 726 722 } 727 723 ··· 814 806 struct reset_control *rstc; 815 807 int ret; 816 808 817 - lockdep_assert_held(&reset_list_mutex); 809 + lockdep_assert_held(&rcdev->lock); 818 810 819 811 /* Expect callers to filter out OPTIONAL and DEASSERTED bits */ 820 812 if (WARN_ON(flags & ~(RESET_CONTROL_FLAGS_BIT_SHARED | ··· 876 868 877 869 scoped_guard(srcu, &rstc->srcu) { 878 870 rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true); 879 - if (rcdev) 871 + if (rcdev) { 872 + guard(mutex)(&rcdev->lock); 880 873 reset_controller_remove(rcdev, rstc); 874 + } 881 875 } 882 876 883 877 synchronize_srcu(&rstc->srcu);
+3
include/linux/reset-controller.h
··· 3 3 #define _LINUX_RESET_CONTROLLER_H_ 4 4 5 5 #include <linux/list.h> 6 + #include <linux/mutex.h> 6 7 7 8 struct reset_controller_dev; 8 9 ··· 41 40 * device tree to id as given to the reset control ops, defaults 42 41 * to :c:func:`of_reset_simple_xlate`. 43 42 * @nr_resets: number of reset controls in this reset controller device 43 + * @lock: protects the reset control list from concurrent access 44 44 */ 45 45 struct reset_controller_dev { 46 46 const struct reset_control_ops *ops; ··· 54 52 int (*of_xlate)(struct reset_controller_dev *rcdev, 55 53 const struct of_phandle_args *reset_spec); 56 54 unsigned int nr_resets; 55 + struct mutex lock; 57 56 }; 58 57 59 58 #if IS_ENABLED(CONFIG_RESET_CONTROLLER)