linux内核空间的IO操作.docx
- 文档编号:23111444
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:11
- 大小:17.85KB
linux内核空间的IO操作.docx
《linux内核空间的IO操作.docx》由会员分享,可在线阅读,更多相关《linux内核空间的IO操作.docx(11页珍藏版)》请在冰豆网上搜索。
linux内核空间的IO操作
探索Linux内核空间文件IO实现(下)
内核空间文件操作函数注释
内核空间读写文件的常规操作步骤同用户空间一样
第一步:
打开文件,获取文件指针
第二步:
将文件读入到一段内存中
第三步:
将一段内存中的数据写入到另一个文件中。
完成上述功能要用的内核函数有:
◆打开文件filp_open()
◆关闭文件filp_close()
◆读文件内容到内存中vfs_read()
◆写内存中的数据到文件vfs_write()
函数filp_open(constchar*filename,intopen_mode,intmode)
函数功能:
在内核空间中打开文件
函数原形:
strcutfile*filp_open(constchar*filename,intopen_mode,intmode);
返回值:
strcutfile*结构指针,供后继函数操作使用,该返回值用IS_ERR()来检验其有效性。
参数:
filename:
表明要打开或创建文件的名称(包括路径部分)。
open_mode:
文件的打开方式,O_RDONLY只读打开、O_WRONLY只写打开、O_RDWR读写打开、O_CREAT文件不存在则创建。
mode:
创建文件时使用,设置创建文件的权限,其它情况可以匆略设为0
示例
structfile*file=NULL;
file=filp_open(/root/test.txt,O_RDWR|O_CREAT,0);
//以读写方式(没有则创建)打开文件/root/test.txt。
并返回test.txt的文件指针给file.
函数filp_close(structfile*filp,fl_owner_tid)
函数功能:
关闭之前打开文件
函数原型:
intfilp_close(structfile*filp,fl_owner_tid);
参数:
structfile*filp:
打开文件的文件指针
fl_owner_tid:
一般传递NULL值,也可用current->files作为实参。
示例
filp_close(file,NULL);//关闭指针为file的文件。
函数vfs_read(structfile*file,char__user*buf,size_tcount,loff_t*pos)
函数功能:
读取已经打开的文件到内存中
函数原型:
ssize_tvfs_read(structfile*file,char__user*buf,size_tcount,loff_t*pos)
{
ssize_tret;
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);
}
returnret;
}
通过filp_open我们已经可以在当前进程的文件描述表中找到了file,于是我们就可以调用保存在file中的文件操作方法(file_operation)file->f_op->read(file,buf,count,pos)来具体的操作文件。
上面的代码实现并不复杂,在做了一些条件判断以后,如果该文件索引节点inode定义了文件的读实现方法的话,就调用此方法。
Linux下特殊文件读往往是用此方法,一些伪文件系统如:
proc,sysfs等,读写文件也是用此方法。
而如果没有定义此方法就会调用通用文件模型的读写方法.它最终就是读内存,或者需要从存储介质中去读数据.
参数:
structfile*file:
打开的文件返回的文件指针,(读的目标文件)
char__user*buf:
在用户空间开辟的一段内存空间的首地址,用来保存文件数据。
size_tcount:
指定读取文件中的多少内容。
单位字节
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(structfile*file,constchar__user*buf,size_tcount,loff_t*pos)
函数功能:
将内存中的一段数据写到文件中
函数原形:
ssize_tvfs_write(structfile*file,constchar__user*buf,size_tcount,loff_t*pos)
{
ssize_tret;
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);
}
returnret;
}
可以看出这个函数和vfs_read()是差不多的,只是调用的文件操作方法不同而已(file->f_op->write),如果没有定义file->f_op->write,同样也需要do_sync_write()调用同样文件写操作,首先把数据写到内存中,然后在适当的时候把数据同步到具体的存储介质中去.
参数:
structfile*file:
打开的文件返回的文件指针,(写的目标文件)
char__user*buf:
数据在内存中的位置,以该地址为起始的一段内存数据将要写到文件中
size_tcount:
指定写入文件中的多少内容。
单位字节
loff_t*pos:
文件起始位置偏移值,若从文件头读取,则偏移值为0.可以在文件自身的信息中获取
示例
loff_t*pos=&(file->f_pos);
vfs_write(file,buf,fsize,pos);
获取文件的大小
我们可以利用文件的inode结构获得文件的大小,参考代码如下
structfile*file=NULL;
structinode*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上已经跑通。
因为涉及的参数比较多,为了清楚地重现重要步骤,对每步骤的函数进行了简单的封装。
参数的传递只要理解上面的介绍即可区分清楚。
执行流程在staticinthello_init(void)函数中
/*
*kernel_hello_file.c
*
*Createdon:
2010-11-9
*Author:
WangBaoYi(zats)
*Email:
wby0322@
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineFILE_PATH_READ"/file_read_test"
//打开文件路径(包括文件名),未来将要读的
#defineFILE_PATH_WRITE"/new_file_test"
//打开文件路径(包括文件名),未来将要写的
structfile*file=NULL;//保存打开文件的文件指针变量
structinode*inode=NULL;//为了获取文件大小用的inode结构变量
int*file_buf;//保存开辟的内存空间的地址的指针变量
loff_tfsize;//保存文件大小的变量
mm_segment_told_fs;//保存内存边界的变量
/*
*kernel_file_open封装了文件打开函数
*参数为文件路径(包含文件名)。
*操作file类型结构变量。
*打开方式为读写(没有则创建)
*/
staticintkernel_file_open(char*file_path)
{
file=filp_open(file_path,O_RDWR|O_CREAT,0);
if(IS_ERR(file))
{
printk("Openfile%sfailed.\n",file_path);
return0;
}
}
/*
*kernel_file_size封装了获取文件大小函数
*参数为待获取大小的文件指针。
*操作inode类型结构变量。
*返回值为文件大小,单位字节
*/
staticloff_tkernel_file_size(structfile*file)
{
inode=file->f_dentry->d_inode;
fsize=inode->i_size;
printk(KERN_ALERT"size=%d\n",(int)fsize);
returnfsize;
}
/*
*kernel_addr_limit_expend封装了内存边界扩展函数
*参数无。
*/
staticintkernel_addr_limit_expend(void)
{
old_fs=get_fs();
set_fs(KERNEL_DS);
return0;
}
/*
*kernel_addr_limit_resume封装了内存边界恢复函数
*参数无。
*/
staticintkernel_addr_limit_resume(void)
{
set_fs(old_fs);
}
/*
*kernel_file_read封装了读文件函数
*参数为open的文件指针,获取的文件大小
*返回值为读入到内存中的首地址。
*/
void*kernel_file_read(structfile*file,loff_tfsize)
{
int*buf;
loff_t*pos=&(file->f_pos);
buf=(int*)kmalloc(fsize+100,GFP_KERNEL);
vfs_read(file,buf,fsize,pos);
returnbuf;
}
/*
*kernel_file_write封装了读文件函数
*参数为open的文件指针,数据在内存中的地址,写入到文件的字节数
*/
staticintkernel_file_write(structfile*file,int*buf,loff_tfsize)
{
loff_t*pos=&(file->f_pos);
vfs_write(file,buf,fsize,pos);
}
/*
*ko的主函数
*/
staticinthello_init(void)//ko的主函数
{
printk(KERN_ALERT"Y(^_^)YHelloWang`sfile.\n");
kernel_file_open(FILE_PATH_READ);//打开文件file_read_test
kernel_file_size(file);//获取file_read_test的大小
/*readfiletomem*/
kernel_addr_limit_expend();//边界扩展
file_buf=kernel_file_read(file,fsize);//读操作
filp_close(file,NULL);//关闭文件file_read_test
kernel_addr_limit_resume();//边界恢复
/*writememtofile*/
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();//边界恢复
return0;
}
staticvoidhello_exit(void)
{
printk(KERN_ALERT"BYEBYEfileY(^_^)Y\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("DualBSD/GPL");
MODULE_AUTHOR("wby");
MODULE_DESCRIPTION("AsimplehelloworldModulewithFile");
简单的效果图
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 内核 空间 IO 操作