一、Linux系统的文件存储结构

在Linux系统中,对计算机中的数据和硬件资源进行管理都是以文件的形式,目录、字符设备、套接字、硬盘、光驱、打印机等都被抽象成文件形式(“Linux系统一切皆文件”)。既然平时我们打交道的都是文件,那么又应该如何找到它们呢?

在Windows操作系统中,想要找到一个文件,要依次进入该文件所在的磁盘分区(也叫盘符),然后再进入该分区下的具体目录,最终找到这个文件。

但是在Linux系统中并不存在C、D、E、F等盘符,Linux系统中的一切文件都是从“根”目录(/)开始的,并按照文件系统层次标准(FHS)采用倒树状结构来存放文件,以及定义了常见目录的用途。

FHS是根据以往无数Linux系统用户和开发者的经验而总结出来的,是用户在Linux系统中存储文件时需要遵守的规则,用于指导用户应该把文件保存到什么位置,以及告诉用户应该在何处找到所需的文件。FHS对于用户来讲只能算是一种道德上的约束,并非必须遵循。

Linux系统中的文件和目录名称是严格区分大小写的。例如,root、rOOt、Root、rooT均代表不同的目录,并且文件名称中不得包含斜杠(/)。

(1) Linux系统中的文件存储结构

 (2)Linux系统中常见的目录名称以及相应内容

目录名称应放置文件的内容
/boot开机所需文件—内核、开机菜单以及所需配置文件等
/dev以文件形式存放任何设备与接口
/etc配置文件
/home用户主目录
/bin存放单用户模式下还可以操作的命令
/lib开机时用到的函数库,以及/bin与/sbin下面的命令要调用的函数
/sbin开机过程中需要的命令
/media用于挂载设备文件的目录
/opt放置第三方的软件
/root系统管理员的家目录
/srv一些网络服务的数据文件目录
/tmp任何人均可使用的“共享”临时目录
/proc虚拟文件系统,例如系统内核、进程、外部设备及网络状态等
/usr/local用户自行安装的软件
/usr/sbinLinux系统开机时不会使用到的软件/命令/脚本
/usr/share帮助与说明文件,也可放置共享文件
/var主要存放经常变化的文件,如日志
/lost+found当文件系统发生错误时,将一些丢失的文件片段存放在这里

(3) 路径

Linux系统的路径指如何定位到某个文件,分为绝对路径和相对路径。

  • 绝对路径:从根目录(/)开始写起的文件或目录名称
  • 相对路径:相对于当前路径的写法

(4)常见的物理(硬件)设备及其文件名称

在Linux系统中一切都是文件,硬件设备也不例外。既然是文件,就必须有文件名称。系统内核中的udev设备管理器会自动把硬件名称规范起来,目的是让用户通过设备文件的名字可以猜出设备大致的属性以及分区信息等;这对于陌生的设备来说特别方便。另外,udev设备管理器的服务会一直以守护进程的形式运行并侦听内核发出的信号来管理/dev目录下的设备文件。

 常用的硬件设备及其文件名称:

硬件设备文件名称
IDE设备/dev/hd[a-d]
SCSI/SATA/U盘/dev/sd[a-z]
virtio设备/dev/vd[a-z]
软驱/dev/fd[0-1]
打印机/dev/lp[0-15]
光驱/dev/cdrom
鼠标/dev/mouse
磁带机/dev/st0或/dev/ht0

 一般的硬盘设备都是以“/dev/sd”开头。而一台主机上可以有多块硬盘,因此系统采用a~z来代表26块不同的硬盘(默认从a开始分配)。

磁盘的分区:

  • 主分区或扩展分区的编号从1开始,到4结束;
  • 逻辑分区从编号5开始(逻辑分区的个数依操作系统而不同,在 linux 系统中, IDE 硬盘最多有 59 个逻辑分区( 5 号到 63 号), SATA 硬盘最多有 11 个逻辑分区( 5 号到 15 号);)。

 【注意】对于分区名称sda3只能表示是编号为3的分区,而不能判断sda设备已经存在了3个分区。

示例:/dev/sda5

表示“这是系统中第一块被识别到的硬件设备中分区编号为5的逻辑分区的设备文件”

二、硬盘设备及分区

硬盘的基础概念

