有时需要在Linux内核中读写文件数据——主要是在需要调试的驱动程序中。内核中没有可供操作文件的标准库,需要用到内核的一些函数。这些函数主要包括:filp_open()filp_close()、vfs_read()、vfs_write()、set_fs()、get_fs()等,这些函数在linux/fs.h和asm/uaccess.h头文件中声明。下面介绍主要步骤1、打开文件filp_open()可以在内核中打开文件,其原型如下:strcutfile*filp_open(constchar*filename,intopen_mode,intmode);该函数返回strcutfile*结构体指针,供后续函数操作使用,返回值使用IS_ERR()检查其有效性。参数说明filename:表示要打开或创建的文件的名称(包括路径部分)。在内核中打开文件时,需要注意打开的时机。需要打开文件的驱动很容易很早就加载打开文件,但是需要打开文件的设备还没有挂载到文件系统,导致无法打开。.open_mode:打开文件的方式。它的值类似于标准库中open对应的参数。可以是O_CREAT、O_RDWR、O_RDONLY等模式:创建文件时使用,设置创建文件的读写权限,其他情况可以简单设置为02。读取中文件的读写操作而写文件内核可以使用vfs_read()和vfs_write,在使用这两个函数之前,需要先解释一下get_fs()和set_fs()这两个函数。vfs_read()和vfs_write()两个函数的原型如下:ssize_tvfs_read(structfile*filp,char__user*buffer,size_tlen,loff_t*pos);ssize_tvfs_write(structfile*filp,constchar__user*buffer,size_tlen,loff_t*pos);注意这两个函数的第二个参数buffer前面有一个__user修饰符,要求两个buffer指针都指向用户空间的内存。如果将内核空间的指针传递给参数,则两个函数都返回失败-EFAULT。但是在Kernel中,我们一般不太容易生成用户空间指针,或者不方便独立使用用户空间内存。要使用内核空间的缓冲区指针使这两个读写函数正常工作,需要使用set_fs()函数或宏(set_fs()可能是一个宏定义)。如果是函数,其原型如下:voidset_fs(mm_segment_tfs);该函数的作用是改变内核检查内存地址的方式。实际上,这个函数的参数fs只有两个值:USER_DS和KERNEL_DS,分别代表用户空间和内核空间。默认情况下,kernel的值为USER_DS,即检查并转换用户空间地址。那么要在这个检查和转换内存地址的函数中使用内核空间地址,需要使用set_fs(KERNEL_DS)来设置。get_fs()一般也可以是一个宏定义,其作用是获取当前设置。这两个函数的一般用法是:mm_segment_told_fs;old_fs=get_fs();set_fs(KERNEL_DS);...//与内存相关的操作set_fs(old_fs);还有一些其他的内核函数也有被__user修改的参数。当内核需要被内核空间的内存替换时,可以使用类似的方法。使用vfs_read()和vfs_write()最需要注意的是参数loff_t*pos,pos指向的值需要初始化,表示从文件的哪里开始读写。3.关闭读写文件intfilp_close(structfile*filp,fl_owner_tid);这个函数的使用很简单,第二个参数一般传NULL值,current->files也作为实参。使用上述功能的其他注意事项:1.事实上,LinuxKernel组的成员不同意在内核中独立读写文件(这可能会影响政策和安全问题),并且需要的文件内容内核由应用程序决定。图层拟合完成。2.使用这种方法在可加载内核模块中读写文件可能会导致模块加载失败,因为内核可能不会EXPORT你需要的所有这些功能。3、分析上面部分函数的参数,这些函数的正确运行依赖于进程环境。因此,有些函数不能在不属于中断句柄或Kernel中任何进程的代码中执行,否则可能会发生crash,为了避免这种情况,可以在内核中创建内核线程,在线程中执行这些函数环境(创建内核线程的方式,请参数kernel_thread()函数)。在VFS的支持下,用户态进程可以使用读写系统调用来读写任何类型的文件系统,但是linux内核中并没有这样的系统调用。我们如何操作文件?我们知道read和write是在进入内核态后实际执行的是sys_read和sys_write,但是查看内核源码发现这些操作文件的函数并没有导出(使用EXPORT_SYMBOL导出),也就是说它们不能在内核模块中使用,那我该怎么办??通过查看sys_open的源码,我们发现它主要使用了do_filp_open()函数,这个函数在fs/namei.c中,而在修改后的文件中,filp_open函数也调用了do_filp_open函数,接口非常类似于sys_open函数。调用参数也和sys_open一样,使用EXPORT_SYMBOL导出,所以我们猜测这个函数可以打开文件,功能和open一样。同样的查找方法,我们在内核中找到了一组操作文件的函数,如下:char__user*buf,size_tcount,loff_t*pos)写入文件ssize_tvfs_write(structfile*file,constchar__user*buf,size_tcount,loff_t*pos)关闭文件intfilp_close(structfile*filp,fl_owner_tid)我们注意到在vfs_read和vfs_write函数中,参数buf用户空间指向的内存地址,如果我们直接使用内核空间的指针,会返回-EFALUT。所以我们需要使用set_fs()和get_fs()宏来改变内核处理内存地址检查的方式,所以在内核空间读写文件的过程是:mm_segment_tfs=get_fs();set_fs(KERNEL_FS);//vfs_write();vfs_read();set_fs(fs);下面是内核中文件操作的例子:#include
