Linux文件系统详解

Linux的一切皆文件

Linux 中的各类事物好比像文档、目录(Mac OS X 和 Windows 系统下称之为文件夹)、键盘、监视器、硬盘、可移动媒体设备、打印机、调制解调器、虚拟终端,还有进程间通讯(IPC)和网络通讯等输入/输出资源都是定义在文件系统空间下的字节流。
一切均可看做是文件,其最显著的好处是对于上面所列出的输入/输出资源,只须要相同的一套 Linux 工具、实用程序和 API。你可使用同一套api(read, write)和工具(cat , 重定向, 管道)来处理unix中大多数的资源.
设计一个系统的终极目标每每就是要找到原子操做,一旦锁定了原子操做,设计工做就会变得简单而有序。“文件”做为一个抽象概念,其原子操做很是简单,只有读和写,这无疑是一个很是好的模型。经过这个模型,API的设计能够化繁为简,用户可使用通用的方式去访问任何资源,自有相应的中间件作好对底层的适配。
现代操做系统为解决信息能独立于进程以外被长期存储引入了文件,文件做为进程建立信息的逻辑单元可被多个进程并发使用。在 UNIX 系统中,操做系统为磁盘上的文本与图像、鼠标与键盘等输入设备及网络交互等 I/O 操做设计了一组通用 API,使他们被处理时都可统一使用字节流方式。换言之,UNIX 系统中除进程以外的一切皆是文件,而 Linux 保持了这一特性。为了便于文件的管理,Linux 还引入了目录(有时亦被称为文件夹)这一律念。目录使文件可被分类管理,且目录的引入使 Linux 的文件系统造成一个层级结构的目录树javascript

在Linux系统中,一切都是文件,理解文件系统,对于学习Linux来讲,是一个很是有必要的前提html

Linux上的文件系统通常来讲就是EXT2或EXT3,但这篇文章并不许备一上来就直接讲它们,而但愿结合Linux操做系统并从文件系统创建的基础——硬盘开始,一步步认识Linux的文件系统。前端

1. 机械硬盘的物理存储机制

  • 现代计算机大部分文件存储功能都是由机械硬盘这种设备提供的。(如今的SSD和闪存从概念和逻辑上都部分继承自机械硬盘,因此使用机械硬盘来进行理解也是没有问题的)
  • 机械硬盘能实现信息存储的功能基于:磁性存储介质可以被磁化,且磁化后会长久保留被磁化的状态,这种被磁化状态可以被读取出来,同时这种磁化状态还可以不断被修改,磁化正好有两个方向,因此能够表示0和1。
    因而硬盘就是把这种磁性存储介质作成一个个盘片,每个盘片上都分布着数量巨大的磁性存储单位,使用磁性读写头对盘片进行写入和读取(从原理上相似黑胶唱片的播放)。
  • 一个硬盘中的磁性存储单位数以亿计(1T硬盘就有约80亿个),因此须要一套规则来规划信息如何存取(好比一本存储信息的书咱们还会分为页,每一页从上到下从左到右读取,同时还有章节目录)
    因而就有了这些物理、逻辑概念:
  1. 一个硬盘有多张盘片叠成,不一样盘片有编号
  2. 每张盘片上的存储颗粒成环形一圈圈地排布,每一圈称为磁道,有编号
  3. 每条磁道上都有一圈存储颗粒,每512*8(512字节,0.5KB)个存储颗粒做为一个扇区,扇区是硬盘上存储的最小物理单位
  4. N个扇区能够组成簇,N取决于不一样的文件系统或是文件系统的配置,簇是此文件系统中的最小存储单位
  5. 全部盘面上的同一磁道构成一个圆柱,称为柱面,柱面是系统分区的最小单位

磁头读写文件的时候,首先是分区读写的,由inode编号(区内惟一的编号后面介绍)找到对应的磁道和扇区,而后一个柱面一个柱面地进行读写。机械硬盘的读写控制系统是一个使人叹为观止的精密工程(一个盘面上有几亿个存储单位,每一个磁道宽度不到几十纳米,磁盘每分钟上万转),同时关于读写的逻辑也是有诸多细节(好比扇区的编号并非连续的),很是有意思,能够自行搜索文章拓展阅读。java

有了硬盘并不意味着LInux能够马上把它用来存储,还须要组合进Linux的文件体系才能被Linux使用。node

2.Linux文件体系

