?? buffer.c.txt
字號:
hash_page_buffers(page, dev, block, size); //將這個新產生的頁加入到相應的hash表中
(3)static struct page * grow_dev_page(struct block_device *bdev, unsigned long index, int size)
page = find_or_create_page(bdev->bd_inode->i_mapping, index, GFP_NOFS); //首先找到一個頁面
bh = page->buffers; //先得到這個頁面的buffer域
if (bh) { //如果buffers域中有數據
if (bh->b_size == size) //如果正好是這個大小的,就返回這個頁面
return page;
if (!try_to_free_buffers(page, GFP_NOFS)) //否則,試著釋放掉這個頁面
goto failed;
}
bh = create_buffers(page, size, 0); //否則的話就在這個頁面上產生一個新的buffer
if (!bh)
goto failed;
link_dev_buffers(page, bh);
return page;
(4)static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)
struct buffer_head *bh, *head;
long offset;
head = NULL;
offset = PAGE_SIZE;
while ((offset -= size) >= 0) { //把這一頁都設置為size大小的buffer
bh = get_unused_buffer_head(async); //必須首先得到一個有效的buffer_head結構
if (!bh)
goto no_grow; //如果沒有,就釋放一些buffer_head結構
bh->b_dev = NODEV;
bh->b_this_page = head; //設置在一個頁中的buffer環
head = bh;
…… //對bh進行初始化
set_bh_page(bh, page, offset);
bh->b_list = BUF_CLEAN;
bh->b_end_io = NULL;
}
return head;
void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset)
{
if (offset >= PAGE_SIZE) //進行合法性檢查
BUG();
bh->b_data = page_address(page) + offset; //數據的開始地址,結束地址可以使用開始
//地址加上bh->b_size來進行計算
bh->b_page = page; //紀錄這個buffer所處的內存頁
}
(4)static inline void link_dev_buffers(struct page * page, struct buffer_head *head)
struct buffer_head *bh, *tail;
bh = head;
do {
tail = bh;
bh = bh->b_this_page; //尋找這個buffer所在的內存頁面的所有的buffer,
} while (bh);
tail->b_this_page = head; //把屬于一個內存頁面的所有的buffer連接成為一個環
page->buffers = head;
page_cache_get(page);
()static void free_more_memory(void)
balance_dirty(); //計算臟塊所占的比例
wakeup_bdflush(); //喚醒寫臟塊進程
try_to_free_pages(GFP_NOFS);
run_task_queue(&tq_disk);
__set_current_state(TASK_RUNNING);
sys_sched_yield();
(3)void balance_dirty(void)
int state = balance_dirty_state(); //計算flush策略
if (state < 0) //如果臟塊比例不打,返回
return;
wakeup_bdflush(); //喚醒flush進程
if (state > 0) { //如果是同步flush的話,就等待他完成
spin_lock(&lru_list_lock);
write_some_buffers(NODEV);
wait_for_some_buffers(NODEV);
}
//返回值-1表示不用flush
//0-->異步flush
//1-->同步flush
(4)static int balance_dirty_state(void)
…… //計算臟的比例
soft_dirty_limit = tot * bdf_prm.b_un.nfract;
hard_dirty_limit = tot * bdf_prm.b_un.nfract_sync;
//如果臟塊數量占的比例不是很大,那么就異步flush,也就是僅僅喚醒flush進程
if (dirty > soft_dirty_limit) {
if (dirty > hard_dirty_limit && !(current->flags & PF_NOIO))
return 1; //如果臟塊比例過大,那么就喚醒flush進程并等待他完成
return 0;
}
*********************************************************************
***********************異步等待操作**********************************
相關文件
include/linux/locks.h
這個函數主要是運行塊設備的運行例程,從而將傳入的buffer_head上所制定的操作完成
void __wait_on_buffer(struct buffer_head * bh)
DECLARE_WAITQUEUE(wait, tsk); //生命等待隊列
get_bh(bh); //buffer_head計數加一
add_wait_queue(&bh->b_wait, &wait); //把buffer_head加入到等待隊列中
do {
run_task_queue(&tq_disk); //運行磁盤操作隊列,進行讀寫
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!buffer_locked(bh)) //如果bh還是加鎖,說明沒有完成操作
break;
schedule(); //調度,等待
} while (buffer_locked(bh)); //直到bh解鎖
…… //后續處理
*********************************************************************
**************************異步讀操作**********************************
struct buffer_head * bread(kdev_t dev, int block, int size)
bh = getblk(dev, block, size); //的到一個buffer_head結構
touch_buffer(bh);
if (buffer_uptodate(bh)) //如果的緩存結構中的buffer_head已經是更新的了,就直接返回
return bh;
ll_rw_block(READ, 1, &bh); //否則進行讀操作
wait_on_buffer(bh); //等待讀操作完成
if (buffer_uptodate(bh))
return bh;
brelse(bh); //釋放bh
return NULL; //失敗的讀操作
**********************************************************************
***************************direct I/O操作*****************************
(1)
int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
kdev_t dev, unsigned long b[], int size)
for (i = 0; i < nr; i++) { //對于每一個輸入的kiobuf的結構
iobuf = iovec[i];
…… //都要進行合法性檢查
}
bufind = bhind = transferred = err = 0;
for (i = 0; i < nr; i++) { //可以walk這些vec來進行讀寫了
iobuf = iovec[i];
offset = iobuf->offset; //
length = iobuf->length; //取出這個kiobuf要讀寫的數據長度
if (!bhs)
bhs = iobuf->bh; //取出這個kiobuf的bh池
for (pageind = 0; pageind < iobuf->nr_pages; pageind++) { //遍歷kiobuf中所有的頁
map = iobuf->maplist[pageind]; //得到一個頁面結構
while (length > 0) { //如果讀寫的長度不是0
blocknr = b[bufind]; //挨個查詢塊號
if (blocknr == -1UL) { //如果塊號是負數
if (rw == READ) {
memset(kmap(map) + offset, 0, size);
flush_dcache_page(map);
kunmap(map);
transferred += size;
goto skip_block;
} else
BUG();
} //????
if (iobuf->dovary && (offset == 0)) {
iosize = RAWIO_BLOCKSIZE;
if (iosize > length)
iosize = length;
} //????
bufind += (iosize/size); //得到下一個讀寫的這個設備的塊號。
tmp = bhs[bhind++]; //從kiobuf的bh池中取出一個bh結構
tmp->b_size = iosize; //設置bh的讀寫大小
set_bh_page(tmp, map, offset); //將取到的頁面掛在bh上
tmp->b_this_page = tmp; //
init_buffer(tmp, end_buffer_io_kiobuf, iobuf); //設置回調函數
tmp->b_dev = dev; //設置讀寫設備號
tmp->b_blocknr = blocknr; //設置讀寫的塊號
…… //其它設置
/*
* 這行代碼很重要。使用這個io_count來對這個kiobuf
* 中所提交的bh進行計數跟蹤。
*/
atomic_inc(&iobuf->io_count);
submit_bh(rw, tmp); //進行實際讀寫
/*
* 如果kiobuf中的bh池(kiobuf->bh)中已經沒有bh了,就等待
* 先前做的kiobuf的讀寫完成,釋放一部分bh。
*/
if (bhind >= KIO_MAX_SECTORS) {
kiobuf_wait_for_io(iobuf); /* wake-one */
err = wait_kio(rw, bhind, bhs, size);
if (err >= 0)
transferred += err;
else
goto finished;
bhind = 0; //釋放原來的bh結構,供后續操作使用
}
length -= iosize; //從要讀取的總長度中減去已經做過的
offset += iosize; //偏移量也增加相應的長度
if (offset >= PAGE_SIZE) { //如果偏移量已經超出了一個頁面
offset = 0; //偏移量置為0
break; //推出這個頁面的循環,取新頁面。
}
}
}
}
if (bhind) { //如果bhind不為0,說明還有剩余的bh沒有完成
kiobuf_wait_for_io(iobuf);
err = wait_kio(rw, bhind, bhs, size); //等待這些bh的完成
if (err >= 0)
transferred += err;
else
goto finished;
}
(2)
static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
mark_buffer_uptodate(bh, uptodate); //標志數據塊已經更新
kiobuf = bh->b_private; //取出kiobuf結構
end_kio_request(kiobuf, uptodate); //完成kiobuf請求
unlock_buffer(bh); //解鎖bh。
(3)
/*
* 這個函數很簡單,就是對于參數指定數目nr的bh結構數據,遍歷這些bh結構,等待,
* 直到所有的bh都更新了。
*/
static int wait_kio(int rw, int nr, struct buffer_head *bh[], int size)
**********************************************************************
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -