Index: sys/compat/linuxkpi/common/include/linux/timer.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/timer.h +++ sys/compat/linuxkpi/common/include/linux/timer.h @@ -36,9 +36,12 @@ #include #include #include +#include +#include struct timer_list { struct callout callout; + struct mtx mtx; union { void (*function) (unsigned long); /* < v4.15 */ void (*function_415) (struct timer_list *); @@ -54,16 +57,24 @@ #define from_timer(var, arg, field) \ container_of(arg, typeof(*(var)), field) +/* + * Avoid witness enrollment with MTX_NOWITNESS flag to not leak this + * data on free() as Linux timers do not have destructors. + */ #define timer_setup(timer, func, flags) do { \ CTASSERT(((flags) & ~TIMER_IRQSAFE) == 0); \ (timer)->function_415 = (func); \ (timer)->data = (unsigned long)(timer); \ + mtx_init(&(timer)->mtx, "lnxtimer", NULL, \ + MTX_DEF | MTX_NEW | MTX_NOWITNESS); \ callout_init(&(timer)->callout, 1); \ } while (0) #define setup_timer(timer, func, dat) do { \ (timer)->function = (func); \ (timer)->data = (dat); \ + mtx_init(&(timer)->mtx, "lnxtimer", NULL, \ + MTX_DEF | MTX_NEW | MTX_NOWITNESS); \ callout_init(&(timer)->callout, 1); \ } while (0) @@ -75,6 +86,8 @@ #define init_timer(timer) do { \ (timer)->function = NULL; \ (timer)->data = 0; \ + mtx_init(&(timer)->mtx, "lnxtimer", NULL, \ + MTX_DEF | MTX_NEW | MTX_NOWITNESS); \ callout_init(&(timer)->callout, 1); \ } while (0) @@ -82,8 +95,8 @@ extern void add_timer(struct timer_list *); extern void add_timer_on(struct timer_list *, int cpu); extern int del_timer(struct timer_list *); +extern int del_timer_sync(struct timer_list *); -#define del_timer_sync(timer) (void)callout_drain(&(timer)->callout) #define timer_pending(timer) callout_pending(&(timer)->callout) #define round_jiffies(j) \ ((int)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask)) Index: sys/compat/linuxkpi/common/src/linux_compat.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_compat.c +++ sys/compat/linuxkpi/common/src/linux_compat.c @@ -1900,7 +1900,13 @@ linux_set_current(curthread); timer = context; - timer->function(timer->data); + mtx_lock(&timer->mtx); + if (!callout_pending(&timer->callout) && + callout_active(&timer->callout)) { + callout_deactivate(&timer->callout); + timer->function(timer->data); + } + mtx_unlock(&timer->mtx); } void @@ -1940,6 +1946,20 @@ return (1); } +int +del_timer_sync(struct timer_list *timer) +{ + int canceled; + + do { + mtx_lock(&timer->mtx); + canceled = callout_stop(&timer->callout); + mtx_unlock(&(timer)->mtx); + } while (unlikely(canceled == 0)); + + return (canceled == 1 ? 1 : 0); +} + /* greatest common divisor, Euclid equation */ static uint64_t lkpi_gcd_64(uint64_t a, uint64_t b)