操作系统(五)文件系统和I/O系统

前言

本文主要涉及操作系统的简介、硬件结构、内存管理、进程管理、文件系统、设备管理等内容,可以作为学习操作系统的辅助文本记录。撰写本文的目的主要是针对操作系统整体做一个相对完整的梳理,以便后续回顾之用。
本文是第五篇,讲述操作系统的文件系统和I/O系统。
第一篇:操作系统(一)基础知识及操作系统启动
第二篇:操作系统(二)内存管理的基础知识
第三篇:操作系统(三)进程和线程的基础知识
第四篇:操作系统(四)进程和线程的调度算法、同步互斥、通信、死锁等

文件系统

文件系统和文件

文件系统:操作系统中管理持久性数据的子系统,提供数据存储和访问功能

  1. 组织、检索、读写访问数据
  2. 大多数计算机系统都有文件系统
  3. Google也是一个文件系统

文件:具有符号名,由字节序列构成的数据项集合

文件系统的功能:

  1. 分配文件磁盘空间

    管理文件块(位置和顺序)

    管理空闲空间(位置)

    分配算法(策略)

  2. 管理文件集合

    定位:文件及其内容

    命名:通过名字找到文件

    文件系统结构:文件组织方式

  3. 数据可靠和安全

    安全:多层次保护数据安全

    可靠:持久保存文件;避免系统泵快、媒体错误、攻击等

文件属性:

  1. 名称、类型、位置、大小……

  2. 文件头:文件系统元数据中的文件信息

    文件属性

    文件存储位置和顺序

文件描述符

  • 文件描述符:操作系统在打开文件表中维护的打开文件状态和信息
    • 文件指针:最近一次读写位置;每个进程分别维护自己的 打开文件指针
    • 文件打开计数:当前文件打开的次数;最后一个打开该文件的进程关闭文件时,就可以将其从文件表中去除了。
    • 文件在磁盘上位置:缓存数据访问信息
    • 访问权限:每个进程的文件访问模式信息
  • 文件的用户视图
    • 持久的数据结构
  • 系统访问接口
    • 字节序列的集合(UNIX)
    • 系统不关心存储磁盘上的数据结构
  • 操作系统的文件视图
    • 数据块的集合
    • 数据块是逻辑存储单元,而扇区是物理存储单元
  • 进程读文件
    • 获取字节所在的数据块
    • 返回数据块内对应部分
  • 进程写文件
    • 获取数据块
    • 修改数据块中对应部分
    • 写回数据块
  • 文件系统中的基本操作单位是数据块
  • 访问模式:
    • 顺序访问:按字节依次读取
    • 随机访问:从中间读写
    • 索引访问:依据数据特征索引
  • 文件内部结构
    • 无结构:字节序列
    • 简单记录结构:分列、固定长度、可变长度等
    • 复杂结构:可执行文件、PDF等
  • 文件共享和访问控制
    • 多用户系统的文件共享是很必要的
    • 访问控制:每个用户能够获得哪些文件的哪些访问权限
      • 访问模式:读、写、执行等

目录、文件别名和文件系统

分层文件系统
  • 文件是以目录的方式组织起来

  • 目录是一类特殊的文件

    目录的内容是文件的索引表<文件名,指向文件的指针>

  • 目录和文件的树形结构

    早期的文件系统是扁平的(只有一层目录)

  • 典型目录操作

    搜索文件、创建文件、删除文件、列目录、重命名文件、遍历路径

  • 操作系统应该只允许内核修改目录

    确保映射的完整性

    如果用户希望修改目录,只能通过系统调用访问目录

目录实现
  • 文件名的线性列表,包含指向数据块的指针

    编程简单,但执行耗时

  • 哈希表,哈希数据结构的线性表

    减少目录搜索时间

文件别名
  • 两个或多个文件名关联同一个文件
  • 实现:
    • **硬链接:**多个文件项指向一个文件(硬链接不可以跨系统,只有删除文件的所有硬链接和源文件时,系统才会彻底删除该文件。)
    • **软链接:**以“快捷方式”指向其他文件,通过存储真实文件的逻辑名称来实现。(软链接相当于重新创建一个文件,该文件的内容是另一个文件的路径,所以访问软链接的时候,相当于访问到了另外一个文件,所以软链接是可以跨文件系统的,甚至目标文件被删除了,链接文件都还在,只不过指向的文件找不到了。)
名字解析(路径遍历)

名字解析:把逻辑名字转换为物理资源(如文件)

  1. 依据路径名,在文件系统中找到实际文件位置
  2. 遍历文件目录直到找到目标文件
  • 举例:解析“/bin/ls”

    • 读取根目录的文件头(在磁盘固定位置)
    • 读取根目录的数据块,搜索“bin"项
    • 读取bin的文件头
    • 读取bin的数据块;搜索“ls”项
    • 读取ls的文件头
  • 当前工作目录(PWD)

    • 每个进程都会指向一个缺省的文件目录用于解析文件名

    • 允许用户指定相对路径来代替绝对路径

      如, 用PWD = "/bin"能够解析“ls”.

文件系统挂载
  • 文件系统必须先挂载才能被访问;
  • 没有挂载的文件系统被挂载在挂载点上
文件系统种类
  • 磁盘文件系统
    • 文件存储在数据存储设备上,如磁盘;
    • 例如:FAT,NTFS, ext2/3,ISO9660等
  • 数据库文件系统
    • 文件特征是可以被寻址(辨识)的
    • 如WinFS
  • 日志文件系统
    • 记录文件系统的修改/事件
  • 网络/分布式文件系统
    • NFS,SMB,AFS,GFS等
  • 特殊/虚拟文件系统

虚拟文件系统

是为了面对多种文件系统,但是希望提供一个统一的文件访问和文件控制的接口

  • 分层结构
    • 虚拟(逻辑)文件系统(VFS, Virtual File System)
    • 特定文件系统模块

  • 功能
    • 提供相同的文件和文件系统接口
    • 管理所有文件和文件系统关联的数据结构
    • 高效查询例程,遍历文件系统
    • 与特定文件系统模块的交互
  • 基本数据结构
    • 文件卷控制块(Unix: “Superblock”)
      • 每个文件系统一个
      • 文件系统详细信息
      • 块、块大小、空余块、计数\指针等
    • 文件控制块(Unix: “vnode” or “inode”)
      • 每个文件一个
      • 文件详细信息
      • 访问权限、拥有者、大小、数据块位置等
    • 目录项(Linux: “dentry”)
      • 每个目录项一个(目录和文件)
      • 将目录项数据结构及树型布局编码成树型数据结构
      • 指向文件控制块、父目录、子目录等

文件缓存和打开文件

打开文件
  • 文件描述符:每个打开的文件都有一个文件描述符
  • 文件描述信息:目录项、当前文件指针、文件操作设置等
  • 打开文件表:
    • 每个进程都有一个进程打开文件表;
    • 有一个系统级的打开文件表
    • 有文件被打开时,文件卷就不能被卸载
  • 打开文件锁
    • 一些文件系统提供文件锁,用于协调多进程的文件访问
    • 强制:根据锁保持情况和访问需求确定 是否拒绝访问
    • **劝告:**进程可以查找锁的状态来决定怎么做

文件分配

  • 文件大小

    • 大多数文件都很小
      • 需要对小文件提供很好的支持
      • 块空间不能太大
    • 一些文件非常大
      • 必须支持大文件
      • 大文件访问需要高效
  • 文件分配:如何表示分配给一个文件数据块的位置和顺序

  • 分配方式:连续分配、链式分配、索引分配

  • 指标:

    存储效率:外部碎片等

    读写性能:访问速度等

  1. 连续分配
  • 优点:文件读取表现好,高效的顺序和随机访问
  • 缺点:碎片和文件增长问题,文件增加怎么办?预先多分配?还是整体迁移?
  1. 链式分配
  • 优点:创建、增加、缩小很容易;没有碎片
  • 缺点:无法实现真正的随机访问,可靠性差,破坏一个指针,后面的数据都丢失了
  1. 索引分配
  • 为每一个文件创建一个索引数据块,里面包含了指向文件数据块的指针列表
  • 优点:创建、增大、缩小很容易,没有碎片;支持直接访问
  • 缺点:文件很小时,索引开销相对大;大文件的表示怎么办?可能一个索引块不够用
  1. 大文件的索引分配
  • 链式索引块
  • 多级索引块
  1. 实际的UFS多级索引分配
  • 数据少的时候,直接对应数据块;

  • 数据大的话,增加索引块,一级索引,二级索引,……

  • 效果:

    提高了文件大小限制阈值;

    动态分配数据块,文件扩展很容易

    小文件开销小;

    为大文件间接分配数据块,但查询速度会有所下降

