本文原創地址:博客園駿馬金龍http://www.javashuo.com/article/p-dfmejtfg-hk.htmlhtml
將磁盤進行分區,分區是將磁盤按柱面進行物理上的劃分。劃分好分區後還要進行格式化,而後再掛載才能使用(不考慮其餘方法)。格式化分區的過程其實就是建立文件系統。node
文件系統的類型有不少種,如CentOS 5和CentOS 6上默認使用的ext2/ext3/ext4,CentOS 7上默認使用的xfs,windows上的NTFS,光盤類的文件系統ISO9660,MAC上的混合文件系統HFS,網絡文件系統NFS,Oracle研發的btrfs,還有老式的FAT/FAT32等。linux
本文將很是全面且詳細地介紹ext家族的文件系統,中間還很是詳細地介紹了inode、軟連接、硬連接、數據存儲方式以及操做文件的理論,基本上看完本文,對文件系統的宏觀理解將再無疑惑。ext家族的文件系統有ext2/ext3/ext4,ext3是有日誌的ext2改進版,ext4對相比ext3作了很是多的改進。雖然xfs/btrfs等文件系統有所不一樣,但它們只是在實現方式上不太同,再加上屬於本身的特性而已。windows
硬盤的讀寫IO一次是一個扇區512字節,若是要讀寫大量文件,以扇區爲單位確定很慢很消耗性能,因此Linux中經過文件系統控制使用"塊"爲讀寫單元。如今的文件系統上,塊的大小通常爲1024bytes(1K)或2048bytes(2K)或4096bytes(4K)。好比須要讀一個或多個塊時,文件系統的IO管理器通知磁盤控制器要讀取哪些塊的數據,硬盤控制器將這些塊按扇區讀取出來,再經過硬盤控制器將這些扇區數據重組返回給計算機。centos
block的出現使得在文件系統層面上讀寫性能大大提升,也大量減小了碎片。可是它的反作用是可能形成空間浪費。因爲文件系統以block爲讀寫單元,即便存儲的文件只有1K大小也將佔用一個block,剩餘的空間徹底是浪費的。在某些業務需求下可能大量存儲小文件,這會浪費大量的空間。緩存
儘管有缺點,可是其優勢足夠明顯,在當下硬盤容量廉價且追求性能的時代,使用block是必定的。網絡
若是存儲的1個文件佔用了大量的block讀取時會如何?假如block大小爲1KB,僅僅存儲一個10M的文件就須要10240個block,並且這些blocks極可能在位置上是不連續在一塊兒的(不相鄰),讀取該文件時難道要從前向後掃描整個文件系統的塊,而後找出屬於該文件的塊嗎?顯然是不該該這麼作的,由於太慢太傻瓜式了。再考慮一下,讀取一個只佔用1個block的文件,難道只讀取一個block就結束了嗎?並非,仍然是掃描整個文件系統的全部block,由於它不知道何時掃描到,掃描到了它也不知道這個文件是否是已經完整而不須要再掃描其餘的block。app
另外,每一個文件都有屬性(如權限、大小、時間戳等),這些屬性類的元數據存儲在哪裏呢?難道也和文件的數據部分存儲在塊中嗎?若是一個文件佔用多個block那是否是每一個屬於該文件的block都要存儲一份文件元數據?可是若是不在每一個block中存儲元數據文件系統又怎麼知道某一個block是否是屬於該文件呢?可是顯然,每一個數據block中都存儲一份元數據太浪費空間。socket
文件系統設計者固然知道這樣的存儲方式很不理想,因此須要優化存儲方式。如何優化?對於這種相似的問題的解決方法是使用索引,經過掃描索引找到對應的數據,並且索引能夠存儲部分數據。函數
在文件系統上索引技術具體化爲索引節點(index node),在索引節點上存儲的部分數據即爲文件的屬性元數據及其餘少許信息。通常來講索引佔用的空間相比其索引的文件數據而言佔用的空間就小得多,掃描它比掃描整個數據要快得多,不然索引就沒有存在的意義。這樣一來就解決了前面全部的問題。
在文件系統上的術語中,索引節點稱爲inode。在inode中存儲了inode號、文件類型、權限、文件全部者、大小、時間戳等元數據信息,最重要的是還存儲了指向屬於該文件block的指針,這樣讀取inode就能夠找到屬於該文件的block,進而讀取這些block並得到該文件的數據。因爲後面還會介紹一種指針,爲了方便稱呼和區分,暫且將這個inode記錄中指向文件data block的指針稱之爲block指針。如下是ext2文件系統中inode包含的信息示例:
Inode: 12 Type: regular Mode: 0644 Flags: 0x0 Generation: 1454951771 Version: 0x00000000:00000001 User: 0 Group: 0 Size: 5 File ACL: 0 Directory ACL: 0 Links: 1 Blockcount: 8 Fragment: Address: 0 Number: 0 Size: 0 ctime: 0x5b628db2:15e0aff4 -- Thu Aug 2 12:50:58 2018 atime: 0x5b628db2:15e0aff4 -- Thu Aug 2 12:50:58 2018 mtime: 0x5b628db2:15e0aff4 -- Thu Aug 2 12:50:58 2018 crtime: 0x5b628db2:15e0aff4 -- Thu Aug 2 12:50:58 2018 Size of extra inode fields: 28 BLOCKS: (0):1024 TOTAL: 1
通常inode大小爲128字節或256字節,相比那些MB或GB計算的文件數據而言小得多的多,但也要知道可能一個文件大小小於inode大小,例如只佔用1個字節的文件。
在向硬盤存儲數據時,文件系統須要知道哪些塊是空閒的,哪些塊是已經佔用了的。最笨的方法固然是從前向後掃描,遇到空閒塊就存儲一部分,繼續掃描直到存儲完全部數據。
優化的方法固然也能夠考慮使用索引,可是僅僅1G的文件系統就有1KB的block共1024*1024=1048576個,這僅僅只是1G,若是是100G、500G甚至更大呢,僅僅使用索引索引的數量和空間佔用也將極大,這時就出現更高一級的優化方法:使用塊位圖(bitmap簡稱bmap)。
位圖只使用0和1標識對應block是空閒仍是被佔用,0和1在位圖中的位置和block的位置一一對應,第一位標識第一個塊,第二個位標識第二個塊,依次下去直到標記完全部的block。
考慮下爲何塊位圖更優化。在位圖中1個字節8個位,能夠標識8個block。對於一個block大小爲1KB、容量爲1G的文件系統而言,block數量有1024*1024個,因此在位圖中使用1024*1024個位共1024*1024/8=131072字節=128K,即1G的文件只須要128個block作位圖就能完成一一對應。經過掃描這100多個block就能知道哪些block是空閒的,速度提升了很是多。
可是要注意,bmap的優化針對的是寫優化,由於只有寫才須要找到空閒block並分配空閒block。對於讀而言,只要經過inode找到了block的位置,cpu就能迅速計算出block在物理磁盤上的地址,cpu的計算速度是極快的,計算block地址的時間幾乎能夠忽略,那麼讀速度基本認爲是受硬盤自己性能的影響而與文件系統無關。大多數稍大一點的文件可能都會存儲在不連續的block上,並且使用了一段時間的文件系統可能會有很多碎片,這時硬盤的隨機讀取性能直接決定讀數據的速度,這也是機械硬盤速度相比固態硬盤慢的多的多的緣由之一,並且固態硬盤的隨機讀和連續讀取速度幾乎是一致的,對它來講,文件系統碎片的多少並不會影響讀取速度。
雖然bmap已經極大的優化了掃描,可是仍有其瓶頸:若是文件系統是100G呢?100G的文件系統要使用128*100=12800個1KB大小的block,這就佔用了12.5M的空間了。試想徹底掃描12800個極可能不連續的block這也是須要佔用一些時間的,雖然快可是扛不住每次存儲文件都要掃描帶來的巨大開銷。
因此須要再次優化,如何優化?簡而言之就是將文件系統劃分開造成塊組,至於塊組的介紹放在後文。
回顧下inode相關信息:inode存儲了inode號、文件屬性元數據、指向文件佔用的block的指針;每個inode佔用128字節或256字節。
如今又出現問題了,一個文件系統中能夠說有無數多個文件,每個文件都對應一個inode,難道每個僅128字節的inode都要單獨佔用一個block進行存儲嗎?這太浪費空間了。
因此更優的方法是將多個inode合併存儲在block中,對於128字節的inode,一個block存儲8個inode,對於256字節的inode,一個block存儲4個inode。這就使得每一個存儲inode的塊都不浪費。
在ext文件系統上,將這些物理上存儲inode的block組合起來,在邏輯上造成一張inode表(inode table)來記錄全部的inode。
舉個例子,每個家庭都要向派出所登記戶口信息,經過戶口本能夠知道家庭住址,而每一個鎮或街道的派出所將本鎮或本街道的全部戶口整合在一塊兒,要查找某一戶地址時,在派出所就能快速查找到。inode table就是這裏的派出所。它的內容以下圖所示。
實際上,在文件系統建立完成後全部的inode號都已經分配好並記錄到inode table中了,只不過被使用的inode號所在的行還有文件屬性的元數據信息和block位置信息,而未被使用的inode號只有一個inode號而已而沒有其餘信息而已。
再細細一思考,就能發現一個大的文件系統仍將佔用大量的塊來存儲inode,想要找到其中的一個inode記錄也須要不小的開銷,儘管它們已經造成了一張邏輯上的表,但扛不住表太大記錄太多。那麼如何快速找到inode,這一樣是須要優化的,優化的方法是將文件系統的block進行分組劃分,每一個組中都存有本組inode table範圍、bmap等。
前面說bmap是塊位圖,用於標識文件系統中哪些block是空閒哪些block是佔用的。
對於inode也同樣,在存儲文件(Linux中一切皆文件)時須要爲其分配一個inode號。可是在格式化建立文件系統後全部的inode號都是被事先設定好存放在inode table中的,所以產生了問題:要爲文件分配哪個inode號呢?又如何知道某一個inode號是否已經被分配了呢?
既然是"是否被佔用"的問題,使用位圖是最佳方案,像bmap記錄block的佔用狀況同樣。標識inode號是否被分配的位圖稱爲inodemap簡稱爲imap。這時要爲一個文件分配inode號只需掃描imap便可知道哪個inode號是空閒的。
imap存在着和bmap和inode table同樣須要解決的問題:若是文件系統比較大,imap自己就會很大,每次存儲文件都要進行掃描,會致使效率不夠高。一樣,優化的方式是將文件系統佔用的block劃分紅塊組,每一個塊組有本身的imap範圍。
前面一直提到的優化方法是將文件系統佔用的block劃分紅塊組(block group),解決bmap、inode table和imap太大的問題。
在物理層面上的劃分是將磁盤按柱面劃分爲多個分區,即多個文件系統;在邏輯層面上的劃分是將文件系統劃分紅塊組。每一個文件系統包含多個塊組,每一個塊組包含多個元數據區和數據區:元數據區就是存儲bmap、inode table、imap等的數據;數據區就是存儲文件數據的區域。注意塊組是邏輯層面的概念,因此並不會真的在磁盤上按柱面、按扇區、按磁道等概念進行劃分。
塊組在文件系統建立完成後就已經劃分完成了,也就是說元數據區bmap、inode table和imap等信息佔用的block以及數據區佔用的block都已經劃分好了。那麼文件系統如何知道一個塊組元數據區包含多少個block,數據區又包含多少block呢?
它只需肯定一個數據——每一個block的大小,再根據bmap至多隻能佔用一個完整的block的標準就能計算出塊組如何劃分。若是文件系統很是小,全部的bmap總共都不能佔用完一個block,那麼也只能空閒bmap的block了。
每一個block的大小在建立文件系統時能夠人爲指定,不指定也有默認值。
假如如今block的大小是1KB,一個bmap完整佔用一個block能標識1024*8= 8192個block(固然這8192個block是數據區和元數據區共8192個,由於元數據區分配的block也須要經過bmap來標識)。每一個block是1K,每一個塊組是8192K即8M,建立1G的文件系統須要劃分1024/8=128個塊組,若是是1.1G的文件系統呢?128+12.8=128+13=141個塊組。
每一個組的block數目是劃分好了,可是每一個組設定多少個inode號呢?inode table佔用多少block呢?這須要由系統決定了,由於描述"每多少個數據區的block就爲其分配一個inode號"的指標默認是咱們不知道的,固然建立文件系統時也能夠人爲指定這個指標或者百分比例。見後文"inode深刻"。
使用dumpe2fs能夠將ext類的文件系統信息所有顯示出來,固然bmap是每一個塊組固定一個block的不用顯示,imap比bmap更小因此也只佔用1個block不用顯示。
下圖是一個文件系統的部分信息,在這些信息的後面還有每一個塊組的信息,其實這裏面的不少信息均可以經過幾個比較基本的元數據推導出來。
從這張表中能計算出文件系統的大小,該文件系統共4667136個blocks,每一個block大小爲4K,因此文件系統大小爲4667136*4/1024/1024=17.8GB。
也能計算出分了多少個塊組,由於每個塊組的block數量爲32768,因此塊組的數量爲4667136/32768=142.4即143個塊組。因爲塊組從0開始編號,因此最後一個塊組編號爲Group 142。以下圖所示是最後一個塊組的信息。
將上文描述的bmap、inode table、imap、數據區的blocks和塊組的概念組合起來就造成了一個文件系統,固然這還不是完整的文件系統。完整的文件系統以下圖
首先,該圖中多了Boot Block、Super Block、GDT、Reserver GDT這幾個概念。下面會分別介紹它們。
而後,圖中指明瞭塊組中每一個部分佔用的block數量,除了superblock、bmap、imap能肯定佔用1個block,其餘的部分都不能肯定佔用幾個block。
最後,圖中指明瞭Superblock、GDT和Reserved GDT是同時出現且不必定存在於每個塊組中的,也指明瞭bmap、imap、inode table和data blocks是每一個塊組都有的。
即上圖中的Boot Block部分,也稱爲boot sector。它位於分區上的第一個塊,佔用1024字節,並不是全部分區都有這個boot sector,只有裝了操做系統的主分區和裝了操做系統的邏輯分區纔有。裏面存放的也是boot loader,這段boot loader稱爲VBR(主分區裝操做系統時)或EBR(擴展分區裝操做系統時),這裏的Boot loader和mbr上的boot loader是存在交錯關係的。開機啓動的時候,首先加載mbr中的bootloader,而後定位到操做系統所在分區的boot serctor上加載此處的boot loader。若是是多系統,加載mbr中的bootloader後會列出操做系統菜單,菜單上的各操做系統指向它們所在分區的boot sector上。它們之間的關係以下圖所示。
可是,這種方式的操做系統菜單早已經棄之不用了,而是使用grub來管理啓動菜單。儘管如此,在安裝操做系統時,仍然有一步是選擇boot loader安裝位置的步驟。
既然一個文件系統會分多個塊組,那麼文件系統怎麼知道分了多少個塊組呢?每一個塊組又有多少block多少inode號等等信息呢?還有,文件系統自己的屬性信息如各類時間戳、block總數量和空閒數量、inode總數量和空閒數量、當前文件系統是否正常、何時須要自檢等等,它們又存儲在哪裏呢?
毫無疑問,這些信息必需要存儲在block中。存儲這些信息佔用1024字節,因此也要一個block,這個block稱爲超級塊(superblock),它的block號可能爲0也可能爲1。若是block大小爲1K,則引導塊正好佔用一個block,這個block號爲0,因此superblock的號爲1;若是block大小大於1K,則引導塊和超級塊同置在一個block中,這個block號爲0。總之superblock的起止位置是第二個1024(1024-2047)字節。
使用df命令讀取的就是每一個文件系統的superblock,因此它的統計速度很是快。相反,用du命令查看一個較大目錄的已用空間就很是慢,由於不可避免地要遍歷整個目錄的全部文件。
[root@xuexi ~]# df -hT Filesystem Type Size Used Avail Use% Mounted on /dev/sda3 ext4 18G 1.7G 15G 11% / tmpfs tmpfs 491M 0 491M 0% /dev/shm /dev/sda1 ext4 190M 32M 149M 18% /boot
superblock對於文件系統而言是相當重要的,超級塊丟失或損壞必將致使文件系統的損壞。因此舊式的文件系統將超級塊備份到每個塊組中,可是這又有所空間浪費,因此ext2文件系統只在塊組0、1和三、五、7冪次方的塊組中保存超級塊的信息,如Group九、Group25等。儘管保存了這麼多的superblock,可是文件系統只使用第一個塊組即Group0中超級塊信息來獲取文件系統屬性,只有當Group0上的superblock損壞或丟失纔會找下一個備份超級塊複製到Group0中來恢復文件系統。
下圖是一個ext4文件系統的superblock的信息,ext家族的文件系統都能使用dumpe2fs -h獲取。
既然文件系統劃分了塊組,那麼每一個塊組的信息和屬性元數據又保存在哪裏呢?
ext文件系統每個塊組信息使用32字節描述,這32個字節稱爲塊組描述符,全部塊組的塊組描述符組成塊組描述符表GDT(group descriptor table)。
雖然每一個塊組都須要塊組描述符來記錄塊組的信息和屬性元數據,可是不是每一個塊組中都存放了塊組描述符。ext文件系統的存儲方式是:將它們組成一個GDT,並將該GDT存放於某些塊組中,存放GDT的塊組和存放superblock和備份superblock的塊相同,也就是說它們是同時出如今某一個塊組中的。讀取時也老是讀取Group0中的塊組描述符表信息。
假如block大小爲4KB的文件系統劃分了143個塊組,每一個塊組描述符32字節,那麼GDT就須要143*32=4576字節即兩個block來存放。這兩個GDT block中記錄了全部塊組的塊組信息,且存放GDT的塊組中的GDT都是徹底相同的。
下圖是一個塊組描述符的信息(經過dumpe2fs獲取)。
保留GDT用於之後擴容文件系統使用,防止擴容後塊組太多,使得塊組描述符超出當前存儲GDT的blocks。保留GDT和GDT老是同時出現,固然也就和superblock同時出現了。
例如前面143個塊組使用了2個block來存放GDT,可是此時第二個block還空餘不少空間,當擴容到必定程度時2個block已經沒法再記錄塊組描述符了,這時就須要分配一個或多個Reserved GDT的block來存放超出的塊組描述符。
因爲新增長了GDT block,因此應該讓每個保存GDT的塊組都同時增長這一個GDT block,因此將保留GDT和GDT存放在同一個塊組中能夠直接將保留GDT變換爲GDT而無需使用低效的複製手段備份到每一個存放GDT的塊組。
同理,新增長了GDT須要修改每一個塊組中superblock中的文件系統屬性,因此將superblock和Reserved GDT/GDT放在一塊兒又能提高效率。
如上圖,除了Data Blocks其餘的部分都解釋過了。data block是直接存儲數據的block,但事實上並不是如此簡單。
數據所佔用的block由文件對應inode記錄中的block指針找到,不一樣的文件類型,數據block中存儲的內容是不同的。如下是Linux中不一樣類型文件的存儲方式。
常規文件的存儲就不解釋了,下面分別解釋特殊文件的存儲方式。
對於目錄文件,其inode記錄中存儲的是目錄的inode號、目錄的屬性元數據和目錄文件的block指針,這裏面沒有存儲目錄自身文件名的信息。
而其data block的存儲方式則以下圖所示。
由圖可知,在目錄文件的數據塊中存儲了其下的文件名、目錄名、目錄自己的相對名稱"."和上級目錄的相對名稱"..",還存儲了指向inode table中這些文件名對應的inode號的指針(並不是直接存儲inode號碼)、目錄項長度rec_len、文件名長度name_len和文件類型file_type。注意到除了文件自己的inode記錄了文件類型,其所在的目錄的數據塊也記錄了文件類型。因爲rec_len只能是4的倍數,因此須要使用"\0"來填充name_len不夠湊滿4倍數的部分。至於rec_len具體是什麼,只需知道它是一種偏移便可。
目錄的data block中並無直接存儲目錄中文件的inode號,它存儲的是指向inode table中對應文件inode號的指針,暫且稱之爲inode指針(至此,已經知道了兩種指針:一種是inode table中每一個inode記錄指向其對應data block的block指針,一個此處的inode指針。題外話:實際上inode指針應該稱之爲存儲在目錄data blcok中的連接link,這個link和inode num一一映射,因此刪除文件的函數稱爲unlink(),表示在目錄的data block中刪除這個連接)。一個頗有說服力的例子,在目錄只有讀而沒有執行權限的時候,使用"ls -l"是沒法獲取到其內文件inode號的,這就代表沒有直接存儲inode號。實際上,由於在建立文件系統的時候,inode號就已經所有劃分好並在每一個塊組的inode table中存放好,inode table在塊組中是有具體位置的,若是使用dumpe2fs查看文件系統,會發現每一個塊組的inode table佔用的block數量是徹底相同的,以下圖是某分區上其中兩個塊組的信息,它們都佔用249個block。
除了inode指針,目錄的data block中還使用數字格式記錄了文件類型,數字格式和文件類型的對應關係以下圖。
注意到目錄的data block中前兩行存儲的是目錄自己的相對名稱"."和上級目錄的相對名稱"..",它們其實是目錄自己的硬連接和上級目錄的硬連接。硬連接的本質後面說明。
由此也就容易理解目錄權限的特殊之處了。目錄文件的讀權限(r)和寫權限(w),都是針對目錄文件的數據塊自己。因爲目錄文件內只有文件名、文件類型和inode指針,因此若是隻有讀權限,只能獲取文件名和文件類型信息,沒法獲取其餘信息,儘管目錄的data block中也記錄着文件的inode指針,但定位指針是須要x權限的,由於其它信息都儲存在文件自身對應的inode中,而要讀取文件inode信息須要有目錄文件的執行權限經過inode指針定位到文件對應的inode記錄上。如下是沒有目錄x權限時的查詢狀態,能夠看到除了文件名和文件類型,其他的全是"?"。
[lisi4@xuexi tmp]$ ll -i d ls: cannot access d/hehe: Permission denied ls: cannot access d/haha: Permission denied total 0 ? d????????? ? ? ? ? ? haha ? -????????? ? ? ? ? ? hehe
注意,xfs文件系統和ext文件系統不同,它連文件類型都沒法獲取。
符號連接即爲軟連接,相似於Windows操做系統中的快捷方式,它的做用是指向原文件或目錄。
軟連接之因此也被稱爲特殊文件的緣由是:它通常狀況下不佔用data block,僅僅經過它對應的inode記錄就能將其信息描述完成;符號連接的大小是其指向目標路徑佔用的字符個數,例如某個符號連接的指向方式爲"rmt --> ../sbin/rmt",則其文件大小爲11字節;只有當符號連接指向的目標的路徑名較長(60個字節)時文件系統纔會劃分一個data block給它;它的權限如何也不重要,因它只是一個指向原文件的"工具",最終決定是否能讀寫執行的權限由原文件決定,因此極可能ls -l查看到的符號連接權限爲777。
注意,軟連接的block指針存儲的是目標文件名。也就是說,連接文件的一切都依賴於其目標文件名。這就解釋了爲何/mnt的軟連接/tmp/mnt在/mnt掛載文件系統後,經過軟連接就能進入/mnt所掛載的文件系統。究其緣由,仍是由於其目標文件名"/mnt"並無改變。
例如如下篩選出了/etc/下的符號連接,注意觀察它們的權限和它們佔用的空間大小。
[root@xuexi ~]# ll /etc/ | grep '^l' lrwxrwxrwx. 1 root root 56 Feb 18 2016 favicon.png -> /usr/share/icons/hicolor/16x16/apps/system-logo-icon.png lrwxrwxrwx. 1 root root 22 Feb 18 2016 grub.conf -> ../boot/grub/grub.conf lrwxrwxrwx. 1 root root 11 Feb 18 2016 init.d -> rc.d/init.d lrwxrwxrwx. 1 root root 7 Feb 18 2016 rc -> rc.d/rc lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc0.d -> rc.d/rc0.d lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc1.d -> rc.d/rc1.d lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc2.d -> rc.d/rc2.d lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc3.d -> rc.d/rc3.d lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc4.d -> rc.d/rc4.d lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc5.d -> rc.d/rc5.d lrwxrwxrwx. 1 root root 10 Feb 18 2016 rc6.d -> rc.d/rc6.d lrwxrwxrwx. 1 root root 13 Feb 18 2016 rc.local -> rc.d/rc.local lrwxrwxrwx. 1 root root 15 Feb 18 2016 rc.sysinit -> rc.d/rc.sysinit lrwxrwxrwx. 1 root root 14 Feb 18 2016 redhat-release -> centos-release lrwxrwxrwx. 1 root root 11 Apr 10 2016 rmt -> ../sbin/rmt lrwxrwxrwx. 1 root root 14 Feb 18 2016 system-release -> centos-release
關於這3種文件類型的文件只須要經過inode就能徹底保存它們的信息,它們不佔用任何數據塊,因此它們是特殊文件。
設備文件的主設備號和次設備號也保存在inode中。如下是/dev/下的部分設備信息。注意到它們的第5列和第6列信息,它們分別是主設備號和次設備號,主設備號標識每一種設備的類型,次設備號標識同種設備類型的不一樣編號;也注意到這些信息中沒有大小的信息,由於設備文件不佔用數據塊因此沒有大小的概念。
[root@xuexi ~]# ll /dev | tail crw-rw---- 1 vcsa tty 7, 129 Oct 7 21:26 vcsa1 crw-rw---- 1 vcsa tty 7, 130 Oct 7 21:27 vcsa2 crw-rw---- 1 vcsa tty 7, 131 Oct 7 21:27 vcsa3 crw-rw---- 1 vcsa tty 7, 132 Oct 7 21:27 vcsa4 crw-rw---- 1 vcsa tty 7, 133 Oct 7 21:27 vcsa5 crw-rw---- 1 vcsa tty 7, 134 Oct 7 21:27 vcsa6 crw-rw---- 1 root root 10, 63 Oct 7 21:26 vga_arbiter crw------- 1 root root 10, 57 Oct 7 21:26 vmci crw-rw-rw- 1 root root 10, 56 Oct 7 21:27 vsock crw-rw-rw- 1 root root 1, 5 Oct 7 21:26 zero
每一個文件都有一個inode,在將inode關聯到文件後系統將經過inode號來識別文件,而不是文件名。而且訪問文件時將先找到inode,經過inode中記錄的block位置找到該文件。
雖然每一個文件都有一個inode,可是存在一種可能:多個文件的inode相同,也就即inode號、元數據、block位置都相同,這是一種什麼樣的狀況呢?可以想象這些inode相同的文件使用的都是同一條inode記錄,因此表明的都是同一個文件,這些文件所在目錄的data block中的inode指針目的地都是同樣的,只不過各指針對應的文件名互不相同而已。這種inode相同的文件在Linux中被稱爲"硬連接"。
硬連接文件的inode都相同,每一個文件都有一個"硬連接數"的屬性,使用ls -l的第二列就是被硬連接數,它表示的就是該文件有幾個硬連接。
[root@xuexi ~]# ls -l total 48 drwxr-xr-x 5 root root 4096 Oct 15 18:07 700 -rw-------. 1 root root 1082 Feb 18 2016 anaconda-ks.cfg -rw-r--r-- 1 root root 399 Apr 29 2016 Identity.pub -rw-r--r--. 1 root root 21783 Feb 18 2016 install.log -rw-r--r--. 1 root root 6240 Feb 18 2016 install.log.syslog
例以下圖描述的是dir1目錄中的文件name1及其硬連接dir2/name2,右邊分別是它們的inode和datablock。這裏也看出了硬連接文件之間惟一不一樣的就是其所在目錄中的記錄不一樣。注意下圖中有一列Link Count就是標記硬連接數的屬性。
每建立一個文件的硬連接,實質上是多一個指向該inode記錄的inode指針,而且硬連接數加1。
刪除文件的實質是刪除該文件所在目錄data block中的對應的inode指針,因此也是減小硬連接次數,因爲block指針是存儲在inode中的,因此不是真的刪除數據,若是仍有其餘指針指向該inode,那麼該文件的block指針仍然是可用的。當硬連接次數爲1時再刪除文件就是真的刪除文件了,此時inode記錄中block指針也將被刪除。
不能跨分區建立硬連接,由於不一樣文件系統的inode號可能會相同,若是容許建立硬連接,複製到另外一個分區時inode可能會和此分區已使用的inode號衝突。
硬連接只能對文件建立,沒法對目錄建立硬連接。之因此沒法對目錄建立硬連接,是由於文件系統已經把每一個目錄的硬連接建立好了,它們就是相對路徑中的"."和"..",分別標識當前目錄的硬連接和上級目錄的硬連接。每個目錄中都會包含這兩個硬連接,它包含了兩個信息:(1)一個沒有子目錄的目錄文件的硬連接數是2,其一是目錄自己,即該目錄datablock中的".",其二是其父目錄datablock中該目錄的記錄,這二者都指向同一個inode號;(2)一個包含子目錄的目錄文件,其硬連接數是2+子目錄數,由於每一個子目錄都關聯一個父目錄的硬連接".."。不少人在計算目錄的硬連接數時認爲因爲包含了"."和"..",因此空目錄的硬連接數是2,這是錯誤的,由於".."不是本目錄的硬連接。另外,還有一個特殊的目錄應該歸入考慮,即"/"目錄,它自身是一個文件系統的入口,是自引用(下文中會解釋自引用)的,因此"/"目錄下的"."和".."的inode號相同,它自身不佔用硬連接,由於其datablock中只記錄inode號相同的"."和"..",再也不像其餘目錄同樣還記錄一個名爲"/"的目錄,因此"/"的硬連接數也是2+子目錄數,但這個2是"."和".."的結果。
[root@xuexi ~]# ln /tmp /mydata ln: `/tmp': hard link not allowed for directory
爲何文件系統本身建立好了目錄的硬連接就不容許人爲建立呢?從"."和".."的用法上考慮,若是當前目錄爲/usr,咱們可使用"./local"來表示/usr/local,可是若是咱們人爲建立了/usr目錄的硬連接/tmp/husr,難道咱們也要使用"/tmp/husr/local"來表示/usr/local嗎?這其實已是軟連接的做用了。若要將其認爲是硬連接的功能,這必將致使硬連接維護的混亂。
不過,經過mount工具的"--bind"選項,能夠將一個目錄掛載到另外一個目錄下,實現僞"硬連接",它們的內容和inode號是徹底相同的。
硬連接的建立方法: ln file_target link_name 。
軟連接就是字符連接,連接文件默認指的就是字符連接文件(注意不是字符設備),使用"l"表示其類型。
硬連接不能跨文件系統建立,不然inode號可能會衝突。因而實現了軟連接以便跨文件系統創建連接。既然是跨文件系統,那麼軟連接必須得有本身的inode號。
軟連接在功能上等價與Windows系統中的快捷方式,它指向原文件,原文件損壞或消失,軟連接文件就損壞。能夠認爲軟連接inode記錄中的指針內容是目標路徑的字符串。
建立方式: ln –s source_file softlink_name ,記住是source_file<--link_name的指向關係(反箭頭),之前我老搞錯位置。
查看軟連接的值: readlink softlink_name
在設置軟連接的時候,source_file雖然不要求是絕對路徑,但建議給絕對路徑。是否還記得軟連接文件的大小?它是根據軟連接所指向路徑的字符數計算的,例如某個符號連接的指向方式爲"rmt --> ../sbin/rmt",它的文件大小爲11字節,也就是說只要創建了軟連接後,軟連接的指向路徑是不會改變的,仍然是"../sbin/rmt"。若是此時移動軟連接文件自己,它的指向是不會改變的,仍然是11個字符的"../sbin/rmt",但此時該軟連接父目錄下可能根本就不存在/sbin/rmt,也就是說此時該軟連接是一個被破壞的軟連接。
inode大小爲128字節的倍數,最小爲128字節。它有默認值大小,它的默認值由/etc/mke2fs.conf文件中指定。不一樣的文件系統默認值可能不一樣。
[root@xuexi ~]# cat /etc/mke2fs.conf [defaults] base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr enable_periodic_fsck = 1 blocksize = 4096 inode_size = 256 inode_ratio = 16384 [fs_types] ext3 = { features = has_journal } ext4 = { features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize inode_size = 256 }
一樣觀察到這個文件中還記錄了blocksize的默認值和inode分配比率inode_ratio。inode_ratio=16384表示每16384個字節即16KB就分配一個inode號,因爲默認blocksize=4KB,因此每4個block就分配一個inode號。固然分配的這些inode號只是預分配,並不真的表明會所有使用,畢竟每一個文件纔會分配一個inode號。可是分配的inode自身會佔用block,並且其自身大小256字節還不算小,因此inode號的浪費表明着空間的浪費。
既然知道了inode分配比率,就能計算出每一個塊組分配多少個inode號,也就能計算出inode table佔用多少個block。
若是文件系統中大量存儲電影等大文件,inode號就浪費不少,inode佔用的空間也浪費不少。可是沒辦法,文件系統又不知道你這個文件系統是用來存什麼樣的數據,多大的數據,多少數據。
固然inodesize、inode分配比例、blocksize均可以在建立文件系統的時候人爲指定。
Ext預留了一些inode作特殊特性使用,以下:某些可能並不是老是準確,具體的inode號對應什麼文件可使用"find / -inum NUM"查看。
因此在ext4文件系統的dumpe2fs信息中,能觀察到fisrt inode號可能爲11也可能爲12。
而且注意到"/"的inode號爲2,這個特性在文件訪問時會用上。
須要注意的是,每一個文件系統都會分配本身的inode號,不一樣文件系統之間是可能會出現使用相同inode號文件的。例如:
[root@xuexi ~]# find / -ignore_readdir_race -inum 2 -ls 2 4 dr-xr-xr-x 22 root root 4096 Jun 9 09:56 / 2 2 dr-xr-xr-x 5 root root 1024 Feb 25 11:53 /boot 2 0 c--------- 1 root root Jun 7 02:13 /dev/pts/ptmx 2 0 -rw-r--r-- 1 root root 0 Jun 6 18:13 /proc/sys/fs/binfmt_misc/status 2 0 drwxr-xr-x 3 root root 0 Jun 6 18:13 /sys/fs
從結果中可見,除了根的Inode號爲2,還有幾個文件的inode號也是 2,它們都屬於獨立的文件系統,有些是虛擬文件系統,如/proc和/sys。
前文說過,inode中保存了blocks指針,可是一條inode記錄中能保存的指針數量是有限的,不然就會超出inode大小(128字節或256字節)。
在ext2和ext3文件系統中,一個inode中最多隻能有15個指針,每一個指針使用i_block[n]表示。
前12個指針i_block[0]到i_block[11]是直接尋址指針,每一個指針指向一個數據區的block。以下圖所示。
第13個指針i_block[12]是一級間接尋址指針,它指向一個仍然存儲了指針的block即i_block[12] --> Pointerblock --> datablock。
第14個指針i_block[13]是二級間接尋址指針,它指向一個仍然存儲了指針的block,可是這個block中的指針還繼續指向其餘存儲指針的block,即i_block[13] --> Pointerblock1 --> PointerBlock2 --> datablock。
第15個指針i_block[14]是三級間接尋址指針,它指向一個任然存儲了指針的block,這個指針block下還有兩次指針指向。即i_block[13] --> Pointerblock1 --> PointerBlock2 --> PointerBlock3 --> datablock。
其中因爲每一個指針大小爲4字節,因此每一個指針block能存放的指針數量爲BlockSize/4byte。例如blocksize爲4KB,那麼一個Block能夠存放4096/4=1024個指針。
以下圖。
爲何要分間接和直接指針呢?若是一個inode中15個指針全是直接指針,假如每一個block的大小爲1KB,那麼15個指針只能指向15個block即15KB的大小,因爲每一個文件對應一個inode號,因此就限制了每一個文件最大爲15*1=15KB,這顯然是不合理的。
若是存儲大於15KB的文件而又不太大的時候,就佔用一級間接指針i_block[12],這時能夠存放指針數量爲1024/4+12=268,因此能存放268KB的文件。
若是存儲大於268K 的文件而又不太大的時候,就繼續佔用二級指針i_block[13],這時能夠存放指針數量爲[1024/4]^2+1024/4+12=65804,因此能存放65804KB=64M左右的文件。
若是存放的文件大於64M,那麼就繼續使用三級間接指針i_block[14],存放的指針數量爲[1024/4]^3+[1024/4]^2+[1024/4]+12=16843020個指針,因此能存放16843020KB=16GB左右的文件。
若是blocksize=4KB呢?那麼最大能存放的文件大小爲([4096/4]^3+[4096/4]^2+[4096/4]+12)*4/1024/1024/1024=4T左右。
固然這樣計算出來的不必定就是最大能存放的文件大小,它還受到另外一個條件的限制。這裏的計算只是代表一個大文件是如何尋址和分配的。
其實看到這裏的計算數值,就知道ext2和ext3對超大文件的存取效率是低下的,它要覈對太多的指針,特別是4KB大小的blocksize時。而ext4針對這一點就進行了優化,ext4使用extent的管理方式取代ext2和ext3的塊映射,大大提升了效率也下降了碎片。
在Linux上執行刪除、複製、重命名、移動等操做時,它們是怎麼進行的呢?還有訪問文件時是如何找到它的呢?其實只要理解了前文中介紹的幾個術語以及它們的做用就很容易知道文件操做的原理了。
注:在這一小節所解釋的都是在單個文件系統下的行爲,在多個文件系統中如何請看下一個小節:多文件系統關聯。
當執行"cat /var/log/messages"命令在系統內部進行了什麼樣的步驟呢?該命令能被成功執行涉及了cat命令的尋找、權限判斷以及messages文件的尋找和權限判斷等等複雜的過程。這裏只解釋和本節內容相關的如何尋找到被cat的/var/log/messages文件。
由於GDT老是和superblock在同一個塊組,而superblock老是在分區的第1024-2047個字節,因此很容易就知道第一個GDT所在的塊組以及GDT在這個塊組中佔用了哪些block。
其實GDT早已經在內存中了,在系統開機的時候會掛載根文件系統,掛載的時候就已經將全部的GDT放進內存中。
前文說過,ext文件系統預留了一些inode號,其中"/"的inode號爲2,因此能夠根據inode號直接定位根目錄文件的data block。
經過var目錄的inode指針,能夠尋找到var目錄的inode記錄,可是指針定位的過程當中,還須要知道該inode記錄所在的塊組以及所在的inode table,因此須要讀取GDT,一樣,GDT已經緩存到了內存中。
將上述步驟中GDT部分的步驟簡化後比較容易理解。以下:找到GDT-->找到"/"的inode-->找到/的數據塊讀取var的inode-->找到var的數據塊讀取log的inode-->找到log的數據塊讀取messages的inode-->找到messages的數據塊並讀取它們。
注意這裏是不跨越文件系統的操做行爲。
對於刪除普通文件:(1)找到文件的inode和data block(根據前一個小節中的方法尋找);(2)將inode table中該inode記錄中的data block指針刪除;(3)在imap中將該文件的inode號標記爲未使用;(4)在其所在目錄的data block中將該文件名所在的記錄行刪除,刪除了記錄就丟失了指向inode的指針;(5)將bmap中data block對應的block號標記爲未使用。
對於刪除目錄文件:找到目錄和目錄下全部文件、子目錄、子文件的inode和data block;在imap中將這些inode號標記爲未使用;將bmap中將這些文件佔用的 block號標記爲未使用;在該目錄的父目錄的data block中將該目錄名所在的記錄行刪除。須要注意的是,刪除父目錄data block中的記錄是最後一步,若是該步驟提早,將報目錄非空的錯誤,由於在該目錄中還有文件佔用。
關於上面的(2)-(5):當(2)中刪除data block指針後,將沒法再找到這個文件的數據;當(3)標記inode號未使用,表示該inode號能夠被後續的文件重用;當(4)刪除目錄data block中關於該文件的記錄,真正的刪除文件,外界再也定位也沒法看到這個文件了;當(5)標記data block爲未使用後,表示開始釋放空間,這些data block能夠被其餘文件重用。
注意,在第(5)步以前,因爲data block還未被標記爲未使用,在superblock中仍然認爲這些data block是正在使用中的。這表示儘管文件已經被刪除了,但空間卻尚未釋放,df也會將其統計到已用空間中(df是讀取superblock中的數據塊數量,並計算轉換爲空間大小)。
何時會發生這種狀況呢?當一個進程正在引用文件時將該文件刪除,就會出現文件已刪除但空間未釋放的狀況。這時步驟已經進行到(4),外界沒法再找到該文件,但因爲進程在加載該文件時已經獲取到了該文件全部的data block指針,該進程能夠獲取到該文件的全部數據,但卻暫時不會釋放該文件空間。直到該進程結束,文件系統纔將未執行的步驟(5)繼續完成。這也是爲何有時候du的統計結果比df小的緣由,關於du和df統計結果的差異,詳細內容見:詳細分析du和df的統計結果爲何不同。
同目錄內重命名文件的動做僅僅只是修改所在目錄data block中該文件記錄的文件名部分,不是刪除再重建的過程。
若是重命名時有文件名衝突(該目錄內已經存在該文件名),則提示是否覆蓋。覆蓋的過程是覆蓋目錄data block中衝突文件的記錄。例如/tmp/下有a.txt和a.log,若將a.txt重命名爲a.log,則提示覆蓋,若選擇覆蓋,則/tmp的data block中關於a.log的記錄被覆蓋,此時它的指針是指向a.txt的inode。
同文件系統下移動文件其實是修改目標文件所在目錄的data block,向其中添加一行指向inode table中待移動文件的inode指針,若是目標路徑下有同名文件,則會提示是否覆蓋,其實是覆蓋目錄data block中衝突文件的記錄,因爲同名文件的inode記錄指針被覆蓋,因此沒法再找到該文件的data block,也就是說該文件被標記爲刪除(若是多個硬連接數,則另當別論)。
因此在同文件系統內移動文件至關快,僅僅在所在目錄data block中添加或覆蓋了一條記錄而已。也所以,移動文件時,文件的inode號是不會改變的。
對於不一樣文件系統內的移動,至關於先複製再刪除的動做。見後文。
關於文件移動,在Linux環境下有一個很是經典網上卻又沒任何解釋的問題:/tmp/a/a能覆蓋爲/tmp/a嗎?答案是不能,但windows能。爲何不能?見mv的一個經典問題(mv的本質)。
在單個文件系統中的文件操做和多文件系統中的操做有所不一樣。本文將對此作出很是詳細的說明。
這裏要明確的是,任何一個文件系統要在Linux上能正常使用,必須掛載在某個已經掛載好的文件系統中的某個目錄下,例如/dev/cdrom掛載在/mnt上,/mnt目錄自己是在"/"文件系統下的。並且任意文件系統的一級掛載點必須是在根文件系統的某個目錄下,由於只有"/"是自引用的。這裏要說明掛載點的級別和自引用的概念。
假如/dev/sdb1掛載在/mydata上,/dev/cdrom掛載在/mydata/cdrom上,那麼/mydata就是一級掛載點,此時/mydata已是文件系統/dev/sdb1的入口了,而/dev/cdrom所掛載的目錄/mydata/cdrom是文件系統/dev/sdb1中的某個目錄,那麼/mydata/cdrom就是二級掛載點。一級掛載點必須在根文件系統下,因此可簡述爲:文件系統2掛載在文件系統1中的某個目錄下,而文件系統1又掛載在根文件系統中的某個目錄下。
再解釋自引用。首先要說的是,自引用的只能是文件系統,而文件系統表現形式是一個目錄,因此自引用是指該目錄的data block中,"."和".."的記錄中的inode指針都指向inode table中同一個inode記錄,因此它們inode號是相同的,即互爲硬連接。而根文件系統是惟一能夠自引用的文件系統。
[root@xuexi /]# ll -ai / total 102 2 dr-xr-xr-x. 22 root root 4096 Jun 6 18:13 . 2 dr-xr-xr-x. 22 root root 4096 Jun 6 18:13 ..
由此也能解釋cd /.和cd /..的結果都仍是在根下,這是自引用最直接的表現形式。
[root@xuexi tmp]# cd /. [root@xuexi /]# [root@xuexi tmp]# cd /.. [root@xuexi /]#
注意,根目錄下的"."和".."都是"/"目錄的硬連接,且其datablock中不記錄名爲"/"的條目,所以除去根目錄下子目錄數後的硬連接數爲2。
[root@server2 tmp]# a=$(ls -ld / | awk '{print $2}') [root@server2 tmp]# b=$(ls -l / | grep "^d" |wc -l) [root@server2 tmp]# echo $((a - b)) 2
掛載文件系統到某個目錄下,例如"mount /dev/cdrom /mnt",掛載成功後/mnt目錄中的文件全都暫時不可見了,且掛載後權限和全部者(若是指定容許普通用戶掛載)等的都改變了,知道爲何嗎?
下面就以經過"mount /dev/cdrom /mnt"爲例,詳細說明掛載過程當中涉及的細節。
在將文件系統/dev/cdrom(此處暫且認爲它是文件系統)掛載到掛載點/mnt以前,掛載點/mnt是根文件系統中的一個目錄,"/"的data block中記錄了/mnt的一些信息,其中包括inode指針inode_n,而在inode table中,/mnt對應的inode記錄中又存儲了block指針block_n,此時這兩個指針仍是普通的指針。
當文件系統/dev/cdrom掛載到/mnt上後,/mnt此時就已經成爲另外一個文件系統的入口了,所以它須要鏈接兩邊文件系統的inode和data block。可是如何鏈接呢?以下圖。
在根文件系統的inode table中,爲/mnt從新分配一個inode記錄m,該記錄的block指針block_m指向文件系統/dev/cdrom中的data block。既然爲/mnt分配了新的inode記錄m,那麼在"/"目錄的data block中,也須要修改其inode指針爲inode_m以指向m記錄。同時,原來inode table中的inode記錄n就被標記爲暫時不可用。
block_m指向的是文件系統/dev/cdrom的data block,因此嚴格提及來,除了/mnt的元數據信息即inode記錄m還在根文件系統上,/mnt的data block已是在/dev/cdrom中的了。這就是掛載新文件系統後實現的跨文件系統,它將掛載點的元數據信息和數據信息分別存儲在不一樣的文件系統上。
掛載完成後,將在/proc/self/{mounts,mountstats,mountinfo}這三個文件中寫入掛載記錄和相關的掛載信息,並會將/proc/self/mounts中的信息同步到/etc/mtab文件中,固然,若是掛載時加了-n參數,將不會同步到/etc/mtab。
而卸載文件系統,其實質是移除臨時新建的inode記錄(固然,在移除前會檢查是否正在使用)及其指針,並將指針指回原來的inode記錄,這樣inode記錄中的block指針也就同時生效而找回對應的data block了。因爲卸載只是移除inode記錄,因此使用掛載點和文件系統均可以實現卸載,由於它們是聯繫在一塊兒的。
下面是分析或結論。
(1).掛載點掛載時的inode記錄是新分配的。
# 掛載前掛載點/mnt的inode號
[root@server2 tmp]# ll -id /mnt 100663447 drwxr-xr-x. 2 root root 6 Aug 12 2015 /mnt [root@server2 tmp]# mount /dev/cdrom /mnt
# 掛載後掛載點的inode號 [root@server2 tmp]# ll -id /mnt 1856 dr-xr-xr-x 8 root root 2048 Dec 10 2015 mnt
由此能夠驗證,inode號確實是從新分配的。
(2).掛載後,掛載點的內容將暫時不可見、不可用,卸載後文件又再次可見、可用。
# 在掛載前,向掛載點中建立幾個文件 [root@server2 tmp]# touch /mnt/a.txt [root@server2 tmp]# mkdir /mnt/abcdir
# 掛載 [root@server2 tmp]# mount /dev/cdrom /mnt # 掛載後,掛載點中將找不到剛建立的文件 [root@server2 tmp]# ll /mnt total 636 -r--r--r-- 1 root root 14 Dec 10 2015 CentOS_BuildTag dr-xr-xr-x 3 root root 2048 Dec 10 2015 EFI -r--r--r-- 1 root root 215 Dec 10 2015 EULA -r--r--r-- 1 root root 18009 Dec 10 2015 GPL dr-xr-xr-x 3 root root 2048 Dec 10 2015 images dr-xr-xr-x 2 root root 2048 Dec 10 2015 isolinux dr-xr-xr-x 2 root root 2048 Dec 10 2015 LiveOS dr-xr-xr-x 2 root root 612352 Dec 10 2015 Packages dr-xr-xr-x 2 root root 4096 Dec 10 2015 repodata -r--r--r-- 1 root root 1690 Dec 10 2015 RPM-GPG-KEY-CentOS-7 -r--r--r-- 1 root root 1690 Dec 10 2015 RPM-GPG-KEY-CentOS-Testing-7 -r--r--r-- 1 root root 2883 Dec 10 2015 TRANS.TBL # 卸載後,掛載點/mnt中的文件將再次可見 [root@server2 tmp]# umount /mnt [root@server2 tmp]# ll /mnt total 0 drwxr-xr-x 2 root root 6 Jun 9 08:18 abcdir -rw-r--r-- 1 root root 0 Jun 9 08:18 a.txt
之因此會這樣,是由於掛載文件系統後,掛載點原來的inode記錄暫時被標記爲不可用,關鍵是沒有指向該inode記錄的inode指針了。在卸載文件系統後,又從新啓用掛載點原來的inode記錄,"/"目錄下的mnt的inode指針又從新指向該inode記錄。
(3).掛載後,掛載點的元數據和data block是分別存放在不一樣文件系統上的。
(4).掛載點即便在掛載後,也仍是屬於源文件系統的文件。
假以下圖中的圓表明一塊硬盤,其中劃分了3個區即3個文件系統。其中根是根文件系統,/mnt是另外一個文件系統A的入口,A文件系統掛載在/mnt上,/mnt/cdrom也是一個文件系統B的入口,B文件系統掛載在/mnt/cdrom上。每一個文件系統都維護了一些inode table,這裏假設圖中的inode table是每一個文件系統全部塊組中的inode table的集合表。
如何讀取/var/log/messages呢?這是和"/"在同一個文件系統的文件讀取,在前面單文件系統中已經詳細說明了。
但如何讀取A文件系統中的/mnt/a.log呢?首先,從根文件系統找到/mnt的inode記錄,這是單文件系統內的查找;而後根據此inode記錄的block指針,定位到/mnt的data block中,這些block是A文件系統的data block;而後從/mnt的data block中讀取a.log記錄,並根據a.log的inode指針定位到A文件系統的inode table中對應a.log的inode記錄;最後今後inode記錄的block指針找到a.log的data block。至此,就能讀取到/mnt/a.log文件的內容。
下圖能更完整的描述上述過程。
那麼又如何讀取/mnt/cdrom中的/mnt/cdrom/a.rpm呢?這裏cdrom表明的文件系統B掛載點位於/mnt下,因此又多了一個步驟。先找到"/",再找到根中的mnt,進入到mnt文件系統中,找到cdrom的data block,再進入到cdrom找到a.rpm。也就是說,mnt目錄文件存放位置是根,cdrom目錄文件存放位置是mnt,最後a.rpm存放的位置纔是cdrom。
繼續完善上圖。以下。
相比ext2文件系統,ext3多了一個日誌功能。
在ext2文件系統中,只有兩個區:數據區和元數據區。若是正在向data block中填充數據時忽然斷電,那麼下一次啓動時就會檢查文件系統中數據和狀態的一致性,這段檢查和修復可能會消耗大量時間,甚至檢查後沒法修復。之因此會這樣是由於文件系統在忽然斷電後,它不知道上次正在存儲的文件的block從哪裏開始、哪裏結束,因此它會掃描整個文件系統進行排除(也許是這樣檢查的吧)。
而在建立ext3文件系統時會劃分三個區:數據區、日誌區和元數據區。每次存儲數據時,先在日誌區中進行ext2中元數據區的活動,直到文件存儲完成後標記上commit纔將日誌區中的數據轉存到元數據區。當存儲文件時忽然斷電,下一次檢查修復文件系統時,只須要檢查日誌區的記錄,將bmap對應的data block標記爲未使用,並把inode號標記未使用,這樣就不須要掃描整個文件系統而耗費大量時間。
雖然說ext3相比ext2多了一個日誌區轉寫元數據區的動做而致使ext3相比ext2性能要差一點,特別是寫衆多小文件時。可是因爲ext3其餘方面的優化使得ext3和ext2性能幾乎沒有差距。
回顧前面關於ext2和ext3文件系統的存儲格式,它使用block爲存儲單元,每一個block使用bmap中的位來標記是否空閒,儘管使用劃分塊組的方法優化提升了效率,可是一個塊組內部仍然使用bmap來標記該塊組內的block。對於一個巨大的文件,掃描整個bmap都將是一件浩大的工程。另外在inode尋址方面,ext2/3使用直接和間接的尋址方式,對於三級間接指針,可能要遍歷的指針數量是很是很是巨大的。
ext4文件系統的最大特色是在ext3的基礎上使用區(extent,或稱爲段)的概念來管理。一個extent儘量的包含物理上連續的一堆block。inode尋址方面也同樣使用區段樹的方式進行了改進。
默認狀況下,EXT4再也不使用EXT3的block mapping分配方式 ,而改成Extent方式分配。
如下是ext4文件系統中一個文件的inode屬性示例,注意最後兩行的EXTENTS。
Inode: 12 Type: regular Mode: 0644 Flags: 0x80000 Generation: 476513974 Version: 0x00000000:00000001 User: 0 Group: 0 Size: 11 File ACL: 0 Directory ACL: 0 Links: 1 Blockcount: 8 Fragment: Address: 0 Number: 0 Size: 0 ctime: 0x5b628ca0:491d6224 -- Thu Aug 2 12:46:24 2018 atime: 0x5b628ca0:491d6224 -- Thu Aug 2 12:46:24 2018 mtime: 0x5b628ca0:491d6224 -- Thu Aug 2 12:46:24 2018 crtime: 0x5b628ca0:491d6224 -- Thu Aug 2 12:46:24 2018 Size of extra inode fields: 28 EXTENTS: (0):33409
(1). 關於EXT4的結構特徵
EXT4在整體結構上與EXT3類似,大的分配方向都是基於相同大小的塊組,每一個塊組內分配固定數量的inode、可能的superblock(或備份)及GDT。
EXT4的inode 結構作了重大改變,爲增長新的信息,大小由EXT3的128字節增長到默認的256字節,同時inode尋址索引再也不使用EXT3的"12個直接尋址塊+1個一級間接尋址塊+1個二級間接尋址塊+1個三級間接尋址塊"的索引模式,而改成4個Extent片段流,每一個片段流設定片段的起始block號及連續的block數量(有可能直接指向數據區,也有可能指向索引塊區)。
片斷流即下圖中索引節點(inde node block)部分的綠色區域,每一個15字節,共60字節。
(2). EXT4刪除數據的結構更改。
EXT4刪除數據後,會依次釋放文件系統bitmap空間位、更新目錄結構、釋放inode空間位。
(3). ext4使用多block分配方式。
在存儲數據時,ext3中的block分配器一次只能分配4KB大小的Block數量,並且每存儲一個block前就標記一次bmap。假如存儲1G的文件,blocksize是4KB,那麼每存儲完一個Block就將調用一次block分配器,即調用的次數爲1024*1024/4KB=262144次,標記bmap的次數也爲1024*1024/4=262144次。
而在ext4中根據區段來分配,能夠實現調用一次block分配器就分配一堆連續的block,並在存儲這一堆block前一次性標記對應的bmap。這對於大文件來講極大的提高了存儲效率。
最大的缺點是它在建立文件系統的時候就劃分好一切須要劃分的東西,之後用到的時候能夠直接進行分配,也就是說它不支持動態劃分和動態分配。對於較小的分區來講速度還好,可是對於一個超大的磁盤,速度是極慢極慢的。例如將一個幾十T的磁盤陣列格式化爲ext4文件系統,可能你會所以而失去一切耐心。
除了格式化速度超慢之外,ext4文件系統仍是很是可取的。固然,不一樣公司開發的文件系統都各有特點,最主要的仍是根據需求選擇合適的文件系統類型。
每個分區格式化後均可以創建一個文件系統,Linux上能夠識別不少種文件系統,那麼它是如何識別的呢?另外,在咱們操做分區中的文件時,並無指定過它是哪一個文件系統的,各類不一樣的文件系統如何被咱們用戶以無差異的方式操做呢?這就是虛擬文件系統的做用。
虛擬文件系統爲用戶操做各類文件系統提供了通用接口,使得用戶執行程序時不須要考慮文件是在哪一種類型的文件系統上,應該使用什麼樣的系統調用來操做該文件。有了虛擬文件系統,只要將全部須要執行的程序調用VFS的系統調用就能夠了,剩下的動做由VFS來幫忙完成。
轉載請務必在文章最開頭標明原文地址
本文原創地址:博客園駿馬金龍http://www.javashuo.com/article/p-dfmejtfg-hk.html