Linux kernel kthread_stop使内核崩溃
我试图学习自旋锁和内核线程,并编写了一个小模块来测试我对内核代码的理解。代码片段是:Linux kernel kthread_stop使内核崩溃,linux-kernel,kernel-module,Linux Kernel,Kernel Module,我试图学习自旋锁和内核线程,并编写了一个小模块来测试我对内核代码的理解。代码片段是: static int kernel_test_thread(void *__unused) { int work; int x; allow_signal(SIGKILL); spin_lock(&kernel_test_device_lock); while(current->vfork_done == NULL || !kthread_should_st
static int kernel_test_thread(void *__unused) {
int work;
int x;
allow_signal(SIGKILL);
spin_lock(&kernel_test_device_lock);
while(current->vfork_done == NULL || !kthread_should_stop())
{
if(signal_pending( current ))
break;
spin_unlock(&kernel_test_device_lock);
msleep_interruptible(100);
spin_lock(&kernel_test_device_lock);
//do some work here
for(work=0;work<=10000;++work)
{
x = work<<1;
}
}
spin_unlock(&kernel_test_device_lock);
return 0;
}
static int __init start_kernel_test(void)
{
struct task_struct * ptask;
ptask = kthread_run(kernel_test_thread, NULL, "kernel_test_thread");
if(IS_ERR(ptask))
return -1;
kernel_test_task = ptask;
return 0;
}
static void stop_kernel_test(void)
{
if(kernel_test_task)
kthread_stop(kernel_test_task);
kernel_test_task=0;
}
static int __init init_test_kernel(void)
{
int rv;
spin_lock_init(&kernel_test_device_lock);
rv = start_kernel_test();
if(rv)
return rv;
printk(KERN_INFO "kernel_test: Kernel Test module started\n");
return 0;
}
// Cleanup module
static void __exit cleanup_test_kernel(void)
{
spin_lock_bh(&kernel_test_device_lock);
stop_kernel_test();
spin_unlock_bh(&kernel_test_device_lock);
printk(KERN_INFO "kernel_test: Kernel Test module stopped\n");
}
module_init(init_test_kernel);
module_exit(cleanup_test_kernel);
static int内核测试线程(void*\u未使用){
智力劳动;
int x;
允许信号(SIGKILL);
自旋锁(内核测试设备锁);
while(current->vfork_done==NULL | | |!kthread_should_stop())
{
if(信号_待定(当前))
打破
自旋解锁(内核测试设备锁定);
msleep_可中断(100);
自旋锁(内核测试设备锁);
//在这里做些工作
对于(work=0;workspin\u lock\u bh()
开始原子部分,禁止调用任何可能等待的函数。但是kthread\u stop()
等待线程退出
因为从kthread退出会破坏线程结构,除非有人在之前增加线程的使用计数器。当调用kthread\u stop()
时,它:
增加kthread的使用计数器
设置kthread的“stop”标志
等待kthread完成
递减kthread的使用计数器
这种算法用于kthread\u stop
carantees,即
在找到kthread\u后退出kthread应该停止()
非零总是安全的
但是,如果kthread可以在不检查kthread_should_stop()
的情况下退出,则应为担保人采取额外的操作,即kthread_stop()
没有看到kthread被销毁。可能的方法是:
struct task\u struct*kernel\u test\u task;
int模块_init(无效)
{
//创建kthread,但不要启动它。
kernel_test_task=kthread_create(…);
//递增使用计数器。
获取任务结构(内核测试任务);
//现在可以安全地启动kthread了——退出它不会破坏它的结构。
唤醒进程(内核测试任务);
}
空模块\u清理(空)
{
//虽然线程现在可以完成,但它的结构保证是活的。
kthread_stop(内核测试任务);
//这将减少使用计数器,在模块_init中增加。
放置任务结构(内核测试任务);
//现在线程被保证完成,并且它的结构被破坏。
}
您确定可以在原子上下文中调用kthread\u should\u stop()
吗?好的,答案是肯定的。罪魁祸首是kthread\u stop()之前的spin\u lock\u bh()
@AndyShevchenko我相信这就是我们应该检查线程是否被要求停止执行的方式。@AndyShevchenko你能解释一下原因吗?它写在你的回溯中。我之前没有注意到这一点。我确实花了更长的时间,即阅读代码(内核核心代码)。我想在“cleanup\u test\u kernel”函数中不需要“spin\u lock\u bh”或任何其他spin锁。如果kthread\u stop要等待线程退出,那么我可以确定“kthread\u stop”何时结束返回实际退出的内核线程。唯一的问题是,当kthread已经退出并销毁时,可以调用kthread\u stop
。但是在示例代码中,不必担心这一点。它仍然可能发生。如果“kernel\u test\u thread”线程收到信号并退出会怎么样。然后我将调用“kthread\u stop”在已经退出的线程上。然后会发生什么?如果对已经退出且结构已破坏的线程调用kthread\u stop
,则可能会发生不好的事情。我已更新了我的答案,并提供了一种避免这种情况的方法。Tsyvarev-我喜欢你的答案,因此接受了它。谢谢。
Jun 15 10:42:31 manik kernel: [ 595.162463] BUG: scheduling while atomic: rmmod/1719/0x00000200
Jun 15 10:42:31 manik kernel: [ 595.162470] Modules linked in: kernel_test(OE-) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass crc32_pclmul snd_usb_audio lpc_ich snd_usbmidi_lib input_leds joydev hid_multitouch snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep ie31200_edac shpchp edac_core 8250_fintek snd_soc_rt5640 snd_soc_rl6231 snd_soc_core snd_compress ac97_bus snd_pcm_dmaengine snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq snd_seq_device snd_timer dw_dmac snd dw_dmac_core elan_i2c snd_soc_sst_acpi spi_pxa2xx_platform soundcore 8250_dw i2c_designware_platform i2c_designware_core soc_button_array mac_hid parport_pc ppdev lp parport autofs4 nouveau i915 mxm_wmi wmi ttm i2c_algo_bit drm_kms_helper e1000e syscopyarea ptp ahci sysfillrect libahci sysimgblt fb_sys_fops pps_core drm sdhci_acpi video sdhci i2c_hid fjes hid_generic usbhid hid
Jun 15 10:42:31 manik kernel: [ 595.162568] CPU: 3 PID: 1719 Comm: rmmod Tainted: G IOE 4.4.0-22-generic #40
Jun 15 10:42:31 manik kernel: [ 595.162572] Hardware name: ADLINK Technology Inc. Express-HL./SHARKBAY, BIOS 1.14 01/01/2013
Jun 15 10:42:31 manik kernel: [ 595.162575] c1ac1967 b70efc6e 00000286 eeebde14 c139dccf e7d44dc0 c1c64dc0 eeebde2c
Jun 15 10:42:31 manik kernel: [ 595.162584] c1090627 c19b6c68 e5343ff0 000006b7 00000200 eeebde68 c17a4518 ffffffff
Jun 15 10:42:31 manik kernel: [ 595.162593] e7d0be00 b70efc6e e7d0be00 00000003 e7d0be00 00000000 c10a4760 e7d44dc0
Jun 15 10:42:31 manik kernel: [ 595.162601] Call Trace:
Jun 15 10:42:31 manik kernel: [ 595.162615] [<c139dccf>] dump_stack+0x58/0x79
Jun 15 10:42:31 manik kernel: [ 595.162623] [<c1090627>] __schedule_bug+0x57/0x70
Jun 15 10:42:31 manik kernel: [ 595.162630] [<c17a4518>] __schedule+0x5e8/0x770
Jun 15 10:42:31 manik kernel: [ 595.162637] [<c10a4760>] ? enqueue_task_fair+0x90/0xd40
Jun 15 10:42:31 manik kernel: [ 595.162642] [<c17a46cd>] schedule+0x2d/0x80
Jun 15 10:42:31 manik kernel: [ 595.162648] [<c17a7085>] schedule_timeout+0x185/0x210
Jun 15 10:42:31 manik kernel: [ 595.162655] [<c124c8b1>] ? sysfs_kf_seq_show+0xb1/0x150
Jun 15 10:42:31 manik kernel: [ 595.162661] [<c1095d0d>] ? check_preempt_curr+0x4d/0x90
Jun 15 10:42:31 manik kernel: [ 595.162666] [<c1095d67>] ? ttwu_do_wakeup+0x17/0x110
Jun 15 10:42:31 manik kernel: [ 595.162672] [<c17a4fd2>] wait_for_completion+0x92/0xf0
Jun 15 10:42:31 manik kernel: [ 595.162678] [<c1096c00>] ? wake_up_q+0x70/0x70
Jun 15 10:42:31 manik kernel: [ 595.162684] [<c108b771>] kthread_stop+0x41/0xf0
Jun 15 10:42:31 manik kernel: [ 595.162691] [<f06c109b>] cleanup_test_kernel+0x1b/0xf80 [kernel_test]
Jun 15 10:42:31 manik kernel: [ 595.162698] [<c10f4a0c>] SyS_delete_module+0x1ac/0x200
Jun 15 10:42:31 manik kernel: [ 595.162704] [<c11dc7bd>] ? ____fput+0xd/0x10
Jun 15 10:42:31 manik kernel: [ 595.162709] [<c1089a64>] ? task_work_run+0x84/0xa0
Jun 15 10:42:31 manik kernel: [ 595.162715] [<c10030f6>] ? exit_to_usermode_loop+0xb6/0xe0
Jun 15 10:42:31 manik kernel: [ 595.162721] [<c100393d>] do_fast_syscall_32+0x8d/0x150
Jun 15 10:42:31 manik kernel: [ 595.162728] [<c17a8098>] sysenter_past_esp+0x3d/0x61