在内核空间中,是不能直接使用open, read, write之类的系统调用直接访问文件的。那怎么在驱动中访问一个文件呢?
我们知道在内核中用struct file来表示一个打开的文件,file结构体中有一个字段f_op,它是struct file_operation的指针。有了这个指针,就可以对文件进行访问了。
代码如下:
struct file *filp;
mm_segment_t fs;
filp = filp_open("/path/to/your/file", O_RDWR, 0);
if(!IS_ERR(filp))
{
fs=get_fs();
set_fs(KERNEL_DS);
filp->f_op->read(...);
filp->f_op->write(...);
set_fs(fs);
filp->f_op->mmap(...);
/* ... */
}
filp_close(filp, NULL);
f_op->read()和f_op->write()的第二个参数是char __user *,也就是说是用户空间的地址,所以在驱动中直接传递kernel空间的指针,这两个函数都会返回失败-EFAULT。因此,在f_op->read()和f_op->write()之前需要使用void set_fs(mm_segment_t fs);来改变kernel对内存地址检查的处理方式。
该函数的参数fs只有两个取值:USER_DS,KERNEL_DS,分别代表用户空间和内核空间,默认情况下,kernel取值为USER_DS。所以可以用set_fs(KERNEL_DS);来让这个两个函数可以接受内核空间的内存。在内核空间中其他用__user修饰的参数,需要用kernel空间的内存代替时,都可以用类似的方法。
另外一个常用的函数f_op->mmap()则不需要设置fs,因为它的参数中不需要用户空间的内存。事实上,在struct file_operation中,只有read和write函数需要用户空间的内存,其他函数都不需要设置fs。
EOF