linux 使用/proc文件系统 实现用户空间与内核模块之间通信
项目中可能会用到用户态和内核模块之间进行通信的功能。想到linux系统本身很多通信都是通过/proc文件系统来的,比如修改网络中连接跟踪表连接数限制/proc/sys/net/netfilter/nf_conntrack_max,这种通信方式比较简单,所以想研究下,下面是我自己写的测试代码:
myproc.c
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/proc_fs.h> 4 #include <linux/string.h> 5 #include <linux/vmalloc.h> 6 #include <asm/uaccess.h> 7 8 MODULE_LICENSE("GPL"); 9 10 #define MY_MEM_SIZE PAGE_SIZE 11 12 static const char *name = "sandals"; 13 static struct proc_dir_entry *proc_entry; 14 static char *mymem; 15 static unsigned long mylen; 16 17 int mywrite(struct file *filp, const char __user *buff, 18 unsigned long len, void *data) 19 { 20 if (len > MY_MEM_SIZE) { 21 printk(KERN_INFO "mywrite too large len.\n"); 22 return -ENOSPC; 23 } 24 25 if (copy_from_user(mymem, buff, len)) { 26 printk(KERN_INFO "mywrite copy_from_user failed.\n"); 27 return -EFAULT; 28 } 29 30 mylen = len; 31 mymem[mylen] = 0; 32 33 return len; 34 } 35 36 int myread(char *page, char **start, off_t off, 37 int count, int *eof, void *data) 38 { 39 int len; 40 41 if (!mylen) { 42 return 0; 43 } 44 45 if (count < mylen || off > 0) { 46 *eof = 1; 47 return 0; 48 } 49 50 len = sprintf(page, "%s\n", mymem); 51 52 return len; 53 } 54 55 int my_module_init(void) 56 { 57 int ret = 0; 58 59 mylen = 0; 60 mymem = NULL; 61 62 mymem = (char *)vmalloc(MY_MEM_SIZE); 63 if (!mymem) { 64 printk(KERN_INFO "my_module vmalloc failed.\n"); 65 ret = -ENOMEM; 66 } 67 else { 68 memset(mymem, 0, MY_MEM_SIZE); 69 70 proc_entry = create_proc_entry(name, 0644, NULL); 71 if (!proc_entry) { 72 ret = -ENOMEM; 73 vfree(mymem); 74 mymem = NULL; 75 printk(KERN_INFO "my_module create_proc_entry failed.\n"); 76 } 77 else { 78 proc_entry->read_proc = myread; 79 proc_entry->write_proc = mywrite; 80 printk(KERN_INFO "my_module_init called. Module is now loaded.\n"); 81 } 82 } 83 84 return ret; 85 } 86 87 void my_module_cleanup(void) 88 { 89 remove_proc_entry(name, NULL); 90 vfree(mymem); 91 mymem = NULL; 92 printk(KERN_INFO "my_module_cleanup called. Module is now unloaded.\n"); 93 return; 94 } 95 96 module_init(my_module_init); 97 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
下面是运行结果的截图: