天天看點

Linux 檔案系統的 Superblock, Inode, Dentry 和 File

(1)背景

   由于Linux系統是多使用者多的,是以檔案系統類型多樣化是在所難免的。從ext2開始,是将檔案屬性和檔案内容分開存儲的,分别由inode和block來負責。

(2)inode

   用于存儲檔案的各屬性,包括:

    - 所有者資訊:檔案的owner,group;

    - 權限資訊:read、write和excite;

    -時間資訊:建立或改變時間(ctime)、最後讀取時間(atime)、最後修改時間(mtime);

    - 标志資訊:一些flags;

    - 内容資訊:type,size,以及相應的block的位置資訊。

   注意:不記錄檔案名或目錄名,檔案名或目錄名記錄在檔案所在目錄對應的block裡。

(3)block

   用來存儲檔案的内容。

(4)建立目錄或檔案

   當建立一個目錄時,檔案系統會為該目錄配置設定一個inode和至少一個block。該inode記錄該目錄的屬性,并指向那塊block。該block記錄該目錄下相關聯的檔案或目錄的關聯性和名字。

   當建立一個檔案時,檔案系統會為該檔案配置設定至少一個inode和與該檔案大小相對應的數量的block。該inode記錄該檔案的屬性,并指向block。

   如果一個目錄中的檔案數太多,以至于1個block容納不下這麼多檔案時,Linux的檔案系統會為該目錄配置設定更多的block。

   (各block之間形成連結清單?)

(5)讀取目錄或檔案

   當我們告知作業系統一個檔案的路徑後,作業系統是如何找到這個檔案的呢?首先作業系統會調用檔案系統的相應接口,接下來:

   遞歸說法:當讀取一個檔案或目錄X時,提供給檔案系統的是一個路徑P。檔案系統會先讀取X所在的目錄D的inode_d(注意這裡,其實是這一操作的遞歸過程),通過inode_d獲得其對應的block_d,在block_d中通過已知的X的名稱,查詢到X的inode_x。

    疊代說法;如果讀取的是/x1/x2/x3/x4/x5這個檔案,則先讀取根目錄的inode_root,然後找到inode_root對應的block_root,在block_root中根據x1這個名字找到x1對應的inode_x1,然後找到inode_x1對應的block_x1,在block_x1中根據x2這個名字找到inode_x2,再找到block_x2,然後根據x3找到inode_x3,再block_x3,根據x4找到inode_x4,再block_x4,再根據x5找到inode_x5,再block_x5,就讀取到我們要的x5的内容了。

2、分區

(1)分區結構

    分區(partition)在被Linux的檔案系統(比如ext2)格式化的時候,會分成inode table和block table兩部分,且大小都是固定的。該分區的所有inode都在inode table裡,所有block都在block table裡。

(2)塊大小

    ext2允許的block size為1024bytes、2048bytes和4096bytes。

(3)inode大小

    ext2一般預設給inode預設的大小為128bytes。

(4)預設分區

    一個T bytes的分區,設定每個block為B bytes,每個inode為I bytes。如果假設平均每個檔案占用兩個block的話,那麼inode的數量就應該設定為T/(2B+I)個,即inode table為T*I/(2B+I) bytes,block table為T*B/(2B+I) bytes。是以一個分區的檔案系統所能容納的檔案數量,被限制于該分區的檔案系統的inode area中的inode數。

    如果一個分區大小為1GB,每個block為4KB,一個inode為128B,并假設平均每個檔案占用2個block。那麼inode的數量為1GB/(8KB+128B)=129055.5,即129055。那麼inode table的大小為129055*128B=15.75MB。是以按照這樣的規劃,如果一個1GB的磁盤,那麼格式化後,就已經有15.75MB被使用了。

   大檔案應用場景:block設定的小一些,inode設定的多一些。比如新聞討論區、BBS等。

   小檔案應用場景:block設定的大一些,inode設定的少一些。比如圖檔分享網站。

3、檢視本機的檔案系統資訊

   使用dumpe2fs指令可以檢視分區的檔案系統的相關資訊。比如我在我的一台測試機上檢視sda1,可以輸入:

dumpe2fs /dev/sda1

   會得到如下内容,一些資訊已經标注在注釋裡了。

(1)檔案系統基本資訊

#該分區的檔案系統的名稱

Filesystem volumn name: MAIN

#上次的挂載點

Last mounted on: <not available>

#檔案系統的通用唯一辨別符

Filesystem UUID: <none>

#檔案系統的

Filesystem magic number: 0xEF53

