加入收藏 | 设为首页 | 会员中心 | 我要投稿 常州站长网 (https://www.0519zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 移动互联 > 评测 > 正文

5分钟搞懂Linux中直接I/O原理

发布时间:2019-06-15 16:08:37 所属栏目:评测 来源:源理君头条号
导读:副标题#e# 在介绍直接 I/O 之前,先来介绍下直接I/O这种机制产生的原因。毕竟已经有了缓存I/O(Buffered I/O),那肯定能够像到缓存I/O有缺陷吧,就按照这个思路来。 什么是缓存 I/O (Buffered I/O) 缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O

下边我们来看一下当进程通过 read() 系统调用读取一个已经设置了 O_DIRECT 标识符的文件的时候,系统都做了哪些处理。 函数 read() 的原型如下所示:

  1. ssize_t read(int feledes, void *buff, size_t nbytes) ; 

操作系统中处理 read() 函数的入口函数是 sys_read(),其主要的调用函数关系图如下:

  1. sys_read()  
  2.  |-----vfs_read()  
  3.  |----generic_file_read()  
  4.  |----generic_file_aio_read()  
  5.  |--------- generic_file_direct_IO() 
  6. ​ 

函数 sys_read() 从进程中获取文件描述符以及文件当前的操作位置后会调用 vfs_read() 函数去执行具体的操作过程,而 vfs_read() 函数最终是调用了 file 结构中的相关操作去完成文件的读操作,即调用了 generic_file_read() 函数,其代码如下所示:

  1. ssize_t  
  2. generic_file_read(struct file *filp,  
  3. char __user *buf, size_t count, loff_t *ppos)  
  4. {  
  5.  struct iovec local_iov = { .iov_base = buf, .iov_len = count };  
  6.  struct kiocb kiocb;  
  7.  ssize_t ret;  
  8.   
  9.  init_sync_kiocb(&kiocb, filp);  
  10.  ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);  
  11.  if (-EIOCBQUEUED == ret)  
  12.  ret = wait_on_sync_kiocb(&kiocb);  
  13.  return ret;  

函数 generic_file_read() 初始化了 iovec 以及 kiocb 描述符。描述符 iovec 主要是用于存放两个内容:用来接收所读取数据的用户地址空间缓冲区的地址和缓冲区的大小;描述符 kiocb 用来跟踪 I/O 操作的完成状态。之后,函数 generic_file_read() 凋用函数 __generic_file_aio_read()。该函数检查 iovec 中描述的用户地址空间缓冲区是否可用,接着检查访问模式,若访问模式描述符设置了 O_DIRECT,则执行与直接 I/O 相关的代码。函数 __generic_file_aio_read() 中与直接 I/O 有关的代码如下所示:

  1. if (filp->f_flags & O_DIRECT) {  
  2.  loff_t pos = *ppos, size;  
  3.  struct address_space *mapping;  
  4.  struct inode *inode;  
  5.   
  6.  mapping = filp->f_mapping;  
  7.  inode = mapping->host;  
  8.  retval = 0;  
  9.  if (!count)  
  10.  goto out;  
  11.  size = i_size_read(inode);  
  12.  if (pos < size) {  
  13.  retval = generic_file_direct_IO(READ, iocb,  
  14.  iov, pos, nr_segs);  
  15.  if (retval > 0 && !is_sync_kiocb(iocb))  
  16.  retval = -EIOCBQUEUED;  
  17.  if (retval > 0)  
  18.  *ppos = pos + retval;  
  19.  }  
  20.  file_accessed(filp);  
  21.  goto out;  

上边的代码段主要是检查了文件指针的值,文件的大小以及所请求读取的字节数目等,之后,该函数调用 generic_file_direct_io(),并将操作类型 READ,描述符 iocb,描述符 iovec,当前文件指针的值以及在描述符 io_vec 中指定的用户地址空间缓冲区的个数等值作为参数传给它。当 generic_file_direct_io() 函数执行完成,函数 __generic_file_aio_read()会继续执行去完成后续操作:更新文件指针,设置访问文件 i 节点的时间戳;这些操作全部执行完成以后,函数返回。 函数 generic_file_direct_IO() 会用到五个参数,各参数的含义如下所示:

  1. rw:操作类型,可以是 READ 或者 WRITE
  2. iocb:指针,指向 kiocb 描述符 
  3. iov:指针,指向 iovec 描述符数组
  4. offset:file 结构偏移量
  5. nr_segs:iov 数组中 iovec 的个数

(编辑:常州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读