文件IO

1.概述

文件io是通过系统调用实现的。每次调用read和write都会触发一次系统调用。

2.read

不论是java的FileInputStream,还是标准c的fread,最终都是调用的系统调用接口read。

ssize_t read(int filedes,void *buf,size_nbytes);


参数分别为文件描述符地址,返回内容的存放地址和请求的字节数,返回值为实际读取字节数(如果到达文件结尾返回0,出错返回-1)

read函数的调用过程如下:

read------> sys_read()------->generic_file_read()------->__generic_file_aio_read()------->do_generic_file_read()------>readpage();

其中read到sys_read为系统调用,从用户态切换到内核态

介绍下这几个函数的主要内容:
1.sys_read():

  • 根据fd取得file对象(file对象是这个进程和这个文件关联的对象,包括inode的指针,偏移量等)
  • 根据file对象检查读写权限,验证参数,检查文件锁,都通过则调用file->f_op->read

2.generic_file_read(filp,buf,count,ppos)

  • 参数包括flip:file对象指针,buf存放返回数据的地址,count要读取的字节数,ppos偏移量
  • 封装了kiocb描述符,iovec描述符,调用__generic_file_aio_read

3.__generic_file_aio_read(kiocb,iovec[],length,ppos)

  • 验证一些参数

  • 建立一个读操作描述符.

  • 调用do_generic_file_read()

4.do_generic_file_read()

  • 通过file对象的f_mapping指针获得address_space对象.(address_space是一个文件的页高速缓存核心数据结构,它有一个指向索引节点对的指针host,同时也是索引节点对象的一个属性)
  • 用要读取的数据的偏移量ppos算出读取的数据在高速缓存中的index(*ppos/4096).通过这个index可以在address_space中找到对应的页(page)
  • 传入计算出的index和ppos在第一页的页内偏移量,开始循环读取所有的page(直到读满所需字节数或者到文件尾)
    • 如果需要预读,就调用page_cache_readahead()读取。
    • 调用find_get_page(*address_space, index)查找是否在页高速缓存中(一个文件的多个page在页高速缓存中以树的方式存在,方便查找)
    • 如果命中,则将返回数据拷贝到用户缓冲区(buf),(通过调用__copy_to_user(),如果用户态内存页不存在可能触发缺页异常来分配页),这里省略了一些分支逻辑。
    • 如果不命中,调用address_space的readpage从硬盘把数据读入页高速缓存,再考到用户缓冲区,继续循环。
  • 更新file对象的偏移量,返回结果。

5.readpage

  • 通过address_space的host指针找到inode对象,通过inode对象算出页中的块数(一块可能是1024或者其他)以及第一块的文件块号。
  • 调用get_block取得逻辑块号,调用bio_alloc()创建一个bio描述符,然后调用submit_bio(),提交io请求到io队列。阻塞线程等待读取完成的回调。

总的来说就是先从缓存取,取不到就读硬盘,拷入缓存,再从缓存读取。

3.write

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值