#修訂版本号

Filesystem revision #: 1 (dynamic)

Filesystem features: has_journal needs_recovery

Filesystem flags: signed_directory_hash

Default mount options: (none)

#檔案系統狀态

Filesystem state: clean

#發生錯誤後的行為

Errors behavior: Continue

#作業系統

Filesystem OS type: Linux

(2)結構資訊

#Inode總數

Inode count: 1313312

#Block總數

Block count: 1313305

#保留block數

Reserved block count: 65665

#空閑block數

Free blocks: 979164

#空閑inode數

Free inodes: 1298415  

#第一個block的編号

First block: 0

#block的大小

Block size: 4096

#fragment的大小

Fragment size: 4096

#每個group的block數是32K個

Blocks per group: 32768

#每個group的fragment數是32K個

Fragments per group: 32768

#每個group的inode數

Inodes per group: 32032

#每個group的inode blocks

Inode blocks per group: 1001

(3)通路資訊

#上次挂載時間

Last mount time: Wed Jan 25 00:32:14 2012

#上次寫時間

Last write time: Wed Jan 24 00:32:14 2012

#挂載數

Mount count: 11

#最大挂在數

Maximum mount count: 20

#上次檢查檔案系統時間

Last checked: Sat Oct 31 22:52:33 2009

#檢查檔案系統時間間隔

Check intervalle: 15552000 (6 months)

#下一次檢查檔案系統的時間

Next check after: Thu Apr 29 22:52:33 2010

#對保留塊有權限的使用者ID

Reserved blocks uid: 0 (user root)

#對保留快有權限的組ID

Reserved blocks gid: 0 (group root)

#第一個inode

First inode: 11

#每個inode大小

Inode size:128

#日志inode

Journal inode: 8

#日志大小為32M

Journal size: 32M

(4)group資訊 

Group 0: (Blocks 0-32767)

  Primary superblock at 0,Group descriptors at 1-1

  Block bitmap at 2 (+2), Inode bitmap at 3 (+3)

  Inode table at 4-1004 (+4)

  0 free blocks, 32019 free inodes, 2 directories

  Free blocks:

  Free inodes: 14-32032

Group 1: (Blocks 32768-65535)

  Backup superblock at 32768, Group descriptors at 32769-32769

  Block bitmap at 32770 (+2), Inode bitmap at 32771 (+3)

  Inode table at 32772-33772 (+4)

  3 free blocks, 32032 free inodes, 0 directories

  Free blocks: 33773-33775

  Free inodes: 32033-64064

Group 2: (Blocks 65536-98303)

  Backup superblock at 65536, Group descriptors at 65537-65537

  Block bitmap at 65538 (+2), Inode bitmap at 65539 (+3)

  Inode table at 65540-66540 (+4)

  3 free blocks, 32032 free inodes, 0 directories

  Free blocks: 66541-66543

  Free inodes: 64065-96096

Group 3: (Blocks 98304-131071)

  Backup superblock at 98304, Group descriptors at 98305-98305

  Block bitmap at 98306 (+2), Inode bitmap at 98307 (+3)

  Inode table at 98308-99308 (+4)

  3 free blocks, 32031 free inodes, 0 directories

  Free blocks: 99309-99311

  Free inodes: 96098-128128

Group 4: (Blocks 131072-163839)

  Backup superblock at 131072, Group descriptors at 131073-131073

  Block bitmap at 131074 (+2), Inode bitmap at 131075 (+3)

  Inode table at 131076-132076 (+4)

  0 free blocks, 32032 free inodes, 0 directories

  Free blocks:

  Free inodes: 128129-160160

...

Group 40: (Blocks 1310720-1313304)

  Backup superblock at 1310720, Group descriptors at 1310721-1310721

  Block bitmap at 1310722 (+2), Inode bitmap at 1310723 (+3)

  Inode table at 1310724-1311724 (+4)

  1580 free blocks, 32032 free inodes, 0 directories

  Free blocks: 1311725-1313304

  Free inodes: 1281281-1313312

    可見,各Group對應的blocks(注意每個block的大小是4096bytes)

    - Group 00:       0(0x000000) -   32767(0x007FFF):    0K =  0 * 32K

    - Group 01:   32768(0x008000) -   65535(0x00FFFF):   32K =  1 * 32K

    - Group 02:   65536(0x010000) -   98303(0x017FFF):   64K =  2 * 32K

    - Group 03:   98304(0x018000) -  131071(0x01FFFF):   96K =  3 * 32K

    - Group 04:  131072(0x020000) -  163839(0x027FFF):  128K =  4 * 32K

    …

    - Group 40: 1310720(0x140000) - 1313304(0x147FFF): 1280K = 40 * 32K

    這40個group一共的大小,是40*32K*4KB = 5GB

4、檔案系統結構

    結合上面指令的輸出結果,一個分區一般含有多個block group,比如上面看到的40個。而每個block group都有superblock、group description、block bitmap、inode bitmap、inode table、data blocks,比如上面的Backup Superblock占用1個block(4KB)、Group descriptors占用1個block(4KB)、Block bitmap占用1個block(1KB)、Inode bitmap占用1個block(1KB)、Inode table占用1001個block(512.5KB)。

    Superblock記錄整個partition的block和inode的總量,已使用和未使用的inode和block的數量,1個block和1個inode的大小,filesystem的挂載時間/最後寫入時間/最後檢查時間、标示該檔案系統是否被挂載的valid bit(0标示未挂載,1标示已挂載)。是MBR中的Superblock的backup。

    Group descriptors描述由何處開始記錄資料,是MBR中的Group descriptors的backup。

    Block bitmap記錄哪個block是空閑的。

    Inode bitmap記錄哪個inode是空閑的。

    Inode table存放inode資料。

    Data blocks存放block資料。

Linux 檔案系統的 Superblock, Inode, Dentry 和 File

通過set number:386 struct ext3_super_block {386 struct ext3_super_block {387 /*00*/  __le32  s_inodes_count;         /* Inodes count */388         __le32  s_blocks_count;         /* Blocks count */389         __le32  s_r_blocks_count;       /* Reserved blocks count */390         __le32  s_free_blocks_count;    /* Free blocks count */391 /*10*/  __le32  s_free_inodes_count;    /* Free inodes count */392         __le32  s_first_data_block;     /* First Data Block */393         __le32  s_log_block_size;       /* Block size */394         __le32  s_log_frag_size;        /* Fragment size */395 /*20*/  __le32  s_blocks_per_group;     /* # Blocks per group */396         __le32  s_frags_per_group;      /* # Fragments per group */397         __le32  s_inodes_per_group;     /* # Inodes per group */398         __le32  s_mtime;                /* Mount time */399 /*30*/  __le32  s_wtime;                /* Write time */400         __le16  s_mnt_count;            /* Mount count */401         __le16  s_max_mnt_count;        /* Maximal mount count */402         __le16  s_magic;                /* Magic signature */403         __le16  s_state;                /* File system state */404         __le16  s_errors;               /* Behaviour when detecting errors */405         __le16  s_minor_rev_level;      /* minor revision level */406 /*40*/  __le32  s_lastcheck;            /* time of last check */407         __le32  s_checkinterval;        /* max. time between checks */408         __le32  s_creator_os;           /* OS */409         __le32  s_rev_level;            /* Revision level */410 /*50*/  __le16  s_def_resuid;           /* Default uid for reserved blocks */411         __le16  s_def_resgid;           /* Default gid for reserved blocks */

  對于ext2和ext3檔案系統來說,這個字段的值應該正好等于0xEF53。如果不等的話,那麼這個硬碟分區上肯定不是一個正常的ext2或ext3檔案系統。

   從這個字段,我們可以得出真正的block的大小。我們把真正block的大小記作B,B=1 << s_log_block_size + 10),機關是bytes。舉例來說,如果這個字段是0,那麼block的大小就是 1024bytes,這正好就是最小的block大小;如果這個字段是2,那麼block大小就是4096 bytes。從這裡我們就得到了block的大小這一非常重要的資料。

  通過這兩個成員,我們可以得到硬碟分區上一共有多少個block group,或者說一共有多少個group descriptors

  s_blocks_count記錄了硬碟分區上的block的總數,而 s_blocks_per_group記錄了每個group中有多少個block。顯然,檔案系統上的block groups數量,我們把它記作G,G=(s_blocks_count-s_first_data_block- 1)/s_blocks_per_group+1。為什麼要減去s_first_data_block,因為s_blocks_count是硬碟分區上全 部的block的數量,而在s_first_data_block之前的block是不歸block group管的,是以當然要減去。最後為什麼又要加一,這是因為尾巴上可能多出來一些block,這些block我們要把它劃在一個相對較小的group 裡面。

  s_inodes_per_group記載了每個block group中有多少個inode。在從已知的inode号,讀取這個inode資料的過程中,s_inodes_per_group起到了至關重要的作用。

  用我們得到的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。

繼續閱讀