设备驱动与文件系统:03 生磁盘的使用
磁盘驱动学习开篇
从这一讲开始,我们进入设备驱动的学习,具体聚焦于设备管理的最后一个部分——磁盘管理。磁盘管理实践也是操作系统课程的最后一块内容。磁盘的驱动器本质上仍是一种设备驱动,其原理不变,核心依旧是文件视图、磁盘的中断处理这三部分内容。不过,磁盘管理相较于之前讲的显示器和键盘管理要复杂得多,其抽象层次更为丰富。
弄明白磁盘驱动处理,整个操作系统课程的学习便全部结束。掌握磁盘驱动原理后,面对如网卡、打印机等同样复杂的设备驱动,我们也能从容应对。接下来,我们将分步骤、分层次地学习磁盘在操作系统中是如何被驱动和处理的。
磁盘工作原理初探
本次学习从生磁盘及其使用入手,这和之前的学习思路一致。
我们先了解磁盘的基本工作原理:通过向磁盘控制器发送out
指令,控制器控制磁盘进行读写操作;磁盘工作完成后,向CPU发出中断信号,以便进行后续处理。整个过程的核心就是out
指令、中断处理,以及如何逐步抽象形成文件视图,而今天的重点是让磁盘工作起来。
磁盘由盘片、磁道、磁头组成。读写磁盘的基本单位是扇区,每个扇区通常为512字节。在实际读写过程中,首先移动磁头到指定磁道,接着磁盘旋转,当目标扇区转到磁头下方时,利用磁生电(读操作)或电生磁(写操作)原理,实现磁盘与内存缓冲区的数据交互。概括来说,磁盘读写主要包括移动磁头、旋转磁盘、数据传输这三个步骤,即寻道、旋转加上数据传输 。
磁盘使用的第一层抽象:从扇区到盘块
要使用磁盘,需向磁盘控制器传递柱面、磁头、扇区、缓存位置等参数。柱面由多个盘片上相同位置的磁道组成,磁头决定在哪个盘面上读写,扇区确定具体的读写位置。通过传递这些参数,结合DMA(直接内存访问)技术,就能实现磁盘与内存的数据交换,而实际操作中,最终是通过out
指令将相关参数写入磁盘控制器的端口来完成读写操作。
不过,直接使用这种方式较为复杂,用户需要了解诸多细节。为了简化操作并提高效率,我们进行第一层抽象,引入盘块号的概念。用户程序只需发送盘块号,操作系统的磁盘驱动负责将盘块号转换为柱面、磁头和扇区号(即c
、h
、s
)。
这种抽象具有重要意义。一方面,用户无需再关注复杂的三维地址(柱面、磁头、扇区),只需处理简单的一维盘块号,使用起来更加便捷;另一方面,操作系统通过合理规划盘块号与实际物理地址的映射关系,提高了磁盘读写效率。例如,我们通常会连续访问盘块,为了加快连续盘块的读写速度,操作系统会将相邻盘块号对应的盘块尽量放置在同一磁道上,减少寻道时间。
在实现盘块号到c
、h
、s
的转换时,我们可以根据磁盘的物理参数(如每个柱面的磁头数、每个磁头的扇区数),通过数学运算得出。具体来说,如果已知盘块号block
,可以通过block
对扇区数sector
取余得到扇区号s
,再结合其他运算得到柱面号c
和磁头号h
。
此外,操作系统还将读写单位从扇区改为盘块,一个盘块由连续的几个扇区组成。这样做虽然会造成一定的空间浪费,但由于磁盘读写中寻道时间占比较大,增大读写单位可以减少寻道次数,从而显著提高读写速度,这是一种以空间换时间的策略。至此,上层应用程序可以通过盘块号访问磁盘,隐藏了底层细节,提升了使用效率 。
磁盘使用的第二层抽象:多进程下的磁盘调度
在多进程环境下,多个进程都需要使用磁盘。如果只有一个进程使用磁盘,它可以直接用盘块号计算c
、h
、s
,通过out
指令驱动磁盘控制器;但多个进程同时使用时,就需要引入请求队列。多个进程将各自的盘块访问请求放入队列,磁盘驱动在磁盘中断时从队列中取出请求,进行c
、h
、s
的换算和out
指令操作 。
这就涉及到磁盘调度问题,即如何合理安排请求队列中的磁盘访问顺序,以提高磁盘工作效率。磁盘读写中,寻道时间是最主要的耗时因素,因此调度算法的目标就是尽量缩短寻道时间。
常见的调度算法从“先来先服务(FCFS)”开始,即按照磁盘请求的先后顺序进行调度。但这种算法可能导致磁头频繁地长途移动,效率较低。例如,磁头起始位置为53,请求序列为98、183、37等,磁头会在不同柱面间来回移动,总移动距离较大。
为了改进,出现了“短寻道优先(SSTF)”算法,它从当前磁头位置出发,优先处理离当前位置最近的请求。这种算法能减少磁头移动距离,但会出现问题:由于磁盘请求通常集中在中间柱面,磁头会在中间区域频繁移动,导致远处的请求长时间得不到处理,产生饥饿现象。
为解决上述问题,又提出了“扫描调度(SCAN)”算法,也叫电梯算法。其基本思想是磁头像电梯一样,先向一个方向移动,处理该方向上的所有请求,到达一端后再反向移动,处理另一方向的请求。这样既保证了公平性,又避免了磁头频繁回退,减少了总移动距离。
如果进一步优化,让磁头在到达一端后快速复位,再向另一方向移动,就形成了更公平的调度方式 。
在实际代码实现中,多个进程访问磁盘时,先根据用户发来的盘块号换算成扇区号,将请求加入请求队列。加入队列时,使用临界区保护确保共享结构的操作安全,并按照电梯算法的规则,根据柱面号对请求进行排序,形成有序队列。磁盘驱动在磁盘中断时,从队列中取出请求,进行c
、h
、s
的计算,通过out
指令发送给磁盘控制器,完成读写操作。操作完成后,再次中断处理,唤醒等待的进程,使其继续工作。
总结与展望
到这里,我们完整地讲述了生磁盘的使用过程,从磁盘的直接操作逐步抽象,实现了多进程高效、方便地使用磁盘,过程中还涉及到进程间的合作、临界区保护、同步等操作系统的重要概念。不过,这里还留下一个伏笔:如何根据文件得到盘块号?后续将把这部分内容与文件系统相结合,呈现出操作系统真正读写文件、管理磁盘的完整故事。