前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【linux学习指南】】Ext系列文件系统(三)ext2 文件系统的认识与构成

【linux学习指南】】Ext系列文件系统(三)ext2 文件系统的认识与构成

作者头像
学习起来吧
发布2025-01-01 08:48:13
发布2025-01-01 08:48:13
9500
代码可运行
举报
文章被收录于专栏:学习C/++
运行总次数:0
代码可运行

📝ext2 ⽂件系统

🌠 宏观认识

所有的准备⼯作都已经做完,是时候认识下⽂件系统了。我们想要在硬盘上储⽂件,必须先把硬盘格式化为某种格式的⽂件系统,才能存储⽂件。⽂件系统的⽬的就是组织和管理硬盘中的⽂件。在Linux 系统中,最常⻅的是ext2系列的⽂件系统。其早期版本为ext2,后来⼜发展出ext3ext4ext3ext4虽然对ext2进⾏了增强,但是其核⼼设计并没有发⽣变化,我们仍是以较⽼的ext2作为演⽰对象。

ext2⽂件系统将整个分区划分成若⼲个同样⼤⼩的块组(BlockGroup),如下图所⽰。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘⽂件。

上图中启动块(BootBlock/Sector)的⼤⼩是确定的,为1KB,由PC标准规定,⽤来存储磁盘分区信息和启动信息,任何⽂件系统都不能修改启动块。启动块之后才是ext2⽂件系统的开始。

🌉 Block Group

ext2⽂件系统会根据分区的⼤⼩划分为数个BlockGroup。⽽每个BlockGroup都有着相同的结构组成。 政府管理各区的例⼦:

  1. 类比政府管理各区来理解BlockGroup结构
    • 超级块(Superblock)副本 - 相当于区政府管理中心
      • 就像每个区都有一个管理中心(超级块副本),在文件系统中,每个BlockGroup都有超级块副本。它存储了文件系统的关键信息,如文件系统的类型(这里是ext2)、块大小、inode数量等。
      • 这就好比区政府管理中心掌握着本区的基本规划信息(如区域面积大小、功能分区数量等)。而且这些信息是非常重要的,当主超级块损坏时,这些副本可以用于恢复文件系统的基本参数。
    • 块位图(Block Bitmap) - 类似土地资源管理部门
      • 块位图负责记录块的使用情况,就像土地资源管理部门记录区内土地(块)的使用状态一样。如果块位图中的某一位为1,表示对应的块已经被使用;为0则表示块未被使用。
      • 当需要分配新的土地(数据块)用于存储文件数据时,这个“土地资源管理部门”(块位图)就会查找未使用的土地(空闲块)来进行分配。
    • inode位图(inode Bitmap) - 类似居民信息登记部门
      • inode位图用于记录inode的使用状态,类似于居民信息登记部门记录区内居民(inode)的居住(使用)情况。一位为1表示对应的inode已经被使用,为0表示未被使用。
      • 当有新居民(新文件)要入住(创建)时,这个“居民信息登记部门”(inode位图)就会查找空闲的居民名额(空闲inode)来登记新居民(存储文件属性)。
    • inode表(inode Table) - 类似居民档案库
      • inode表就像是一个居民档案库,每个inode(居民档案)存储了文件(居民)的各种属性信息,如文件的类型(普通文件、目录、符号链接等)、文件的访问权限、文件的大小、文件的创建时间、修改时间、访问时间以及最重要的文件数据块指针。
      • 当需要查询某个居民(文件)的详细信息(属性)时,就会通过居民编号(inode编号)在这个“居民档案库”(inode表)中查找对应的档案(inode)。
    • 数据块(Data Blocks) - 类似居民住宅和商业用地等实际土地用途区域
      • 数据块是真正存储文件数据内容的地方,就好比区内的居民住宅、商业用地等实际使用的土地。对于小文件,可能只占用少量的数据块,就像小商店只占用一小块土地一样;而大文件可能会占用多个数据块,如同大型商场需要占用大面积的土地。

🌠块组内部构成

🌉超级块(SuperBlock)

存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息。记录的信息主要有:bolck和inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。SuperBlock的信息被破坏,可以说整个⽂件系统结构就被破坏了

超级块在每个块组的开头都有⼀份拷⻉(第⼀个块组必须有,后⾯的块组可以没有)。为了保证⽂ 件系统在磁盘部分扇区出现物理问题的情况下还能正常⼯作,就必须保证⽂件系统的superblock信 息在这种情况下也能正常访问。所以⼀个⽂件系统的superblock会在多个blockgroup中进⾏备份, 这些superblock区域的数据保持⼀致。

代码语言:javascript
代码运行次数:0
复制
/*
 * Structure of the super block
 */
