Linux中page、buffer_head、bio的联系

Linux高速缓存概述 [数据缓冲区高速缓存] 内核通过保存一个称为数据缓冲区高速缓存的内部数据缓冲区池来试图减小对磁盘的存取频率。高速缓冲含有最近被使用过的磁盘块的数据 在Linux内核0.11中,它默认最多支持16M的物理内存。对系统内存的分配情况如下:Linux内核占用物理内存最前段的一部分。随后是高速缓冲区,它的最高内存地址为4MB。高速缓冲区被显示内存ROM BIOS分成两段。剩余的内存部分称为主内存区, 阅读详情

在Linux Block IO层,说到关键数据结构我想可能就只有标题中描述的三种了。我们今天就来详细描述这三种数据结构在文件系统和块设备层扮演的角色以及他们之间的联系。

PAGE

page在内核中被称为缓存页,在文件系统中扮演最核心的角色。Linux使用内存缓存文件数据,而所有的文件内容都被分割成page然后通过一定方式组织起来,便于查找。
这里写图片描述
page大小固定,当前一般为4KB。一个大文件的缓存可能会占据很多page。



BUFFER_HEAD

buffer_head顾名思义,表示缓冲区头部。这个缓冲区缓冲的是磁盘等块设备数据,而buffer_head则是描述缓冲区的元数据。

前面说过,内核以page为单位管理文件内容,page典型大小为4KB,而一般块设备的访问以扇区为单位,扇区的一般大小为512 byte,当然随着技术的进步,这个大小也在不断提升。而文件系统最小逻辑可寻址单元称为块。块的大小要比扇区大,但又比页小,典型大小为1K。 内核执行磁盘的所有操作是按照块来操作的。

在如此背景之下,便诞生了buffer_head这样的数据结构,它是内核page与磁盘上物理数据块之间的桥梁。一方面,每个page包含多个buffer_head(一般4个),另外一方面,buffer_head中又记录了底层设备块号信息。这样,通过page->buffer_head->block就能完成数据的读写。

page与buffer_head数据结构之间关系如下图所示:假设page大小为4KB,而文件系统块大小为1KB。
这里写图片描述

page通过private字段索引该page的第一个buffer_head,而所有的buffer_head通过b_this_page形成一个单循环链表;
buffer_head中的b_data指向缓存文件的块数据;
buffer_head内还通过b_page指向其所属的page(图中未画出)

由于buffer_head描述的是文件系统块缓存,既然缓存,便存在数据一致性问题:缓存中的数据可能比磁盘数据落后,缓存中的数据也可能比磁盘数据新。因此,需要一种机制来描述这些状态。buffer_head中需要一系列的状态位。

enum bh_state_bits {
    BH_Uptodate, 
    BH_Dirty,
    BH_Lock,
    BH_Req,
    BH_Uptodate_Lock,
    BH_Mapped,
    BH_New,
    BH_Async_Read,
    BH_Async_Write,
    BH_Delay,
    BH_Boundary,
    BH_Write_EIO,
    BH_Unwritten,
    BH_Quiet, 
    BH_Meta,
    BH_Prio,
    BH_Defer_Completion, 
    BH_PrivateStart,
}

其中:
BH_Uptodate: 表示缓存数据与磁盘数据一致
BH_Dirty: 表示缓存数据被更新,有待同步至磁盘上。
这些状态何时会被更新呢?

以BH_Uptodate为例,当文件系统向块设备层发起一次读请求时,会注册一个完成时的回调函数end_buffer_read_sync,在IO层返回读取结果后,该函数内根据读取结果:

  • 如果读取成功,则说明buffer_head缓冲区中的数据与磁盘上一致,设置BH_Update。
  • 如果读取失败,说明buffer_head缓冲区的数据处于一种不一致状态,此时,需要清除buffer_head的BH_Update。
static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate)
{
    if (uptodate) {
        set_buffer_uptodate(bh);
    } else {
        clear_buffer_uptodate(bh);
    }
    unlock_buffer(bh);
}

