一、概述
磁盘也属于外设,所以在unix/linux的世界里,操作磁盘也要像操作文件一样。
那么操作系统是如何将磁盘抽象成文件系统的呢?
二、直接使用磁盘
1.前言
操作系统把磁盘抽象成文件,本质是屏蔽掉使用磁盘的细节。
所以,首先要明白如何直接使用磁盘。
所谓使用磁盘,即①把内存缓冲区(缓存)的数据写到磁盘数据块中或②把磁盘数据块的数据读到缓存中。
2.找到磁盘数据块
根据磁盘的结构可知,通过柱面
、磁头
、扇区
定位磁盘数据块。
3.直接使用磁盘(CHS方式)
(1)只要在程序中向磁盘控制器
的寄存器写入柱面号
、磁头号
、扇区号
以及缓存起始地址和大小,即可使用磁盘。
(2)相关源码(在kernel/blk_drv/hd.c
中)
显然,让用户通过记住
柱面号
(cyl)、磁头号
(head)、扇区号
(sect)来使用磁盘是很不方便的。
柱面:cylinder
磁头:head
扇区:sector
三、从磁盘到文件的第1层抽象:盘块号
1.前言
磁盘实际上是一个个磁盘数据块(假设有n
块),如果让用户通过块号i
(
i
∈
[
0
,
n
−
1
]
i\in[0, n-1]
i∈[0,n−1])来使用磁盘,那么就比CHS方式便捷多了。
2.操作系统要实现盘块号block和CHS的映射
(1)磁盘编址方式
- 高效的磁盘编址方式,可以使磁盘访问时间更少。
- 磁盘访问时间 = 写入控制器时间 + 寻道时间 + 旋转时间 + 传输时间,且已知寻道时间最耗时。
- 所以,这样编址:从0号柱面和0号盘面开始(如下图所示),0号盘块对应0号扇区,1号盘块对应1号扇区。
假设用户要读取1~4号扇区的内容,按上述编址,就不需要换道了。
PS : 但实际上,这样编址是有问题的,因为当读完1号扇区的内容,并不能立马就读2号扇区,而这种连续放置的方式,会导致重新转一圈才能读2号扇区。(本文忽略这一问题。)
(2)盘块号block和CHS的映射
1)block = C * (NH * NS) + H * NS + S
CHS分别指柱面号、磁头号和扇区号;
而NH指磁头数,NS指扇区数。
比如3号盘块对应3号扇区,即C = 0, H = 0, S = 3。
PS:根据盘块号来寻址准确说叫LBA
(Logical Block Addressing)逻辑块寻址模式。
2)用户提供block,操作系统将block转为CHS
①S = block % NS
②H = (block / NS) % NH
③C = block / (NS * NH)
(3)一个盘块等于几个扇区比较合适?
以空间换时间的想法,多读一些磁盘数据块,虽然里面的数据不一定用上(空间利用率下降),但读写速度更好。
linux-0.11中,1个盘块 = 2个扇区(512B)
(4)相关源码(在kernel/blk_drv/hd.c
中)
此时,用户可以通过盘块号block请求使用磁盘,而操作系统负责把block转化为CHS来满足用户的请求。
四、从磁盘到文件的第2层抽象:请求队列
1.前言
磁盘是给多个进程使用的,所以操作系统将多个进程访问磁盘的盘块号(比如:进程1请求访问盘块2,进程2请求访问盘块7)放入请求队列,然后按照某种方法(即调度算法)选择盘块号处理。
由上文可知,寻道时间是最耗时的,所以好的调度算法要使得整体寻道时间尽可能少。
2.调度算法
(1)FCFS : First Come First Service
98先到,先移动到98号磁道上。
该调度算法的优缺点:
①优点:公平、容易实现
②缺点:磁头在长途奔袭!(好生动的拟人,指在寻道上很耗时)
(2)SSTF : Shortest-seek-time First
移动到离当前磁头所在磁道最近的磁道。
比如65号磁道离53号磁道最近,那么就移动到65号磁道。
该调度算法的优缺点:
①优点:整体寻道时间少
②缺点:如果总是有离磁头近的请求,会导致离磁头远的请求一直得不到响应,即出现饥饿现象。
(3)SCAN
规定:磁头向0号磁道运动,然后折返向199号磁道运动。
优化:不必到达0号磁道再折返,只需到达请求队列中最小的磁道号就可以折返了;同理,也不必到达199号磁道再折返。
该调度算法的优缺点:
①优点:解决了饥饿现象
②缺点:两端请求响应较慢
(4)C-SCAN:电梯算法
解决了两端请求响应较慢的问题,比较公平且整体寻道时间较少(磁头复位时间比较快)。
3.相关源码
在
blk_drv/ll_rw_blk.c
中
在
blk_drv/blk.h
中
由上面源码可知,操作系统维护请求队列以使得整体寻道时间更少,这不仅让用户方便地使用磁盘,而且还提高了磁盘的使用效率。
4.从磁盘到文件系统的第1和2层抽象的总结
(1)进程用盘块号发出使用磁盘的请求(通过中断,靠OS使用硬件资源)后睡眠
(2)操作系统处理磁盘中断
- 操作系统维护请求队列,根据电梯算法选择盘块号
- do_hd_request函数中,算出CHS
- hd_out函数中,将CHS写入磁盘控制器的端口(寄存器)中
(3)唤醒进程
五、从磁盘到文件系统的第3层抽象:文件
1.前言
普通用户连扇区都不知道是啥,更别提通过盘块号来使用磁盘了。
所以,操作系统还需要进一步对磁盘进行抽象,即让用户通过读写文件来使用磁盘。
2.建立文件和盘块集合的映射
(0)通俗理解
用户读写文件的某个部分,操作系统知道该部分对应磁盘中的哪个或哪些盘块。
和上文将block和CHS的映射逻辑一致,要知道文件和盘块集合的映射,得先知道文件当初是怎么存储在磁盘中的。
(1)文件在磁盘中的存储方式
- 连续结构
假设文件大小为1500B,用户修改了文件的第700字节~第800字节,而每个盘块是1024B,所以修改部分对应第1个盘块。因此,只要知道分配给该文件的起始盘块号(比如,6),则操作系统就知道要把用户修改的内容(还在内存中)写入6号盘块。
起始盘块存储在文件的FCB中
该结构的优缺点:
①优点:随机访问,修改方便。
②缺点:文件大小受限。(对于f文件,起始盘块假设是0,只能再增加2个盘块的内容了。)
- 链式结构
该结构的优缺点:
①优点:便于增删文件内容
②缺点:不能随机访问,不便于修改
- 索引结构
是连续结构和链式结构的折中,既实现随机访问,又方便增删文件内容。
- 多级索引
linux-0.11便是采用多级索引的方式。
(2)让用户通过文件使用磁盘
1)根据上述文件存储方式(比如索引结构),当用户操作文件的某个部分,操作系统就能推算出该文件对应于磁盘的哪个盘块号从而让用户使用磁盘。
2)L30 文件使用磁盘的实现
六、从磁盘到文件系统的第4层抽象:文件系统
1.前言
1个文件映射到一些盘块,那么一堆文件便映射到整个磁盘,为了让用户高效的使用磁盘,显然操作系统要把文件组织起来,即建立文件系统。
2.文件组织结构
(1)单级目录结构
缺点:查找速度慢、文件不允许重名、不便于文件共享
(2)两级目录结构
缺点:每个用户的目录又属于单级目录结构
(3)多级目录结构(树形目录结构)
用户通过路径(绝对路径 或 相对路径)访问文件从而使用磁盘,操作系统就需要进行目录解析找到文件。
还有无环图目录结构,便于文件共享。
3.L32 目录解析代码实现
目录解析四部曲:
①通过current->root
找到根目录
②通过find_entry
函数读取目录项(对应上图的<var, 13><my, 82>)
③inr
即目标目录的索引节点号(对应上图的82)
④通过iget
函数再读取下一层目录(对应上图的my目录)
重复②~④,即可得到data文件的FCB。