linux0.12 内核学习 (buffer.c)

linux文件系统之高速缓冲区

linux高速缓存区是采用hash数组的格式对缓存头信息进行管理。通过一个free_list指针指向空闲的缓存头节点,缓存头节点间使用双向链表进行连接,并且采用lru缓存管理算法对数据进行维护。
大致见如下笔记图:

fs/buffer.c源码浏览

extern int end;  // linux内核代码的末端,高速缓存的起始位置在内核代码的末端位置。
struct buffer_head * start_buffer = (struct buffer_head *) &end; // 首个buffer_head 的结构
struct buffer_head * hash_table[NR_HASH];  // hash数组表,对应上图。其中NR_HASH为307项
static struct buffer_head * free_list; // 空闲的首缓存头指针
static struct task_struct * buffer_wait = NULL; //等待空闲缓存块而睡眠的任务队列头指针,用于申请一个缓存块时无可用的空闲缓存块而进行等待加入队列。
int NR_BUFFERS = 0;
复制代码
wait_on_buffer
static inline void wait_on_buffer(struct buffer_head * bh)
{
	cli(); // 关中断,设置进程不可中断地睡眠在该缓存区的b_wait 中。
	while (bh->b_lock)
		sleep_on(&bh->b_wait);   // 需要wake_up明确的进行唤醒。
	sti(); // 开中断
}
复制代码
static int sync_dev(int dev)
{
        /****
        ****  对设备的缓存进行入盘操作
        ****
        ****/
    
	int i;
	struct buffer_head * bh;

	bh = start_buffer;  // 遍历NR_BUFFERS对应的所有缓存头
	for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
		if (bh->b_dev != dev)
			continue;
		wait_on_buffer(bh); // wait for b_lock util get lock.  
		if (bh->b_dirt) 
			ll_rw_block(WRITE,bh);  // refresh dirty content to disk
	}
	return 0;
}

复制代码
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
该宏定义的是hash算法,通过对dev和block进行幂次计算,然后计算其所属于的数组位置。

#define hash(dev,block) hash_table[_hashfn(dev,block)]
返回hash表的首指针位置
复制代码
remove_from_queues 从缓存中摘除该缓存头
static inline void remove_from_queues(struct buffer_head * bh)
{
/* remove from hash-queue */
	if (bh->b_next)
		bh->b_next->b_prev = bh->b_prev;
	if (bh->b_prev)
		bh->b_prev->b_next = bh->b_next;
	// 调整前后指针
	if (hash(bh->b_dev,bh->b_blocknr) == bh)
		hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
	// 假设指针为第一个数组指向的指针,则调节数组的指向
	
/* remove from free list */
	if (!(bh->b_prev_free) || !(bh->b_next_free))
		panic("Free block list corrupted");
	bh->b_prev_free->b_next_free = bh->b_next_free;
	bh->b_next_free->b_prev_free = bh->b_prev_free;
	// 调整bh前后的free node,且当其等于free_list时,进行更正
	if (free_list == bh)
		free_list = bh->b_next_free;
}

复制代码
insert_into_queues
static inline void insert_into_queues(struct buffer_head * bh)
{
/* put at end of free list */
	bh->b_next_free = free_list;
	bh->b_prev_free = free_list->b_prev_free;
	free_list->b_prev_free->b_next_free = bh;
	free_list->b_prev_free = bh;
	// 将buffer_head插入到free_list的最后一个位置,同时更新各个指针的指向
/* put the buffer in new hash-queue if it has a device */
	bh->b_prev = NULL;
	bh->b_next = NULL;
	if (!bh->b_dev)
		return;
	bh->b_next = hash(bh->b_dev,bh->b_blocknr);
	//插入到hash对应dev项的第一个位置
	hash(bh->b_dev,bh->b_blocknr) = bh;
	bh->b_next->b_prev = bh;
}


复制代码
find_buffer
static struct buffer_head * find_buffer(int dev, int block)
{		
	struct buffer_head * tmp;

	for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
		if (tmp->b_dev==dev && tmp->b_blocknr==block)
			return tmp;
	return NULL;
}

复制代码
get_hash_table 找到合适的hash table buffer
/*
 * Why like this, I hear you say... The reason is race-conditions.
 * As we don't lock buffers (unless we are readint them, that is),
 * something might happen to it while we sleep (ie a read-error
 * will force it bad). This shouldn't really happen currently, but
 * the code is ready.
 */
struct buffer_head * get_hash_table(int dev, int block)
{
	struct buffer_head * bh;

repeat:
	if (!(bh=find_buffer(dev,block)))
		return NULL;
	bh->b_count++;
	wait_on_buffer(bh);
	if (bh->b_dev != dev || bh->b_blocknr != block) {
	    // if bh is not current block,then release it.
		brelse(bh);
		goto repeat;
	}
	return bh;
}

复制代码
get_blk 找寻一块合适的缓存头块
struct buffer_head * getblk(int dev,int block)
{
	struct buffer_head * tmp;

repeat:
	if (tmp=get_hash_table(dev,block))
		return tmp;
	tmp = free_list;
	// 遍历free_list链表,找到满足count为0后尝试上锁,之后进行上锁等待,解锁后探测是否被引用
	do {
		if (!tmp->b_count) {
			wait_on_buffer(tmp);	/* we still have to wait */
			if (!tmp->b_count)	/* on it, it might be dirty */
				break;
		}
		tmp = tmp->b_next_free;
	} while (tmp != free_list || (tmp=NULL));
	/* Kids, don't try THIS at home ^^^^^. Magic */
	
	// 假设没有合适的bufferr,等待buffer_wait的释放
	if (!tmp) {
		printk("Sleeping on free buffer ..");
		sleep_on(&buffer_wait);
		printk("ok\n");
		goto repeat;
	}
	tmp->b_count++;
	remove_from_queues(tmp);
/*
 * Now, when we know nobody can get to this node (as it's removed from the
 * free list), we write it out. We can sleep here without fear of race-
 * conditions.
 */
	if (tmp->b_dirt)
		sync_dev(tmp->b_dev);
/* update buffer contents */
	tmp->b_dev=dev;
	tmp->b_blocknr=block;
	tmp->b_dirt=0;
	tmp->b_uptodate=0;
/* NOTE!! While we possibly slept in sync_dev(), somebody else might have
 * added "this" block already, so check for that. Thank God for goto's.
 */
	if (find_buffer(dev,block)) {
		tmp->b_dev=0;		/* ok, someone else has beaten us */
		tmp->b_blocknr=0;	/* to it - free this block and */
		tmp->b_count=0;		/* try again */
		insert_into_queues(tmp);
		goto repeat;
	}
/* and then insert into correct position */
	insert_into_queues(tmp);
	return tmp;
}

复制代码
brelse 释放缓存块并释放全局buffer_wait
void brelse(struct buffer_head * buf)
{
	if (!buf)
		return;
	wait_on_buffer(buf);
	if (!(buf->b_count--))
		panic("Trying to free free buffer");
	wake_up(&buffer_wait);
}

复制代码
buffer初始化

void buffer_init(void)
{
	struct buffer_head * h = start_buffer;
	void * b = (void *) BUFFER_END;
	int i;

	while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
		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++;
		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++)
		hash_table[i]=NULL;
}	
复制代码
copyblk汇编指令
#define COPYBLK(from, to) \
__asm__("cld\n\t" \
        "rep\n\t" \
        "movsl\n\t"\
        ::"c" (BLOCK_SIZE/4), "S" (from), "D" (to) \
        : "cx", "di","si")
)


复制代码
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值