磁盘组成主要包括:盘片、磁头、磁头臂、盘片主轴、步进电机(马达、永磁铁等)、空气过滤片

  1. 一个硬盘有多张盘片叠成,每张盘片都有两个盘面,一般每个盘面都会利用,都可以存储数据,成为有效盘片,也有个别磁盘盘面数为单数。每个有效盘面有一个盘面编号(至上而下,从0开始依次编号)。每个有效盘面上都有可以读写数据的磁头(header)。磁头号与盘面号对应。磁头是利用气流漂浮在盘面上,没有接触到盘面。任何异物或尘埃都可能使得磁头摩擦到盘面而造成数据永久性损坏。
  2. 每张盘片上的存储颗粒成环形一圈圈地排布,每一圈称为磁道(track),每个磁道都有编号(由外至内,从0开始依次编号),每个盘面有300~1024个磁道。
  3. 每条磁道上都有一圈存储颗粒,每512*8bit(512字节,0.5KB)个存储颗粒作为一个扇区(sector)扇区是硬盘上存储的最小物理单位。扇区从1开始编号。不可能发生读半个或1/4个扇区的情况,因为磁头只能定位到某个扇区的开头或结尾,而不能在扇区内部定位。
  4. N个扇区可以组成,N取决于不同的文件系统或是文件系统的配置,簇是此文件系统中的最小存储单位
  5. 所有盘面上的同一磁道构成一个圆柱,称为柱面(cylinder)柱面是系统分区的最小单位
  6. 磁盘存储原理是通过读写头去改变磁盘表面上磁性粒子簇的N、S极,N极表示1,S表示0.

磁盘实物图
磁盘剖面图

磁盘读写原理:

磁盘写入数据时,数据存放顺序是从第一磁道的第一个磁头所有扇区开始,然后是同一柱面的下一磁头,当一个柱面存储空间用完后,将会写入第一盘面相邻的下一磁道,同一柱面的下一磁头,直到文件内容全部写完。

(简而言之,按照从上到下,从外到内,按柱面进行数据读写。柱面、磁头、扇区三者简称CHS,所以扇区地址又称CHS地址。早期小容量磁盘通过磁头读取扇区头标中的CHS地址,进行数据读取。)

目前大容量磁盘使用LBA编址方式Logical Block Address,逻辑块寻址方式)。LBA编址方式磁盘对外提供的地址全部为线性地址,把磁盘想象成只有一个磁道,这个磁道是无限长的直线,扇区是这条直线上的等长线段,从1开始编号。磁头、磁道、扇区的对应关系保存在磁盘控制电路的ROM芯片中。读取磁盘数据时,系统将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑地址翻译成物理地址,即确定数据所在柱面号、磁头号、扇区号。

MBR引导分区

硬盘设备是由大量的扇区组成的,每个扇区的容量为512字节。其中第一个扇区最重要,它里面保存着主引导记录(Master boot record,MBR)与磁盘分区表(Disk partition table)信息

硬盘主引导记录放有最基本的引导加载程序(boot loader),是系统开机启动的关键环节。引导加载程序是一段指令,用以通知计算机如何访问分区表并并定位操作系统的位置。引导程序会因操作系统不同而不同,但是MBR是不属于任何一个操作系统,具有公共引导的特性。利用引导代码可以实现多重系统引导,多系统引导有两种实现方式:①用Windows操作系统在引导分区中设置一段代码,先加载进入用户选择系统的界面,允许用户选择要进入的系统,再进入指定的操作系统;②改变MBR中的引导代码,该代码直接呈现给用户一个选择系统的界面。

引导程序的作用

 分区表则跟分区有关,它记录了硬盘分区的相关信息。分区存储的信息:分区号(partition id)、分区的起始柱面和分区的柱面数量。Linux操作系统在初始化时就可以根据分区表中三种信息来识别硬盘设备。

主引导记录需要占用446字节,分区表占用64字节,结束符占用2字节;其中分区表中每记录一个分区信息就需要16字节,这样一来最多只有4个分区信息可以写到第一个扇区中,这4个分区就是4个主分区。2字节结束符也是识别分区表的标志,要判定扇区的[447-510]字节是不是分区表,就看其后紧跟的两个字节[511-512]是不是“55AA”,若是,则为分区表。

 第一个扇区中的数据信息: 

分区表项详细解析

分区表项各字节含义

注释:

