第 5 章 输入/输出(I/O)管理

Intro

【考纲内容】

(一)I/O管理基础设备: 设备的基本概念,设备的分类,I/O接口 I/O控制方式:轮询方式,中断方式,DMA方式 I/O 软件层次结构:中断处理程序,驱动程序,设备独立性软件,用户层 I/O 软件输入/输出应用程序接口:字符设备接口,块设备接口,网络设备接口阻塞/非阻塞I/O

(二)设备独立软件 缓冲区管理;设备分配与回收;假脱机技术(SPOOLing);设备驱动程序接口)

(三)外存管理 磁盘:磁盘结构,格式化,分区,磁盘调度方法

(四)固态硬盘 读写性能特效,磨损均衡

【复习提示】

本章的内容较为分散,重点掌握 I/O 接口、IO 软件、三种IO控制方式、高速缓存与缓冲区、SPOOLing 技术,磁盘特性和调度算法。本章很多知识点与硬件高度相关,建议与计算机组成原理的对应章节结合复习。已复习过计算机组成原理的读者遇到比较熟悉的内容时也可适当跳过。另外,未复习过计算机组成原理的读者可能会觉得本章的习题较难,但不需要担心。

本章内容在历年统考真题中所占的比重不大,若统考中出现本章的题目,则基本上可以断定一定非常简单,看过相关内容的读者就一定会做,而未看过的读者基本上只能靠“蒙”。考研成功的秘诀是复习要反复多次并全面,偷工减料是要吃亏的,希望读者重视本章的内容。

一、I/O 管理概述

0x00 I/O 设备

I/O设备管理是操作系统设计中最凌乱也最具挑战性的部分。由于它包含了很多领域的不同设备及与设备相关的应用程序,因此很难有一个通用且一致的设计方案。

1. 设备的分类

按信息交换的单位分类,I/O设备可分为:

  1. 块设备。信息交换以数据块为单位。它属于有结构设备,如磁盘等。磁盘设备的基本特征是传输速率较高、可寻址,即对它可随机地读/写任意一块。
  2. 字符设备。信息交换以字符为单位。它属于无结构类型,如交互式终端机、打印机等。 它们的基本特征是传输速率低、不可寻址,并且时常采用中断 I/O 方式。

按传输速率分类,IO设备可分为:

  1. 低速设备。传输速率仅为每秒几字节到数百字节的一类设备,如键盘、鼠标等。
  2. 中速设备。传输速率为每秒数千字节至数万字节的一类设备,如激光打印机等。
  3. 高速设备。传输速率在数百千字节至千兆字节的一类设备,如磁盘机、光盘机等。

2. I/O接口

I/O 接口(设备控制器)位于CPU与设备之间,它既要与CPU 通信,又要与设备通信,还要具有按CPU发来的命令去控制设备工作的功能,主要由三部分组成,如图5.1所示。

1

  1. 设备控制器与CPU的接口。该接口有三类信号线:数据线地址线控制线。数据线通常与两类寄存器相连:数据寄存器(存放从设备送来的输入数据或从CPU送来的输出数据)和控制/状态寄存器(存放从CPU送来的控制信息或设备的状态信息)。
  2. 设备控制器与设备的接口。一个设备控制器可以连接一个或多个设备,因此控制器中有一个或多个设备接口。每个接口中都存在数据、控制和状态三种类型的信号。
  3. I/O逻辑。用于实现对设备的控制。它通过一组控制线与CPU交互,对从CPU收到的I/O命令进行译码。CPU启动设备时,将启动命令发送给控制器,同时通过地址线把地址发送给控制器,由控制器的I/O逻辑对地址进行译码,并相应地对所选设备进行控制。

设备控制器的主要功能有:①接收和识别CPU发来的命令,如磁盘控制器能接收读、写、查找等命令;②数据交换,包括设备和控制器之间的数据传输,以及控制器和主存之间的数据传输;③标识和报告设备的状态,以供CPU 处理;④地址识别;⑤数据缓冲;⑥差错控制。

3. I/O 端口

I/O端口是指设备控制器中可被CPU直接访问的寄存器,主要有以下三类寄存器。

I/O 端口为了实现 CPU 与 I/O 端口进行通信,有两种方法,如图 5.2 所示。

  1. 独立编址。为每个端口分配一个I/O端口号,所有I/O端口形成I/O端口空间,普通用户程序不能对其进行访问,只有操作系统使用特殊的I/O指令才能访问端口。
  2. 统一编址。又称内存映射I/O,每个端口被分配唯一的内存地址,且不会有内存被分配这一地址,通常分配给端口的地址靠近地址空间的顶端。

2

0x01 I/O控制方式

设备管理的主要任务之一是控制设备和内存或CPU 之间的数据传送。外围设备和内存之间的输入/输出控制方式有4种,下面分别加以介绍。

1. 程序直接控制方式

如图5.3(a)所示,计算机从外部设备读取的每个字,CPU 需要对外设状态进行循环检查,直到确定该字已经在I/O控制器的数据寄存器中。在程序直接控制方式中,由于CPU的高速性和I/O设备的低速性,致使CPU的绝大部分时间都处于等待I/O设备完成数据I/O的循环测试中,造成了 CPU 资源的极大浪费。在该方式中,CPU 之所以要不断地测试 I/O 设备的状态,就是因为在CPU中未采用中断机构,使I/O设备无法向CPU报告它已完成了一个字符的输入操作。

3a

程序直接控制方式虽然简单且易于实现,但其缺点也显而易见,由于CPU和I/O设备只能串行工作,导致CPU的利用率相当低。

2. 中断驱动方式

中断驱动方式的思想是,允许IO设备主动打断CPU的运行并请求服务,从而“解放”CPU,使得其向 I/O 控制器发送读命令后可以继续做其他有用的工作。如图 5.3(b)所示,我们从 I/O 控制器和CPU两个角度分别来看中断驱动方式的工作过程。

从 I/O 控制器的角度来看,I/O 控制器从 CPU 接收一个读命令,然后从外部设备读数据。一旦数据读入I/O控制器的数据寄存器,便通过控制线给CPU发出中断信号,表示数据已准备好,然后等待 CPU请求该数据。I/O 控制器收到 CPU 发出的取数据请求后,将数据放到数据总线上;传到 CPU的寄存器中。至此,本次 I/O操作完成,I/O 控制器又可开始下一次 I/O 操作。

从CPU的角度来看,CPU发出读命令,然后保存当前运行程序的上下文(包括程序计数器及处理机寄存器),转去执行其他程序。在每个指令周期的末尾,CPU检查中断。当有来自I/O控制器的中断时,CPU保存当前正在运行程序的上下文,转去执行中断处理程序以处理该中断。这时,CPU从IO控制器读一个字的数据传送到寄存器,并存入主存。接着,CPU恢复发出I/O命令的程序(或其他程序)的上下文;然后继续运行。

中断驱动方式比程序直接控制方式有效,但由于数据中的每个字在存储器与I/O控制器之间的传输都必须经过CPU,这就导致了中断驱动方式仍然会消耗较多的CPU时间。

