http://bbs.chinaunix.net/forum-viewthread-tid-3670672.html

EXT2文件系统
EXT2是second extended file system的简写。这个文件最早的目的是取代minix文件系统。开发于1993年。在设计之初没有提供journal的功能。
EXT2的磁盘分布
在ext2文件系统中,硬盘分区首先被划分为一个个的 block,一个 ext2 文件系统上的每个 block 都是一样大小的,但是对于不同的 ext2 文件系统,block 的大小可以有区别。典型的 block 大小是 1024 bytes 或者 4096 bytes。这个大小在创建 ext2 文件系统的时候被决定。
这些 blocks 被聚在一起分成几个大的 block group。每个 block group 中有多少个block 是固定的。
每个 block group 都相对应一个 group descriptor,这些 group descriptor 被聚在一起放在硬盘分区的开头部分,跟在 super block 的后面。在这个 descriptor 当中有几个重要的 block 指针。一个硬盘分区上的 block 计数是从 0 开始的,并且这个计数对于这个硬盘分区来说是全局性质的。
在 block group 的 group descriptor 中,其中有一个 block 指针指向这个 block group 的 block bitmap,block bitmap 中的每个 bit 表示一个 block,如果该 bit 为 0,表示该 block 中有数据,如果 bit 为 1,则表示该 block 是空闲的。
这个 block bitmap 只占用一个block。假设 block 大小为 S bytes,那么 block bitmap 当中只能记载 8*S 个 block 的情况。一个 block group 最多只能有 8*S*S bytes 这么大。
在 block group 的 group descriptor 中另有一个 block 指针指向 inode bitmap,这个 bitmap 同样也是正好有一个 block 那么大,里面的每一个 bit 相对应一个 inode。硬盘上的一个 inode 大体上相对应于文件系统上的一个文件或者目录。关于 inode,我们下面还要进一步讲到。

在 block group 的 descriptor 中另一个重要的 block 指针,是指向的 inode table。这个 inode table 就不止一个 block 那么大了。这个 inode table 就是这个 block group 中所聚集到的全部 inode 放在一起形成的。

SuperBlock
ext2 文件系统的 super block,就是硬盘分区开头(开头的第一个 byte 是 byte 0)从 byte 1024 开始往后的一部分数据。由于 block size 最小是 1024 bytes,所以 super block 可能是在 block 1 中(此时 block 的大小正好是 1024 bytes),也可能是在 block 0 中。
下面是superblock的数据结构。

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;    /* Free inodes count */
        __le32  s_first_data_block;     /* 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;     /* # Inodes per group */
        __le32  s_mtime;                /* Mount time */
        __le32  s_wtime;                /* Write time */
        __le16  s_mnt_count;            /* Mount count */
        __le16  s_max_mnt_count;        /* Maximal mount count */
        __le16  s_magic;                /* Magic signature */
        __le16  s_state;                /* File system state */
        __le16  s_errors;               /* Behaviour when detecting errors */
        __le16  s_minor_rev_level;      /* minor revision level */
        __le32  s_lastcheck;            /* time of last check */
        __le32  s_checkinterval;        /* max. time between checks */
        __le32  s_creator_os;           /* OS */
        __le32  s_rev_level;            /* Revision level */
        __le16  s_def_resuid;           /* Default uid for reserved blocks */
        __le16  s_def_resgid;           /* 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 */
};

super block 一共有 1024 bytes 那么大。在 super block 中,我们第一个要关心的字段是 magic 签名,EXT3的对应字段的值应该正好等于 0xEF53。
在 super block 中另一个重要的字段是 s_log_block_size。从这个字段,我们可以得出真正的 block 的大小。我们把真正 block 的大小记作 B,B = 1 << (s_log_block_size + 10),单位是 bytes。举例来说,如果这个字段是 0,那么 block 的大小就是 1024 bytes,这正好就是最小的 block 大小;如果这个字段是 2,那么 block 大小就是 4096 bytes。从这里我们就得到了 block 的大小这一非常重要的数据
GroupDescription
而 group descriptors 是从 super block 后面的第一个 block 开始。那么硬盘分区上一共有多少个 block group,或者说一共有多少个 group descriptors,这我们要在 super block 中找答案。super block 中的 s_blocks_count 记录了硬盘分区上的 block 的总数,而 s_blocks_per_group 记录了每个 group 中有多少个 block。
知道了硬盘分区上一共有多少个 block group,我们就可以把这么多个 group descriptors 读出来了。先来看看 group descriptor 是什么样子的。
除了superblock之外,需要介绍的是块组描述符group descriptor, 他提供了块组中的块位图 block bitmap,inode的位图和inode table的起始块等信息。

/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
        __le32  bg_block_bitmap;                /* Blocks bitmap block */
        __le32  bg_inode_bitmap;                /* Inodes bitmap block */
        __le32  bg_inode_table;         /* Inodes table block */
        __le16  bg_free_blocks_count;   /* 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];
};

inode
另一个重要的数据结构是ext2 inode, 就是所谓的ext2索引节点。这个inode和kernel中的vfs的inode是不完全一样的。Ext2 inode决定了如何把物理磁盘上的数据块组织成为文件。
前面都准备好了以后,我们现在终于可以开始读取文件了。首先要读的,当然是文件系统的根目录。注意,这里所谓的根目录,是相对于这一个文件系统或者说硬盘分区而言的,它并不一定是整个 Linux 操作系统上的根目录。这里的这个 root 目录存放在一个固定的 inode 中,这就是文件系统上的 inode 2。需要提到 inode 计数同 block 计数一样,也是全局性质的。这里需要特别注意的是,inode 计数是从 1 开始的,而前面我们提到过 block 计数是从 0 开始,这个不同在开发程序的时候要特别留心。(这一奇怪的 inode 计数方法,曾经让本文作者大伤脑筋。)
那么,我们先来看一下得到一个 inode 号数以后,怎样读取这个 inode 中的用户数据。在 super block 中有一个字段 s_inodes_per_group 记载了每个 block group 中有多少个 inode。用我们得到的 inode 号数除以 s_inodes_per_group,我们就知道了我们要的这个 inode 是在哪一个 block group 里面,这个除法的余数也告诉我们,我们要的这个 inode 是这个 block group 里面的第几个 inode;然后,我们可以先找到这个 block group 的 group descriptor,从这个 descriptor,我们找到这个 group 的 inode table,再从 inode table 找到我们要的第几个 inode,再以后,我们就可以开始读取 inode 中的用户数据了。
这个公式是这样的:block_group = (ino - 1) / s_inodes_per_group。这里 ino 就是我们的 inode 号数。而 offset = (ino - 1) % s_inodes_per_group,这个 offset 就指出了我们要的 inode 是这个 block group 里面的第几个 inode。
找到这个 inode 之后,我们来具体的看看 inode 是什么样的。

/*
* Structure of an inode on the disk
*/
struct ext2_inode {
        __le16  i_mode;         /* File mode */
        __le16  i_uid;          /* Low 16 bits of Owner Uid */
        __le32  i_size;         /* Size in bytes */
        __le32  i_atime;        /* Access time */
        __le32  i_ctime;        /* Creation time */
        __le32  i_mtime;        /* Modification time */
        __le32  i_dtime;        /* Deletion Time */
        __le16  i_gid;          /* Low 16 bits of Group Id */
        __le16  i_links_count;  /* Links count */
        __le32  i_blocks;       /* Blocks count */
        __le32  i_flags;        /* File flags */
        union {
                struct {
                        __le32  l_i_reserved1;
                } linux1;
                struct {
                        __le32  h_i_translator;
                } hurd1;
                struct {
                        __le32  m_i_reserved1;
                } masix1;
        } osd1;                         /* OS dependent 1 */
        __le32  i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
        __le32  i_generation;   /* File version (for NFS) */
        __le32  i_file_acl;     /* File ACL */
        __le32  i_dir_acl;      /* Directory ACL */
        __le32  i_faddr;        /* Fragment address */
        union {
                struct {
                        __u8    l_i_frag;       /* Fragment number */
                        __u8    l_i_fsize;      /* Fragment size */
                        __u16   i_pad1;
                        __le16  l_i_uid_high;   /* these 2 fields    */
                        __le16  l_i_gid_high;   /* were reserved2[0] */
                        __u32   l_i_reserved2;
                } linux2;
                struct {
                        __u8    h_i_frag;       /* Fragment number */
                        __u8    h_i_fsize;      /* Fragment size */
                        __le16  h_i_mode_high;
                        __le16  h_i_uid_high;
                        __le16  h_i_gid_high;
                        __le32  h_i_author;
                } hurd2;
                struct {
                        __u8    m_i_frag;       /* Fragment number */
                        __u8    m_i_fsize;      /* Fragment size */
                        __u16   m_pad1;
                        __u32   m_i_reserved2[2];
                } masix2;
        } osd2;                         /* OS dependent 2 */
};

