『 Linux 』文件系统

文章目录

    • 磁盘构造
      • 磁盘抽象化
    • 磁盘的寻址方式
    • 磁盘控制器
    • 磁盘数据传输
    • 文件系统
      • Inode
      • 数据块(Data Blocks)
      • 超级块(SuperBlock)
      • 块组描述符(Group Descriptor)


磁盘构造

请添加图片描述

磁盘内部构造由磁头臂,磁头,主轴,盘片,盘面,磁道,柱面,扇区构成;

  • 磁头臂控制磁头的移动,可以精确地定位到磁盘上的特定磁道;
  • 磁头负责读取和写入数据;在读取数据时,磁头会检测盘片表面的磁性变化;在写入数据时,磁头会改变盘片表面的磁性,以存储数据;
  • 主轴带有马达,使盘片高速旋转;这种旋转允许磁头访问盘片上的任意位置;
  • 盘片数据存储的介质,通常有多个盘片叠加在一起,每个盘片有两个盘面;
  • 盘面盘片的每一面,用于存储数据;每个盘面都配备有对应的磁头;
  • 磁道盘面上的同心圆,数据以磁道为单位进行组织;每个磁道可以进一步被分割成多个扇区;
  • 柱面由所有盘面上相同磁道号的磁道组成;设想如果磁盘的多个盘片沿主轴方向穿透,形成的圆柱形结构即为柱面;
  • 扇区磁道进一步划分的单位,是磁盘存储数据的最小物理单元;每个扇区通常存储512字节或更多的数据;


磁盘抽象化

请添加图片描述

磁带设备的存储最终数据将被存储到磁带上;

将磁带拉直可以将其看成连续不断的空间;

将磁盘盘面进行抽象化;

由于盘片的高速转动+磁头臂带动磁头的移动可以将其看成是一个螺旋的运动;

螺旋化后拉直为一个以扇区为最小单位的连续不断的空间;

与磁带不同,磁带的访问为顺序访问,磁盘的访问通过盘片的高速旋转+磁头臂带动磁头可以进行随机访问;


磁盘的寻址方式

请添加图片描述

  • CHS(Cylinder-Head-Sector)寻址

    CHS寻址方式使用柱面号,磁头号和扇区号来定位磁盘上的数据;

    每个地址由三个部分组成:柱面号( C ),磁头号( H )和扇区号( S );

    • 柱面号( C ):表示磁盘上的柱面,柱面是所有盘片上相同半径的磁道的集合(从0开始编号);
    • 磁头号( H ):表示盘片上的磁头,磁头用于读取和写入数据(从0开始编号);
    • 扇区号( S ):表示磁道上的扇区,扇区是数据存储的最小单位(从1开始编号);
  • LBA(Logical Block Addressing)寻址

    LBA寻址方式使用逻辑块地址定位磁盘上的数据;

    每个逻辑块地址是一个唯一的整数,表示磁盘上的一个逻辑块(这里指扇区);

    • 逻辑块地址(LBA):表示磁盘上的一个逻辑块,逻辑块是数据存储的基本单位;
    • LBA寻址方式将整个磁盘视为一个连续的逻辑块数组,每个逻辑块都有一个唯一的地址;

因物理原因, LBA(Logical Block Addressing) 寻址最终以算法转换为 CHS(Cylinder-Head-Sector) 寻址;

  • LBA寻址转换为CHS寻址公式

    • 柱面号( C )

      C = LBA / ( H * S );
      
    • 磁头号( H )

      H = ( LBA / S ) % H;
      
    • 扇区号( S )

      S = ( LBA % S ) + 1; #CHS中扇区号从1开始计算
      
    • 例:

      • 磁盘有3盘片(6盘面);
      • 每个盘面有20000个扇区;
      • 每个盘面有50个磁道;
      • 每个磁道有400个扇区;
      • 需要访问的扇区编号(LBA)为28888;

      柱面号的计算:28888 / ( 50 * 400 ) = 1;

      相对扇区计算:28888 % ( 50 * 400 ) = 8888;

      磁道编号计算:8888 / 400 = 22;

      磁道上相对扇区编号:8888 % 400 = 88;

      结果:

      • 盘面编号:1;
      • 磁道编号:22;
      • 扇区编号:89(从1开始编号);