3b

3. DMA 方式

在中断驱动方式中,I/O 设备与内存之间的数据交换必须要经过CPU中的寄存器,所以速度还是受限,而DMA(直接存储器存取)方式的基本思想是在I/O设备和内存之间开辟直接的数据交换通路,彻底“解放”CPU。DMA方式的特点如下:

  1. 基本单位是数据块。
  2. 所传送的数据,是从设备直接送入内存的,或者相反。
  3. 仅在传送一个或多个数据块的开始和结束时,才需 CPU 干预,整块数据的传送是在 DMA 控制器的控制下完成的。

图5.4列出了 DMA控制器的组成。

4

要在主机与控制器之间实现成块数据的直接交换,须在 DMA 控制器中设置如下 4 类寄存器:

  1. 命令/状态寄存器(CR)。接收从 CPU发来的IV/O 命令、有关控制信息,或设备的状态。
  2. 内存地址寄存器(MAR)。在输入时,它存放把数据从设备传送到内存的起始目标地址;在输出时,它存放由内存到设备的内存源地址。
  3. 数据寄存器(DR)。暂存从设备到内存或从内存到设备的数据。
  4. 数据计数器(DC)。存放本次要传送的字(节)数。

如图 5.3(c)所示,DMA 方式的工作过程是:CPU接收到 I/O 设备的 DMA请求时,它给DMA控制器发出一条命令,同时设置 MAR 和 DC 初值,启动 DMA 控制器,然后继续其他工作。之后CPU 就把控制操作委托给 DMA 控制器,由该控制器负责处理。DMA 控制器直接与存储器交互,传送整个数据块,每次传送一个字,这个过程不需要CPU参与。传送完成后,DMA控制器发送一个中断信号给处理器:因此只有在传送开始和结束时才需要CPU的参与。

DMA方式与中断方式的主要区别是,中断方式在每个数据需要传输时中断CPU,而DMA方式则是在所要求传送的一批数据全部传送结束时才中断CPU;此外,中断方式的数据传送是在中断处理时由 CPU 控制完成的,而 DMA 方式则是在 DMA 控制器的控制下完成的。

3c

*4. 通道控制方式

I/O 通道是指专门负责输入/输出的处理机。I/O 通道方式是 DMA 方式的发展,它可以进一步减少CPU的干预,即把对一个数据块的读(或写)为单位的干预,减少为对一组数据块的读(或写)及有关控制和管理为单位的干预。同时,又可以实现 CPU、通道和 I/O 设备三者的并行操作,从而更有效地提高整个系统的资源利用率。

例如,当 CPU 要完成一组相关的读(或写)操作及有关控制时,只需向 I/O 通道发送一条 I/O指令,以给出其所要执行的通道程序的首地址和要访问的I/SO设备,通道接到该指令后,执行通道程序便可完成CPU指定的I/O任务,数据传送结束时向CPU发中断请求。

I/O 通道与一般处理机的区别是:通道指令的类型单一,没有自己的内存,通道所执行的通道程序是放在主机的内存中的,也就是说通道与CPU共享内存。

I/O 通道与 DMA 方式的区别是:DMA方式需要CPU来控制传输的数据块大小、传输的内存位置,而通道方式中这些信息是由通道控制的。另外,每个DMA控制器对应一台设备与内存传递数据,而一个通道可以控制多台设备与内存的数据交换。

 

0x02 I/O 软件层次结构

I/O 软件涉及的面很宽,往下与硬件有着密切关系,往上又与虚拟存储器系统、文件系统和用户直接交互,它们都需要 I/O 软件来实现I/O操作。

为使复杂的I/O软件能具有清晰的结构、良好的可移植性和易适应性,目前已普遍采用层次式结构的I/O软件。将系统中的设备管理模块分为若干个层次,每层都是利用其下层提供的服务,完成输入/输出功能中的某些子功能,并屏蔽这些功能实现的细节,向高层提供服务。在层次式结构的 I/O 软件中,只要层次间的接口不变,对某一层中的软件的修改都不会引起其下层或高层代码的变更,仅最低层才涉及硬件的具体特性。

5-5

一个比较合理的层次划分如图 5.5 所示。整个 I/O 软件可以视为具有4个层次的系统结构,各层次及其功能如下:

1. 用户层I/O软件

实现与用户交互的接口,用户可直接调用在用户层提供的、与I/O操作有关的库函数,对设备进行操作。一般而言,大部分的 I/O 软件都在操作系统内部,但仍有一小部分在用户层,包括与用户程序链接在一起的库函数。用户层软件必须通过一组系统调用来获取操作系统服务。

2. 设备独立性软件

用于实现用户程序与设备驱动器的统一接口、设备命令、设备的保护及设备的分配与释放等,同时为设备管理和数据传送提供必要的存储空间。

设备独立性也称设备无关性,使得应用程序独立于具体使用的物理设备。为实现设备独立性而引入了逻辑设备和物理设备这两个概念。在应用程序中,使用逻辑设备名来请求使用某类设备;而在系统实际执行时,必须将逻辑设备名映射成物理设备名使用。

使用逻辑设备名的好处是:①增加设备分配的灵活性;②易于实现 I/O 重定向,所谓 I/O 重定向,是指用于 I/O 操作的设备可以更换(即重定向),而不必改变应用程序。

为了实现设备独立性,必须再在驱动程序之上设置一层设备独立性软件。总体而言,设备独立性软件的主要功能可分为以下两个方面:①执行所有设备的公有操作,包括:对设备的分配与回收:将逻辑设备名映射为物理设备名;对设备进行保护,禁止用户直接访问设备;缓冲管理;差错控制;提供独立于设备的大小统一的逻辑块,屏蔽设备之间信息交换单位大小和传输速率的差异。 ②向用户层(或文件层)提供统一接口。无论何种设备,它们向用户所提供的接口应是相同的。例如,对各种设备的读/写操作,在应用程序中都统一使用 read/write 命令等。

3. 设备驱动程序

与硬件直接相关,负责具体实现系统对设备发出的操作指令,驱动I/O设备工作的驱动程序。通常,每类设备配置一个设备驱动程序,它是I/O进程与设备控制器之间的通信程序,通常以进程的形式存在。设备驱动程序向上层用户程序提供一组标准接口,设备具体的差别被设备驱动程序所封装,用于接收上层软件发来的抽象I/O要求,如read和write 命令,转换为具体要求后,发送给设备控制器,控制I/O设备工作;它也将由设备控制器发来的信号传送给上层软件,从而为I/O内核子系统隐藏设备控制器之间的差异

4. 中断处理程序

用于保存被中断进程的CPU环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场后,返回到被中断进程。

中断处理层的主要任务有:进行进程上下文的切换,对处理中断信号源进行测试,读取设备状态和修改进程状态等。由于中断处理与硬件紧密相关,对用户而言,应尽量加以屏蔽,因此应放在操作系统的底层,系统的其余部分尽可能少地与之发生联系。

 

类似于文件系统的层次结构,I/O 子系统的层次结构也是我们需要记忆的内容,但记忆不是死记硬背,我们以用户对设备的一次命令来总结各层次的功能,帮助各位读者记忆。