Linux以文件的形式对计算机中的数据和硬件资源进行管理,也就是完全的一切皆文件,反映在Linux的文件类型上就是:普通文件、目录文件(也就是文件夹)、设备文件、连接文件、管道文件、套接字文件(数据通讯的接口)等等。而这些种类繁多的文件被Linux使用目录树进行管理, 所谓的目录树就是以根目录(/)为主,向下呈现分支状的一种文件结构。不一样于纯粹的ext2之类的文件系统,我把它称为文件体系,一切皆文件和文件目录树的资源管理方式一块儿构成了Linux的文件体系,让Linux操做系统能够方便使用系统资源。
因此文件系统比文件体系涵盖的内容少不少,Linux文件体系主要在于把操做系统相关的东西用文件这个载体实现:文件系统挂载在操做系统上,操做系统整个系统又放在文件系统里。但本文中文件体系的相关内容不是不少,大部分地方均可以用文件系统代替文件体系。linux

1. Linux中的文件类型:

1.1. 普通文件(-)

从Linux的角度来讲,相似mp四、pdf、html这样应用层面上的文件类型都属于普通文件
Linux用户能够根据访问权限对普通文件进行查看、更改和删除编程

1.2. 目录文件(d,directory file)

目录文件对于用惯Windows的用户来讲不太容易理解,目录也是文件的一种
目录文件包含了各自目录下的文件名和指向这些文件的指针,打开目录事实上就是打开目录文件,只要有访问权限,你就能够随意访问这些目录下的文件(普通文件的执行权限就是目录文件的访问权限),可是只有内核的进程可以修改它们
虽然不能修改,可是咱们可以经过vim去查看目录文件的内容vim

这种类型的文件相似Windows中的快捷方式,是指向另外一个文件的间接指针,也就是咱们常说的软连接api

1.4. 块设备文件(b,block)和字符设备文件(c,char)

这些文件通常隐藏在/dev目录下,在进行设备读取和外设交互时会被使用到
好比磁盘光驱就是块设备文件,串口设备则属于字符设备文件
系统中的全部设备要么是块设备文件,要么是字符设备文件,无一例外安全

1.5. FIFO(p,pipe)

管道文件主要用于进程间通信。好比使用mkfifo命令能够建立一个FIFO文件,启用一个进程A从FIFO文件里读数据,启动进程B往FIFO里写数据,先进先出,随写随读。

1.6. 套接字(s,socket)

用于进程间的网络通讯,也能够用于本机之间的非网络通讯
这些文件通常隐藏在/var/run目录下,证实着相关进程的存在

Linux 的文件是没有所谓的扩展名的,一个 Linux文件能不能被执行与它是否可执行的属性有关,只要你的权限中有 x ,好比[ -rwx-r-xr-x ] 就表明这个文件能够被执行,与文件名没有关系。跟在 Windows下能被执行的文件扩展名一般是 .com .exe .bat 等不一样。
不过,能够被执行跟能够执行成功不同。好比在 root 主目彔下的 install.log 是一个文本文件,修改权限成为 -rwxrwxrwx 后这个文件可以真的执行成功吗? 固然不行,由于它的内容根本就没有能够执行的数据。因此说,这个 x 表明这个文件具备可执行的能力, 可是能不能执行成功,固然就得要看该文件的内容了。
虽然如此,不过咱们仍然但愿能从扩展名来了解该文件是什么东西,因此通常咱们仍是会以适当的扩展名来表示该文件是什么种类的。
因此Linux 系统上的文件名真的只是让你了解该文件可能的用途而已, 真正的执行与否仍然须要权限的规范才行。好比常见的/bin/ls 这个显示文件属性的指令要是权限被修改成没法执行,那么ls 就变成不能执行了。这种问题最常发生在文件传送的过程当中。例如你在网络上下载一个可执行文件,可是恰恰在你的 Linux 系统中就是没法执行,那就多是档案的属性被改变了。并且从网络上传送到你 的 Linux 系统中,文件的属性权限确实是会被改变的

2. Linux目录树

对Linux系统和用户来讲,全部可操做的计算机资源都存在于目录树这个逻辑结构中,对计算机资源的访问均可以认为是目录树的访问。就硬盘来讲,全部对硬盘的访问都变成了对目录树中某个节点也就是文件夹的访问,访问时不须要知道它是硬盘仍是硬盘中的文件夹。
目录树的逻辑结构也很是简单,就是从根目录(/)开始,不断向下展开各级子目录。

3.硬盘分区

硬盘分区是硬盘结合到文件体系的第一步,本质是「硬盘」这个物理概念转换成「区」这个逻辑概念,为下一步格式化作准备。
因此分自己并非必须的,你彻底能够把一整块硬盘做为一个区。但从数据的安全性以及系统性能角度来看,分区仍是有不少用处的,因此通常都会对硬盘进行分区。

