侧边栏壁纸
博主头像
landery博主等级

行李箱里装不下我想去的远方

  • 累计撰写 45 篇文章
  • 累计创建 26 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

操作系统_02_Linux文件系统

landery
2022-04-18 / 0 评论 / 0 点赞 / 85 阅读 / 4,639 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-05,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

操作系统_02_Linux文件系统

需要搞清楚的问题:

1、当我运行一个可执行文件时,整个操作系统运行的过程。

2、正在运行的进程,执行代码块,创建文件、打开文件、删除文件、读取文件、写入文件时发生了什么。

以下内容绝大部分来自参考文献,转载请附带参考文献。

1 文件系统基本概念

文件系统是操作系统与用户的接口,为用户管理数据,这些数据通过文件系统直观的存储的存储介质上。

1.1 文件

文件系统的基本数据单元是文件,文件具有如下属性:文件名、文件分类、元数据等。

  1. 文件名是文件在存储系统上的唯一标识,用户因此不需要关心文件的存储方式、访问路径、以及文件在磁盘上存储的位置等。不同文件系统对文件名的规则不同。例如ext2文件系统,限定文件名长度255个字符。
  2. 文件分类为了更有效地组织和管理文件。按照用途分类,文件可以分为系统文件、库文件、用户文件。按照文件的性质可以分为普通文件、目录文件和特殊文件。按照文件的保护级别可以分为只读文件、可读写文件、可执行文件。按照数据形式还可以分为源文件、目标文件和可执行文件。不同操作系统分类方法也不同,windows按照文件扩展名来标识文件类型,Linux则是通过隐含在文件属性中的信息来标识。
  3. 文件主要包含两部分的内容,一部分是文件自身所包含的数据,另一部分是关于文件的描述性息,被称为文件属性,也被称为元数据,例如文件创建日期、文件长度、文件权限、存储位置等。

Unix在设计的时候就提出:一切皆文件,如果一个东西不是文件,那就是进程。

  • 普通文件:用户大部分时间都在进行操作的文件。包括文本文件、C语言源代码、shell脚本、二进制的可执行程序和各种类型的数据。对Linux来说,文件就是文件,Linux唯一要区别它的就是,它是不是可执行文件
  • 目录文件:目录也是文件,它们包含文件名和子目录名,并包含指向那些文件和子目录的指针。目录文件是Linux存储文件名的地方,使用ls命令可以列出一个目录的内容,但这没有触及到文件本身,如果将一个文件从一个目录移动到另一个目录,事实上只是把这个文件的说明从一个目录文件移动到了另一个文件目录中。
  • **特殊文件:**在系统中,有很多特殊的文件,比如链接、设备文件(在Linux中所有设备都用文件来表示,大多数设备文件都放在/dev目录中),命名管道、套接字等。

1.2 目录

前面已经说过,目录也是文件,所有文件与目录在系统中形成了一个树状结构如下:

!1649925397800.png

Linux系统中每个文件都被赋予了一个唯一的数值,这个数值称为索引节点inode(index node),它包含了一个文件的全部信息。索引节点存储在一个成为索引节点表(inode table)中,该表在磁盘格式化时被分配。

每个实际的磁盘或分区都有自己的索引节点表。Linux文件系统把索引节点号1值赋予了根目录,可以通过查找根目录开始的一个目录链来找到文件系统中的任何文件。

1.3 文件系统挂载与卸载

在Linux中要使用一个文件系统前,必须先挂在那个文件系统,每个文件系统都有自己的根目录,可以通过挂在命令mount/umount挂载和卸载一个文件系统。

2 索引节点、目录、目录项、文件存储

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

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

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

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

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

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

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

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

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

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

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

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

1649926710907.png

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

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

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

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

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

3 虚拟文件系统VFS

由于文件系统种类繁多,如NTFS、ext2、ext3、ext4等,而操作系统则希望对用户提供统一的接口,于是通过在用户层和文件系统层引入一层抽象的虚拟文件系统层,隐藏各种不同文件系统的实现细节,对用户提供统一的API。

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

1649927058883.png

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

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

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

4 用户进程对文件的访问

从用户角度来说,拿read()函数作为例子,每个文件在内核中都有一个对应的文件对象结构体,在这个结构体中包含的f_op指针执行具体文件系统的功能函数,其中就包含了read的操作。当用户空间发起read()请求时,经历了VFS再到具体的文件系统。

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

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

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

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

1649928252603.png

4.1 操作系统打开文件表

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

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

4.2 进程打开文件表

进程打开文件表包含文件的描述符以及文件指针。

进程打开文件表包含指向系统打开文件表的句柄,操作系统打开文件表包含指向inode表。

1649928546438.png

系统打开文件表中的属性给系统提供了维护内存中inode表的依据,当没有任何进程引用内存中的inode文件时,系统打开文件表中的文件打开计数器为0,操作系统会根据规则,收回该inode节点空间。

当我们写入文件时,由于内存和磁盘的速度差异性,操作系统对磁盘读写会以数据块进行,就算用户只读取文件中一个字符的内容,操作系统也会讲包含该文件该字符的数据块读入内存,写操作同理。用户读写与操作系统读写差异性,由文件系统屏蔽,用户无法感知。

5 软链接与硬链接

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

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

1649929478732.png

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

1649929508527.png

6 Linux常见文件类型

1649921994433.png

windows里通过扩展名来区分文件类型的。linux里文件扩展名和文件类型没有关系。但为了容易区分和兼容用户使用windows的习惯,我们还是会用扩展名来表示文件类型。举例如下:

  • 源码.tar、.tar.gz、.tgz、.zip、.tar.bz表示压缩文件,创建命令一般为tar,gzip,zip等。
  • .sh表示shell脚本文件,通过shell语言开发的程序。
  • .pl表示perl语言文件,通过perl语言开发的程序。
  • .py表示python语言文件,通过python语言开发的程序。
  • .html、.htm、.php、.jsp、.do表示网页语言的文件。
  • .conf表示系统服务的配置文件。
  • .rpm表示rpm安装包文件。

参考文献

0

评论区