空闲空间管理和冗余磁盘阵列RAID

空闲空间管理
  • 跟踪记录文件卷中未分配的数据块
  1. 位图
  • 用位图代表空闲数据块列表,0为空闲,1为已分配

  • 使用简单但可能会是一个很大的向量表

    160GB—40M数据块–5MB位图

    查找空闲块的时间长

  1. 链表

  2. 链式索引

冗余磁盘阵列RAID(Redundant Array of Indexpensive Disks)

文件卷:一个拥有完整文件系统实例的外存空间通常常驻在磁盘的单个分区上

冗余磁盘阵列是磁盘管理技术

实现:

  • 软件:操作系统内核的文件卷管理
  • 硬件:RAID硬件控制器(I/O)
  1. RAID-0:磁盘条带化

把数据块分成多个子块,存储在独立的磁盘中

通过独立磁盘上并行数据块访问提供更大的磁盘带宽

  1. RAID-1: 磁盘镜像

向两个磁盘写入,从任何一个读取

可靠性成倍增长;读取性能 线性增加

  1. RAID-4:带校验的磁盘条带化

数据块级的磁盘条带化加专用奇偶校验磁盘;允许从任意一个故障磁盘中恢复

  1. RAID-5: 带分布式校验的磁盘条带化

校验和分散,降低校验和磁盘的读写压力

  1. RAID嵌套

上面的几种组合使用,如RAID0+1,并行并且可靠性增加

I/O系统

  1. 字符设备: 键盘/鼠标、串口等

    访问特征:以字节为单位顺序访问

  2. **块设备:**磁盘驱动器,磁带驱动器,光驱等

    访问特征:以数据块为基本访问单位,数据访问均匀

  3. **网络设备:**以太网、无线、蓝牙等

    访问特征:格式化报文交换,比较复杂

同步与异步I/O

  1. 阻塞I/O:wait要等待;‘
  • 读数据(read)时,进程将进入等待状态,直到完成数据读出;
  • 写数据(write)时,进程将进入等待状态,直到设备完成数据写入;
  1. 非阻塞I/O:Don’t wait不等待;
  • 立即从read/write系统调用中返回,返回值为成功传输的字节数;
  • read/write的传输字节数可能为0;
  1. 异步I/O:Tell me Later
  • 读数据时,使用指针标记好用户缓冲区,立即返回,稍后内核将填充缓冲区并通知用户;
  • 写数据时,使用指针标记好用户缓冲区,立即返回;稍后内核将处理数据并通知用户;

I/O结构

I/O控制方式

