阅读本文之前还是建议读者先了解下系统调用,可参考之前的文章说一说linux的系统调用
大部分人都是通过ps获取机器的进程数,但ps不但消耗大量的系统调用,而且在异常情况下可能会卡死,因为ps命令主要是通过读取/proc目录下的文件获取进程相关信息的。
因此本文通过为linux内核增加系统调用,实现一次系统调用获取系统进程数。
本文使用内核版本:5.5.0
首先在arch/x86/entry/syscalls/syscall_64.tbl增加系统调用表,当前系统调用号已经到了547,因此我们使用的系统调用号从548开始。
在include/linux/syscalls.h增加系统调用函数声明
在kernel/sys.c增加函数定义
内核每个进程的结构(PCB)是task_struct,用链表进行管理。因此只需要遍历链表获取链表长度就是进程数。
make menuconfig (load->save->exit)
make –j8 (8是机器的cpu核数,具体根据机器配置设置)
make modules
make modules_install
make install
查看/lib/modules目录下是否生成新内核 设置启动引导,启动默认使用5.5内核启动。
重启系统。。。。。。
查看系统内核版本,已经是最新内核了
OK,接下来编译测试程序t.c
测试程序如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
intproc_count = syscall(548);
printf("current system has process counts: %ld\n",proc_count);
return 0;
}
注:由于没有修改GLIBC,所以测试程序直接通过系统调用号调用。
编译:gcc –o t t.c
测试结果:
和ps的耗时对比:
可能有些人看到上面时间相差不大,主要是由于我自己的测试机没有业务进程,当有成千上万个进程的时候,耗时还是比较明显的。
总结:本文主要通过增加系统调用方式获取当前系统的进程数,之前都是通过ps获取进程数信息,但ps消耗系统性能,而且当系统异常时可能出现卡住问题,不靠谱。但通过增加系统调用,直接获取PCB链表的长度,大大减少了系统调用,提高了效率,减少了性能损耗。
其实之前一直想这个问题怎么去实现,但一直没有动手操作过,花了2个小时(编译内核比较久,而且中间又出现过失败)才搞定。
其实除了这种方法,还有其他方式(不编译内核)可以实现,那就是增加内核模块(KO),通过增加KO也是可以实现的。
另外,在内核安全方面,通过增加特定系统调用捕获恶意访问或调用,实现类似audit审计系统及时发现异常;另外也可以通过增加系统调用和KO实现截获系统调用(例如挖矿程序),及时发现是否有人利用线上机器进行挖矿。(PS:请将技术用在正道上^_^)