extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list;
static struct task_struct * buffer_wait = NULL;
int NR_BUFFERS = 0;
/*这就是让任务等代的函数。参考sleep函数*/
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
/*先把所有的inode写入到缓冲区中,之后再调用磁盘写函数ll_rw_block写入到磁盘中*/
int sys_sync(void)
{
int i;
struct buffer_head * bh;
sync_inodes(); /* write out inodes into buffers */
bh = start_buffer;
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
wait_on_buffer(bh);
if (bh->b_dirt)
ll_rw_block(WRITE,bh);
}
return 0;
}
/*把某个设备的缓冲区写入到磁盘中*/
static int sync_dev(int dev)
{
int i;
struct buffer_head * bh;
bh = start_buffer;
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
if (bh->b_dev != dev)
continue;
wait_on_buffer(bh);
if (bh->b_dirt)
ll_rw_block(WRITE,bh);
}
return 0;
}
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
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;
if (free_list == bh)
free_list = bh->b_next_free;
}
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;
/* 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(bh->b_dev,bh->b_blocknr) = bh;
bh->b_next->b_prev = bh;
}
/*从hash表中查找指定设备的特定的缓冲区块*/
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;
}
struct buffer_head * get_hash_table(int dev, int block)
{
struct buffer_head * bh;
repeat:
if (!(bh=find_buffer(dev,block))) //如果hash表没有,就返回null
return NULL;
bh->b_count++; //把缓冲区块使用数加1,并等待解锁
wait_on_buffer(bh);
/*如果不等于指定的设备号和block号,释放缓冲区,重新查找*/
if (bh->b_dev != dev || bh->b_blocknr != block) {
brelse(bh);
goto repeat;
}
return bh;
}
struct buffer_head * getblk(int dev,int block)
{
struct buffer_head * tmp;
repeat:
//从hash表中查找,如果没有找到,就从free_list中查找
if (tmp=get_hash_table(dev,block))
return tmp;
tmp = free_list;
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));
/*如果没有找到,就打印log,并等待*/
if (!tmp) {
printk("Sleeping on free buffer ..");
sleep_on(&buffer_wait);
printk("ok\n");
goto repeat;
}
/*找到了就把引用数加1,并把这个缓冲区从hash表和free_list中移除*/
tmp->b_count++;
remove_from_queues(tmp);
/*如果有脏标志,就同步一下这个设备的额缓冲区*/
if (tmp->b_dirt)
sync_dev(tmp->b_dev);
/*再次查找一下这个缓冲区是否已经再hash表,如果是,说明在等待时,已经有进程使用了,则释放这个缓冲区,并 重新查找
注意这里的find_buffer函数作用,就是为了保证再确认等待时没有其他进程再修改。
*/
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;
}
/* 更新一下缓冲区结构的内容 */
tmp->b_dev=dev;
tmp->b_blocknr=block;
tmp->b_dirt=0;
tmp->b_uptodate=0;
/*插入到对应的链表中*/
insert_into_queues(tmp);
return tmp;
}
/*功能:释放缓冲区块*/
void brelse(struct buffer_head * buf)
{
/*缓冲区块不存在,出错*/
if (!buf)
return;
/*等待块解锁*/
wait_on_buffer(buf);
/*缓冲块引用数减1*/
if (!(buf->b_count--))
panic("Trying to free free buffer");
/*唤醒等待n链表*/
wake_up(&buffer_wait);
}
/*
*函数功能:读取特定设备上特定磁盘块到缓冲区中
*/
struct buffer_head * bread(int dev,int block)
{
struct buffer_head * bh;
/*读取特定设备的特定缓冲区块*/
if (!(bh=getblk(dev,block)))
panic("bread: getblk returned NULL\n");
/*如果是最新的就返回*/
if (bh->b_uptodate)
return bh;
/*如果不是最新的,则从磁盘进行读取,并设置更新标志*/
ll_rw_block(READ,bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return (NULL);
}
/*缓冲区初始化函数*/
void buffer_init(void)
{
struct buffer_head * h = start_buffer;
void * b = (void *) BUFFER_END;
int i;
/*指针b指向缓冲区尾部,从尾部开始初始化缓冲区,并且空出来显存所占据的地方,而缓冲区头部存放buffer_head结构,并用h指向它*/
/*把所有的缓冲区的结构体都清空,并且放入到一个双向链表中b_prev_free,b_next_free是双向链表的指针;b_next,b_prev是hash表的指针*/
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指向第一个结构体buffer_head.并把free_list添加到链表中来*/
h--;
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
/*初始化hash表*/
for (i=0;i<NR_HASH;i++)
hash_table[i]=NULL;
}