页缓冲在《linux内核情景分析》一书的第5.6节文件的写与读一章中说明的很详细,这里摘抄下来;
在文件系统层中有三隔主要的数据结构,file结构、dentry结构和inode结构;
file结构:代表目标文件的一个上下文,不同进程可以在同一文件上建立不同的上下文,而且同一进程也可以通过打开一个文件多次而建立起多个上下文。因此不能在file结构上设置缓冲区队列,因为这些file结构体之间都不共享。
dentry结构体:该结构体是文件名结构体,通过软/硬链接可以得到多个dentry结构体对应一个文件,dentry结构体和文件也不是一对一关系,所以也不能在该结构体上建立缓冲区队列;
inode结构体:很显然就只有inode结构体了,inode结构体和文件是一对一的关系,可以这么说inode就是代表文件。在inode结构体上设置了i_mapping指针,该指针指向了一个address_space数据结构,一般来说该数据结构就是inode->i_data,缓冲区队列就是在该数据结构中;
挂在缓冲区队列中的不是记录块而是内存页面,因此当一个进程调用mmap()函数将一个文件映射到它用户空间时,它只要设置相应的内存映射表,就可以很自然的把这些缓存页面映射到进程的用户空间。所以才又起名为i_mapping。
这里还要了解下基数树概念,先看看图(图片来自《深入linux内核架构》)
基数树不是不是平衡树,树本身由两种不同的数据结构组成,树根节点和非叶子节点,树根节点由简单的数据结构表示,其中包含了树的高度和指向组成树的第一个节点的数据结构。节点本质上是数组,count是该节点的指针计数,其他的都是指向下一层节点的指针。而叶子节点是指向page的指针;
其中节点上的数据结构还包含了搜索标记,比如脏页标记和回写标记,可以很快的指定哪边有标记的页;
块缓冲
块缓冲在结构上由两个部分组成:
1、缓冲头:包含与缓冲区状态相关的所有管理数据,块号、长度,访问器等,这些缓冲头不直接存储在缓冲头之后,而是由缓冲头指针指向的物理内存独立区域中。
2、有用的数据保存在专门分配的页中,这些页也可以能同事存在页缓冲中。
缓冲头:
/*
* Historically, a buffer_head was used to map a single block
* within a page, and of course as the unit of I/O through the
* filesystem and block layers. Nowadays the basic I/O unit
* is the bio,