kernel_modules
加载/卸载模块
在虚拟机中可以在kernel_modules下的1-2-test文件夹下尝试
1 2
| insmod module.ko rmmod module.ko
|
内核oops
内核级错误报告,遇到无法安全处理的操作(空指针引用,非法访问内存,堆栈溢出)时触发,但不会导致内核崩溃,oops记录了错误发生时的系统状态
oops实例分析
内核日志打印
dmesg -c 可以显示并清除当前日志信息
dmesg | tail -10 显示最后10行
模块传参
根据module_param(str, charp, 0000)的声明可对模块进行传参
参数分别对应变量名,变量类型,权限
1 2 3 4 5 6 7 8 9 10
| static char *str = "the worm";
module_param(str, charp, 0000); MODULE_PARM_DESC(str, "A simple string");
static int __init cmd_init(void) { pr_info("Early bird gets %s\n", str); return 0; }
|
1 2 3 4
| root@qemux86:~/skels/kernel_modules/6-cmd-mod# insmod cmd_mod.ko Early bird gets the worm root@qemux86:~/skels/kernel_modules/6-cmd-mod# insmod cmd_mod.ko str="tired" Early bird gets tired
|
kernel_api
控制台日志
0-7对应严重等级
1 2 3
| #include<linux/kernel.h> pr_debug("Hello!\n"); printk(KERN_INFO "Hello2!\n");
|
1 2
| cat /proc/sys/kernel/printk echo 6 > /proc/sys/kernel/printk
|
内存分配
1 2 3 4 5 6
| #include <linux/slab.h> string = kmalloc(string_len+1,GFP_KERNEL); if(!string){ } kfree(string);
|
在原子上下文中睡眠
在原子上下文中,进行阻塞或者睡眠的操作会产生错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static int sched_spin_init(void) { spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);
set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(5 * HZ);
spin_unlock(&lock);
return 0; }
|
如上的代码,会产生错误如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| root@qemux86:~/skels/kernel_api/2-sched-spin# insmod sched-spin.ko BUG: scheduling while atomic: insmod/279/0x00000002 #0: c4227db8 (&lock){+.+.}-{2:2}, at: sched_spin_init+0x32/0x90 [sched_spin] Call Trace: dump_stack+0x6d/0x8b __schedule_bug.cold+0x65/0x76 __schedule+0x577/0x720 ? mark_held_locks+0x3f/0x70 ? schedule_timeout+0x172/0x2f0 ? _raw_spin_unlock_irqrestore+0x45/0x50 ? schedule_timeout+0x172/0x2f0 schedule+0x56/0xd0 schedule_timeout+0x177/0x2f0 ? del_timer_sync+0xc0/0xc0 ? 0xe0831000 sched_spin_init+0x61/0x90 [sched_spin] ? sched_spin_init+0x32/0x90 [sched_spin]
|
根据调用栈分析,能定位到错误位置
1 2 3 4 5
| sched_spin_init+0x61/0x90 [sched_spin] ↓ schedule_timeout+0x177/0x2f0 ↓ schedule+0x56/0xd0
|
进程pid宏
可以通过 next_task 获取下一个进程的pid
1 2 3 4
| ti1 = task_info_alloc(current->pid); ti2 = task_info_alloc(current->parent->pid); ti3 = task_info_alloc(next_task(current)->pid); ti4 = task_info_alloc(next_task(next_task(current))->pid);
|