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];
缓冲区初始化:系统启动时,所有I/O缓冲区都在空闲列表中,所有设备列表和I/O队列均为空
缓冲区列表:
缓冲区分配给(dev,blk)时,会被插入设备表的dev_list中
- 缓冲区正在使用:标记为busy并从空闲列表中删除
通过使用相同的next_free来维护设备I/O序列
缓冲区不在繁忙时,释放回空闲列表,保留在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);
}