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_control 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 control handle.

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
8c91302a 44a0acb2

+36 -32
+36 -32
drivers/reset/core.c
··· 49 49 * @triggered_count: Number of times this reset line has been reset. Currently 50 50 * only used for shared resets, which means that the value 51 51 * will be either 0 or 1. 52 + * @lock: serializes the internals of reset_control_acquire() 52 53 */ 53 54 struct reset_control { 54 55 struct reset_controller_dev __rcu *rcdev; ··· 62 61 bool array; 63 62 atomic_t deassert_count; 64 63 atomic_t triggered_count; 64 + struct mutex lock; 65 65 }; 66 66 67 67 /** ··· 709 707 if (reset_control_is_array(rstc)) 710 708 return reset_control_array_acquire(rstc_to_array(rstc)); 711 709 712 - guard(mutex)(&reset_list_mutex); 710 + guard(mutex)(&rstc->lock); 713 711 714 712 if (rstc->acquired) 715 713 return 0; ··· 861 859 list_add(&rstc->list, &rcdev->reset_control_head); 862 860 rstc->id = index; 863 861 kref_init(&rstc->refcnt); 862 + mutex_init(&rstc->lock); 864 863 rstc->acquired = acquired; 865 864 rstc->shared = shared; 866 865 get_device(rcdev->dev); ··· 875 872 refcnt); 876 873 struct reset_controller_dev *rcdev; 877 874 878 - lockdep_assert_held(&reset_list_mutex); 875 + lockdep_assert_held(&rstc->srcu); 879 876 880 - scoped_guard(srcu, &rstc->srcu) { 881 - rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true); 882 - if (rcdev) { 883 - guard(mutex)(&rcdev->lock); 884 - reset_controller_remove(rcdev, rstc); 885 - } 877 + rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true); 878 + if (rcdev) { 879 + lockdep_assert_held(&rcdev->lock); 880 + reset_controller_remove(rcdev, rstc); 886 881 } 887 882 888 - synchronize_srcu(&rstc->srcu); 889 - cleanup_srcu_struct(&rstc->srcu); 890 - kfree(rstc); 883 + mutex_destroy(&rstc->lock); 891 884 } 892 885 893 - static void __reset_control_put_internal(struct reset_control *rstc) 886 + static void reset_control_put_internal(struct reset_control *rstc) 894 887 { 895 - lockdep_assert_held(&reset_list_mutex); 888 + struct reset_controller_dev *rcdev; 889 + int ret = 0; 896 890 897 891 if (IS_ERR_OR_NULL(rstc)) 898 892 return; 899 893 900 - kref_put(&rstc->refcnt, __reset_control_release); 894 + scoped_guard(srcu, &rstc->srcu) { 895 + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); 896 + if (!rcdev) 897 + /* Already released. */ 898 + return; 899 + 900 + guard(mutex)(&rcdev->lock); 901 + ret = kref_put(&rstc->refcnt, __reset_control_release); 902 + } 903 + 904 + if (ret) { 905 + synchronize_srcu(&rstc->srcu); 906 + cleanup_srcu_struct(&rstc->srcu); 907 + kfree(rstc); 908 + } 901 909 } 902 910 903 911 static void reset_gpio_aux_device_release(struct device *dev) ··· 1118 1104 { 1119 1105 bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; 1120 1106 bool gpio_fallback = false; 1121 - struct reset_control *rstc; 1107 + struct reset_control *rstc = ERR_PTR(-EINVAL); 1122 1108 struct reset_controller_dev *rcdev; 1123 1109 struct of_phandle_args args; 1124 1110 int rstc_id; ··· 1183 1169 1184 1170 flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL; 1185 1171 1186 - /* reset_list_mutex also protects the rcdev's reset_control list */ 1187 - rstc = __reset_control_get_internal(rcdev, rstc_id, flags); 1172 + scoped_guard(mutex, &rcdev->lock) 1173 + rstc = __reset_control_get_internal(rcdev, rstc_id, flags); 1188 1174 1189 1175 out_put: 1190 1176 of_node_put(args.np); ··· 1227 1213 return 0; 1228 1214 1229 1215 err: 1230 - guard(mutex)(&reset_list_mutex); 1231 - 1232 1216 while (i--) 1233 - __reset_control_put_internal(rstcs[i].rstc); 1217 + reset_control_put_internal(rstcs[i].rstc); 1234 1218 1235 1219 return ret; 1236 1220 } ··· 1238 1226 { 1239 1227 int i; 1240 1228 1241 - guard(mutex)(&reset_list_mutex); 1242 - 1243 1229 for (i = 0; i < resets->num_rstcs; i++) 1244 - __reset_control_put_internal(resets->rstc[i]); 1230 + reset_control_put_internal(resets->rstc[i]); 1245 1231 kfree(resets); 1246 1232 } 1247 1233 ··· 1257 1247 return; 1258 1248 } 1259 1249 1260 - guard(mutex)(&reset_list_mutex); 1261 - 1262 - __reset_control_put_internal(rstc); 1250 + reset_control_put_internal(rstc); 1263 1251 } 1264 1252 EXPORT_SYMBOL_GPL(reset_control_put); 1265 1253 ··· 1268 1260 */ 1269 1261 void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs) 1270 1262 { 1271 - guard(mutex)(&reset_list_mutex); 1272 - 1273 1263 while (num_rstcs--) 1274 - __reset_control_put_internal(rstcs[num_rstcs].rstc); 1264 + reset_control_put_internal(rstcs[num_rstcs].rstc); 1275 1265 } 1276 1266 EXPORT_SYMBOL_GPL(reset_control_bulk_put); 1277 1267 ··· 1488 1482 return &resets->base; 1489 1483 1490 1484 err_rst: 1491 - guard(mutex)(&reset_list_mutex); 1492 - 1493 1485 while (--i >= 0) 1494 - __reset_control_put_internal(resets->rstc[i]); 1486 + reset_control_put_internal(resets->rstc[i]); 1495 1487 1496 1488 kfree(resets); 1497 1489