当一个块被调入内存时(也就是说,在读入后或等待写出时),它要存储在缓冲区中。每个缓冲区与一个块对应,它相当于是磁盘块在内存中的表示。块包含一个或多个扇区,但大小不能超过一页,所以一页可以容纳一个或多个内存块。由于内核在处理数据时需要一些相关的控制信息(比如块属于哪个设备,块对应于哪个缓冲区),所以,每一个缓冲区都有一个对应的描述符。该描述符用 buffer_head 结构体表示,称作缓冲区头,在文件  <linux/buffer_head.h> 中定义,它包含了内核操作缓冲区的全部信息。

      下面给出缓冲区头结构体和其中每一个域的说明:


struct buffer_head {
          unsigned long b_state;          /* buffer state bitmap (see above) */
          struct buffer_head *b_this_page;/* circular list of page's buffers */
          struct page *b_page;            /* the page this bh is mapped to */
 
          sector_t b_blocknr;             /* start block number */
          size_t b_size;                  /* size of mapping */
          char *b_data;                   /* pointer to data within the page */
 
          struct block_device *b_bdev;
          bh_end_io_t *b_end_io;          /* I/O completion */
          void *b_private;                /* reserved for b_end_io */
          struct list_head b_assoc_buffers; /* associated with another mapping */
          struct address_space *b_assoc_map;      /* mapping this buffer is
                                                    associated with */
          atomic_t b_count;               /* users using this buffer_head */
  };

      缓冲区头的目的在于描述磁盘块和物理内存缓冲区之间的映射关系。这个结构体在内核中只是扮演一个描述符的角色,说明从缓冲区到块的映射关系。

      在2.6内核以前,缓冲区头的作用比现在还要重要。因为缓冲区头作为内核中的 IO 操作单元,不仅仅描述了从磁盘块到物理内存的映射,而且还是所有块 IO 操作的容器。但是在2.6内核以后改变了这种策略,它使用一个新的结构 -- bio 来作为操作容器。

      bio 结构体定义于 <linux/bio.h> 中,下面给出 bio 结构体和每个域的描述:


struct bio {
        sector_t             bi_sector;         /* associated sector on disk */
        struct bio           *bi_next;          /* list of requests */
        struct block_device  *bi_bdev;          /* associated block device */
        unsigned long        bi_flags;          /* status and command flags */
         unsigned long        bi_rw;             /* read or write? */
        unsigned short       bi_vcnt;           /* number of bio_vecs off */
        unsigned short       bi_idx;            /* current index in bi_io_vec */
        unsigned short       bi_phys_segments;  /* number of segments after coalescing */
        unsigned short       bi_hw_segments;    /* number of segments after remapping */
        unsigned int         bi_size;           /* I/O count */
        unsigned int         bi_hw_front_size;  /* size of the first mergeable segment */
        unsigned int         bi_hw_back_size;   /* size of the last mergeable segment */
        unsigned int         bi_max_vecs;       /* maximum bio_vecs possible */
        struct bio_vec       *bi_io_vec;        /* bio_vec list */
        bio_end_io_t         *bi_end_io;        /* I/O completion method */
        atomic_t             bi_cnt;            /* usage counter */
        void                 *bi_private;       /* owner-private method */
        bio_destructor_t     *bi_destructor;    /* destructor method */
};

      使用 bio 结构体的目的主要是代表正在现场执行的 IO 操作,所以该结构体中的主要域都是用来管理相关信息的,其中最重要的几个域是 bi_io_vecs , bi_vcnt 和 bi_idx 。下图显示了 bio 结构体及其他结构体之间的关系。


      说明:每一个块 IO 请求都通过一个 bio 结构体表示。每个请求包含一个或多个块,这些块存储在 bio_vec 结构体数组中。这些结构体描述了每个片段在物理页中的实际位置,并且像向量一样被组织在一起。 IO 操作的第一个片段由 b_io_vec 结构体所指向,其他的片段在其后依次放置,共有 bi_vcnt个片段。当块 IO 层开始执行请求,需要使用各个片段时, bi_idx 域会不断更新,从而指向当前片段。

      新老方法的比较:

      缓冲区头和新的 bio 结构体之间存在显著差别。bio 结构体代表的是 IO操作,它可以包括内存中的一个或多个页;而另一方面,buffer_head 结构体代表的是一个缓冲区,它描述的仅仅是磁盘中的一个块,所以他可能会引起不必要的分割,将请求按块为单位划分,只能靠以后再重新组合。由于 bio 结构体是轻量级的,它描述的块可以不需要连续存储区,并且不需要分割 IO 操作。