例如, ①当用户要读取某设备的内容时,通过操作系统提供的read命令接口,这就经过了用户层。 ②操作系统提供给用户使用的接口,一般是统一的通用接口,也就是几乎每个设备都可以响应的统一命令,如read命令,用户发出的read命令,首先经过设备独立层进行解析,然后交往下层。 ③接下来,不同类型的设备对read命令的行为会有所不同,如磁盘接收read命令后的行为与打印机接收read命令后的行为是不同的。因此,需要针对不同的设备,把read命令解析成不同的指令,这就经过了设备驱动层。 ④命令解析完毕后,需要中断正在运行的进程,转而执行read命令,这就需要中断处理程序。 ⑤最后,命令真正抵达硬件设备,硬件设备的控制器按照上层传达的命令操控硬件设备,完成相应的功能。

 

0x03 应用程序 I/O 接口

在I/O系统与高层之间的接口中,根据设备类型的不同,又进一步分为若干接口。

1. 字符设备接口

字符设备是指数据的存取和传输是以字符为单位的设备,如键盘、打印机等。基本特征是传输速率较低、不可寻址,并且在输入/输出时通常采用中断驱动方式。

get和 put 操作。由于字符设备不可寻址,只能采取顺序存取方式,通常为字符设备建立一个字符缓冲区,用户程序通过 get 操作从缓冲区获取字符,通过 put 操作将字符输出到缓冲区。

in-control 指令。字符设备类型繁多,差异甚大,因此在接口中提供一种通用的 in-control 指令来处理它们(包含了许多参数,每个参数表示一个与具体设备相关的特定功能)。

字符设备都属于独占设备,为此接口中还需要提供打开和关闭操作,以实现互斥共享。

2. 块设备接口

块设备是指数据的存储和传输是以数据块为单位的设备,典型的块设备是磁盘。基本特征是传输速率较高、可寻址。磁盘设备的 I/O 常采用DMA方式

隐藏了磁盘的二维结构。在二维结构中,每个扇区的地址需要用磁道号和扇区号来表示块设备接口将磁盘的所有扇区从 0 到 n-1 依次编号,这样,就将二维结构变为一种线性序列。

将抽象命令映射为低层操作。块设备接口支持上层发来的对文件或设备的打开、读、写和关闭等抽象命令,该接口将上述命令映射为设备能识别的较低层的具体操作。

内存映射接口通过内存的字节数组来访问磁盘,而不提供读/写磁盘操作。映射文件到内存的系统调用返回包含文件副本的一个虚拟内存地址。只在需要访问内存映像时,才由虚拟存储器实际调页。内存映射文件的访问如同内存读写一样简单,极大地方便了程序员。

3. 网络设备接口

现代操作系统都提供面向网络的功能,因此还需要提供相应的网络软件和网络通信接口,使计算机能够通过网络与网络上的其他计算机进行通信或上网浏览。

许多操作系统提供的网络I/O接口为网络套接字接口,套接字接口的系统调用使应用程序创建的本地套接字连接到远程应用程序创建的套接字,通过此连接发送和接收数据。

4. 阻塞/非阻塞I/O

操作系统的I/O接口还涉及两种模式:阻塞和非阻塞。

阻塞I/O是指当用户进程调用I/O操作时,进程就被阻塞,需要等待I/O操作完成,进程才被唤醒继续执行。非阻塞I/O是指用户进程调用I/O操作时,不阻塞该进程,该I/O调用返回一个错误返回值,通常,进程需要通过轮询的方式来查询I/O操作是否完成。

大多数操作系统提供的I/O接口都是采用阻塞I/O。

 

0x04 错题整理

12345678910111213
 CDABBAAACDB 
141516171819202122232425
            

 

二、设备独立性软件

在学习本节时,请读者思考以下问题:1)当处理机和外部设备的速度差距较大时,有什么办法可以解决问题?

0x00 与设备无关的软件

与设备无关的软件是I/O系统的最高层软件,它的下层是设备驱动程序,其间的界限因操作系统和设备的不同而有所差异。比如,一些本应由设备独立性软件实现的功能,也可能放在设备驱动程序中实现。这样的差异主要是出于对操作系统、设备独立性软件和设备驱动程序运行效率等多方面因素的权衡。总体而言,设备独立性软件包括执行所有设备公有操作的软件。

0x01 高速缓存与缓冲区

1. 磁盘高速缓存(Disk Cache)

操作系统中使用磁盘高速缓存技术来提高磁盘的I/O速度,对访问高速缓存要比访问原始磁盘数据更为高效。例如,正在运行进程的数据既存储在磁盘上,又存储在物理内存上,也被复制到CPU的二级和一级高速缓存中。不过,磁盘高速缓存技术不同于通常意义下的介于CPU与内存之间的小容量高速存储器,而是指利用内存中的存储空间来暂存从磁盘中读出的一系列盘块中的信息。因此,磁盘高速缓存逻辑上属于磁盘,物理上则是驻留在内存中的盘块。

高速缓存在内存中分为两种形式:一种是在内存中开辟一个单独的空间作为磁盘高速缓存,大小固定;另一种是把未利用的内存空间作为一个缓冲池,供请求分页系统和磁盘 I/O 时共享。

2. 缓冲区(Buffer)

在设备管理子系统中,引入缓冲区的目的主要如下:

  1. 缓和CPU与IO设备间速度不匹配的矛盾。
  2. 减少对 CPU 的中断频率,放宽对 CPU 中断响应时间的限制。
  3. 解决基本数据单元大小(即数据粒度)不匹配的问题。
  4. 提高 CPU 和 I/O 设备之间的并行性。

其实现方法如下:

  1. 采用硬件缓冲器,但由于成本太高,除一些关键部位外,一般不采用硬件缓冲器。
  2. 采用缓冲区(位于内存区域)。

根据系统设置缓冲器的个数,缓冲技术可以分为如下几种:

(1) 单缓冲

在主存中设置一个缓冲区。当设备和处理机交换数据时,先将数据写入缓冲区,然后需要数据的设备或处理机从缓冲区取走数据,在缓冲区写入或取出的过程中,另一方需等待。

如图5.6所示,在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为T,操作系统将该缓冲区中的数据传送到用户区的时间为 M,而CPU 对这一块数据处理的时间为 C。

5-6

在研究每块数据的处理时间时,有一个技巧:假设一种初始状态,然后计算下一次到达相同状态时所需要的时间,就是处理一块数据所需要的时间。在单缓冲中,这种初始状态为:工作区是满的,缓冲区是空的。如题目无明确说明,通常认为缓冲区的大小和工作区的大小相等。

假设 T > C,从初始状态开始,当工作区数据处理完后,时间为 C,缓冲区还没充满,当缓冲区充满时,经历了 T 时间,停止再冲入数据,然后缓冲区向工作区传送数据,当工作区满了后,缓冲区的数据同时也为空,用时为 M,到达下一个开始状态,整个过程用时 M + T;若 T < C,同理,整个过程用时 M + C。故单缓冲区处理每块数据的用时为 max(C, T) + M。

