把块存放在页高速缓存中

本文详细介绍了Linux内核中块缓冲区的管理,包括块缓冲区头、缓冲区页数据结构的详细信息,以及如何分配和释放块设备缓冲区页。通过缓冲区头的b_state字段和b_count计数器确保数据正确性,同时利用页高速缓存存储块数据,提高效率。
摘要由CSDN通过智能技术生成

VFS(映射层)和各种文件系统以叫做“块”的逻辑单位组织磁盘数据。在Linux内核的旧版本中,主要有两种不同的磁盘高速缓存:页高速缓存和缓冲区高速缓存,前者用来存放访问磁盘文件内容时生成的磁盘数据页,后者把通过VFS(管理磁盘文件系统)访问的块的内容保留在内存中。

 

从2.4.10的稳定版本开始,缓冲区高速缓存其实就不存在了。事实上,由于效率的原因,不再单独分配块缓冲区;相反,把它们存放在叫做“缓冲区页”的专门页中,而缓冲区页保存在页高速缓存中。

 

缓冲区页在形式上就是与称做“缓冲区头”的附加描述符相关的数据页,其主要目的是快速确定页中的一个块在磁盘中的地址。实际上,页高速缓存内的页中的一大块数据在磁盘上的地址不一定是相邻的。

 

1 块缓冲区和缓冲区头

 

每个块缓冲区都有buffer_head类型的缓冲区头描述符。该描述符包含内核必须了解的、有关如何处理块的所有信息。因此,在对所有块操作之前,内核检查缓冲区首部。缓冲区首部的字段位于/include/linux/Buffer_head.h:
struct buffer_head {
      unsigned long b_state;            /* 缓冲区状态标志 */
      struct buffer_head *b_this_page;  /* 指向缓冲区页的链表中的下一个元素的指针 */
      struct page *b_page;              /* 指向拥有该块的缓冲区页的描述符的指针 */

      sector_t b_blocknr;               /* 与块设备相关的块号(起始逻辑块号) */
      size_t b_size;                    /* 块大小 */
      char *b_data;                     /* 块在缓冲区页内的位置 */

      struct block_device *b_bdev;      /* 指向块设备描述符的指针 */
      bh_end_io_t *b_end_io;            /* I/O完成方法 */
       void *b_private;                 /* 指向I/O完成方法数据的指针 */
      struct list_head b_assoc_buffers; /* 为与某个索引节点相关的间接块的链表提供的指针 */
      atomic_t b_count;                 /* 块使用计数器 */
};

 

缓冲区头的两个字段编码表示块的磁盘地址:b_bdev字段表示包含块的块设备,通常是磁盘或分区;而b_blocknr字段存放逻辑块号,即块在磁盘或分区中的编号。

 

b_data字段表示块缓冲区在缓冲区页中的位置。实际上,这个位置的编号依赖于页是否在高端内存。如果页在高端内存,则b_data字段存放的是块缓冲区相对于页的起始位置的偏移量,否则,b_data存放的就是是块缓冲区的线性地址。

 

b_state字段可以存放几个标志。其中一些标志是通用的,我们在下面把它们列出来了。每个文件系统还可以定义自己的私有缓冲区首部标志。

BH_Uptodate:缓冲区包含有效数据时被置位
BH_Dirty:如果缓冲区脏就置位(表示缓冲区中的数据必须写回块设备)
BH_Lock:如果缓冲区加锁就置位,通常发生在缓冲区进行磁盘传输时
BH_Req:如果已经为初始化缓冲区而请求数据传输就置位
BH_Mapped:如果缓冲区被映射到磁盘就置位,即:如果相应的缓冲区首部的b_bdev和b_blocknr是有效的就置位
BH_New:如果相应的块刚被分配而还没有被访问过就置位
BH_Async_Read:如果在异步地读缓冲区就置位
BH_Async_Write:如果在异步地写缓冲区就置位
BH_Delay:如果还没有在磁盘上分配缓冲区就置位
BH_Boundary:如果两个相邻的块在其中一个提交之后不再相邻就置位
BH_Write_EIO:如果写块时出现I/O错误就置位
BH_Ordered:如果必须严格地把块写到在它之前提交的块的后面就置位(用于日志文件系统)
BH_Eopnotsupp:如果块设备的驱动程序不支持所请求的操作就置位

 

缓冲区头有它们自己的slab分配器高速缓存,其描述符kmem_cache_s存在变量bh_cachep中。alloc_buffer_head()和free_buffer_head()函数分别用于获取和释放缓冲区首部。

struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
{
      struct buffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);
      if (ret) {
            get_cpu_var(bh_accounting).nr++;
            recalc_bh_state();
            put_cpu_var(bh_accounting);
      }
      return ret;
}

 

void free_buffer_head(struct buffer_head *bh)
{
    

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值