struct ext2_super_block
{
    __le32 s_inodes_count;
    /* Inodes count */
    __le32 s_blocks_count;
    /* Blocks count */
    __le32 s_r_blocks_count; /* Reserved blocks count */
    __le32 s_free_blocks_count;
    /* Free blocks count */
    __le32 s_free_inodes_count;
    __le32 s_first_data_block;
    /* Free inodes count */
    /* First Data Block */
    __le32 s_log_block_size; /* Block size */
    __le32 s_log_frag_size;
    /* Fragment size */
    __le32 s_blocks_per_group;
    /* # Blocks per group */
    __le32 s_frags_per_group; /* # Fragments per group */
    __le32 s_inodes_per_group;
    __le32 s_mtime;
    __le32 s_wtime;
    __le16 s_mnt_count;
    /* # Inodes per group */
    /* Mount time */
    /* Write time */
    /* Mount count */
    __le16 s_max_mnt_count;
    __le16 s_magic;
    __le16 s_state;
    __le16 s_errors;
    /* Maximal mount count */
    /* Magic signature */
    /* File system state */
    /* Behaviour when detecting errors */
    __le16 s_minor_rev_level; /* minor revision level */
    __le32 s_lastcheck;
    __le32 s_checkinterval;
    __le32 s_creator_os;
    __le32 s_rev_level;
    __le16 s_def_resuid;
    __le16 s_def_resgid;
    /* time of last check */
    /* max. time between checks */
    /* OS */
    /* Revision level */
    /* Default uid for reserved blocks */
    /* Default gid for reserved blocks */
    /*
     * These fields are for EXT2_DYNAMIC_REV superblocks only.
     *
     * Note: the difference between the compatible feature set and
     * the incompatible feature set is that if there is a bit set
     * in the incompatible feature set that the kernel doesn't
     * know about, it should refuse to mount the filesystem.
     *
     * e2fsck's requirements are more strict; if it doesn't know
     * about a feature in either the compatible or incompatible
     * feature set, it must abort and not try to meddle with
     * things it doesn't understand...
     */
    __le32 s_first_ino;              /* First non-reserved inode */
    __le16 s_inode_size;             /* size of inode structure */
    __le16 s_block_group_nr;         /* block group # of this superblock */
    __le32 s_feature_compat;         /* compatible feature set */
    __le32 s_feature_incompat;       /* incompatible feature set */
    __le32 s_feature_ro_compat;      /* readonly-compatible feature set */
    __u8 s_uuid[16];                 /* 128-bit uuid for volume */
    char s_volume_name[16];          /* volume name */
    char s_last_mounted[64];         /* directory where last mounted */
    __le32 s_algorithm_usage_bitmap; /* For compression */
    /*
     * Performance hints.  Directory preallocation should only
     * happen if the EXT2_COMPAT_PREALLOC flag is on.
     */
    __u8 s_prealloc_blocks;     /* Nr of blocks to try to preallocate*/
    __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
    __u16 s_padding1;
    /*
     * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
     */
    __u8 s_journal_uuid[16]; /* uuid of journal superblock */
    __u32 s_journal_inum;    /* inode number of journal file */
    __u32 s_journal_dev;     /* device number of journal file */
    __u32 s_last_orphan;     /* start of list of inodes to delete */
    __u32 s_hash_seed[4];    /* HTREE hash seed */
    __u8 s_def_hash_version; /* Default hash version to use */
    __u8 s_reserved_char_pad;
    __u16 s_reserved_word_pad;
    __le32 s_default_mount_opts;
    __le32 s_first_meta_bg; /* First metablock block group */
    __u32 s_reserved[190];  /* Padding to the end of the block */
};

🌠GDT(GroupDescriptorTable)

块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储⼀个块组的描述信息,如在这个块组中从哪⾥开始是inodeTable,从哪⾥开始是Data Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。

代码语言:javascript
代码运行次数:0
复制
// 磁盘级blockgroup的数据结构
/*
 * Structure of a blocks group descriptor
 */
struct ext2_group_desc
{
    __le32 bg_block_bitmap;/* Blocks bitmap block */
    __le32 bg_inode_bitmap;/* Inodes bitmap */
    __le16 bg_free_blocks_count; /* Inodes table block*/
    __le32 bg_inode_table;/* Free blocks count */
    __le16 bg_free_inodes_count;/* Free inodes count */
    __le16 bg_used_dirs_count; /* Directories count */
    __le16 bg_pad;
    __le32 bg_reserved[3];
};

🌉块位图(BlockBitmap)

BlockBitmap中记录着DataBlock中哪个数据块已经被占⽤,哪个数据块没有被占⽤

🌉inode位图(InodeBitmap)

每个bit表⽰⼀个inode是否空闲可⽤。

🌉i节点表(InodeTable)

  • 存放⽂件属性如⽂件⼤⼩,所有者,最近修改时间等
  • 当前分组所有Inode属性的集合
  • inode编号以分区为单位,整体划分,不可跨分区

🌉Data Block

数据区:存放⽂件内容,也就是⼀个⼀个的Block。根据不同的⽂件类型有以下⼏种情况:

🌉块位图(BlockBitmap)

  • 对于普通⽂件,⽂件的数据存储在数据块中。
  • 对于⽬录,该⽬录下的所有⽂件名和⽬录名存储在所在⽬录的数据块中,除了⽂件名外,ls-l命令看到的其它信息保存在该⽂件的inode中。
  • Block 号按照分区划分,不可跨分区