讲分区就不得不先提每块硬盘上最重要的第一扇区,这个扇区中有硬盘主引导记录(Master boot record, MBR) 及分区表(partition table), 其中 MBR 占有 446 bytes,而分区表占有 64 bytes。硬盘主引导记录放有最基本的引导加载程序,是系统开机启动的关键环节,在附录中有更详细的说明。而分区表则跟分区有关,它记录了硬盘分区的相关信息,但因分区表仅有 64bytes , 因此最多只能记彔四块分区(分区自己其实就是对分区表进行设置)。

只能分四个区实在太少了,因而就有了扩展分区的概念,既然第一个扇区所在的分区表只能记录四条数据, 那我能否利用额外的扇区来记录更多的分区信息。
把普通能够访问的分区称为主分区,扩展分区不一样于主分区,它自己并无内容,它是为进一步逻辑分区提供空间的。在某块分区指定为扩展分区后,就能够对这块扩展分区进一步分红多个逻辑分区。操做系统规定:

  1. 四块分区每块均可以是主分区或扩展分区
  2. 扩展分区最多只能有一个(也不必有多个)
  3. 扩展分区能够进一步分割为多个逻辑分区
  4. 扩展分区只是逻辑概念,自己不能被访问,也就是不能被格式化后做为数据访问的分区,可以做为数据访问的分区只有主分区和逻辑分区
  5. 逻辑分区的数量依操做系统而不一样,在 Linux 系统中,IDE 硬盘最多有 59 个逻辑分区(5 号到 63 号), SATA 硬盘则有 11 个逻辑分区(5 号到 15 号)
    通常给硬盘进行分区时,一个主分区一个扩展分区,而后把扩展分区划分为N个逻辑分区是最好的

是否能够不要主分区呢?不知道,但好像不用管,你建立分区的时候会自动给你配置类型
特殊的,你最好单独分一个swap区(内存置换空间),它独为一类,功能是:当有数据被存放在物理内存里面,可是这些数据又不是常被 CPU 所取用时,那么这些不常被使用的程序将会被丢到硬盘的 swap 置换空间当中, 而将速度较快的物理内存空间释放出来给真正须要的程序使用

4.格式化

咱们知道Linux操做系统支持不少不一样的文件系统,好比ext二、ext三、XFS、FAT等等,而Linux把对不一样文件系统的访问交给了VFS(虚拟文件系统),VFS能访问和管理各类不一样的文件系统。因此有了区以后就须要把它格式化成具体的文件系统以便VFS访问。

标准的Linux文件系统Ext2是使用「基于inode的文件系统」

咱们知道通常操做系统的文件数据除了文件实际内容外, 还带有不少属性,例如 Linux 操做系统的文件权限(rwx)与文件属性(拥有者、群组、 时间参数等),文件系统一般会将属性和实际内容这两部分数据分别存放在不一样的区块
在基于inode的文件系统中,权限与属性放置到 inode 中,实际数据放到 data block 区块中,并且inode和data block都有编号
Ext2 文件系统在此基础上

文件系统最前面有一个启动扇区(boot sector)
这个启动扇区能够安装开机管理程序, 这个设计让咱们能将不一样的引导装载程序安装到个别的文件系统前端,而不用覆盖整个硬盘惟一的MBR, 也就是这样才能实现多重引导的功能
把每一个区进一步分为多个块组 (block group),每一个块组有独立的inode/block体系
若是文件系统高达数百 GB 时,把全部的 inode 和block 统统放在一块儿会由于 inode 和 block的数量太庞大,不容易管理
这其实很好理解,由于分区是用户的分区,实际计算机管理时还有个最适合的大小,因而计算机会进一步的在分区中分块
(但这样岂不是可能出现大文件放不了的问题?有什么机制善后吗?)
每一个块组实际还会分为分为6个部分,除了inode table 和 data block外还有4个附属模块,起到优化和完善系统性能的做用
因此整个分区大概会这样划分:

1. inode table

