内核空间文件操作函数注释

来源:互联网 发布:索引超出数组界限 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");
0 0
原创粉丝点击