正如前面已经提到的,inode 只在超级块中唯一编号,且每个分区只有一个超级块,这就是硬链接无法跨越多个分区的原因。
通过对以上内容的了解,可以看出,EXT2会有如下逻辑块结构。inode中有数据结构i_block[EXT2_N_BLOCKS], 其中前12个指针指到数据块,第 13 个 block,也就是所谓的 indirect block,里面存放的全部是 block 指针,这些 block 指针指向的 block 才被用来存放用户数据。第 14 个 block 是所谓的 double indirect block,里面存放的全是 block 指针,这些 block 指针指向的 block 也被全部用来存放 block 指针,而这些 block 指针指向的 block,才被用来存放用户数据。第 15 个 block 是所谓的 triple indirect block,比上面说的 double indirect block 有多了一层 block 指针。
在indirect block中,由于每个指针的长度是32bit, 即4个byte. 所以一个4096B的数据块可以包含1024个指针。

因为这个结构,可以计算出,如果文件系统的block大小为1024B, 那么最大的当个文件可以到达16GB,12*1024+(1024/4)*1024+(1024/4)*1024/4*1024+(1024/4)*1024/4*1024/4*1024=17247252480=16GB
Theoretical ext2 filesystem limits under Linux

Block size:        1 KiB        2 KiB        4 KiB        8 KiB          
max. file size:        16 GiB        256 GiB        2 TiB        64 TiB          
max. filesystem size:        2 TiB        8 TiB        16 TiB        32 TiB

由于各个架构上的限制,在i386结构上,ext3文件只能达到2TB, 而且不支持8k的页面。 由于系统调用的限制,有些应用程序不能支持大于2GB文件的读写。