主要记录文件的属性以及该文件实际数据是放置在哪些block中,它记录的信息至少有这些:
大小、真正内容的block号码(一个或多个)
访问模式(read/write/excute)
拥有者与群组(owner/group)
各类时间:创建或状态改变的时间、最近一次的读取时间、最近修改的时间
没有文件名!文件名在目录的block中!
一个文件占用一个 inode,每一个inode有编号
Linux 系统存在 inode 号被用完但磁盘空间还有剩余的状况
注意,这里的文件不仅仅是普通文件,目录文件也就是文件夹其实也是一个文件,还有其余的也是
inode 的数量与大小在格式化时就已经固定了,每一个inode 大小均固定为128 bytes (新的ext4 与xfs 可设定到256 bytes)
文件系统可以创建的文件数量与inode 的数量有关,存在空间还够但inode不够的状况
系统读取文件时须要先找到inode,并分析inode 所记录的权限与使用者是否符合,若符合才可以开始实际读取 block 的内容
inode 要记录的资料很是多,但恰恰又只有128bytes , 而inode 记录一个block 号码要花掉4byte ,假设我一个文件有400MB 且每一个block 为4K 时, 那么至少也要十万条block 号码的记录!inode 哪有这么多空间来存储?为此咱们的系统很聪明的将inode 记录block 号码的区域定义为12个直接,一个间接, 一个双间接与一个三间接记录区(详细见附录)

2. data block

放置文件内容数据的地方
在格式化时block的大小就固定了,且每一个block都有编号,以方便inode的记录
原则上,block 的大小与数量在格式化完就不可以再改变了(除非从新格式化)
在Ext2文件系统中所支持的block大小有1K, 2K及4K三种,因为block大小的区别,会致使该文件系统可以支持的最大磁盘容量与最大单一文件容量各不相同:
Block 大小 1KB 2KB 4KB
最大单一档案限制 16GB 256GB 2TB
最大档案系统总容量 2TB 8TB 16TB
每一个block 内最多只可以放置一个文件的资料,但一个文件能够放在多个block中(大的话)
若文件小于block ,则该block 的剩余容量就不可以再被使用了(磁盘空间会浪费)
因此若是你的档案都很是小,可是你的block 在格式化时却选用最大的4K 时,可能会产生容量的浪费
既然大的block 可能会产生较严重的磁碟容量浪费,那么咱们是否就将block 大小定为1K ?这也不妥,由于若是block 较小的话,那么大型档案将会占用数量更多的block ,而inode 也要记录更多的block 号码,此时将可能致使档案系统不良的读写效能
事实上如今的磁盘容量都太大了,因此通常都会选择4K 的block 大小

3. superblock

记录整个文件系统相关信息的地方,通常大小为1024bytes,记录的信息主要有:
block 与inode 的总量
未使用与已使用的inode / block 数量
一个valid bit 数值,若此文件系统已被挂载,则valid bit 为0 ,若未被挂载,则valid bit 为1
block 与inode 的大小 (block 为1, 2, 4K,inode 为128bytes 或256bytes);
其余各类文件系统相关信息:filesystem 的挂载时间、最近一次写入资料的时间、最近一次检验磁碟(fsck) 的时间
Superblock是很是重要的, 没有Superblock ,就没有这个文件系统了,所以若是superblock死掉了,你的文件系统可能就须要花费不少时间去挽救
每一个块均可能含有superblock,可是咱们也说一个文件系统应该仅有一个superblock 而已,那是怎么回事?事实上除了第一个块内会含有superblock 以外,后续的块不必定含有superblock,而若含有superblock则该superblock主要是作为第一个块内superblock的备份,这样能够进行superblock的救援

4. Filesystem Description

文件系统描述
这个区段能够描述每一个block group的开始与结束的block号码,以及说明每一个区段(superblock, bitmap, inodemap, data block)分别介于哪个block号码之间

5. block bitmap

块对照表
若是你想要新增文件时要使用哪一个block 来记录呢?固然是选择「空的block」来记录。那你怎么知道哪一个block 是空的?这就得要经过block bitmap了,它会记录哪些block是空的,所以咱们的系统就可以很快速的找到可以使用的空间来记录
一样在你删除某些文件时,那些文件本来占用的block号码就得要释放出来, 此时在block bitmap 中对应该block号码的标志位就得要修改为为「未使用中」

6. inode bitmap

与block bitmap 是相似的功能,只是block bitmap 记录的是使用与未使用的block 号码, 至于inode bitmap 则是记录使用与未使用的inode 号码

5.挂载

在一个区被格式化为一个文件系统以后,它就能够被Linux操做系统使用了,只是这个时候Linux操做系统还找不到它,因此咱们还须要把这个文件系统「注册」进Linux操做系统的文件体系里,这个操做就叫「挂载」 (mount)。
挂载是利用一个目录当成进入点(相似选一个现成的目录做为代理),将文件系统放置在该目录下,也就是说,进入该目录就能够读取该文件系统的内容,相似整个文件系统只是目录树的一个文件夹(目录)。
这个进入点的目录咱们称为「挂载点」。

因为整个 Linux 系统最重要的是根目录,所以根目录必定须要挂载到某个分区。 而其余的目录则可依用户本身的需求来给予挂载到不一样的分去。

