歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux高速緩存詳解

Linux高速緩存詳解

日期:2017/2/28 14:54:59   编辑:Linux教程

在Linux高速緩存概述中介紹了Linux 0.11中的高速緩存的基礎結構,這一部分將詳細分析Linux高速緩存部分的相關函數。


[數據結構]
這裡介紹下另外和高速緩存相關的數據結構,高速緩存散列表、空閒鏈表指針free_list以及等待在緩存塊上的指針buffer_wait。它們定義分別如下:(代碼來源buffer.c)
struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list;
static struct task_struct * buffer_wait = NULL;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
int NR_BUFFERS = 0;


hash_table就是之前介紹過的緩存散列表,散列函數定義如下
#define _hashfn(dev,block) (((unsigned )(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
使用兩個宏,_hashfn(dev,block)計算相應的設備號和邏輯塊號在散列表上的索引,使用hash(dev,block),獲取計算的索引值在hash_table上的項,也就是指向雙向鏈表的指針


free_list指向所有緩存塊構成的雙向鏈表的指針,可以將其看成是整個鏈表的頭指針


buffer_wait是一個指向進程的指針,當進程試圖獲取一個緩存塊時。如果所有的緩存塊都不是空閒的,就會讓buffer_wait指向這個進程,並且讓這個進程進入不可中斷的睡眠狀態。當有任何進程釋放一個緩存塊時,就會喚醒buffer_wait指向的進程。(個人對此有個問題,當所有的緩存塊都非空閒時,如果有多個進程試圖獲取緩存塊,這幾個進程都會進入不可中斷的睡眠狀態。但buffer_wait只是指向最後調用的那個進程,因此,當緩存塊被釋放,只有最後那個進程被喚醒,其它進程會一直處於不可中斷的睡眠狀態?)


start_buffer表示緩沖區開始地址,end是由連接程序ld生成的表明程序末端的變量(來自《Linux內核完全注釋》對end的解釋)


NR_BUFFERS表示緩沖塊的個數,NR_BUFFERS其實是一個宏,在fs.h中定義,對應變量nr_buffers。
[緩沖區的初始化]
緩沖區的初始化由buffer_init完成。緩沖區的初始化過程是這樣的,從緩沖區的高地址部分開始,劃分出一個個大小為1KB(BLOCK_SIZE)部分作為數據緩沖部分,也就是在Linux高速緩存概述中介紹的buffer_data部分。從緩沖區的低地址部分開始,建立對應每個buffer_data部分的緩沖塊頭部分,也就是buffer_head部分。初始化之後的緩沖區的示意圖如下


初始化代碼如下所示
/*
buffer_end表示緩沖區的結束地址
*/
void buffer_init(long buffer_end)
{
struct buffer_head * h = start_buffer;
void * b;
int i;
/*
由於內存地址的640K~1M部分被用於顯存和BIOS使用,所以這裡需要對緩存的結束地址做調整
*/
if (buffer_end == 1<<20) //2^20=1M
b = ( void *) (640*1024); //640K
else
b = ( void *) buffer_end;
/*
為了保證有足夠的空間來存儲緩沖塊的頭部和緩沖塊的數據緩沖部分,需要滿足b-BLOCK_SIZE>=h+1
*/
while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
//設置緩沖塊頭部的初始值,並讓data指向數據緩沖部分
h->b_dev = 0;
h->b_dirt = 0;
h->b_count = 0;
h->b_lock = 0;
h->b_uptodate = 0;
h->b_wait = NULL;
//空閒的緩沖塊的b_next和b_prev都為NULL
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = ( char *) b; //讓data指向數據緩沖部分
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
NR_BUFFERS++;
/*
看是否到了顯存和BIOS使用的內存區域,如果是,就要調整高地址
*/
if (b == (void *) 0x100000)//16^5=2^20=1M
b = (void *) 0xA0000; //0xA0000=640K
}
h--;
free_list = start_buffer; //讓free_list指向鏈表頭
free_list->b_prev_free = h; //構造循環結構
h->b_next_free = free_list;
//初始化緩沖區的散列表,所有項都設為空
for (i=0;i<NR_HASH;i++)
hash_table[i]=NULL;
}

Copyright © Linux教程網 All Rights Reserved