linux块大小与分区大小问题相关推荐

  1. Linux下察看swap分区大小及增加分区大小

    Linux下察看swap分区大小的命令 top 或者fdisk -l 或者free -m SWAP分区一般大小为物理内存的2倍,但最大不超过2G: 增加SWAP空间的方法有两个:增加另外一个SWAP分 ...

  2. linux修改swap分区大小2GB,Linux下修改Swap分区大小

    据了解Linux下可以有两种方法创建交换空间,一种是创建交换分区,另一种是创建交换文件.本文记录的是创建交换文件的方法,因为我用的是这种方法.. 添加交换文件步骤: 1.找个地方创建一个.swap的文 ...

  3. linux mei swap,Linux | 手动扩展SWaP分区大小

    查看内存大小[root@localhost /]# grep MemTotal /proc/meminfo MemTotal:      1035292 kB 查看虚拟内存大小(交换分区) [root ...

  4. Linux调整挂载磁盘分区大小

    问题描述: Linux系统安装在一个256G固态硬盘上(/dev/sdb):根目录(/dev/sdb1,73G).home目录(/dev/sdb5,112G).swap(/dev/sdb7,45G)目 ...

  5. Linux下修改Swap分区大小

    据了解Linux下可以有两种方法创建交换空间,一种是创建交换分区,另一种是创建交换文件.本文记录的是创建交换文件的方法,因为我用的是这种方法.. 添加交换文件步骤:  1.找个地方创建一个.swap的 ...

  6. linux内核mtd分区,linux-kernel – 在运行时调整MTD分区大小

    我正在使用嵌入式设备,并希望能够通过 Linux调整其MTD分区大小而无需重新启动. 问题是我的Linux映像大小已经增加,它所在的当前MTD分区(mtd0)现在太小了.但是,它之后的分区(mtd1) ...

  7. Raspberry Pi Zero 单板配置手记(四)调整 TF 卡分区大小的不同方式

    RPi Zero 调整 TF 卡分区大小的不同方式 本文章为系列文章<Raspberry Pi Zero 单板配置手记>的第四篇,上一篇为<Raspberry Pi Zero 单板配 ...

  8. mount查看linux分区大小,Linux磁盘管理----分区格式化挂载fdisk、mkfs、mount

    1,磁盘分区命令fdisk [root@localhost ~]# fdisk -l #查看磁盘分区情况 Disk /dev/sda: 10.8 GB, 10837518250 bytes 255 h ...

  9. linux 安装分区设置分区大小

    一.Linux分区挂载点介绍 Linux分区挂载点介绍,推荐容量仅供参考不是绝对,跟各系统用途以及硬盘空间配额等因素实际调整: 分区类型 介绍 备注 /boot 启动分区 一般设置100M-200M, ...

最新文章

  1. Rocksdb 利用recycle_log_file_num 重用wal-log文件
  2. NetGear 夜鹰 RAX40V2 设备与固件分析
  3. GDOI2017 旅游记
  4. Linux服务器下PHPMailer发送邮件报错504
  5. Python学习:numpy的使用技巧和注意
  6. JavaScript入门(part6)--运算符
  7. [转]深入浅出Java设计模式之备忘录模式
  8. python中int什么意思_python中int是什么意思
  9. 空字符串(“”)和null的区别
  10. java生成类图_Java反向生成类图
  11. 绕过tp路由器管理密码_TP LINK路由器的登陆网址是什么?
  12. 小丁带你走进git的世界三-撤销修改
  13. leetcode 838.推多米诺
  14. SOLIDWORKS中钣金展开标注是英文怎么办?
  15. excel表格怎么求时间差值_excel表格,如何计算日期的天数或时间差
  16. android p2p 连接服务器上,当通过Wi-Fi P2P使用网络服务发现时无法连接到Android设备每个人都可以使用网络服务发现...
  17. 小白终是踏上了这条不归路----小文的mysql学习笔记目录
  18. Luogu P5037 抓捕
  19. 特殊监管区解决方案,高等学历继续教育及高职扩招综合管理平台服务技术功能详解
  20. JavaScript 编程规范(一)

热门文章

  1. java quickfix_QuickFix Java 讲解(一)概述、下载方法,和协议内容
  2. 安装python3出现报错信息:configure:error:cannot run C complied programs
  3. idea编译报错:Error:Kotlin: Module was compiled with an incompatible version of Kotlin.
  4. Mysql入门【Mysql基础】
  5. wpf 模拟抖音很火的罗盘时钟,附源码,下载就能跑
  6. 理光一体机扫描的时候显示服务器响应错误,理光(ricoh)2550一体机扫描文件到server 2012r2的共享文件夹传输失败。...
  7. EXT4文件系统学习(11)VFS之内存结构sb和inode
  8. ​使用ChatGPT进行文章降重​
  9. 阿里云基础产品技术月刊 2018年12月 1
  10. 忍者的时代用计算机怎么弹,火影忍者百豪纲手怎么玩 上墙 弹墙 三连摔操作方法...