void end_buffer_read_sync(struct    
    buffer_head *bh, int uptodate)
{
    __end_buffer_read_notouch(bh, uptodate);
    put_bh(bh);
}




BIO

        在 Linux 2.6 版本以前,buffer_head 是 kernel 中非常重要的数据结构,它曾经是 kernel 中 I/O 的基本单位(现在已经是 bio 结构),它曾被用于为一个块映射一个页,它被用于描述磁盘块到物理页的映射关系,所有的 block I/O 操作也包含在 buffer_head 中。但是这样也会引起比较大的问题:buffer_head 结构过大(现在已经缩减了很多),用 buffer head 来操作 I/O 数据太复杂,kernel 更喜欢根据 page 来工作(这样性能也更好);另一个问题是一个大的 buffer_head 常被用来描述单独的 buffer,而且 buffer 还很可能比一个页还小,这样就会造成效率低下;第三个问题是 buffer_head 只能描述一个 buffer,这样大块的 I/O 操作常被分散为很多个 buffer_head,这样会增加额外占用的空间。因此 2.6 开始的 kernel (实际 2.5 测试版的 kernel 中已经开始引入)使用 bio 结构直接处理 page 和地址空间,而不是 buffer。
        因此,当前的内核在向块设备层提交读写请求时,都会将buffer_head封装在bio结构中,而不再使用原来的buffer_head,例如下面这段代码是ext2文件系统向磁盘写数据的实现:

static int submit_bh_wbc(int rw, struct buffer_head *bh,                         
unsigned long bio_flags, struct writeback_control *wbc)
{
    struct bio *bio;           

    if (test_set_buffer_req(bh) && (rw & WRITE))                 
        clear_buffer_write_io_error(bh);

    bio = bio_alloc(GFP_NOIO, 1); 
    if (wbc) {                 
        wbc_init_bio(wbc, bio);
        wbc_account_io(wbc, bh->b_page, 
            bh->b_size);
    }

    bio->bi_iter.bi_sector = bh-
        >b_blocknr * (bh->b_size >> 9);
    bio->bi_bdev = bh->b_bdev; 

    bio_add_page(bio, bh->b_page, bh-
        >b_size, bh_offset(bh));

    bio->bi_end_io = end_bio_bh_io_sync;
    bio->bi_private = bh;
    bio->bi_flags |= bio_flags;
    ......
}
linux内核之page数据结构 Linux内核的内存管理以page页面为核心,struct page数据结构提供了很多字段,其中_refcount_mapcount是两个非常重要的引用计数,正确理解它们是理解Linux内核内存管理的基石。对于文件映射页面,mapping指向该文件所属的address_space结构,它包含文件所属的介质相关信息,如inode节点,节点对应操作方法等;对于PG_private页面,主要在块设备的buffer_head中使用,如buffer_migrate_page()会增加_refcount; 阅读详情

相关推荐

芯片设计新思路:如何用SystemC+TLM2.0快速搭建ESL性能模型(附GEM5实战案例)

本文探讨了在芯片设计早期利用SystemCTLM2.0标准快速构建电子系统级(ESL)性能模型的方法。通过对比不同抽象层次,详细介绍了如何搭建事务级模型,并与GEM5仿真平台协同,实现高效的架构探索性能评估。文章最后通过一个片上网络(NoC)带宽优化的实战案例,展示了该方法如何驱动数据驱动的设计决策,从而在流片前规避风险、优化芯片性能。

fire9的博客 332

Linux 通用块设备层基础之buffer_head .

Linux 通用块设备层基础之buffer_head

程序员应用AI大模型创业实现财务自由的100种赚钱方案原理与实战指南

成功的 AI 创业者都遵循着 “技术 + 需求 + 变现” 的铁三角法则。记住:不是要做 “全能大模型”,而是成为某个垂直领域的 “AI 解决方案专家”。现在就开始行动:用周末 2 小时完成第一个 MVP,下周启动种子用户测试,三个月内找到可复制的盈利模式。当你实现第一个 10 万用户时,会发现财务自由的密码藏在持续迭代的每个 0.1 版本更新中。延伸思考:你的技术背景适合切入哪个细分领域?

AI天才研究院 1304

page,bio,与buffer_head的关系

一、pagebuffer_head的关系 1、页中的块在磁盘上连续如果page中的块在磁盘上连续,那么page的PG_private不会被置位,private字段也不会指向buffer_head的链表。 但是page还是得用到buffer_head结构,因为它需要通过get_block()函数来获得磁盘上的逻辑块号。虽然ext2_getblock()函数的代码我暂时还没有

guogaofeng1219的专栏 3297

块缓冲区缓冲区首部buffer_head

注:本文分析基于linux-4.18.0-193.14.2.el8_2内核版本,即CentOS 8.2 1 buffer_head 2 struct buffer_head主要成员变量 在这里插入代码片 3 创建buffer_head 4 删除buffer_head 5 结构关系

Blue summer的博客 1984

Linuxpagebuffer_headbio的关系

pagebuffer_headbuffer_headbio

最后一个bug的博客 537

buffer_headbio

一、pagebuffer_head的关系   1、页中的块在磁盘上连续 如果page中的块在磁盘上连续,那么page的PG_private不会被置位,private字段也不会指向buffer_head的链表。   但是page还是得用到buffer_head结构,因为它需要通过get_block()函数来获得磁盘上的逻辑块号。 虽然ext2_getblock()函数的代码我暂时还没有

海纳百川 4728

Linux 页高速缓存之buffer head

这里主要分析page, buffer_head与磁盘块之间关联。

bin_linux96的专栏 2534

2010-3-29 page buffer_head

与前两个帖子有点重复,只是想全面具体一点。 通过阅读函数do_mpage_readpage()的代码,我可以确定pagebuffer_head没有必然关系,即在页高速缓存中,如果页中的块在磁盘上不连续,那么就需要构造buffer_head链表,由page中的private字段指向该链表头,且PG_private标志置位;如果页中的块

yangp01的专栏 3123

Linux文件系统(四) - 从文件系统到块设备/从page cache到bio, request, request_queue

回写线程一步步会把page cache变成bio,然后bio组织成request,最终request链接到resquest queue中,供块设备层使用。 上一节中do_writepages通过a_ops->writepages会调用不同文件系统中在struct address_space_operations中实现的writepage函数来将page cache写到磁盘,在fat文件系统中这个结

luckywang1103的专栏 4958

LINUX下进程打开的文件怎么底层磁盘关联的?

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34162228的博客 128

Linux基础IO(三)(内核级缓冲区到磁盘)

用户进程 ↔ 文件描述符: 通过fd找到内核中的。文件对象 ↔ 地址空间通过f_mapping指针找到所属的。文件偏移 ↔ 缓存页: 当你读文件偏移量 X 时,内核计算出对应的页索引。然后通过中的i_pages(基数树) 查找index,如果能找到,就得到对应的。这个就是文件内容在内存中的缓存。缓存页 ↔ 磁盘块如果缓存命中,数据直接从拷贝到用户空间。如果缓存未命中,内核会分配一个新的。对于这个新页,内核会通过文件系统提供的a_ops函数,根据文件 inode 页索引index。

Xzq210509的博客 348

buffer_head数据结构

buffer_head用来将一个单独的block映射到一个page,一般80x86体系结构上,根据block size大小,一个page可以包含1-8个block,比如如果block size = 1K,那么一个缓存page缓存4个block,且buffer_head是文件系统block layer的io基本单位。假设page size = 4K, block size = 1K。bio取代了buffer_head作为io基本单位。

GetnextWindow的专栏 1566

linux进入磁盘目录,LINUX下进程打开的文件怎么底层磁盘关联的?

一直有个疑惑,文件是放在磁盘中的,但是操作文件却是在内存中,这两者是怎么关联的呢,虽然至今还没有找到更详细的答案,但是对linux底层数据结构进行梳理后,发现了其中的一些线索,与大家分享。一、相关的linux数据结构1. fd在编程语言里面,打开一个文件一般的操作需要建立一个文件描述符fd:int fd = open(...);fd是一个int型,其实是一个数组的下标,前三个0,1,2被输入,输出...

weixin_42619742的博客 206

Linux内核缓存管理技术全景图谱:从网络到存储的十八般武艺

Linux内核缓存管理技术全景解析 Linux内核缓存管理作为系统的"隐形骨架",支撑着文件系统、网络、存储等核心子系统的高效运行。本文基于Linux 6.x内核源码,系统梳理了七大类缓存技术: 基础内存分配层:包含SLAB/SLUB对象缓存、kmalloc通用分配、vmalloc虚拟内存及CMA连续内存分配器,为上层提供基础内存管理能力。 网络子系统缓存:包括sk_buff网络包缓冲区、TCP接收缓冲区page_frag分片缓存,针对网络数据包的高效处理进行优化。 存储文件系统缓存:

zhilin_tang的专栏 146

Linux文件系统从磁盘读页面

1. 引言 在我前面的博客中详细分析了Linux页面缓存的实现机制,包括各种数据结构以及之间的关联。本篇专栏中我们将会详细讨论文件系统如何从磁盘上读出一个页面。 我们知道,文件系统以页面(page,默认大小4096字节)为单位缓存文件数据,而早期的Linux中是以buffer head结构组织文件缓存的。每个buffer head数据大小与文件系统块大小相同,在当前版本操作系统中,page

趴趴熊的专栏 2116

通用块层,scsi_cmd的产生及发送,mmc block实现.

1. 引言 在我前面的博客中详细分析了Linux页面缓存的实现机制,包括各种数据结构以及之间的关联。本篇专栏中我们将会详细讨论文件系统如何从磁盘上读出一个页面。 我们知道,文件系统以页面(page,默认大小4096字节)为单位缓存文件数据,而早期的Linux中是以buffer head结构组织文件缓存的。每个buffer head数据大小与文件系统块大小相同,在当前版本操作系统中,pageb

fouweng的博客 2485

buffer_head bio

bio是一个io的基本单位,一个bio里面包含n个bio_vec,而每个bio_vec(page,offset,len)里面包含一个segment,而每个segment里面包含连续的几个buffer。而buffer_head就是用来保存对物理内存磁盘块之间映射关系的结构,也就是buffer_head对应于一个buffer 简言之,buffer_head是用来管理buffer的,bio是用来传输

少想多做 3373

海关与上市公司匹配数据(2000-2016年)

一、数据介绍数据名称:海关与上市公司匹配数据数据年份:2000-2016年数据说明:该数据匹配了上市公司的证券代码相关信息,也可以利用它进行其他信息匹配指标说明:海关数据指标包括贸易国、贸易产品名称、8位hs编码、进出口编码、贸易方式、进出口金额、数量、价格、交易时间、公司名称等信息;匹配后为上市公司出口信息。(注,部分年份统计方式有变化,因此不是完全平衡面板,但是不影响正常研究使用)二、数据匹配方式参考金祥义(2017)匹配方式,采用递进的合并方法,首先匹配两个数据库中的企业名称,然后将剩余样本依次按企业地址、法定代表人、邮政编码及企业电话后 7 位进行合并。三、类似文献示例 金祥义,戴金平. 有效信息披露与企业出口表现[J]. 世界经济, 2019,(05):99-122.李宏,王云廷,吴东松.专利质量对企业出口竞争力的影响机制:基于知识宽度视角的探究[J].世界经济研究,2021(01):32-46+134.

上一篇: Ubuntu16.04 一个内存虚拟磁盘块设备驱动的例子
cxy_chen
博客等级 码龄10年 5粉丝 3原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值