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

下面是运行结果的截图:

posted @ 2016-03-15 17:50  sandals  阅读(2044)  评论(0编辑  收藏  举报