CHS寻址方式逆向得到LBA编号;


磁盘控制器

请添加图片描述

磁盘硬件中存在磁盘控制器(物理硬件);

  • 磁盘控制器的功能:
    • 数据传输
    • 执行命令
    • 错误检测和纠正
    • 缓存管理

在磁盘控制器中存在一系列的寄存器(硬件):命令寄存器,数据寄存器,状态寄存器,地址寄存器等;

  • 命令寄存器

    用于存储来自计算机的操作命令;

  • 数据寄存器

    用于暂存从计算机写入磁盘的数据,或者从磁盘读取的数据;

  • 状态寄存器

    用于指示当前磁盘的状态,以及最近一次操作的结果;

  • 地址寄存器

    用于指定数据在磁盘上的位置,如扇区号或磁道号;

同时在磁盘硬件中为用户提供了一系列的 接口/串口 ;

接口/串口 作为驱动程序与磁盘控制器之间的桥梁,操作系统将通过磁盘接口(接口/串口)间接调用磁盘控制器从而操作磁盘;


磁盘数据传输

请添加图片描述

计算机中存在一种允许外部设备直接与系统内存进行数据传输的硬件组件DMA;

DMA(Direct Memory Access,直接内存访问);

DMA在进行数据传输时无需经过CPU因此可以减少CPU负担;

假设用户请求创建一个名为newfile.txt新文件并写入数据:

  • 用户请求

    用户请求或进程调用open("newfile.txt", O_CREAT | O_WRONLY);

  • 系统调用处理

    CPU将系统调用转发给OS;

    OS内核文件系统模块接收请求;

  • 文件系统操作

    文件系统将维护对应的结构体并为其分配数据块;

  • 数据写入

    用户或应用程序调用write进行数据写入;

    文件系统写入分配的数据块;

  • DMA配置

    OS配置DMA控制器设置源地址和目标地址并启动DMA传输;

  • 驱动程序操作

    驱动程序将写入命令和数据块地址发送给磁盘控制器;

    驱动程序处理终端和状态信息;

  • 磁盘控制器操作

    磁盘控制器接收写入命令并解析;

    磁盘控制器通过DMA从内存读取数据并写入磁盘扇区;

    磁盘控制器报告状态;


文件系统

请添加图片描述

操作系统通常无法直接管理巨大的磁盘空间,因此需要对磁盘进行分区(类比Windows中对C,D,E,F盘的分区);

分区的方式一般通过操作系统维护其struct结构体即可;

struct partion{
    int start;
    int end;
    //...
}

而实际每个分区的大小也会比较大,需要继续对分区进行区分管理;

一般情况下每个分区都由以下组成:

  • 启动块(Boot Block)

    一般情况下BootBlock为引导块,只存在于系统盘当中;

    但有些情况也会存在其他分区当中;

    存在该块的分区一般被称为引导分区;

  • 块组(Block group)

    每个分区由若干个块组组成,由Blockgroup 0Blockgroup n;

    块组是文件系统重最基本的管理单元,每个块组包含多个数据块,Inode表和其他元数据;

(该图为演示,与内核空间映像存在差异)

块组中所包含的多个数据块即为文件系统;

每个块组通常包含以下几个部分:

  • 超级块(Superblock)

    • 存储文件系统的全局元数据;
  • 块组描述符表(Group Descriptor Table)

    • 存储每个块组的描述符,描述块组的元数据位置和状态;
  • 块位图(Block Bitmap)

    • 跟踪块组中数据块的使用情况;
  • Inode位图(Inode Bitmap)

    • 跟踪块组中Inode的使用情况;
  • Inode表(Inode Table)

    • 存储文件和目录的元数据;
    • Inode表中将存若干个Inode;
    • Inode用于存储文件基本属性(如文件类型,文件权限,拥有者,所属组等);
  • 数据块(Data Blocks)

    • 存储实际的文件和目录内容;