① 第2、3、4字节和6、7、8字节用CHS地址分别表示分区起始扇区地址和结束扇区地址。

  • 磁头号由8位表示,其范围为(0 --2^8 - 1)即(0 磁头-- 254磁头)。  
  • 扇区号由6位表示,其范围为(0 -- 2^6 - 1),即(1扇区-- 63扇区)。  
  • 柱面号由10位表示,其范围为(0 --2 ^10 - 1),即(0 柱面-- 1023柱面)。注意,当柱面号超过1023时,这10位依然表示成1023。

②第9、10、11、12字节和13、14、15、16字节用LBA地址分别表示本分区已用扇区数和总扇区数。

③逻辑扇区号与(柱面,磁头,扇区)的相互转换:

令L = 逻辑扇区号,C = 柱面号,H = 磁头号,S = 扇区号。

每道扇区数 = 63,每柱面磁头数 = 255,每柱面扇区数 = 每道扇区数* 每柱面磁头数

                                                                                        = 63 × 255= 16065

柱面号下标从0开始。磁头号[0 -- 254],扇区号[1 -- 63]。逻辑扇区号下标也从0开始。

CHS地址------->LBA地址

L = C×16065 + H ×63 + S - 1 ;

比如(1柱面,1磁头,1扇区),其逻辑扇区号为:

L = 1×16065 + 1×63 + 1 - 1 = 16128

LBA地址------->CHS地址

C = L / 16065

H = (L % 16065) / 63

S = (L % 16065) % 63 + 1

比如逻辑扇区号 16127:

C = 16127 / 16065 = 1

H = (16127 % 16065) / 63 = 0

S = (16127 % 16065) % 63 + 1 = 63

即(1柱面,0磁头,63扇区)

【问题】每块硬盘最多只能创建4个分区吗?

这显然是不合理也不够用的。为解决分区个数不够的问题,可以将第一个扇区的分区表中16字节(原本要写入主分区信息)的空间(称之为“扩展分区”)拿出来指向另一个分区。所以,扩展分区其实不是一个真正的分区,更像是一个占用16字节分区表空间的指针(一个指向另一个分区的指针)。这样,用户一般会选择使用3个主分区加1个扩展分区的方法,然后再扩展分区中创建出数个逻辑分区,从而满足多分区(>4个分区)的要求。  

扩展分区自身不能存储数据,用户需要在其指向的对应分区(称为“逻辑分区”)上进行操作

扩展引导记录(Extend boot record, EBR )结构:

 扩展分区通过链表的形式将多个子扩展分区相连。EBR引导扇区和MBR引导扇区相似,446字节用于引导,64字节拓展分区表(注意:只有分区表项1和分区表项2有效,后两个表项未使用)。

磁盘分区结构图

为什么要进行分区?
(1)易于管理和使用:
比如说我们把磁盘分了sda1、sda2、sda3、sda4盘,我们假设sda1盘为系统盘,其他的比如说游戏、办公、软件盘,这样我们要重新分哪个区就直接在对应的盘分就可以了,不需要整块磁盘进行分区。根据用途我们也能较快的去使用相应的磁盘。
(2)有利于数据的安全:
通过分区可以降低数据损失的风险。出现硬盘坏道、错误操作、重装系统都有可能造成数据损失,如果分区了,那么我们就可以将损失最小化。
(3)节约寻找文件的时间:
分区以后,电脑搜索文件时只需要在相对应的分区搜索就可以了,没必要进行全盘搜索。大大节省了寻找文件的时间。

MBR引导分区局限性:

操作系统无法使用2.2TB以上的磁盘容量;

MBR仅有一个区块,即所有信息全都放在第一个扇区上,若被破坏后,经常无法或很难恢复;

MBR内存放启动引导程序的区块仅446字节,无法存储更多的程序代码

【小结】

  • 一个硬盘主分区至少有1个,最多4个,扩展分区可以没有,最多1个。且主分区+扩展分区总和不能超过4个。逻辑分区可以有若干个。
  • 硬盘的容量=主分区容量+扩展分区容量
  • 扩展分区容量=各逻辑分区的容量总和

GPT 分区

为什么要提出新的GPT分区方案呢?

