第一层抽象:从扇区到磁盘块请求
基于如图所示的编址结构,C、H、S扇区地址所对应的扇区号是
s
e
c
t
o
r
=
c
×
(
H
e
a
d
s
×
S
e
c
t
o
r
s
)
+
H
×
S
e
c
t
o
r
s
+
S
sector=c\times(Heads \times Sectors) + H\times Sectors + S
sector=c×(Heads×Sectors)+H×Sectors+S
其中sector是扇区号,sectors是灭个磁道的扇区数,Heads是磁盘的磁头数量。再将这个公式简单变形就可以得到:
s
e
c
t
o
r
=
(
C
×
H
e
a
d
s
+
H
)
×
S
e
c
t
o
r
s
+
S
sector = (C \times Heads + H) \times Sectors +S
sector=(C×Heads+H)×Sectors+S
此时再根据扇区号sector来算出C、H、S就很容易了,即
S
=
s
e
c
t
o
r
%
S
e
c
t
o
r
s
S = sector \% Sectors
S=sector%Sectors
H
=
=
s
e
c
t
o
r
/
S
e
c
t
o
r
s
%
H
e
a
d
s
H = = sector /Sectors\% Heads
H==sector/Sectors%Heads
S
=
s
e
c
t
o
r
/
S
e
c
t
o
r
s
/
H
e
a
d
s
S = sector/ Sectors/Heads
S=sector/Sectors/Heads
实际上,多个连续的扇区就是一个磁盘块。引入磁盘块以后用户读写磁盘的基本单位就不再是扇区,而是磁盘块了。
第二层抽象:多进程产生的磁盘块的请求队列
经过第一层抽象以后,我们只要告诉操作系统系统读写的磁盘块就可以完成磁盘读写。而经过第二层抽象以后,磁盘读写会编程这个样子:想进行磁盘读写的进程首先建立一个磁盘请求数据结构,并在这个数据结构中填上要读写的盘块号,然后将这个数据结构放入磁盘请求队列中就完成了“磁盘读写”。剩下的工作交给操作系统完成,对用户完全透明。第二层的核心就是磁盘调度算法。
磁盘调度算法
第三层抽象:从磁盘请求到高速缓存
高速缓存是磁盘管理的又一层抽象,即操作系统将磁盘数据“变成”一系列位于内核态内存中的缓存内容。具体来说,从用户角度出发,磁盘读写变成了高速缓存读写,用户向高速缓存发出读写请求,如果用户请求的数据在高速缓存中,操作系统会直接将信息返回;如果不再,才发出磁盘请求去读写磁盘。
当用户发出一个磁盘读写请求时,操作系统会在高速缓存中查找这个磁盘块是否已经在高速缓存中,如果在就直接返回。所以高速缓存的关键是要提供一种基址来快速查找一个磁盘块数据是否在高速缓存中。
要根据一个关键词(盘块号)来快速查找这个关键字是否在一个表中,最通常使用的数据结构就是散列表,所以高速缓存要以盘块号为关键字形成一个散列表来组织那些已载入的磁盘块数据——缓存块。
如果发现高速缓存中没有用户请求的磁盘块,此时应该去读写物理磁盘,这就要求在高速缓存中取出一个空闲缓存块,用来缓存从磁盘中读出的数据,而组织空闲缓存块通常使用的数据结构就是空闲链表。
因此设计磁盘高速缓存的核心就是要建立两个数据结构:用一个散列表组织有内容的缓存块,再用一个空闲列表组织那些空闲的缓存块,如图所示
第四层抽象:引出文件
操作系统在这一层抽象就是要将磁盘块抽象为一个字符流,经过抽象以后:(1)用户看到并访问的是一个文件,是一个字符流。(2)从磁盘物理设备出发,磁盘中只有磁盘块,所以字符流最终还要存放在盘块上的(3)操作系统要将字符流读写映射为磁盘块的读写。实现文件抽象的关键在于建立字符流和盘块好之间的硬件关系。
第五层抽象:将真个磁盘抽象成一个文件系统
操作系统中不可能只有一个文件,对一个文件到很对文件,首先要解决的就是如何组织多个文件最容易想到的组织方法就是将将很多个文件并列在一起,如图所示
如果一个磁盘上有几万个文件,并且将这几万个文件都并列在一起。如果这几万个文件用ls列出来,会是多么长的表。
文件目录树