每种设备都有一个设备控制器,控制器相当于一个小 CPU,它可以自己处理一些事情,当 CPU 给设备发送了一个指令,让设备控制器去读设备的数据,读完如何通知CPU?

  1. 轮询等待

    控制器的寄存器一般会有状态标记位,用来标识输入或输出操作是否完成,,让 CPU 一直查寄存器的状态,直到状态标记为完成。显然CPU浪费了相当多时间。

  2. 中断

    设备完成任务后触发中断到中断控制器,中断控制器就通知 CPU,一个中断产生了,CPU 需要停下当前手里的事情来处理中断。

  3. DMA(Direct Memory Access

    中断的方式对于频繁读写数据的磁盘,并不友好,这样 CPU 容易经常被打断,会占用 CPU 大量的时间。DMA可以使得设备在 CPU 不参与的情况下,能够自行完成把设备 I/O 数据放入到内存。那要实现 DMA 功能要有 「DMA 控制器」硬件的支持。

Q: DMA是什么?

A: DMA(Direct Memory Access,直接内存存取)是计算机系统中一种用于高效地进行数据传输的技术。DMA允许外部设备(如硬盘驱动器、网络适配器等)直接和系统内存进行数据传输,而无需通过中央处理器(CPU)的干预,从而提高了系统的整体性能和效率。

在没有使用DMA的情况下,数据传输通常需要通过CPU来完成,这意味着CPU必须参与每一个数据传输操作,即使这些操作与CPU的主要任务无关。这样会占用CPU的时间和资源,并降低系统的整体性能。

而有了DMA技术,外部设备可以直接和系统内存进行数据传输,而无需CPU的直接参与。DMA控制器负责管理数据的传输过程,它可以独立地访问系统内存,读取或写入数据,而无需CPU的干预。这样一来,CPU就可以专注于执行其他任务,从而提高了系统的并发性和整体性能。

DMA 的工作方式如下:

  • CPU 需对 DMA 控制器下发指令,告诉它想读取多少数据,读完的数据放在内存的某个地方就可以了;
  • 接下来,DMA 控制器会向磁盘控制器发出指令,通知它从磁盘读数据到其内部的缓冲区中,接着磁盘控制器将缓冲区的数据传输到内存;
  • 当磁盘控制器把数据传输到内存的操作完成后,磁盘控制器在总线上发出一个确认成功的信号到 DMA 控制器;
  • DMA 控制器收到信号后,DMA 控制器发中断通知 CPU 指令完成,CPU 就可以直接用内存里面现成的数据了;

可以看到, CPU 当要读取磁盘数据的时候,只需给 DMA 控制器发送指令,然后返回去做其他事情,当磁盘数据拷贝到内存后,DMA 控制机器通过中断的方式,告诉 CPU 数据已经准备好了,可以从内存读数据了。仅仅在传送开始和结束时需要 CPU 干预

I/O数据传输

  • 程序控制I/O(PIO, Programmed I/O)
    • 通过CPU的in/out或者load/store传输所有数据
    • 特点:硬件简单、编程容易;消耗的CPU时间和数据量成正比
    • 适用于简单的、小型的设备I/O
  • 直接内存访问(DMA)
    • 设备控制器可以直接访问系统总线
    • 控制器直接与内存互相传输数据
    • 特点:设备传输数据不影响CPU; 需要CPU参与设置
    • 适用于高吞吐量I/O

操作系统需要了解设备状态

  • I/O操作完成时间

  • I/O操作遇到错误

  • 两种方式:轮询和设备中断

  1. 轮询
  • I/O设备在特定的状态寄存器中放置状态和错误信息
  • 操作系统定期检测状态寄存器
  • 特点:
    • 简单
    • I/O操作频繁或不可预测时,开销大和延时长
  1. 设备中断
  • CPU在I/O之前设置任务参数
  • CPU发出I/O请求后,继续执行其他任务;
  • I/O设备处理I/O请求
  • I/O设备处理完成后,出发CPU中断请求
  • CPU接收中断,分发到相应中断处理例程
  • 特点:
    • 处理不可预测事件效果好
    • 开销相对较高
  1. 一些设备可能结合了轮询和设备中断
  • 高宽带网络设备(数据多,量大)
    • 第一个传入数据包到达前采用中断
    • 轮询后面的数据包直到硬件缓存为空

磁盘调度

磁盘工作机制

  1. 读取或写入时,磁头必须被定位在期望的磁道,并从所期望的柱面和扇区开始
  2. 寻道时间:定位到期望的磁道所花费的事件
  3. 旋转延迟:从零扇区开始处到达目的地所花费的时间

平均旋转延迟时间=磁盘旋转一周时间的一半

磁盘调度算法:

  1. 寻道时间是磁盘访问最耗时的部分;
  2. 同时会有多个在同一磁盘上的I/O请求;
  3. 随机处理磁盘访问请求的性能表现很差
1. 先进先出FIFO算法

先来先服务(First-Come,First-Served,FCFS),顾名思义,先到来的请求,先被服务。这种算法,比较简单粗暴,但是如果大量进程竞争使用磁盘,请求访问的磁道可能会很分散,那先来先服务算法在性能上就会显得很差,因为寻道时间过长。

2. 最短服务时间优先(SSTF)

最短寻道时间优先(Shortest Seek First,SSF)算法的工作方式是,优先选择从当前磁头位置所需寻道时间最短的请求。

98,183,37,122,14,124,65,67

那么,那么根据距离磁头( 53 位置)最近的请求的算法,具体的请求则会是下列从左到右的顺序:

65,67,37,14,98,122,124,183

这个算法可能存在某些请求的饥饿,因为本次例子我们是静态的序列,看不出问题,假设是一个动态的请求,如果后续来的请求都是小于 183 磁道的,那么 183 磁道可能永远不会被响应,于是就产生了饥饿现象,这里产生饥饿的原因是磁头在一小块区域来回移动

3. 扫描算法(SCAN)(电梯算法)

磁头在一个方向上移动,访问所有未完成的请求,直到磁头到达该方向上的最后的磁道,才调换方向,这就是扫描(Scan)算法

扫描调度算法性能较好,不会产生饥饿现象,但是存在这样的问题,中间部分的磁道会比较占便宜,中间部分相比其他部分响应的频率会比较多,也就是说每个磁道的响应频率存在差异。

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

循环扫描(Circular Scan, CSCAN )规定:只有磁头朝某个特定方向移动时,才处理磁道访问请求,而返回时直接快速移动至最靠边缘的磁道,也就是复位磁头,这个过程是很快的,并且返回中途不处理任何请求,该算法的特点,就是磁道只响应一个方向上的请求

循环扫描算法相比于扫描算法,对于各个位置磁道响应频率相对比较平均.

5. LOOK与C-LOOK算法

针对 SCAN 算法的优化则叫 LOOK 算法,它的工作方式,磁头在每个方向上仅仅移动到最远的请求位置,然后立即反向移动,而不需要移动到磁盘的最始端或最末端,反向移动的途中会响应请求

针对 C-SCAN 算法的优化则叫 C-LOOK,它的工作方式,磁头在每个方向上仅仅移动到最远的请求位置,然后立即反向移动,而不需要移动到磁盘的最始端或最末端,反向移动的途中不会响应请求

6. N步扫描(N-step-SCAN)算法
  • 磁盘粘着(Arm Stickiness)现象

    SSTF、SCAN以及CSCAN等算法中,可能出现磁头停留在某处不动的情况(因为一直在响应附近的请求)

  • N步扫描算法:

    1. 将磁盘请求队列分成长度为N的子队列
    2. 按照FIFO算法依次处理所有子队列
    3. 按照扫描算法处理每个子队列
7. 双队列扫描算法(FSCAN)算法
  • FSCAN算法是N步扫描算法的简化,只是将磁盘请求队列分成两个子队列
  • 将磁盘I/O请求分成两个子队列
  • 交替使用扫描算法处理一个队列
  • 新生成的磁盘I/O请求放入另一队列中,所有的新请求都被推迟到下一次扫描时处理

磁盘缓存

缓存:数据传输双方访问速度差异较大时,引入的速度匹配中间层

磁盘缓存是磁盘扇区在内存中的缓存区

  • 磁盘缓存的调度算法很类似虚拟存储调度算法
  • 磁盘的访问频率远远低于虚拟存储的内存访问频率

单缓存(single Buffer Cache)

双缓存(Double Buffer Cache)

小结

本节主要操作系统的进程和线程的调度算法、同步互斥、通信、死锁等。
本主要文参考:

  1. 《操作系统》–清华大学网课
  2. 小林coding

如果您觉得我写的不错,麻烦给我一个免费的赞!如果内容中有错误,也欢迎向我反馈。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值