linux-0.11分析:init文件 main.c的第八个buffer_init(buffer_memory_end)初始化函数 第九篇随笔
作者:互联网
8、第八个初始化函数,buffer_init(buffer_memory_end)
参考 [github这个博主的 厉害][ https://github.com/sunym1993/flash-linux0.11-talk ]
这个函数buffer_init
可以看出携带了一个参数buffer_memory_end
,这个参数前面出现过,已经赋值了,
也就是在mian.c
开始的时候
void main(void)
{
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
if (memory_end > 12*1024*1024)
buffer_memory_end = 4*1024*1024;
else if (memory_end > 6*1024*1024)
buffer_memory_end = 2*1024*1024;
else
buffer_memory_end = 1*1024*1024;
......
就是这一段代码把buffer_init
的值设置好了;看看下面这个图吧;根据内存大小不一样位置也不一样;总之它是指向缓存区的主要需要用到的内存的开始
之前通过第一个初始化函数mem_init
把用mem_map
内存管理了起来;
include文件 -> linux文件 -> fs.h
buffer_head
这个结构体
#define NR_HASH 307
#define BLOCK_SIZE 1024
struct buffer_head {
char * b_data; /* pointer to data block (1024 bytes) */
unsigned long b_blocknr; /* block number */
unsigned short b_dev; /* device (0 = free) */
unsigned char b_uptodate;
unsigned char b_dirt; /* 0-clean,1-dirty */
unsigned char b_count; /* users using this block */
unsigned char b_lock; /* 0 - ok, 1 -locked */
struct task_struct * b_wait; //之前用到那个task[64]数组的那个结构体
struct buffer_head * b_prev;
struct buffer_head * b_next;
struct buffer_head * b_prev_free;
struct buffer_head * b_next_free;
};
看看这个初始化函数buffer_init
的代码吧:
fs文件 -> buffer.c
#define BLOCK_SIZE 1024
extern int end;
int NR_BUFFERS = 0;
static struct buffer_head * free_list;
struct buffer_head * hash_table[NR_HASH];
void buffer_init(long buffer_end)
{
struct buffer_head * h = start_buffer;
void * b;
int i;
if (buffer_end == 1<<20) // 1<<20 为1MB
b = (void *) (640*1024);
else
b = (void *) buffer_end;
while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { //BLOCK_SIZE=1024
h->b_dev = 0;
h->b_dirt = 0;
h->b_count = 0;
h->b_lock = 0;
h->b_uptodate = 0;
h->b_wait = NULL;
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = (char *) b;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
NR_BUFFERS++; //NR_BUFFERS = 0
if (b == (void *) 0x100000)
b = (void *) 0xA0000;
}
h--;
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
for (i=0;i<NR_HASH;i++) //NR_HASH=307
hash_table[i]=NULL;
}
先看看这一个宏定义
extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
这个end
是一个外部变量,
这个外部变量 end 并不是操作系统代码写就的,而是由链接器 ld 在链接整个程序时设置的一个外部变量,帮我们计算好了整个内核代码的末尾地址。
再看start_buffer就是取的end
的地址为buffer_head
这个结构体定义的start_buffer
所以start_buffer
是这个这个缓冲区的开始的位置
第一部分:
void * b;
if (buffer_end == 1<<20) // 1<<20 为1MB buffer_end = buffr_memory_end
b = (void *) (640*1024);
else
b = (void *) buffer_end;
判断了传入的主要内存开始的位置是否等于1MB;如果等于b
的值就置为640*1024这个位置;否则就是本身
第二部分:
struct buffer_head * h = start_buffer;
void * b;
int i;
while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { //BLOCK_SIZE=1024
h->b_dev = 0;
h->b_dirt = 0;
h->b_count = 0;
h->b_lock = 0;
h->b_uptodate = 0;
h->b_wait = NULL;
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = (char *) b;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
NR_BUFFERS++; //NR_BUFFERS = 0
if (b == (void *) 0x100000)
b = (void *) 0xA0000;
}
可以这是在把缓冲区分块,
很明显,b是缓冲区尾部,h为缓冲区的头部,
从尾部开始向下进行分块,一块大小为1024也就是一页,每分一块前面的缓冲区头就加一个,
并且它里面的h->b_data
就指向刚刚产生着块缓冲区,
h->b_prev_free = h-1
指向上一个头; h->b_next_free = h+1
指向下一个头
看看下面这个图吧
第三部分:
h--;
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
这就在实现双向链表,把最后h
的下一个(next)指向第一个,把第一个的上一个(prve)指向最后一个
老规矩看图
第四部分:
struct buffer_head * hash_table[NR_HASH];
......
for (i=0;i<NR_HASH;i++)
hash_table[i]=NULL; //NR_HASH=307
这里可以看出就是把buffer_head
的结构体数组hash_table[307]
大小为307的置为空
这是数组的作用是干啥?
引用:[github的博主所讲的内容;多多支持][https://mp.weixin.qq.com/s/X8BSbf1qShS11_fzfyOhTg]
其实今天的这个代码在 buffer.c 中,而 buffer.c 是在 fs 包下的,也就是文件系统包下的。所以它今后是为文件系统而服务,具体是内核程序如果需要访问块设备中的数据,就都需要经过缓冲区来间接地操作。
也就是说,读取块设备的数据(硬盘中的数据),需要先读到缓冲区中,如果缓冲区已有了,就不用从块设备读取了,直接取走。
那怎么知道缓冲区已经有了要读取的块设备中的数据呢?从双向链表从头遍历当然可以,但是这效率可太低了。所以需要一个 hashmap 的结构方便快速查找,这就是 hash_table 这个数组的作用。
标签:1024,head,end,struct,buffer,free,init,memory 来源: https://www.cnblogs.com/shuisanya/p/16575620.html