那就是MBR分区方案存在一些问题。其一是MBR分区主分区数目不能超过4个,很多时候4个主分区并不能满足实际需求。其二,也是最关键的问题是MBR分区方案无法支持超过2TB容量的磁盘。(MBR分区用4个字节存储分区的总扇区数,最大能表示2的32次方的扇区个数,按每扇区512字节计算,每个分区最大不能超过2.2TB。磁盘容量超过2.2TB以后,分区的起始位置也就无法表示了。)

GPT分区介绍

GUID分区表(简称GPT,使用GUID分区表的磁盘称为GPT磁盘)是源自EFI标准的一种较新的磁盘分区表结构的标准。与目前普遍使用的主引导记录(MBR)分区方案相比,GPT提供了更加灵活的磁盘分区机制。它具有如下优点:

  • 支持2TB以上的大硬盘,可管理的硬盘大小达到18EB。
  • 每个磁盘的分区个数几乎没有限制(Windows系统最多只允许划分128个分区)。
  • 分区大小几乎没有限制。因为它用64位的整数表示扇区号,分区可以支持8ZB大小(2^64 * 512)
  • 分区表自带备份。在磁盘的首尾部分分别保存了一份相同的分区表,其中一份被破坏后,可以通过另一份恢复;
  • 循环冗余检验值针对关键数据结构而计算,提高了数据崩溃的检测几率;
  • 虽然MBR提供1字节分区类型代码,但GPT使用一个16字节的全局唯一标识符(GUID)值来标识分区类型,这使分区类型更不容易冲突;
  • 每个分区可以有一个名称(不同于卷标)。
GPT分区结构

详细字节存放信息可参考链接: 

GPT分区表详解_li33293884的博客-CSDN博客_gpt分区表

Linux分区命令

1. MBR分区

1) 查看分区情况:lsblk

2) 使用fdisk工具创建分区

fdisk工具命令集合:

 使用fdisk工具进行MBR分区过程

①启动fdisk工具(使用管理员权限)

 ②创建一个分区n(new的缩写)

 n 创建分区时,p代表创建主分区,e代表创建扩展分区;接下来的参数依次是起始扇区,可以默认;后一个值可以为结束扇区、扇区数量、分区大小。注意,设置扇区数量时,表示方法为 + (扇区数量) ;设置分区大小时,表示方法为 + (分区大小 K/M/G),这两个加号不能省略。

 ③查看分区p(打开分区列表)

 ④保存分区并写入磁盘

⑤删除分区d (delete缩写)

2. GPT 分区

① 安装gdisk

yum install -y gdisk

 ② GPT常用命令


Command (? for help): m
b    back up GPT data to a file                           //将GPT数据备份到文件中
c    change a partition's name                            //更改分区的名称
d    delete a partition                                   //删除分区
i    show detailed information on a partition             //显示分区的详细信息
l    list known partition types                           //列出已知的分区类型
n    add a new partition                                  //添加一个新的分区
o    create a new empty GUID partition table (GPT)        //创建一个新的空GUID分区表(GPT)
p    print the partition table                            //打印分区表
q    quit without saving changes                          //没有保存更改就退出
r    recovery and transformation options (experts only)   //恢复和转换选项(仅限专家使用)
s    sort partitions                                      //整理分区
t    change a partition's type code                       //不要更改分区的类型代码
v    verify disk                                          //验证磁盘
w    write table to disk and exit                         //将表写入磁盘并退出
x    extra functionality (experts only)                   //额外功能(仅限专家使用)
?    print this menu                                      //打印菜单

③ GPT分区演示

三、文件系统

用户在硬件存储设备中执行的文件建立、写入、读取、修改、转存与控制等操作都是依靠文件系统来完成的。文件系统的作用是合理规划硬盘,以保证用户正常的使用需求。

Linux系统支持数十种文件系统,而最常见的文件系统如下所示。

Ext2:最早可追溯到1993年,是Linux系统的第一个商业级文件系统,它基本沿袭了UNIX文件系统的设计标准。但由于不包含日志读写功能,数据丢失的可能性很大,因此大家能不用就不用,或者顶多建议用于SD存储卡或U盘。

Ext3:是一款日志文件系统,它会把整个硬盘的每个写入动作的细节都预先记录下来,然后再进行实际操作,以便在发生异常宕机后能回溯追踪到被中断的部分。Ext3能够在系统异常宕机时避免文件系统资料丢失,并能自动修复数据的不一致与错误。然而,当硬盘容量较大时,所需的修复时间也会很长,而且也不能100%地保证资料不会丢失。

