第二部分: 虚拟文件系统
1.分层结果
2.上层: 虚拟文件系统
底层: 特定文件系统模块
虚拟文件系统的目标
目的: 对所有不同文件系统的抽象
功能:
- 提供相同的文件和文件系统接口
- 管理所有文件和文件系统关联的数据结构
- 高效查询例程,遍历文件系统
- 与特定文件系统模块的交互
数据结构:
1.卷[第四声]控制块(UNIX: “superblock”)
- 每个文件系统一个
- 文件系统详细信息
- 块,块大小,空余块,计数,指针等
1.文件控制块(UNIX: “vnode” or “inode”)
- 每个文件一个
- 文件详细信息
- 许可,拥有者,大小,数据库位置等
1.目录节点(Linux: “dentry”)
- 每个目录项一个(目录和文件)
- 将目录项数据结构及树形布局编码成树形数据结构
- 指向文件控制块,父节点,项目列表等
文件系统数据结构 :
- 卷控制块(每个文件系统一个)
- 文件控制块(每个文件一个)
- 目录节点(每个目录项一个)
持续存储在二级存储中:
在分配在存储设备中的数据块中
当需要时加载进内存:
- 卷控制块: 当文件系统挂载时进入内存
- 文件控制块: 当文件被访问时进入内存
- 目录节点: 在遍历一个文件路径时进入内存
数据块缓存
各种缓存方式
1.数据块按需读入内存:
- 提供 read() 操作
- 预读: 预先读取后面的数据块
1.数据块使用后被缓存:
- 假设数据将会再次被使用
- 写操作可能被缓存和延迟写入
1.两种数据块缓存方式:
- 普通缓冲区缓存
- 页缓存: 同一缓存数据块和内存页
分页要求: 当需要一个页时才将其载入内存
支持存储: 一个页(在虚拟地址空间中)可以被映射到一个本地文件中(在二级存储中)
文件数据块的页缓存
- 在虚拟内存中文件数据块被映射成页
- 文件的读写操作被转换成对内存的访问
- 可能导致缺页和/或设置为脏页
- 问题: 页置换 – 从进程或文件页缓存中 ?
打开文件的数据结构
我们都知道打开文件我们就可以对文件进行读写, 但是打开文件时操作系统干了那些事情就是这次需要学习的.
1.打开文件描述:
- 每个被打开的文件一个
- 文件状态信息
- 目录项,当前文件指针,文件操作设置等
1.打开文件表:
- 一个进程一个
- 一个系统级的
- 每个卷控制块也会保存一个列表
- 所以如果有文件被打开将不能被卸载
- 一些操作系统和文件系统提供该功能
- 调节对文件的访问
- 强制和劝告:
强制 - 根据锁保持情况和需求拒绝访问
劝告 - 进程可以查找锁的状态来决定怎么做
文件分配
打开文件后我们需要对文件进行相关的操作, 这些操作的背后是操作系统对内存/文件等的分配数据块
如何分配数据块
分配方式:
- 连续分配
- 链式分配
- 索引分配
指标:
- 高效: 如存储利用(外部碎片)
- 表现: 如访问速度
一、方式一:连续分配:
只需要知道 文件头指定起始块和长度
位置/分配策略: 最先匹配,最佳匹配,…
优势: 文件读取表现好;高效的顺序和随机访问
缺点: 碎片;文件增长问题
类似数组的形式。
二、方式二:链式分配:
文件以数据块链表方式存储
文件头包含了到第一块和最后一块的指针
优势: 创建,增大,缩小很容易;没有碎片
劣势: 不可能进行真正的随机访问;可靠性
三、索引分配:
为每个文件创建一个名为索引数据块的非数据数据块(到文件数据块的指针列表)
文件头包含了索引数据块
优势: 创建,增大,缩小很容易;没有碎片;支持直接访问
劣势: 当文件很小时,存储索引的开销大;处理大文件难
两种索引:
早期Unix阶段的文件索引块:
可以看出如果文件容量小的很容易就能找到, 但是对于大容量的文件就非常麻烦, 对于性能及其数据块的开销等等都是有着很大的影响。
空闲空间列表
站在磁盘的角度, 我们需要对文件进行分配空闲空间块, 对于空闲空间块一定是从空闲的磁盘块中来的。 但是空闲的磁盘块他不是属于文件的,与此同时他还需要被文件系统管理起来(类比我不是你们公司的人, 但是我需要和你们公司合作, 所以需要遵守贵公司的规定,,., )
操作系统需要有效并且快速的将这些空闲的空间组织起来供文件系统去查找 及其分配等等 ,这些都是我们操作系统的文件系统需要去解决的问题。
管理空闲空间块的使用程度:
1.用位图代表空闲数据块列表:
11111101101110111
如果 i = 0表明数据块i 是空闲的, 反之是分配的
1.使用简单但是可能会是一个big vector:
- 例如: 160GB disk →(有40MB的空闲块) 40M blocks → 5MB worth of bits(需要5MB来表示160GB磁盘的空闲情况)
- 然而,如果空闲空间在磁盘中均匀分布,那么再找到”0”之前需要扫描 磁盘上数据块总数 (n)/ 空闲块的数目(r)
1.这个管理空闲空间的数据块空间 是需要保护:
- 指向空闲列表的指针
- 位图:
必须保存在磁盘上;
在内存和磁盘拷贝可能有所不同;
不允许block[i]在内存中的状态为bit[i]=1而在磁盘中bit[i]=0
解决:
在磁盘上设置bit[i] = 1;
分配block[i];
在内存中设置bit[i] = 1
多磁盘管理 -RAID
通常磁盘通过分区来最大限度减小寻道时间:
- 一个分区是一个柱面的集合
- 每个分区都是逻辑上独立的磁盘
分区: 硬件磁盘的一种适合操作系统指定格式的划分
卷: 一个拥有一个文件系统实例的可访问的存储空间
(通常常驻在磁盘的单个分区上)
提高磁盘数据可靠性及其性能
- 使用多个并行磁盘来增加: 吞吐量(通过并行),可靠性和可用性(通过冗余)
- RAID - 冗余磁盘阵列:
各种磁盘管理技术;RAID levels: 不同RAID分类,
如RAID-0,RAID-1,RAID-5
实现:
在操作系统内核: 存储,卷管理; RAID硬件控制器(IO)
为什么我们可以通过RAID来提高磁盘效率呢?
答 :我们将数据放在相对独立的硬盘里面, 每个硬盘可以相对独立的并行工作。 这样就可以实现数据并行的访问。
一、RAID-0
数据块分成多个子块, 存储在独立的磁盘中: 和内存交叉相似
通过更大的有效块大小来提供更大的磁盘带宽
二、RAID-1
可靠性成倍增长
读取性能线性增加(向两个磁盘写入,从任何一个读取)
三、RAID-4
数据块级磁带配有专用奇偶校验磁盘: 允许从任意一个故障磁盘中恢复
条带化和奇偶校验按byte-by-byte或者bit-by-bit: RAID-0,4,5: block-wise ;RAID-3: bit-wise
四、RAID-5
每个条带快有一个奇偶校验块,允许有一个磁盘错误
五、RAID-6
两个冗余块,有一种特殊的编码方式,允许两个磁盘错误
磁盘调度
磁盘性能优化的另一个层面(一个是RAID上一章) :
通过重新组织IO的顺序来有效的减少磁盘的访问开销
磁盘的性能怎么来表示:
- 读取或写入时,磁头必须被定位在期望的磁道,并从所期望的扇区开始
- 寻道时间: 定位到期望的磁道所花费的时间
- 旋转延迟: 从扇区的开始处到到达目的处花费的时间
平均旋转延迟时间 = 磁盘旋转一周时间的一半
IO传输时间表达式
寻道时间是性能上区别的原因
对单个磁盘,会有一个IO请求数目
如果请求是随机的,那么会表现很差
如何解决这种磁盘上寻道时间的开销大的问题
(一) FIFO
按顺序处理请求
公平对待所有进程
在有很多进程的情况下,接近随机调度的性能
虽然上述的FIFO是一种简洁的方式 ,但是它并不高效。 所以需要另一种方法 :
(二) 最短服务优先:
选择从磁臂当前位置需要移动最少的IO请求
总是选择最短寻道时间
(三) skan方法(电梯的IO请求调度算法) :
磁臂在一个方向上移动,满足所有为完成的请求,直到磁臂到达该方向上最后的磁道
调换方向
(四) c-skan方法 :
限制了仅在一个方向上扫描
当最后一个磁道也被访问过了后,磁臂返回到磁盘的另外一端再次进行扫描
(五) c-loop(c-skan改进)方法:
磁臂先到达该方向上最后一个请求处,然后立即反转
还有很多其他的方式:
SSTF、SCAN、CSCAN等几种调度算法。这几种就自己网上查具体实现的方式。
这几种算法也就是解决了机械硬盘的访问读写慢的问题, 性能的差异解决。 想要从根本上解决问题, 那么就买SSD固态硬盘吧…..