🌠inode和datablock映射(弱化)

  • inode内部存在_ _le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ , EXT2_N_BLOCKS =15,就是⽤来进⾏inode和block映射的
  • 这样⽂件=内容+属性,就都能找到了。

思考: 请解释:知道inode号的情况下,在指定分区,请解释:对⽂件进⾏增、删、查、改是在做什么?

  1. 查询操作
    • 查找文件属性
      • 首先,根据inode号在inode表中定位对应的inode。inode表通常存储在每个块组中,通过inode号可以快速计算出inode在inode表中的位置。
      • 一旦找到inode,就可以读取其中存储的文件属性,如文件类型(是普通文件、目录、符号链接等)、访问权限、文件大小、创建时间、修改时间和访问时间等信息。
    • 读取文件内容
      • inode中有一个i_block数组,它用于存储文件数据块的指针。对于小文件,文件数据可能直接通过i_block数组中的直接指针指向的数据块来读取。
      • 如果是较大的文件,可能会涉及间接指针。例如,一级间接指针指向的块中存储了其他数据块的地址,通过这些地址可以找到文件的其他数据部分。按照这种方式,根据inode中的指针信息,就可以将文件的数据块内容读取出来。
  2. 增加操作(以增加文件内容为例)
    • 分配新的数据块(如果需要)
      • 首先检查块位图,找到未使用的数据块。块位图记录了每个数据块的使用状态,通过查找其中为0的位对应的块,就可以确定空闲的数据块。
      • 然后更新块位图,将对应的位设置为1,表示该块已经被使用。
    • 更新inode指针信息
      • 如果文件原来的数据块已经存满,需要增加新的数据块来存储新增的文件内容。对于小文件,可能直接使用i_block数组中剩余的直接指针来指向新分配的数据块。
      • 对于较大的文件,可能需要更新间接指针。例如,如果一级间接指针指向的块已经存满了数据块地址,就需要分配一个新的块来存储更多的数据块地址,并更新间接指针指向这个新块。
      • 同时,更新inode中的文件大小属性,以反映文件内容的增加。
  3. 删除操作
    • 释放数据块
      • 根据inode中的i_block指针,找到文件所占用的数据块。然后将这些数据块在块位图中的对应位设置为0,表示这些块已经空闲,可以被重新分配。
    • 释放inode
      • 将inode在inode位图中的对应位设置为0,表示这个inode已经空闲。同时,可能会清除inode表中对应的inode内容,这样这个inode就可以被重新用于存储新文件的属性。
  4. 修改操作(以修改文件内容为例)
    • 小修改(文件大小不变)
      • 如果修改后的文件大小不变,只是内容改变,那么根据inode中的i_block指针找到文件的数据块,直接在这些数据块中修改文件内容即可。
    • 大修改(文件大小改变)
      • 如果修改后的文件变大,需要先按照增加文件内容的方式分配新的数据块,更新inode指针和文件大小属性,然后将新的内容写入新分配的数据块和原来的数据块中。
      • 如果修改后的文件变小,需要先释放多余的数据块(将块位图中对应的位设置为0),然后更新inode中的文件大小属性和i_block指针(如果有指针指向了释放的数据块,需要进行调整),最后修改剩余数据块中的文件内容。

🔴结论:

  • 分区之后的格式化操作,就是对分区进⾏分组,在每个分组中写⼊SB、GDT、Block Bitmap、InodeBitmap等管理信息,这些管理信息统称:⽂件系统
  • 只要知道⽂件的inode号,就能在指定分区中确定是哪⼀个分组,进⽽在哪⼀个分组确定是哪⼀个inode
  • 拿到inode⽂件属性和内容就全部都有了

下⾯,通过touch⼀个新⽂件来看看如何⼯作。

代码语言:javascript
代码运行次数:0
复制
[root@localhost linux]# touch abc
 [root@localhost linux]# ls -i abc
 263466 abc

创建⼀个新⽂件主要有以下4个操作:

  1. 存储属性 内核先找到⼀个空闲的i节点(这⾥是263466)。内核把⽂件信息记录到其中。
  2. 存储数据 该⽂件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第⼀块 数据复制到300,下⼀块复制到500,以此类推。
  3. 记录分配情况 ⽂件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。
  4. 添加⽂件名到⽬录 新的⽂件名abc。linux如何在当前的⽬录中记录这个⽂件?内核将⼊⼝(263466,abc)添加到 ⽬录⽂件。⽂件名和inode之间的对应关系将⽂件名和⽂件的内容及属性连接起来。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 📝ext2 ⽂件系统
  • 🌠 宏观认识
    • 🌉 Block Group
  • 🌠块组内部构成
    • 🌉超级块(SuperBlock)
  • 🌠GDT(GroupDescriptorTable)
    • 🌉块位图(BlockBitmap)
    • 🌉inode位图(InodeBitmap)
    • 🌉i节点表(InodeTable)
    • 🌉Data Block
    • 🌉块位图(BlockBitmap)
  • 🌠inode和datablock映射(弱化)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档