Linux 通用块设备层基础之buffer_head
2012-05-29 17:34
246 查看
1. 块设备
Linux 系统中能够随机访问的数据片(chunk)的设备称为块设备,这些数据片称为片。而字符设备是按照字符流的方式有序访问。常见的块设备如硬盘,CD-ROM,而字符设备主要有串口和键盘。块设备最小可寻址的单元称为扇区,通常情况下,扇区的大小为512个字节。而文件系统最小逻辑可寻址单元称为块。块的大小要比扇区大,但比页小,一般为512,1K,或者是4K. 内核执行磁盘的所有操作是按照块来操作的,又称为"文件块"或者是"I/O块"。
2. 缓冲区与缓冲区头
当一个块被调入到内存中,它要被存储在一个缓冲区中。每个缓冲区与一个块对应,它相当于磁盘块在内存中的表示。而文件在内存中由file结构体表示。由于内核处理块时需要一些信息,如块属于哪个设备与块对应于哪个缓冲区。所以每个缓冲区都有一个缓冲区描述符,称为buffer_head. 它包含了内核操作缓冲区所需要的全部信息,在Linux- 2.6.20下的<linux/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 */
void *b_private; /* reserved for b_end_io *I/O完成的方法/
struct list_head b_assoc_buffers; /* associated with another mapping */
struct address_space *b_assoc_map; /* mapping this buffer is
associated with *缓冲区对应的映射,即address_space/
atomic_t b_count; /* users using this buffer_head *表示缓冲区的使用计数/
};
b_state 表示缓冲区的状态,合法的标志存放在 bh_state_bits中,该枚举在<linux/buffer_head.h>中定义。
enum bh_state_bits {
BH_Uptodate, /* Contains valid data *该缓冲区包含可用数据/
BH_Dirty, /* Is dirty 该缓冲区是脏的,缓冲区的内容比磁盘中的块内容要新,所以缓冲区的内容必须被写回磁盘*/
BH_Lock, /* Is locked 该缓冲区正在被I/O操作访问,被锁定以防止并发访问*/
BH_Req, /* Has been submitted for I/O *该缓冲区有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 *缓冲区是通过get_block()刚刚映射的,尚且不能访问/
BH_Async_Read, /* Is under end_buffer_async_read I/O 该缓冲区正通过end_buffer_async_read()被异步I/O读操作使用*/
BH_Async_Write, /* Is under end_buffer_async_write I/O *该缓冲区正通过end_buffer_async_write()被异步写操作使用/
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_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
*/
};
注意:
在操作的缓冲区头之前,应该先使用get_bh()函数增加缓冲区头的引用计数,确保该缓冲区头不会再被分配出去,当完成缓冲区头的操作之后,还必须使用put_bh函数减少引用计数。与缓冲区头对应的磁盘物理块由b_blocknr索引,该值是b_bdev域指明的块设备的逻辑块号。与缓冲区对应的内存物理页由b_page表示. b_data直接指向相应的块(它位于b_page所指明的页面上的某个位置),块的大小由b_size表示。所以块在内存中的起始位置在b_data处,结束位置在(b_data+b_size处。 缓冲区头的目的在于描述磁盘块和物理内存缓冲区之间的映射关系.
在2.6以前,缓冲区头的作用比现在还重要。因为缓冲区头作为内核I/O操作单元,不仅仅描述了从磁盘块到物理内存的映射,而且还是所有块I/O操作的窗口。
但会带来问题:
(1)对内核来说更倾向操作页面,用一个巨大的缓冲区头表示每一个独立的缓冲区效率低下,对缓冲区头的操作不方面
(2)它仅描述单个缓冲区,当作为所有I/O容器使用时,它会使内核打断对大块数据的I/O操作,使其成为对多个buffer_head结构体进行操作,所以引入bio,对块进行操作
总结:
缓冲区:磁盘块在物理内存中的表示形式
缓冲区描述符:对缓冲区的相关信息的描述,描述了缓冲区与磁盘块的映射关系
bio(块I/O):真正的磁盘块操作用bio来表示,无论是经过页面高速缓存的I/O还是直接I/O,都是用bio来操作数据块的。
Linux 系统中能够随机访问的数据片(chunk)的设备称为块设备,这些数据片称为片。而字符设备是按照字符流的方式有序访问。常见的块设备如硬盘,CD-ROM,而字符设备主要有串口和键盘。块设备最小可寻址的单元称为扇区,通常情况下,扇区的大小为512个字节。而文件系统最小逻辑可寻址单元称为块。块的大小要比扇区大,但比页小,一般为512,1K,或者是4K. 内核执行磁盘的所有操作是按照块来操作的,又称为"文件块"或者是"I/O块"。
2. 缓冲区与缓冲区头
当一个块被调入到内存中,它要被存储在一个缓冲区中。每个缓冲区与一个块对应,它相当于磁盘块在内存中的表示。而文件在内存中由file结构体表示。由于内核处理块时需要一些信息,如块属于哪个设备与块对应于哪个缓冲区。所以每个缓冲区都有一个缓冲区描述符,称为buffer_head. 它包含了内核操作缓冲区所需要的全部信息,在Linux- 2.6.20下的<linux/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 */
void *b_private; /* reserved for b_end_io *I/O完成的方法/
struct list_head b_assoc_buffers; /* associated with another mapping */
struct address_space *b_assoc_map; /* mapping this buffer is
associated with *缓冲区对应的映射,即address_space/
atomic_t b_count; /* users using this buffer_head *表示缓冲区的使用计数/
};
b_state 表示缓冲区的状态,合法的标志存放在 bh_state_bits中,该枚举在<linux/buffer_head.h>中定义。
enum bh_state_bits {
BH_Uptodate, /* Contains valid data *该缓冲区包含可用数据/
BH_Dirty, /* Is dirty 该缓冲区是脏的,缓冲区的内容比磁盘中的块内容要新,所以缓冲区的内容必须被写回磁盘*/
BH_Lock, /* Is locked 该缓冲区正在被I/O操作访问,被锁定以防止并发访问*/
BH_Req, /* Has been submitted for I/O *该缓冲区有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 *缓冲区是通过get_block()刚刚映射的,尚且不能访问/
BH_Async_Read, /* Is under end_buffer_async_read I/O 该缓冲区正通过end_buffer_async_read()被异步I/O读操作使用*/
BH_Async_Write, /* Is under end_buffer_async_write I/O *该缓冲区正通过end_buffer_async_write()被异步写操作使用/
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_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
*/
};
注意:
在操作的缓冲区头之前,应该先使用get_bh()函数增加缓冲区头的引用计数,确保该缓冲区头不会再被分配出去,当完成缓冲区头的操作之后,还必须使用put_bh函数减少引用计数。与缓冲区头对应的磁盘物理块由b_blocknr索引,该值是b_bdev域指明的块设备的逻辑块号。与缓冲区对应的内存物理页由b_page表示. b_data直接指向相应的块(它位于b_page所指明的页面上的某个位置),块的大小由b_size表示。所以块在内存中的起始位置在b_data处,结束位置在(b_data+b_size处。 缓冲区头的目的在于描述磁盘块和物理内存缓冲区之间的映射关系.
在2.6以前,缓冲区头的作用比现在还重要。因为缓冲区头作为内核I/O操作单元,不仅仅描述了从磁盘块到物理内存的映射,而且还是所有块I/O操作的窗口。
但会带来问题:
(1)对内核来说更倾向操作页面,用一个巨大的缓冲区头表示每一个独立的缓冲区效率低下,对缓冲区头的操作不方面
(2)它仅描述单个缓冲区,当作为所有I/O容器使用时,它会使内核打断对大块数据的I/O操作,使其成为对多个buffer_head结构体进行操作,所以引入bio,对块进行操作
总结:
缓冲区:磁盘块在物理内存中的表示形式
缓冲区描述符:对缓冲区的相关信息的描述,描述了缓冲区与磁盘块的映射关系
bio(块I/O):真正的磁盘块操作用bio来表示,无论是经过页面高速缓存的I/O还是直接I/O,都是用bio来操作数据块的。
相关文章推荐
- Linux 上的基础网络设备详解
- Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动
- Linux基础之命令练习Day1-init,who,date,cal,man,clear,passwd,su,whoami,mkdir,touch,rm,cp,mv,head,tail,more,less,echo
- Linux基础知识之命令的语法通用格式
- Linux入职基础-3.5_设备文件loop
- linux基础学习(十一) 时间的同步 设备的挂载
- (十四)Linux基础之设备、查找、链接
- Linux设备驱动程序——设备驱动编程基础
- linux 基础复习(9)设备驱动入门转
- Linux 字符设备驱动开发基础(四)—— ioctl() 函数解析
- Linux 上的基础网络设备详解
- linux驱动学习--第一天:设备驱动概述(一)之基础知识
- Linux设备驱动模型学习之基础中的基础篇
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux基础之命令练习Day1-init,who,date,cal,man,clear,passwd,su,whoami,mkdir,touch,rm,cp,mv,head,tail,more...
- linux0.11缓冲处理过程及一点块设备的基础知识
- Linux 上的基础网络设备详解
- 2.最基础Linux设备驱动程序:HelloWorld
- Linux 上的基础网络设备详解
- 【Linux基础系列之】设备模型