15-磁盘驱动(生磁盘)

生磁盘驱动就是指CPU直接向磁盘控制器读写数据,不是通过文件系统操作磁盘,文件系统是对生磁盘驱动的进一步抽象
那么磁盘驱动跟其他外设驱动一样,仍然从硬件开始,如下图所示

CPU通过PCI总线向磁盘控制器发读写指令,待读写的内容载入内存后,磁盘控制器再向CPU发中断信号,CPU从内存中取数据。

使用磁盘首先从认识磁盘开始

磁盘整体上是一个柱形的结构。圆柱是由一个个盘面叠加起来的,每个盘面又内到外的圆环称为磁道,每个刺刀上又分成多个扇区。磁盘访问的基本单位是扇区

磁盘读写的过程就是CPU向磁盘控制器发指令,磁盘控制器先驱动磁臂到目标磁道上,然后在磁道上旋转到目标扇区,最后从目标扇区中读写内容,传输到内存。如下图所示

也就是说CPU需要向磁盘控制器发送柱面、磁头、扇区、内存的读写缓存位置。
柱面是指在圆柱的哪一个子圆柱上,磁头指在哪一个盘面上。如下图所示

向磁盘控制器out柱面、磁头、扇区、缓冲区
毕竟向磁盘控制器写柱面、磁头、扇区这些指令很麻烦,程序员还要去找柱面、磁头扇区这些信息。因此向上作一层抽象,程序员只用指定盘块号(block),然后磁盘驱动由盘块号计算出cyl(柱面)、head(磁头)、sec(扇区)。过程如下

那么盘块号如何让编址使得磁盘访问比较快呢?
磁盘的访问时间=写入控制器时间+寻道时间(8-12ms)+旋转时间(7000rpm:半周4ms)+传输时间(50M/s,约0.3s)
可以看出寻道时间占大头,寻道时间是指将磁臂移到目标磁道上,是一个机械运动,自然耗时较久。旋转时间是指在同一个磁道上旋转到目标扇区的时间。
由于我们实际的程序总是会连续读写多个盘块,因此我们希望相邻盘块可以快速读出,那么将同一个磁道上的相邻位置编址成逻辑上的盘块号。磁盘驱动要做的事情是由盘块号计算柱面、磁头和扇区

盘块号又是怎么编址的呢:C*(Head*sectors)+H*sectors+S
C是指柱面号,head是指每个柱面上的磁头个数,sector是指每个磁道上的扇区个数,H指位于纵向的第几个磁头上,S指位于磁道上的第几个扇区上。
将上述公式%sectors即取余操作就可以计算出扇区,再通过其他类似操作也可以计算出C和H。
如果我们每次读写的扇区个数越多,那么读写速度也就越大,每次读写的扇区个数就是盘块大小。而盘块越大,每次产生的内存碎片也就越大,会导致空间利用率降低,如下图所示。

因此盘块的大小是在空间利用率和读写速度之间取得平衡。
由于现在的操作系统都支持多进程,每个进程都有一个盘块号(block),那么先处理那一个进程使得总得磁盘读写时间比较短,用户等待时间也不长呢。那么在磁盘驱动前面又要使用第二层抽象:请求队列。即通过磁盘调度算法将不同进程的block放进请求队列中,使得平均访问延迟小。如下图所示

下面就进一步探究磁盘调度算法

还是从最简单的先来先服务(FCFS)模型先分析
FCFS是最直观、公平的调度算法。但是FCFS模型会造成寻道过程中近的位置到远的位置频繁移动,我们希望每次访问的磁盘尽量相邻,这样寻道时间短,平均延迟时间也就短。

下面看一个实例:磁盘开始位置=53(block号)
请求队列=98,183,27,122,14,124,65,67

FCFS造成磁臂在较长的距离上反复折腾,寻道时间过长
因此我们想到了短寻道时间优先算法(SSTF),类似于进程调度的短任务优先
这样寻道尽可能在附近的位置进行。那么跟短任务优先一样,会出现饥饿问题
接着上面的实例,SSTF处理过程如下:

假如在处理183之前,不断插入小于183盘块进程,那么183永远得不到响应

进一步引出了SSTF+中途不回折(SCAN):即由起始位置先连续访问到block小的位置,中间从小的位置依次访问到block最大的位置,这样每个请求都有处理的机会

这样中间位置被扫描到了两次,对两边不公平。


我们在实际操作系统中采用的是C-SCAN磁盘调度(电梯算法
即SCAN+直接移动到另一端:辆段请求都能快速处理
磁头由开始位置移动到最小位置后,不原路折返,而是切换到最大位置。这样每个位置只扫描一次,由保证了每次寻道都尽可能连续,且每个请求都能得到响应。如下所示

总结一下,生磁盘的使用过程:

.

后面还需要将生磁盘再向上抽象一层,加上文件系统就成用户使用的熟磁盘了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章