buffer.c ( File view )

  • By 2010-08-31
  • View(s):24
  • Download(s):2
  • Point(s): 1
			/*
* 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 void
wait_on_buffer (struct buffer_head *bh)
{

  cli ();			// 关中断。
  while (bh->b_lock)		// 如果已被上锁,则进程进入睡眠,等待其解锁。
    sleep_on (&bh->b_wait);
  sti ();			// 开中断。

}

//// 系统调用。同步设备和内存高速缓冲中数据。
int
sys_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;

}

//// 对指定设备进行高速缓冲数据与设备上数据的同步操作。
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;

}

//// 使指定设备在高速缓冲区中的数据无效。
// 扫描高速缓冲中的所有缓冲块,对于指定设备的缓冲区,复位其有效(更新)标志和已修改标志。
void inline
invalidate_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 操作是不需要知道是否是软盘或其它什么特殊介质的。
*/
//// 检查磁盘是否更换,如果已更换就使对应高速缓冲区无效。
void
check_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 void
remove_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 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 */
/* 如果该缓冲块对应一个设备,则将其插入新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;
// 如果该缓冲区所属的设备号或块号在睡眠时发生了改变,则撤消对它的引用计数,重新寻找。
      
...
...
(Not finished, please download and read the complete file)
			
...
Expand> <Close

Want complete source code? Download it here

Point(s): 1

Download
0 lines left, continue to read
Sponsored links

File list

Tips: You can preview the content of files by clicking file names^_^
Name Size Date
linux0.00 B0% 04-10-07
<boot>0.00 B04-10-07 15:01
bootsect.s12.49 kB08-01-04 21:38
head.s13.22 kB08-01-04 21:38
setup.s12.42 kB08-01-04 21:38
<fs>0.00 B04-10-07 15:01
bitmap.c8.46 kB02-09-04 13:12
block_dev.c3.95 kB02-09-04 13:12
buffer.c17.71 kB02-09-04 13:12
char_dev.c4.09 kB02-09-04 13:12
exec.c18.90 kB02-09-04 13:12
fcntl.c3.33 kB02-09-04 13:12
file_dev.c4.82 kB02-09-04 13:12
file_table.c209.00 B02-09-04 13:12
inode.c14.92 kB02-09-04 13:12
ioctl.c1.94 kB02-09-04 13:12
Makefile6.80 kB08-01-04 21:45
namei.c37.20 kB02-09-04 13:12
open.c10.00 kB02-09-04 13:12
pipe.c5.42 kB02-09-04 13:12
read_write.c5.86 kB02-09-04 13:12
stat.c2.69 kB02-09-04 13:12
super.c13.57 kB02-09-04 13:12
truncate.c2.46 kB02-09-04 13:12
<include>0.00 B04-10-07 15:01
a.out.h8.22 kB02-09-04 13:14
<asm>0.00 B04-10-07 15:01
io.h772.00 B02-09-04 13:14
memory.h1.03 kB08-01-04 22:13
segment.h2.50 kB02-09-04 13:14
system.h4.08 kB02-09-04 13:14
const.h589.00 B02-09-04 13:14
ctype.h1.68 kB02-09-04 13:14
errno.h2.30 kB02-09-04 13:14
fcntl.h3.30 kB02-09-04 13:14
<linux>0.00 B04-10-07 15:01
config.h2.16 kB02-09-04 13:14
fs.h9.72 kB02-09-04 13:14
hdreg.h2.94 kB02-09-04 13:14
head.h760.00 B02-09-04 13:14
kernel.h1.44 kB02-09-04 13:14
mm.h473.00 B02-09-04 13:14
sched.h13.25 kB02-09-04 13:14
sys.h5.41 kB02-09-04 13:14
tty.h3.93 kB02-09-04 13:14
signal.h4.01 kB02-09-04 13:14
stdarg.h1.77 kB02-09-04 13:14
stddef.h378.00 B02-09-04 13:14
string.h21.75 kB02-09-04 13:14
<sys>0.00 B04-10-07 15:01
stat.h2.37 kB02-09-04 13:14
times.h377.00 B02-09-04 13:14
types.h1.10 kB02-09-04 13:14
utsname.h423.00 B02-09-04 13:14
wait.h1.48 kB02-09-04 13:14
termios.h13.58 kB02-09-04 13:14
time.h1.81 kB02-09-04 13:14
unistd.h9.21 kB02-09-04 13:14
utime.h392.00 B02-09-04 13:14
<init>0.00 B04-10-07 15:01
main.c12.52 kB02-09-04 13:12
<kernel>0.00 B04-10-07 15:01
asm.s5.10 kB08-01-04 22:48
<blk_drv>0.00 B04-10-07 15:01
blk.h5.69 kB02-09-04 13:14
floppy.c23.49 kB02-09-04 13:12
hd.c17.14 kB02-09-04 13:12
ll_rw_blk.c7.59 kB02-09-04 13:12
Makefile4.25 kB08-01-04 22:53
ramdisk.c6.13 kB02-09-04 13:12
<chr_drv>0.00 B04-10-07 15:01
console.c30.91 kB02-09-04 13:12
keyboard.S21.04 kB08-01-04 22:59
Makefile4.81 kB08-01-04 22:59
rs_io.s5.75 kB08-01-04 22:59
serial.c2.91 kB02-09-04 13:12
tty_io.c18.40 kB02-09-04 13:12
tty_ioctl.c10.70 kB02-09-04 13:12
exit.c8.08 kB02-09-04 13:12
fork.c6.78 kB15-07-07 22:10
<math>0.00 B04-10-07 15:01
Makefile3.21 kB08-01-04 23:01
math_emulate.c2.08 kB02-09-04 13:12
mktime.c2.72 kB02-09-04 13:12
panic.c952.00 B02-09-04 13:12
printk.c1.75 kB02-09-04 13:12
sched.c18.57 kB16-07-07 21:23
signal.c5.61 kB02-09-04 13:12
sys.c7.62 kB02-09-04 13:12
system_call.s12.53 kB08-01-04 22:48
traps.c8.29 kB04-10-07 14:57
vsprintf.c9.96 kB02-09-04 13:12
<lib>0.00 B04-10-07 15:01
close.c397.00 B02-09-04 13:12
ctype.c1.72 kB02-09-04 13:12
dup.c401.00 B02-09-04 13:12
errno.c66.00 B02-09-04 13:12
execve.c607.00 B02-09-04 13:12
Makefile4.83 kB08-01-04 22:30
malloc.c13.50 kB02-09-04 13:12
open.c1.22 kB02-09-04 13:12
setsid.c382.00 B02-09-04 13:12
string.c199.00 B02-09-04 13:12
wait.c774.00 B02-09-04 13:12
write.c545.00 B02-09-04 13:12
_exit.c616.00 B02-09-04 13:12
Makefile8.58 kB08-01-04 22:21
<mm>0.00 B04-10-07 15:01
Makefile2.91 kB08-01-04 22:34
memory.c25.10 kB02-09-04 13:12
page.s842.00 B08-01-04 22:34
<tools>0.00 B04-10-07 15:01
build.c8.12 kB02-09-04 13:12
...
Sponsored links

buffer.c (286.77 kB)

Need 1 point
Your Point(s)

Your Point isn't enough.

Get point immediately by PayPal

More(Debit card / Credit card / PayPal Credit / Online Banking)

Submit your source codes. Get more point

LOGIN

Don't have an account? Register now
Need any help?
Mail to: support@codeforge.com

切换到中文版?

CodeForge Chinese Version
CodeForge English Version

Where are you going?

^_^"Oops ...

Sorry!This guy is mysterious, its blog hasn't been opened, try another, please!
OK

Warm tip!

CodeForge to FavoriteFavorite by Ctrl+D