20191323王予涵第十二章学习笔记

20191323王予涵第十二章学习笔记

一、知识点归纳和总结

块设备I/O和缓冲区管理

  • 当进程试图读取(dev,blk)标识的磁盘块时,它首先在缓冲区缓存中搜索分配给磁盘块的缓冲区。若缓冲区存在并且包含有效数据,只需从缓冲区中读取数据,无需再次从磁盘中读取数据块;若缓冲区不存在,则为磁盘块分配相应缓冲区,将数据从磁盘读入缓冲区,然后从缓冲区中读数据。
  • 当某个块被读入时,该缓冲区将被保存在缓冲区缓存中,以供任意进程对同一个块的下一次读/写请求使用;当进程写入磁盘块时,会将数据写入缓冲区,将缓冲区标记为脏,以延迟写入,并将其释放至缓冲区缓存中。
  • 脏缓冲区只有在重新分配到不同的块时才会写入磁盘

从磁盘块中读:

BUFFER *bread(dev,blk){
    BUFFER *bp = getblk(dev,blk);  
    if (bp data valid)             
    return bp;                    
    bp->opcode = READ;             
    strat_io(bp);                   
    wait for I/O completion;
    return bp;
}

写入磁盘块:

write_block(dev, blk, data){
    BUFFER *bp = bread(dev,blk);
    write data to bp;
    (synchronous write)? bwrite(bp):dwrite(bp);   
}
同步写入bwrite(bp):

同步写入等待写操作完成,用于顺序块或可移动设备

bwrite (BUFFER *bp){
	bp->opcode = WRITE;
	start_io(bp);
	wait for I/O completion;
	brelse(bp);
}
延迟写入dwrite(bp):

延迟写入无写操作,用于随机访问设备

dwrite(BUFFER *bp){
	mark bp dirty for delay_write;
    brelse(bp);                       
}

脏缓冲区写入操作:

  • 脏缓冲区只用在重新分配到不同的磁盘块时才会被写入磁盘
  • awrite()会调用start_io()在缓冲区开始I/O操作,但不会等待操作完成
  • 当异步ASYNC完成后,磁盘中断处理程序将释放缓冲区
awrite(BUFFER *bp){
	bp -> opcode = ASYNC;
	start_io(bp);
}

物理块设备I/O:

I/O队列中保存着等待I/O的缓冲区

start_io(BUFFER *bp){
    enter bp into device I/O queue;
    if (bp is first buffer in I/O queue)
    issue I/O command for bp to device;
}

缓冲区管理算法

缓冲区结构体:

typdef struct buf{
    struct buf *next_free;
    struct buf *next_dev;
    int dev,blk;
    int opcode;
    int dirty;
  	int async;
  	int valid;
  	int busy;
  	int wanted;
  	struct semaphore lock = 1;
  	struct semaphore iodone = 0;
  	char buf[BLKSIZE];
}BUFFER;
BUFFER buf[NBUF], *freelist;

设备表:

struct devtab{
  	u16 dev;
  	BUFFER *dev_list;
  	BUFFER *io_queue;
}devtab[NDEV];
  1. 缓冲区初始化:系统启动时,所有I/O缓冲区都在空闲列表中,所有设备列表和I/O队列均为空

  2. 缓冲区列表:

    1. 缓冲区分配给(dev,blk)时,会被插入设备表的dev_list中

      • 缓冲区正在使用:标记为busy并从空闲列表中删除
    2. 通过使用相同的next_free来维护设备I/O序列

    3. 缓冲区不在繁忙时,释放回空闲列表,保留在dev_list中,以便重用

信号量缓冲区管理算法(PV)

具备优点:

  • 数据一致性
  • 良好的缓存效果
  • 高效率:没有重试循环,没有不必要的唤醒
  • 无死锁和饥饿

信号量定义

BUFFER buf[NBUF];
SEMAPHORE free = NBUF;
SEMAPHORE buf[i].sem = 1;

算法伪代码

BUFFER *getblk(dev,blk)
{
    while(1){
  (1).      p(free);                              
  (2).      if (bp in dev_list){                  
  (3).          if (bp not BUSY){                 
                    remove from freelist;         
                    P(bp);                        
                    return bp;
                 }
            //bp in cache but BUSY
                V(free);                          
  (4).          P(bp);                            
                return bp;
           }
            //bp not in cache, try to create a bp=(dev.blk)
  (5).     bp = first buffer taken out of freelist;
           P(bp);                             
  (6).     if (bp dirty){                    
              awrite(bp);                     
              continue;
           }
  (7).     reassign bp to (dev,blk);          
           return bp;
      }
}
brelse (BUFFER *bp)
{
  (8).if (bp queue has waiter) {V(bp); return; }
  (9).if (bp dirty && freee queue has waiter){ awrite(bp); return;}
  (10).enter bp into (tail of) freelist; V(bp); V(free);
}
posted @ 2021-11-20 16:57  WangYuHan20191323  阅读(23)  评论(0编辑  收藏  举报