项目中可能会用到用户态和内核模块之间进行通信的功能。想到linux系统本身很多通信都是通过/proc文件系统来的,比如修改网络中连接跟踪表连接数限制/proc/sys/net/netfilter/nf_conntrack_max,这种通信方式比较简单,所以想研究下,下面是我自己写的测试代码:
myproc.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h> MODULE_LICENSE("GPL"); #define MY_MEM_SIZE PAGE_SIZE static const char *name = "sandals";
static struct proc_dir_entry *proc_entry;
static char *mymem;
static unsigned long mylen; int mywrite(struct file *filp, const char __user *buff,
unsigned long len, void *data)
{
if (len > MY_MEM_SIZE) {
printk(KERN_INFO "mywrite too large len.\n");
return -ENOSPC;
} if (copy_from_user(mymem, buff, len)) {
printk(KERN_INFO "mywrite copy_from_user failed.\n");
return -EFAULT;
} mylen = len;
mymem[mylen] = ; return len;
} int myread(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len; if (!mylen) {
return ;
} if (count < mylen || off > ) {
*eof = ;
return ;
} len = sprintf(page, "%s\n", mymem); return len;
} int my_module_init(void)
{
int ret = ; mylen = ;
mymem = NULL; mymem = (char *)vmalloc(MY_MEM_SIZE);
if (!mymem) {
printk(KERN_INFO "my_module vmalloc failed.\n");
ret = -ENOMEM;
}
else {
memset(mymem, , MY_MEM_SIZE); proc_entry = create_proc_entry(name, , NULL);
if (!proc_entry) {
ret = -ENOMEM;
vfree(mymem);
mymem = NULL;
printk(KERN_INFO "my_module create_proc_entry failed.\n");
}
else {
proc_entry->read_proc = myread;
proc_entry->write_proc = mywrite;
printk(KERN_INFO "my_module_init called. Module is now loaded.\n");
}
} return ret;
} void my_module_cleanup(void)
{
remove_proc_entry(name, NULL);
vfree(mymem);
mymem = NULL;
printk(KERN_INFO "my_module_cleanup called. Module is now unloaded.\n");
return;
} module_init(my_module_init);
module_exit(my_module_cleanup);
简单讲下思路,这段代码,会在/proc根目录下,创建一个sandals文件,你可以通过cat test > /proc/sandals来写入。然后用cat /proc/sandals就可以输出刚刚输入的内容。
/proc文件系统其实不是特别难,简单的讲就是分以下步骤就可以了。(前提是你已经会了如果创建自定义内核模块,如果不会,可以在网上搜一下,这个网上很多)
1、创建一个/proc文件(和创建普通文件很像,当然系统调用不同),通过调用 create_proc_entry 来创建。
2、注册对这个文件读写的回调函数,读取回调函数就是你cat /proc/sandals的时候会调用。写回调函数就是echo 的时候会调用 。注册的代码就是78、79两行代码。
3、读写的时候,传递过来的参数,就不多说了。可以自己在网查一下。
4、编译就可以运行了。
makefile文件,就一行:
obj-m += myproc.o
下面是编译的命令(我用的是centos 6.6的系统,如果是其他的系统,自己替换-C部分,这部分是指定的内核原码的位置):
make -C /usr/src/kernels/`uname -r` SUBDIRS=$PWD modules
下面是运行结果的截图: