文件系统 订阅
文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性。从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。 展开全文
文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性。从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。
信息
外文名
file system
类    别
操作系统
中文名
文件系统
目    的
为了管理空间
文件系统简介
在计算机中,文件系统(file system)是命名文件及放置文件的逻辑存储和恢复的系统。DOS、Windows、OS/2、Macintosh和UNIX-based操作系统都有文件系统,在此系统中文件被放置在分等级的(树状)结构中的某一处。文件被放置进目录(Windows中的文件夹)或子目录,在树状结构中你希望的位置中。文件系统指定命名文件的规则。这些规则包括文件名的字符数最大量,哪种字符可以使用,以及某些系统中文件名后缀可以有多长。文件系统还包括通过目录结构找到文件的指定路径的格式。 [1]  文件系统是软件系统的一部分,它的存在使得应用可以方便的使用抽象命名的数据对象和大小可变的空间。
收起全文
精华内容
下载资源
问答
  • 文件系统

    千次阅读 2018-09-05 09:17:21
    操作系统层:即文件系统,操作系统如何将各个硬件管理并对上提供更高层次接口; 单机引擎层:常见存储系统对应单机引擎原理大概介绍,利用文件系统接口提供更高级别的存储系统接口; 分布式层:如何将多个...

    在工程架构领域里,存储是一个非常重要的方向,这个方向从底至上,我分成了如下几个层次来介绍:

    1. 硬件层:讲解磁盘,SSD,SAS, NAS, RAID等硬件层的基本原理,以及其为操作系统提供的存储界面;
    2. 操作系统层:即文件系统,操作系统如何将各个硬件管理并对上提供更高层次接口;
    3. 单机引擎层:常见存储系统对应单机引擎原理大概介绍,利用文件系统接口提供更高级别的存储系统接口;
    4. 分布式层:如何将多个单机引擎组合成一个分布式存储系统;
    5. 查询层:用户典型的查询语义表达以及解析;

                                                               元数据——块数据——缓冲数据——文件数据

    概述

    操作系统对系统的软件资源(不论是应用软件和系统软件)的管理都以文件方式进行,承担这部分功能的操作系统称为文件系统。

    文件系统

    文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性。从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。

    在计算机中,文件系统(file system)是命名文件及放置文件的逻辑存储和恢复的系统。DOS、Windows、OS/2、Macintosh和UNIX-based操作系统都有文件系统,在此系统中文件被放置在分等级的(树状)结构中的某一处。文件被放置进目录(Windows中的文件夹)或子目录,在树状结构中你希望的位置中。【linux树形目录,也就是树谱总分关系无限下延续】

    文件系统指定命名文件的规则。这些规则包括文件名的字符数最大量,哪种字符可以使用,以及某些系统中文件名后缀可以有多长。文件系统还包括通过目录结构找到文件的指定路径的格式。 

    文件系统是软件系统的一部分,它的存在使得应用可以方便的使用抽象命名的数据对象和大小可变的空间。

    文件系统种类

    FAT(8/16/32)
    NTFS
    CDFS
    exFAT
    RAW
    Ext
         1.Ext2
         2.Ext3
         3.Ext4

    XFS
    Btrfs
    ZFS
    HFS
    HFS+
    ReiserFS
    JFS
    VMFS
    UFS
    VXFS
    ReFS
    WBFS
    PFS

    简单介绍

    FAT16:我们以前用的DOS、Windows 95都使用FAT16文件系统,现在常用的Windows 98/2000/XP等系统均支持FAT16文件系统。它最大可以管理大到2GB的分区,但每个分区最多只能有65525个簇(簇是磁盘空间的配置单位)。随着硬盘或分区容量的增大,每个簇所占的空间将越来越大,从而导致硬盘空间的浪费。 

    FAT32:随着大容量硬盘的出现,从Windows 98开始,FAT32开始流行。它是FAT16的增强版本,可以支持大到2TB(2048G的分区。FAT32使用的簇比FAT16小,从而有效地节约了硬盘空间。 

    NTFS:最大分区2TB。另:简单卷最大2TB,动态卷最大16TB。
    
    Ext4 是 Ext3 的改进版,修改了 Ext3 中部分重要的数据结构,而不仅仅像 Ext3 对 Ext2 那样,只是增加了一个日志功能而已。Ext4 可以提供更佳的性能和可靠性,还有更为丰富的功能:
    1. 与 Ext3 兼容。执行若干条命令,就能从 Ext3 在线迁移到 Ext4,而无须重新格式化磁盘或重新安装系统。原有 Ext3 数据结构照样保留,Ext4 作用于新数据,当然,整个文件系统因此也就获得了 Ext4 所支持的更大容量。
    
    2. 更大的文件系统和更大的文件。较之 Ext3 目前所支持的最大 16TB 文件系统和最大 2TB 文件,Ext4 分别支持 1EB(1,048,576TB, 1EB=1024PB, 1PB=1024TB)的文件系统,以及 16TB 的文件。
    
    3. 无限数量的子目录。Ext3 目前只支持 32,000 个子目录,而 Ext4 支持无限数量的子目录。
    
    ext3和ext4的最大区别在于,ext3在fsck时需要耗费大量时间(文件越多,时间越长),而ext4在fsck时用的时间会少非常多
    
    ext4是第四代扩展文件系统(英语:Fourth EXtended filesystem,缩写为ext4)是linux系统下的日志文件系统,是ext3文件系统的后继版本
    ext4的文件系统容量达到1EB,而文件容量则达到16TB,这是一个非常大的数字了。对一般的台式机和服务器而言,这可能并不重要,但对于大型磁盘阵列的用户而言,这就非常重要了。
    ext3目前只支持32000个子目录,而ext4取消了这一限制,理论上支持无限数量的子目录。
    
    xfs是一种非常优秀的日志文件系统,它是SGI公司设计的。xfs被称为业界最先进的、最具可升级性的文件系统技术
    xfs是一个64位文件系统,最大支持8EB减1字节的单个文件系统,实际部署时取决于宿主操作系统的最大块限制。对于一个32位Linux系统,文件和文件系统的大小会被限制在16TB
    xfs在很多方面确实做的比ext4好,ext4受限制于磁盘结构和兼容问题,可扩展性和scalability确实不如xfs,另外xfs经过很多年发展,各种锁的细化做的也比较好。
    
    注:Ext2: 是 GNU/Linux 系统中标准的文件系统,其特点为存取文件的性能极好,对于中小型的文件更显示出优势,这主要得利于其簇快取层的优良设计。其单一文件大小与文件系统本身的容量上限与文件系统本身的簇大小有关,在一般常见的 x86 电脑系统中,簇最大为 4KB, 则单一文件大小上限为 2048GB, 而文件系统的容量上限为 16384GB。但由于目前核心 2.4 所能使用的单一分割区最大只有 2048GB,因此实际上能使用的文件系统容量最多也只有 2048GB。

    centos7.0开始默认文件系统是xfs,centos6是ext4,centos5是ext3

     

    各种文件系统支持的最大硬盘容量

    NTFS格式(windows的分区,Linux也能用):支持最大分区为2TB,最大文件为2TB;

    FAT32格式(windows的分区,Linux也能用):支持最大分区为128GB,最大文件为4GB;

    Ext2格式:最大分区大小为4TB,最大文件大小为1TB;

    Ext3格式:最大分区大小为16TB,最大文件大小为2TB;

    EXT4格式:最大分区大小为1EB,最大文件大小为16TB;

    XFS格式:最大支持8EB减1字节的单个文件系统;实际部署时取决于宿主操作系统的最大块限制。对于一个32位Linux操作系统,文件和文件系统的大小会被限制在16TB;

    ReiserFS格式:最大分区大小为4TB,最大文件大小为1TB;

     注:1EB=1024PB,1PB=1024TB,1TB=1024GB

    EXT4是第四代扩展文件系统(英语:Fourth EXtended filesystem,缩写为ext4)是Linux系统下的日志文件系统,是ext3文件系统的后继版本。
    Ext4的文件系统容量达到1EB,而文件容量则达到16TB,这是一个非常大的数字了。对一般的台式机和服务器而言,这可能并不重要,但对于大型磁盘阵列的用户而言,这就非常重要了。

    XFS是一个64位文件系统,最大支持8EB减1字节的单个文件系统,实际部署时取决于宿主操作系统的最大块限制。对于一个32位Linux系统,文件和文件系统的大小会被限制在16TB。

    二者各有特点,而性能表现基本上是差不多的。例如,谷歌公司就考虑将EXT2系统升级,最终确定为EXT4系统。谷歌公司表示,他们还考虑过XFS和JFS。结果显示,EXT4和XFS的表现类似,不过从EXT2升级到EXT4比升级到XFS容易。

    对于存储海量的小文件,或者超大规模的文件,文件大小也偏大的话,建议你使用xfs,否则使用ext4,ext4比较稳定,是主流的Linux文件系统

    在Linux下,理论上文件最大可以达到4T(看清楚是4T不是4G),但在实际操作中都在2G左右(一般不超过4G),超过2G的单个文件较之小于2G的文件安全系数降低不少。另外对于ext3系统,如果突然断电,容易出现硬盘问题,这种问题在大文件多的硬盘硬盘中大文件多的区域特别容易发生,而且经常是毁灭性的。如果要存放大文件,建议使用reiserfs系统。

    功能

    结构图
    结构图

     

    文件的系统是操作系统用于明确磁盘或分区上的文件的方法和数据结构;即在磁盘上组织文件的方法。也指用于存储文件的磁盘或分区,或文件系统种类。因此,可以说"我有2个文件系统"意思是他有2个分区,一个存文件,或他用 "扩展文件系统",意思是文件系统的种类。

    磁盘或分区和它所包括的文件系统的不同是很重要的。少数程序(包括最有理由的产生文件系统的程序)直接对磁盘或分区的原始扇区进行操作;这可能破坏一个存在的文件系统。大部分程序基于文件系统进行操作,在不同种文件系统上不能工作。

    一个分区或磁盘在作为文件系统使用前,需要初始化,并将记录数据结构写到磁盘上。这个过程就叫建立文件系统。

    大部分UNIX文件系统种类具有类似的通用结构,即使细节有些变化。其中心概念是超级块superblock,i节点inode,数据块data block,目录块directory block,和间接块indirection block。超级块包括文件系统的总体信息,比如大小(其准确信息依赖文件系统)。i节点包括除了名字外的一个文件的所有信息,名字与i节点数目一起存在目录中,目录条目包括文件名和文件的i节点数目。i节点包括几个数据块的数目,用于存储文件的数据。i节点中只有少量数据块数的空间,如果需要更多,会动态分配指向数据块的指针空间。这些动态分配的块是间接块;为了找到数据块,这名字指出它必须先找到间接块的号码。

    UNIX文件系统通常允许在文件中产生孔,意思是文件系统假装文件中有一个特殊的位置只有0字节,但没有为这文件的这个位置保留实际的磁盘空间。这对小的 [2]  二进制文件经常发生,Linux共享库、一些数据库和其他一些特殊情况。

    孔有一定的用处。在笔者的系统中,一个简单的测量工具显示在200MB使用的磁盘空间中,由于孔,节约了大约4MB。在这个系统中,程序相对较少,没有 [3]  数据库文件

    文件系统的功能包括:管理和调度文件的存储空间,提供文件的逻辑结构、物理结构和存储方法;实现文件从标识到实际地址的映射,实现文件的控制操作和存取操作,实现文件信息的共享并提供可靠的文件保密和保护措施,提供文件的安全措施。

    文件的逻辑结构是依照文件的内容的逻辑关系组织文件结构。文件的逻辑结构可以分为流式文件和记录式文件。

    流式文件:文件中的数据是一串字符流,没有结构。

    记录文件:由若干逻辑记录组成,每条记录又由相同的数据项组成,数据项的长度可以是确定的,也可以是不确定的。

    主要缺陷:数据关联差,数据不一致,冗余性。

    linux文件系统详解

    最近在做磁盘性能优化,需要结合文件系统原理去思考优化方向,因此借此机会进一步加深了对文件系统的认识。在看这篇文章之前,建议先看下前面一篇关于磁盘工作原理的解读。下面简单总结一些要点分享出来:

    Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其中。

    一、文件系统层次分析

    由上而下主要分为用户层、VFS层、文件系统层、缓存层、块设备层、磁盘驱动层、磁盘物理层

    用户层:最上面用户层就是我们日常使用的各种程序,需要的接口主要是文件的创建、删除、打开、关闭、写、读等。 

    VFS层:我们知道Linux分为用户态和内核态,用户态请求硬件资源需要调用System Call通过内核态去实现。用户的这些文件相关操作都有对应的System Call函数接口,接口调用 VFS对应的函数。 

    文件系统层:不同的文件系统实现了VFS的这些函数,通过指针注册到VFS里面。所以,用户的操作通过VFS转到各种文件系统。文件系统把文件读写命令转化为对磁盘LBA的操作,起了一个翻译和磁盘管理的作用。 

    缓存层:文件系统底下有缓存,Page Cache,加速性能。对磁盘LBA的读写数据缓存到这里。

    块设备层:块设备接口Block Device是用来访问磁盘LBA的层级,读写命令组合之后插入到命令队列,磁盘的驱动从队列读命令执行。Linux设计了电梯算法等对很多LBA的读写进行优化排序,尽量把连续地址放在一起。

    磁盘驱动层:磁盘的驱动程序把对LBA的读写命令转化为各自的协议,比如变成ATA命令,SCSI命令,或者是自己硬件可以识别的自定义命令,发送给磁盘控制器。Host Based SSD甚至在块设备层和磁盘驱动层实现了FTL,变成对Flash芯片的操作。 

    磁盘物理层:读写物理数据到磁盘介质。

    二、文件系统结构与工作原理(主要以ext4为例)

    我们都知道,windows文件系统主要有fat、ntfs等,而linux文件系统则种类多的很,主要有VFS做了一个软件抽象层,向上提供文件操作接口,向下提供标准接口供不同文件系统对接,下面主要就以EXT4文件系统为例,讲解下文件系统结构与工作原理:

    上面两个图大体呈现了ext4文件系统的结构,从中也相信能够初步的领悟到文件系统读写的逻辑过程。下面对上图里边的构成元素做个简单的讲解:

    引导块:为磁盘分区的第一个块,记录文件系统分区的一些信息,,引导加载当前分区的程序和数据被保存在这个块中。一般占用2kB,

    超级块:

    超级块用于存储文件系统全局的配置参数(譬如:块大小,总的块数和inode数)和动态信息(譬如:当前空闲块数和inode数),其处于文件系统开始位置的1k处,所占大小为1k。为了系统的健壮性,最初每个块组都有超级块和组描述符表(以下将用GDT)的一个拷贝,但是当文件系统很大时,这样浪费了很多块(尤其是GDT占用的块多),后来采用了一种稀疏的方式来存储这些拷贝,只有块组号是3, 5 ,7的幂的块组(譬如说1,3,5,7,9,25,49…)才备份这个拷贝。通常情况下,只有主拷贝(第0块块组)的超级块信息被文件系统使用,其它拷贝只有在主拷贝被破坏的情况下才使用。

    块组描述符:

    GDT用于存储块组描述符,其占用一个或者多个数据块,具体取决于文件系统的大小。它主要包含块位图,inode位图和inode表位置,当前空闲块数,inode数以及使用的目录数(用于平衡各个块组目录数),具体定义可以参见ext3_fs.h文件中struct ext3_group_desc。每个块组都对应这样一个描述符,目前该结构占用32个字节,因此对于块大小为4k的文件系统来说,每个块可以存储128个块组描述符。由于GDT对于定位文件系统的元数据非常重要,因此和超级块一样,也对其进行了备份。GDT在每个块组(如果有备份)中内容都是一样的,其所占块数也是相同的。从上面的介绍可以看出块组中的元数据譬如块位图,inode位图,inode表其位置不是固定的,当然默认情况下,文件系统在创建时其位置在每个块组中都是一样的,如图2所示(假设按照稀疏方式存储,且n不是3,5,7的幂)

    块组:

    每个块组包含一个块位图块,一个 inode 位图块,一个或多个块用于描述 inode 表和用于存储文件数据的数据块,除此之外,还有可能包含超级块和所有块组描述符表(取决于块组号和文件系统创建时使用的参数)。下面将对这些元数据作一些简要介绍。

    块位图:

    块位图用于描述该块组所管理的块的分配状态。如果某个块对应的位未置位,那么代表该块未分配,可以用于存储数据;否则,代表该块已经用于存储数据或者该块不能够使用(譬如该块物理上不存在)。由于块位图仅占一个块,因此这也就决定了块组的大小。

    Inode位图:

    Inode位图用于描述该块组所管理的inode的分配状态。我们知道inode是用于描述文件的元数据,每个inode对应文件系统中唯一的一个号,如果inode位图中相应位置位,那么代表该inode已经分配出去;否则可以使用。由于其仅占用一个块,因此这也限制了一个块组中所能够使用的最大inode数量。

    Inode表:

    Inode表用于存储inode信息。它占用一个或多个块(为了有效的利用空间,多个inode存储在一个块中),其大小取决于文件系统创建时的参数,由于inode位图的限制,决定了其最大所占用的空间。

    以上这几个构成元素所处的磁盘块成为文件系统的元数据块,剩余的部分则用来存储真正的文件内容,称为数据块,而数据块其实也包含数据和目录。

    了解了文件系统的结构后,接下来我们来看看操作系统是如何读取一个文件的:

    大体过程如下:

    1、根据文件所在目录的inode信息,找到目录文件对应数据块

    2、根据文件名从数据块中找到对应的inode节点信息

    3、从文件inode节点信息中找到文件内容所在数据块块号

    4、读取数据块内容

    到这里,相信很多人会有一个疑问,我们知道一个文件只有一个Inode节点来存放它的属性信息,那么你可能会想如果一个大文件,那它的block一定是多个的,且可能不连续的,那么inode怎么来表示呢,下面的图告诉你答案:

     

     也就是说,如果文件内容太大,对应数据块数量过多,inode节点本身提供的存储空间不够,会使用其他的间接数据块来存储数据块位置信息,最多可以有三级寻址结构。

     到这里,应该都已经非常清楚文件读取的过程了,那么下面再抛出两个疑问:

    1、文件的拷贝、剪切的底层过程是怎样的?

    2、软连接和硬连接分别是如何实现的?

    下面来结合stat命令动手操作一下,便知真相:

    1)拷贝文件:创建一个新的inode节点,并且拷贝数据块内容

    2)剪切文件:同个分区里边mv,inode节点不变,只是更新目录文件对应数据块里边的文件名和inode对应关系;跨分区mv,则跟拷贝一个道理,需要创建新的inode,因为inode节点不同分区是不能共享的。

    3)软连接:创建软连接会创建一个新的inode节点,其对应数据块内容存储所链接的文件名信息,这样原文件即便删除了,重新建立一个同名的文件,软连接依然能够生效。

     

     4)硬链接:创建硬链接,并不会新建inode节点,只是links加1,还有再目录文件对应数据块上增加一条文件名和inode对应关系记录;只有将硬链接和原文件都删除之后,文件才会真正删除,即links为0才真正删除。

     三、文件顺序读写和随机读写

    从前面文章了解了磁盘工作原理之后,也已经明白了为什么文件随机读写速度会比顺序读写差很多,这个问题在windows里边更加明显,为什么呢?究其原因主要与文件系统工作机制有关,fat和ntfs文件系统设计上,每个文件所处的位置相对连续甚至紧靠在一起,这样没有为每个文件留下足够的扩展空间,因此容易产生磁盘碎片,用过windows系统的应该也知道,windows磁盘分区特别提供了磁盘碎片整理的高级功能。如下图:

    那回过来,看看linux 文件系统ext4,都说linux不需要考虑磁盘碎片,究竟是怎么回事?

    主要是因为Linux的文件系统会将文件分散在整个磁盘,在文件之间留有大量的自由空间,而不是像Windows那样将文件一个接一个的放置。当一个文件被编辑了并且变大了,一般都会有足够的自由空间来保存文件。如果碎片真的产生了,文件系统就会尝试在日常使用中将文件移动来减少碎片,所以不需要专门的碎片整理程序。但是,如果磁盘空间占用已经快满了,那碎片是不可避免的,文件系统的设计本来就是用来满足正常情况下使用的。如果磁盘空间不够,那要么就是数据冗余了,要么就该换容量更大的磁盘。你可以使用fsck命令来检测一下一个Linux文件系统的碎片化程度,只需要在输出中查看非连续i节点个数(non-contiguous inodes)就可以了。

    关于文件系统的就讲这么多,下篇会讲解linux内核提供的一个资源管控机制cgroup,分析其原理及使用过程。

    ext4文件系统bug:
    http://www.phoronix.com/scan.php?page=news_item&px=MTIxNDQ

    Linux(unix)与微软文件系统比较

    相同点

    用户和组

    Linux是多用户多任务操作系统而Windows是单用户多任务操作系统。都可以由许多不同的用户来使用,为每个用户提供单独的环境和资源。基于用户身份来控制安全性。都可以以组成员的方式来控制资源的访问权限,这样在用户数目较大时可以不必为每一个帐号设置权限。

    用户和组可以集中管理,让多个服务器共享相同的用户和身份验证数据。

    文件系统

    Linux和Windows都支持多种文件系统。文件资源可以通过NetBIOS、FTP或者其他协议与其他客户机共享。可以很灵活地对各个独立的文件系统进行组织,由管理员来决定它们在何处可以以何种方式被访问。

    端口和设备

    两种操作系统都支持各种物理设备端口,比如并口、串口和 USB 接口。支持各种控制器,比如 IDE 和 SCSI 控制器。Linux 还支持很多“刚刚上市”的标准硬件。

    网络

    Linux和Windows都支持多种网络协议,比如TCP/IP、NetBIOS和IPX。都支持多种类型的网络适配器。都具备通过网络共享资源的能力,比如共享文件和打印。都可以提供网络服务能力,比如 DHCP 和 DNS。

    服务

    Linux和Windows都提供服务。所谓服务,指的是那些在后台运行的应用程序,可以为系统和远程调用该服务的计算机提供一些功能。在系统引导的时候可以单独控制并自动启动这些程序。(注意:Linux 中沿用了 Unix 的习惯,称这种应用程序为 daemon)

    不同点

    Linux 的应用目标是网络而不是打印

    Windows最初出现的时候,这个世界还是一个纸张的世界。Windows的伟大成就之一在于您的工作成果可以方便地看到并打印出来。这样一个开端影响了 Windows 的后期发展。

    同样,Linux 也受到了其起源的影响。Linux 的设计定位于网络操作系统。它的设计灵感来自于 Unix操作系统,因此它的命令的设计比较简单,或者说是比较简洁。由于纯文本可以非常好地跨网络工作,所以 Linux 配置文件和数据都以文本为基础。

    对那些熟悉图形环境的人来说,Linux服务器初看可能比较原始。但是Linux开发更多关注的是它的内在功能而不是表面上的东西。即使是在纯文本的环境中,Linux同样拥有非常先进的网络、脚本和安全能力。执行一些任务所需的某些表面上看起来比较奇怪的步骤是令人费解的,除非您认识到 Linux 是期望在网络上与其他 Linux系统协同执行这些任务。Linux的自动执行能力也很强,只需要设计批处理文件就可以让系统自动完成非常详细的任务。Linux 的这种能力来自于其基于文本的本质。

    可选的 GUI

    Linux有图形组件。Linux支持高端的图形适配器和显示器,完全胜任图形相关的工作。许多数字效果艺术家在Linux工作站上来进行他们的设计工作,而以前这些工作需要使用IRIX系统来完成。但是,图形环境并没有集成到 Linux 中,而是运行于系统之上的单独一层。这意味着您可以只运行 GUI,或者在需要时才运行 GUI。如果您的系统主要任务是提供Web应用,那么您可以停掉图形界面,而将其所用的内存和CPU资源用于您的服务。如果您需要在 GUI 环境下做一些工作,可以再打开它,工作完成后再将其关闭。

    Linux 有图形化的管理工具,以及日常办公的工具,比如电子邮件、网络浏览器和文档处理工具等。不过,在 Linux 中,图形化的管理工具通常是控制台 (命令行) 工具的扩展。也就是说,用图形化工具能完成的所有工作,用控制台命令同样可以完成。同样,使用图形化工具并不妨碍您对配置文件进行手工修改。其实际意义可能并不是特别显而易见,但是,如果在图形化管理工具中所做的任何工作都可以以命令行的方式完成,这就表示那些工作也可以由一个脚本来实现。脚本化的命令可以成为自动执行的任务。Linux 同时支持这两种方式,并不要求您只用文本或者只用 GUI。您可以根据您的需要选择最好的方法。

    Linux 中的配置文件是人类可读的文本文件,这与过去的 Windows 中的 INI 文件类似,但与 Windows 的注册表机制在思路上有本质的区别。每一个应用程序都有其自己的配置文件,而且通常不与其他的配置文件放在一起。不过,大部分的配置文件都存放于一个目录树 (/etc) 下的单个地方,所以看起来它们在逻辑上是在一起。文本文件的配置方式使得不通过特殊的系统工具就可以完成配置文件的备份、检查和编辑工作。

    文件名扩展

    Linux不使用文件名扩展来识别文件的类型。相反,Linux根据文件的头内容来识别其类型。为了提高文件可读性您仍可以使用文件名扩展,但这对 Linux 系统来说没有任何作用。不过,有一些应用程序,比如 Web 服务器,可能使用命名约定来识别文件类型,但这只是特定的应用程序的要求而不是 Linux 系统本身的要求。

    Linux通过文件访问权限来判断文件是否为可执行文件。任何一个文件都可以赋予可执行权限,这样程序和脚本的创建者或管理员可以将它们识别为可执行文件。这样做有利于安全。保存到系统上的可执行的文件不能自动执行,这样就可以防止许多脚本病毒

    重新引导是最后的手段

    如果您使用Windows已经很长时间了,您可能已经习惯出于各种原因(从软件安装到纠正服务故障)而重新引导系统。在Linux思想中您的这一习惯需要改变。Linux在本质上更遵循“牛顿运动定律”。一旦开始运行,它将保持运行状态,直到受到外来因素的影响,比如硬件的故障。实际上,Linux系统的设计使得应用程序不会导致内核的崩溃,因此不必经常重新引导(与Windows系统的设计相对而言)。所以除了Linux内核之外,其他软件的安装、启动、停止和重新配置都不用重新引导系统。

    如果您确实重新引导了 Linux 系统,问题很可能得不到解决,而且还会使问题更加恶化。学习并掌握 Linux 服务和运行级别是成功解决问题的关键。学习 Linux 最困难的就是克服重新引导系统的习惯。

    另外,您可以远程地完成Linux中的很多工作。只要有一些基本的网络服务在运行,您就可以进入到那个系统。而且,如果系统中一个特定的服务出现了问题,您可以在进行故障诊断的同时让其他服务继续运行。当您在一个系统上同时运行多个服务的时候,这种管理方式非常重要。

    命令区分大小写

    所有的 Linux 命令和选项都区分大小写。例如, -R 与 -r 不同,会去做不同的事情。控制台命令几乎都是小写的。

    【参考资料】

    1、存储系统科普——文件系统介绍 - 玄苦 - 博客园 https://www.cnblogs.com/xuanku/p/io_fs.html

    2、对文件系统的理解 - 一肩担风月 - 博客园 https://www.cnblogs.com/shangye/p/6177993.html

    3、Linux文件系统详解 - AlanTu - 博客园 https://www.cnblogs.com/alantu2018/p/8461749.html

    4、Linux文件系统_ https://baike.baidu.com/item/Linux%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/10986747

    5、linux文件系统特点-linux操作系统-麦子学院 http://www.maiziedu.com/wiki/linux/feature/

    6、深入理解操作系统原理之文件系统 -  https://blog.csdn.net/xiaokang123456kao/article/details/74171875

    展开全文
  • 一口气搞懂「文件系统」,就靠这 25 张图了

    万次阅读 多人点赞 2020-08-13 21:48:43
    文件系统的基本数据单位是文件,它的目的是对磁盘上的文件进行组织管理,那组织的方式不同,就会形成不同的文件系统。 Linux 最经典的一句话是:「一切皆文件」,不仅普通的文件和目录,就连块设备、管道、socket 等...


    前言

    不多 BB,直接上「硬菜」。


    正文

    文件系统的基本组成

    文件系统是操作系统中负责管理持久数据的子系统,说简单点,就是负责把用户的文件存到磁盘硬件中,因为即使计算机断电了,磁盘里的数据并不会丢失,所以可以持久化的保存文件。

    文件系统的基本数据单位是文件,它的目的是对磁盘上的文件进行组织管理,那组织的方式不同,就会形成不同的文件系统。

    Linux 最经典的一句话是:「一切皆文件」,不仅普通的文件和目录,就连块设备、管道、socket 等,也都是统一交给文件系统管理的。

    Linux 文件系统会为每个文件分配两个数据结构:索引节点(index node)和目录项(directory entry,它们主要用来记录文件的元信息和目录层次结构。

    • 索引节点,也就是 inode,用来记录文件的元信息,比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。索引节点是文件的唯一标识,它们之间一一对应,也同样都会被存储在硬盘中,所以索引节点同样占用磁盘空间
    • 目录项,也就是 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成目录结构,但它与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是缓存在内存

    由于索引节点唯一标识一个文件,而目录项记录着文件的名,所以目录项和索引节点的关系是多对一,也就是说,一个文件可以有多个别字。比如,硬链接的实现就是多个目录项中的索引节点指向同一个文件。

    注意,目录也是文件,也是用索引节点唯一标识,和普通文件不同的是,普通文件在磁盘里面保存的是文件数据,而目录文件在磁盘里面保存子目录或文件。

    目录项和目录是一个东西吗?

    虽然名字很相近,但是它们不是一个东西,目录是个文件,持久化存储在磁盘,而目录项是内核一个数据结构,缓存在内存。

    如果查询目录频繁从磁盘读,效率会很低,所以内核会把已经读过的目录用目录项这个数据结构缓存在内存,下次再次读到相同的目录时,只需从内存读就可以,大大提高了文件系统的效率。

    注意,目录项这个数据结构不只是表示目录,也是可以表示文件的。

    那文件数据是如何存储在磁盘的呢?

    磁盘读写的最小单位是扇区,扇区的大小只有 512B 大小,很明显,如果每次读写都以这么小为单位,那这读写的效率会非常低。

    所以,文件系统把多个扇区组成了一个逻辑块,每次读写的最小单位就是逻辑块(数据块),Linux 中的逻辑块大小为 4KB,也就是一次性读写 8 个扇区,这将大大提高了磁盘的读写的效率。

    以上就是索引节点、目录项以及文件数据的关系,下面这个图就很好的展示了它们之间的关系:

    在这里插入图片描述

    索引节点是存储在硬盘上的数据,那么为了加速文件的访问,通常会把索引节点加载到内存中。

    另外,磁盘进行格式化的时候,会被分成三个存储区域,分别是超级块、索引节点区和数据块区。

    • 超级块,用来存储文件系统的详细信息,比如块个数、块大小、空闲块等等。
    • 索引节点区,用来存储索引节点;
    • 数据块区,用来存储文件或目录数据;

    我们不可能把超级块和索引节点区全部加载到内存,这样内存肯定撑不住,所以只有当需要使用的时候,才将其加载进内存,它们加载进内存的时机是不同的:

    • 超级块:当文件系统挂载时进入内存;
    • 索引节点区:当文件被访问时进入内存;

    虚拟文件系统

    文件系统的种类众多,而操作系统希望对用户提供一个统一的接口,于是在用户层与文件系统层引入了中间层,这个中间层就称为虚拟文件系统(Virtual File System,VFS)。

    VFS 定义了一组所有文件系统都支持的数据结构和标准接口,这样程序员不需要了解文件系统的工作原理,只需要了解 VFS 提供的统一接口即可。

    在 Linux 文件系统中,用户空间、系统调用、虚拟机文件系统、缓存、文件系统以及存储之间的关系如下图:

    Linux 支持的文件系统也不少,根据存储位置的不同,可以把文件系统分为三类:

    • 磁盘的文件系统,它是直接把数据存储在磁盘中,比如 Ext 2/3/4、XFS 等都是这类文件系统。
    • 内存的文件系统,这类文件系统的数据不是存储在硬盘的,而是占用内存空间,我们经常用到的 /proc/sys 文件系统都属于这一类,读写这类文件,实际上是读写内核中相关的数据数据。
    • 网络的文件系统,用来访问其他计算机主机数据的文件系统,比如 NFS、SMB 等等。

    文件系统首先要先挂载到某个目录才可以正常使用,比如 Linux 系统在启动时,会把文件系统挂载到根目录。


    文件的使用

    我们从用户角度来看文件的话,就是我们要怎么使用文件?首先,我们得通过系统调用来打开一个文件。

    write 的过程

    fd = open(name, flag); # 打开文件
    ...
    write(fd,...);         # 写数据
    ...
    close(fd);             # 关闭文件
    

    上面简单的代码是读取一个文件的过程:

    • 首先用 open 系统调用打开文件,open 的参数中包含文件的路径名和文件名。
    • 使用 write 写数据,其中 write 使用 open 所返回的文件描述符,并不使用文件名作为参数。
    • 使用完文件后,要用 close 系统调用关闭文件,避免资源的泄露。

    我们打开了一个文件后,操作系统会跟踪进程打开的所有文件,所谓的跟踪呢,就是操作系统为每个进程维护一个打开文件表,文件表里的每一项代表「文件描述符」,所以说文件描述符是打开文件的标识。

    打开文件表

    操作系统在打开文件表中维护着打开文件的状态和信息:

    • 文件指针:系统跟踪上次读写位置作为当前文件位置指针,这种指针对打开文件的某个进程来说是唯一的;
    • 文件打开计数器:文件关闭时,操作系统必须重用其打开文件表条目,否则表内空间不够用。因为多个进程可能打开同一个文件,所以系统在删除打开文件条目之前,必须等待最后一个进程关闭文件,该计数器跟踪打开和关闭的数量,当该计数为 0 时,系统关闭文件,删除该条目;
    • 文件磁盘位置:绝大多数文件操作都要求系统修改文件数据,该信息保存在内存中,以免每个操作都从磁盘中读取;
    • 访问权限:每个进程打开文件都需要有一个访问模式(创建、只读、读写、添加等),该信息保存在进程的打开文件表中,以便操作系统能允许或拒绝之后的 I/O 请求;

    在用户视角里,文件就是一个持久化的数据结构,但操作系统并不会关心你想存在磁盘上的任何的数据结构,操作系统的视角是如何把文件数据和磁盘块对应起来。

    所以,用户和操作系统对文件的读写操作是有差异的,用户习惯以字节的方式读写文件,而操作系统则是以数据块来读写文件,那屏蔽掉这种差异的工作就是文件系统了。

    我们来分别看一下,读文件和写文件的过程:

    • 当用户进程从文件读取 1 个字节大小的数据时,文件系统则需要获取字节所在的数据块,再返回数据块对应的用户进程所需的数据部分。
    • 当用户进程把 1 个字节大小的数据写进文件时,文件系统则找到需要写入数据的数据块的位置,然后修改数据块中对应的部分,最后再把数据块写回磁盘。

    所以说,文件系统的基本操作单位是数据块


    文件的存储

    文件的数据是要存储在硬盘上面的,数据在磁盘上的存放方式,就像程序在内存中存放的方式那样,有以下两种:

    • 连续空间存放方式
    • 非连续空间存放方式

    其中,非连续空间存放方式又可以分为「链表方式」和「索引方式」。

    不同的存储方式,有各自的特点,重点是要分析它们的存储效率和读写性能,接下来分别对每种存储方式说一下。

    连续空间存放方式

    连续空间存放方式顾名思义,文件存放在磁盘「连续的」物理空间中。这种模式下,文件的数据都是紧密相连,读写效率很高,因为一次磁盘寻道就可以读出整个文件。

    使用连续存放的方式有一个前提,必须先知道一个文件的大小,这样文件系统才会根据文件的大小在磁盘上找到一块连续的空间分配给文件。

    所以,文件头里需要指定「起始块的位置」和「长度」,有了这两个信息就可以很好的表示文件存放方式是一块连续的磁盘空间。

    注意,此处说的文件头,就类似于 Linux 的 inode。

    连续空间存放方式

    连续空间存放的方式虽然读写效率高,但是有「磁盘空间碎片」和「文件长度不易扩展」的缺陷。

    如下图,如果文件 B 被删除,磁盘上就留下一块空缺,这时,如果新来的文件小于其中的一个空缺,我们就可以将其放在相应空缺里。但如果该文件的大小大于所有的空缺,但却小于空缺大小之和,则虽然磁盘上有足够的空缺,但该文件还是不能存放。当然了,我们可以通过将现有文件进行挪动来腾出空间以容纳新的文件,但是这个在磁盘挪动文件是非常耗时,所以这种方式不太现实。

    磁盘碎片

    另外一个缺陷是文件长度扩展不方便,例如上图中的文件 A 要想扩大一下,需要更多的磁盘空间,唯一的办法就只能是挪动的方式,前面也说了,这种方式效率是非常低的。

    那么有没有更好的方式来解决上面的问题呢?答案当然有,既然连续空间存放的方式不太行,那么我们就改变存放的方式,使用非连续空间存放方式来解决这些缺陷。

    非连续空间存放方式

    非连续空间存放方式分为「链表方式」和「索引方式」。

    我们先来看看链表的方式。

    链表的方式存放是离散的,不用连续的,于是就可以消除磁盘碎片,可大大提高磁盘空间的利用率,同时文件的长度可以动态扩展。根据实现的方式的不同,链表可分为「隐式链表」和「显式链接」两种形式。

    文件要以「隐式链表」的方式存放的话,实现的方式是文件头要包含「第一块」和「最后一块」的位置,并且每个数据块里面留出一个指针空间,用来存放下一个数据块的位置,这样一个数据块连着一个数据块,从链头开是就可以顺着指针找到所有的数据块,所以存放的方式可以是不连续的。

    隐式链表

    隐式链表的存放方式的缺点在于无法直接访问数据块,只能通过指针顺序访问文件,以及数据块指针消耗了一定的存储空间。隐式链接分配的稳定性较差,系统在运行过程中由于软件或者硬件错误导致链表中的指针丢失或损坏,会导致文件数据的丢失。

    如果取出每个磁盘块的指针,把它放在内存的一个表中,就可以解决上述隐式链表的两个不足。那么,这种实现方式是「显式链接」,它指把用于链接文件各数据块的指针,显式地存放在内存的一张链接表中,该表在整个磁盘仅设置一张,每个表项中存放链接指针,指向下一个数据块号

    对于显式链接的工作方式,我们举个例子,文件 A 依次使用了磁盘块 4、7、2、10 和 12 ,文件 B 依次使用了磁盘块 6、3、11 和 14 。利用下图中的表,可以从第 4 块开始,顺着链走到最后,找到文件 A 的全部磁盘块。同样,从第 6 块开始,顺着链走到最后,也能够找出文件 B 的全部磁盘块。最后,这两个链都以一个不属于有效磁盘编号的特殊标记(如 -1 )结束。内存中的这样一个表格称为文件分配表(File Allocation Table,FAT

    显式链接

    由于查找记录的过程是在内存中进行的,因而不仅显著地提高了检索速度,而且大大减少了访问磁盘的次数。但也正是整个表都存放在内存中的关系,它的主要的缺点是不适用于大磁盘

    比如,对于 200GB 的磁盘和 1KB 大小的块,这张表需要有 2 亿项,每一项对应于这 2 亿个磁盘块中的一个块,每项如果需要 4 个字节,那这张表要占用 800MB 内存,很显然 FAT 方案对于大磁盘而言不太合适。

    接下来,我们来看看索引的方式。

    链表的方式解决了连续分配的磁盘碎片和文件动态扩展的问题,但是不能有效支持直接访问(FAT除外),索引的方式可以解决这个问题。

    索引的实现是为每个文件创建一个「索引数据块」,里面存放的是指向文件数据块的指针列表,说白了就像书的目录一样,要找哪个章节的内容,看目录查就可以。

    另外,文件头需要包含指向「索引数据块」的指针,这样就可以通过文件头知道索引数据块的位置,再通过索引数据块里的索引信息找到对应的数据块。

    创建文件时,索引块的所有指针都设为空。当首次写入第 i 块时,先从空闲空间中取得一个块,再将其地址写到索引块的第 i 个条目。

    索引的方式

    索引的方式优点在于:

    • 文件的创建、增大、缩小很方便;
    • 不会有碎片的问题;
    • 支持顺序读写和随机读写;

    由于索引数据也是存放在磁盘块的,如果文件很小,明明只需一块就可以存放的下,但还是需要额外分配一块来存放索引数据,所以缺陷之一就是存储索引带来的开销。

    如果文件很大,大到一个索引数据块放不下索引信息,这时又要如何处理大文件的存放呢?我们可以通过组合的方式,来处理大文件的存。

    先来看看链表 + 索引的组合,这种组合称为「链式索引块」,它的实现方式是在索引数据块留出一个存放下一个索引数据块的指针,于是当一个索引数据块的索引信息用完了,就可以通过指针的方式,找到下一个索引数据块的信息。那这种方式也会出现前面提到的链表方式的问题,万一某个指针损坏了,后面的数据也就会无法读取了。

    链式索引块

    还有另外一种组合方式是索引 + 索引的方式,这种组合称为「多级索引块」,实现方式是通过一个索引块来存放多个索引数据块,一层套一层索引,像极了俄罗斯套娃是吧。

    多级索引块

    Unix 文件的实现方式

    我们先把前面提到的文件实现方式,做个比较:

    在这里插入图片描述

    那早期 Unix 文件系统是组合了前面的文件存放方式的优点,如下图:

    早期 Unix 文件系统

    它是根据文件的大小,存放的方式会有所变化:

    • 如果存放文件所需的数据块小于 10 块,则采用直接查找的方式;
    • 如果存放文件所需的数据块超过 10 块,则采用一级间接索引方式;
    • 如果前面两种方式都不够存放大文件,则采用二级间接索引方式;
    • 如果二级间接索引也不够存放大文件,这采用三级间接索引方式;

    那么,文件头(Inode)就需要包含 13 个指针:

    • 10 个指向数据块的指针;
    • 第 11 个指向索引块的指针;
    • 第 12 个指向二级索引块的指针;
    • 第 13 个指向三级索引块的指针;

    所以,这种方式能很灵活地支持小文件和大文件的存放:

    • 对于小文件使用直接查找的方式可减少索引数据块的开销;
    • 对于大文件则以多级索引的方式来支持,所以大文件在访问数据块时需要大量查询;

    这个方案就用在了 Linux Ext 2/3 文件系统里,虽然解决大文件的存储,但是对于大文件的访问,需要大量的查询,效率比较低。

    为了解决这个问题,Ext 4 做了一定的改变,具体怎么解决的,本文就不展开了。


    空闲空间管理

    前面说到的文件的存储是针对已经被占用的数据块组织和管理,接下来的问题是,如果我要保存一个数据块,我应该放在硬盘上的哪个位置呢?难道需要将所有的块扫描一遍,找个空的地方随便放吗?

    那这种方式效率就太低了,所以针对磁盘的空闲空间也是要引入管理的机制,接下来介绍几种常见的方法:

    • 空闲表法
    • 空闲链表法
    • 位图法

    空闲表法

    空闲表法就是为所有空闲空间建立一张表,表内容包括空闲区的第一个块号和该空闲区的块个数,注意,这个方式是连续分配的。如下图:

    空闲表法

    当请求分配磁盘空间时,系统依次扫描空闲表里的内容,直到找到一个合适的空闲区域为止。当用户撤销一个文件时,系统回收文件空间。这时,也需顺序扫描空闲表,寻找一个空闲表条目并将释放空间的第一个物理块号及它占用的块数填到这个条目中。

    这种方法仅当有少量的空闲区时才有较好的效果。因为,如果存储空间中有着大量的小的空闲区,则空闲表变得很大,这样查询效率会很低。另外,这种分配技术适用于建立连续文件。

    空闲链表法

    我们也可以使用「链表」的方式来管理空闲空间,每一个空闲块里有一个指针指向下一个空闲块,这样也能很方便的找到空闲块并管理起来。如下图:

    空闲链表法

    当创建文件需要一块或几块时,就从链头上依次取下一块或几块。反之,当回收空间时,把这些空闲块依次接到链头上。

    这种技术只要在主存中保存一个指针,令它指向第一个空闲块。其特点是简单,但不能随机访问,工作效率低,因为每当在链上增加或移动空闲块时需要做很多 I/O 操作,同时数据块的指针消耗了一定的存储空间。

    空闲表法和空闲链表法都不适合用于大型文件系统,因为这会使空闲表或空闲链表太大。

    位图法

    位图是利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上所有的盘块都有一个二进制位与之对应。

    当值为 0 时,表示对应的盘块空闲,值为 1 时,表示对应的盘块已分配。它形式如下:

    1111110011111110001110110111111100111 ...
    

    在 Linux 文件系统就采用了位图的方式来管理空闲空间,不仅用于数据空闲块的管理,还用于 inode 空闲块的管理,因为 inode 也是存储在磁盘的,自然也要有对其管理。


    文件系统的结构

    前面提到 Linux 是用位图的方式管理空闲空间,用户在创建一个新文件时,Linux 内核会通过 inode 的位图找到空闲可用的 inode,并进行分配。要存储数据时,会通过块的位图找到空闲的块,并分配,但仔细计算一下还是有问题的。

    数据块的位图是放在磁盘块里的,假设是放在一个块里,一个块 4K,每位表示一个数据块,共可以表示 4 * 1024 * 8 = 2^15 个空闲块,由于 1 个数据块是 4K 大小,那么最大可以表示的空间为 2^15 * 4 * 1024 = 2^27 个 byte,也就是 128M。

    也就是说按照上面的结构,如果采用「一个块的位图 + 一系列的块」,外加「一个块的 inode 的位图 + 一系列的 inode 的结构」能表示的最大空间也就 128M,这太少了,现在很多文件都比这个大。

    在 Linux 文件系统,把这个结构称为一个块组,那么有 N 多的块组,就能够表示 N 大的文件。

    下图给出了 Linux Ext2 整个文件系统的结构和块组的内容,文件系统都由大量块组组成,在硬盘上相继排布:

    最前面的第一个块是引导块,在系统启动时用于启用引导,接着后面就是一个一个连续的块组了,块组的内容如下:

    • 超级块,包含的是文件系统的重要信息,比如 inode 总个数、块总个数、每个块组的 inode 个数、每个块组的块个数等等。
    • 块组描述符,包含文件系统中各个块组的状态,比如块组中空闲块和 inode 的数目等,每个块组都包含了文件系统中「所有块组的组描述符信息」。
    • 数据位图和 inode 位图, 用于表示对应的数据块或 inode 是空闲的,还是被使用中。
    • inode 列表,包含了块组中所有的 inode,inode 用于保存文件系统中与各个文件和目录相关的所有元数据。
    • 数据块,包含文件的有用数据。

    你可以会发现每个块组里有很多重复的信息,比如超级块和块组描述符表,这两个都是全局信息,而且非常的重要,这么做是有两个原因:

    • 如果系统崩溃破坏了超级块或块组描述符,有关文件系统结构和内容的所有信息都会丢失。如果有冗余的副本,该信息是可能恢复的。
    • 通过使文件和管理数据尽可能接近,减少了磁头寻道和旋转,这可以提高文件系统的性能。

    不过,Ext2 的后续版本采用了稀疏技术。该做法是,超级块和块组描述符表不再存储到文件系统的每个块组中,而是只写入到块组 0、块组 1 和其他 ID 可以表示为 3、 5、7 的幂的块组中。


    目录的存储

    在前面,我们知道了一个普通文件是如何存储的,但还有一个特殊的文件,经常用到的目录,它是如何保存的呢?

    基于 Linux 一切皆文件的设计思想,目录其实也是个文件,你甚至可以通过 vim 打开它,它也有 inode,inode 里面也是指向一些块。

    和普通文件不同的是,普通文件的块里面保存的是文件数据,而目录文件的块里面保存的是目录里面一项一项的文件信息。

    在目录文件的块中,最简单的保存格式就是列表,就是一项一项地将目录下的文件信息(如文件名、文件 inode、文件类型等)列在表里。

    列表中每一项就代表该目录下的文件的文件名和对应的 inode,通过这个 inode,就可以找到真正的文件。

    目录格式哈希表

    通常,第一项是「.」,表示当前目录,第二项是「..」,表示上一级目录,接下来就是一项一项的文件名和 inode。

    如果一个目录有超级多的文件,我们要想在这个目录下找文件,按照列表一项一项的找,效率就不高了。

    于是,保存目录的格式改成哈希表,对文件名进行哈希计算,把哈希值保存起来,如果我们要查找一个目录下面的文件名,可以通过名称取哈希。如果哈希能够匹配上,就说明这个文件的信息在相应的块里面。

    Linux 系统的 ext 文件系统就是采用了哈希表,来保存目录的内容,这种方法的优点是查找非常迅速,插入和删除也较简单,不过需要一些预备措施来避免哈希冲突。

    目录查询是通过在磁盘上反复搜索完成,需要不断地进行 I/O 操作,开销较大。所以,为了减少 I/O 操作,把当前使用的文件目录缓存在内存,以后要使用该文件时只要在内存中操作,从而降低了磁盘操作次数,提高了文件系统的访问速度。


    软链接和硬链接

    有时候我们希望给某个文件取个别名,那么在 Linux 中可以通过硬链接(Hard Link软链接(Symbolic Link 的方式来实现,它们都是比较特殊的文件,但是实现方式也是不相同的。

    硬链接是多个目录项中的「索引节点」指向一个文件,也就是指向同一个 inode,但是 inode 是不可能跨越文件系统的,每个文件系统都有各自的 inode 数据结构和列表,所以硬链接是不可用于跨文件系统的。由于多个目录项都是指向一个 inode,那么只有删除文件的所有硬链接以及源文件时,系统才会彻底删除该文件。

    硬链接

    软链接相当于重新创建一个文件,这个文件有独立的 inode,但是这个文件的内容是另外一个文件的路径,所以访问软链接的时候,实际上相当于访问到了另外一个文件,所以软链接是可以跨文件系统的,甚至目标文件被删除了,链接文件还是在的,只不过指向的文件找不到了而已。

    软链接


    文件 I/O

    文件的读写方式各有千秋,对于文件的 I/O 分类也非常多,常见的有

    • 缓冲与非缓冲 I/O
    • 直接与非直接 I/O
    • 阻塞与非阻塞 I/O VS 同步与异步 I/O

    接下来,分别对这些分类讨论讨论。

    缓冲与非缓冲 I/O

    文件操作的标准库是可以实现数据的缓存,那么根据「是否利用标准库缓冲」,可以把文件 I/O 分为缓冲 I/O 和非缓冲 I/O

    • 缓冲 I/O,利用的是标准库的缓存实现文件的加速访问,而标准库再通过系统调用访问文件。
    • 非缓冲 I/O,直接通过系统调用访问文件,不经过标准库缓存。

    这里所说的「缓冲」特指标准库内部实现的缓冲。

    比方说,很多程序遇到换行时才真正输出,而换行前的内容,其实就是被标准库暂时缓存了起来,这样做的目的是,减少系统调用的次数,毕竟系统调用是有 CPU 上下文切换的开销的。

    直接与非直接 I/O

    我们都知道磁盘 I/O 是非常慢的,所以 Linux 内核为了减少磁盘 I/O 次数,在系统调用后,会把用户数据拷贝到内核中缓存起来,这个内核缓存空间也就是「页缓存」,只有当缓存满足某些条件的时候,才发起磁盘 I/O 的请求。

    那么,根据是「否利用操作系统的缓存」,可以把文件 I/O 分为直接 I/O 与非直接 I/O

    • 直接 I/O,不会发生内核缓存和用户程序之间数据复制,而是直接经过文件系统访问磁盘。
    • 非直接 I/O,读操作时,数据从内核缓存中拷贝给用户程序,写操作时,数据从用户程序拷贝给内核缓存,再由内核决定什么时候写入数据到磁盘。

    如果你在使用文件操作类的系统调用函数时,指定了 O_DIRECT 标志,则表示使用直接 I/O。如果没有设置过,默认使用的是非直接 I/O。

    如果用了非直接 I/O 进行写数据操作,内核什么情况下才会把缓存数据写入到磁盘?

    以下几种场景会触发内核缓存的数据写入磁盘:

    • 在调用 write 的最后,当发现内核缓存的数据太多的时候,内核会把数据写到磁盘上;
    • 用户主动调用 sync,内核缓存会刷到磁盘上;
    • 当内存十分紧张,无法再分配页面时,也会把内核缓存的数据刷到磁盘上;
    • 内核缓存的数据的缓存时间超过某个时间时,也会把数据刷到磁盘上;

    阻塞与非阻塞 I/O VS 同步与异步 I/O

    为什么把阻塞 / 非阻塞与同步与异步放一起说的呢?因为它们确实非常相似,也非常容易混淆,不过它们之间的关系还是有点微妙的。

    先来看看阻塞 I/O,当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。

    注意,阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程。过程如下图:

    阻塞 I/O

    知道了阻塞 I/O ,来看看非阻塞 I/O,非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read 调用才可以获取到结果。过程如下图:

    非阻塞 I/O

    注意,这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。

    举个例子,访问管道或 socket 时,如果设置了 O_NONBLOCK 标志,那么就表示使用的是非阻塞 I/O 的方式访问,而不做任何设置的话,默认是阻塞 I/O。

    应用程序每次轮询内核的 I/O 是否准备好,感觉有点傻乎乎,因为轮询的过程中,应用程序啥也做不了,只是在循环。

    为了解决这种傻乎乎轮询方式,于是 I/O 多路复用技术就出来了,如 select、poll,它是通过 I/O 事件分发,当内核数据准备好时,再以事件通知应用程序进行操作。

    这个做法大大改善了应用进程对 CPU 的利用率,在没有被通知的情况下,应用进程可以使用 CPU 做其他的事情。

    下图是使用 select I/O 多路复用过程。注意,read 获取数据的过程(数据从内核态拷贝到用户态的过程),也是一个同步的过程,需要等待:

    I/O 多路复用

    实际上,无论是阻塞 I/O、非阻塞 I/O,还是基于非阻塞 I/O 的多路复用都是同步调用。因为它们在 read 调用时,内核将数据从内核空间拷贝到应用程序空间,过程都是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read 调用就会在这个同步过程中等待比较长的时间。

    而真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待。

    当我们发起 aio_read 之后,就立即返回,内核自动将数据从内核空间拷贝到应用程序空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。过程如下图:

    异步 I/O

    下面这张图,总结了以上几种 I/O 模型:

    在前面我们知道了,I/O 是分为两个过程的:

    1. 数据准备的过程
    2. 数据从内核空间拷贝到用户进程缓冲区的过程

    阻塞 I/O 会阻塞在「过程 1 」和「过程 2」,而非阻塞 I/O 和基于非阻塞 I/O 的多路复用只会阻塞在「过程 2」,所以这三个都可以认为是同步 I/O。

    异步 I/O 则不同,「过程 1 」和「过程 2 」都不会阻塞。

    用故事去理解这几种 I/O 模型

    举个你去饭堂吃饭的例子,你好比用户程序,饭堂好比操作系统。

    阻塞 I/O 好比,你去饭堂吃饭,但是饭堂的菜还没做好,然后你就一直在那里等啊等,等了好长一段时间终于等到饭堂阿姨把菜端了出来(数据准备的过程),但是你还得继续等阿姨把菜(内核空间)打到你的饭盒里(用户空间),经历完这两个过程,你才可以离开。

    非阻塞 I/O 好比,你去了饭堂,问阿姨菜做好了没有,阿姨告诉你没,你就离开了,过几十分钟,你又来饭堂问阿姨,阿姨说做好了,于是阿姨帮你把菜打到你的饭盒里,这个过程你是得等待的。

    基于非阻塞的 I/O 多路复用好比,你去饭堂吃饭,发现有一排窗口,饭堂阿姨告诉你这些窗口都还没做好菜,等做好了再通知你,于是等啊等(select 调用中),过了一会阿姨通知你菜做好了,但是不知道哪个窗口的菜做好了,你自己看吧。于是你只能一个一个窗口去确认,后面发现 5 号窗口菜做好了,于是你让 5 号窗口的阿姨帮你打菜到饭盒里,这个打菜的过程你是要等待的,虽然时间不长。打完菜后,你自然就可以离开了。

    异步 I/O 好比,你让饭堂阿姨将菜做好并把菜打到饭盒里后,把饭盒送到你面前,整个过程你都不需要任何等待。


    迟到理由

    是的,小林依然迟到了,因为最近发生了一件非常倒霉的事情,我之前使用的图床挂掉了……

    这就导致我所有文章的图片都挂了,好在大部分博客平台都会转存图片,所以微信公众号、CSDN、知乎等平台都正常,但我的本地文章笔记和博客园平台的图片都挂掉了,在博客园还有个读者私信提醒我的文章图片挂了,他很喜欢小林文章,希望早点恢图片,太感动了。

    这就是白嫖免费图床的下场,本打算换阿里云图床,但阿里云图床是按访问流量收费的,如果有人搞你,那直接刷爆你的钱包,想想都可怕,小林穷搞不起搞不起。

    后来,询问了一位朋友 guide 哥,他说可以使用 GitHub 作为图床,用开源工具 Picgo 关联 GitHub 上传图片,再通过 jsdelivr CDN 加速访问,这一套组合很完美,于是我就采用了此方案搭建了自己的图床,依旧继续白嫖,我就不信 GitHub 也挂!

    图床虽然搞定了,最糟糕的事情才开始,我要把以前近 500 张的图片重新保存(以前有的图片丢了)和分类,并一个一个上传到 Github,接着还得把图片的新地址改到本地文章,这工作量简直要命,到现在我也才搞定了操作系统篇的图片,网络篇的图片还有 2/3 没弄完,瞬间后悔自己画那么多图。

    唉,发完这篇文章,小林还得继续恢复图片……

    最近,我都在 B 站学习操作系统,但有时候是想看操作系统,但奈何 B 站首页推送太丰富,看着看着半天就过去了,甚至还花了一天时间专门看一个 UP 主解说「火影忍者」动漫全集,于是就这么忘了文章的事情,哈哈哈。

    不过,确实很过瘾,毕竟偷的了忙中闲,方能人上人嘛。

    好了,小林是专为大家图解的工具人,我们下次见!


    好文推荐

    凉了!张三同学没答好「进程间通信」,被面试官挂了…

    万粉福利,300 页图解网络 PDF 打包送你

    展开全文
  • moosefs使用辅助文件系统,恢复文件

    万次阅读 2020-11-19 10:15:16
    文章目录一 查看moosefs垃圾回收时间二 挂载moosefs辅助文件系统三 undel恢复文件1 单文件恢复2 多文件批量恢复 moosefs文件系统,client客户端误删除或丢失的文件是可以通过moosefs的文件辅助系统恢复的。 一 查看...

    moosefs文件系统,client客户端误删除或丢失的文件是可以通过moosefs的文件辅助系统恢复的。

    一 查看moosefs垃圾回收时间

    回收时间是一个文件被删除后还能保留的时间, 单位是秒, 如果被删除的文件过了回收时间,就没法再恢复了,所以第一点要先查看moosefs的文件回收时间

    在客服端使用mfsgettrashtime命令,查看moosefs文件的回收清空时间
    在这里插入图片描述

    上图mfs文件的回收时间是 86400秒,也就是24小时。 mfsdata是我的mfs挂载目录。

    如果你想自己设置回收时间的话,使用mfssettrashtime [time] [dir]


    二 挂载moosefs辅助文件系统

    moosefs的辅助文件系统,可以看成是你客户端的mfs回收站(以下简称mfs回收站)可以通过挂载这个文件系统,恢复文件。

    不同客户端里的mfs回收站里的内容是不一样的。比如你在10机器上删除的文件,只能通过10上的mfs回收站恢复,11上的mfs回收站只包含本机上删除的文件,10上删除的只能去10恢复。

    开始挂载moosefs回收站, 和挂载moosefs文件系统类似。

    mkdir /home/roo/mfsmeta  (新建一个空目录作为mfs回收站)
    
    mfsmount -m /home/roo/mfsmeta -H 192.168.0.21  (192.168.0.21 是我的moosfs master主机IP)
    
    cd /home/roo/mfsmeta 
    

    进入到mfsmeta之后,查看mfsmeta的文件结构。如图:
    在这里插入图片描述

    你也可以使用tree查看,因为我删除的文件太多了,这里就不放tree目录结构图了。

    如果你在查看文件的时候,报了如下错误:

    ls: error while loading shared libraries: libfuse.so.2: cannot open shared object file: No such file or directory
    

    解决方法:输入以下命令更新/etc/ld.so.conf即可:

    sudo ldconfig
    

    mfsmeta里基本上就是 sustainedtrash 这两个文件夹, 可能还有 reserved

    sustained, reserved里面是已经删除的但是仍然被其他用户一直打开的文件,在其他用户释放后就会被删除,不是我们的目标,不用管这两个文件夹。

    我们的目标是trash 文件夹, 它包含这所有在本机上被删除的mfs文件

    trash 的里面 只有两类文件, 第一类是包含被删除信息的文件夹,第二类是undel文件夹,我们主要就是通过undel文件夹恢复被删除文件的。
    在这里插入图片描述

    上图就是trash里的内容, 这些文件夹都包含着被删除的文件, moosefs使用了十六进制统一管理这些目录,进入其中一个文件夹:
    在这里插入图片描述

    这些就是被删除掉的文件。这里面还有一个undel将被删除的文件mv到undel里就可以实现文件的恢复


    三 undel恢复文件

    1 单文件恢复

    如果你只要恢复一两个文件, 直接在…/trash/文件夹下面 find 文件名 寻找到文件所在目录,进入后将指定文件mv 到 当前目录下的undel里即可恢复,如图:
    先创建一个测试文件,然后删除
    在这里插入图片描述

    cd 进入 …/xxx/trash/ 进行恢复:
    在这里插入图片描述

    查看恢复结果:
    在这里插入图片描述

    2 多文件批量恢复

    如果我们是误操作 rm -rf 删除了很多文件, 一个个恢复简直不可能。
    我尝试了 mv ??? ./undel 将trash目录下所有非undel的都已移入到undel里,结果不可行,
    又尝试 mv 001 undel 将trash目录下的一个文件夹001移入到undel里,也不行。

    看来只能是像单文件恢复那样操作恢复了。

    于是我花5分钟写了个python脚本,实现了批量恢复.

    # coding=utf-8
    
    """
    Author: rpl
    
    date: 19-10-30 下午2:19
    desc:file mv to undel
    """
    
    import os
    import shutil
    import traceback
    
    parent_dir = '/home/roo/mfsmeta/trash/'  # 替换成你自己的路径
    
    sub_dir_list = []
    err_list = []
    
    for name in os.listdir(parent_dir):
        if name != 'undel':
            sub_dir = os.path.join(parent_dir, name)
            sub_dir_list.append(sub_dir)
    
            ssub_undel = os.path.join(sub_dir, 'undel')
            for name2 in os.listdir(sub_dir):
                if name2 != 'undel':
                    ssub_file = os.path.join(sub_dir, name2)
                    try:
                        shutil.move(ssub_file, ssub_undel)
                        print('{} is ok'.format(ssub_file))
                    except:
                        print(traceback.format_exc())
    
                        err_list.append(ssub_file)
    
    print()
    print('------ err file list -----')
    for i in err_list:  # 打印出所有执行失败的文件
        print(i)
    

    效果很好,一次就成功恢复了所有误删的文件。如图:
    在这里插入图片描述

    脚本打印出了一些恢复失败的错误信息,
    在这里插入图片描述

    最后结尾统计了恢复失败的文件:
    在这里插入图片描述

    可以看到恢复失败的都是.pyc文件,以及回收箱里的文件,都是非目标文件。

    如果脚本一次执行没有全部恢复,可以多执行几遍。

    展开全文
  • Linux文件系统详解

    万次阅读 多人点赞 2019-05-29 16:07:53
    从操作系统的角度详解Linux文件系统层次、文件系统分类、文件系统的存储结构、不同存储介质的区别(RAM、ROM、Flash)、存储节点inode。本文参考: http://blog.chinaunix.net/uid-8698570-id-1763151.html ...

    从操作系统的角度详解Linux文件系统层次、文件系统分类、文件系统的存储结构、不同存储介质的区别(RAM、ROM、Flash)、存储节点inode。本文参考:

    http://blog.chinaunix.net/uid-8698570-id-1763151.html
    http://www.iteye.com/topic/816268
    http://soft.chinabyte.com/os/142/12315142.shtml
    http://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/
    http://blog.csdn.net/kension/article/details/3796603
    http://www.360doc.com/content/11/0915/17/3200886_148505332.shtml
    在LINUX系统中有一个重要的概念:一切都是文件。 其实这是UNIX哲学的一个体现,而Linux是重写UNIX而来,所以这个概念也就传承了下来。在UNIX系统中,把一切资源都看作是文件,包括硬件设备。UNIX系统把每个硬件都看成是一个文件,通常称为设备文件,这样用户就可以用读写文件的方式实现对硬件的访问。这样带来优势也是显而易见的:
    UNIX 权限模型也是围绕文件的概念来建立的,所以对设备也就可以同样处理了。
    在这里插入图片描述

    1. 硬盘驱动

    常见的硬盘类型有PATA, SATA和AHCI等,在Linux系统中,对不同硬盘所提供的驱动模块一般都存放在内核目录树drivers/ata中,而对于一般通用的硬盘驱动,也许会直接被编译到内核中,而不会以模块的方式出现,可以通过查看/boot/config-xxx.xxx文件来确认:

    CONFIG_SATA_AHCI=y

    1. General Block Device Layer

    这一层的作用,正是解答了上面提出的第一个问题,不同的硬盘驱动,会提供不同的IO接口,内核认为这种杂乱的接口,不利于管理,需要把这些接口抽象一下,形成一个统一的对外接口,这样,不管你是什么硬盘,什么驱动,对外而言,它们所提供的IO接口没什么区别,都一视同仁的被看作块设备来处理。

    所以,如果在一层做的任何修改,将会直接影响到所有文件系统,不管是ext3,ext4还是其它文件系统,只要在这一层次做了某种修改,对它们都会产生影响。

    1. 文件系统

    文件系统这一层相信大家都再熟悉不过了,目前大多Linux发行版本默认使用的文件系统一般是ext4,另外,新一代的btrfs也呼之欲出,不管什么样的文件系统,都是由一系列的mkfs.xxx命令来创建,如:

    mkfs.ext4 /dev/sda

    mkfs.btrfs /dev/sdb

    内核所支持的文件系统类型,可以通过内核目录树 fs 目录中的内容来查看。

    1. 虚拟文件系统(VFS)

    Virtual File System这一层,正是用来解决上面提出的第二个问题,试想,当我们通过mkfs.xxx系列命令创建了很多不同的文件系统,但这些文件系统都有各自的API接口,而用户想要的是,不管你是什么API,他们只关心mount/umount,或open/close等操作。

    所以,VFS就把这些不同的文件系统做一个抽象,提供统一的API访问接口,这样,用户空间就不用关心不同文件系统中不一样的API了。VFS所提供的这些统一的API,再经过System Call包装一下,用户空间就可以经过SCI的系统调用来操作不同的文件系统。

    VFS所提供的常用API有:

    mount(), umount() …

    open(),close() …

    mkdir() …
    和文件系统关系最密切的就是存储介质,存储介质大致有RAM,ROM,磁盘磁带,闪存等。

    闪存(Flash Memory)是一种长寿命的非易失性(在断电情况下仍能保持所存储的数据信息)的存储器,数据删除不是以单个的字节为单位而是以固定的区块为单位(注意:NOR Flash 为字节存储。),区块大小一般为256KB到20MB。闪存是电子可擦除只读存储器(EEPROM)的变种,EEPROM与闪存不同的是,它能在字节水平上进行删除和重写而不是整个芯片擦写,这样闪存就比EEPROM的更新速度快。由于其断电时仍能保存数据,闪存通常被用来保存设置信息,如在电脑的BIOS(基本输入输出程序)、PDA(个人数字助理)、数码相机中保存资料等。
    外存通常是磁性介质或光盘,像硬盘,软盘,磁带,CD等,能长期保存信息,并且不依赖于电来保存信息,但是由机械部件带动,速度与CPU相比就显得慢的多。内存指的就是主板上的存储部件,是CPU直接与之沟通,并用其存储数据的部件,存放当前正在使用的(即执行中)的数据和程序,它的物理实质就是一组或多组具备数据输入输出和数据存储功能的集成电路,内存只用于暂时存放程序和数据,一旦关闭电源或发生断电,其中的程序和数据就会丢失。
    RAM又分为动态的和静态。。静态被用作cache,动态的常用作内存。。网上说闪存不能代替DRAM是因为闪存不像RAM(随机存取存储器)一样以字节为单位改写数据,因此不能取代RAM。这个以后可以了解下硬件的知识再来辨别.

    Linux下的文件系统结构如下:
    在这里插入图片描述
    Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。
      不同的文件系统类型有不同的特点,因而根据存储设备的硬件特性、系统需求等有不同的应用场合。在嵌入式Linux应用中,主要的存储设备为RAM(DRAM, SDRAM)和ROM(常采用FLASH存储器),常用的基于存储设备的文件系统类型包括:jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs等。
      1. 基于FLASH的文件系统
      Flash(闪存)作为嵌入式系统的主要存储媒介,有其自身的特性。Flash的写入操作只能把对应位置的1修改为0,而不能把0修改为1(擦除Flash就是把对应存储块的内容恢复为1),因此,一般情况下,向Flash写入内容时,需要先擦除对应的存储区间,这种擦除是以块(block)为单位进行的。
     闪存主要有NOR和NAND两种技术。Flash存储器的擦写次数是有限的,NAND闪存还有特殊的硬件接口和读写时序。因此,必须针对Flash的硬件特性设计符合应用要求的文件系统;传统的文件系统如ext2等,用作Flash的文件系统会有诸多弊端。
      在嵌入式Linux下,MTD(Memory Technology Device,存储技术设备)为底层硬件(闪存)和上层(文件系统)之间提供一个统一的抽象接口,即Flash的文件系统都是基于MTD驱动层的(参见上面的Linux下的文件系统结构图)。使用MTD驱动程序的主要优点在于,它是专门针对各种非易失性存储器(以闪存为主)而设计的,因而它对Flash有更好的支持、管理和基于扇区的擦除、读/写操作接口。
      顺便一提,一块Flash芯片可以被划分为多个分区,各分区可以采用不同的文件系统;两块Flash芯片也可以合并为一个分区使用,采用一个文件系统。即文件系统是针对于存储器分区而言的,而非存储芯片。
      (1) jffs2
      JFFS文件系统最早是由瑞典Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS2是RedHat公司基于JFFS开发的闪存文件系统,最初是针对RedHat公司的嵌入式产品eCos开发的嵌入式文件系统,所以JFFS2也可以用在Linux, uCLinux中。
      Jffs2: 日志闪存文件系统版本2 (Journalling Flash FileSystem v2)
      主要用于NOR型闪存,基于MTD驱动层,特点是:可读写的、支持数据压缩的、基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。
      目前jffs3正在开发中。关于jffs系列文件系统的使用详细文档,可参考MTD补丁包中mtd-jffs-HOWTO.txt。
      jffsx不适合用于NAND闪存主要是因为NAND闪存的容量一般较大,这样导致jffs为维护日志节点所占用的内存空间迅速增大,另外,jffsx文件系统在挂载时需要扫描整个FLASH的内容,以找出所有的日志节点,建立文件结构,对于大容量的NAND闪存会耗费大量时间。
       (2) yaffs:Yet Another Flash File System
      yaffs/yaffs2是专为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统。与jffs2相比,它减少了一些功能(例如不支持数据压缩),所以速度更快,挂载时间很短,对内存的占用较小。另外,它还是跨平台的文件系统,除了Linux和eCos,还支持WinCE, pSOS和ThreadX等。
      yaffs/yaffs2自带NAND芯片的驱动,并且为嵌入式系统提供了直接访问文件系统的API,用户可以不使用Linux中的MTD与VFS,直接对文件系统操作。当然,yaffs也可与MTD驱动程序配合使用。
      yaffs与yaffs2的主要区别在于,前者仅支持小页(512 Bytes) NAND闪存,后者则可支持大页(2KB) NAND闪存。同时,yaffs2在内存空间占用、垃圾回收速度、读/写速度等方面均有大幅提升。
      (3) Cramfs:Compressed ROM File System
      Cramfs是Linux的创始人 Linus Torvalds参与开发的一种只读的压缩文件系统。它也基于MTD驱动程序。
      在cramfs文件系统中,每一页(4KB)被单独压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本。
      Cramfs文件系统以压缩方式存储,在运行时解压缩,所以不支持应用程序以XIP方式运行,所有的应用程序要求被拷到RAM里去运行,但这并不代表比Ramfs需求的RAM空间要大一点,因为Cramfs是采用分页压缩的方式存放档案,在读取档案时,不会一下子就耗用过多的内存空间,只针对目前实际读取的部分分配内存,尚没有读取的部分不分配内存空间,当我们读取的档案不在内存时,Cramfs文件系统自动计算压缩后的资料所存的位置,再即时解压缩到RAM中。
      另外,它的速度快,效率高,其只读的特点有利于保护文件系统免受破坏,提高了系统的可靠性。
      由于以上特性,Cramfs在嵌入式系统中应用广泛。
      但是它的只读属性同时又是它的一大缺陷,使得用户无法对其内容对进扩充。?
      Cramfs映像通常是放在Flash中,但是也能放在别的文件系统里,使用loopback 设备可以把它安装别的文件系统里。
      (4) Romfs
      传统型的Romfs文件系统是一种简单的、紧凑的、只读的文件系统,不支持动态擦写保存,按顺序存放数据,因而支持应用程序以XIP(eXecute In Place,片内运行)方式运行,在系统运行时,节省RAM空间。uClinux系统通常采用Romfs文件系统。
      其他文件系统:fat/fat32也可用于实际嵌入式系统的扩展存储器(例如PDA, Smartphone, 数码相机等的SD卡),这主要是为了更好的与最流行的Windows桌面操作系统相兼容。ext2也可以作为嵌入式Linux的文件系统,不过将它用于FLASH闪存会有诸多弊端。
      2. 基于RAM的文件系统
      (1) Ramdisk
      Ramdisk是将一部分固定大小的内存当作分区来使用。它并非一个实际的文件系统,而是一种将实际的文件系统装入内存的机制,并且可以作为根文件系统。将一些经常被访问而又不会更改的文件(如只读的根文件系统)通过Ramdisk放在内存中,可以明显地提高系统的性能。
      在Linux的启动阶段,initrd提供了一套机制,可以将内核映像和根文件系统一起载入内存。
      (2)ramfs/tmpfs
      Ramfs是Linus Torvalds开发的一种基于内存的文件系统,工作于虚拟文件系统(VFS)层,不能格式化,可以创建多个,在创建时可以指定其最大能使用的内存大小。(实际上,VFS本质上可看成一种内存文件系统,它统一了文件在内核中的表示方式,并对磁盘文件系统进行缓冲。)
      Ramfs/tmpfs文件系统把所有的文件都放在RAM中,所以读/写操作发生在RAM中,可以用ramfs/tmpfs来存储一些临时性或经常要修改的数据,例如/tmp和/var目录,这样既避免了对Flash存储器的读写损耗,也提高了数据读写速度。
      Ramfs/tmpfs相对于传统的Ramdisk的不同之处主要在于:不能格式化,文件系统大小可随所含文件内容大小变化。
      Tmpfs的一个缺点是当系统重新引导时会丢失所有数据。
      3. 网络文件系统NFS (Network File System)
      NFS是由Sun开发并发展起来的一项在不同机器、不同操作系统之间通过网络共享文件的技术。在嵌入式Linux系统的开发调试阶段,可以利用该技术在主机上建立基于NFS的根文件系统,挂载到嵌入式设备,可以很方便地修改根文件系统的内容。
      以上讨论的都是基于存储设备的文件系统(memory-based file system),它们都可用作Linux的根文件系统。实际上,Linux还支持逻辑的或伪文件系统(logical or pseudo file system),例如procfs(proc文件系统),用于获取系统信息,以及devfs(设备文件系统)和sysfs,用于维护设备文件。
      附录:NOR闪存与NAND闪存比较
    NOR FLASH
    接口时序同SRAM,易使用
    读取速度较快
    擦除速度慢,以64-128KB的块为单位
    写入速度慢(因为一般要先擦除)
    随机存取速度较快,支持XIP(eXecute In Place,芯片内执行),适用于代码存储。在嵌入式系统中,常用于存放引导程序、根文件系统等。
    单片容量较小,1-32MB
    最大擦写次数10万次

    NAND FLASH
    地址/数据线复用,数据位较窄
    读取速度较慢
    擦除速度快,以8-32KB的块为单位
    写入速度快
    顺序读取速度较快,随机存取速度慢,适用于数据存储(如大容量的多媒体应用)。在嵌入式系统中,常用于存放用户文件系统等。
    单片容量较大,8-128MB,提高了单元密度
    http://bbs.ednchina.com/BLOG_ARTICLE_142972.HTM

    三、文件存储结构

    介绍文件存储结构前先来看看文件系统如何划分磁盘,创建一个文件、目录、链接的过程。

    1.物理磁盘到文件系统
    我们知道文件最终是保存在硬盘上的。硬盘最基本的组成部分是由坚硬金属材料制成的涂以磁性介质的盘片,不同容量硬盘的盘片数不等。每个盘片有两面,都可记录信息。盘片被分成许多扇形的区域,每个区域叫一个扇区,每个扇区可存储128×2的N次方(N=0.1.2.3)字节信息。在DOS中每扇区是128×2的2次方=512字节,盘片表面上以盘片中心为圆心,不同半径的同心圆称为磁道。硬盘中,不同盘片相同半径的磁道所组成的圆柱称为柱面。磁道与柱面都是表示不同半径的圆,在许多场合,磁道和柱面可以互换使用,我们知道,每个磁盘有两个面,每个面都有一个磁头,习惯用磁头号来区分。扇区,磁道(或柱面)和磁头数构成了硬盘结构的基本参数,帮这些参数可以得到硬盘的容量,基计算公式为:
    存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
    要点:
    (1)硬盘有数个盘片,每盘片两个面,每个面一个磁头
    (2)盘片被划分为多个扇形区域即扇区
    (3)同一盘片不同半径的同心圆为磁道
    (4)不同盘片相同半径构成的圆柱面即柱面
    (5)公式: 存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
    (6)信息记录可表示为:××磁道(柱面),××磁头,××扇区
    那么这些空间又是怎么管理起来的呢?unix/linux使用了一个简单的方法。
    它将磁盘块分为以下三个部分:

    1. 超级块,文件系统中第一个块被称为超级块。这个块存放文件系统本身的结构信息。比如,超级块记录了每个区域的大小,超级块也存放未被使用的磁盘块的信息。
    2. I-切点表。超级块的下一个部分就是i-节点表。每个i-节点就是一个对应一个文件/目录的结构,这个结构它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息。一个文件系统维护了一个索引节点的数组,每个文件或目录都与索引节点数组中的唯一一个元素对应。系统给每个索引节点分配了一个号码,也就是该节点在数组中的索引号,称为索引节点号
    3. 数据区。文件系统的第3个部分是数据区。文件的内容保存在这个区域。磁盘上所有块的大小都一样。如果文件包含了超过一个块的内容,则文件内容会存放在多个磁盘块中。一个较大的文件很容易分布上千个独产的磁盘块中。

    Linux正统的文件系统(如ext2、ext3)一个文件由目录项、inode和数据块组成。
    目录项:包括文件名和inode节点号。
    Inode:又称文件索引节点,是文件基本信息的存放地和数据块指针存放地。
    数据块:文件的具体内容存放地。

    Linux正统的文件系统(如ext2、3等)将硬盘分区时会划分出目录块、inode Table区块和data block数据区域。一个文件由一个目录项、inode和数据区域块组成。Inode包含文件的属性(如读写属性、owner等,以及指向数据块的指针),数据区域块则是文件内容。当查看某个文件时,会先从inode table中查出文件属性及数据存放点,再从数据块中读取数据。

    文件存储结构大概如下:
    在这里插入图片描述
    其中目录项的结构如下(每个文件的目录项存储在改文件所属目录的文件内容里):

    图4:目录项结构
    在这里插入图片描述
    其中文件的inode结构如下(inode里所包含的文件信息可以通过stat filename查看得到):
    在这里插入图片描述
    以上只反映大体的结构,linux文件系统本身在不断发展。但是以上概念基本是不变的。且如ext2、ext3、ext4文件系统也存在很大差别,如果要了解可以查看专门的文件系统介绍。
    2. 创建一个文件的过程

    我们从前面可以知道文件的内容和属性是分开存放的,那么又是如何管理它们的呢?现在我们以创建一个文件为例来讲解。
    在命令行输入命令:
    $ who > userlist
    当完成这个命令时。文件系统中增加了一个存放命令who输出内容的新文件userlist,那么这整个过程到底是怎么回事呢?
    文件主要有属性、内容以及文件名三项。内核将文件内容存放在数据区,文件属性存放在i-节点,文件名存放在目录中。
    创建成功一个文件主要有以下四个步骤:

    1.    存储属性 也就是文件属性的存储,内核先找到一块空的i-节点。例如,内核找到i-节点号921130。内核把文件的信息记录其中。如文件的大小、文件所有者、和创建时间等。
      
    2.    存储数据 即文件内容的存储,由于该文件需要3个数据块。因此内核从自由块的列表中找到3个自由块。如600、200、992,内核缓冲区的第一块数据复制到块600,第二和第三分别复制到922和600.
      
    3.    记录分配情况,数据保存到了三个数据块中。所以必须要记录起来,以后再找到正确的数据。分配情况记录在文件的i-节点中的磁盘序号列表里。这3个编号分别放在最开始的3个位置。
      
    4.    添加文件名到目录,新文件的名字是userlist 内核将文件的入口(47,userlist)添加到目录文件里。文件名和i-节点号之间的对应关系将文件名和文件和文件的内容属性连接起来,找到文件名就找到文件的i-节点号,通过i-节点号就能找到文件的属性和内容。
      

    代码具体实现过程参考:
    http://blog.csdn.net/kai_ding/article/details/9206057
    3.创建一个目录的过程

    前面说了创建一个文件的大概过程,也了解文件内容、属性以及入口的保存方式,那么创建一个目录时又是怎么回事呢?
    我现在test目录使用命令mkdir 新增一个子目录child:

    从用户的角度看,目录child是目录test的一个子目录,那么在系统中这层关系是怎么实现的呢?实际上test目录包含一个指向子目录child的i-节点的链接,原理跟普通文件一样,因为目录也是文件。

    目录其实也是文件,只是它的内容比较特殊。所以它的创建过程和文件创建过程一样,只是第二步写的内容不同。

    1.  系统找到空闲的i-节点号887220,写入目录的属性
      
    2.  找到空闲的数据块1002来存储目录的内容,只是目录的内容比较特殊,包含文件名字列表,列表一般包含两个部分:i-节点号和文件名,这个列表其实也就是文件的入口,新建的目录至少包含三个目录”.”和”..”其中”.”指向自己,”..”指向上级目录,我们可以通过比较对应的i-节点号来验证,887270 对应着上级目录中的child对应的i-节点号
      
    3.  记录分配情况。这个和创建文件完全一样
      
    4.  添加目录的入口到父目录,即在父目录中的child入口。
      

    一般都说文件存放在某个目录中,其实目录中存入的只是文件在i-节点表的入口,而文件的内容则存储在数据区。我们一般会说“文件userlist在目录test中”,其实这意味着目录test中有一个指向i-节点921130的链接,这个链接所附加的文件名为userlist,这也可以这样理解:目录包含的是文件的引用,每个引用被称为链接。文件的内容存储在数据块。文件的属性被记录在一个被称为i-节点的结构中。I-节点的编号和文件名关联起来存在目录中。
    注意:其中“.”表示是当前目录。而“…”是当前目录的父目录。但也有特殊情况:如我们查看根目录/的情况:

    发现“.”和“…”都指向i-节点2。实际上当我们用mkfs创建一个文件系统时,mkfs都会将根目录的父目录指向自己。所以根目录下.和…指向同一个i-节点也不奇怪了。
    代码具体实现参考:
    http://blog.csdn.net/kai_ding/article/details/9206057

    1. 理解链接

    我们知道文件都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方;而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块。图 1.展示了程序通过文件名获取文件内容的过程。
    图 1. 通过文件名打开文件
    在这里插入图片描述

    图 1. 通过文件名打开文件

    清单 3. 移动或重命名文件

     # stat /home/harris/source/glibc-2.16.0.tar.xz
      File: `/home/harris/source/glibc-2.16.0.tar.xz'
      Size: 9990512        Blocks: 19520      IO Block: 4096   regular file
    Device: 807h/2055d      Inode: 2485677     Links: 1
    Access: (0600/-rw-------)  Uid: ( 1000/  harris)   Gid: ( 1000/  harris)
    ...
    ...
    # mv /home/harris/source/glibc-2.16.0.tar.xz /home/harris/Desktop/glibc.tar.xz
    # ls -i -F /home/harris/Desktop/glibc.tar.xz
    2485677 /home/harris/Desktop/glibc.tar.xz
    

    在 Linux 系统中查看 inode 号可使用命令 stat 或 ls -i(若是 AIX 系统,则使用命令 istat)。清单 3.中使用命令 mv 移动并重命名文件 glibc-2.16.0.tar.xz,其结果不影响文件的用户数据及 inode 号,文件移动前后 inode 号均为:2485677。
    为解决文件的共享使用,Linux 系统引入了两种链接:硬链接 (hard link) 与软链接(又称符号链接,即 soft link 或 symbolic link)。

    具体关系可以看下图:

    为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。若一个 inode 号对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名(见 图 2.hard link 就是 file 的一个别名,他们有共同的 inode)。硬链接可由命令 link 或 ln 创建。如下是对文件 oldfile 创建硬链接。
    link oldfile newfile
    ln oldfile newfile
    由于硬链接是有着相同 inode 号仅文件名不同的文件,因此硬链接存在以下几点特性:
    文件有相同的 inode 及 data block;
    只能对已存在的文件进行创建;
    不能交叉文件系统进行硬链接的创建;
    不能对目录进行创建,只可对文件创建;
    删除一个硬链接文件并不影响其他有相同 inode 号的文件。

    创建一个链接的步骤大概如下:
    1) 通过原文件的文件名找到文件的i-节点号
    2) 添加文件名关联到目录,新文件的名字是mylink 内核将文件的入口(921130,mylink)添加到目录文件里。
    和创建文件的过程比较发现,链接少了写文件内容的步骤,完全相同的是把文件名关联到目录这一步
    现在.i- 节点号921130对应了两个文件名。链接数也会变成2个,文件的内容并不会发生任何变化。前面我们已经讲了:目录包含的是文件的引用,每个引用被称为链接。所以链接文件和原始文件本质上是一样的,因为它们都是指向同一个i-节点。由于此原因也就可以理解链接的下列特性:你改变其中任何一个文件的内容,别的链接文件也一样是变化;另外如果你删除某一个文件,系统只会在所指向的i-节点上把链接数减1,只有当链接数减为零时才会真正释放i-节点。
    硬链接有两个特点:
    1)不能跨文件系统
    2)不能对目录
    清单 4. 硬链接特性展示

    # ls -li 
     total 0 
    
     // 只能对已存在的文件创建硬连接
     # link old.file hard.link 
     link: cannot create link `hard.link' to `old.file': No such file or directory 
    
     # echo "This is an original file" > old.file 
     # cat old.file 
     This is an original file 
     # stat old.file 
      File: `old.file'
      Size: 25             Blocks: 8          IO Block: 4096   regular file 
     Device: 807h/2055d      Inode: 660650      Links: 2 
     Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root) 
     ... 
     // 文件有相同的 inode 号以及 data block 
     # link old.file hard.link | ls -li 
     total 8 
     660650 -rw-r--r-- 2 root root 25 Sep  1 17:44 hard.link 
     660650 -rw-r--r-- 2 root root 25 Sep  1 17:44 old.file 
    
     // 不能交叉文件系统
     # ln /dev/input/event5 /root/bfile.txt 
     ln: failed to create hard link `/root/bfile.txt' => `/dev/input/event5': 
     Invalid cross-device link 
    
     // 不能对目录进行创建硬连接
     # mkdir -p old.dir/test 
     # ln old.dir/ hardlink.dir 
     ln: `old.dir/': hard link not allowed for directory 
     # ls -iF 
     660650 hard.link  657948 old.dir/  660650 old.file
    

    软链接与硬链接不同,若文件用户数据块中存放的内容是另一文件的路径名的指向,则该文件就是软连接。软链接就是一个普通文件,只是数据块内容有点特殊。软链接有着自己的 inode 号以及用户数据块(见 图 2.)。因此软链接的创建与使用没有类似硬链接的诸多限制:
    软链接有自己的文件属性及权限等;
    可对不存在的文件或目录创建软链接;
    软链接可交叉文件系统;
    软链接可对文件或目录创建;
    创建软链接时,链接计数 i_nlink 不会增加;
    删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接被称为死链接(即 dangling link,若被指向路径文件被重新创建,死链接可恢复为正常的软链接)。
    图 2. 软链接的访问
    在这里插入图片描述
    软链接
    实际上只是一段文字,里面包含着它所指向的文件的名字,系统看到软链接后自动跳到对应的文件位置处进行处理;相反,硬链接为文件开设一个新的目录项,硬链接与文件原有的名字是平权的,在Linux看来它们是等价的。由于这个原因,硬链接不能连接两个不同文件系统上的文件。

    软连接与windows下的快捷方式类似
    至于硬连接,举个例子说吧,你把dir1/file1硬连接到dir2/file2, 就是在dir2下建立一个dir1/file1的镜像文件file2,它与file1是占用一样大的空间的,并且改动两者中的一个,另一个也会发生同样的改动.
    软连接和硬连接可以这样理解:
    硬连接就像一个文件有多个文件名,
    软连接就是产生一个新文件(这个文件内容,实际上就是记当要链接原文件路径的信息),这个文件指向另一个文件的位置,
    硬连接必须在同一文件系统中,而软连接可以跨文件系统
    硬连接 :源文件名和链接文件名都指向相同的物理地址,目录不能够有硬连接,文件在磁盘中只有一个复制,可以节省硬盘空间,由于删除文件要在同一个索引节点属于唯一的连接时才能成功,因此可以防止不必要的误删除软连接(符号连接)用ln -s命令创建文件的符号连接,符号连接是linux特殊文件的一种,作为一个文件,它的资料是它所连接的文件的路径名,类似于硬件方式,可以删除原始文件 而连接文件仍然存在。**
    清单 5. 软链接特性展示

    # ls -li 
     total 0 
    
     // 可对不存在的文件创建软链接
     # ln -s old.file soft.link 
     # ls -liF 
     total 0 
     789467 lrwxrwxrwx 1 root root 8 Sep  1 18:00 soft.link -> old.file 
    
     // 由于被指向的文件不存在,此时的软链接 soft.link 就是死链接
     # cat soft.link 
     cat: soft.link: No such file or directory 
    
     // 创建被指向的文件 old.file,soft.link 恢复成正常的软链接
     # echo "This is an original file_A" >> old.file 
     # cat soft.link 
     This is an original file_A 
    
     // 对不存在的目录创建软链接
     # ln -s old.dir soft.link.dir 
     # mkdir -p old.dir/test 
     # tree . -F --inodes 
     . 
    ├── [ 789497]  old.dir/ 
    │   └── [ 789498]  test/ 
    ├── [ 789495]  old.file 
    ├── [ 789495]  soft.link -> old.file 
    └── [ 789497]  soft.link.dir -> old.dir/
    

    代码具体实现参考:http://blog.csdn.net/kai_ding/article/details/8942884

    四、文件节点inode
    可以看到inode节点好比是文件的大脑,下面就详细介绍一下inode。
    1.inode是什么
    理解inode,要从文件储存说起。
    扇区(sector):硬件(磁盘)上的最小的操作单位,是操作系统和块设备(硬件、磁盘)之间传送数据的单位。
    block由一个或多个sector组成,文件系统中最小的操作单位;OS的虚拟文件系统从硬件设备上读取一个block,实际为从硬件设备读取一个或多个sector。对于文件管理来说,每个文件对应的多个block可能是不连续的;
    block最终要映射到sector上,所以block的大小一般是sector的整数倍。不同的文件系统block可使用不同的大小,操作系统会在内存中开辟内存,存放block到所谓的block buffer中。在Ext2中,物理块的大小是可变化的,这取决于在创建文件系统时的选择,之所以不限制大小,也正体现了Ext2的灵活性和可扩充性。通常,Ext2的物理块占一个或几个连续的扇区,显然,物理块的数目是由磁盘容量等硬件因素决定的。具体文件系统所操作的基本单位是逻辑块,只在需要进行I/O操作时才进行逻辑块到物理块的映射,这显然避免了大量的I/O操作,因而文件系统能够变得高效。逻辑块作为一个抽象的概念,它必然要映射到具体的物理块上去,因此,逻辑块的大小必须是物理块大小的整数倍,一般说来,两者是一样大的。
    通常,一个文件占用的多个物理块在磁盘上是不连续存储的,因为如果连续存储,则经过频繁的删除、建立、移动文件等操作,最后磁盘上将形成大量的空洞,很快磁盘上将无空间可供使用。因此,必须提供一种方法将一个文件占用的多个逻辑块映射到对应的非连续存储的物理块上去,Ext2等类文件系统是用索引节点解决这个问题的。
    在这里插入图片描述在这里插入图片描述
    文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。
    在Unix/Linux上,一个文件由一个inode 表示。inode在系统管理员看来是每一个文件的唯一标识,在系统里面,inode是一个结构,存储了关于这个文件的大部分信息。
    2.inode内容
    inode包含文件的元信息,具体来说有以下内容:
    *文件的字节数
    文件拥有者的UserID文件的GroupID
    *文件的读、写、执行权限
    *文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
    链接数,即有多少文件名指向这个inode文件数据block的位置可以用stat命令,查看某个文件的inode信息:statexample.txt
    总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。
    inode中存储了一个文件的以下信息:
    3.inode结构

    struct inode {
            struct hlist_node       i_hash;              /* 哈希表 */
            struct list_head        i_list;              /* 索引节点链表 */
            struct list_head        i_dentry;            /* 目录项链表 */
            unsigned long           i_ino;               /* 节点号 */
            atomic_t                i_count;             /* 引用记数 */
            umode_t                 i_mode;              /* 访问权限控制 */
            unsigned int            i_nlink;             /* 硬链接数 */
            uid_t                   i_uid;               /* 使用者id */
            gid_t                   i_gid;               /* 使用者id组 */
            kdev_t                  i_rdev;              /* 实设备标识符 */
            loff_t                  i_size;              /* 以字节为单位的文件大小 */
            struct timespec         i_atime;             /* 最后访问时间 */
            struct timespec         i_mtime;             /* 最后修改(modify)时间 */
            struct timespec         i_ctime;             /* 最后改变(change)时间 */
            unsigned int            i_blkbits;           /* 以位为单位的块大小 */
            unsigned long           i_blksize;           /* 以字节为单位的块大小 */
            unsigned long           i_version;           /* 版本号 */
            unsigned long           i_blocks;            /* 文件的块数 */
            unsigned short          i_bytes;             /* 使用的字节数 */
            spinlock_t              i_lock;              /* 自旋锁 */
            struct rw_semaphore     i_alloc_sem;         /* 索引节点信号量 */
            struct inode_operations *i_op;               /* 索引节点操作表 */
            struct file_operations  *i_fop;              /* 默认的索引节点操作 */
            struct super_block      *i_sb;               /* 相关的超级块 */
            struct file_lock        *i_flock;            /* 文件锁链表 */
            struct address_space    *i_mapping;          /* 相关的地址映射 */
            struct address_space    i_data;              /* 设备地址映射 */
            struct dquot            *i_dquot[MAXQUOTAS]; /* 节点的磁盘限额 */
            struct list_head        i_devices;           /* 块设备链表 */
            struct pipe_inode_info  *i_pipe;             /* 管道信息 */
            struct block_device     *i_bdev;             /* 块设备驱动 */
            unsigned long           i_dnotify_mask;      /* 目录通知掩码 */
            struct dnotify_struct   *i_dnotify;          /* 目录通知 */
            unsigned long           i_state;             /* 状态标志 */
            unsigned long           dirtied_when;        /* 首次修改时间 */
            unsigned int            i_flags;             /* 文件系统标志 */
            unsigned char           i_sock;              /* 可能是个套接字吧 */
            atomic_t                i_writecount;        /* 写者记数 */
            void                    *i_security;         /* 安全模块 */
            __u32                   i_generation;        /* 索引节点版本号 */
            union {
                    void            *generic_ip;         /* 文件特殊信息 */
            } u;
    };
    

    inode就是一个文件的一部分描述,不是全部,在内核中,inode对应了这样一个实际存在的结构。
    复制代码
    纵观整个inode的C语言描述,没有发现关于文件名的东西,也就是说文件名不由inode保存,实际上系统是不关心文件名的,对于系统中任何的操作,大部分情况下你都是通过文件名来做的,但系统最终都要通过找到文件对应的inode来操作文件,由inode结构中 *i_op指向的接口来操作。
    文件系统如何存取文件的:
    1)、根据文件名,通过Directory里的对应关系,找到文件对应的Inodenumber
    2)、再根据Inodenumber读取到文件的Inodetable
    3)、再根据Inodetable中的Pointer读取到相应的Blocks
    这里有一个重要的内容,就是Directory,他不是我们通常说的目录,而是一个列表,记录了一个文件/目录名称对应的Inodenumber。

    转自: https://www.cnblogs.com/alantu2018/p/8461749.html

    展开全文
  • Linux文件系统

    万次阅读 2019-03-25 18:49:40
    Linux系统启动时,首先挂载根文件系统,之后可以自动或手动挂载其他的文件系统,这些文件系统要挂载到挂载点上,与虚拟文件系统(Virtual File System)和通用块设备层(General Block Device Layer)建立联系。...
  • linux系统下创建文件系统

    万次阅读 2018-06-16 23:51:04
    任何硬盘和u盘等存储介质都需要建立文件系统之后,才能使用。我们u盘和硬盘之所以跟买的容量不一样,就是因为里面存储着文件系统。没有文件系统,那就是纯粹的硬件,我们是不能使用的。windows中我们可以格式化u盘...
  • 操作系统文件系统题库

    万次阅读 多人点赞 2018-08-02 15:14:47
    网络课课后题 1、UNIX系统中,把输入输出设备看做是 A、普通文件 ...3、文件系统实现文件的按名存取是通过下列哪一项工作完成的? A、文件寻址 B、位示图查找 C、目录项分解 D、文件目录查找 ...
  • FAT32文件系统结构详解

    万次阅读 多人点赞 2018-04-13 15:38:58
    1. SD卡中FAT32文件系统快速入门 1.1. 理论知识 1.1.1. MBR(Main Boot Record) 主引导记录,占446字节, 为计算机启动后从可启动介质上首先装入内存并且执行的代码,通常用来解释分区结构 1.1.2. DBR(DOS Boot ...
  • FATFS 文件系统

    千次阅读 2016-06-18 16:26:08
    1、文件系统是什么? 负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。 即在磁盘上组织文件的方法。 常用的文件系统: -FAT / FATFS -NTFS: 基于安全性的文件系统,是Windows NT所采用的独特的...
  • FAT文件系统详解(二)

    万次阅读 2020-04-02 21:43:46
    上一篇文章主要讨论了硬盘的构造、分区表的含义、每个分区中的划分,虽然是指的FAT16文件系统,其实,也同样适用于FAT32文件系统,因为FAT32是兼容FAT16的,FAT16和FAT32到底差别在哪里? 第一,FAT表表示一个簇号的...
  • 分布式文件系统

    千次阅读 2018-09-05 10:24:44
    相对于本机端的文件系统而言,分布式文件系统(英语:Distributed file system, DFS),或是网络文件系统(英语:Network File System),是一种允许文件通过网络在多台主机上分享的文件系统,可让多机器上的多用户...
  • 操作系统-文件系统

    千次阅读 2019-04-10 17:11:42
    在前面操作系统内核资源管理功能中有三个功能,分别是进程管理、存储器管理和设备管理而唯独没有文件系统的功能,其实在之前是别说操作系统内核就连操作系统中都没有文件系统这个功能的,但随着人们要存储到磁盘上的...
  • 最近在学习hadoop时关于分布式文件系统(hdfs)中的块定义有点模糊,以及它内部与操作系统中物理磁盘块的...而构建于单个磁盘之上的文件系统(linux文件系统)通过磁盘块来管理该文件系统中的块,该文件系统中的文件大小是
  • windows 文件系统

    千次阅读 2018-07-05 22:53:55
    1.什么是文件系统文件系统是操作系统用于明确存储设备(磁盘、固态硬盘)上组织文件的方法。从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。FAT...
  • 一、什么是Linux设备文件系统  首先我们不看定义,定义总是太抽象很难理解,我们先看现象。当我们往开发板上移植了一个新的文件系统之后(假如各种设备驱动也移植好了),启动开发板,我们用串口工具进入开发板,...
  • 嵌入式根文件系统一般都是使用busybox 1.下载 https://busybox.net/ 我没安装git工具,我就直接下载源码了 我们就下载一个19.2的版本 放入linux系统中某个目录,解压 需改顶层Makefile nfs服务器搭建,...
  • 文件系统与数据库系统区别

    万次阅读 2018-10-12 10:29:54
    本文从结构性、数据共享、数据独立、数据冗余介绍文件系统与数据库系统区别: 文件系统把数据组织成相互独立的数据文件,实现了记录内的结构性,但整体无结构;而数据库系统实现整体数据的结构化,也是数据库系统...
  • FAT文件系统详解(一)

    万次阅读 2020-03-30 21:22:20
    我说是为了“虚拟文件系统”管理讲解做铺垫,我一直的想法就是“一定要知道原理,才能做的更远更好”,因为你知道这其中的原理了,之后如果遇到问题了,就不好慌乱,一切让你心慌意乱的事儿都是一些你不能把握的事情...
  • Windows系统常见的文件系统格式

    千次阅读 2019-05-12 08:43:17
    FAT文件系统诞生于1977年,它最初是为软盘设计的文件系统,但是后来随着微软推出dos和win 9x系统,FAT文件系统经过适配被逐渐用到了硬盘上,并且在那时的20年中,一直是主流的文件系统。 后来随着硬件技术的进步...
  • NAS文件系统

    千次阅读 2019-01-18 15:10:23
    NAS是一个可共享访问,弹性扩展,高可靠,高性能的分布式文件系统。它基于 POSIX 文件接口,天然适配原生操作系统,提供共享访问,同时保证数据一致性和锁互斥。 NAS 具有以下特性: 无缝集成 NAS 支持标准的文件...
  • 对linux系统而言,对一个文件系统,如果想要使用它,就必须对其进行挂载,挂载就是将文件系统安装到linux文件系统的某个目录下,这个目录可以自己创建,或则选择linux存在的目录,必须是目录文件就行了,挂载后,这...
  • 一、各种分布式文件系统对比 1.1 表格对比 技术 优点 缺点 总结 1、 HDFS 1、大数据批量读写,吞吐量高; 2、一次写入,多次读取,顺序读写; ...
  • 虚拟化、文件系统、查找文件

    万次阅读 2019-11-27 12:27:27
    文章目录虚拟化虚拟化的概念安装KVM安装gustos了解并配置KVM网络桥接:NAT:仅主机(hostonly):文件系统了解文件系统的概念:了解硬链接的概念:挂载文件系统:查找文件: 虚拟化 虚拟化的概念 虚拟化≠虚拟机 虚拟化...
  • Linux 文件系统类型 磁盘文件系统。 包括硬盘、CD-ROM、DVD、USB存储器、磁盘阵列等。常见文件系统格式有:autofs、coda、Ext(Extended File sytem,扩展文件系统)、Ext2、Ext3、VFAT、ISO9660(通常是CD-ROM...
  • 操作系统概论【五】- - 文件系统

    千次阅读 多人点赞 2020-09-06 17:52:53
    文章目录第五章、文件系统一、文件1. 文件命名2. 文件结构3. 文件类型4. 文件存取5. 文件属性6. 文件操作二、目录1. 目录文件的结构2. 目录结构3. 路径名4. 目录操作三、文件系统的实现1. 实现文件文件存储的4种常用...
  • 常见文件系统

    千次阅读 2016-09-12 21:40:22
    常见文件系统 一、常见嵌入式根文件系统 1、JFFS文件系统 2、Jffs2: 日志闪存嵌入式系统文件系统版本2 (Journalling Flash FileSystem v2) 3、yaffs/yaffs2是专为嵌入式系统使用 NAND型闪存而设计的一种日志...
  • 浅谈linux中的根文件系统(rootfs的原理和介绍)

    万次阅读 多人点赞 2017-10-04 22:37:53
    linux中有一个让很多初学者都不是特别清楚的概念,叫做“根文件系统”。我接触linux前前后后也好几年了,但是对这个问题,至今也不是特别的清楚,至少没法向其他初学者们给出一个很全面很到位的解释。于是,今天我们...
  • Linux系统如何支持NTFS文件系统

    万次阅读 2017-03-16 07:32:35
    由于Linux系统默认是不支持NTFS文件系统的,因此,我们基本不能在Linux系统中挂载NTFS文件系统类型的硬盘或移动硬盘。为此,最主要的问题是如何使Linux系统支持NTFS文件系统。一般情况下,在Linux系统中,我们并不...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 772,874
精华内容 309,149
关键字:

文件系统