到这里Linux的文件体系的构建过程其实已经大致讲完了,总结一下就是:硬盘通过分区和格式化,每一个区都成为了一个文件系统,挂载这个文件系统后就可让Linux操做系统经过VFS访问硬盘时跟访问一个普通文件夹同样。这里经过一个在目录树中读取文件的实际例子来细讲一下目录文件和普通文件。

6.目录树的读取过程

首先咱们要知道

  1. 每一个文件(无论是通常文件仍是目录文件)都会占用一个inode
  2. 依据文件内容的大小来分配一个或多个block给该文件使用
  3. 建立一个文件后,文件完整信息分布在3处地方,生成2个新文件:
    3.1 文件名记录在该文件所在目录的目录文件的block中,没有新文件生成
    3.2 文件属性、权限信息、记录具体内容的block编号记录在inode中,inode是新生成文件
    3.3 文件具体内存记录在block中,block是新生成文件
  4. 由于文件名的记录是在目录的block当中,「新增/删除/改名文件名」与目录的w权限有关
    因此在Linux/Unix中,文件名称只是文件的一个属性,叫别名也好,叫绰号也罢,仅为了方便用户记忆和使用,但系统内部并不须要用文件名来定为文件位置,这样处理最直观的好处就是,你能够对正在使用的文件更名,换目录,甚至放到废纸篓,都不会影响当前文件的使用,这在Windows里是没法想象的。好比你打开个Word文件,而后对其进行重命名操做,Windows会告诉你门儿都没有,关闭文件先!但在Mac里就毫无压力,由于Mac的操做系统一样采用了inode的设计。

建立文件过程

当在ext2下创建一个通常文件时, ext2 会分配一个inode 与相对于该文件大小的block 数量给该文件

  1. 例如:假设个人一个block 为4 Kbytes ,而我要创建一个100 KBytes 的文件,那么linux 将分配一个inode 与25 个block 来储存该文件
  2. 但同时请注意,因为inode 仅有12 个直接指向,所以还要多一个block 来做为区块号码的记录

建立目录过程

当在ext2文件系统创建一个目录时(就是新建了一个目录文件),文件系统会分配一个inode与至少一块block给该目录

  1. inode记录该目录的相关权限与属性,并记录分配到的那块block号码
  2. 而block则是记录在这个目录下的文件名与该文件对应的inode号
  3. block中还会自动生成两条记录,一条是.文件夹记录,inode指向自身,另外一条是..文件夹记录,inode指向父文件夹

从目录树中读取某个文件过程

  1. 由于文件名是记录在目录的block当中,所以当咱们要读取某个文件时,就必定会通过目录的inode与block ,而后才可以找到那个待读取文件的inode号码,最终才会读到正确的文件的block内的资料。
  2. 因为目录树是由根目录开始,所以操做系统先经过挂载信息找到挂载点的inode号,由此获得根目录的inode内容,并依据该inode读取根目录的block信息,再一层一层的往下读到正确的文件。
    举例来讲,若是我想要读取/etc/passwd 这个文件时,系统是如何读取的呢?
    先看一下这个文件以及有关路径文件夹的信息:
1$ ll -di / /etc /etc/passwd
2     128 dr-xr-x r-x . 17 root root 4096 May 4 17:56 /
333595521 drwxr-x r-x . 131 root root 8192 Jun 17 00:20 /etc
436628004 -rw-r-- r-- . 1 root root 2092 Jun 17 00:20 /etc/passwd
复制代码

因而该文件的读取流程为:

  1. /的inode:
    经过挂载点的信息找到inode号码为128的根目录inode,且inode规定的权限让咱们能够读取该block的内容(有r与x)
  2. /的block:
    通过上个步骤取得block的号码,并找到该内容有etc/目录的inode号码(33595521)
  3. etc/的inode:
    读取33595521号inode得知具备r与x的权限,所以能够读取etc/的block内容
  4. etc/的block:
    通过上个步骤取得block号码,并找到该内容有passwd文件的inode号码(36628004)
  5. passwd的inode:
    读取36628004号inode得知具备r的权限,所以能够读取passwd的block内容
  6. passwd的block:
    最后将该block内容的资料读出来
本文摘录自:http://www.cnblogs.com/bellkosmos/p/detail_of_linux_file_system.html。

偶得一日闲,查阅Linux文件系统相关文章,偶然发现该文章,通读全文后茅塞顿开,感叹原文做者Linux之透彻,佩服至极,所以摘录到本人公众号内,稍加修整,以便广大Linux爱好者阅读。

以为本文对你有帮助?请分享给更多人

关注「编程无界」,提高装逼技能

相关文章
相关标签/搜索