linux块大小与分区大小问题
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块大小与分区大小问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年广东省安全员B证第三批(项目负
- 下一篇: android 背景磨砂效果,跨浏览器磨