Linux教程

linux-0.11分析:init文件 main.c的第八个buffer_init(buffer_memory_end)初始化函数 第九篇随笔

本文主要是介绍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 这个数组的作用。

这篇关于linux-0.11分析:init文件 main.c的第八个buffer_init(buffer_memory_end)初始化函数 第九篇随笔的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!