赞
踩
文件系统是操作系统中负责管理持久数据的子系统,说简单点,就是负责把用户的文件存到磁盘硬件中,因为即使计算机断电了,磁盘里的数据并不会丢失,所以可以持久化的保存文件。
文件系统的基本数据单位是文件,它的目的是对磁盘上的文件进行组织管理,那组织的方式不同,就会形成不同的文件系统。
Linux 文件系统会为每个文件分配两个数据结构:
它们主要用来记录文件的元信息和目录层次结构。
索引节点: 文件的唯一标识
用来记录文件的元信息
,包括: inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。
目录项
用来记录文件的名字、索引节点指针、与其他目录项的层级关联关系
。多个目录项关联起来,就会形成目录结构
由于索引节点唯一标识一个文件,而目录项记录着文件的名,又因为一个文件可以有多个别名,所以目录项和索引节点的关系是多对一
注意,目录也是文件
,也是用索引节点唯一标识,和普通文件不同的是,普通文件在磁盘里面保存的是文件数据
,而目录文件在磁盘里面保存子目录或文件
。
那文件数据是如何存储在磁盘的呢?
磁盘读写的最小单位是扇区,扇区的大小只有 512B ,很明显,如果每次读写都以这么小为单位,那这读写的效率会非常低。
所以,文件系统把多个扇区组成了一个逻辑块,每次读写的最小单位就是逻辑块,Linux 中的逻辑块大小为 4KB,也就是一次性读写 8 个扇区,这将大大提高了磁盘的读写效率。
以上就是索引节点、目录项以及文件数据的关系
,下面这个图就很好的展示了它们之间的关系:
索引节点是存储在硬盘上的数据,那么为了加速文件的访问,通常会把索引节点加载到内存中。
另外,磁盘进行格式化的时候,会被分成三个存储区域,分别是超级块、索引节点区和数据块区
。
超级块,用来存储文件系统的元数据,比如块个数、块大小、空闲块等等。
索引节点区,用来存储索引节点;
数据块区,用来存储文件数据或目录数据;
我们不可能把超级块和索引节点区全部加载到内存,这样内存肯定撑不住,所以只有当需要使用的时候,才将其加载进内存,它们加载进内存的时机是不同的:
超级块:当文件系统挂载时进入内存;
索引节点区:当文件被访问时进入内存;
文件系统的种类众多,而操作系统希望对用户提供一个统一的接口,于是在用户层与文件系统层
引入了中间层,这个中间层就称为虚拟文件系统(Virtual File System,VFS)
VFS 定义了一组所有文件系统都支持的数据结构和标准接口,这样程序员不需要了解文件系统的工作原理,只需要了解 VFS 提供的统一接口即可。
在 Linux 文件系统中,用户空间、系统调用、虚拟机文件系统、缓存、文件系统以及存储之间的关系如下图:
Linux 支持的文件系统也不少,根据存储位置的不同,可以把文件系统分为三类:
磁盘的文件系统
它是直接把数据存储在磁盘中
内存的文件系统
这类文件系统的数据不是存储在硬盘的,而是占用内存空间
网络的文件系统
用来访问其他计算机主机数据的文件系统
我们从用户角度来看文件的话,就是我们要怎么使用文件?
流程如下:
跟踪进程打开的所有文件
我们打开了一个文件后,操作系统会跟踪进程打开的所有文件
怎么跟踪?
就是操作系统为每个进程维护一个打开文件表
,文件表里的每一项代表「文件描述符」
,所以说文件描述符是打开文件的标识。
操作系统在打开文件表中维护的打开文件的状态和信息有哪些?
文件指针
:系统跟踪上次读写位置作为当前文件位置指针,这种指针对打开文件的某个进程来说是唯一的;
文件打开计数器
:文件关闭时,操作系统必须重用其打开文件表条目,否则表内空间不够用。因为多个进程可能打开同一个文件
,所以系统在删除打开文件条目之前,必须等待最后一个进程关闭文件,该计数器跟踪打开和关闭的数量,当该计数为 0 时,系统关闭文件,
删除该条目;
文件磁盘位置
:绝大多数文件操作都要求系统修改文件数据,该信息保存在内存中,以免每个操作都从磁盘中读取;
访问权限
:每个进程打开文件都需要有一个访问模式(创建、只读、读写、添加等),该信息保存在进程的打开文件表中,以便操作系统能允许或拒绝之后的 I/O 请求;
用户和操作系统的差异
如何把文件数据和磁盘块对应起来
,操作系统并不会关心你想存在磁盘上的任何的数据结构。所以,用户和操作系统对文件的读写操作是有差异的,用户习惯以字节的方式读写文件,而操作系统则是以数据块来读写文件
,那屏蔽掉这种差异的工作就由文件系统完成。
读文件和写文件的过程:
读文件
当用户进程从文件读取 1 个字节大小的数据时,文件系统则需要获取字节所在的数据块,再返回数据块对应的用户进程所需的数据部分。
写文件
当用户进程把 1 个字节大小的数据写进文件时,文件系统则找到需要写入数据的数据块的位置,然后修改数据块中对应的部分,最后再把数据块写回磁盘。
所以说,文件系统的基本操作单位是数据块。
文件的数据是要存储在硬盘上面的,数据在磁盘上的存放方式,就像程序在内存中存放的方式那样,有以下两种:
连续空间存放方式
非连续空间存放方式
又可以分为「链表方式」和「索引方式」
。
不同的存储方式,有各自的特点,重点是要分析它们的存储效率和读写性能
这种模式下,文件的数据都是紧密相连,读写效率很高,因为一次磁盘寻道就可以读出整个文件。
使用前提
必须先知道一个文件的大小,这样文件系统才会根据文件的大小在磁盘上找到一块连续的空间分配给文件。
所以,文件头里需要指定「起始块的位置」和「长度」
,有了这两个信息就可以很好的表示文件存放方式是一块连续的磁盘空间。
缺点
非连续空间存放方式分为「链表方式」和「索引方式」
。
特点
链表的方式存放是离散的,于是就可以消除磁盘碎片,
可大大提高磁盘空间的利用率,同时文件的长度可以动态扩展
。
根据实现的方式的不同,链表可分为「隐式链表」和「显式链接」
两种形式。
实现的方式
文件头要包含「第一块」和「最后一块」
的位置,并且每个数据块里面留出一个指针空间
,用来存放下一个数据块的位置,这样一个数据块连着一个数据块,从链头开始就可以顺着指针找到所有的数据块,所以存放的方式可以是不连续
的。
图示:
缺点
什么是显式链接?
取出每个磁盘块的指针,把它放在内存的一个表中。可以解决上述隐式链表的两个不足。
把用于链接文件各数据块的指针,显式地存放在内存的一张链接表
中,该表在整个磁盘仅设置一张,每个表项中存放链接指针,指向下一个数据块号。
举例:
对于显式链接的工作方式,我们举个例子,文件 A 依次使用了磁盘块 4、7、2、10 和 12 ,文件 B 依次使用了磁盘块 6、3、11 和 14 。利用下图中的表,可以从第 4 块开始,顺着链走到最后,找到文件 A 的全部磁盘块。同样,从第 6 块开始,顺着链走到最后,也能够找出文件 B 的全部磁盘块。最后,这两个链都以一个不属于有效磁盘编号的特殊标记(如 -1 )结束。内存中的这样一个表格称为文件分配表(File Allocation Table,FAT)
。
优点
由于查找记录的过程是在内存中进行的,因而不仅显著地提高了检索速度,而且大大减少了访问磁盘的次数。
缺点
不适用于大磁盘。
是什么?
链表
的方式解决了连续分配的磁盘碎片和文件动态扩展
的问题,但是不能有效支持直接访问,索引的方式可以解决这个问题。
索引的实现是为每个文件创建一个「索引数据块」
,里面存放的是指向文件数据块的指针列表,说白了就像书的目录一样,要找哪个章节的内容,看目录查就可以。
优点
文件的创建、增大、缩小很方便;
不会有碎片的问题;
支持顺序读写和随机读写;
缺点
存储索引需要额外开销
大文件如何存储?
如果文件很大,大到一个索引数据块放不下索引信息,这时又要如何处理大文件的存放呢?我们可以通过组合的方式,来处理大文件的存储。
链表 + 索引
这种组合称为「链式索引块」
,它的实现方式是在索引数据块留出一个存放下一个索引数据块的指针,于是当一个索引数据块的索引信息用完了,就可以通过指针的方式,找到下一个索引数据块的信息。
缺点
那这种方式也会出现前面提到的链表方式的问题,万一某个指针损坏了,后面的数据也就会无法读取了。
索引 + 索引
这种组合称为「多级索引块」,实现方式是通过一个索引块来存放多个索引数据块,一层套一层索引,像极了俄罗斯套娃是吧。
算法思想:根据进程请求访问磁盘的先后顺序进行调度。
假设磁头的初始位置是100号磁道,有多个进程先后陆续地请求访问55、58、39、18、90、160、150、38、184号磁道。
按照先来先服务算法规则,按照请求到达的顺序,磁头需要一次移动到55、58、39、18、90、160、150、38、184号磁道。
磁头共移动了 45 + 3 + 19 + 21 + 72 + 70 + 10 + 112 + 146 = 498个磁道。响应一个请求平均需要移动498 / 9 = 55.3个磁道(平均寻找长度)。
优点:公平;如果请求访问的磁道比较集中的话,算法性能还算可以。
缺点:如果大量进程竞争使用磁盘,请求访问的磁道很分散,FCFS在性能上很差,寻道时间长。
算法思想:优先处理的磁道是与当前磁头最近的磁道。可以保证每次寻道时间最短,但是不能保证总的寻道时间最短。(其实是贪心算法的思想,只是选择眼前最优,但是总体未必最优)。
假设磁头的初始位置是100号磁道,有多个进程先后陆续地请求访问55、58、39、18、90、160、150、38、184号磁道。
磁头总共移动了(100 -18)+ (184 -18) = 248个磁道。响应一个请求平均需要移动248 / 9 = 27.5个磁道(平均寻找长度)。
可能产生饥饿现象。
扫描算法是一扫到底,然后依次扫回来去
假设某磁盘的磁道为0~200号,磁头的初始位置是100号磁道,且此时磁头正在往磁道号增大的方向移动,有多个进程先后陆续的访问55、58、39、18、90、160、150、38、184号磁道。
磁头共移动了(184 - 100)+ (184 -18) = 250个磁道。响应一个请求平均需要移动 250 / 9 = 27.5个磁道(平均寻找长度)。
循环扫描算法是一扫到底,然后迅速回到首柱面,再依次往后扫
循环扫描(C-SCAN)调度是 SCAN 的一个变种,以提供更均匀的等待时间。像 SCAN 一样,C-SCAN 移动磁头从磁盘一端到磁盘另一端,并且处理行程上的请求。然而,当磁头到达另一端时,它立即返回到磁盘的开头,而并不处理任何回程上的请求。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。