假设存在一个文件系统,其应包含以下块组:

struct superblock {
    int fs_size;  // 文件系统的大小
    int block_size;  // 块大小
    int free_blocks;  // 空闲块数量
    int free_inodes;  // 空闲Inode数量
    // 其他文件系统元数据
};

struct group_descriptor {
    int block_bitmap;  // 块位图的起始位置
    int inode_bitmap;  // Inode位图的起始位置
    int inode_table;  // Inode表的起始位置
    int free_blocks;  // 块组中的空闲块数量
    int free_inodes;  // 块组中的空闲Inode数量
    // 其他块组元数据
};

struct block_group {
    struct superblock sb;  // 超级块
    struct group_descriptor gd;  // 块组描述符
    char block_bitmap[128];  // 块位图
    char inode_bitmap[128];  // Inode位图
    struct inode inodes[1024];  // Inode表
    char data_blocks[4096][4096];  // 数据块
};

struct inode {
    int file_type;  // 文件类型
    int permissions;  // 文件权限
    int size;  // 文件大小
    int block_pointers[12];  // 数据块指针
    // 其他文件元数据
};

磁盘中最小的存储单位为扇区,而在文件系统中最小的单位为 文件系统块 ;

存储数据的数据块中存在若干个 文件系统块 ;

文件系统块的大小必须 >= 扇区大小,一般最常用为4kb;

  • 在数据的存储中,一般只有最后一个文件系统块会产生空间浪费:

    假设一个文件的的大小为5kb,将会为其分配两个文件系统块用于存储,其中第二个块为最后一个块将浪费3kb的空间;


Inode

请添加图片描述

在Linux中,文件的内容与文件的属性构成一个完整的文件;

其中文件的内容与文件的属性是分开管理的;

  • 文件的内容管理在数据块(Data Blocks)中
  • 文件的属性管理在Inode表中的Inode中;

Inode可以看作是一个结构体,其包含一个文件的所有属性:

struct inode {
    uint16_t i_mode;        // 文件类型和权限
    uint16_t i_uid;         // 文件所有者的用户ID
    uint32_t i_size;        // 文件大小(字节)
    uint32_t i_atime;       // 最后访问时间
    uint32_t i_ctime;       // 创建时间
    uint32_t i_mtime;       // 最后修改时间
    uint32_t i_dtime;       // 删除时间
    uint16_t i_gid;         // 文件所属组的组ID
    uint16_t i_links_count; // 链接计数
    uint32_t i_blocks;      // 文件占用的块数
    uint32_t i_flags;       // 文件标志
    uint32_t i_block[15];   // 数据块指针
    // 其他文件系统特定的信息
};

其中每个Inode都在对应的文件系统中存在一个唯一编号(不同文件系统之间的Inode编号可以重复);

在Linux当中可以采用ls -li获取其Inode编号;

$ ls -li
total 0
2360117 -rw-rw-r-- 1 _XXX _XXX 0 Jun  1 18:02 newfile1.c
2360116 -rw-rw-r-- 1 _XXX _XXX 0 Jun  1 18:00 newfile.c

其中在每个块组中都存在一个Inode位图(Inode Bitmap)来跟踪该文件系统中的Inode的使用情况(利用位图可以大大节省跟踪时所使用的空间);

当需要访问一个文件时文件系统将根据Inode中的编号查找文件的目录和数据块指针从而访问文件的实际数据;

  • 文件的文件名不存在于Inode之中,而是单独存放在目录的数据结构当中

    每个目录在文件系统当中被视为一个特殊的文件,其自身拥有一个Inode与数据块;

    目录中的数据块保存了文件名与对应Inode编号的映射关系,这些映射关系被称为目录条目;

    • 目录条目的结构演示

      struct directory_entry {
          uint32_t inode_number;  // Inode编号
          char file_name[256];    // 文件名
      };
      

      当通过文件名访问文件时文件系统将会执行以下步骤:

      假设文件路径为/home/user/file.txt;

      • 根目录(/)

        查找根目录的Inode(通常为Inode2);

        在根目录的数据块中查找home目录的目录条并获取其Inode编号;

      • home目录

        查找home目录的Inode;

        home目录的数据块中,查找user目录的目录条目并获取其Inode编号;

      • user目录

        查找user目录的Inode;

        user目录的数据块中,查找file.txt的目录条目并获取其Inode编号;

      • file.txt文件

        查找file.txt的Inode;

        通过Inode中的数据块指针访问其文件的实际数据;


数据块(Data Blocks)

请添加图片描述

数据块中存在若干个文件系统块;

在文件系统中的块位图(Bolck Bitmap)即为跟踪当前文件系统中数据块内各个文件系统块的使用情况;

在Inode中存在一组数据块指针数组,一般情况这个指针数组的大小为15;

这个指针数组中包含了三种数据块指针:

  • 直接指针(Direct Pointers)
    • 通常有12个直接指针,每个直接指针直接指向一个数据块(下标0-11)。
    • 直接指针用于存储文件的前12个数据块。
  • 单重间接指针(Single Indirect Pointer)
    • 指向一个间接块,间接块中包含指向数据块的指针(下标12)。
    • 单重间接指针用于存储更多的数据块。
  • 双重间接指针(Double Indirect Pointer)
    • 指向一个双重间接块,双重间接块中包含指向间接块的指针,间接块中再包含指向数据块的指针(下标13)。
    • 双重间接指针用于存储更多的数据块。
  • 三重间接指针(Triple Indirect Pointer)
    • 指向一个三重间接块,三重间接块中包含指向双重间接块的指针,双重间接块中再包含指向间接块的指针,间接块中再包含指向数据块的指针(下标14)。
    • 三重间接指针用于存储更多的数据块。

可以将其中的数据块指针数据看成是一种树状结构;

删除一个文件的本质是删除其对应文件系统中的Block Bitmap以及相关映射删除(所以理论上数据的删除可以被修复),当需要再此使用时只需要对文件系统块对应的内容进行覆盖即可;


超级块(SuperBlock)

请添加图片描述

超级块中包含了当前文件系统中的全局信息和元数据(文件系统大小,块大小,空闲块数量等);

通常超级块位于文件系统的起始位置,每个块组中都可以存在一个超级块以便于在超级块损坏时可以进行对超级块的恢复;

超级块通常存在以下内容:

  • 文件系统元数据
    • 超级块包含文件系统的全局元数据,如文件系统的大小、块大小、空闲块数量、空闲Inode数量等。
    • 这些元数据用于文件系统的管理和操作。
  • 文件系统状态
    • 超级块包含文件系统的状态信息,如文件系统是否已挂载、是否已清除等。
    • 这些状态信息用于文件系统的维护和恢复。
  • 文件系统配置
    • 超级块包含文件系统的配置参数,如块大小、Inode大小、块组大小等。
    • 这些配置参数用于文件系统的初始化和操作。

超级块的结构示例如下:

struct superblock {
    uint32_t s_inodes_count;        // 文件系统中的Inode总数
    uint32_t s_blocks_count;        // 文件系统中的块总数
    uint32_t s_r_blocks_count;      // 保留块总数
    uint32_t s_free_blocks_count;   // 空闲块总数
    uint32_t s_free_inodes_count;   // 空闲Inode总数
    uint32_t s_first_data_block;    // 第一个数据块的块号
    uint32_t s_log_block_size;      // 块大小(以2的幂次表示)
    uint32_t s_log_frag_size;       // 碎片大小(以2的幂次表示)
    uint32_t s_blocks_per_group;    // 每个块组的块数
    uint32_t s_frags_per_group;     // 每个块组的碎片数
    uint32_t s_inodes_per_group;    // 每个块组的Inode数
	//...
    // 其他文件系统特定的信息
};