Ext4:Ext3的改进版本,作为RHEL 6系统中默认的文件管理系统,它支持的存储容量高达1EB(1EB=1,073,741,824GB),且能够有无限多的子目录。另外,Ext4文件系统能够批量分配block(块),从而极大地提高了读写效率。现在很多主流服务器也会使用Ext4文件系统。

XFS:是一种高性能的日志文件系统,而且是RHEL 7/8中默认的文件管理系统。它的优势在发生意外宕机后尤其明显,即可以快速地恢复可能被破坏的文件,而且强大的日志功能只需花费极低的计算和存储性能。它支持的最大存储容量为18EB(18EB等于18,874,368TB。假设每块硬盘的容量是100TB,那么大概需要19万块硬盘才能把18EB的数据都装下。),这几乎满足了所有需求。

在拿到一块新的硬盘存储设备后,先需要分区,然后再格式化文件系统,最后才能挂载并正常使用。硬盘的分区操作取决于您的需求和硬盘大小;也可以选择不进行分区,但是必须对硬盘进行格式化处理。

类比:就像拿到了一张未裁切的完整纸张那样,首先要进行裁切以方便使用(分区),接下来在裁切后的纸张上画格以便能书写工整(格式化),最后是正式的使用(挂载)。

 四、硬盘格式化

Linux操作系统支持很多不同的文件系统,比如ext2、ext3、XFS等等,而Linux把对不同文件系统的访问交给了VFS(虚拟文件系统),VFS能访问和管理各种不同的文件系统。所以分区完需要把它格式化成具体的文件系统以便VFS访问。

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

文件的存储

(1)文件系统通常会将文件的属性和实际内容这两部分数据分别存放在不同的区块

(2)在基于inode的文件系统中,权限与属性放置到 inode 中,实际数据放到 data block 区块中,而且inode和data block都有编号

存储划分:

(1)文件系统最前面有一个启动扇区(boot sector)

这个启动扇区可以安装开机管理程序, 这个设计让我们能将不同的引导装载程序安装到个别的文件系统前端,而不用覆盖整个硬盘唯一的MBR, 也就是这样才能实现多重引导的功能。

(2)把每个区进一步分为多个块组 (block group),每个块组有独立的inode/block体系

每个块组实际还会分为分为6个部分,除了inode table 和 data block外还有4个附属模块,起到优化和完善系统性能的作用。

Linux 格式化命令

格式化命令mkfs

 参数指定:

-t : 指定文件系统的类型,Linux 的预设值为ext2,可以指定为ext3,4等

( Windows下的文件系统有Fat32、NTFS,CentOS使用的文件系统为ext,之前centOS5版本使用ext3作为默认的文件系统,而CentOS6使用ext4作为默认的文件系统)

mkfs本身并不执行建立文件系统的工作,而是去调用相关的程序来执行。例如,若在"-t" 参数中指定ext2,则 mkfs会调用mke2fs 来格式化创建文件系统。

mkfs.ext3 mkfs.reiserfs mkfs.ext2 mkdosfs mkfs.msdos mkfs.vfat ,通过文件名,我们知道这些工具是支持什么文件系统。

文件系统存储结构

 ExtX文件系统存储结构如下图所示:

 Super block(超级块):存放文件系统本身的结构信息。记录的主要信息:

  • block和inode的总量、使用量、未使用量
  • block和inode的大小
  • 文件系统的最近一次挂载时间、最近一次写入数据的时间等
  • 一个validbit 数值,若此文件系统已被挂载,则valid bit为0,否则为1

GDT(Group Description Table ,块组描述符):描述每个块组属性信息。包括块组(block group)的开始与结束号,以及说明每个段区(superblock、bitmap、inode map、data block)分别介于哪个block号之间。

inode Bitmap(inode 位图):每个bit表示一个inode是否空闲可用(1表示已被使用,0表示未被使用)。

Block Bitmap(块位图):记录着Data block 数据块的占用情况(1表示已被使用,0表示未被使用)。

bitmap就是用一个bit(比特)位来标记某个元素对应的value,而key是该元素。使用Bit来存储数据,可以极大节省存储空间。

例如:存储20亿个整数。

按int存储,存储20亿个int,占用的空间(2000000000*4/1024/1024/1024)约7.45G

