分类: LINUX
2015-07-11 13:56:47
原文地址:create_empty_buffers解析 作者:zixin
readpage方法里面包装了block_read_full_page函数,prepare_write里面包装了block_prepare_write函数,其中均调用了create_empty_buffers调用create_buffers为该页建立缓冲区队列,然后对队列进行初始化。
/*
*调用create_buffers为该页建立缓冲区队列,然后对队列进行初始化。
*没有涉及bh的state标志
*调用的create_buffers中设置bh->state = 0
*且把新分配的buffer放入BUF_CLEAN链表(BH_dirty标志为0)
* 缓冲队列头赋给page->buffer
*/
void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize)
{
struct buffer_head *bh, *head, *tail;
/* FIXME: create_buffers should fail if there's no enough memory */
//为该页建立缓冲区队列
head = create_buffers(page, blocksize, 1);
if (page->buffers)
BUG();
//对缓冲队列进行初始化
bh = head;
do {
bh->b_dev = dev; //设备标识符
bh->b_blocknr = 0; //逻辑块号
bh->b_end_io = NULL;
tail = bh;
bh = bh->b_this_page;
} while (bh);
tail->b_this_page = head; //双向链表
page->buffers = head; //链表头赋给page->buffers
page_cache_get(page);
}
EXPORT_SYMBOL(create_empty_buffers);
/*
* Create the appropriate buffers when given a page for data area and
* the size of each buffer.. Use the bh->b_this_page linked list to
* follow the buffers created. Return NULL if unable to create more
* buffers.
* The async flag is used to differentiate async IO (paging, swapping)
* from ordinary buffer allocations, and only async requests are allowed
* to sleep waiting for buffer heads.
*/
/*
*为页面page以async形式(是否异步),分配大小为size的缓冲区
*不能分配更多的buffers时返回NULL
*/
static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)
{
struct buffer_head *bh, *head;
long offset;
try_again:
head = NULL;
offset = PAGE_SIZE; //页面大小
//分配一个buffers就offset-size
while ((offset - = size) >= 0) {
//get_unused_buffer_head来获得一个新的缓冲区首部
//页I/O操作对bh请求,如果未用缓冲区首部链表不为空,则获取unused_list_lock自旋锁,删除其中一个元素并返回它的地址
bh = get_unused_buffer_head(async);
if (!bh)
goto no_grow;
bh->b_dev = NODEV; //虚拟设备标识符
bh->b_this_page = head;
head = bh;
bh->b_state = 0; //state状态标志均为0
bh->b_next_free = NULL; //链接针对缓冲区首部链表的字段
bh->b_pprev = NULL;
atomic_set(&bh->b_count, 0);
bh->b_size = size; //块大小
set_bh_page(bh, page, offset); //设置bh对象的b_page指针和b_date指针
bh->b_list = BUF_CLEAN; //放入BUF_CLEAN链表(BH_dirty标志为0)
bh->b_end_io = NULL;
}
return head;
/*
* In case anything failed, we just free everything we got.
*/
//如果没有分配成功
no_grow:
if (head) {
spin_lock(&unused_list_lock);
do {
bh = head;
head = head->b_this_page;
__put_unused_buffer_head(bh);
} while (head);
spin_unlock(&unused_list_lock);
/* Wake up any waiters ... */
wake_up(&buffer_wait);
}
/*
* Return failure for non-async IO requests. Async IO requests
* are not allowed to fail, so we have to wait until buffer heads
* become available. But we don't want tasks sleeping with
* partially complete buffers, so all were released above.
*/
if (!async)
return NULL;
/* We're _really_ low on memory. Now we just
* wait for old buffer heads to become free due to
* finishing IO. Since this is an async request and
* the reserve list is empty, we're sure there are
* async buffer heads in use.
*/
run_task_queue(&tq_disk);
free_more_memory();
goto try_again;
}
create_empty_buffers(page,dev,blocksize)
+ +
create_buffers bh队列初始化 b_dev = dev逻辑设备标识符
为该页建立buffer队列 bh队列第一个bh地址给page->buffers
+
+++++++++++++++++++++++++++++++++++++++
+ +
get_unsued_buf_head bh->b_dev=NODEV 虚拟设备标识符
获得新bh set_bh_page(bh,page,offset)设置了bh对象b_page指针
b_data指针
bh->state = 0
bh->b_list = BUF_CLEAN 这里表示放入BUF_CLEAN链表
问题1:
问题3:create_empty_buffers中调用了create_buffers将bh对象的b_dev赋值为NODEV,调用完后,又将b_dev赋值为传参进来的dev,即inode->i_dev,为什么呢?