Linux2.6内核--对块IO层操作的讨论相关推荐

  1. 操作系统与存储:解析Linux内核全新异步IO引擎io_uring设计与实现

    作者:draculaqian,腾讯后台开发工程师 引言 存储场景中,我们对性能的要求非常高.在存储引擎底层的IO技术选型时,可能会有如下讨论关于IO的讨论. http://davmac.org/dav ...

  2. Linux文件系统之:通用块处理层 ll_rw_block | +往期文章回顾

    </proc 文件系统并使用/proc 进行输入> <Linux虚拟文件系统概述> <Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件 ...

  3. linux内核的块设备驱动框架详解

    1.块设备和字符设备的差异 (1)块设备只能以块为单位接受输入和返回输出,而字符设备则以字节为单位.大多数设备是字符设备,因为它们不需要缓冲而且不以固定块大小进行操作; (2)块设备对于 I/O 请求 ...

  4. Linux2.6 内核进程调度分析

    Linux2.6 内核进程调度分析    进程的调度时机与引起进程调度的原因和进程调度的方式有关.在 2.6 中,除核心应用     主动调用调度器之外, 核心还在应用不完全感知的情况下在以下三种时机 ...

  5. 详解Linux2.6内核中基于platform机制的驱动模型

    原文地址:详解Linux2.6内核中基于platform机制的驱动模型 作者:nacichan [摘要]本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型.首先介绍了P ...

  6. Windows内核原理-同步IO与异步IO

    目录 Windows内核原理-同步IO与异步IO 背景 目的 I/O 同步I/O 异步I/O I/O完成通知 总结 参考文档 Windows内核原理-同步IO与异步IO 背景 在前段时间检查异常连接导 ...

  7. linux中initrd的含义,Linux2.6 内核的 Initrd 机制解析

    1.什么是 Initrdinitrd 的英文含义是 boot loaderinitialized RAM disk,就是由 boot loader 初始化的内存盘.在 linux内核启动前, boot ...

  8. linux2.6内核Makefile详解

    熟悉内核的Makefile对开发设备驱动.理解内核代码结构都是非常重要的 linux2.6内核Makefile的许多特性和2.4内核差别很大,在内核目录的documention/kbuild/make ...

  9. 1.聊聊Netty那些事儿之从内核角度看IO模型

    从今天开始我们来聊聊Netty的那些事儿,我们都知道Netty是一个高性能异步事件驱动的网络框架. 它的设计异常优雅简洁,扩展性高,稳定性强.拥有非常详细完整的用户文档. 同时内置了很多非常有用的模块 ...

最新文章

  1. JS nodeType返回类型
  2. PMP考试错题记录(2)
  3. 【前沿】MIT搞了个进取型机器人!能研究学习对象操纵的基础
  4. 设计模式 - 基本功的重要性
  5. 调用toString()方法的注意事项
  6. iconfont 图标转为字体_iconfont字体图标的使用方法--超简单!
  7. 前端学习(1578):React简介
  8. HTML+CSS+JS实现 ❤️从亮到暗图片滤镜特效❤️
  9. LNMP实现服务器轮询负载均衡
  10. 技术转管理,用什么来拯救自己?
  11. websocket实现java服务端与js端通信
  12. (转)git 忽略规则
  13. -矩阵-创建矩阵-meshgrid函数
  14. 深入理解Angular2变化监测和ngZone
  15. Google浏览器被搜狗篡改怎么恢复?
  16. mysql回表什么意思_什么是MYSQL回表查询
  17. alpine 使用国内源
  18. MySQL数据库卸载+MySQL常用的图形化管理工具介绍
  19. java连接qq邮箱_java如何使用ssl连接qq邮箱
  20. 哈工大21秋移动互联网复习

热门文章

  1. Android各个文件夹对应的分辨率?
  2. IE遭破坏后的自我修复方法
  3. Web 2.0背后的长尾理论
  4. 美团第一位前端工程师竟是转行程序员!关于他的10年技术生涯
  5. jQuery,Ashx发送站内信
  6. Java Comparator排序
  7. 提取网页中的链接并生成xml
  8. 【剑指offer】丑数
  9. JAVA多线程机制之死锁
  10. CodeSign error: code signing is required for product type Application in SDK iOS XXX的解决办法