?? buffer.c.txt
字號:
any question,send email to netxiong@263.net
相關文件:
/init/main.c
該文件提供了文件的buffer功能的大部分實現,同時也對塊設備的buffer有效
****************************基本數據結構*************************
(1):#define NR_SIZES 7 //最多由7種buffer大小的類型512,1024,2048,4096,8192,34816,
(2):static char buffersize_index[65] =
{-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
4, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
5, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
6};//hash函數的映射表,-1處不使用,0----6代表了7種類型
(3):#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
#例如 4096>>9 = 8(1000)
#buffersize_index[8] = 3
(4):static struct buffer_head **hash_table; //hash數組,存儲了所有的buffer
static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED//鏈表的自旋鎖
**********************************************************************
****************************各種內存連表的定義和函數*************************
(5):struct bh_free_head {
struct buffer_head *list;
spinlock_t lock;
};
(6):static struct bh_free_head free_list[NR_SIZES];
基本函數:
static void __remove_from_free_list(struct buffer_head * bh, int index)
#將bh代表的buffer從free_list buffer池中刪除
#程序挺有意思,值得一看,很簡單
#首先將bh從雙向鏈表中刪除,
#如果free_list指向的是bh,則將free_list指向bh的next buffer.
定義了lru數組,4個元素。(include/linux/fs.h)
BUF_CLEAN0,BUF_LOCKED,BUF_DIRTY,BUF_PROTECTED
static struct buffer_head *lru_list[NR_LIST]; //幾種不同的buffer池
static int nr_buffers_type[NR_LIST]; //每一種相應的buffer池中的buffer數量
static unsigned long size_buffers_type[NR_LIST]; //每一種相應的池中的總量
static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED;//鏈表的自旋鎖
處理函數:
(1):static void __insert_into_lru_list(struct buffer_head * bh, int blist)
#將一個buffer插入倒blist類型的lru buffer池中
#將bh加入到 &lru_list[blist]的前面(后來的buffer加入到頭部)
#nr_buffers_type[blist]++; //增加相應的buffer數目
#size_buffers_type[blist] += bh->b_size;//增加相應的buffer池的容量
(2):static void __remove_from_lru_list(struct buffer_head * bh, int blist)
(8):
static struct buffer_head * unused_list;
static int nr_unused_buffer_heads; //為使用的buffer_head的數目
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;//鏈表的自旋鎖
***************************************************************************
************************基本宏************************************
(1):#define _hashfn(dev,block) \ //哈希映射函數
((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
(((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \
((block) << (bh_hash_shift - 12))))
(2):#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)]
#這兩個宏的作用就是buffer池中取出相應的buffer。
******************************************************************
***************************基本函數*******************************
(1):void __init buffer_init(unsigned long mempages)
#這個函數再main.c中被調用,作用是為系統提供一系列的buffer.
#首先進行了一系列的計算
# hash_table = (struct buffer_head **)
__get_free_pages(GFP_ATOMIC, order);
#然后調用__get_free_pages進行頁分配,從而產生了一個buffer池
#對hash_table的buffer池進行初始化。
#對free_list進行初始化
#對lru_list進行初始化
******************************************************************
****************************守護進程*******************************
(1):static int __init bdflush_init(void)
#初始化兩個守護線程
# kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
#kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
(2):int kupdate(void *sem)
#更新進程
(3):int bdflush(void *sem)
#守護進程,無限循環,負責將dirty數據刷新倒設備上
#主要的函數調用是flushed = flush_dirty_buffers(0);
(4):static int flush_dirty_buffers(int check_flushtime)
#這個函數將實際上的dirty數據寫倒設備上去
#bh = lru_list[BUF_DIRTY]; //我們值更新BUF_DIRTY的buffer.
#ll_rw_block(WRITE, 1, &bh); //這是最為關鍵的一步,將buffer中的數 //據寫到塊設備上去
*******************************************************************
**************************數據結構圖********************************
hash_table
[0]------->buffer_head
[1]--->null
[…]
[n]--->null
[n+1]------>buffer_head
|<---------b_pprev
b_next--------->buffer_head
|<---------------b_pprev
[n+2]
[…]
free_list (使用b_next_free字段進行連接)
[0](512)--------->buffer_head-------->buffer_head
[1](1024)-------->buffer_head-------->buffer_head
[…]
(使用b_next_free字段進行連接)
unused_list------>buffer_head--------->buffer_head
********************************************************************
**************************getblk函數集******************************
(1):struct buffer_head * getblk(kdev_t dev, int block, int size) (2.4.2)
#函數的作用是從設備號dev和請求的塊號block來得到所請求的buffer池入口
# bh = __get_hash_table(dev, block, size);//從hash表中取出buffer入口
# if (bh)
goto out; //如果能夠找到,就到出口處
#否則bh = free_list[isize].list;//從free_list表中取出一個空閑的head
#if (bh) { //如果free_list表中還有buffer_head
__remove_from_free_list(bh, isize);
atomic_set(&bh->b_count, 1); //buffer_head的使用者加一
}//如果空閑的head表中又buffer_head,則把他從空閑表中刪除并加一
#如果bh有效init_buffer(bh, NULL, NULL)//對bh進行初始化
# __insert_into_queues(bh); //加入到hash_table相應的入口中
#out:
touch_buffer(bh); //將buffer中的page位置位(?)
return bh; //返回bh
#如果沒有相應的buffer_head
#refill_freelist(size) //從新對free_list進行處理,等待一個可用的free
#跳轉到函數頭,從新執行。
(2):static void refill_freelist(int size)
# balance_dirty(NODEV);//對dirty數據頁進行平衡,計算是否要想設備寫
# grow_buffers(size); //增加buffers。
(3):static int grow_buffers(int size)(2.4.2)
#在free_list[]上擴建一頁塊長為blocksize的備用緩沖區;
#page = alloc_page(GFP_BUFFER);//申請一個頁
#bh = create_buffers(page, size, 0);//在頁上生成一個size的緩沖區
#insert_point = free_list[isize].list;//得到插入點
#if (insert_point) {//插到頭節點的后面
tmp->b_next_free = insert_point->b_next_free;
tmp->b_prev_free = insert_point;
insert_point->b_next_free->b_prev_free = tmp;
insert_point->b_next_free = tmp;
} else {//如果是第一個話,就插入倒后面
tmp->b_prev_free = tmp;
tmp->b_next_free = tmp;
}
(4):static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)
#創建塊長為blocksize的buffer_head結構來描述頁面page.
#bh = get_unused_buffer_head(async);//得到一個buffer_head
# if (!bh)
goto no_grow; //如果沒有buffer_head,等待
#否則的話就對bh進行設置
#no_grow:
# wait_event(buffer_wait, nr_unused_buffer_heads >= MAX_BUF_PER_PAGE);//等待
():static struct buffer_head * get_unused_buffer_head(int async)
#得到一個空閑的buffer_head
():static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
#將buffer_head加入到unused_list中去
# if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS)
kmem_cache_free(bh_cachep, bh);//如果buffer太多,釋放
#否則 nr_unused_buffer_heads++;
bh->b_next_free = unused_list;
bh->b_this_page = NULL;
unused_list = bh;//將新buffer_head加入到unused_list中去
#注意:unused_list就是在這里被賦值的。無論unused_list是什么。
********************************************************************
************************緩存的申請和釋放過程*************************
union bdflush_param {
struct {
int nfract; /* 臟塊比例達到多少喚醒bdflush進程 */
int dummy1; /* old "ndirty" */
int dummy2; /* old "nrefill" */
int dummy3; /* unused */
int interval; /* jiffies delay between kupdate flushes */
int age_buffer; /* Time for normal buffer to age before we flush it */
int nfract_sync;/* 臟塊比例達到多少喚醒bdflush進程進行同步flush */
int dummy4; /* unused */
int dummy5; /* unused */
} b_un;
unsigned int data[N_PARAM];
} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}}; //默認值是40%和60%
(1)struct buffer_head * getblk(kdev_t dev, int block, int size)
for (;;) { //循環一直到申請成功
struct buffer_head * bh;
bh = get_hash_table(dev, block, size); //從hash表中得到一個bh
if (bh)
return bh; //如果可以的話就返回
if (!grow_buffers(dev, block, size)) //如果
free_more_memory(); //釋放一部分buffers
}
(2)static int grow_buffers(kdev_t dev, unsigned long block, int size)
/* size大小必須是設備硬扇區大小的整數倍 */
if (size & (get_hardsect_size(dev)-1))
BUG();
/* Size大小必須在512字節和PAGE_SIZE之間 */
if (size < 512 || size > PAGE_SIZE)
BUG();
//將塊的序號進行頁對齊,例如頁大小為4K,塊設備的大小為1K,那么第5塊的index就是
//2,這里的index就是以4K頁來計算的號碼
sizebits = -1;
do {
sizebits++;
} while ((size << sizebits) < PAGE_SIZE);
index = block >> sizebits;
block = index << sizebits;
page = grow_dev_page(bdev, index, size); //產生一頁
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -