Linux操作系统(六):文件系统组件

参考资料:阿秀的笔记

文件系统

  • 1. 文件系统的基本组成
  • 2. 文件的使用
  • 3.文件如何存储
    • 3.1 目录怎么存储
  • 4.Linux继承于Unix系统的Unix文件实现方式
    • 4.1 Linux Ext 2/3 文件系统
    • 4.2 Linux Ext 4 文件系统
    • 4.3 磁盘空闲空间的管理机制
      • 4.3.1 空闲表法
      • 4.3.2 空闲链表法
      • 4.3.3 位图法(Linux系统使用的方法)
  • 5. 文件系统的结构
  • 6.文件怎么取别名
  • 7.文件怎么读写I/O
    • 7.1 缓冲与非缓冲 I/O
    • 7.2 直接与非直接 I/O
    • 7.3 阻塞与非阻塞 I/O VS 同步与异步 I/O

1. 文件系统的基本组成

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

在这里插入图片描述

如何唯一标识文件?索引节点 inode,记录了文件的元信息,比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。存储在硬盘中占用磁盘空间

如何组织文件之间的关系?目录项directory entry,记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。通过多个目录项的关联就能形成目录结构。目录项是由内核维护的一个数据结构,不存放于磁盘,而是缓存在内存

注意,一个文件可以有多个别名,所以目录项和索引节点的关系是多对一,即多个目录项中的索引节点可以指向同一个文件。

Linux中目录和目录项关系是什么?目录是个文件,持久化存储在磁盘,而目录项是内核一个数据结构,缓存在内存。由于查询目录频繁从磁盘读效率低,所以内核会把已经读过的目录用目录项这个数据结构缓存在内存,下次再次读到相同的目录时,只需从内存读就可以,大大提高了文件系统的效率。目录项可以视为一个表示目录的数据结构。

文件系统如何把文件存储在磁盘?磁盘读写的最小单位是扇区 512B,文件系统把多个扇区组成了一个逻辑块。Linux 中的逻辑块大小为 4KB。

磁盘为什么要分为三个储存分区?便于数据组织和管理,磁盘进行格式化时分成三个存储区域,分别是超级块、索引节点区和数据块区:

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

超级块和索引节点区数据会在需要时加载到内存中:

  • 超级块:当文件系统挂载时进入内存;

  • 索引节点区:当文件被访问时进入内存

    文件系统的实现确实包含在内核中,但并不是所有文件系统信息都一开始就加载到内核空间中,而是根据需要进行加载和缓存,以提高性能和节省内存。文件系统首先要先挂载到某个目录才可以正常使用,比如 Linux 系统在启动时,会把文件系统挂载到根目录。

文件种类很多导致文件系统也很多,文件系统如何提供用户易用性?Linux系统会根据不同的需求和限制选择适合特定文件类型的文件系统,来更好地满足用户的需求,并提供更好的性能、可靠性和功能特性。

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

  • 磁盘的文件系统把数据存储在磁盘中,比如 Ext 2/3/4、XFS 等。
  • 内存的文件系统,数据占用内存空间,比如 /proc 和 /sys 文件系统,读写这类文件,实际上是读写内核中相关的数据。
  • 网络的文件系统,用来访问其他计算机主机数据的文件系统,比如 NFS、SMB 等等。

Linux为了对用户提供一个统一的接口,在用户层与文件系统层引入了中间层,虚拟文件系统(Virtual File System,VFS)。
在这里插入图片描述

2. 文件的使用

  VFS为不同的文件系统提供了一个抽象层次,隐藏了文件系统的具体实现细节。这使得内核可以支持多种不同的文件系统,而用户程序不需要关心文件系统的具体细节。VFS提供了文件描述符来进行读取、写入、关闭文件等操作。提供了虚拟的目录结构,用于管理所有已挂载的文件系统(Linux支持可插拔的文件系统模块,可以在运行时加载和卸载不同类型的文件系统,而不需要重新编译内核)。
  从用户角度来看文件的使用过程:
在这里插入图片描述

3.文件如何存储

请添加图片描述
在这里插入图片描述

3.1 目录怎么存储

  目录是一个特殊的文件。每个文件在存储时都用一个inode表(相当于索引了)来存放文件元信息,包含文件地址(指向的是数据块)等。
  目录的数据块里面保存的是目录里面一项一项的文件信息。
在这里插入图片描述
  保存目录的格式改成哈希表,对文件名进行哈希计算,把哈希值保存起来,如果我们要查找一个目录下面的文件名,可以通过名称取哈希。如果哈希能够匹配上,就说明这个文件的信息在相应的块里面。

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

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

4.Linux继承于Unix系统的Unix文件实现方式

  本节中的4.1和4.2讲述了Linux文件的存储如何实现,本质是针对已经写入数据的数据块的组织和管理。4.3讲述空闲空间管理,针对数据块应该放在硬盘上的哪个位置?最简单的思想就是将硬盘所有的区扫描一遍,找个空的地方随便放,但这样显然效率低下,所以引入了针对磁盘的空闲空间也是要引入管理的机制。

4.1 Linux Ext 2/3 文件系统

在这里插入图片描述
  在实际中采用了多级组合方式:
  第一级组合相当于索引:文件头中的inode(索引节点) 是一个数据结构,记录了文件在文件系统中的基本信息,包括文件的物理位置。从效果上相当于一个索引数据块,存放指向文件数据块的指针列表。
  通过第一级索引块来存放第二级索引块

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

优点:解决大文件的存储
缺点:对于大文件的访问,需要大量的查询,效率比较低。

4.2 Linux Ext 4 文件系统

对Ext3文件系统的改进和扩展:

  • 支持更大的文件大小(最大16TB)和更大的分区大小(最大1EB),这使得Ext4更适合于处理大型文件和存储设备。
  • 改进的文件分配算法和数据结构,以提高文件的分配和管理效率。例如,采用了多级索引、延迟分配等技术来减少磁盘碎片化,并优化了空闲块管理算法。

       延迟分配(Delayed Allocation)是一种文件系统优化技术,旨在减少磁盘碎片化并提高文件写入性能。它的基本思想是推迟文件系统实际分配磁盘空间的时间,直到需要写入数据时才进行实际的分配。这种技术在磁盘写入过程中可以使得文件系统更有效地组织数据,从而提高文件系统的性能。

4.3 磁盘空闲空间的管理机制

4.3.1 空闲表法

在这里插入图片描述

  针对连续空间存放的文件存储方法,可以使用空闲表法:为所有空闲空间建立一张表,表内容包括空闲区的第一个块号和该空闲区的块个数。
  当请求分配磁盘空间时,系统依次扫描空闲表里的内容,直到找到一个合适的空闲区域为止。当用户撤销一个文件时,系统回收文件空间。这时,也需顺序扫描空闲表,寻找一个空闲表条目并将释放空间的第一个物理块号及它占用的块数填到这个条目中。
  使用场景:建立连续文件。少量的空闲区。

4.3.2 空闲链表法

在这里插入图片描述
  空闲链表法只要在主存中保存一个指针,令它指向第一个空闲块。当创建文件需要一块或几块时,就从链头上依次取下一块或几块。反之,当回收空间时,把这些空闲块依次接到链头上。

  其特点是简单,但不能随机访问,工作效率低,因为每当在链上增加或移动空闲块时需要做很多 I/O 操作,同时数据块的指针消耗了一定的存储空间。空闲表法和空闲链表法都不适合用于大型文件系统,因为这会使空闲表或空闲链表太大。

4.3.3 位图法(Linux系统使用的方法)

  在 Linux 文件系统就采用了位图的方式来管理空闲空间,不仅用于数据空闲块的管理,还用于 inode 空闲块的管理,因为 inode 也是存储在磁盘的,自然也要有对其管理。
  位图法利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上所有的盘块都有一个二进制位与之对应。当值为 0 时,表示对应的盘块空闲,值为 1 时,表示对应的盘块已分配。它形式如下:

1111110011111110001110110111111100111 ...