(2) 双缓冲

根据单缓冲的特点,CPU在传送时间M内处于空闲状态,由此引入双缓冲。I/O设备输入数据时先装填到缓冲区1,在缓冲区1填满后才开始装填缓冲区2,与此同时处理机可以从缓冲区1中取出数据送入用户进程,当缓冲区1中的数据处理完后,若缓冲区2已填满,则处理机又从缓冲区2中取出数据送入用户进程,而V/O设备又可以装填缓冲区1。注意,必须等缓冲区2充满才能让处理机从缓冲区2取出数据。双缓冲机制提高了处理机和输入设备的并行程度。

为了研究双缓冲处理一块数据的用时,我们先规定一种初始状态:工作区是空的,其中一个缓冲区是满的,另外一个缓冲区是空的:我们不妨假设缓冲区1是空的,缓冲区2是满的。

如图5.7所示,我们假设 T < C + M,缓冲区2开始向工作区传送数据,缓冲区1开始冲入数据,当工作区充满数据后,缓冲区为空,时间为M,然后工作区开始处理数据,缓冲区1继续冲入数据,因为此时只有一个 V/O 设备,所以缓冲区 2 虽然为空,但不能冲入数据。当缓冲区1充满数据后,工作区的数据还未处理完毕,时间为T,当工作区数据处理完毕后,此时工作区为空,缓冲区1满,缓冲区2为空,达到下一个初始状态,用时C+M。

7

我们再来分析T>C+M的情况。缓冲区 2开始向工作区传送数据,缓冲区1开始冲入数据,当工作区充满数据并处理完后,用时C+M,但缓冲区1的数据还未充满;当时间为T时,缓冲区1的数据充满,到达下一个初始状态。

总结:双缓冲区处理一块数据的用时为 max(C + M, T)

若 M + C < T,则可使块设备连续输入;若C + M > T,则可使CPU 不必等待设备输入。对于字符设备,若采用行输入方式,则采用双缓冲可使用户在输入第一行后,在CPU执行第一行中的命令的同时,用户可继续向第二缓冲区输入下一行数据。而单缓冲情况下则必须等待一行数据被提取完毕才可输入下一行的数据。

若两台机器之间通信仅配置了单缓冲,如图5.8(a)所示,则它们在任意时刻都只能实现单方向的数据传输。例如,只允许把数据从 A 机传送到 B 机,或从 B 机传送到A 机,而绝不允许双方同时向对方发送数据。为了实现双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区,如图5.8(b)所示。

8

(3) 循环缓冲

包含多个大小相等的缓冲区,每个缓冲区中有一个链接指针指向下一个缓冲区,最后一个缓冲区指针指向第一个缓冲区,多个缓冲区构成一个环形。

循环缓冲用于输入/输出时,还需要有两个指针 in 和 out 。对输入而言,首先要从设备接收数据到缓冲区中,in指针指向可以输入数据的第一个空缓冲区;当运行进程需要数据时,从循环缓冲区中取一个装满数据的缓冲区,并从此缓冲区中提取数据,out指针指向可以提取数据的第一个满缓冲区。输出则正好相反。

(4) 缓冲池

由多个系统公用的缓冲区组成,缓冲区按其使用状况可以形成三个队列:空缓冲队列、装满输入数据的缓冲队列(输入队列)和装满输出数据的缓冲队列(输出队列)。还应具有4种缓冲区:用于收容输入数据的工作缓冲区、用于提取输入数据的工作缓冲区、用于收容输出数据的工微信公众号:djky66作缓冲区及用于提取输出数据的工作缓冲区,如图5.9所示。

9

当输入进程需要输入数据时,便从空缓冲队列的队首摘下一个空缓冲区,把它作为收容输入工作缓冲区,然后把输入数据输入其中,装满后再将它挂到输入队列队尾。当计算进程需要输入数据时,便从输入队列取得一个缓冲区作为提取输入工作缓冲区,计算进程从中提取数据,数据用完后再将它挂到空缓冲队列尾。当计算进程需要输出数据时,便从空缓冲队列的队首取得一个输出时,由输出进程从输出队列中取得一个装满输出数据的缓冲区,作为提取输出工作缓冲区,当数据提取完后,再将它挂到空缓冲队列的队尾。

对于循环缓冲和缓冲池,我们只是定性地介绍它们的机理,而不去定量研究它们平均处理一块数据所需要的时间。而对于单缓冲和双缓冲,我们只要按照上面的模板分析,就可以解决任何计算单缓冲和双缓冲情况下数据块处理时间的问题,以不变应万变。

3. 高速缓存与缓冲区的对比

高速缓存是可以保存数据拷贝的高速存储器,访问高速缓存比访问原始数据更高效,速度更快。高速缓存和缓冲区的对比见表5.1

1

0x02 设备分配与回收

1. 设备分配概述

设备分配是指根据用户的I/O请求分配所需的设备。分配的总原则是充分发挥设备的使用效率,尽可能地让设备忙碌,又要避免由于不合理的分配方法造成进程死锁。从设备的特性来看,采用下述三种使用方式的设备分别称为独占设备共享设备虚拟设备

  1. 独占式使用设备。进程分配到独占设备后,便由其独占,直至该进程释放该设备。
  2. 分时式共享使用设备。对于共享设备,可同时分配给多个进程,通过分时共享使用。
  3. 以 SPOOLing 方式使用外部设备。SPOOLing 技术实现了虚拟设备功能,可以将设备同时分配给多个进程。这种技术实质上就是实现了对设备的I/O操作的批处理。

2. 设备分配的数据结构

设备分配依据的主要数据结构有设备控制表(DCT)、控制器控制表(COCT)、通道控制表(CHCT)和系统设备表(SDT),各数据结构功能如下。

设备控制表(DCT):一个设备控制表就表征一个设备,而这个控制表中的表项就是设备的各个属性,如图5.10所示。凡因请求本设备而未得到满足的进程,应将其PCB按某种策略排成一个设备请求队列,设备队列的队首指针指向该请求队列队首PCB。

10

设备控制器控制设备与内存交换数据,而设备控制器又需要请求通道为它服务,因此每个COCT[图 5.11(a)]有一个表项存放指向相应通道控制表(CHCT)[图 5.11(b)] 的指针,.而一个通道可为多个设备控制器服务,因此CHCT中必定有一个指针,指向一个表,这个表上的信息表达的是CHCT提供服务的那几个设备控制器。CHCT与 COCT的关系是一对多的关系。

系统设备表(SDT):整个系统只有一张SDT,如图5.11(c)所示。它记录已连接到系统中的所有物理设备的情况,每个物理设备占一个表目。

11

在多道程序系统中,进程数多于资源数,因此要有一套合理的分配原则,主要考虑的因素有:I/O 设备的固有属性、I/O 设备的分配算法、I/O 设备分配的安全性以及 IO 设备的独立性。

3. 设备分配的策略

  1. 设备分配原则。设备分配应根据设备特性、用户要求和系统配置情况。既要充分发挥设备的使用效率,又要避免造成进程死锁,还要将用户程序和具体设备隔离开。
  2. 设备分配方式。设备分配方式有静态分配和动态分配两种。 ①静态分配主要用于对独占设备的分配,它在用户作业开始执行前,由系统一次性分配该作业所要求的全部设备、控制器。一旦分配,这些设备、控制器就一直为该作业所占用,直到该作业被撤销。静态分配方式不会出现死锁,但设备的使用效率低。 ②动态分配在进程执行过程中根据执行需要进行。当进程需要设备时,通过系统调用命令向系统提出设备请求,由系统按某种策略给进程分配所需要的设备、控制器,一旦用完,便立即释放。这种方式有利于提高设备利用率,但若分配算法使用不当,则有可能造成进程死锁。
  3. 设备分配算法。常用的动态设备分配算法有先请求先分配、优先级高者优先等。 对于独占设备,既可以采用动态分配方式,又可以采用静态分配方式,但往往采用静态分配方式。共享设备可被多个进程所共享,一般采用动态分配方式,但在每个 I/O 传输的单位时间内只被一个进程所占有,通常采用先请求先分配和优先级高者优先的分配算法,

4. 设备分配的安全性

设备分配的安全性是指设备分配中应防止发生进程死锁。

  1. 安全分配方式。每当进程发出IO请求后便进入阻塞态,直到其 I/O 操作完成时才被唤醒。这样,一旦进程已经获得某种设备后便阻塞,不能再请求任何资源,而在它阻塞时也不保持任何资源。其优点是设备分配安全,缺点是CPU和I/O设备是串行工作的。
  2. 不安全分配方式。进程在发出IO请求后仍继续运行,需要时又发出第二个、第三个V/O请求等。仅当进程所请求的设备已被另一进程占用时,才进入阻塞态。优点是一个进程可同时操作多个设备,使进程推进迅速;缺点是有可能造成死锁。

5. 逻辑设备名到物理设备名的映射

为了提高设备分配的灵活性和设备的利用率,方便实现I/O重定向,引入了设备独立性。设备独立性是指应用程序独立于具体使用的物理设备。

为了实现设备独立性,在应用程序中使用逻辑设备名来请求使用某类设备,在系统中设置一张逻辑设备表(Logical Unit Table,LUT),用于将逻辑设备名映射为物理设备名。LUT表项包括逻辑设备名、物理设备名和设备驱动程序入口地址;当进程用逻辑设备名来请求分配设备时,系统为它分配一台相应的物理设备,并在LUT中建立一个表目,当以后进程再利用该逻辑设备名请求I/O操作时,系统通过查找LUT来寻找对应的物理设备和驱动程序。

在系统中可采取两种方式设置逻辑设备表:

  1. 在整个系统中只设置一张 LUT,所有进程的设备分配情况都记录在同一张 LUT 中,因此不允许LUT中具有相同的逻辑设备名,主要适用于单用户系统。
  2. 为每个用户设置一张LUT。每当用户登录时,系统便为该用户建立一个进程,同时也为之建立一张LUT,并将该表放入进程的PCB.中。

0x03 SPOOLing 技术(假脱机技术)

为了缓和 CPU的高速性与IVO 设备低速性之间的矛盾,引入了脱机输入/输出技术,它是操.作系统中采用的一项将独占设备改造成共享设备的技术。该技术利用专门的外围控制机,将低速I/O 设备上的数据传送到高速磁盘上,或者相反。SPOOLing 系统的组成如图 5.12 所示。

12

  1. 输入井和输出井 在磁盘上开辟出的两个存储区域。输入井模拟脱机输入时的磁盘,用于收容IO设备输入的内存数据。输出井模拟脱机输出时的磁盘,用于收容用户程序的输出数据。一个进程的输入(或输出)数据保存为一个文件,所有进程的数据输入(或输出)文件链接成一个输入(或输出)队列。
  2. 输入缓冲区和输出缓冲区 在内存中开辟的两个缓冲区。输入缓冲区用于暂存由输入设备送来的数据,以后再传送到输入井。输出缓冲区用于暂存从输出井送来的数据,以后再传送到输出设备。
  3. 输入进程和输出进程 输入/输出进程用于模拟脱机输入/输出时的外围控制机。用户要求的数据从输入设备经过输入缓冲区送到输入井,当CPU需要输入数据时,直接从输入井读入内存。用户要求输出的数据先从内存送到输出井,待输出设备空闲时,再将输出井中的数据经过输出缓冲区送到输出设备。

共享打印机是使用 SPOOLing 技术的实例。当用户进程请求打印输出时,SPOOLing 系统同意打印,但是并不真正立即把打印机分配给该进程,而由假脱机管理进程完成两项任务:

  1. 在磁盘缓冲区中为之申请一个空闲盘块,并将要打印的数据送入其中暂存。
  2. 为用户进程申请一张空白的用户请求打印表,并将用户的打印要求填入其中,再将该表挂到假脱机文件队列上。

这两项工作完成后,虽然还没有任何实际的打印输出,但是对于用户进程而言,其打印任务已完成。对用户而言,系统并非立即执行真实的打印操作,而只是立即将数据输出到缓冲区,真正的打印操作是在打印机空闲且该打印任务已排在等待队列队首时进行的。

SPOOLing系统的特点如下: ①提高了 I/O 的速度,将对低速I/O设备执行的I/O操作演变为对磁盘缓冲区中数据的存取,如同脱机输入/输出一样,缓和了CPU和低速VO设备之间的速度不匹配的矛盾; ②将独占设备改造为共享设备,在假脱机打印机系统中,实际上并没有为任何进程分配设备; ③实现了虚拟设备功能,对每个进程而言,它们都认为自己独占了一个设备。

前面我们提到过SPOOLing技术是一种以空间换时间的技术,我们很容易理解它牺牲了空间,因为它开辟了磁盘上的空间作为输入井和输出井,但它又如何节省时间呢?

从前述内容我们了解到,磁盘是一种高速设备,在与内存交换数据的速度上优于打印机、键盘、鼠标等中低速设备。试想一下,若没有 SPOOLing 技术,CPU要向打印机输出要打印的数据,打印机的打印速度比较慢,CPU就必须迁就打印机,在打印机把数据打印完后才能继续做其他的工作,浪费了CPU 的不少时间。在 SPOOLing技术下,CPU要打印机打印的数据可以先输出到磁盘的输出井中(这个过程由假脱机进程控制),然后做其他的事情。若打印机此时被占用,则SPOOLing系统就会把这个打印请求挂到等待队列上,待打印机有空时再把数据打印出来。向磁盘输出数据的速度比向打印机输出数据的速度快,因此就节省了时间。

0x04 设备驱动程序接口

如果每个设备驱动程序与操作系统的接口都不同,那么每次出现一个新设备时,都必须为此修改操作系统。因此,要求每个设备驱动程序与操作系统之间都有着相同或相近的接口。这样会使得添加一个新设备驱动程序变得很容易,同时也便于开发人员编制设备驱动程序。

