前面說過,虛擬文件系統VFS是對各種文件系統的一個抽象層,抽取其共性,以便對外提供統一管理接口,便於內核對不同種類的文件系統進行管理。那麼首先我們得看一下對於一個具體的文件系統,我們該關注重點在哪裏。
對於存儲設備(以硬盤爲例)上的數據,可分爲兩部分:點擊(此處)摺疊或打開
- [root@localhost ~]# tune2fs -l /dev/sda1
- tune2fs 1.39 (29-May-2006)
- Filesystem volume name: /boot
- Last mounted on:
- Filesystem UUID: 6ade5e49-ddab-4bf1-9a45-a0a742995775
- Filesystem magic number: 0xEF53
- Filesystem revision #: 1 (dynamic)
- Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery sparse_super
- Default mount options: user_xattr acl
- Filesystem state: clean
- Errors behavior: Continue
- Filesystem OS type: Linux
- Inode count: 38152
- Block count: 152584
- Reserved block count: 7629
- Free blocks: 130852
- Free inodes: 38111
- First block: 1
- Block size: 1024
- Fragment size: 1024
- Reserved GDT blocks: 256
- Blocks per group: 8192
- Fragments per group: 8192
- Inodes per group: 2008
- Inode blocks per group: 251
- Filesystem created: Thu Dec 13 00:42:52 2012
- Last mount time: Tue Nov 20 10:35:28 2012
- Last write time: Tue Nov 20 10:35:28 2012
- Mount count: 12
- Maximum mount count: -1
- Last checked: Thu Dec 13 00:42:52 2012
- Check interval: 0 ()
- Reserved blocks uid: 0 (user root)
- Reserved blocks gid: 0 (group root)
- First inode: 11
- Inode size: 128
- Journal inode: 8
- Default directory hash: tea
- Directory Hash Seed: 72070587-1b60-42de-bd8b-a7b7eb7cbe63
- Journal backup: inode blocks
hda: 37580963840/(1024*1024*1024)=35GB
hdb: 8589934592/(1024*1024*1024)=8GB
hdd: 8589934592/(1024*1024*1024)=8GB
如果這是三塊實際的物理硬盤的話,廠家所標稱的容量就分別是37.5GB、8.5GB和8.5GB。可能有些童鞋覺得虛擬機有點“假”,那麼我就來看看實際硬盤到底是個啥樣子。
主角1:西部數據 500G SATA接口 CentOS 5.5
實際容量:500107862016B = 465.7GB主角2:希捷 160G SCSI接口 CentOS 5.5
實際容量:160041885696B=149GB大家可以看到,VMware公司的水平還是相當不錯的,虛擬硬盤和物理硬盤“根本”看不出差別,畢竟屬於雲平臺基礎架構支撐者的風雲人物嘛。
以硬盤/dev/hdd1爲例,它是我新增的一塊新盤,格式化成ext2後,根目錄下只有一個lost+found目錄,讓我們來看一下它的佈局情況,以此來開始我們的文件系統之旅。
對於使用了ext2文件系統的分區來說,superblock的大小爲1024字節,其實ext3的superblock也是1024字節。下面的小程序可以證明這一點:
點擊(此處)摺疊或打開
- #include <stdio.h>
- #include <linux/ext2_fs.h>
- #include <linux/ext3_fs.h>
- int main(int argc,char** argv){
- printf("sizeof of ext2 superblock=%d\n",sizeof(struct ext2_super_block));
- printf("sizeof of ext3 superblock=%d\n",sizeof(struct ext3_super_block));
- return 0;
- }
硬盤的第一個字節是從0開始編號,所以第一個字節是byte0,以此類推。/dev/hdd1分區頭部的1024個字節(從byte0~byte1023)都用0填充,因爲/dev/hdd1不是主引導盤。superblock是從byte1024開始,佔1024B存儲空間。我們用dd命令把superblock的信息提取出來:
點擊(此處)摺疊或打開
- dd if=/dev/hdd1 of=./hdd1sb bs=1024 skip=1 count=1
上面的程序稍加改造,我們就可以以更直觀的方式看到superblock的輸出了:
點擊(此處)摺疊或打開
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <linux/ext2_fs.h>
- #include <linux/ext3_fs.h>
- int main(int argc,char** argv){
- printf("sizeof of ext2 superblock=%d\n",sizeof(struct ext2_super_block));
- printf("sizeof of ext3 superblock=%d\n",sizeof(struct ext3_super_block));
- char buf[1024] = {0};
- int fd = -1;
- struct ext2_super_block hdd1sb;
- memset(&hdd1sb,0,1024);
- if(-1 == (fd=open("./hdd1sb",O_RDONLY,0777))){
- printf("open file error!\n");
- return 1;
- }
- if(-1 == read(fd,buf,1024)){
- printf("read error!\n");
- close(fd);
- return 1;
- }
- memcpy((char*)&hdd1sb,buf,1024);
- printf("inode count : %ld\n",hdd1sb.s_inodes_count);
- printf("block count : %ld\n",hdd1sb.s_blocks_count);
- printf("Reserved blocks count : %ld\n",hdd1sb.s_r_blocks_count);
- printf("Free blocks count : %ld\n",hdd1sb.s_free_blocks_count);
- printf("Free inodes count : %ld\n",hdd1sb.s_free_inodes_count);
- printf("First Data Block : %ld\n",hdd1sb.s_first_data_block);
- printf("Block size : %ld\n",1<<(hdd1sb.s_log_block_size+10));
- printf("Fragment size : %ld\n",1<<(hdd1sb.s_log_frag_size+10));
- printf("Blocks per group : %ld\n",hdd1sb.s_blocks_per_group);
- printf("Fragments per group : %ld\n",hdd1sb.s_frags_per_group);
- printf("Inodes per group : %ld\n",hdd1sb.s_inodes_per_group);
- printf("Magic signature : 0x%x\n",hdd1sb.s_magic);
- printf("size of inode structure : %d\n",hdd1sb.s_inode_size);
- close(fd);
- return 0;
- }
對於ext2/ext3文件系統來說數字簽名Magic signature都是0xef53,如果不是那麼它一定不是ext2/ext3文件系統。這裏我們可以看到,我們的/dev/hdd1確實是ext2文件系統類型。hdd1中一共包含1048576個inode節點(inode編號從1開始),每個inode節點大小爲128字節,所有inode消耗的存儲空間是1048576×128=128MB;總共包含2097065個block,每個block大小爲4096字節,每32768個block組成一個group,所以一共有2097065/32768=63.99,即64個group(group編號從0開始,即Group0~Group63)。 所以整個/dev/hdd1被劃分成了64個group,詳情如下:
用命令tune2fs可以驗證我們之前的分析:
再通過命令dumpe2fs /dev/hdd1的輸出,可以得到我們關注如下部分:
接下來以Group0爲例,主superblock在Group0的block0裏,根據前面的分析,我們可以畫出主superblock在block0中的位置如下:
因爲superblock是如此之重要,一旦它出錯你的整個系統就玩兒完了,所以文件系統中會存在磁盤的多個不同位置會存在主superblock的備份副本,一旦系統出問題後還可以通過備份的superblock對文件系統進行修復。第一版ext2文件系統的實現裏,每個Group裏都存在一份superblock的副本,然而這樣做的負面效果也是相當明顯,那就是嚴重降低了磁盤的空間利用率。所以在後續ext2的實現代碼中,選擇用於備份superblock的Group組號的原則是3N、5N、7N其中N=0,1,2,3…。根據這個公式我們來計算一下/dev/hdd1中備份有supeblock的Group號:
也就是說Group1、3、5、7、9、25、27、49裏都保存有superblock的拷貝,如下:
用block號分別除以32768就得到了備份superblock的Group號,和我們在上面看到的結果一致。我們來看一下/dev/hdd1中Group和block的關係:
從上圖中我們可以清晰地看出在使用了ext2文件系統的分區上,包含有主superblock的Group、備份superblock的Group以及沒有備份superblock的Group的佈局情況。存儲了superblock的Group中有一個組描述符(Group descriptors)緊跟在superblock所在的block後面,佔一個block大小;同時還有個Reserved GDT跟在組描述符的後面。
Reserved GDT的存在主要是支持ext2文件系統的resize功能,它有自己的inode和data block,這樣一來如果文件系統動態增大,Reserved GDT就正好可以騰出一部分空間讓Group descriptor向下擴展。
未完,待續...
wjlkoorey2582013-01-10 19:02:32
wjlkoorey2582013-01-10 18:59:52
我12年寫了ext2 幾篇文章,供你參考。.....