块组描述符(Group Descriptor)

请添加图片描述

块组描述符用于描述每个块组的元数据位置和状态;

其一般包含了所有块组的描述符,其中每个块组都有一个对应的块组描述符;

  • 块组描述符的作用

    • 描述块组元数据的位置

      块组描述符一般包含组内重要的元数据(块位图,Inode位图,Inode表)的起始位置;

      通过快描述符使得文件系统可以快速定位组内元数据;

    • 跟踪块组的状态

      块组描述符包含块组内空闲块和空闲Inode的数量;

      这些信息一般用于文件系统的管理和优化;

块组描述符的结构示例:

struct group_descriptor {
    uint32_t block_bitmap;  // 块位图的起始位置
    uint32_t inode_bitmap;  // Inode位图的起始位置
    uint32_t inode_table;   // Inode表的起始位置
    uint16_t free_blocks_count; // 块组中的空闲块数量
    uint16_t free_inodes_count; // 块组中的空闲Inode数量
    uint16_t used_dirs_count;   // 块组中的已使用目录数量
    // 其他块组元数据
};

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

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

相关文章

Exce 两列一组对齐呈现,缺失补 0

Excel 里有 多 组数据,每组 2 列,每组长度不同。第 1 列是编号,列之间的编号有重复。 ABCDEFGH1Mass10Mass11Mass12Mass132802200581309088146532802225938133306824779282975598142002482273148413154988335698822331305832720485110460842…

go解析yaml

