磁盘工作过程
1)磁头移动,找到柱面
2)柱面中选择读写的磁道
3)旋转磁盘,将对应磁道中要读写的那个扇区转到磁头下方
4)都系扇区中的内容到缓存中
代码实现
1:第一层抽象-扇区到磁盘块请求
因为数据传输数据和寻道、旋转时间相比要小得多,所以寻道,旋转一次读写K个扇区的策略比只读写一个扇区的策略,读写速度会提供K倍。所以抽象处磁盘快后,磁盘的读写速度会有非常显著的提高。
当用户传入磁盘的盘块号时,就可以找到扇区号,然后加入传输请求中了。
static void make_request(int major,int rw, struct buffer_head * bh)
req->sector = bh->b_blocknr<<1;
add_request(major+blk_dev,req);
2:第二层抽象-多进程的磁盘请求队列
电梯调度算法:先朝某个方向进行扫描,处理经过的所有磁盘请求,直到这个方向不再磁盘请求时,磁头迅速复位到另一个方向的最大请求位置,然后沿该方向进行扫描。
通过循环遍历和算法判断条件,找到可以插入的位置。
static void add_request(struct blk_dev_struct * dev, struct request * req)
{
cli();
for ( ; tmp->next ; tmp=tmp->next)
if ((IN_ORDER(tmp,req) ||
!IN_ORDER(tmp,tmp->next)) &&
IN_ORDER(req,tmp->next))
break;
req->next=tmp->next;
tmp->next=req;
sti();
}
3:第三层抽象-从磁盘请求到高速缓存
当用户需要读取100B的数据时,真正读入的数据是以扇区为大小,所以会大于100B,那么如果将多余的数据存放在内核态内存中,那么就会大幅度减少磁盘读写次数,提高磁盘使用效率。这就是磁盘高速缓存。
struct buffer_head * bread(int dev,int block)
{
struct buffer_head * bh;
if (!(bh=getblk(dev,block)))
panic("bread: getblk returned NULL\n");
if (bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return NULL;
}