『 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;         // 文件所有者的用户IDuint32_t i_size;        // 文件大小(字节)uint32_t i_atime;       // 最后访问时间uint32_t i_ctime;       // 创建时间uint32_t i_mtime;       // 最后修改时间uint32_t i_dtime;       // 删除时间uint16_t i_gid;         // 文件所属组的组IDuint16_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;   // 块组中的已使用目录数量// 其他块组元数据
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs2019 QT UI 添加新成员或者控件代码不提示问题解决方法

右键点击头文件,添加ui的头文件 添加现有项 找到uic目录的头文件 打开ui,QtWidgetsApplication2.ui,进行测试 修改一个名字: 重点: 设置一个布局: 点击生成解决方案: 以后每次添加控件后,记得点击保存 这样…

flink 作业报日志类冲突的解决方案

文章目录 背景思考初步解决方案深入思考下终极解决方案总结 背景 实时作业在页面提交任务后,报NoSuchMethodException 方法,看了下是关于log4j的,首先是作业升级了很多依赖的版本,其次flink 也升级 到了1.19版本 思考 打的Jar有…

CSS选择器的常见用法

大家好,本期博客整理了前端语言 CSS 中选择器的入门级常见用法,希望能对大家有所帮助 CSS 选择器的主要功能就是选中⻚⾯指定的标签元素,选中了元素,才可以设置元素的属性。 那么,css选择器有哪几种呢? 以…

全面理解渗透测试

揭秘网络安全的秘密武器:全面理解渗透测试 在数字化时代,网络安全已成为人们关注的焦点。网络攻击和数据泄露事件频发,给个人、企业和国家带来了巨大的损失。为了应对这一挑战,渗透测试作为一种重要的网络安全评估手段&#xff0…

Docker-----emqx部署

emqx通过Docker容器化部署流程 1.创建持久化挂载目录 mkdir -p /home/emqx/etc ------挂载emqx的配置文件目录 mkdir -p /home/emqx/data ------挂载emqx的存储目录 mkdir -p /home/emqx/log ------挂载emqx的日志目录 [root home]# mkdir -p /home/emqx/etc [root home]# mkd…

【Redis】 使用Java操作Redis的客户端

文章目录 🍃前言🌴项目的创建🎋引入依赖🌳配置端⼝转发🌲更改 Redis 配置文件🎄连接 Redis Server⭕总结 🍃前言 我们使用 Java 操作 Redis 客户端时我们需要进行以下操作。 注意:J…

Linux上部署和安装MinIO

🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主 📌 擅长领域:全栈工程师、爬虫、ACM算法,大数据,深度学习 💒 公众号…

2024年6月1日 (周六) 叶子游戏新闻

Embracer探讨单机游戏大作涨价超过70美元的可能性在Embracer集团等待公布新公司名称的同时,他们对游戏大作的价格上涨做出了评论。几年来,游戏大作的价格已经达到了70美元的门槛。Embracer集团的CEO Lars Wingefors在采访中表示,电子游戏行业…

vulnhub靶场之FunBox-10

一.环境搭建 1.靶场描述 As always, its a very easy box for beginners. This works better on VitualBox rather than VMware 2.靶场下载 Funbox: Under Construction! ~ VulnHub 3.靶场启动 靶场IP地址我们不知道,但是网段我们知道是192.168.2.0/24 二.信息…

stack学习

std::stack 类是一种容器适配器,它给予程序员栈的功能——特别是 FILO(先进后出)数据结构。该类模板用处为底层容器的包装器——只提供特定函数集合。栈从被称作栈顶的容器尾部推弹元素。 operator 赋值给容器适配器 (公开成员函数) 元素访问…

Base64码转换

title: Base64码转换 date: 2024-06-01 20:30:28 tags: vue3 后端图片前端显示乱码 现象 后端传来一个图片,前端能够接收,但是console.log()后发现图片变成了乱码,但是检查后台又发现能够正常的收到了这张图片。 处理方法 笔者有尝试将图…

Java关键字详解

文章目录 什么是关键字?数据类型(10个)byte、char、boolean、short、int、float、long、double、void、enum 流程控制(12个)if、else、do、while、for 、switch、case、assertbreak(跳出循环)co…

STM32(八):独立看门狗 (标准库函数)

前言 上一篇文章介绍了STM32单片机中的USART串口通信,这篇文章我们来介绍一下如何用STM32单片机中的独立看门狗来实现检测按键点灯的程序。 一、实验原理 单片机系统会由于受到外界的干扰,而造成程序执行紊乱,系统无法正常运行。为了防止这…

STL:stack和queue

文章目录 stack的介绍和使用stack的介绍stack的使用stack的模拟实现 queue的介绍和使用queue的介绍queue的使用queue的模拟实现 priority_queue的介绍和使用priority_queue的介绍priority_queue的使用优先级队列的模拟实现 deque的介绍deque的结构deque的缺陷为什么选择deque作…

Django ORM魔法:用Python代码召唤数据库之灵!

探索Django ORM的神奇世界,学习如何用Python代码代替复杂的SQL语句,召唤数据库之灵,让数据管理变得轻松又有趣。从基础概念到高级技巧,阿佑带你一步步成为Django ORM的魔法师,让你的应用开发速度飞起来! 文…

golang线程池ants-四种使用方法

目录 1、ants介绍 2、使用方式汇总 3、各种使用方式详解 3.1 默认池 3.2 普通模式 3.3 带参函数 3.4 多池多协程 4、总结 1、ants介绍 众所周知,goroutine相比于线程来说,更加轻量、资源占用更少、无线程上下文切换等优势,但是也不能…

前端Vue小兔鲜儿电商项目实战Day06

一、本地购物车 - 列表购物车 1. 基础内容渲染 ①准备模板 - src/views/cartList/index.vue <script setup> const cartList [] </script><template><div class"xtx-cart-page"><div class"container m-top-20"><div…

vs2019 无法打开QT的UI文件

/* * --------------------------- Microsoft Visual StudioQt5.15.2\5.15.2\msvc2019_64 --------------------------- D:\QT_Project_vs\QtWidgetsApplication1\QtWidgetsApplication1\QtWidgetsApplication1.ui 无法打开文件。 --------------------------- 确定 -------…

基于LQR控制算法的电磁减振控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于LQR控制算法的电磁减振控制系统simulink建模与仿真。仿真输出控制器的收敛曲线。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a 08_029m 4.系统原理…

系统架构设计师【第5章】: 软件工程基础知识 (核心总结)

文章目录 5.1 软件工程5.1.1 软件工程定义5.1.2 软件过程模型5.1.3 敏捷模型5.1.4 统一过程模型&#xff08;RUP&#xff09;5.1.5 软件能力成熟度模型 5.2 需求工程5.2.1 需求获取5.2.2 需求变更5.2.3 需求追踪 5.3 系统分析与设计5.3.1 结构化方法5.3.2 面向对象…