使用Bitmap,按位存储,占用空间(2000000000/8/1024/1024/1024)约0.23G

如何使用bit位表示一个数?

 如何添加一个数呢?

 如何删除一个数呢?

inode Table(节点表):记录文件的属性以及文件实际数据的位置。

(每个文件仅占用一个inode,每个inode大小固定为128字节,记录一个block消耗4字节。当文件的inode被写满后,Linux系统会自动分配出一个block,专门用于像inode那样记录data block块的信息)

  • 该文件的访问权限(read、write、execute);
  • 该文件的所有者与所属组(owner、group);
  • 该文件的大小(size);
  • 该文件的创建或内容修改时间(Ctime);
  • 该文件的最后一次访问时间(Atime);
  • 该文件的修改时间(Mtime);
  • 文件的特殊权限(SUID、SGID、SBIT);
  • 该文件的真实数据地址(point)。

Data Block(数据块):存放具体文件内容。

文件系统中所支持的 block 大小通常有1kB、2KB及4KB三种。在格式化时,block的大小就固定了,且每个block都有编号,以便inode记录。由于block大小的差异,会导致该文件系统能够支持的最大磁盘容量与最大单一文件容量并不相同。

对于存储文件内容的block块,有下面两种常见的情况(以4KB大小的block为例进行说明)

  • 情况1:文件很小(1KB),但依然会占用一个block(剩余容量不会被使用),因此会潜在地浪费3KB。
  • 情况2:文件很大(5KB),那么会占用两个block(5KB−4KB后剩下的1KB也要占用一个block)。
Block 大小1KB2KB4KB
最大单一文件限制16GB256GB2TB
最大文件系统总容量2TB8TB16TB

最大单一文件容量的计算方法

一个文件对应一个inode。ext2文件系统为了让inode记录尽可能多的data block,定义了四个记录block号码的区域,分别为12个直接记录区1个间接记录区1个双间接记录区1个三间接记录区,所谓间接记录区就是用data block记录data block号码.

以每个 block 的大小1KB为例:
 (1) 12个直接指向:12 × 1K = 12 K    (一个直接记录区记录一个data block号码,一个data block 1K)
 (2) 1个间接:256 × 1K = 256 K         (一次间接指针指向一个data block,由该data block间接记录文件data block号码,由于data block为1K,记录一个data block要4byte,所以一个data block可以保持1024 / 4 = 256 个data block号码)
(3)  1个双间接:256 × 256 × 1K = 65526 K
(4)1个三间接:256 × 256 × 256 × 1K = 16,777,216K
最大单一文件容量等于四个记录区容量的总和,12 + 256 + 65526 + 6,777,216 = 116,843,010 K,约等于16G。

【注意】该方法仅限于<2k的block,受到文件系统本身的限制,ext2文件系统限制单个文件最大容量为2T。

虚拟文件系统(Virtual File System,VFS)

