• 操作系统学习笔记(六) 文件系统


    零——什么是文件系统?

    文件这个词,相信大家从小就不陌生。实体的文件,可能会是打印的A4纸;虚拟的文件,可能是*.doc、*.dll以及*.exe等等格式。文件,就是用来记录信息的逻辑单元。

    文件系统这个概念,我们大部分人可能也接触过。重装系统的时候,会遇到给磁盘分区,以及格式化的问题;当然,格式化U盘也是常用的操作。装机的时候,如果你细心,你会发现分区软件会显示每个分区的格式。格式化这个概念,许多人都接触过但是不太清楚到底做了什么。

    其实,格式化就是把磁盘这样的存储设备,设置成我们需要的文件系统。FAT、NTFS这两个词相信大家都是见过的,他们都是文件系统,也是我们在格式化的时候需要选择的目标文件系统。

    总体来看,文件系统就是操作系统处理文件的部分。

    一、文件

    文件是一种抽象机制,它提供了一种在磁盘上保留信息并且方便以后读取的方法。在Linux操作系统中,文件名并没有规定任何格式,比如一个aha.txt,只是提示用户这可能是一个文本文件,然而并不保证任何内容。对应的,windows是需要后缀名这个信息的。

    文件可能有许多种结构,如:

    流式文件,无结构的字节序列,操作系统根本不知道也不关心文件的内容是什么,见到的就是字节,含义在用户程序中解释,Linux和windows都是这样的;

    树,通过键值查询文件,操作系统维护记录树。

    文件分为许多种,在Linux中,文件分为普通文件、目录文件和特殊文件。普通文件包括:二进制文件和ASCII文件。前者是二进制,需要用特定的规则来读,后者是我们常见的字符文件。

    目录文件除了自身属性外,记录了该目录下的文件名称。

    特殊文件:包括块设备文件和字符设备文件。块设备文件,如硬盘,支持随机访问操作;字符设备文件通常是串行设备,如鼠标键盘等,自然不支持随机访问。

    文件的存取,对于主流的Linux和windows操作系统,都不是顺序的,因为这样会造成很大的空穴浪费。一般都是通过索引式文件存取。对于Linux的文件系统,详情可见后面的Ext2/3文件系统介绍。

    我们在windows操作系统下,右键就可以显示文件的属性。文件的属性规定了不同的用户可以对它进行的操作,以及文件自身的大小、位置、更新时间等信息。Linux操作系统中可以用ls -l来查看完整的文件属性,包括文件类型,用户、用户组、其他用户的操作权限,以及大小、位置和修改时间等信息。当然,这并不全。

    二、目录

    现代操作系统,通常采用了层次目录系统,把目录组成一棵树。通常会有一个根目录,然后直到文件,形成一个绝对路径;也可以预先进入一个目录,然后使用相对目录访问。

    在Linux操作系统中,目录其实也是一种文件,在类型标识中为d。

    目录同样有文件的各种属性,不过在对属性的解释上可能与文件有些许区别。

    三、文件系统的实现

    1、文件系统的布局

    毫无疑问,文件系统存在于磁盘上。一开始我们提到了分区的概念。磁盘被划分了多个分区,一般来说可以有4个分区,其中一个分区为扩展分区,可以进一步分出许多逻辑分区。通常,一个分区中只存在一种文件系统。磁盘的头上是启动扇区,存放着主引导记录(MBR),然后是分区表,记录着磁盘的分区情况。一个分区被标记为活动分区。每个分区的开始会有一个引导块。

    下图是Linux操作系统的Ext2文件系统的布局。

    可以看到,Linux操作系统把磁盘块分成了组,每个组中都可能有超级块的备份。

    超级块存储了文件系统的关键参数,包括inode和block的使用情况等。

    接下来的两组bitmap记录了本组块和inode的使用情况。之后是inode表,因为Linux采用了多级块索引,所以一部分块需要用作索引块。最后才是实际的存储区域。

    2、文件系统的实现

    最简单的实现自然是顺序存储,这样显然会造成管理上的不方便,以及内存的利用率很低。改进使用链表,简单串联起文件。这种方法速度会相当慢,也无法随机存取。

    可靠的实现方法:

    (1)内存中采用表的链表分配。每个块都需要一个表项,记录文件中下一个块的位置。这个表格称为文件分配表(FAT)。

    (2)inode。这是Linux的Ext文件系统采用的方法,采用预先分配好的inode,每个inode分配给一个文件,记录文件的属性信息,并指向实际存储文件的块。

    3、目录的实现

    windows采取的方法,是有一个文件表,每个表项包含了文件名称与对应的属性;Linux系统的Ext文件系统同样采取inode的方式,目录的inode记录该目录的属性,在数据块中存储该目录下的文件名以及对应的inode。

    4、共享文件

    在不同的目录上创建连接文件,就可以实现文件的共享。Linux操作系统采取了两种方式:

    (1)硬连接。硬连接其实没有占用新的inode节点,而是在需要创建文件的目录数据块中,新增了一个项:文件名-inode。访问时,会顺着访问路径查找原来的文件。硬链接存在一个问题,就是这个inode必须是在同一个分区中,不然无法找到这个inode。

    (2)软连接,也叫符号连接。这种方式类似windows的快捷方式,真正创建了一个文件,分配了inode。文件的内容比较简单,就是原文件的路径。

    5、日志文件系统

    日志文件系统的思想,是保存一个用于记录系统下一步要做什么的日志。这样,系统如果崩溃了,可以通过查看日志来获取崩溃前的任务,并完成它们。Ext3文件系统就是支持日志的系统,它是Ext2的扩展,也很容易升级。

    6、虚拟文件系统

    我们说到不同分区可能有不同的文件系统,所以系统必须能组织起不同的文件系统,并提供统一的操作接口。这就是虚拟文件系统(VFS),Linux操作系统采用了它。即使不同的分区采用了不同的文件系统,也可以采用POSIX接口对所有的文件系统进行操作。

    四、文件系统的管理和性能

    1、磁盘空间的管理

    首先要确定的是,也要如内存分页一样,把磁盘分为块进行管理。块的大小是一个影响因素。

    2、空闲空间的管理

    如内存一样,位图的方式是合理的,Ext文件系统使用了位图。另外,也可以通过空闲块链表的方式进行管理。

    3、文件系统的备份

    文件系统可能由于各种原因损坏,比如意外的灾难或者操作错误。备份到磁带上,可分为物理转储和逻辑转储。前者前部按需输出,后者从某一目录开始,递归地转储自给定基准日期后更改的全部文件和目录。

    4、文件系统的一致性

    因为文件的直接存储块和记录空闲空间的位图等结构是分离的,因此可能会出现不一致的情况。

    5、提高性能的方法

    (1)高速缓存。缓存的概念,遍布计算机的各个领域。磁盘的缓存与其他缓存也类似,内存页面置换算法也在这里适用。

    (2)块提前读。根据局部性的原理,提前读取部分可能用到的块。

    五、Linux文件系统实例分析

     1、LInux虚拟文件系统

    虚拟文件系统隐对用户隐藏了Linux支持的文件系统之间的区别,以及文件是一个本地设备,还是挂载的设备,或者是网络访问的远程设备等。

    VFS定义了一个基本的文件系统抽象以及这些抽象上允许的操作。VFS支持四个主要结构:

    (1)Superblock。该结构记录了文件系统布局的重要信息。

    (2)Inode。每个inode表示一个确切的文件,目录和设备也是文件,也有自己的inode。

    (3)Dentry。表示一个目录项,由文件系统在运行过程中创建。目录项被缓存在dentry_cache中。对于前面提到的硬链接,多个进程通过一个硬链接会访问同一个文件,文件对象都会指向这个cache中的同一个目录项。

    (4)File。这是一个打开文件在内存中表示的数据结构,在调用open时被创建,可以支持read/write/close/lseek等系统调用。

    2、Ext2文件系统

    Ext2文件系统的布局,其实我们前面已经提到了,参见三、1节的文件系统布局。

    具体地讲,块0不被Linux使用,而通常用来存放启动计算机的代码。块0后被分为多个块组,每个块组包括:
    (1)superblock。包含了文件系统的个数,磁盘块数以及空闲块的起始位置。
    (2)组描述符。存放了位图的位置、空闲块数、组中的inode数,以及组中目录数的信息。这个信息很重要,ext2文件系统会试图把目录均匀地分散存储到磁盘上。

    (3)inode和block的位图。

    (4)inode的存储区域。在ext2中inode大小为128字节,最新的ext4中已经增到到了256字节。

    (5)实际的存储块。ext2会试图把普通文件组织到与父目录相同的块组上,而把同一个块上的数据文件组织成初始文件i节点。

    下面的图是在我的虚拟机用dumpe2fs查看的文件系统:

    这是头部的信息,从超级块中读取。我们可以看到,包含了文件系统的特性、魔数(magic number)、inode的总数、块的总数、保留块数、空闲的inode和块数,以及块的大小、每组的块数量和inode数量、文件系统的修改时间、inode的大小等等信息。

    因为文件系统是ext4文件系统了,所以inode256字节,并且包含了128M的日志。

    这张图是两个实际的块组,从组描述符以及位图读出了许多信息。块组的起止位置,是否备份了superblock,组描述符的位置和位图的位置,inode表的位置,以及inode和块的使用情况等等。

    当打开一个文件时,我们前面提到,会为目录dentry进行缓存。操作系统将文件调入内存,并把i节点存放在i节点表中,i节点表是一个内核数据结构,用于保存当前所有打开的文件和目录的i节点。

    我们知道,执行open时会返回一个文件描述符(通常是整数),因此会有一个文件描述符表,用来记录fd以及对应的表项。实际上,每个进程维护自己的文件描述符表,并且在它和i节点表间维护一个打开文件描述符表,并将文件读写位置放入其中。

  • 相关阅读:
    jenkins配置完全正确,控制台显示邮件发送成功,但未收到问题
    中移4G模块-ML302-OpenCpu开发-串口开发
    中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云-RRPC通讯)
    中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云-接收和发送数据)
    中移4G模块-ML302-OpenCpu开发-GPIO
    中移4G模块-ML302-OpenCpu开发-服务器搭建
    中移4G模块-ML302-OpenCpu开发-前端网页搭建
    中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云-订阅主题)
    中移4G模块-ML302-OpenCpu开发-2-MQTT连接阿里云
    MateBook14一个多月的使用体验(开发向)
  • 原文地址:https://www.cnblogs.com/lustar/p/7912714.html
Copyright © 2020-2023  润新知