内核空间文件操作函数注释
来源:互联网 发布:索引超出数组界限 u8 编辑:程序博客网 时间:2024/05/09 19:51
内核空间读写文件的常规操作步骤同用户空间一样
第一步:打开文件,获取文件指针
第二步:将文件读入到一段内存中
第三步:将一段内存中的数据写入到另一个文件中。
完成上述功能要用的内核函数有:
◆打开文件filp_open()
◆关闭文件filp_close()
◆读文件内容到内存中vfs_read()
◆写内存中的数据到文件vfs_write()
函数 filp_open(const char* filename, int open_mode, int mode)
函数功能:在内核空间中打开文件
函数原形:
strcut file* filp_open(const char* filename, int open_mode, int mode);
返回值:strcut file*结构指针,供后继函数操作使用,该返回值用IS_ERR()来检验其有效性。
参数:
filename:表明要打开或创建文件的名称(包括路径部分)。
open_mode:文件的打开方式,O_RDONLY 只读打开、O_WRONLY 只写打开、O_RDWR 读写打开、O_CREAT 文件不存在则创建。
mode:创建文件时使用,设置创建文件的权限,其它情况可以匆略设为0
示例
struct file *file = NULL;file = filp_open(/root/test.txt,O_RDWR|O_CREAT,0);//以读写方式(没有则创建)打开文件/root/test.txt。并返回test.txt的文件指针给file.
函数 filp_close(struct file*filp, fl_owner_t id)
函数功能:关闭之前打开文件
函数原型:int filp_close(struct file*filp, fl_owner_t id);
参数:
struct file*filp:打开文件的文件指针
fl_owner_t id:一般传递NULL值,也可用current->files作为实参。
示例
filp_close(file, NULL); //关闭指针为file的文件。
函数 vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
函数功能:读取已经打开的文件到内存中
函数原型:
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos){ ssize_t ret; if (!(file->f_mode & FMODE_READ)) //判断文件是否可读 return -EBADF; if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read)) //是否定义文件读方法 return -EINVAL; if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) return -EFAULT; ret = rw_verify_area(READ, file, pos, count); //读校验 , if (ret >= 0) { count = ret; if (file->f_op->read) ret = file->f_op->read(file, buf, count, pos); //调用文件读操作方法 else ret = do_sync_read(file, buf, count, pos); //通用文件模型读方法 if (ret > 0) { fsnotify_access(file->f_path.dentry); add_rchar(current, ret); } inc_syscr(current); } return ret;}
通过filp_open我们已经可以在当前进程的文件描述表中找到了file , 于是我们就可以调用保存在file中的文件操作方法(file_operation) file->f_op->read(file, buf, count, pos)来具体的操作文件。
上面的代码实现并不复杂,在做了一些条件判断以后,如果该文件索引节点inode定义了文件的读实现方法的话,就调用此方法。Linux下特殊文件读往往是用此方法, 一些伪文件系统如:proc,sysfs等,读写文件也是用此方法。而如果没有定义此方法就会调用通用文件模型的读写方法.它最终就是读内存,或者需要从存储介质中去读数据.
参数:
struct file *file:打开的文件返回的文件指针,(读的目标文件)
char __user *buf:在用户空间开辟的一段内存空间的首地址,用来保存文件数据。
size_t count:指定读取文件中的多少内容。单位字节
loff_t *pos:文件起始位置偏移值,若从文件头读取,则偏移值为0.可以在文件自身的信息中获取
示例
int *buf;loff_t *pos = &(file->f_pos);buf = (int *)kmalloc(fsize+100,GFP_KERNEL);//分配一个文件自身大小+100字节边界的内存空间,将用来存放打开的文件,内存分配方式为kmalloc的flag标志GFP_KERNEL。vfs_read(file, buf, fsize, pos); //读文件(指针为file)到内存(buf为起始地址)中,读取字节数定为文件自身大小,偏移为自身.
函数 vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
函数功能:将内存中的一段数据写到文件中
函数原形:
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos){ ssize_t ret; if (!(file->f_mode & FMODE_WRITE)) return -EBADF; if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write)) return -EINVAL; if (unlikely(!access_ok(VERIFY_READ, buf, count))) return -EFAULT; ret = rw_verify_area(WRITE, file, pos, count); if (ret >= 0) { count = ret; if (file->f_op->write) ret = file->f_op->write(file, buf, count, pos); else ret = do_sync_write(file, buf, count, pos); if (ret > 0) { fsnotify_modify(file->f_path.dentry); add_wchar(current, ret); } inc_syscw(current); } return ret;}
可以看出这个函数和vfs_read()是差不多的,只是调用的文件操作方法不同而已(file->f_op->write) ,如果没有定义file->f_op->write ,同样也需要do_sync_write()调用同样文件写操作, 首先把数据写到内存中,然后在适当的时候把数据同步到具体的存储介质中去.
参数:
struct file *file:打开的文件返回的文件指针,(写的目标文件)
char __user *buf:数据在内存中的位置,以该地址为起始的一段内存数据将要写到文件中
size_t count:指定写入文件中的多少内容。单位字节
loff_t *pos:文件起始位置偏移值,若从文件头读取,则偏移值为0.可以在文件自身的信息中获取
示例
loff_t *pos = &(file->f_pos);vfs_write(file,buf,fsize,pos);
获取文件的大小
我们可以利用文件的inode结构获得文件的大小,参考代码如下
struct file *file = NULL;struct inode *inode = NULL;file = filp_open(file_path,O_RDWR|O_CREAT,0);inode = file->f_dentry->d_inode;fsize = inode->i_size;printk(KERN_ALERT "size=%d/n",(int)fsize);
示例代码
此ko模块代码在arm架构的fpga上已经跑通。因为涉及的参数比较多,为了清楚地重现重要步骤,对每步骤的函数进行了简单的封装。参数的传递只要理解上面的介绍即可区分清楚。执行流程在static int hello_init(void)函数中
/** kernel_hello_file.c** Created on: 2010-11-9* Author: Wang BaoYi(zats)* Email:wby0322@gmail.com*/#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/syscalls.h>#include <asm/unistd.h>#include <asm/uaccess.h>#define FILE_PATH_READ "/file_read_test"//打开文件路径(包括文件名),未来将要读的#define FILE_PATH_WRITE "/new_file_test"//打开文件路径(包括文件名),未来将要写的struct file *file = NULL; //保存打开文件的文件指针变量struct inode *inode = NULL; //为了获取文件大小用的inode结构变量int *file_buf; //保存开辟的内存空间的地址的指针变量loff_t fsize; //保存文件大小的变量mm_segment_t old_fs; //保存内存边界的变量/** kernel_file_open封装了文件打开函数* 参数为文件路径(包含文件名)。* 操作file类型结构变量。* 打开方式为读写(没有则创建)*/static int kernel_file_open(char *file_path){ file = filp_open(file_path,O_RDWR|O_CREAT,0); if (IS_ERR(file)) { printk("Open file %s failed./n", file_path); return 0; }}/** kernel_file_size封装了获取文件大小函数* 参数为待获取大小的文件指针。* 操作inode类型结构变量。* 返回值为文件大小,单位字节*/static loff_t kernel_file_size(struct file *file){ inode = file->f_dentry->d_inode; fsize = inode->i_size; printk(KERN_ALERT "size=%d/n",(int)fsize); return fsize;}/** kernel_addr_limit_expend封装了内存边界扩展函数* 参数无。*/static int kernel_addr_limit_expend(void){ old_fs = get_fs(); set_fs(KERNEL_DS); return 0;}/** kernel_addr_limit_resume封装了内存边界恢复函数* 参数无。*/static int kernel_addr_limit_resume(void){ set_fs(old_fs);}/** kernel_file_read封装了读文件函数* 参数为open的文件指针,获取的文件大小* 返回值为读入到内存中的首地址。*/void *kernel_file_read(struct file *file,loff_t fsize){ int *buf; loff_t *pos = &(file->f_pos); buf = (int *)kmalloc(fsize+100,GFP_KERNEL); vfs_read(file, buf, fsize, pos); return buf;}/** kernel_file_ write封装了读文件函数* 参数为open的文件指针,数据在内存中的地址,写入到文件的字节数*/static int kernel_file_write(struct file *file,int *buf,loff_t fsize){ loff_t *pos = &(file->f_pos); vfs_write(file,buf,fsize,pos);}/** ko的主函数*/static int hello_init(void) //ko的主函数{ printk(KERN_ALERT "Y(^_^)Y Hello Wang`s file./n"); kernel_file_open(FILE_PATH_READ); //打开文件file_read_test kernel_file_size(file); //获取file_read_test的大小 /*read file to mem*/ kernel_addr_limit_expend(); //边界扩展 file_buf = kernel_file_read(file,fsize); //读操作 filp_close(file, NULL); //关闭文件file_read_test kernel_addr_limit_resume(); //边界恢复 /*write mem to file*/ kernel_file_open(FILE_PATH_WRITE); //打开文件new_file_test,没有则创建 kernel_addr_limit_expend(); //边界扩展 kernel_file_write(file,file_buf,fsize); //将前面读到内存中的数据,写入到文件new_file_test中 filp_close(file, NULL); //关闭文件 kernel_addr_limit_resume(); //边界恢复 return 0;}static void hello_exit(void){ printk(KERN_ALERT "BYE BYE file Y(^_^)Y/n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("wby");MODULE_DESCRIPTION("A simple hello world Module with File");
- 内核空间文件操作函数注释
- Driver:LED灯操作、内核空间和用户空间的数据交互、ioctl函数、设备文件安装与销毁
- 用户空间和内核空间文件操作 file_operations
- linux内核空间 打开、读、写等文件操作实现
- Windows内核函数(2) - 内核模式下的文件操作
- Windows内核编程之简单文件的操作相关函数
- Linux内核查找文件操作函数的过程
- 一些内核操作函数
- 内核文件操作
- 内核操作文件
- 内核态文件操作
- 内核模式 文件操作
- 内核态文件操作
- Linux 内核文件操作
- 内核态文件操作
- 内核态文件操作
- linux内核空间与用户空间互访操作
- c++文件\函数\头文件注释格式
- 『AngularJS』一点小小的理解
- VS2013 未能对Qt5.3库进行智能提示
- NSTimer你真的会用了吗
- 经典重读《信号与系统》-第三章
- 汇编语言21号中断
- 内核空间文件操作函数注释
- Spark SQL之External DataSource外部数据源(二)源码分析
- 说说构建高可扩Web架构和分布式系统
- 一篇很全面的freemarker教程
- NSNull
- Json.Net 排除某些字段
- Spring事务的传播行为和隔离级别
- 【C基础】常见动态内存错误
- bzoj3107: [cqoi2013]二进制a+b DP