Linux支持多种不同文件系统,要实现这个目的,就要将对各种不同文件系统和管理纳入到一个统一的框架中,让内核中的文件系统界面成为一条文件系统“总线”,使用户程序可以通过同一个文件系统操作界面,也就是同一组系统调用,对各种不同的文件系统(以及文件)进行操作。这样,就可以对用户程序隐去各种不同文件系统的细节,为用户程序提供一个统一的、抽象的、虚拟的文件系统界面,这就是所谓“虚拟文件系统(Virtual Filesystem Switch/System,VFS”。

这个抽象界面主要由一组标准的、抽象的文件操作构成,以系统调用的形式提供于用户程序,如read()、write()、lseek()等等。这样,用户程序就可以把所有的文件都看作一致的、抽象的“VFS文件”,通过这些系统调用对文件进行操作,而无需关心具体的文件属于什么文件系统以及具体文件系统的设计和实现。例如,在Linux操作系统中,可以将DOS格式的磁盘或分区(即文件系统)“安装”到系统中,然后用户程序可以安完全相同的方式访问这些文件,就好像它们也是ext2格式的文件一样。

假设一个进程使用系统调用read()读取磁盘上的文件。下面步骤是内核响应进程读请求的步骤:

(1)系统调用read()会触发相应的VFS(Virtual Filesystem Switch)函数(sys_read()),传递的参数有文件描述符和文件偏移量。

(2)VFS确定请求的数据是否已经在内存缓冲区中;若数据不在内存中,确定如何执行读操作。 (3)假设内核必须从块设备上读取数据,这样内核就必须确定数据在物理设备上的位置。这由映射层(Mapping Layer)来完成。

(4)此时内核通过通用块设备层(Generic Block Layer)在块设备上执行读操作,启动I/O 操作,传输请求的数据

(5)在通用块设备层之下是I/O调度层(I/O Scheduler Layer),根据内核的调度策略,对等待的I/O等待队列排序。

(6)最后,块设备驱动(Block Device Driver)通过向磁盘控制器发送相应的命令,执行真正的数据传输

VFS主要对象及其数据结构:

虚拟文件系统(VFS)支持的文件系统可以分成主要三种类型

①磁盘文件系统

管理本地磁盘和模拟磁盘的设备,基于磁盘的文件系统有:

  • Linux的Ext2、Ext3和XFS
  • Unix文件系统的变种,如sysv、UFS、MINIX和VERITAS VxFS。
  • 微软的文件系统,如MS-DOS、VFAT、NFTS
  • ISO9660 CD-ROM文件系统和UDF(Universal Disk Format)DVD文件系统
  • 其他文件系统如IBM OS/2中的HPFS、Apple’s Macintosh的HFS、AFFS 和ADFS等。

②网络文件系统

它允许方便访问网络上其他计算机的文件系统。VFS支持的网络文件系统有 NFS、Coda、AFS(Andrew filesystem)、CIFS(Common Internet Filesystem)和NCP(Novell’s NetWare Core Protocol)。

③特殊文件系统

它不管理磁盘空间。/proc就是一个特殊的文件系统。

虚拟文件系统有四个主要对象类型

(1)spuerblock 表示特定加载的文件系统。

(2)inode 表示特定的文件。

(3)dentry 表示一个目录项,路径的一个组成部分。

(4)file 表示进程打开的一个文件。

使用Linux命令查看inode信息

(1) 查看文件的inode信息:stat

 

 (2) 查看文件类型:file

 

 (3) 查看inode号码:ls -i

 

 

 (可以看到stat命令中也有Inode,22360就是inode号)

 (4) 查看硬盘分区的inode数量和使用情况:df -i

 

五、挂载

在一个区被格式化为一个文件系统之后,它就可以被Linux操作系统使用了,只是这个时候Linux操作系统还找不到它,所以我们还需要把这个文件系统注册进Linux操作系统的文件体系里,这个操作就叫挂载 (mount)。
挂载是利用一个已存在的目录文件当成进入点(类似选一个现成的目录作为代理),将文件系统放置(关联)在该目录下,也就是说,进入该目录就可以读取该文件系统的内容,类似整个文件系统只是目录树的一个文件夹(目录)。
这个进入点的目录我们称为挂载点

由于整个 Linux 系统最重要的是根目录,因此根目录一定需要挂载到某个分区。 而其他的目录则可依用户自己的需求来给予挂载到不同的分区。

【小结】

硬盘经过分区和格式化,每个区都成为了一个文件系统,挂载这个文件系统后就可以让Linux操作系统通过VFS访问硬盘时跟访问一个普通文件夹一样。

Linux挂载和卸载命令

挂载mount

 卸载umount

卸载方法一

 卸载方法二

强制卸载加参数-l

六、文件寻址(文件读取)

一个文件由一个目录项、inode、数据区域块组成。

目录结构:

在 Linux 下的 ext2 文件系统创建一个目录时, ext2 会分配一个 inode 与至少一块 block 给该目录。
inode 记录该目录的相关权限与属性,并可记录分配到的那块 block 号码
block 则是记录在这个目录下的文件名与该文件名占用的 inode 号码数据.

如下图所示:

上面的图描述的是查看文件的流程,从图中可以看出 tmp/ 目录文件对应的 Block 块中存储的是该目录下文件名以及文件名对应的 inode 号码,而 a.txt、c.txt 文件对应的 Block 块中存储的是 a.txt c.txt 文件的内容

由于目录树是由根目录(/)开始读起,因此系统透过挂载的信息可以找到挂载点的 inode 号码(通常一个 文件系统 的最顶层 inode 号码会由 2 号开始),此时就能够得到根目录的 inode 内容,并依据该 inode 读取根目录的 block 内的文件名数据,再一层一层的往下读。

现以查看 a.txt 文件内容为例,说明在文件系统是如何查看文件内容的:

① 透过挂载点的信息找到 inode 号码为 2 的根目录 inode,根据 inode 的访问权限判断是否可以读取该 block 的内容 ;

② 从inode中取得 block 的号码,并找到该内容有 tmp/ 目录的 inode 号码 (131098);

③ 根据 tmp/ 目录文件对应的 inode 号码 (131098) 找到 tmp/ 目录文件对应 Block 数据块

④ 从 tmp/ 目录文件对应的 Block 块中找出 a.txt 文件对应的 inode 号码 (131101)

⑤ 从 a.txt 文件对应的 inode 信息 中找到对应的 Block 块

⑥ 读出 a.txt 文件对应的 Block 块中的数据(this is a.txt file)

七、 软硬方式链接

在Windows系统中,快捷方式就是指向原始文件的一个链接文件,可以让用户从不同的位置来访问原始的文件;原文件一旦被删除或剪切到其他地方,会导致链接文件失效。但是,这个看似简单的东西在Linux系统中可不太一样。Linux系统中存在软链接和硬链接两种不同的类型。

软链接(soft link)也叫符号链接(symbolic link),仅仅包含所链接文件的名称和路径,很像一个记录地址的标签。文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic link)。当原始文件被删除或移动后,新的链接文件也会随之失效,不能被访问可以针对文件、目录设置软链接,跨文件系统进行链接也不是问题。从这一点来看,它与Windows系统的“快捷方式”具有一样的性质。(可以通过readlink查看其指向)

