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.

timers: Add shutdown mechanism to the internal functions

Tearing down timers which have circular dependencies to other
functionality, e.g. workqueues, where the timer can schedule work and work
can arm timers, is not trivial.

In those cases it is desired to shutdown the timer in a way which prevents
rearming of the timer. The mechanism to do so is to set timer->function to
NULL and use this as an indicator for the timer arming functions to ignore
the (re)arm request.

Add a shutdown argument to the relevant internal functions which makes the
actual deactivation code set timer->function to NULL which in turn prevents
rearming of the timer.

Co-developed-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home
Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org
Link: https://lore.kernel.org/r/20221123201625.253883224@linutronix.de

+54 -8
+54 -8
kernel/time/timer.c
··· 1300 1300 /** 1301 1301 * __timer_delete - Internal function: Deactivate a timer 1302 1302 * @timer: The timer to be deactivated 1303 + * @shutdown: If true, this indicates that the timer is about to be 1304 + * shutdown permanently. 1305 + * 1306 + * If @shutdown is true then @timer->function is set to NULL under the 1307 + * timer base lock which prevents further rearming of the time. In that 1308 + * case any attempt to rearm @timer after this function returns will be 1309 + * silently ignored. 1303 1310 * 1304 1311 * Return: 1305 1312 * * %0 - The timer was not pending 1306 1313 * * %1 - The timer was pending and deactivated 1307 1314 */ 1308 - static int __timer_delete(struct timer_list *timer) 1315 + static int __timer_delete(struct timer_list *timer, bool shutdown) 1309 1316 { 1310 1317 struct timer_base *base; 1311 1318 unsigned long flags; ··· 1320 1313 1321 1314 debug_assert_init(timer); 1322 1315 1323 - if (timer_pending(timer)) { 1316 + /* 1317 + * If @shutdown is set then the lock has to be taken whether the 1318 + * timer is pending or not to protect against a concurrent rearm 1319 + * which might hit between the lockless pending check and the lock 1320 + * aquisition. By taking the lock it is ensured that such a newly 1321 + * enqueued timer is dequeued and cannot end up with 1322 + * timer->function == NULL in the expiry code. 1323 + * 1324 + * If timer->function is currently executed, then this makes sure 1325 + * that the callback cannot requeue the timer. 1326 + */ 1327 + if (timer_pending(timer) || shutdown) { 1324 1328 base = lock_timer_base(timer, &flags); 1325 1329 ret = detach_if_pending(timer, base, true); 1330 + if (shutdown) 1331 + timer->function = NULL; 1326 1332 raw_spin_unlock_irqrestore(&base->lock, flags); 1327 1333 } 1328 1334 ··· 1358 1338 */ 1359 1339 int timer_delete(struct timer_list *timer) 1360 1340 { 1361 - return __timer_delete(timer); 1341 + return __timer_delete(timer, false); 1362 1342 } 1363 1343 EXPORT_SYMBOL(timer_delete); 1364 1344 1365 1345 /** 1366 1346 * __try_to_del_timer_sync - Internal function: Try to deactivate a timer 1367 1347 * @timer: Timer to deactivate 1348 + * @shutdown: If true, this indicates that the timer is about to be 1349 + * shutdown permanently. 1350 + * 1351 + * If @shutdown is true then @timer->function is set to NULL under the 1352 + * timer base lock which prevents further rearming of the timer. Any 1353 + * attempt to rearm @timer after this function returns will be silently 1354 + * ignored. 1355 + * 1356 + * This function cannot guarantee that the timer cannot be rearmed 1357 + * right after dropping the base lock if @shutdown is false. That 1358 + * needs to be prevented by the calling code if necessary. 1368 1359 * 1369 1360 * Return: 1370 1361 * * %0 - The timer was not pending 1371 1362 * * %1 - The timer was pending and deactivated 1372 1363 * * %-1 - The timer callback function is running on a different CPU 1373 1364 */ 1374 - static int __try_to_del_timer_sync(struct timer_list *timer) 1365 + static int __try_to_del_timer_sync(struct timer_list *timer, bool shutdown) 1375 1366 { 1376 1367 struct timer_base *base; 1377 1368 unsigned long flags; ··· 1394 1363 1395 1364 if (base->running_timer != timer) 1396 1365 ret = detach_if_pending(timer, base, true); 1366 + if (shutdown) 1367 + timer->function = NULL; 1397 1368 1398 1369 raw_spin_unlock_irqrestore(&base->lock, flags); 1399 1370 ··· 1420 1387 */ 1421 1388 int try_to_del_timer_sync(struct timer_list *timer) 1422 1389 { 1423 - return __try_to_del_timer_sync(timer); 1390 + return __try_to_del_timer_sync(timer, false); 1424 1391 } 1425 1392 EXPORT_SYMBOL(try_to_del_timer_sync); 1426 1393 ··· 1501 1468 * __timer_delete_sync - Internal function: Deactivate a timer and wait 1502 1469 * for the handler to finish. 1503 1470 * @timer: The timer to be deactivated 1471 + * @shutdown: If true, @timer->function will be set to NULL under the 1472 + * timer base lock which prevents rearming of @timer 1473 + * 1474 + * If @shutdown is not set the timer can be rearmed later. If the timer can 1475 + * be rearmed concurrently, i.e. after dropping the base lock then the 1476 + * return value is meaningless. 1477 + * 1478 + * If @shutdown is set then @timer->function is set to NULL under timer 1479 + * base lock which prevents rearming of the timer. Any attempt to rearm 1480 + * a shutdown timer is silently ignored. 1481 + * 1482 + * If the timer should be reused after shutdown it has to be initialized 1483 + * again. 1504 1484 * 1505 1485 * Return: 1506 1486 * * %0 - The timer was not pending 1507 1487 * * %1 - The timer was pending and deactivated 1508 1488 */ 1509 - static int __timer_delete_sync(struct timer_list *timer) 1489 + static int __timer_delete_sync(struct timer_list *timer, bool shutdown) 1510 1490 { 1511 1491 int ret; 1512 1492 ··· 1549 1503 lockdep_assert_preemption_enabled(); 1550 1504 1551 1505 do { 1552 - ret = __try_to_del_timer_sync(timer); 1506 + ret = __try_to_del_timer_sync(timer, shutdown); 1553 1507 1554 1508 if (unlikely(ret < 0)) { 1555 1509 del_timer_wait_running(timer); ··· 1601 1555 */ 1602 1556 int timer_delete_sync(struct timer_list *timer) 1603 1557 { 1604 - return __timer_delete_sync(timer); 1558 + return __timer_delete_sync(timer, false); 1605 1559 } 1606 1560 EXPORT_SYMBOL(timer_delete_sync); 1607 1561