⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffer.c

📁 带中文注释的Linux+0.11+源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** linux/fs/buffer.c** (C) 1991 Linus Torvalds*//** 'buffer.c' implements the buffer-cache functions. Race-conditions have* been avoided by NEVER letting a interrupt change a buffer (except for the* data, of course), but instead letting the caller do it. NOTE! As interrupts* can wake up a caller, some cli-sti sequences are needed to check for* sleep-on-calls. These should be extremely quick, though (I hope).*//** 'buffer.c'用于实现缓冲区高速缓存功能。通过不让中断过程改变缓冲区,而是让调用者* 来执行,避免了竞争条件(当然除改变数据以外)。注意!由于中断可以唤醒一个调用者,* 因此就需要开关中断指令(cli-sti)序列来检测等待调用返回。但需要非常地快(希望是这样)。*//** NOTE! There is one discordant note here: checking floppies for* disk change. This is where it fits best, I think, as it should* invalidate changed floppy-disk-caches.*//*bread获取缓冲块(getblk)块中数据有效?调用块设备低层块读写函数ll_rw_block()进入睡眠等待状态块中数据有效?释放该缓冲块返回NULL返回缓冲块头指针* 注意!这里有一个程序应不属于这里:检测软盘是否更换。但我想这里是* 放置该程序最好的地方了,因为它需要使已更换软盘缓冲失效。*/#include <stdarg.h>		// 标准参数头文件。以宏的形式定义变量参数列表。主要说明了-个// 类型(va_list)和三个宏(va_start, va_arg 和va_end),用于// vsprintf、vprintf、vfprintf 函数。#include <linux/config.h>	// 内核配置头文件。定义键盘语言和硬盘类型(HD_TYPE)可选项。#include <linux/sched.h>	// 调度程序头文件,定义了任务结构task_struct、初始任务0 的数据,// 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。#include <linux/kernel.h>	// 内核头文件。含有一些内核常用函数的原形定义。#include <asm/system.h>		// 系统头文件。定义了设置或修改描述符/中断门等的嵌入式汇编宏。#include <asm/io.h>		// io 头文件。定义硬件端口输入/输出宏汇编语句。extern int end;			// 由连接程序ld 生成的表明程序末端的变量。[??]struct buffer_head *start_buffer = (struct buffer_head *) &end;struct buffer_head *hash_table[NR_HASH];	// NR_HASH = 307 项。static struct buffer_head *free_list;static struct task_struct *buffer_wait = NULL;int NR_BUFFERS = 0;//// 等待指定缓冲区解锁。static inline voidwait_on_buffer (struct buffer_head *bh){  cli ();			// 关中断。  while (bh->b_lock)		// 如果已被上锁,则进程进入睡眠,等待其解锁。    sleep_on (&bh->b_wait);  sti ();			// 开中断。}//// 系统调用。同步设备和内存高速缓冲中数据。intsys_sync (void){  int i;  struct buffer_head *bh;  sync_inodes ();		/* write out inodes into buffers *//*将i 节点写入高速缓冲 */// 扫描所有高速缓冲区,对于已被修改的缓冲块产生写盘请求,将缓冲中数据与设备中同步。  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;}//// 对指定设备进行高速缓冲数据与设备上数据的同步操作。intsync_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;}//// 使指定设备在高速缓冲区中的数据无效。// 扫描高速缓冲中的所有缓冲块,对于指定设备的缓冲区,复位其有效(更新)标志和已修改标志。void inlineinvalidate_buffers (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_uptodate = bh->b_dirt = 0;    }}/** This routine checks whether a floppy has been changed, and* invalidates all buffer-cache-entries in that case. This* is a relatively slow routine, so we have to try to minimize using* it. Thus it is called only upon a 'mount' or 'open'. This* is the best way of combining speed and utility, I think.* People changing diskettes in the middle of an operation deserve* to loose :-)** NOTE! Although currently this is only for floppies, the idea is* that any additional removable block-device will use this routine,* and that mount/open needn't know that floppies/whatever are* special.*//** 该子程序检查一个软盘是否已经被更换,如果已经更换就使高速缓冲中与该软驱* 对应的所有缓冲区无效。该子程序相对来说较慢,所以我们要尽量少使用它。* 所以仅在执行'mount'或'open'时才调用它。我想这是将速度和实用性相结合的* 最好方法。若在操作过程当中更换软盘,会导致数据的丢失,这是咎由自取?。** 注意!尽管目前该子程序仅用于软盘,以后任何可移动介质的块设备都将使用该* 程序,mount/open 操作是不需要知道是否是软盘或其它什么特殊介质的。*///// 检查磁盘是否更换,如果已更换就使对应高速缓冲区无效。voidcheck_disk_change (int dev){  int i;// 是软盘设备吗?如果不是则退出。  if (MAJOR (dev) != 2)    return;// 测试对应软盘是否已更换,如果没有则退出。  if (!floppy_change (dev & 0x03))    return;// 软盘已经更换,所以释放对应设备的i 节点位图和逻辑块位图所占的高速缓冲区;并使该设备的// i 节点和数据块信息所占的高速缓冲区无效。  for (i = 0; i < NR_SUPER; i++)    if (super_block[i].s_dev == dev)      put_super (super_block[i].s_dev);  invalidate_inodes (dev);  invalidate_buffers (dev);}// hash 函数和hash 表项的计算宏定义。#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)#define hash(dev,block) hash_table[_hashfn(dev,block)]//// 从hash 队列和空闲缓冲队列中移走指定的缓冲块。static inline voidremove_from_queues (struct buffer_head *bh){/* remove from hash-queue *//* 从hash 队列中移除缓冲块 */  if (bh->b_next)    bh->b_next->b_prev = bh->b_prev;  if (bh->b_prev)    bh->b_prev->b_next = bh->b_next;// 如果该缓冲区是该队列的头一个块,则让hash 表的对应项指向本队列中的下一个缓冲区。  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;}//// 将指定缓冲区插入空闲链表尾并放入hash 队列中。static inline voidinsert_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 *//* 如果该缓冲块对应一个设备,则将其插入新hash 队列中 */  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;}//// 在高速缓冲中寻找给定设备和指定块的缓冲区块。// 如果找到则返回缓冲区块的指针,否则返回NULL。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;}/** 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;  for (;;)    {// 在高速缓冲中寻找给定设备和指定块的缓冲区,如果没有找到则返回NULL,退出。      if (!(bh = find_buffer (dev, block)))	return NULL;// 对该缓冲区增加引用计数,并等待该缓冲区解锁(如果已被上锁)。      bh->b_count++;      wait_on_buffer (bh);// 由于经过了睡眠状态,因此有必要再验证该缓冲区块的正确性,并返回缓冲区头指针。      if (bh->b_dev == dev && bh->b_blocknr == block)	return bh;// 如果该缓冲区所属的设备号或块号在睡眠时发生了改变,则撤消对它的引用计数,重新寻找。      bh->b_count--;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -