有没有好的方法来保持内核模块加载直到关联的定时器回调 returns
Is there good way to keep kernel module loaded until an associated timer callback returns
我正在编写一个内核模块,它设置一个定时器,在一段时间后调用模块中的回调函数。
代码如下:
static struct timer_list test_timer;
static void timeout_cb(unsigned long data)
{
printk("cb called\n");
}
static int __init timer_module_init( void )
{
init_timer(&test_timer);
test_timer.expires = jiffies + HZ*5;
test_timer.data = 0;
test_timer.function = timeout_cb;
add_timer(&test_timer);
return 0;
}
我以为在调用回调函数之前卸载模块,系统会挂掉。而且,这确实发生了。
# insmod timer_test.ko && lsmod | grep timer_test && rmmod timer_test.ko
timer_test 1034 0 ### No ref count to the module
### After some seconds, the system hung up
我认为这个问题的一个简单解决方案是在 add_timer()
之前递增模块的引用计数并在 timeout_cb()
结束时递减它,这样可以保持模块加载直到 timeout_cb()
结束.
static void timeout_cb(unsigned long data)
{
printk("cb called\n");
module_put(THIS_MODULE); // decrementing ref count
}
static int __init timer_module_init( void )
{
...
try_module_get(THIS_MODULE); // incrementing ref count
add_timer(&test_timer);
return 0;
}
这似乎工作正常,但严格来说,如果模块在 module_put()
returns timeout_cb()
returns 之后 timeout_cb()
returns 之前卸载,系统将挂起。 =21=]
//objdump
static void timeout_cb(unsigned long data)
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: e8 00 00 00 00 callq 9 <timeout_cb+0x9>
9: 48 c7 c7 00 00 00 00 mov [=14=]x0,%rdi
10: 31 c0 xor %eax,%eax
12: e8 00 00 00 00 callq 17 <timeout_cb+0x17>
printk("cb called\n");
module_put(THIS_MODULE);
17: 48 c7 c7 00 00 00 00 mov [=14=]x0,%rdi
1e: e8 00 00 00 00 callq 23 <timeout_cb+0x23>
}
// I think the system would hang up if the module is unloaded here.
23: c9 leaveq
24: c3 retq
25: 90 nop
有什么好的方法可以让模块加载到 timeout_cb()
returns 完全?
简单的解决方案可以正常工作,因为 timeout_cb()
是在中断上下文中调用的,尽管我不确定这是常规方法。
在module_exit
函数中您需要停用定时器。您可以使用
以同步方式执行此操作
timer_del_sync(&test_timer);
这将保证计时器的回调不会在返回时执行。因此,只有两种可能的变体:
计时器在执行回调之前已停用。由于停用,回调执行将永远不会发生。
计时器已停用,回调已完成。
您可以将此方法与 module_put
/try_module_get
方法结合使用,这样您的回调将在任何情况下执行。
我正在编写一个内核模块,它设置一个定时器,在一段时间后调用模块中的回调函数。 代码如下:
static struct timer_list test_timer;
static void timeout_cb(unsigned long data)
{
printk("cb called\n");
}
static int __init timer_module_init( void )
{
init_timer(&test_timer);
test_timer.expires = jiffies + HZ*5;
test_timer.data = 0;
test_timer.function = timeout_cb;
add_timer(&test_timer);
return 0;
}
我以为在调用回调函数之前卸载模块,系统会挂掉。而且,这确实发生了。
# insmod timer_test.ko && lsmod | grep timer_test && rmmod timer_test.ko
timer_test 1034 0 ### No ref count to the module
### After some seconds, the system hung up
我认为这个问题的一个简单解决方案是在 add_timer()
之前递增模块的引用计数并在 timeout_cb()
结束时递减它,这样可以保持模块加载直到 timeout_cb()
结束.
static void timeout_cb(unsigned long data)
{
printk("cb called\n");
module_put(THIS_MODULE); // decrementing ref count
}
static int __init timer_module_init( void )
{
...
try_module_get(THIS_MODULE); // incrementing ref count
add_timer(&test_timer);
return 0;
}
这似乎工作正常,但严格来说,如果模块在 module_put()
returns timeout_cb()
returns 之后 timeout_cb()
returns 之前卸载,系统将挂起。 =21=]
//objdump
static void timeout_cb(unsigned long data)
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: e8 00 00 00 00 callq 9 <timeout_cb+0x9>
9: 48 c7 c7 00 00 00 00 mov [=14=]x0,%rdi
10: 31 c0 xor %eax,%eax
12: e8 00 00 00 00 callq 17 <timeout_cb+0x17>
printk("cb called\n");
module_put(THIS_MODULE);
17: 48 c7 c7 00 00 00 00 mov [=14=]x0,%rdi
1e: e8 00 00 00 00 callq 23 <timeout_cb+0x23>
}
// I think the system would hang up if the module is unloaded here.
23: c9 leaveq
24: c3 retq
25: 90 nop
有什么好的方法可以让模块加载到 timeout_cb()
returns 完全?
简单的解决方案可以正常工作,因为 timeout_cb()
是在中断上下文中调用的,尽管我不确定这是常规方法。
在module_exit
函数中您需要停用定时器。您可以使用
timer_del_sync(&test_timer);
这将保证计时器的回调不会在返回时执行。因此,只有两种可能的变体:
计时器在执行回调之前已停用。由于停用,回调执行将永远不会发生。
计时器已停用,回调已完成。
您可以将此方法与 module_put
/try_module_get
方法结合使用,这样您的回调将在任何情况下执行。