硬链接(hard link)可以将它理解为一个“指向原始文件block的指针”,系统会创建出一个与原来一模一样的inode信息块。所以,硬链接文件与原始文件其实是一模一样的,只是名字不同每添加一个硬链接,该文件的inode个数就会增加1;而且只有当该文件的inode个数为0时,才算彻底将它删除。换言之,由于硬链接实际上是指向原文件block的指针,因此即便原始文件被删除,依然可以通过硬链接文件来访问。需要注意的是,由于技术的局限性,不能跨分区对目录文件进行硬链接。

 【注意】目录文件的"链接数"。创建目录时,默认会生成两个目录项:"."和".."。前者的inode号码就是当前目录的inode号码,等同于当前目录的"硬链接";后者的inode号码就是当前目录的父目录的inode号码,等同于父目录的"硬链接"。所以,任何一个目录的"硬链接"总数,总是等于2加上它的子目录总数(含隐藏目录)。是不能对目录做硬链接

Linux 命令创建文件的软硬链接ln(全称“link”)

语法格式:

ln [参数]  原始文件名 链接文件名

参数:

 创建软链接示例

 由上图可知,新创建的软链接文件test_softlink.txt和test.txt文件内容是一致的,但是两个文件对应的inode号码是不一样的。

 当删掉原始文件test.txt 后,软链接文件test_softlink.txt立刻就无法读取了。

创建硬链接示例:

 由上图可以看到,源文件与目标文件的inode号码相同,都指向同一个inode,硬链接数变成了2(这表示的是文件的inode信息块的数量变为2),test_hardlink.txt类型也成为了普通文件。

删除源文件test.txt,后仍然可以打开test_hardlink.txt文件。

删除一个文件名test.txt,使得inode节点中的"链接数"减1(仅仅删除了一个指向真实文件的指针而已)。但是它的链接数并没有减为0,所以这个文件数据块并没有删除。

参考链接:

(1) Inode与block详解【图文】_moakia_51CTO博客

(2)理解 Linux 中的 inodes - Linux开发那些事儿 - 博客园 (cnblogs.com)

(3)Linux inode 详解 - LinSenGeGe - 博客园 (cnblogs.com)

(4)存储管理:Linux中磁盘的管理(分区、格式化、挂载)、LVM_wangxu_190的博客-CSDN博客

(5)Linux文件系统(inode、block……) - xumenger - 博客园 (cnblogs.com)

(6)磁盘文件系统-深解析_小一!的博客-CSDN博客

(7)Linux软连接和硬链接 | 满江风雪 (metmoon.com)

(8)第6章 存储结构与管理硬盘 | 《Linux就该这么学》 (linuxprobe.com)

Logo

更多推荐