对于每种设备类型,例如磁盘,操作系统都要定义一组驱动程序必须支持的函数。对磁盘而言;这些函数自然包含读、写、格式化等。驱动程序中通常包含一张表格,这张表格具有针对这些函数指向驱动程序自身的指针。装载驱动程序时,操作系统记录这个函数指针表的地址,所以当操作系统需要调用一个函数时,它可以通过这张表格发出间接调用。:这个函数指针表定义了驱动程序与操作系统其余部分之间的接口。给定类型的所有设备都必须服从这一要求。

与设备无关的软件还要负责将符号化的设备名映射到适当的驱动程序上。例如,在UNIX中,设备名/dev/disk0唯一确定了一个特殊文件的i结点,这个i结点包含了主设备号(用于定位相应的驱动程序)和次设备号(用来确定要读写的具体设备)。

在UNIX和Windows中,设备是作为命名对象出现在文件系统中的,:因此针对文件的常规保护规则也适用于I/O设备。系统管理员可以为每个设备设置适当的访问权限。

 

三、磁盘和固态硬盘

0x00 磁盘

磁盘(Disk)是由表面涂有磁性物质的物理盘片,通过一个称为磁头的导体线圈从磁盘存取数据。在读/写操作期间,磁头固定,磁盘在下面高速旋转。如图5.13所示,磁盘盘面上的数据存储在一组同心圆中,称为磁道。每个磁道与磁头一样宽,一个盘面有上千个磁道。磁道又划分为几百个扇区,每个扇区固定存储大小,一个扇区称为一个盘块。相邻磁道及相邻扇区间通过一定的间隙分隔开,以避免精度错误。注意,由于扇区按固定圆心角度划分,所以密度从最外道向里道增加,磁盘的存储能力受限于最内道的最大记录密度。

磁盘安装在一个磁盘驱动器中,它由磁头臂、用于旋转磁盘的主轴和用于数据输入/输出的电子设备组成。如图5.14所示,多个盘片垂直堆叠,组成磁盘组,每个盘面对应一个磁头,所有磁头固定在一起,与磁盘中心的距离相同且一起移动。所有盘片上相对位置相同的磁道组成柱面。扇区是磁盘可寻址的最小单位,磁盘上能存储的物理块数目由扇区数、磁道数及磁盘面数决定,磁盘地址用“柱面号·盘面号·扇区号”表示。

13

磁盘按不同的方式可分为若干类型:磁头相对于盘片的径向方向固定的,称为固定头磁盘,每个磁道一个磁头;磁头可移动的,称为活动头磁盘,磁头臂可来回伸缩定位磁道;磁盘永久固定在磁盘驱动器内的,称为固定盘磁盘;可移动和替换的,称为可换盘磁盘。

操作系统中几乎每介绍一类资源及其管理时,都要涉及一类调度算法。用户访问文件,需要操作系统的服务,文件实际上存储在磁盘中,操作系统接收用户的命令后,经过一系列的检验访问权限和寻址过程后,最终都会到达磁盘,控制磁盘把相应的数据信息读出或修改。当有多个请求同时到达时,操作系统就要决定先为哪个请求服务,这就是磁盘调度算法要解决的问题。

0x01 磁盘的管理

1. 磁盘初始化

一个新的磁盘只是一个磁性记录材料的空白盘。在磁盘可以存储数据之前,必须将它分成扇区,以便磁盘控制器能够进行读写操作,这个过程称为低级格式化(或称物理格式化)。低级格式化为每个扇区使用特殊的数据结构,填充磁盘。每个扇区的数据结构通常由头部、数据区域(通常为512B大小)和尾部组成。头部和尾部包含了一些磁盘控制器的使用信息。

大多数磁盘在工厂时作为制造过程的一部分就已低级格式化,这种格式化能够让制造商测试磁盘,并且初始化逻辑块号到无损磁盘扇区的映射。对于许多磁盘,当磁盘控制器低级格式化时,还能指定在头部和尾部之间留下多长的数据区,通常选择256或512字节等。

2. 分区

在可以使用磁盘存储文件之前,操作系统还要将自己的数据结构记录到磁盘上,分为两步:第一步是,将磁盘分为由一个或多个柱面组成的分区(即我们熟悉的C盘、D盘等形式的分区),每个分区的起始扇区和大小都记录在磁盘主引导记录的分区表中;第二步是,对物理分区进行逻辑格式化(创建文件系统),操作系统将初始的文件系统数据结构存储到磁盘上,这些数据结构包括空闲时间和已分配的空间以及一个初始为空的目录。

因扇区的单位太小,为了提高效率,操作系统将多个相邻的扇区组合在一起,形成一簇(在Linux中称为块)。为了更高效地管理磁盘,一簇只能存放一个文件的内容,文件所占用的空间只能是簇的整数倍;如果文件大小小于一簇(甚至是0字节),也要占用一簇的空间。

3. 引导块

计算机启动时需要运行一个初始化程序(自举程序),它初始化CPU、寄存器、设备控制器和内存等,接着启动操作系统。为此,自举程序找到磁盘上的操作系统内核,将它加载到内存,并转到起始地址,从而开始操作系统的运行。

自举程序通常存放在 ROM 中,为了避免改变自举代码而需要改变ROM硬件的问题,通常只在 ROM 中保留很小的自举装入程序,而将完整功能的引导程序保存在磁盘的启动块上,启动块位于磁盘的固定位置。具有启动分区的磁盘称为启动磁盘或系统磁盘。

引导ROM中的代码指示磁盘控制器将引导块读入内存,然后开始执行,它可以从非固定的磁盘位置加载整个操作系统,并且开始运行操作系统。下面以Windows为例来分析引导过程。Windows允许将磁盘分为多个分区,有一个分区为引导分区,它引导包含操作系统和设备驱动程序。Windows系统将引导代码存储在1磁盘的第0号扇区,它称为主引导记录(MBR)。引导首先运行 ROM 中的代码,这个代码指示系统从 MBR 中读取引导代码。除了包含引导代码,MBR还包含:一个磁盘分区表和一个标志(以指示从哪个分区引导系统),如图 5.15 所示。当系统找到引导分区时,读取分区的第一个扇区,称为引导扇区,并继续余下的引导过程,包括加载各种系统服务。

14

4. 坏块

由于磁盘有移动部件且容错能力弱,因此容易导致一个或多个扇区损坏。部分磁盘甚至在出厂时就有坏块。根据所用的磁盘和控制器,对这些块有多种处理方式。

对于简单磁盘,如采用IDE控制器的磁盘,坏块可手动处理,如MS-DOS的Format命令执行逻辑格式化时会扫描磁盘以检查坏块。坏块在FAT表上会标明,因此程序不会使用它们。

对于复杂的磁盘,控制器维护磁盘内的坏块列表。这个列表在出厂低级格式化时就已初始化,并在磁盘的使用过程中不断更新。低级格式化将一些块保留作为备用,操作系统看不到这些块。控制器可以采用备用块来逻辑地替代坏块,这种方案称为扇区备用

对坏块的处理实质上就是用某种机制使系统不去使用坏块。

