Ext2

Ext2【Ext2】EXT2第二代扩展档案系统(英语:second extended filesystem,缩写为 ext2),是LINUX核心所用的档案系统 。它开始由Rémy Card设计,用以代替ext,于1993年1月加入linux核心支持之中 。ext2 的经典实现为LINUX核心中的ext2fs档案系统驱动,最大可支持2TB的档案系统,至linux核心2.6版时,扩展到可支持32TB 。其他的实现包括GNU Hurd,Mac OS X (第3方),Darwin (第3方),BSD 。ext2为数个LINUX发行版的默认档案系统,如Debian、Red Hat Linux等 。
简介其单一档案大小与档案系统本身的容量上限与档案系统本身的簇大小有关,在一般常见的 x86 电脑系统中,簇最大为 4KB, 则单一档案大小上限为 2048GB, 而档案系统的容量上限为 16384GB 。但由于目前核心 2.4 所能使用的单一分割区最大只有 2048GB,实际上能使用的档案系统容量最多也只有 2048GB 。至于Ext3档案系统,它属于一种日誌档案系统,是对ext2系统的扩展 。它兼容ext2,并且从ext2转换成ext3并不複杂 。Ext2档案系统具有以下一般特点:1、当创建Ext2档案系统时,系统管理员可以根据预期的档案平均长度来选择最佳的块大小(从1024B——4096B) 。例如,当档案的平均长度小于几千位元组时,块的大小为1024B是最佳的,因为这会产生较少的内部碎片——也就是档案长度与存放块的磁碟分区有较少的不匹配 。另一方面,大的块对于 大于几千位元组的档案通常比较合合适,因为这样的磁碟传送较少,因而减轻了系统的开销 。2、当创建Ext2档案系统时,系统管理员可以根据在给定大小的分区上预计存放的档案数来选择给该分区分配多少个索引节点 。这可以有效地利用磁碟的空间 。3、档案系统把磁碟块分为组 。每组包含存放在相邻磁轨上的数据块和索引节点 。正是这种结构,使得可以用较少的磁碟平均寻道时间对存放在一个单独块组中的档案并行访问 。4、在磁碟数据块被实际使用之前,档案系统就把这些块预分配给普通档案 。因此当档案的大小增加时,因为物理上相邻的几个块已被保留,这就减少了档案的碎片 。5、支持快速符号连结 。如果符号连结表示一个短路径名(小于或等于60个字元),就把它存放在索引节点中而不用通过由一个数据块进行转换 。Ext2还包含了一些使它既健壮又灵活的特点:1、档案更新策略的谨慎实现将系统崩溃的影响减到最少 。我们只举一个例子来体现这个优点:例如,当给档案创建一个硬连结时,首先增加磁碟索引节点中 的硬连结计数器,然后把这个新的名字加到合适的目录中 。在这种方式下,如果在更新索引节点后而改变这个目录之前出现一个硬体故障,这样即使索引节点的计数 器产生错误,但目录是一致的 。因此,儘管删除档案时无法自动收回档案的数据块,但并不导致灾难性的后果 。如果这种处理的顺序相反(更新索引节点前改变目 录),同样的硬体故障将会导致危险的不一致,删除原始的硬连结就会从磁碟删除它的数据块,但新的目录项将指向一个不存在的索引节点 。如果那个索引节点号以 后又被另外的档案所使用,那幺向这箇旧目录的写操作将毁坏这个新的档案 。2、在启动时支持对档案系统的状态进行自动的一致性检查 。这种检查是由外部程式e2fsck完成的,这个外部程式不仅可以在系统崩溃之后被激活,也 可以在一个预定义的档案系统安装数(每次安装操作之后对计数器加1)之后被激活,或者在自从最近检查以来所花的预定义时间之后被激活 。3、支持不可变(immutable)的档案(不能修改、删除和更名)和仅追加(append-only)的档案(只能把数据追加在档案尾) 。4、既与Unix System V Release 4(SVR4)相兼容,也与新档案的用户组ID的BSD语义相兼容 。在SVR4中,新档案採用创建它的进程的用户组ID;而在BSD中,新档案继承包含它 的目录的用户组ID 。Ext2包含一个安装选项,由你指定採用哪种语义 。即使Ext2档案系统是如此成熟、稳定的程式,也还要考虑引入另外几个负面特性 。目前,一些负面特性已新的档案系统或外部补丁避免了 。另外一些还仅仅处于计画阶段,但在一些情况下,已经在Ext2的索引节点中为这些特性引入新的栏位 。最重要的一些特点如下:块片(block fragmentation)系统管理员对磁碟的访问通常选择较大的块,因为计算机应用程式常常处理大档案 。因此,在大块上存放小档案就会浪费很多磁碟空间 。这个问题可以通过把几个档案存放在同一块的不同片上来解决 。透明地处理压缩和加密档案这些新的选项(创建一个档案时必须指定)将允许用户透明地在磁碟上存放压缩和(或)加密的档案版本 。逻辑删除一个undelete选项将允许用户在必要时很容易恢复以前已删除的档案内容 。日誌日誌避免档案系统在被突然卸载(例如,作为系统崩溃的后果)时对其自动进行的耗时检查 。实际上,这些特点没有一个正式地包含在Ext2档案系统中 。有人可能说Ext2是这种成功的牺牲品;直到几年前,它仍然是大多数Linux发布公司採用的首选档案系统,每天有成千上万的用户在使用它,这些用户会对用其他档案系统来代替Ext2的任何企图产生质疑 。Ext2中缺少的最突出的功能就是日誌,日誌是高可用伺服器必需的功能 。为了平顺过渡,日誌没有引入到Ext2档案系统;但是,我们在后面 “Ext3档案系统”中会讨论,完全与Ext2兼容的一种新档案系统已经创建,这种档案系统提供了日誌 。不真正需要日誌的用户可以继续使用良好而老式的Ext2档案系统,而其他用户可能採用这种新的档案系统 。现在发行的大部分系统採用Ext3作为标準的档案系统 。Ext2档案系统格式The Second Extended File System(ext2)档案系统是Linux系统中的标準档案系统,是通过对Minix的档案系统进行扩展而得到的,其存取档案的性能极好 。在ext2档案系统中,档案由inode(包含有档案的所有信息)进行唯一标识 。一个档案可能对应多个档案名称,只有在所有档案名称都被删除后,该档案才会被删除 。此外,同一档案在磁碟中存放和被打开时所对应的inode是不同的,并由核心负责同步 。ext2档案系统採用三级间接块来存储数据块指针,并以块(block,默认为1KB)为单位分配空间 。其磁碟分配策略是儘可能将逻辑相邻的档案分配到磁碟上物理相邻的块中,并儘可能将碎片分配给儘量少的档案,以从全局上提高性能 。ext2档案系统将同一目录下的档案(包括目录)儘可能的放在同一个块组中,但目录则分布在各个块组中以实现负载均衡 。在扩展档案时,会儘量一次性扩展8个连续块给档案(以预留空间的形式实现) 。磁碟组织在ext2系统中,所有元数据结构的大小均基于“块”,而不是“扇区” 。块的大小随档案系统的大小而有所不同 。而一定数量的块又组成一个块组,每个块组的起始部分有多种多样的描述该块组各种属性的元数据结构 。ext2系统中对各个结构的定义都包含在原始码的include/linux/ext2_fs.h档案中 。1、超级块每个ext2档案系统都必须包含一个超级块,其中存储了该档案系统的大量基本信息,包括块的大小、每块组中包含的块数等 。同时,系统会对超级块进行备份,备份被存放在块组的第一个块中 。超级块的起始位置为其所在分区的第1024个位元组,占用1KB的空间,其结构如下:struct ext2_super_block {__le32 s_inodes_count; // 档案系统中inode的总数__le32 s_blocks_count; // 档案系统中块的总数__le32 s_r_blocks_count; // 保留块的总数__le32 s_free_blocks_count; // 未使用的块的总数(包括保留块)__le32 s_free_inodes_count; // 未使用的inode的总数__le32 s_first_data_block; // 块ID,在小于1KB的档案系统中为0,大于1KB的档案系统中为1__le32 s_log_block_size; // 用以计算块的大小(1024算术左移该值即为块大小)__le32 s_log_frag_size; // 用以计算段大小(为正则1024算术左移该值,否则右移)__le32 s_blocks_per_group; // 每个块组中块的总数__le32 s_frags_per_group; // 每个块组中段的总数__le32 s_inodes_per_group; // 每个块组中inode的总数__le32 s_mtime; // POSIX中定义的档案系统装载时间__le32 s_wtime; // POSIX中定义的档案系统最近被写入的时间__le16 s_mnt_count; // 最近一次完整校验后被装载的次数__le16 s_max_mnt_count; // 在进行完整校验前还能被装载的次数__le16 s_magic; // 档案系统标誌,ext2中为0xEF53__le16 s_state; // 档案系统的状态__le16 s_errors; // 档案系统发生错误时驱动程式应该执行的操作__le16 s_minor_rev_level; // 局部修订级别__le32 s_lastcheck; // POSIX中定义的档案系统最近一次检查的时间__le32 s_checkinterval; // POSIX中定义的档案系统最近检查的最大时间间隔__le32 s_creator_os; // 生成该档案系统的作业系统 __le32 s_rev_level; // 修订级别__le16 s_def_resuid; // 报留块的默认用户ID__le16 s_def_resgid; // 保留块的默认组ID// 仅用于使用动态inode大小的修订版(EXT2_DYNAMIC_REV)__le32 s_first_ino; // 标準档案的第一个可用inode的索引(非动态为11)__le16 s_inode_size; // inode结构的大小(非动态为128)__le16 s_block_group_nr; // 保存此超级块的块组号__le32 s_feature_compat; // 兼容特性掩码__le32 s_feature_incompat; // 不兼容特性掩码__le32 s_feature_ro_compat; // 唯读特性掩码__u8 s_uuid[16]; // 卷ID,应儘可能使每个档案系统的格式唯一char s_volume_name[16]; // 卷名(只能为ISO-Latin-1字元集,以’\0’结束)char s_last_mounted[64]; // 最近被安装的目录__le32 s_algorithm_usage_bitmap; // 档案系统採用的压缩算法// 仅在EXT2_COMPAT_PREALLOC标誌被设定时有效__u8 s_prealloc_blocks; // 预分配的块数__u8 s_prealloc_dir_blocks; // 给目录预分配的块数__u16 s_padding1;// 仅在EXT3_FEATURE_COMPAT_HAS_JOURNAL标誌被设定时有效,用以支持日誌__u8 s_journal_uuid[16]; // 日誌超级块的卷ID__u32 s_journal_inum; // 日誌档案的inode数目__u32 s_journal_dev; // 日誌档案的设备数__u32 s_last_orphan; // 要删除的inode列表的起始位置__u32 s_hash_seed[4]; // HTREE散列种子__u8 s_def_hash_version; // 默认使用的散列函式__u8 s_reserved_char_pad;__u16 s_reserved_word_pad;__le32 s_default_mount_opts;__le32 s_first_meta_bg; // 块组的第一个元块__u32 s_reserved[190];};2、块组描述符一个块组描述符用以描述一个块组的属性 。块组描述符组由若干块组描述符组成,描述了档案系统中所有块组的属性,存放于超级块所在块的下一个块中 。一个块组描述符的结构如下: struct ext2_group_desc{__le32 bg_block_bitmap; // 块点阵图所在的第一个块的块ID__le32 bg_inode_bitmap; // inode点阵图所在的第一个块的块ID__le32 bg_inode_table; // inode表所在的第一个块的块ID__le16 bg_free_blocks_count; // 块组中未使用的块数__le16 bg_free_inodes_count; // 块组中未使用的inode数__le16 bg_used_dirs_count; // 块组分配的目录的inode数__le16 bg_pad;__le32 bg_reserved[3];};3、块点阵图和inode点阵图块点阵图和inode点阵图的每一位分别指出块组中对应的那个块或inode是否被使用 。4、inode表inode表用于跟蹤定位每个档案,包括位置、大小等(但不包括档案名称),一个块组只有一个inode表 。一个inode的结构如下:struct ext2_inode {__le16 i_mode; // 档案格式和访问许可权__le16 i_uid; // 档案所有者ID的低16位__le32 i_size; // 档案位元组数__le32 i_atime; // 档案上次被访问的时间__le32 i_ctime; // 档案创建时间__le32 i_mtime; // 档案被修改的时间__le32 i_dtime; // 档案被删除的时间(如果存在则为0)__le16 i_gid; // 档案所有组ID的低16位__le16 i_links_count; // 此inode被连线的次数__le32 i_blocks; // 档案已使用和保留的总块数(以512B为单位)__le32 i_flags; // 此inode访问数据时ext2的实现方式union {struct {__le32 l_i_reserved1; // 保留} linux1;struct {__le32 h_i_translator; // “翻译者”标籤} hurd1;struct {__le32 m_i_reserved1; // 保留} masix1;} osd1; // 作业系统相关数据__le32 i_block[EXT2_N_BLOCKS]; // 定位存储档案的块的数组,前12个为块号,第13个为一级间接块号,第14个为二级间接块号,第15个为三级间接块号 __le32 i_generation; // 用于NFS的档案版本__le32 i_file_acl; // 包含扩展属性的块号,老版本中为0__le32 i_dir_acl; // 表示档案的“High Size”,老版本中为0__le32 i_faddr; // 档案最后一个段的地址union {struct {__u8 l_i_frag; // 段号__u8 l_i_fsize; // 段大小__u16 i_pad1;__le16 l_i_uid_high; // 档案所有者ID的高16位__le16 l_i_gid_high; // 档案所有组ID的高16位__u32 l_i_reserved2;} linux2;struct {__u8 h_i_frag; // 段号__u8 h_i_fsize; // 段大小__le16 h_i_mode_high;__le16 h_i_uid_high; // 档案所有者ID的高16位__le16 h_i_gid_high; // 档案所有组ID的高16位__le32 h_i_author;} hurd2;struct {__u8 m_i_frag; // 段号__u8 m_i_fsize; // 段大小__u16 m_pad1;__u32 m_i_reserved2[2];} masix2;} osd2; // 作业系统相关数据};5、数据块数据块中存放档案的内容,包括目录表、扩展属性、符号连结等 。目录结构在ext2档案系统中,目录是作为档案存储的 。根目录总是在inode表的第二项,而其子目录则在根目录档案的内容中定义 。目录项在include/linux/ext2_fs.h档案中定义,其结构如下:struct ext2_dir_entry_2 {__le32 inode; // 档案入口的inode号,0表示该项未使用__le16 rec_len; // 目录项长度__u8 name_len; // 档案名称包含的字元数__u8 file_type; // 档案类型char name[255]; // 档案名称};档案扩展属性档案的属性大多数是位于该档案的inode结构中的标準属性,也还包含其他一些扩展属性(于系统中所有的inode相关,通常用于增加额外的功能),在fs/ext2/xattr.h档案中定义 。inode的i_file_acl栏位中保存扩展属性的块的块号 。属性头部项位于属性块的起始位置,其后为属性入口项,而属性值能根据属性入口项找到所在位置 。1、属性头部项struct ext2_xattr_header {__le32 h_magic; // 标识码,为0xEA020000__le32 h_refcount; // 属性块被连结的数目__le32 h_blocks; // 用于扩展属性的块数__le32 h_hash; // 所有属性的哈希值__u32 h_reserved[4];};2、属性入口项struct ext2_xattr_entry {__u8 e_name_len; // 属性名长度__u8 e_name_index; // 属性名索引__le16 e_value_offs; // 属性值在值块中的偏移量__le32 e_value_block; // 保存值的块的块号__le32 e_value_size; // 属性值长度__le32 e_hash; // 属性名和值的哈希值char e_name[0]; // 属性名};