Linux-【文件系统下】
一、引入inode概念文件 数据 属性 当我们使用ls -l 的时候看到了除了文件名 还能看到文件的元数据 属性ls -l 读取存储在磁盘上的文件信息 然后显示出来其实这个信息除了通过这种方式来读取 一个stat 命令能够查看更多信息文件数据都存储在 块 中 那么很显然我们还必须找到一个地方存储文件的元信息属性信息比如文件的创建者 、文件的创建日期 、 文件大小等等。这种存储文件元信息的区域就叫做 inode中文译名 索引结点每一个文件都有对应的inode里面包含了与该文件有关的一些信息。Linux下文件的存储是属性 和 内容 分离存储的Linux下保存文件属性的集合叫做 inode 一个文件 一个inode inode内有一个唯一的标识符 叫做inode号所以一个文件的属性 inode长什么样子呢 重点文件名不存放在 inode 中因为string的大小会浮动导致inode结点大小改变而是存放在目录文件的数据块里目录项中。这是 inode 设计的一个关键点文件名和 inode 分离使得硬链接成为可能。inode 的大小一般是128字节或者256 我们后面统一 128字节 。这使得文件系统可以像数组一样管理 inode通过 inode 号直接计算出它在磁盘上的位置。任何文件的内容大小可以不同但是属性的大小一定是相同的问题引出1. 硬盘是典型的 块 设备 操作系统读取硬盘数据的时候 读取的基本单位是块 。 块又是硬盘的每个分区下的结构 难道 块 是随意在分区上排布的吗 要如何找到块呢2. 上面提到的存储文件属性的 inode 又是如何放置的 文件系统就是为了组织管理这些的文件系统通过在分区中预先规划出块组在块组中设立位图来管理空闲状态设立inode表来集中存放属性并利用inode内的指针数组来记录内容块的位置从而将一盘散沙的LBA扇区组织成了一个井然有序、可以通过路径和文件名快速存取数据的结构化空间。二、ext2文件系统我们想要在硬盘上存储文件必须先把硬盘格式化为某种格式的文件系统才能存储文件裸硬盘本身只是一堆无序的物理扇区没有任何 “文件” 的概念操作系统无法直接在上面创建、读取或删除文件。格式化的本质给硬盘分区写入一套固定的管理规则文件系统比如 Ext2/Ext3/Ext4、NTFS、FAT32 等。只有完成格式化分区才会被划分成块、块组、inode 表等结构操作系统才能用 “文件” 的方式去组织和访问数据。文件系统的目的就是组织和管理硬盘中的文件数据怎么存把文件内容拆分成块记录块的位置属性怎么存用 inode 存储文件的权限、大小、时间戳等元数据资源怎么分配用位图管理空闲块和 inode避免数据覆盖路径怎么解析用目录文件维护 “文件名 → inode 号” 的映射让用户能通过路径找到文件。2.1 宏观认识ext2 文件系统将整个分区划分成若干个同样大小的块组 (Block Group)只要能管理一个分区就能管理所有分区也就能管理所有磁盘文件上图中启动块Boot Block/Sector的大小是确定的为1KB由PC标准规定用来存储磁盘分区信息和启动信息任何文件系统都不能修改启动块。启动块之后才是ext2文件系统的开始。2.2 Block GroupExt2 文件系统将每个分区划分为若干个 Block Group所有块组的结构完全相同就像一个 “行政区”每个行政区独立管理自己的资源整体又由超级块统一协调。每个 Block Group 的结构从前往后依次为启动块Boot Block→ 超级块Super Block→ 块组描述符表GDT→ 块位图Block Bitmap→ inode 位图Inode Bitmap→ inode 表Inode Table→ 数据块Data Block。2.3 块组内部构成块组的各个组件各司其职共同完成文件的存储与管理缺一不可。inode 和 数据块 跨组编号的inode和数据块不能跨分区所以一个分区内部inode编号和块号是唯一的2.3.1 超级块(Suoer Block)超级块存储整个分区的文件系统全局信息是 Ext 文件系统的核心若超级块损坏整个文件系统将无法使用。其记录的关键信息包括Block 和 Inode 的总数量、空闲数量Block 和 Inode 的大小文件系统的挂载时间、写入时间、磁盘检查时间块组的数量、每个块组的 Block/Inode 数量。为了保证可靠性超级块会在多个块组中进行备份第一个块组必须有防止单个扇区物理损坏导致超级块丢失。2.3.2 GDT(Group Descriptor Table)GDT 包含多个块组描述符一个块组对应一个描述符记录每个块组的局部信息块组内 Block Bitmap、Inode Bitmap、Inode Table 的起始块号块组内空闲 Block、空闲 Inode 的数量块组内已使用的目录数量。GDT 同样会在多个块组中备份与超级块配合实现文件系统的整体管理。2.3.3 块位图(Block Bitmap)位图采用位bit作为单位每一位对应一个 Block 或 Inode用于快速标记资源的空闲 / 占用状态Block Bitmap每一位对应一个 Data Block0 表示空闲1 表示已占用2.3.4 inode位图(Inode Bitmap)Inode Bitmap每一位对应一个 Inode0 表示空闲1 表示已占用。位图的设计让文件系统能快速找到空闲的 Block/Inode避免了遍历整个分区的低效操作。举一个例子删除电影 不需要把内容删掉 只需要把位图清0 对于磁盘来说只要块 inode 没有内容就是乱码无效对于文件的恢复 把位图再置12.3.5 节点表(Inode Table)在 Linux 中文件 内容 属性文件的内容存储在 Data Block 中而文件的属性元信息则存储在Inode索引节点中Inode 表就是块组内所有 Inode 的集合。什么是 InodeInode 是一个固定大小的结构体通常 128/256 字节每个文件对应唯一的一个 Inode且 Inode 编号以分区为单位全局唯一不可跨分区。Inode 中存储的文件属性包括文件的权限、所有者、所属组文件的大小、创建时间、访问时间、修改时间文件占用的 Data Block 编号文件的硬链接数。重要注意文件名并不存储在 Inode 中这是 Linux 文件系统的关键设计也是软硬链接实现的基础。2.3.6 Data BlockData Block 是真正存储文件内容的区域根据文件类型的不同Data Block 的存储内容也不同普通文件直接存储文件的实际数据目录文件存储文件名与 Inode 号的映射关系这是目录的核心本质设备文件 / 管道文件无实际数据Data Block 为空。Data Block 的编号以分区为单位全局唯一不可跨分区文件占用的 Data Block 编号会记录在其对应的 Inode 中。2.4 inode 和 datablock 映射(弱化)Inode 中包含一个块指针数组 i_block [EXT2_N_BLOCKS]EXT2_N_BLOCKS15用于建立 Inode 与 Data Block 的映射关系通过这个数组就能找到文件内容所在的所有 Data Block。问知道inode 号的情况下在指定分区 解释 : 对文件的增 、 删 、 查 、 改 是在做什么分区之后的格式化操作就是对分区进行分组 在每个组中写入 SB 、GDT Block bitmap等管理信息 这些管理信息统称为文件系统只要知道文件的inode号 就能在指定分区中确定是哪一个分组 进而在哪一个分组中确定是哪一个inode拿到inode文件的属性和内容就全部都有了下面通过touch一个新文件来看看如何工作。第一步用 inode 编号查 inode 位图有效性校验每个块组都有一个inode 位图inode bitmap用 1 个 bit 标记对应 inode 是否被占用bit1这个 inode 有效代表存在一个文件 / 目录bit0这个 inode 空闲未被使用。拿到 inode 编号后先去位图里查对应 bit如果是 1 → 说明这个 inode 是合法存在的如果是 0 → 说明这个文件已经被删除或不存在。第二步从 inode 表中读取 inode 结构体每个块组都有一个inode 表inode table是一段连续的磁盘空间里面按顺序存放所有 inode 结构体每个 inode 大小固定比如 128/256 字节。计算偏移inode 在 inode 表中的偏移 (inode 编号 - 1) × 每个 inode 的大小直接读取这段偏移的数据就能得到完整的struct ext2_inode里面包含了文件的所有元信息权限、大小、时间戳、数据块指针等。第三步通过 inode 里的 data block 数组找到文件内容struct ext2_inode里有一个数组i_block[EXT2_N_BLOCKS]通常是 15 个指针前 12 个是直接块指针直接指向存储文件内容的 data block 编号后 3 个是间接块指针指向索引块索引块里再存 data block 编号用来存大文件。只要遍历这个数组就能拿到文件所有 data block 的编号再根据块号 → LBA 地址 → 磁盘扇区最终读出文件的全部内容。2.5 目录与文件名我们平时访问文件时使用的是路径 文件名如 /home/whb/test.c但 Linux 的文件系统核心是 Inode并不直接识别文件名那么从 “文件名” 到 “文件内容 / 属性” 的过程是如何实现的这就涉及到目录的本质、路径解析和路径缓存。目录的本质文件名与 Inode 的映射文件在 Linux 中目录也是一种文件没有特殊的 “目录结构”其本质是目录的属性存储在其对应的 Inode 中与普通文件一致目录的内容存储在其对应的 Data Block 中内容为一系列 “文件名 - Inode 号” 的键值对。所以在一个目录中文件名不可以重复简单来说目录就是一个 “映射表”建立了文件名和 Inode 号的关联这也是为什么删除文件名只是删除目录中的一条映射记录而不是直接删除文件数据。2.6 路径解析问题打开当前工作目录文件 查看当前工作目录文件的内容 ?当前工作目录不也是文件吗 我们访问当前工作目录不也是只知道当前工作目录的文件名吗 要访问它 不也要知道当前工作目录的inode 所以也要打开 当前工作目录的 上一级 目录 ... 上一级目录也是目录 所以类似 递归 需要把路径中所有目录全部解析 出口是 / 根目录 。任何文件 都有路径 访问目标文件 例如以访问/home/whb/test.c为例路径解析的步骤为系统开机后默认知道根目录 “/” 的 Inode 号固定值先打开根目录的 Inode找到其对应的 Data Block在根目录的 Data Block 中查找 “home” 对应的 Inode 号打开 home 目录的 Inode在 home 目录的 Data Block 中查找 “whb” 对应的 Inode 号打开 whb 目录的 Inode在 whb 目录的 Data Block 中查找 “test.c” 对应的 Inode 号找到后即可通过该 Inode 获取文件的属性和内容所在的 Data Block。核心结论访问文件必须依赖路径路径的本质是逐层的目录映射表最终通过文件名找到 Inode 号进而访问文件。所以这个用户提供文件名 进程提供cwd 共同构建了linux的路径结构2.7 路径缓存如果每次访问文件都要从根目录开始逐层解析磁盘上的目录效率会非常低。因此Linux 内核引入了路径缓存dentry 缓存在内存中只在OS中保存不存在磁盘里维护了一棵树形的目录结构由内核结构体struct dentry目录项构成。每个文件 / 目录都对应一个 dentry 结构包含其 Inode 指针、父目录 dentry 指针、子目录 dentry 链表当首次访问某个路径时内核会从磁盘加载目录信息在内存中创建 dentry 结构形成树形缓存后续再次访问该路径时直接从内存的 dentry 缓存中查找无需再访问磁盘大幅提升效率。dentry 缓存采用LRU最近最少使用 机制进行淘汰同时结合哈希表实现快速查找平衡了缓存效率和内存占用。2.8 挂载分区Inode 和 Block 的编号都是以分区为单位的跨分区后 Inode 号会重复那么 Linux 如何管理多个分区的文件系统答案是挂载mount。挂载的本质将一个格式化好的分区与一个空目录建立关联这个目录称为挂载点此后访问该挂载点就是访问对应分区的文件系统。简单来说挂载就是将分区的文件系统 “接入” Linux 的根目录树形结构中。以挂载一个 ext4 格式的磁盘镜像文件为例# 创建磁盘镜像5M dd if/dev/zero of./disk.img bs1M count5 # 格式化为ext4文件系统 mkfs.ext4 disk.img # 创建挂载点 mkdir /mnt/mydisk # 挂载分区到挂载点 sudo mount -t ext4 ./disk.img /mnt/mydisk/ # 卸载分区 sudo umount /mnt/mydisk关键结论未挂载的分区即使格式化了文件系统也无法被访问访问文件时系统会根据路径前缀判断目标文件所在的分区挂载点进而在对应分区中解析 InodeLinux 的根目录树形结构本质是多个挂载的分区通过挂载点连接而成的整体。所以 可以根据访问目标文件的 路径前缀 准确判断我在哪一个分区2.9 文件系统总结三、软硬链接基于 “文件名与 Inode 分离” 的设计Linux 实现了文件链接机制分为硬链接Hard Link和软链接Symbolic Link两者的实现原理和使用场景截然不同是 Linux 文件系统的重要特性。3.1 硬链接硬链接的本质是在目录中添加一条新的 “文件名 - Inode 号” 映射记录让多个文件名指向同一个 Inode这些文件名就是该文件的硬链接。可以对文件进行备份# 创建文件abc touch abc # 为abc创建硬链接def ln abc def # 查看Inode号两者Inode号相同 ls -li abc def # 输出263466 abc 263466 def硬链接的核心特性硬链接与原文件共享同一个 Inode拥有相同的文件属性和内容修改其中一个另一个也会同步变化Inode 中记录了硬链接数创建硬链接时链接数 1删除硬链接时链接数 - 1只有当硬链接数为 0 时系统才会真正删除文件的 Inode 和 Data Block释放磁盘空间硬链接不能跨分区Inode 号仅在分区内唯一# 为abc创建软链接abc.s ln -s abc abc.s # 查看Inode号软链接有独立的Inode号 ls -li # 输出263563 abc 2631678 lrwxrwxrwx 1 root root 3 abc.s - abc硬链接不能指向目录避免目录树形结构出现循环导致路径解析死循环。硬链接的特殊应用Linux 中的.当前目录 和..上级目录 就是硬链接每个目录的硬链接数至少为 2自身的. 父目录中的映射记录若目录有子目录子目录的..会让该目录的硬链接数 1。3.2 软连接链接也叫符号链接的本质是一个独立的文件有自己的 Inode 和 Data Block其 Data Block 中存储的内容不是实际数据而是目标文件的路径 文件名相当于 Windows 中的 “快捷方式”。删掉快捷方式并不会影响文件内容本身# 为abc创建软链接abc.s ln -s abc abc.s # 查看Inode号软链接有独立的Inode号 ls -li # 输出263563 abc 2631678 lrwxrwxrwx 1 root root 3 abc.s - abc软链接的文件权限位以l开头明确标识其为软链接箭头指向目标文件。软链接的核心特性软链接是独立文件有自己的 Inode 和 Data Block与目标文件的 Inode 无关删除软链接不会影响目标文件删除目标文件软链接会变成 “死链接”指向不存在的文件软链接可以跨分区也可以指向目录访问软链接时系统会根据其 Data Block 中存储的路径自动跳转到目标文件实现间接访问。3.3 软硬链接对比特性硬链接软链接Inode 号与目标文件相同有独立的 Inode 号本质目录的映射记录独立的文件跨分区不支持支持指向目录不支持支持目标文件删除仍可访问链接数 0变成死链接存储内容无独立内容共享数据存储目标文件的路径3.4 软硬链接的用途硬链接用于文件备份删除原文件仍可通过硬链接访问、实现.和..目录标识软链接用于简化文件路径如将深层目录的文件链接到根目录、版本管理如将 python3 链接到 python、跨分区访问文件 / 目录。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2418349.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!