帖子
-
2838
主题
-
668
精华
-
9
可用积分
-
41
专家积分
-
100
在线时间
-
1600 小时
注册时间
-
2008-08-15
最后登录
-
2011-12-01
论坛徽章:
-
0
|
五. 文件 使用文件来通信其实是有点牵强的,不过这个当时在bell的一个项目中,我确实这个干过就来出来了
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <asm/uaccess.h>
- #include <linux/mm.h>
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Kenthy@163.com.");
- MODULE_DESCRIPTION("Kernel study and test.");
-
- struct file *filp;
- mm_segment_t fs;
-
- void SLEEP_MILLI_SEC(int nMilliSec)
- {
- long timeout = (nMilliSec) * 100 / 1000;
- while(timeout > 0)
- {
- timeout = schedule_timeout(timeout);
- }
- }
-
- void fileread(const char * filename)
- {
- struct file *filp;
- struct inode *inode;
- mm_segment_t fs;
- off_t fsize;
- char *buf;
- unsigned long magic;
- filp=filp_open(filename,O_RDONLY,0);
- inode=filp->f_dentry->d_inode;
-
- magic=inode->i_sb->s_magic;
- printk("file system magic:%li \n",magic);
- printk("super blocksize:%li \n",inode->i_sb->s_blocksize);
- printk("inode %li \n",inode->i_ino);
- fsize=inode->i_size;
- printk("file size:%i \n",(int)fsize);
- buf=(char *) kmalloc(fsize+1,GFP_ATOMIC);
-
- fs=get_fs();
- set_fs(KERNEL_DS);
- filp->f_op->read(filp,buf,fsize,&(filp->f_pos));
- set_fs(fs);
-
- buf[fsize]='\0';
- printk("The File Content is:\n");
- printk("%s\n",buf);
-
- kfree(buf);
- filp_close(filp,NULL);
- }
-
- void filewrite(char* filename, char* data)
- {
- fs=get_fs();
- set_fs(KERNEL_DS);
- filp->f_op->write(filp, data, strlen(data),&filp->f_pos);
- set_fs(fs);
- }
-
- void test_write(char* filename)
- {
- int i;
- char data[20];
- filp = filp_open(filename, O_RDWR|O_APPEND, 0644);
- if(IS_ERR(filp))
- {
- printk("open error...\n");
- return;
- }
-
-
- for(i=0;i<10;i++)
- {
- sprintf(data, "%s, %d\n", "kernel write test", i);
- filewrite(filename, data);
- SLEEP_MILLI_SEC(1000);
- }
- }
-
- int init_module()
- {
- char *filename="/root/log";
-
- printk("%s\n", "begin write data");
- test_write(filename);
-
- printk("%s\n", "begin read data");
- fileread(filename);
- return 0;
- }
-
- void cleanup_module()
- {
- filp_close(filp,NULL);
- printk("Good,Bye!\n");
- }
-
复制代码
上面的代码还附送了内核中如何sleep 六. copy_xxx_user copy_from_user函数的目的是从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0.这么简单的一个函数却含盖了许多关于内核方面的知识,比如内核关于异常出错的处理.从用户空间拷贝数据到内核中时必须很小心,假如用户空间的数据地址是个非法的地址,或是超出用户空间的范围,或是那些地址还没有被映射到,都可能对内核产生很大的影响,如oops,或被造成系统安全的影响.所以copy_from_user函数的功能就不只是从用户空间拷贝数据那样简单了,他还要做一些指针检查连同处理这些 问题的方法. 函数原型在[arch/i386/lib/usercopy.c]中
- unsigned long
- copy_from_user(void *to, const void __user *from, unsigned long n)
- {
- might_sleep();
- if (access_ok(VERIFY_READ, from, n))
- n = __copy_from_user(to, from, n);
- else
- memset(to, 0, n);
- return n;
- }
-
复制代码
具体的代码实现我就不讲了,我自己也看的懵懂!!!还是来使用使用吧
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <linux/fs.h>
- #include <linux/sched.h>
- #include <asm/uaccess.h>
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Kenthy@163.com.");
- MODULE_DESCRIPTION("Kernel study and test.");
-
-
- #define DP_MAJOR 251//主设备号
- #define DP_MINOR 0 //次设备号
- #define DEV_NAME "kenthy"
-
- static int char_read(struct file *filp, char __user *buffer, size_t, loff_t*);
- static int char_open(struct inode*, struct file*);
- static int char_write(struct file *filp, const char __user *buffer, size_t, loff_t*);
- static int char_release(struct inode*, struct file*);
-
- static int chropen;
- struct cdev *chardev;
- static int len;
-
- static char *to;
- static const struct file_operations char_ops={
- .read = char_read,
- .write = char_write,
- .open = char_open,
- .release = char_release,
- };
-
- static int __init char_init(void)
- {
- dev_t dev;
- printk(KERN_ALERT"Initing......\n");
- dev = MKDEV(DP_MAJOR, DP_MINOR);
- chardev = cdev_alloc();
-
- if(chardev == NULL){
- return -1;
- }
- if(register_chrdev_region(dev, 10, DEV_NAME)){
- printk(KERN_ALERT"Register char dev error\n");
- return -1;
- }
- chropen = 0;
- len = 0;
- cdev_init(chardev, &char_ops);
- if(cdev_add(chardev, dev, 1)){
- printk(KERN_ALERT"Add char dev error!\n");
- }
- return 0;
- }
-
- static int char_open(struct inode *inode, struct file *file)
- {
- if(chropen == 0)
- chropen++;
- else{
- printk(KERN_ALERT"Another process open the char device\n");
- return -1;
- }
- try_module_get(THIS_MODULE);
- return 0;
- }
-
- static int char_release(struct inode *inode,struct file *file)
- {
- chropen--;
- module_put(THIS_MODULE);
- return 0;
- }
-
- static int char_read(struct file *filp,char __user *buffer,size_t length,loff_t *offset)
- {
- unsigned long nn;
- nn = copy_to_user(buffer, to, length);
- printk("nn = %ld\n", nn);
- printk("buffer = %s\n", buffer);
- return length;
- }
-
- static int char_write(struct file *filp, const char __user *buffer, size_t length, loff_t *offset)
- {
- unsigned long n;
- to = (char *)kmalloc((sizeof(char)) * (length+1), GFP_KERNEL);
- memset(to, '\0', length+1);
- n = copy_from_user(to, buffer, length);
- printk("n = %ld\n", n);
- printk("to = %s\n", to);
- return length;
- }
-
- static void __exit module_close(void)
- {
- len=0;
- printk(KERN_ALERT"Unloading..........\n");
-
- unregister_chrdev_region(MKDEV(DP_MAJOR,DP_MINOR),10);
- cdev_del(chardev);
- }
-
- module_init(char_init);
- module_exit(module_close);
复制代码
这个与mmap的类似都依赖于一个字符设备文件 sudo insmod chardev.ko 在使用测试程序前我们要创建一个字符设备: #mknod /dev/chardev0 c 251 0 测试程序代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- int main(int args, char *argv[])
- {
- int testdev;
- int i, rf = 0;
- char buf[15];
-
- memset(buf, '\0', 15);
- testdev = open("/dev/chardev0", O_RDWR);
- if(testdev == -1){
- perror("open\n");
- exit(0);
- }
- if((write(testdev, "1111111111", 10)) < 0){
- perror("Write error!\n");
- exit(0);
- }
- close(testdev);
- printf("write finish!\n");
- testdev = open("/dev/chardev0", O_RDWR);
- rf = read(testdev, buf, 3);
- if(rf < 0)
- perror("read error\n");
- printf("Read: %s\n", buf);
- close(testdev);
-
- return 0;
- }
复制代码
运行程序: #./test Read: 111 看一下内核信息: #dmesg 最后几行信息如下: nn = 0 buffer = 1111111111 n = 0 to = 111 这就说明设备注册正确,从用户到内核copy_from_user和从内核到用户copy_to_user都顺利完成了。呵呵,你是不是觉得还少了点什么东西,对我前面说还有ioctl没有讲 在内核空间中ioctl是很多内核操作结构的一个成员函数,如文件操作结构struct file_operations(include/linux/fs.h)、协议操作结构struct proto_ops(include/linux/net.h)等、tty操作结构struct tty_driver(include/linux/tty_driver.h)等,而这些操作结构分别对应各种内核设备,只要在用户空间打开这些设备,如I/O设备可用open(2)打开,网络协议可用socket(2)打开等,获取一个文件描述符后,就可以在这个描述符上调用ioctl(2)来向内核交换数据。 ioctl(2)函数的基本使用格式为: int ioctl(int fd, int cmd, void *data) 第一个参数是文件描述符;cmd是操作命令,一般分为GET、SET以及其他类型命令,GET是用户空间进程从内核读数据,SET是用户空间进程向内核写数据,cmd虽然是一个整数,但是有一定的参数格式的,下面再详细说明;第三个参数是数据起始位置指针, cmd命令参数是个32位整数,分为四部分: dir(2b) size(14b) type(8b) nr(8b) 详细定义cmd要包括这4个部分时可使用宏_IOC(dir,type,nr,size)来定义,而最简单情况下使用_IO(type, nr)来定义就可以了,这些宏都在include/asm/ioctl.h中定义 本文cmd定义为: #define NEWCHAR_IOC_MAGIC 'M' #define NEWCHAR_SET _IO(NEWCHAR_IOC_MAGIC, 0) #define NEWCHAR_GET _IO(NEWCHAR_IOC_MAGIC, 1) #define NEWCHAR_IOC_MAXNR 1 要定义自己的ioctl操作,可以有两个方式,一种是在现有的内核代码中直接添加相关代码进行支持,比如想通过socket描述符进行ioctl操作,可在net/ipv4/af_inet.c中的inet_ioctl()函数中添加自己定义的命令和相关的处理函数,重新编译内核即可,不过这种方法一般不推荐;第二种方法是定义自己的内核设备,通过设备的ioctl()来操作,可以编成模块,这样不影响原有的内核,这是最通常的做法。 大致过程如下
- 进行ioctl调用的基本处理函数
- static int newchar_ioctl(struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg)
- {
- int ret;
- // 首先检查cmd是否合法
- if (_IOC_TYPE(cmd) != NEWCHAR_IOC_MAGIC) return -EINVAL;
- if (_IOC_NR(cmd) > NEWCHAR_IOC_MAXNR) return -EINVAL;
- // 错误情况下的缺省返回值
- ret = EINVAL;
- switch(cmd)
- {
- case KNEWCHAR_SET:
- // 设置操作,将数据从用户空间拷贝到内核空间
- {
- struct newchar nc;
- if(copy_from_user(&nc, (const char*)arg, sizeof(nc)) != 0)
- return -EFAULT;
- ret = do_set_newchar(&nc);
- }
- break;
- case KNEWCHAR_GET:
- // GET操作通常会在数据缓冲区中先传递部分初始值作为数据查找条件,获取全部
- // 数据后重新写回缓冲区
- // 当然也可以根据具体情况什么也不传入直接向内核获取数据
- {
- struct newchar nc;
- if(copy_from_user(&nc, (const char*)arg, sizeof(nc)) != 0)
- return -EFAULT;
- ret = do_get_newchar(&nc);
- if(ret == 0){
- if(copy_to_user((unsigned char *)arg, &nc, sizeof(nc))!=0)
- return -EFAULT;
- }
- }
- break;
- }
- return ret;
- }
复制代码
由于能力有限,难免会有错误和纰漏,还望给位海涵并指正, 当然也还存在其他的user kernel ipc, 也希望给位指出来。工作量比较大我的代码很多都只是提供了一种思路,要像深究研究的话,还必须DIY了!!!马上放寒假了,要回家过最后一个舒服的大年了,也要离开cu一段时间了,念念不舍啊... 参考文献: Linux 系统内核空间与用户空间通信的实现与分析: http://www.ibm.com/developerworks/cn/linux/l-netlink/index.html Linux Netfilter实现机制和扩展技术: [url]http://www.ibm.com/developerworks/cn/linux/l-ntflt/index.html[/url] |
|