go解析yaml文件关键就是结构体的创建 初学go tag字段要和yaml文件中的key对应起来,每个层级都要创建对应的结构体,有点烦 package configimport ("gopkg.in/yaml.v3""os" )type Config struct {MysqlConfig MysqlConfig yaml:&q…

Spring Boot 开发 -- 过滤器与拦截器详解

引言 在Web开发中,经常需要对请求进行预处理或在响应后进行后处理,Spring Boot提供了过滤器和拦截器两种机制来实现这一需求。虽然它们都可以用来处理HTTP请求和响应,但在使用场景、执行顺序和配置方式上存在明显的差异。本文将详细讲解Spri…

【UML用户指南】-01-UML基本元素的介绍(一)

1、UML的词汇表 (1)事物; (2)关系; (3)图。 事物是对模型中首要成分的抽象;关系把事物结合在一起;图聚集了相关的事物。 注:事物也称为元素 2…

东芝机械人电池低报警解除与机器人多旋转数据清零

今天启动一台设备,触摸屏一直显示机器人报警(翻译过后为电池电量低),更换电池后关机重启后也不能消除,所以打开示教器,下面就来说说怎么解决此项问题(可以参考官方发的手册,已手册为…

携程梁建章:持续投资创新与AI,开启旅游行业未来增长

5月30至31日,携程集团在上海和张家界举办Envision 2024全球合作伙伴大会,邀请超50个国家和地区的1600余名外籍旅游业嘉宾与会,共同探讨中国跨境旅游市场发展机遇,讲好中国故事。 携程国际业务增速迅猛,创新与AI解锁未…

IntelliJ IDEA / Android Studio 方法显示Git提交人

显示方法: 设置 > 编辑器 > 嵌入提示 > Code Vision > 代码作者(勾选) IntelliJ IDEA Android Studio

css-表头筛选的特定样式

背景 饿了么的表头筛选样式比较简单,如图1,产品觉得不够醒目(觉得用户可能不知道这是筛选,我表示不理解) 要求改进筛选的样式,达到图2的效果,主要是状态列,既希望这列的宽度固定&a…

git应用最佳实践

插: AI时代,程序员或多或少要了解些人工智能,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家(前言 – 人工智能教程 ) 坚持不懈,越努力越幸运,大家…

Linux内网中安装jdk1.8详细教程

本章教程,主要介绍如何在内网环境中配置JDK1.8环境变量 一、下载Linux版压缩包 下载地址:https://www.oracle.com/java/technologies/downloads/#java8 下载完成之后,通过XFTP等工具,将安装包上传到内网服务器 二、安装配置步骤 1、解压压缩包 tar -zxvf /usr/local/jdk-…

jpeg编码学习

正点原子stm32教程提到过jpeg解码库libjpeg,但是没有提到jpeg编码,我也好奇jpeg编码怎么实现,用代码怎么生成jpeg文件的。所以最近学习了jpeg编码,在这里做记录。 参考文章 jpeg图片格式详解 https://blog.csdn.net/yun_hen/art…

【嵌入式DIY实例】-OLED显示网络时钟

OLED显示网络时钟 文章目录 OLED显示网络时钟1、硬件准备与接线2、代码实现在上一个ESP8266 NodeMCU文章中,我们用DS3231 RTC芯片和SSD1306 OLED制作了一个简单的实时时钟,时间和日期显示在SSD1306屏幕上,并且可以通过两个按钮进行设置。 在本中,我们将使用ESP 8266 NodeMC…

SpringBoot 多模块 多环境 项目 单元测试

环境描述 假设项目中有以下三个yml文件: application.ymlapplication-dev.ymlapplication-prod.yml 假设项目各Module之间依赖关系如下: 其中,D依赖C,C依赖B,B依赖A,D对外提供最终的访问接口 现在要想采…

glpi 安装与使用

1、环境介绍 操作系统:龙蜥os 8.9 nginx:1.26.1 php:8.2.19 mysql:MarinaDB 10.3.9 glpi:10.0.6 fusioninventory:fusioninventory-10.0.61.1 2、安装epel源 dnf install epel-release -y dnf install htt…

洗地机什么牌子好?洗地机前十名排行榜

现代吸拖扫一体洗地机不仅高效,还具有智能化设计,使清洁变得轻松。它强大的吸尘功能能够轻松应对灰尘和碎屑,不论是硬质地面还是地毯,都能提供理想的清洁效果。配合拖地功能,通过内置水箱和智能拖布,能彻底…

纵向导航栏使用navbar-nav-scroll溢出截断问题

项目场景: 组件:Bootstrap-4.6.2、JQuery 3.7.1 测试浏览器:Firefox126.0.1、Microsoft Edge125.0.2535.67 IDE:eclipes2024-03.R 在编写CRM的工作台主页面时,由于该页面使用的是较旧的技术,所以打算使用…

virtualbox识别windows上usb设备

当你插入 USB 时,你的宿主操作系统可以轻松访问它并使用其中的文件。如果需要VirtualBox 的虚拟机也能访问物理机的 USB设备,需要安装安装扩展包管理器。 第一步: 要安装 VirtualBox 扩展包,只需访问 VirtualBox 官方下载页面&a…

OpenCV学习 基础图像操作(十七):泛洪与分水岭算法

原理 泛洪填充算法和分水岭算法是图像处理中的两种重要算法,主要用于区域分割,但它们的原理和应用场景有所不同,但是他们的基础思想都是基于区域迭代实现的区域之间的划分。 泛洪算法 泛洪填充算法(Flood Fill)是一…

seaborn和matplotlib显示两条曲线图例

总结,添加label和plt.legend,以下由chatgpt生成 在使用 Seaborn 的 kdeplot(核密度估计图)时,显示图例也是一个常见需求,尤其是当你想比较多个不同分布的数据时。下面我将提供一个示例,说明如何…

实战还原AI驱动的网络攻击:如何构建SecOps智能自动化防线

随着AI技术的迅猛发展,网络攻击手段日益多样化和高度自动化,给企业和个人带来了巨大网络安全挑战。在此背景下,为企业提供全面高效安全保障的Fortinet SecOps解决方案应运而生。在Fortinet 2024网安攻防“Demo季”第二期直播中,Fo…