前面已经大概的分析了下高速缓存区相关知识,这里再来分析下几个重要的函数;
1、清缓存:把缓存区数据和设备进行同步
sys_sync(void)函数:首先把i节点从内存中写入到缓存块中( 把i节点写入缓存块函数:sync_inodes(void),从内存inode_table[] i节点数组中扫描修改过的i节点,然后根据i节点号把所处的整块逻辑块都读取到缓存块中,接着把内存中修改过的i节点存放到缓存块相应位置);扫描缓存区中所有缓存头结构,如果已经修改过就发出设备写请求,就会把修改过的缓存块写入到设备磁盘块中;
sync_dev(int dev)函数是对指定的块设备进行数据同步,而上面的是对所有缓存区进行数据同步,因为两个清缓存函数类似,所以就挑一个具有代表性的分析下:
//对指定设备进行高速缓存区数据和设备上数据进行同步
//这里采用先让修改的缓存数据和设备块数据同步,
//然后把i节点写入到高速缓存区中,最后再次让缓存区和设备块数据同步。
//这样做是,第一次同步,可以把脏块同步干净,然后把i节点写入高速缓存区中,
//这时候同步i节点就变的简单了。最后同步i节点和因为i节点写入而变脏的块
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_dev == dev && bh->b_dirt)//因为上一步很可能要等待解锁,在这期间缓存块可能被修改,所以最好要再次判断
ll_rw_block(WRITE,bh);//调用写请求函数
}
sync_inodes();//把内存中改变过的i节点写入到缓存区中
bh = start_buffer;//步骤和上面一样
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
if (bh->b_dev != dev)
continue;
wait_on_buffer(bh);
if (bh->b_dev == dev && bh->b_dirt)
ll_rw_block(WRITE,bh);
}
return 0;
}
static inline void remove_from_queues(struct buffer_head * bh);从链表中删除缓存块,这没有什么技巧,都是些简单的链表操作;重点看下插入链表,先调整双链表,这里把插入的缓存块放到链表最后,所以会有:越靠近free_list指针的缓存头就越久没有使用(到时候查找空闲缓存头时就更有效率);然后再调整下hash链表,这个hash链表不是一一映射的,而是hash链表(或者说hash数组表),可以查看下:http://blog.csdn.net/yuzhihui_no1/article/details/43677663
//将指定缓冲区插入空闲链表尾并放入hash队列中
static inline void insert_into_queues(struct buffer_head * bh)
{
/* put at end of free list; 放到空闲链表尾部&#