1. 背景
linux 内核是介于应用和驱动之间的抽象层;系统调用api是kernel与app间的接口,kernel与driver之间也有一层low-level-api(如注册驱动模块,注册中断ISR等),driver与设备间的接口即为I/O寄存器(寄存器地址与硬件配置有关)。内核的主要任务是满足多个应用对设备资源(CPU、RAM、DISK、NET)的请求,而实际的硬件资源是有限的,不同需求的应用无限,如何合理分配资源是kernel的主要设计问题。
2. 遇到的问题
a)应用调用的api执行结果是否有效?
b)应用调用的api响应时间是否够快?
c)kernelspace的代码出现非法内存地址访问;
d)kernelspace的线程出现死锁,无响应;
e)kernelspace出现内存泄漏
3. 可行的解决方案
a)理解kernel的运行上下文:
启动流程> startkernel -> deviceinit (requestirq) -> registerfilesystem -> mountrootfs -> /sbin/init -> /bin/bash
请求等待> scanf -> read -> inode-lookup -> fs_read -> readblock -> wait-dma -> sleep -> schedule
响应唤醒> disk-irq -> dma-done -> wakeup -> schedule -> readblock -> fs_read -> read
b) kernel中的全局变量因多线程(不同应用进程的系统调用或中断请求)访问需要加锁;
函数中引用到了全局变量的需要在引用处加锁或该函数被引用时加锁;mutex和spinlock都不可重复获取;
c) 跟踪api的执行结果和时间:printk日志(/proc/kmesg),dumpstack检查调用顺序, strace 和 ftrace的使用
d)kernel异常操作出现panic或oops时:使用addr2line vmlinux 0x2121241 检查出错的源码行和调用栈;
e)对于kernel中出现的卡死问题,打开CONFIG_DETECT_HUNG_TASK,可用echo w > /proc/sysrq-trigger打印阻塞线程调用栈,然后分析各线程持有的交叉锁;
f)使用kexec转存kernel crash时的内存镜像vmcore,待重启后使用crash工具分析;对于锁死问题可强制触发crash:echo c >/proc/sysrq-trigger, 再转存内存日志分析;
g)对于内存泄漏问题可打开相关内存检查config:CONFIG_DEBUG_KMEMLEAK、 CONFIG_KMEMCHECK,然后从日志输出中定位泄漏代码行;
4. 参考链接