5. 文件系统的结构

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

提到 Linux 是用位图的方式管理空闲空间,用户在创建一个新文件时,Linux 内核会通过 inode 的位图找到空闲可用的 inode,并进行分配。如果采用「一个块的位图 + 一系列的块」,外加「一个块的 inode 的位图 + 一系列的 inode 的结构」能表示的最大空间也就 128M。

  所以Linux系统引入了块组结构。下图给出了 Linux Ext2 整个文件系统的结构和块组的内容,文件系统都由大量块组组成,在硬盘上相继排布:
在这里插入图片描述Ext2 文件系统的结构和块组的内容中

  • 引导块(boot block)是指存储引导加载程序(boot loader)的区域。
  • 块组(Block Group):结构
    • 超级块,包含的是文件系统的重要信息,比如 inode 总个数(每个文件都对应一个 Inode)、块总个数(存储文件内容的区域个数)、每个块组的 inode 个数(文件系统将 Inode 分为若干块组,每个块组包含一定数量的 Inode)、每个块组的块个数等等。
    • 块组描述符,包含文件系统中各个块组的状态,比如块组中空闲块和 inode 的数目等,每个块组都包含了文件系统中「所有块组的组描述符信息」。
    • 数据位图和 inode 位图, 用于表示对应的数据块或 inode 是空闲的,还是被使用中。
    • inode 列表,包含了块组中所有的 inode,inode 用于保存文件系统中与各个文件和目录相关的所有元数据。
    • 数据块,包含文件的有用数据。

6.文件怎么取别名

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

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

7.文件怎么读写I/O

7.1 缓冲与非缓冲 I/O

指在进行输入/输出(I/O)操作时数据的处理方式不同。
  缓冲 I/O 是指在进行 I/O 操作时,系统会先将数据从磁盘读取到内存缓冲区中,然后再从缓冲区中读取或写入数据到文件。这样的方式可以减少实际 I/O 操作的次数,提高效率。

例如,C/C++ 中的标准 I/O 函数(如 fread()、fwrite()、fgets()、fputs() 等)都是采用缓冲 I/O 的方式。

  非缓冲 I/O 是指在进行 I/O 操作时,数据直接从磁盘中读取或写入到目标文件,没有经过缓冲区的中间处理。如在通信领域或一些特殊的硬件操作中。

例如,Unix/Linux 中的 read() 和 write() 等系统调用就是非缓冲 I/O 的方式。

7.2 直接与非直接 I/O

关于数据传输时是否涉及的中间缓冲区
  直接 I/O 是指数据在进行输入/输出操作时,数据可以直接从用户空间(例如应用程序)直接传输到设备或文件系统,而无需经过内核缓冲区的中转。

例如在 Linux 中可以使用 O_DIRECT 标志来指示直接 I/O。程序直接将数据从用户空间写入到文件系统的某个位置,跳过内核空间的缓冲区,直接写入磁盘。

  非直接 I/O 是指数据在进行输入/输出操作时,数据必须先从用户空间复制到内核空间的缓冲区中,然后再从内核空间的缓冲区传输到设备或文件系统。

大多数操作系统默认采用非直接 I/O 的方式。内核可以更好地管理数据的传输,因此可能更加稳定可靠。

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

阻塞与非阻塞 I/O:描述了程序在进行 I/O 操作时是否会暂停执行

  • 阻塞 I/O 是指程序在进行 I/O 操作时,如果无法立即得到结果,程序会暂停执行(阻塞),直到得到结果为止。
  • 非阻塞 I/O 是指程序在进行 I/O 操作时,如果无法立即得到结果,程序不会暂停执行,而是会立即返回一个状态指示暂时无法完成操作,然后程序可以继续执行其他任务。

    与异步 I/O 不同的是,非阻塞 I/O 下的程序并不会主动等待 I/O 操作完成的通知或结果。 相反,它会立即返回一个状态,告诉程序当前的 I/O 操作是否完成,然后程序可以根据这个状态继续执行其他任务,或者进行其他操作,而不需要等待 I/O 操作完成。

  • 阻塞 I/O 的优点是简单易用,但可能会造成程序在等待 I/O 完成时浪费大量的时间。非阻塞 I/O 则可以让程序更加灵活地处理 I/O 操作,但需要额外的代码来处理返回的状态。

同步与异步 I/O:述了程序在发起 I/O 操作后是否需要等待操作完成。

  • 同步 I/O 是指程序在发起 I/O 操作后,需要等待操作完成才能继续执行后续的任务,即发起 I/O 操作的线程需要主动等待 I/O 操作完成。
  • 异步 I/O 是指程序发起 I/O 操作后,不需要等待操作完成,而是可以继续执行后续的任务,当操作完成后会得到通知,或者由另一个线程来处理完成的操作。
  • 同步 I/O 的优点是编程模型简单,易于理解和控制,但可能会造成程序在等待 I/O 操作完成时浪费大量的时间。异步 I/O 则可以让程序更加高效地利用系统资源,但需要额外的处理机制来处理操作完成的通知。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/529639.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

js语法---简单理解promise

promise语法结构 创建一个promise对象 let p new Promise(function(resolve,reject){// 执行的操作...// 判断操作的结果并执行对应的回调函数if(){resolve()}else{reject()} } 以上实例化了一个promise对象,其中包含了一个参数function,这个函数会在…

从二维数组到一维数组——探索01背包问题的动态规划优化

文章目录 题目前知背包问题 二维dp数组一、思路二、解题方法三、Code 一维dp数组一、思路二、解题方法三、Code 总结 本文将继续上一篇博客爬楼梯之后继续讲解同样用到了动态规划的 01背包问题 在解决动态规划问题时,我们经常面临着空间复杂度的挑战。01背包问题是…

书生·浦语大模型-第三节课笔记/作业

笔记 作业 原版 prompt控制节奏,实现类似关键词检索、主题、信息抽取等功能注意这里根据llm返回的topic (prompt: 告诉我这句话的主题,直接说主题不要解释)进行召回检索(CacheRetriever), 并再次让大模型判断query与返回的检索的相关程度. 如果本地检索…

【工具-工具指南】

项目-开发工具 ■ 编辑器■ Xmind ■ UI交互设计■ AxureRP9 ■ 项目管理■ boardmix■ excalidraw ■ Markdown■ MarkText■ Typora■ Ulysses■ Notable■ VNote■ Mou■ Bears■ Notion■ 有道云■ 印象笔记 ■ 硬件画图■ AD■ Allegro■ PADS■ Eagle■ Altium■ Fritzin…

保研线性代数复习4

一.范数(Norms) 1.什么是范数? 范数是一个向量空间V的函数,每一个属于向量空间V的向量x都匹配了一个实数(它的长度): 2.范数的性质? 齐次性: 正定性: 三…

SpringBoot整合MyBatis四种常用的分页方式

目录 方式1 一、准备工作 1. 创建表结构 2. 导入表数据 3. 导入pom.xml依赖 4. 配置application.yml文件 5. 创建公用的实体类 项目结构 2. 创建controller层 3. 创建service层 4. 创建mapper层 5. 创建xml文件 6. 使用postman进行测试,测试结果如下…

第6章 6.1.1 文本格式化 sprintf函数(MATLAB入门课程)

sprintf函数源自 C 语言标准库中的同名函数,这个函数在 C 语言中用于创建格式化的字符串,且使用频率非常高。作为一门高级编程语言,MATLAB借鉴了 C 语言和其他编程语言中的许多特性和命名惯例。在MATLAB中,sprintf函数主要有两种用…

学习记录14-运算放大器2

目录 前言 一、理想放大器 二、虚断 二、虚短 虚短的两个使用条件 1.虚短概念 2.如果我们将运放的同相端和反相端颠倒会怎样呢? 总结 前言 主要讲述运算放大器的虚短虚断 一、理想放大器 如果没有基础或只是想简单了解,可以看我前一篇文章&am…

数学基础:常见函数图像

来自: https://www.desmos.com/calculator/l3u8133jwj?langzh-CN 推荐: https://www.shuxuele.com/index.html 一、三角函数 1.1 正弦 sin(x) 1.2 余弦 cos(x) 1.3 正切 tan(x) 1.4 余切 cot(x) 1.5 正弦余弦综合 1.6 正切余切综合 二、指数对数

【数据结构与算法】力扣 19. 删除链表的倒数第 N 个结点

题目描述 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入: head [1,2,3,4,5], n 2 输出: [1,2,3,5]示例 2: 输入: head [1], n 1 输出: []示例…

[方案实操|数据技术]数据要素十大创新模式(3):深数所-数据交易动态合规体系

“ 推动数据要素更好发展,政策创新是前提,数据质量管理是基础,安全和隐私保护是关键,合规性遵循是条件,数据共享和交易平台是手段。” 数据要素十大创新模式系列文章。 [方案实操|数据技术]数据要素十大创新模式(1)&a…

uniapp 表单使用Uview校验 包括城市选择器

<view><!-- 注意&#xff0c;如果需要兼容微信小程序&#xff0c;最好通过setRules方法设置rules规则 --><u--form labelPosition"left" :model"model1" :rules"rules" ref"uForm" labelWidth"174"><u…

生产端消息可靠性保证: 确认(Confirm)机制

1.PostConstruct注解 PostConstruct注解是Java EE规范中的一部分&#xff0c;主要用于标记在一个Bean初始化完成后需要执行的方法。这个注解由JSR-250定义&#xff0c;并且在Spring框架以及其他遵循Java EE标准的应用服务器中广泛支持。 功能与用途&#xff1a;初始化方法,当…

扫描IP开放端口该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开

扫描IP开放端口该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开 #/bin/bash #该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开放来哪些端口 #用telnet方式 IP$1 #IP119.254.3.28 #获得IP的前…

UML学习

UML(Unified Modeling Language)&#xff1a;统一建模语言&#xff0c;提供了一套符号和规则来帮助分析师和设计师表达系统的架构、行为和交互 类图&#xff1a;描绘类、接口之间的关系(继承、实现、关联、依赖等)以及类的内部结构(属性和方法)&#xff0c;直观展现系统的静态…

书生浦语大模型实战营第二次课作业

目录 教程来源1.环境配置1.1 初始化环境1.2 激活创建的虚拟环境然后继续安装所需的python包 2.下载模型并运行模型2.1 创建相应的文件夹和文件2.2 编写下载模型的代码运行下载模型2.3 编写运行模型的代码运行代码 测试模型效果 教程来源 视频教程&#xff1a;https://www.bili…

4套java开发的智慧系统源码 智慧校园系统源码 智慧工地系统源码 智慧城管系统源码

4套java智慧系统源码 智慧校园系统源码 智慧工地系统源码 智慧城管系统源码 3D 智能导诊系统源码 Java智慧校园系统源码 智慧学校源码 微信小程序电子班牌 智慧校园系统简介&#xff1a; 智慧校园的建设逐渐被师生、家长认可接受&#xff0c;智慧校园通过对在校师生、教务等…

IO-DAY8

使用消息队列去实现2个终端之间的互相聊天 要求:千万不要做出来2个终端之间的消息发送是读一写的&#xff0c;一定要能够做到&#xff0c;一个终端发送n条消息&#xff0c;另一个终端一条消息都不回复 A终端&#xff1a; #include<myhead.h> typedef struct msgbuf {lon…

蝙蝠优化算法(bat optimization algorithm)

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 算法背景 蝙蝠优化算法&#xff08;Bat Algorithm&#xff09;是一种基于群体智能的优化算法&#xff0c;它的灵感来源于蝙蝠捕食时的回声定位行…

LeetCode 377——组合总和 Ⅳ

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题一看应该就是需要用到动态规划算法&#xff0c;假设我们以 f[d]表示总和为 d 的元素组合的个数&#xff0c;首先&#xff0c;我们遍历 nums 数组&#xff0c; 如果有 nums[i] < target&#xff0c;那么组…