0x02 磁盘调度算法

一次磁盘读写操作的时间由寻找(寻道)时间、旋转延迟时间和传输时间决定。

  1. 寻找时间 Ts。活动头磁盘在读写信息前,将磁头移动到指定磁道所需要的时间。这个时间除跨越 n 条磁道的时间外,还包括启动磁臂的时间 s,即

    Ts=m×n+s

    式中,m是与磁盘驱动器速度有关的常数,约为0.2ms,磁臂的启动时间约为2ms。

  2. 旋转延迟时间 Tr。磁头定位到某一磁道的扇区所需要的时间,设磁盘的旋转速度为 r,则

    Tr=12r

    对于硬盘,典型的旋转速度为 5400 转/分,相当于一周11.1ms,.则T.为5.55ms;对于软盘,其旋转速度为 300~600 转/分, 则 T,为50~100ms。

  3. 传输时间 Tt。从磁盘读出或向磁盘写入数据所经历的时间,这个时间取决于每次所读/写的字节数b和磁盘的旋转速度:

    Tt=brN

    式中,r为磁盘每秒的转数,N为一个磁道上的字节数。

在磁盘存取时间的计算中,寻道时间与磁盘调度算法相关;而延迟时间和传输时间都与磁盘旋转速度相关,且为线性相关,所以在硬件上,转速是磁盘性能的一个非常重要的参数。

总平均存取时间 Ta。可以表示为

Ta=Ts+12r+brN

虽然这里给出了总平均存取时间的公式,但是这个平均值是没有太大实际意义的,因为在实际的磁盘 I/O 操作中,存取时间与磁盘调度算法密切相关。

目前常用的磁盘调度算法有以下几种。

1. 先来先服务(First Come First Served,FCFS)算法

FCFS算法根据进程请求访问磁盘的先后顺序进行调度,这是一种最简单的调度算法,如图5.16所示。该算法的优点是具有公平性。若只有少量进程需要访问,且大部分请求都是访问簇聚的文件扇区,则有望达到较好的性能:若有大量进程竞争使用磁盘,则这种算法在性能上往往接近于随机调度。所以,实际磁盘调度中会考虑一些更为复杂的调度算法

15

例如,磁盘请求队列中的请求顺序分别为 55, 58, 39, 18, 90, 160, 150, 38, 184,磁头的初始位置是磁道100,采用FCFS算法时磁头的运动过程如图5.16所示。磁头共移动了 (45+3+19+21+72+70+10+ 112+146)=498 个磁道,平均寻找长度= 498/9=55.3。

2. 最短寻找时间优先(Shortest Seek Time First,SSTF)算法

SSTF算法选择调度处理的磁道是与当前磁头所在磁道距离最近的磁道,以便使每次的寻找时间最短。当然,总是选择最小寻找时间并不能保证平均寻找时间最小,但能提供比FCFS算法更好的性能。这种算法会产生“饥饿”现象。如图5.17所示,.若某时刻磁头正在18号磁道,而在18号磁道附近频繁地增加新的请求,则 SSTF 算法使得磁头长时间在18号磁道附近工作,将使184号磁道的访问被无限期地延迟,即被“饿死”。

16

例如,磁盘请求队列中的请求顺序分别为 55, 58, 39, 18, 90, 160, 150, 38, 184,磁头初始位置是磁道100,采用SSTF算法时磁头的运动过程如图5.17所示。磁头共移动了10+32+3+16+1+20+132+10+24=248个磁道,平均寻找长度=248/9=27.5。

3. 扫描(SCAN)算法(又称电梯调度算法)

SCAN算法在磁头当前移动方向上选择与当前磁头所在磁道距离最近的请求作为下一次服务的对象,实际上就是在最短寻找时间优先算法的基础上规定了磁头运动的方向,如图5.18所示。由于磁头移动规律与电梯运行相似,因此又称电梯调度算法。SCAN算法对最近扫描过的区域不公平,因此它在访问局部性方面不如FCFS 算法和SSTF算法好。

18

例如,磁盘请求队列中的请求顺序分别为 55, 58, 39, 18, 90, 160, 150, 38, 184,磁头初始位置是磁道 100。采用SCAN算法时,不但要知道磁头的当前位置,而且要知道磁头的移动方向,假设磁头沿磁道号增大的顺序移动,则磁头的运动过程如图5.18所示。移动磁道的顺序为100,150,160,184,200,90,58,55,39,38, 18。 磁头共移动了(50 + 10 + 24 + 16 + 110 + 32 + 3 + 16 + 1 + 20) =282个磁道,平均寻道长度:=282/9=31.33。

4. 循环扫描(Circular SCAN,C-SCAN)算法

在扫描算法的基础上规定磁头单向移动来提供服务,回返时直接快速移动至起始端而不服务任何请求。由于SCAN算法偏向于处理那些接近最里或最外的磁道的访问请求,所以使用改进型的 C-SCAN 算法来避免这个问题,如图 5.19 所示。

19

采用 SCAN算法和C-SCAN算法时,磁头总是严格地遵循从盘面的一端到另一端,显然,在实际使用时还可以改进,即磁头移动只需要到达最远端的一个请求即可返回,不需要到达磁盘端点。这种形式的 SCAN 算法和 C-SCAN 算法称为 LOOK 调度(见图 5.20)和 C-LOOK(见图 5.21)调度,因为它们在朝一个给定方向移动前会查看是否有请求。

20

注意,若无特别说明,也可以默认 SCAN 算法和 C-SCAN算法为 LOOK 和 C-LOOK调度(请读者认真领悟,并通过结合后面的习题进一步加深对以上相关算法的理解)。

例如,磁盘请求队列中的请求顺序为 55, 58, 39, 18, 90, 160, 150, 38, 184,磁头初始位置是磁道100。采用C-SCAN算法时,假设磁头沿磁道号增大的顺序移动,则磁头的运动过程如图5.19所示。移动磁道的顺序为 100,150,160,184,200,0,18,38,39,55,58,90。 磁头共移动 50 + 10 + 24 + 16 +200+18+ 20+1+16+3+32= 390个磁道,平均寻道长度= 390/9=43.33。

对比以上几种磁盘调度算法,FCFS算法太过简单,性能较差,仅在请求队列长度接近于1时才较为理想;SSTF算法较为通用和自然:SCAN·算法和C-SCAN算法在磁盘负载较大时比较占优势。它们之间的比较见下表。

 优点缺点
FCFS 算法公平、简单平均寻道距离大,仅应用在磁盘I/O较少的场合
SSTF 算法性能比“先来先服务”好能保证平均寻道时间最短,可能出现“饥饿”现象
SCAN 算法寻道性能较好,可避免“饥饿”现象不利于远离磁头一端的访问请求
C-SCAN 算法消除了对两端磁道请求的不公平 

除减少寻找时间外,减少延迟时间也是提高磁盘传输效率的重要因素。可以对盘面扇区进行交替编号,对磁盘片组中的不同盘面错位命名。假设每个盘面有8个扇区,磁盘片组共8个盘面,则可以采用如图5.22所示的编号。

