缓冲和缓存是利用一部分系统物理内存,确保最重要的、最常使用的块设备数据在操作时可直接从主存获取,而无需从低速设备读取。内核为块设备提供了两种通用的缓存方案。、
1. 页缓存:针对以页为单位的所有操作,并考虑了特定体系结构上的页长度。基本上其他类型的文件访问也是基于内核中的这一技术实现的,所以也缓存实际上会负责块设备的大部分工作。
2. 块缓存:以块为操作单位。在进行I/O操作时,存取的是设备的各个块,而不是整个内存页。
在许多场合下,页缓存和块缓存是联合使用的。页的长度对所有文件系统都是相同的,基本上为4K,但是块长度则需要取决于特定的文件系统或其设置。
曾经,缓冲区是对块设备进行I/O操作的传统方式。但在现在这个领域中,缓冲区只用于支持规模很小的读取操作,在这种场合下高级方法可能显得比较笨重。所以在内核版本2.5开发期间引入了BIO,以替换缓冲区,用于块传输的标准数据结构。
块缓存的结构
与内存页相比,块的大小小于等于内存页的,且长度是可变的,依赖于使用的块设备文件系统。块缓存也由两部分组成。
1. 缓冲头(buffer header)包含了与缓冲区状态相关的管理数据
2. 数据保存在专门分配的页中,这些页也可能同时存在于页缓存中。它存储在物理内存的一个独立区域中,由缓冲头结构中一个对应的指针表示。
图1 页与缓冲之间的链接
从图1可以看出页与缓存之间的关系,sector表示的是磁盘一个扇区大小512 Byte,block表示块大小,假设为1024 Byte(也有可能是4096 Byte),page表示页大小4096 Byte。从图中可知,页可以细分为更小的部分,各个部分之间是完全连续的,一个缓冲区(block buffer)至少512 Byte组成,每页最多可包括MAX_BUF_PER_PAGE个缓冲区。
块缓存主要的数据元素是缓冲头,它的定义是buffer_head.h文件中。
/*
* 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, and buffer_heads are used for extracting block
* mappings (via a get_block_t call), for tracking state within
* a page (via a page_mapping) and for wrapping bio submission
* for backward compatibility reasons (e.g. submit_bh).
*/
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 I/O完成*/
void *b_private; /* reserved for b_end_io 保留给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 缓冲头的使用计数*/
};
缓冲区类似于页,可以有许多状态。缓冲头的当前状态保存在b_state成员中,可以接受枚举类型bh_state_bits提供的值。
enum bh_state_bits {
BH_Uptodate, /* Contains valid data 缓冲区当前的数据是否与后备存储器匹配*/
BH_Dirty, /* Is dirty 缓冲区数据已修改,不再与后备存储器匹配,脏缓冲区*/
BH_Lock, /* Is locked 锁定缓冲区,防止多线程并发处理缓冲区,干扰彼此*/
BH_Req, /* Has been submitted for I/O */
BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
* IO completion of other buffers in the page
*/
BH_Mapped, /* Has a disk mapping */
BH_New, /* Disk mapping was newly created by get_block 新建的缓冲区*/
BH_Async_Read, /* Is under end_buffer_async_read I/O */
BH_Async_Write, /* Is under end_buffer_async_write I/O */
BH_Delay, /* Buffer is not yet allocated on disk */
BH_Boundary, /* Block is followed by a discontiguity */
BH_Write_EIO, /* I/O error on write */
BH_Ordered, /* ordered write */
BH_Eopnotsupp, /* operation not supported (barrier) */
BH_Unwritten, /* Buffer is allocated on disk but not written */
BH_Quiet, /* Buffer Error Prinks to be quiet */
BH_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
*/
};