磁盘是连续自转设备,磁头读/写一个物理块后,需要经过短暂的处理时间才能开始读/写下一块。假设逻辑记录数据连续存放在磁盘空间中,若在盘面上按扇区交替编号连续存放,则连续读/写多条记录时能减少磁头的延迟时间;同柱面不同盘面的扇区若能错位编号,连续读/写相邻两个盘面的逻辑记录时也能减少磁头延迟时间。

以图5.22为例,在随机扇区访问情况下,定位磁道中的一个扇区平均需要转过4个扇区,这时,延迟时间是传输时间的4倍,这是一种非常低效的方式。理想的情况是不需要定位而直接连续读取扇区,没有延迟时间,这样磁盘数据存取效率可以成倍提高。但由于读取扇区的顺序是不可预测的,所以延迟时间不可避免。图5.22中的编号方式是读取连续编号扇区时的一种方法。

22

磁盘寻块时间分为三个部分,即寻道时间、延迟时间和传输时间,寻道时间和延迟时间属于“找”的时间,凡是“找”的时间都可以通过一定的方法削减,但传输时间是磁盘本身性质所决定的,不能通过一定的措施减少。

0x03 固态硬盘

1. 固态硬盘的特性

固态硬盘(SSD)是一种基于闪存技术的存储器。它与U盘并无本质差别,只是容量更大,存取性能更好。一个 SSD 由一个或多个闪存芯片和闪存翻译层组成,如图5.23 所示。闪存芯片替代传统旋转磁盘中的机械驱动器,而闪存翻译层将来自CPU的逻辑块读写请求翻译成对底层物理设备的读写控制信号,因此闪存翻译层相当于扮演了磁盘控制器的角色。

23

在图 5.23 中,一个闪存由 B 块组成,每块由P页组成。通常,页的大小是 512B~4KB,每块由 32~128页组成,块的大小为16KB~512KB。数据是以页为单位读写的。只有在一页所属的块整个被擦除后,才能写这一页。不过,一旦擦除一块,块中的每页就都可以直接再写一次。某块进行若干次重复写后,就会磨损坏,不能再使用。

随机写很慢,有两个原因。首先,擦除块比较慢,通常比访问页高一个数量级。其次,如果写操作试图修改包含已有数据的页 Pi ;那么这个块中所有含有用数据的页都必须被复制到一个新(擦除过的)块中,然后才能进行对页 Pi 的写操作。

比起传统磁盘,SSD有很多优点,它由半导体存储器构成,没有移动的部件,因而随机访问速度比机械磁盘要快很多,也没有任何机械噪声和震动,能耗更低、抗震性好、安全性高等。

随着技术的不断发展,价格也不断下降,SSD会有望逐步取代传统机械硬盘。

2. 磨损均衡(Wear Leveling)

固态硬盘也有缺点,闪存的擦写寿命是有限的,一般是几百次到几千次。如果直接用普通闪存组装 SSD,那么实际的寿命表现可能非常令人失望一一读写数据时会集中在 SSD 的一部分闪存,这部分闪存的寿命会损耗得特别快。一旦这部分闪存损坏,整块 SSD 也就损坏了。这种磨损不均衡的情况,可能会导致一块 256GB 的 SSD,只因数兆空间的闪存损坏而整块损坏。

为了弥补 SSD 的寿命缺陷,引入了磨损均衡。SSD 磨损均衡技术大致分为两种:

  1. 动态磨损均衡。写入数据时,自动选择较新的闪存块。老的闪存块先歇一歇。
  2. 静态磨损均衡。这种技术更为先进,就算没有数据写入,SSD也会监测并自动进行数据分配,让老的闪存块承担无须写数据的存储任务,同时让较新的闪存块腾出空间,平常的读写操作在较新的闪存块中进行。如此一来,各闪存块的寿命损耗就都差不多。

有了这种算法加持,SSD 的寿命就比较可观了。例如,对于一个 256GB 的 SSD,如果闪存的擦写寿命是500次,那么就需要写入125TB 数据,才寿终正寝。就算每天写入10GB 数据,也要三十多年才能将闪存磨损坏,更何况很少有人每天往 SSD 中写入10GB数据。

四、本章疑难点

0x00 设备分配

  1. 分配设备。首先根据IO请求中的物理设备名查找系统设备表(SDT),从中找出该设备的 DCT,再根据 DCT 中的设备状态字段,可知该设备是否正忙。若忙,便将请求IO 进程的PCB 挂到设备队列上;若空闲,则按照一定的算法计算设备分配的安全性,若安全则将设备分配给请求进程,否则仍将其PCB挂到设备队列上。
  2. 分配控制器。系统把设备分配给请求I/O 的进程后,再到其 DCT 中找出与该设备连接的控制器的 COCT,从 COCT 中的状态字段中可知该控制器是否忙碌。若忙,则将请求 V/O进程的 PCB 挂到该控制器的等待队列上;若空闲,则将控制器分配给进程。
  3. 分配通道。在该COCT 中又可找到与该控制器连接的通道的 CHCT,再根据 CHCT 内的状态信息,可知该通道是否忙碌。若忙,则将请求I/O的进程挂到该通道的等待队列上;若空闲,则将该通道分配给进程。只有在上述三者都分配成功时,这次设备的分配才算成功。然后,便可启动该 I/O 设备进行数据传送。

为使独占设备的分配具有更强的灵活性,提高分配的成功率,还可从以下两方面对基本的设备分配程序加以改进:

  1. 增加设备的独立性。进程使用逻辑设备名请求 I/O。这样,系统首先从 SDT 中找出第一个该类设备的 DCT。若该设备忙,则又查找第二个该类设备的 DCT。仅当所有该类设备都忙时,才把进程挂到该类设备的等待队列上;只要有一个该类设备可用,系统便进一步计算分配该设备的安全性。
  2. 考虑多通路情况。为防止I/O系统的“瓶颈”现象,通常采用多通路的I/O系统结构。此时对控制器和通道的分配同样要经过几次反复,即若设备(控制器)所连接的第一个控制器(通道)忙时,则应查看其所连接的第二个控制器(通道),仅当所有控制器(通道)都忙时,此次的控制器(通道)分配才算失败,才把进程挂到控制器(通道)的等待队列上。而只要有一个控制器(通道)可用,系统便可将它分配给进程。

设备分配过程中,先后分别访问的数据结构为 SDT→DCT→COCT→CHCT。要成功分配一个设备,必须要:①设备可用;②控制器可用;③通道可用。所以,“设备分配,要过三关”。

0x01 提高磁盘 I/O 速度的方法

  1. 提前读。在读磁盘当前块时,把下一磁盘块也读入内存缓冲区。
  2. 延迟写。仅在缓冲区首部设置延迟写标志,然后释放此缓冲区并将其链入空闲缓冲区链表的尾部,当其他进程申请到此缓冲区时,才真正把缓冲区信息写入磁盘块。
  3. 虚拟盘。是指用内存空间去仿真磁盘,又叫RAM盘。虚拟盘是一种易失性存储器。虚拟盘常用于存放临时文件。