基礎學習篇 - CentOS 7.x

第七章、Linux 磁碟與檔案系統管理

Linux 的磁碟掛載等特色,以及檔案系統 (filesystem) 的介紹

最近更新時間: 2017/09/04

系統管理員很重要的任務之一就是管理好自己的磁碟檔案系統,每個分割槽不可太大也不能太小, 太大會造成磁碟容量的浪費,太小則會產生檔案無法儲存的困擾。此外,我們在前面幾章談到的檔案權限與屬性中, 這些權限與屬性分別記錄在檔案系統的哪個區塊內?這就得要談到 filesystem 中的 inode 與 block 了。同時,為了虛擬化與大容量磁碟, 現在的 CentOS 7 預設使用大容量效能較佳的 xfs 當預設檔案系統了!這也得了解一下。 在本章我們的重點在於如何製作檔案系統,包括分割、格式化與掛載等,是很重要的一個章節喔!

7.1 認識 Linux 檔案系統

Linux 最傳統的磁碟檔案系統 (filesystem) 使用的是 EXT2 這個啦!所以要瞭解 Linux 的檔案系統就得要由認識 EXT2 開始! 而檔案系統是建立在磁碟上面的,因此我們得瞭解磁碟的物理組成才行。磁碟物理組成的部分我們在第零章談過了,至於磁碟分割則在第二章談過了,所以底下只會很快的複習這兩部份。 重點在於 inode, block 還有 superblock 等檔案系統的基本部分喔!

7.1.1 磁碟組成與分割的複習

由於各項磁碟的物理組成我們在第零章裡面就介紹過, 同時第二章也談過分割的概念了,所以這個小節我們就拿之前的重點出來介紹就好了! 詳細的資訊請您回去那兩章自行複習喔!^_^。好了,首先說明一下磁碟的物理組成,整顆磁碟的組成主要有:

  • 圓形的磁碟盤(主要記錄資料的部分);
  • 機械手臂,與在機械手臂上的磁碟讀取頭(可讀寫磁碟盤上的資料);
  • 主軸馬達,可以轉動磁碟盤,讓機械手臂的讀取頭在磁碟盤上讀寫資料。

從上面我們知道資料儲存與讀取的重點在於磁碟盤,而磁碟盤上的物理組成則為(假設此磁碟為單碟片, 磁碟盤圖示請參考第二章圖2.2.1的示意):

  • 磁區(Sector)為最小的物理儲存單位,且依據磁碟設計的不同,目前主要有 512bytes 與 4K 兩種格式;
  • 將磁區組成一個圓,那就是磁柱(Cylinder);
  • 早期的分割主要以磁柱為最小分割單位,現在的分割通常使用磁區為最小分割單位(每個磁區都有其號碼喔,就好像座位一樣);
  • 磁碟分割表主要有兩種格式,一種是限制較多的 MBR 分割表,一種是較新且限制較少的 GPT 分割表。
  • MBR 分割表中,第一個磁區最重要,裡面有:(1)主要開機區(Master boot record, MBR)及分割表(partition table), 其中 MBR 佔有 446 bytes,而 partition table 則佔有 64 bytes。
  • GPT 分割表除了分割數量擴充較多之外,支援的磁碟容量也可以超過 2TB。

至於磁碟的檔名部份,基本上,所有實體磁碟的檔名都已經被模擬成 /dev/sd[a-p] 的格式,第一顆磁碟檔名為 /dev/sda。 而分割槽的檔名若以第一顆磁碟為例,則為 /dev/sda[1-128] 。除了實體磁碟之外,虛擬機的磁碟通常為 /dev/vd[a-p] 的格式。 若有使用到軟體磁碟陣列的話,那還有 /dev/md[0-128] 的磁碟檔名。使用的是 LVM 時,檔名則為 /dev/VGNAME/LVNAME 等格式。 關於軟體磁碟陣列與 LVM 我們會在後面繼續介紹,這裡主要介紹的以實體磁碟及虛擬磁碟為主喔!

  • /dev/sd[a-p][1-128]:為實體磁碟的磁碟檔名;
  • /dev/vd[a-d][1-128]:為虛擬磁碟的磁碟檔名

複習完物理組成後,來複習一下磁碟分割吧!如前所述,以前磁碟分割最小單位經常是磁柱,但 CentOS 7 的分割軟體, 已經將最小單位改成磁區了,所以容量大小的分割可以切的更細~此外,由於新的大容量磁碟大多得要使用 GPT 分割表才能夠使用全部的容量, 因此過去那個 MBR 的傳統磁碟分割表限制就不會存在了。不過,由於還是有小磁碟啊!因此, 你在處理分割的時候,還是得要先查詢一下,你的分割是 MBR 的分割?還是 GPT 的分割?在第三章的 CentOS 7 安裝中, 鳥哥建議過強制使用 GPT 分割喔!所以本章後續的動作,大多還是以 GPT 為主來介紹喔!舊的 MBR 相關限制回去看看第二章吧!

7.1.2 檔案系統特性

我們都知道磁碟分割完畢後還需要進行格式化(format),之後作業系統才能夠使用這個檔案系統。 為什麼需要進行『格式化』呢?這是因為每種作業系統所設定的檔案屬性/權限並不相同, 為了存放這些檔案所需的資料,因此就需要將分割槽進行格式化,以成為作業系統能夠利用的『檔案系統格式(filesystem)』。

由此我們也能夠知道,每種作業系統能夠使用的檔案系統並不相同。 舉例來說,windows 98 以前的微軟作業系統主要利用的檔案系統是 FAT (或 FAT16),windows 2000 以後的版本有所謂的 NTFS 檔案系統,至於 Linux 的正統檔案系統則為 Ext2 (Linux second extended file system, ext2fs)這一個。此外,在預設的情況下,windows 作業系統是不會認識 Linux 的 Ext2 的。

傳統的磁碟與檔案系統之應用中,一個分割槽就是只能夠被格式化成為一個檔案系統,所以我們可以說一個 filesystem 就是一個 partition。但是由於新技術的利用,例如我們常聽到的LVM與軟體磁碟陣列(software raid), 這些技術可以將一個分割槽格式化為多個檔案系統(例如LVM),也能夠將多個分割槽合成一個檔案系統(LVM, RAID)! 所以說,目前我們在格式化時已經不再說成針對 partition 來格式化了, 通常我們可以稱呼一個可被掛載的資料為一個檔案系統而不是一個分割槽喔!

那麼檔案系統是如何運作的呢?這與作業系統的檔案資料有關。較新的作業系統的檔案資料除了檔案實際內容外, 通常含有非常多的屬性,例如 Linux 作業系統的檔案權限(rwx)與檔案屬性(擁有者、群組、時間參數等)。 檔案系統通常會將這兩部份的資料分別存放在不同的區塊,權限與屬性放置到 inode 中,至於實際資料則放置到 data block 區塊中。 另外,還有一個超級區塊 (superblock) 會記錄整個檔案系統的整體資訊,包括 inode 與 block 的總量、使用量、剩餘量等。

每個 inode 與 block 都有編號,至於這三個資料的意義可以簡略說明如下:

  • superblock:記錄此 filesystem 的整體資訊,包括inode/block的總量、使用量、剩餘量, 以及檔案系統的格式與相關資訊等;
  • inode:記錄檔案的屬性,一個檔案佔用一個inode,同時記錄此檔案的資料所在的 block 號碼;
  • block:實際記錄檔案的內容,若檔案太大時,會佔用多個 block 。

由於每個 inode 與 block 都有編號,而每個檔案都會佔用一個 inode ,inode 內則有檔案資料放置的 block 號碼。 因此,我們可以知道的是,如果能夠找到檔案的 inode 的話,那麼自然就會知道這個檔案所放置資料的 block 號碼, 當然也就能夠讀出該檔案的實際資料了。這是個比較有效率的作法,因為如此一來我們的磁碟就能夠在短時間內讀取出全部的資料, 讀寫的效能比較好囉。

我們將 inode 與 block 區塊用圖解來說明一下,如下圖所示,檔案系統先格式化出 inode 與 block 的區塊,假設某一個檔案的屬性與權限資料是放置到 inode 4 號(下圖較小方格內),而這個 inode 記錄了檔案資料的實際放置點為 2, 7, 13, 15 這四個 block 號碼,此時我們的作業系統就能夠據此來排列磁碟的讀取順序,可以一口氣將四個 block 內容讀出來! 那麼資料的讀取就如同下圖中的箭頭所指定的模樣了。

inode/block 資料存取示意圖
圖7.1.1、inode/block 資料存取示意圖

這種資料存取的方法我們稱為索引式檔案系統(indexed allocation)。那有沒有其他的慣用檔案系統可以比較一下啊? 有的,那就是我們慣用的隨身碟(快閃記憶體),隨身碟使用的檔案系統一般為 FAT 格式。FAT 這種格式的檔案系統並沒有 inode 存在,所以 FAT 沒有辦法將這個檔案的所有 block 在一開始就讀取出來。每個 block 號碼都記錄在前一個 block 當中, 他的讀取方式有點像底下這樣:

FAT檔案系統資料存取示意圖
圖7.1.2、FAT檔案系統資料存取示意圖

上圖中我們假設檔案的資料依序寫入1->7->4->15號這四個 block 號碼中, 但這個檔案系統沒有辦法一口氣就知道四個 block 的號碼,他得要一個一個的將 block 讀出後,才會知道下一個 block 在何處。 如果同一個檔案資料寫入的 block 分散的太過厲害時,則我們的磁碟讀取頭將無法在磁碟轉一圈就讀到所有的資料, 因此磁碟就會多轉好幾圈才能完整的讀取到這個檔案的內容!

常常會聽到所謂的『磁碟重組』吧? 需要磁碟重組的原因就是檔案寫入的 block 太過於離散了,此時檔案讀取的效能將會變的很差所致。 這個時候可以透過磁碟重組將同一個檔案所屬的 blocks 彙整在一起,這樣資料的讀取會比較容易啊! 想當然爾,FAT 的檔案系統需要三不五時的磁碟重組一下,那麼 Ext2 是否需要磁碟重整呢?

由於 Ext2 是索引式檔案系統,基本上不太需要常常進行磁碟重組的。但是如果檔案系統使用太久, 常常刪除/編輯/新增檔案時,那麼還是可能會造成檔案資料太過於離散的問題,此時或許會需要進行重整一下的。 不過,老實說,鳥哥倒是沒有在 Linux 作業系統上面進行過 Ext2/Ext3 檔案系統的磁碟重組說!似乎不太需要啦!^_^

7.1.3 Linux 的 EXT2 檔案系統(inode)

第五章當中我們介紹過 Linux 的檔案除了原有的資料內容外,還含有非常多的權限與屬性,這些權限與屬性是為了保護每個使用者所擁有資料的隱密性。 而前一小節我們知道 filesystem 裡面可能含有的 inode/block/superblock 等。為什麼要談這個呢?因為標準的 Linux 檔案系統 Ext2 就是使用這種 inode 為基礎的檔案系統啦!

而如同前一小節所說的,inode 的內容在記錄檔案的權限與相關屬性,至於 block 區塊則是在記錄檔案的實際內容。 而且檔案系統一開始就將 inode 與 block 規劃好了,除非重新格式化(或者利用 resize2fs 等指令變更檔案系統大小),否則 inode 與 block 固定後就不再變動。但是如果仔細考慮一下,如果我的檔案系統高達數百GB時, 那麼將所有的 inode 與 block 通通放置在一起將是很不智的決定,因為 inode 與 block 的數量太龐大,不容易管理。

為此之故,因此 Ext2 檔案系統在格式化的時候基本上是區分為多個區塊群組 (block group) 的,每個區塊群組都有獨立的 inode/block/superblock 系統。感覺上就好像我們在當兵時,一個營裡面有分成數個連,每個連有自己的聯絡系統, 但最終都向營部回報連上最正確的資訊一般!這樣分成一群群的比較好管理啦!整個來說,Ext2 格式化後有點像底下這樣:

ext2檔案系統示意圖
圖7.1.3、ext2檔案系統示意圖 (註1)

在整體的規劃當中,檔案系統最前面有一個開機磁區(boot sector),這個開機磁區可以安裝開機管理程式, 這是個非常重要的設計,因為如此一來我們就能夠將不同的開機管理程式安裝到個別的檔案系統最前端,而不用覆蓋整顆磁碟唯一的 MBR, 這樣也才能夠製作出多重開機的環境啊!至於每一個區塊群組(block group)的六個主要內容說明如後:

  • data block (資料區塊)

data block 是用來放置檔案內容資料地方,在 Ext2 檔案系統中所支援的 block 大小有 1K, 2K 及 4K 三種而已。在格式化時 block 的大小就固定了,且每個 block 都有編號,以方便 inode 的記錄啦。 不過要注意的是,由於 block 大小的差異,會導致該檔案系統能夠支援的最大磁碟容量與最大單一檔案容量並不相同。 因為 block 大小而產生的 Ext2 檔案系統限制如下:(註2)

Block 大小1KB2KB4KB
最大單一檔案限制16GB256GB2TB
最大檔案系統總容量2TB8TB16TB

你需要注意的是,雖然 Ext2 已經能夠支援大於 2GB 以上的單一檔案容量,不過某些應用程式依然使用舊的限制, 也就是說,某些程式只能夠捉到小於 2GB 以下的檔案而已,這就跟檔案系統無關了! 舉例來說,鳥哥在環工方面的應用中有一套秀圖軟體稱為PAVE(註3), 這套軟體就無法捉到鳥哥在數值模式模擬後產生的大於 2GB 以上的檔案!所以後來只能找更新的軟體來取代它了!

除此之外 Ext2 檔案系統的 block 還有什麼限制呢?有的!基本限制如下:

  • 原則上,block 的大小與數量在格式化完就不能夠再改變了(除非重新格式化);
  • 每個 block 內最多只能夠放置一個檔案的資料;
  • 承上,如果檔案大於 block 的大小,則一個檔案會佔用多個 block 數量;
  • 承上,若檔案小於 block ,則該 block 的剩餘容量就不能夠再被使用了(磁碟空間會浪費)。

如上第四點所說,由於每個 block 僅能容納一個檔案的資料而已,因此如果你的檔案都非常小,但是你的 block 在格式化時卻選用最大的 4K 時,可能會產生一些容量的浪費喔!我們以底下的一個簡單例題來算一下空間的浪費吧!

例題:
假設你的Ext2檔案系統使用 4K block ,而該檔案系統中有 10000 個小檔案,每個檔案大小均為 50bytes, 請問此時你的磁碟浪費多少容量?
答:
由於 Ext2 檔案系統中一個 block 僅能容納一個檔案,因此每個 block 會浪費『 4096 - 50 = 4046 (byte)』, 系統中總共有一萬個小檔案,所有檔案容量為:50 (bytes) x 10000 = 488.3Kbytes,但此時浪費的容量為:『 4046 (bytes) x 10000 = 38.6MBytes 』。想一想,不到 1MB 的總檔案容量卻浪費將近 40MB 的容量,且檔案越多將造成越多的磁碟容量浪費。

什麼情況會產生上述的狀況呢?例如 BBS 網站的資料啦!如果 BBS 上面的資料使用的是純文字檔案來記載每篇留言, 而留言內容如果都寫上『如題』時,想一想,是否就會產生很多小檔案了呢?

好,既然大的 block 可能會產生較嚴重的磁碟容量浪費,那麼我們是否就將 block 大小訂為 1K 即可? 這也不妥,因為如果 block 較小的話,那麼大型檔案將會佔用數量更多的 block ,而 inode 也要記錄更多的 block 號碼,此時將可能導致檔案系統不良的讀寫效能。

所以我們可以說,在您進行檔案系統的格式化之前,請先想好該檔案系統預計使用的情況。 以鳥哥來說,我的數值模式模擬平台隨便一個檔案都好幾百 MB,那麼 block 容量當然選擇較大的!至少檔案系統就不必記錄太多的 block 號碼,讀寫起來也比較方便啊!

Tips 鳥哥 事實上,現在的磁碟容量都太大了!所以,大概大家都只會選擇 4K 的 block 大小吧!呵呵!
  • inode table (inode 表格)

再來討論一下 inode 這個玩意兒吧!如前所述 inode 的內容在記錄檔案的屬性以及該檔案實際資料是放置在哪幾號 block 內! 基本上,inode 記錄的檔案資料至少有底下這些:(註4)

  • 該檔案的存取模式(read/write/excute);
  • 該檔案的擁有者與群組(owner/group);
  • 該檔案的容量;
  • 該檔案建立或狀態改變的時間(ctime);
  • 最近一次的讀取時間(atime);
  • 最近修改的時間(mtime);
  • 定義檔案特性的旗標(flag),如 SetUID...;
  • 該檔案真正內容的指向 (pointer);

inode 的數量與大小也是在格式化時就已經固定了,除此之外 inode 還有些什麼特色呢?

  • 每個 inode 大小均固定為 128 bytes (新的 ext4 與 xfs 可設定到 256 bytes);
  • 每個檔案都僅會佔用一個 inode 而已;
  • 承上,因此檔案系統能夠建立的檔案數量與 inode 的數量有關;
  • 系統讀取檔案時需要先找到 inode,並分析 inode 所記錄的權限與使用者是否符合,若符合才能夠開始實際讀取 block 的內容。

我們約略來分析一下 EXT2 的 inode / block 與檔案大小的關係好了。inode 要記錄的資料非常多,但偏偏又只有 128bytes 而已, 而 inode 記錄一個 block 號碼要花掉 4byte ,假設我一個檔案有 400MB 且每個 block 為 4K 時, 那麼至少也要十萬筆 block 號碼的記錄呢!inode 哪有這麼多可記錄的資訊?為此我們的系統很聰明的將 inode 記錄 block 號碼的區域定義為12個直接,一個間接, 一個雙間接與一個三間接記錄區。這是啥?我們將 inode 的結構畫一下好了。

inode 結構示意圖
圖7.1.4、inode 結構示意圖

上圖最左邊為 inode 本身 (128 bytes),裡面有 12 個直接指向 block 號碼的對照,這 12 筆記錄就能夠直接取得 block 號碼啦! 至於所謂的間接就是再拿一個 block 來當作記錄 block 號碼的記錄區,如果檔案太大時, 就會使用間接的 block 來記錄號碼。如上圖 7.1.4 當中間接只是拿一個 block 來記錄額外的號碼而已。 同理,如果檔案持續長大,那麼就會利用所謂的雙間接,第一個 block 僅再指出下一個記錄號碼的 block 在哪裡, 實際記錄的在第二個 block 當中。依此類推,三間接就是利用第三層 block 來記錄號碼啦!

這樣子 inode 能夠指定多少個 block 呢?我們以較小的 1K block 來說明好了,可以指定的情況如下:

  • 12 個直接指向: 12*1K=12K
    由於是直接指向,所以總共可記錄 12 筆記錄,因此總額大小為如上所示;

  • 間接: 256*1K=256K
    每筆 block 號碼的記錄會花去 4bytes,因此 1K 的大小能夠記錄 256 筆記錄,因此一個間接可以記錄的檔案大小如上;

  • 雙間接: 256*256*1K=2562K
    第一層 block 會指定 256 個第二層,每個第二層可以指定 256 個號碼,因此總額大小如上;

  • 三間接: 256*256*256*1K=2563K
    第一層 block 會指定 256 個第二層,每個第二層可以指定 256 個第三層,每個第三層可以指定 256 個號碼,因此總額大小如上;

  • 總額:將直接、間接、雙間接、三間接加總,得到 12 + 256 + 256*256 + 256*256*256 (K) = 16GB

此時我們知道當檔案系統將 block 格式化為 1K 大小時,能夠容納的最大檔案為 16GB,比較一下檔案系統限制表的結果可發現是一致的!但這個方法不能用在 2K 及 4K block 大小的計算中, 因為大於 2K 的 block 將會受到 Ext2 檔案系統本身的限制,所以計算的結果會不太符合之故。

Tips 鳥哥 如果你的 Linux 依舊使用 Ext2/Ext3/Ext4 檔案系統的話,例如鳥哥之前的 CentOS 6.x 系統,那麼預設還是使用 Ext4 的檔案系統喔! Ext4 檔案系統的 inode 容量已經可以擴大到 256bytes 了,更大的 inode 容量,可以紀錄更多的檔案系統資訊,包括新的 ACL 以及 SELinux 類型等, 當然,可以紀錄的單一檔案容量達 16TB 且單一檔案系統總容量可達 1EB 哩!
  • Superblock (超級區塊)

Superblock 是記錄整個 filesystem 相關資訊的地方, 沒有 Superblock ,就沒有這個 filesystem 了。他記錄的資訊主要有:

  • block 與 inode 的總量;
  • 未使用與已使用的 inode / block 數量;
  • block 與 inode 的大小 (block 為 1, 2, 4K,inode 為 128bytes 或 256bytes);
  • filesystem 的掛載時間、最近一次寫入資料的時間、最近一次檢驗磁碟 (fsck) 的時間等檔案系統的相關資訊;
  • 一個 valid bit 數值,若此檔案系統已被掛載,則 valid bit 為 0 ,若未被掛載,則 valid bit 為 1 。

Superblock 是非常重要的,因為我們這個檔案系統的基本資訊都寫在這裡,因此,如果 superblock 死掉了, 你的檔案系統可能就需要花費很多時間去挽救啦!一般來說, superblock 的大小為 1024bytes。相關的 superblock 訊息我們等一下會以 dumpe2fs 指令來呼叫出來觀察喔!

此外,每個 block group 都可能含有 superblock 喔!但是我們也說一個檔案系統應該僅有一個 superblock 而已,那是怎麼回事啊? 事實上除了第一個 block group 內會含有 superblock 之外,後續的 block group 不一定含有 superblock , 而若含有 superblock 則該 superblock 主要是做為第一個 block group 內 superblock 的備份咯,這樣可以進行 superblock 的救援呢!

  • Filesystem Description (檔案系統描述說明)

這個區段可以描述每個 block group 的開始與結束的 block 號碼,以及說明每個區段 (superblock, bitmap, inodemap, data block) 分別介於哪一個 block 號碼之間。這部份也能夠用 dumpe2fs 來觀察的。

  • block bitmap (區塊對照表)

如果你想要新增檔案時總會用到 block 吧!那你要使用哪個 block 來記錄呢?當然是選擇『空的 block 』來記錄新檔案的資料囉。 那你怎麼知道哪個 block 是空的?這就得要透過 block bitmap 的輔助了。從 block bitmap 當中可以知道哪些 block 是空的,因此我們的系統就能夠很快速的找到可使用的空間來處置檔案囉。

同樣的,如果你刪除某些檔案時,那麼那些檔案原本佔用的 block 號碼就得要釋放出來, 此時在 block bitmap 當中相對應到該 block 號碼的標誌就得要修改成為『未使用中』囉!這就是 bitmap 的功能。

  • inode bitmap (inode 對照表)

這個其實與 block bitmap 是類似的功能,只是 block bitmap 記錄的是使用與未使用的 block 號碼, 至於 inode bitmap 則是記錄使用與未使用的 inode 號碼囉!

  • dumpe2fs: 查詢 Ext 家族 superblock 資訊的指令

瞭解了檔案系統的概念之後,再來當然是觀察這個檔案系統囉!剛剛談到的各部分資料都與 block 號碼有關! 每個區段與 superblock 的資訊都可以使用 dumpe2fs 這個指令來查詢的!不過很可惜的是,我們的 CentOS 7 現在是以 xfs 為預設檔案系統, 所以目前你的系統應該無法使用 dumpe2fs 去查詢任何檔案系統的。沒關係,鳥哥先找自己的一部機器來跟大家介紹, 你可以在後續的格式化內容講完之後,自己切出一個 ext4 的檔案系統去查詢看看即可。鳥哥這塊檔案系統是 1GB 的容量,使用預設方式來進行格式化的, 觀察的內容如下:

[root@study ~]# dumpe2fs [-bh] 裝置檔名
選項與參數:
-b :列出保留為壞軌的部分(一般用不到吧!?)
-h :僅列出 superblock 的資料,不會列出其他的區段內容!

範例:鳥哥的一塊 1GB ext4 檔案系統內容
[root@study ~]# blkid   <==這個指令可以叫出目前系統有被格式化的裝置
/dev/vda1: LABEL="myboot" UUID="ce4dbf1b-2b3d-4973-8234-73768e8fd659" TYPE="xfs"
/dev/vda2: LABEL="myroot" UUID="21ad8b9a-aaad-443c-b732-4e2522e95e23" TYPE="xfs"
/dev/vda3: UUID="12y99K-bv2A-y7RY-jhEW-rIWf-PcH5-SaiApN" TYPE="LVM2_member"
/dev/vda5: UUID="e20d65d9-20d4-472f-9f91-cdcfb30219d6" TYPE="ext4"  <==看到 ext4 了!

[root@study ~]# dumpe2fs /dev/vda5
dumpe2fs 1.42.9 (28-Dec-2013)
Filesystem volume name:   <none>           # 檔案系統的名稱(不一定會有)
Last mounted on:          <not available>  # 上一次掛載的目錄位置
Filesystem UUID:          e20d65d9-20d4-472f-9f91-cdcfb30219d6
Filesystem magic number:  0xEF53           # 上方的 UUID 為 Linux 對裝置的定義碼
Filesystem revision #:    1 (dynamic)      # 下方的 features 為檔案系統的特徵資料
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent 64bit 
 flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl   # 預設在掛載時會主動加上的掛載參數
Filesystem state:         clean            # 這塊檔案系統的狀態為何,clean 是沒問題
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              65536            # inode 的總數
Block count:              262144           # block 的總數
Reserved block count:     13107            # 保留的 block 總數
Free blocks:              249189           # 還有多少的 block 可用數量
Free inodes:              65525            # 還有多少的 inode 可用數量
First block:              0
Block size:               4096             # 單個 block 的容量大小
Fragment size:            4096
Group descriptor size:    64
....(中間省略)....
Inode size:               256              # inode 的容量大小!已經是 256 了喔!
....(中間省略)....
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      3c2568b4-1a7e-44cf-95a2-c8867fb19fbc
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             32M              # Journal 日誌式資料的可供紀錄總容量
Journal length:           8192
Journal sequence:         0x00000001
Journal start:            0

Group 0: (Blocks 0-32767)                  # 第一塊 block group 位置
  Checksum 0x13be, unused inodes 8181
  Primary superblock at 0, Group descriptors at 1-1   # 主要 superblock 的所在喔!
  Reserved GDT blocks at 2-128
  Block bitmap at 129 (+129), Inode bitmap at 145 (+145)
  Inode table at 161-672 (+161)                       # inode table 的所在喔!
  28521 free blocks, 8181 free inodes, 2 directories, 8181 unused inodes
  Free blocks: 142-144, 153-160, 4258-32767           # 底下兩行說明剩餘的容量有多少
  Free inodes: 12-8192
Group 1: (Blocks 32768-65535) [INODE_UNINIT]          # 後續為更多其他的 block group 喔!
....(底下省略)....
# 由於資料量非常的龐大,因此鳥哥將一些資訊省略輸出了!上表與你的螢幕會有點差異。
# 前半部在秀出 supberblock 的內容,包括標頭名稱(Label)以及inode/block的相關資訊
# 後面則是每個 block group 的個別資訊了!您可以看到各區段資料所在的號碼!
# 也就是說,基本上所有的資料還是與 block 的號碼有關就是了!很重要!

如上所示,利用 dumpe2fs 可以查詢到非常多的資訊,不過依內容主要可以區分為上半部是 superblock 內容, 下半部則是每個 block group 的資訊了。從上面的表格中我們可以觀察到鳥哥這個 /dev/vda5 規劃的 block 為 4K, 第一個 block 號碼為 0 號,且 block group 內的所有資訊都以 block 的號碼來表示的。 然後在 superblock 中還有談到目前這個檔案系統的可用 block 與 inode 數量喔!

至於 block group 的內容我們單純看 Group0 資訊好了。從上表中我們可以發現:

  • Group0 所佔用的 block 號碼由 0 到 32767 號,superblock 則在第 0 號的 block 區塊內!
  • 檔案系統描述說明在第 1 號 block 中;
  • block bitmap 與 inode bitmap 則在 129 及 145 的 block 號碼上。
  • 至於 inode table 分佈於 161-672 的 block 號碼中!
  • 由於 (1)一個 inode 佔用 256 bytes ,(2)總共有 672 - 161 + 1(161本身) = 512 個 block 花在 inode table 上, (3)每個 block 的大小為 4096 bytes(4K)。由這些數據可以算出 inode 的數量共有 512 * 4096 / 256 = 8192 個 inode 啦!
  • 這個 Group0 目前可用的 block 有 28521 個,可用的 inode 有 8181 個;
  • 剩餘的 inode 號碼為 12 號到 8192 號。

如果你對檔案系統的詳細資訊還有更多想要瞭解的話,那麼請參考本章最後一小節的介紹喔! 否則檔案系統看到這裡對於基礎認知您應該是已經相當足夠啦!底下則是要探討一下, 那麼這個檔案系統概念與實際的目錄樹應用有啥關連啊?

7.1.4 與目錄樹的關係

由前一小節的介紹我們知道在 Linux 系統下,每個檔案(不管是一般檔案還是目錄檔案)都會佔用一個 inode , 且可依據檔案內容的大小來分配多個 block 給該檔案使用。而由第五章的權限說明中我們知道目錄的內容在記錄檔名, 一般檔案才是實際記錄資料內容的地方。那麼目錄與檔案在檔案系統當中是如何記錄資料的呢?基本上可以這樣說:

  • 目錄

當我們在 Linux 下的檔案系統建立一個目錄時,檔案系統會分配一個 inode 與至少一塊 block 給該目錄。其中,inode 記錄該目錄的相關權限與屬性,並可記錄分配到的那塊 block 號碼; 而 block 則是記錄在這個目錄下的檔名與該檔名佔用的 inode 號碼資料。也就是說目錄所佔用的 block 內容在記錄如下的資訊:

目錄佔用的 block 記錄的資料示意圖
圖7.1.5、記載於目錄所屬的 block 內的檔名與 inode 號碼對應示意圖

如果想要實際觀察 root 家目錄內的檔案所佔用的 inode 號碼時,可以使用 ls -i 這個選項來處理:

[root@study ~]# ls -li
total 8
53735697 -rw-------. 1 root root 1816 May  4 17:57 anaconda-ks.cfg
53745858 -rw-r--r--. 1 root root 1864 May  4 18:01 initial-setup-ks.cfg

由於每個人所使用的電腦並不相同,系統安裝時選擇的項目與 partition 都不一樣,因此你的環境不可能與我的 inode 號碼一模一樣!上表的左邊所列出的 inode 僅是鳥哥的系統所顯示的結果而已!而由這個目錄的 block 結果我們現在就能夠知道, 當你使用『 ll / 』時,出現的目錄幾乎都是 1024 的倍數,為什麼呢?因為每個 block 的數量都是 1K, 2K, 4K 嘛! 看一下鳥哥的環境:

[root@study ~]# ll -d / /boot /usr/sbin /proc /sys
dr-xr-xr-x.  17 root root  4096 May  4 17:56 /         <== 1 個 4K block
dr-xr-xr-x.   4 root root  4096 May  4 17:59 /boot     <== 1 個 4K block
dr-xr-xr-x. 155 root root     0 Jun 15 15:43 /proc     <== 這兩個為記憶體內資料,不佔磁碟容量
dr-xr-xr-x.  13 root root     0 Jun 15 23:43 /sys
dr-xr-xr-x.   2 root root 16384 May  4 17:55 /usr/sbin <== 4 個 4K block

由於鳥哥的根目錄使用的 block 大小為 4K ,因此每個目錄幾乎都是 4K 的倍數。 其中由於 /usr/sbin 的內容比較複雜因此佔用了 4 個 block !至於奇怪的 /proc 我們在第五章就講過該目錄不佔磁碟容量, 所以當然耗用的 block 就是 0 囉!

Tips 鳥哥 由上面的結果我們知道目錄並不只會佔用一個 block 而已,也就是說: 在目錄底下的檔案數如果太多而導致一個 block 無法容納的下所有的檔名與 inode 對照表時,Linux 會給予該目錄多一個 block 來繼續記錄相關的資料;
  • 檔案:

當我們在 Linux 下的 ext2 建立一個一般檔案時, ext2 會分配一個 inode 與相對於該檔案大小的 block 數量給該檔案。例如:假設我的一個 block 為 4 Kbytes ,而我要建立一個 100 KBytes 的檔案,那麼 linux 將分配一個 inode 與 25 個 block 來儲存該檔案! 但同時請注意,由於 inode 僅有 12 個直接指向,因此還要多一個 block 來作為區塊號碼的記錄喔!

  • 目錄樹讀取:

好了,經過上面的說明你也應該要很清楚的知道 inode 本身並不記錄檔名,檔名的記錄是在目錄的 block 當中。 因此在第五章檔案與目錄的權限說明中, 我們才會提到『新增/刪除/更名檔名與目錄的 w 權限有關』的特色!那麼因為檔名是記錄在目錄的 block 當中, 因此當我們要讀取某個檔案時,就務必會經過目錄的 inode 與 block ,然後才能夠找到那個待讀取檔案的 inode 號碼, 最終才會讀到正確的檔案的 block 內的資料。

由於目錄樹是由根目錄開始讀起,因此系統透過掛載的資訊可以找到掛載點的 inode 號碼,此時就能夠得到根目錄的 inode 內容,並依據該 inode 讀取根目錄的 block 內的檔名資料,再一層一層的往下讀到正確的檔名。舉例來說,如果我想要讀取 /etc/passwd 這個檔案時,系統是如何讀取的呢?

[root@study ~]# ll -di / /etc /etc/passwd
     128 dr-xr-xr-x.  17 root root 4096 May  4 17:56 /
33595521 drwxr-xr-x. 131 root root 8192 Jun 17 00:20 /etc
36628004 -rw-r--r--.   1 root root 2092 Jun 17 00:20 /etc/passwd

在鳥哥的系統上面與 /etc/passwd 有關的目錄與檔案資料如上表所示,該檔案的讀取流程為(假設讀取者身份為 dmtsai 這個一般身份使用者):

  1. / 的 inode:
    透過掛載點的資訊找到 inode 號碼為 128 的根目錄 inode,且 inode 規範的權限讓我們可以讀取該 block 的內容(有 r 與 x) ;

  2. / 的 block:
    經過上個步驟取得 block 的號碼,並找到該內容有 etc/ 目錄的 inode 號碼 (33595521);

  3. etc/ 的 inode:
    讀取 33595521 號 inode 得知 dmtsai 具有 r 與 x 的權限,因此可以讀取 etc/ 的 block 內容;

  4. etc/ 的 block:
    經過上個步驟取得 block 號碼,並找到該內容有 passwd 檔案的 inode 號碼 (36628004);

  5. passwd 的 inode:
    讀取 36628004 號 inode 得知 dmtsai 具有 r 的權限,因此可以讀取 passwd 的 block 內容;

  6. passwd 的 block:
    最後將該 block 內容的資料讀出來。
  • filesystem 大小與磁碟讀取效能:

另外,關於檔案系統的使用效率上,當你的一個檔案系統規劃的很大時,例如 100GB 這麼大時, 由於磁碟上面的資料總是來來去去的,所以,整個檔案系統上面的檔案通常無法連續寫在一起(block 號碼不會連續的意思), 而是填入式的將資料填入沒有被使用的 block 當中。如果檔案寫入的 block 真的分的很散, 此時就會有所謂的檔案資料離散的問題發生了。

如前所述,雖然我們的 ext2 在 inode 處已經將該檔案所記錄的 block 號碼都記上了, 所以資料可以一次性讀取,但是如果檔案真的太過離散,確實還是會發生讀取效率低落的問題。 因為磁碟讀取頭還是得要在整個檔案系統中來來去去的頻繁讀取! 果真如此,那麼可以將整個 filesystem 內的資料全部複製出來,將該 filesystem 重新格式化, 再將資料給他複製回去即可解決這個問題。

此外,如果 filesystem 真的太大了,那麼當一個檔案分別記錄在這個檔案系統的最前面與最後面的 block 號碼中, 此時會造成磁碟的機械手臂移動幅度過大,也會造成資料讀取效能的低落。而且讀取頭在搜尋整個 filesystem 時, 也會花費比較多的時間去搜尋!因此, partition 的規劃並不是越大越好, 而是真的要針對您的主機用途來進行規劃才行!^_^

7.1.5 EXT2/EXT3/EXT4 檔案的存取與日誌式檔案系統的功能

上一小節談到的僅是讀取而已,那麼如果是新建一個檔案或目錄時,我們的檔案系統是如何處理的呢? 這個時候就得要 block bitmap 及 inode bitmap 的幫忙了!假設我們想要新增一個檔案,此時檔案系統的行為是:

  1. 先確定使用者對於欲新增檔案的目錄是否具有 w 與 x 的權限,若有的話才能新增;
  2. 根據 inode bitmap 找到沒有使用的 inode 號碼,並將新檔案的權限/屬性寫入;
  3. 根據 block bitmap 找到沒有使用中的 block 號碼,並將實際的資料寫入 block 中,且更新 inode 的 block 指向資料;
  4. 將剛剛寫入的 inode 與 block 資料同步更新 inode bitmap 與 block bitmap,並更新 superblock 的內容。

一般來說,我們將 inode table 與 data block 稱為資料存放區域,至於其他例如 superblock、 block bitmap 與 inode bitmap 等區段就被稱為 metadata (中介資料) 囉,因為 superblock, inode bitmap 及 block bitmap 的資料是經常變動的,每次新增、移除、編輯時都可能會影響到這三個部分的資料,因此才被稱為中介資料的啦。

  • 資料的不一致 (Inconsistent) 狀態

在一般正常的情況下,上述的新增動作當然可以順利的完成。但是如果有個萬一怎麼辦? 例如你的檔案在寫入檔案系統時,因為不知名原因導致系統中斷(例如突然的停電啊、 系統核心發生錯誤啊~等等的怪事發生時),所以寫入的資料僅有 inode table 及 data block 而已, 最後一個同步更新中介資料的步驟並沒有做完,此時就會發生 metadata 的內容與實際資料存放區產生不一致 (Inconsistent) 的情況了。

既然有不一致當然就得要克服!在早期的 Ext2 檔案系統中,如果發生這個問題, 那麼系統在重新開機的時候,就會藉由 Superblock 當中記錄的 valid bit (是否有掛載) 與 filesystem state (clean 與否) 等狀態來判斷是否強制進行資料一致性的檢查!若有需要檢查時則以 e2fsck 這支程式來進行的。

不過,這樣的檢查真的是很費時~因為要針對 metadata 區域與實際資料存放區來進行比對, 呵呵~得要搜尋整個 filesystem 呢~如果你的檔案系統有 100GB 以上,而且裡面的檔案數量又多時, 哇!系統真忙碌~而且在對 Internet 提供服務的伺服器主機上面, 這樣的檢查真的會造成主機復原時間的拉長~真是麻煩~這也就造成後來所謂日誌式檔案系統的興起了。

  • 日誌式檔案系統 (Journaling filesystem)

為了避免上述提到的檔案系統不一致的情況發生,因此我們的前輩們想到一個方式, 如果在我們的 filesystem 當中規劃出一個區塊,該區塊專門在記錄寫入或修訂檔案時的步驟, 那不就可以簡化一致性檢查的步驟了?也就是說:

  1. 預備:當系統要寫入一個檔案時,會先在日誌記錄區塊中紀錄某個檔案準備要寫入的資訊;
  2. 實際寫入:開始寫入檔案的權限與資料;開始更新 metadata 的資料;
  3. 結束:完成資料與 metadata 的更新後,在日誌記錄區塊當中完成該檔案的紀錄。

在這樣的程序當中,萬一資料的紀錄過程當中發生了問題,那麼我們的系統只要去檢查日誌記錄區塊, 就可以知道哪個檔案發生了問題,針對該問題來做一致性的檢查即可,而不必針對整塊 filesystem 去檢查, 這樣就可以達到快速修復 filesystem 的能力了!這就是日誌式檔案最基礎的功能囉~

那麼我們的 ext2 可達到這樣的功能嗎?當然可以啊! 就透過 ext3/ext4 即可! ext3/ext4 是 ext2 的升級版本,並且可向下相容 ext2 版本呢! 所以囉,目前我們才建議大家,可以直接使用 ext4 這個 filesystem 啊! 如果你還記得 dumpe2fs 輸出的訊息,可以發現 superblock 裡面含有底下這樣的資訊:

Journal inode:            8
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             32M
Journal length:           8192
Journal sequence:         0x00000001

看到了吧!透過 inode 8 號記錄 journal 區塊的 block 指向,而且具有 32MB 的容量在處理日誌呢! 這樣對於所謂的日誌式檔案系統有沒有比較有概念一點呢?^_^。

7.1.6 Linux 檔案系統的運作

我們現在知道了目錄樹與檔案系統的關係了,但是由第零章的內容我們也知道, 所有的資料都得要載入到記憶體後 CPU 才能夠對該資料進行處理。想一想,如果你常常編輯一個好大的檔案, 在編輯的過程中又頻繁的要系統來寫入到磁碟中,由於磁碟寫入的速度要比記憶體慢很多, 因此你會常常耗在等待磁碟的寫入/讀取上。真沒效率!

為了解決這個效率的問題,因此我們的 Linux 使用的方式是透過一個稱為非同步處理 (asynchronously) 的方式。所謂的非同步處理是這樣的:

當系統載入一個檔案到記憶體後,如果該檔案沒有被更動過,則在記憶體區段的檔案資料會被設定為乾淨(clean)的。 但如果記憶體中的檔案資料被更改過了(例如你用 nano 去編輯過這個檔案),此時該記憶體中的資料會被設定為髒的 (Dirty)。此時所有的動作都還在記憶體中執行,並沒有寫入到磁碟中! 系統會不定時的將記憶體中設定為『Dirty』的資料寫回磁碟,以保持磁碟與記憶體資料的一致性。 你也可以利用第四章談到的 sync指令來手動強迫寫入磁碟。

我們知道記憶體的速度要比磁碟快的多,因此如果能夠將常用的檔案放置到記憶體當中,這不就會增加系統性能嗎? 沒錯!是有這樣的想法!因此我們 Linux 系統上面檔案系統與記憶體有非常大的關係喔:

  • 系統會將常用的檔案資料放置到主記憶體的緩衝區,以加速檔案系統的讀/寫;
  • 承上,因此 Linux 的實體記憶體最後都會被用光!這是正常的情況!可加速系統效能;
  • 你可以手動使用 sync 來強迫記憶體中設定為 Dirty 的檔案回寫到磁碟中;
  • 若正常關機時,關機指令會主動呼叫 sync 來將記憶體的資料回寫入磁碟內;
  • 但若不正常關機(如跳電、當機或其他不明原因),由於資料尚未回寫到磁碟內, 因此重新開機後可能會花很多時間在進行磁碟檢驗,甚至可能導致檔案系統的損毀(非磁碟損毀)。

7.1.7 掛載點的意義 (mount point)

每個 filesystem 都有獨立的 inode / block / superblock 等資訊,這個檔案系統要能夠連結到目錄樹才能被我們使用。 將檔案系統與目錄樹結合的動作我們稱為『掛載』。 關於掛載的一些特性我們在第二章稍微提過, 重點是:掛載點一定是目錄,該目錄為進入該檔案系統的入口。 因此並不是你有任何檔案系統都能使用,必須要『掛載』到目錄樹的某個目錄後,才能夠使用該檔案系統的。

舉例來說,如果你是依據鳥哥的方法安裝你的 CentOS 7.x 的話, 那麼應該會有三個掛載點才是,分別是 /, /boot, /home 三個 (鳥哥的系統上對應的裝置檔名為 LVM, LVM, /dev/vda2)。 那如果觀察這三個目錄的 inode 號碼時,我們可以發現如下的情況:

[root@study ~]# ls -lid / /boot /home
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /
128 dr-xr-xr-x.  4 root root 4096 May  4 17:59 /boot
128 drwxr-xr-x.  5 root root   41 Jun 17 00:20 /home

看到了吧!由於 XFS filesystem 最頂層的目錄之 inode 一般為 128 號,因此可以發現 /, /boot, /home 為三個不同的 filesystem 囉! (因為每一行的檔案屬性並不相同,且三個目錄的掛載點也均不相同之故。) 我們在第六章一開始的路徑中曾經提到根目錄下的 . 與 .. 是相同的東西, 因為權限是一模一樣嘛!如果使用檔案系統的觀點來看,同一個 filesystem 的某個 inode 只會對應到一個檔案內容而已(因為一個檔案佔用一個 inode 之故), 因此我們可以透過判斷 inode 號碼來確認不同檔名是否為相同的檔案喔!所以可以這樣看:

[root@study ~]# ls -ild /  /.  /..
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /.
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /..

上面的資訊中由於掛載點均為 / ,因此三個檔案 (/, /., /..) 均在同一個 filesystem 內,而這三個檔案的 inode 號碼均為 128 號,因此這三個檔名都指向同一個 inode 號碼,當然這三個檔案的內容也就完全一模一樣了! 也就是說,根目錄的上層 (/..) 就是他自己!這麼說,看的懂了嗎? ^_^

7.1.8 其他 Linux 支援的檔案系統與 VFS

雖然 Linux 的標準檔案系統是 ext2 ,且還有增加了日誌功能的 ext3/ext4 ,事實上,Linux 還有支援很多檔案系統格式的, 尤其是最近這幾年推出了好幾種速度很快的日誌式檔案系統,包括 SGI 的 XFS 檔案系統, 可以適用更小型檔案的 Reiserfs 檔案系統,以及 Windows 的 FAT 檔案系統等等, 都能夠被 Linux 所支援喔!常見的支援檔案系統有:

  • 傳統檔案系統:ext2 / minix / MS-DOS / FAT (用 vfat 模組) / iso9660 (光碟)等等;
  • 日誌式檔案系統: ext3 /ext4 / ReiserFS / Windows' NTFS / IBM's JFS / SGI's XFS / ZFS
  • 網路檔案系統: NFS / SMBFS

想要知道你的 Linux 支援的檔案系統有哪些,可以察看底下這個目錄:

[root@study ~]# ls -l /lib/modules/$(uname -r)/kernel/fs

系統目前已載入到記憶體中支援的檔案系統則有:

[root@study ~]# cat /proc/filesystems
  • Linux VFS (Virtual Filesystem Switch)

瞭解了我們使用的檔案系統之後,再來則是要提到,那麼 Linux 的核心又是如何管理這些認識的檔案系統呢? 其實,整個 Linux 的系統都是透過一個名為 Virtual Filesystem Switch 的核心功能去讀取 filesystem 的。 也就是說,整個 Linux 認識的 filesystem 其實都是 VFS 在進行管理,我們使用者並不需要知道每個 partition 上頭的 filesystem 是什麼~ VFS 會主動的幫我們做好讀取的動作呢~

假設你的 / 使用的是 /dev/hda1 ,用 ext3 ,而 /home 使用 /dev/hda2 ,用 reiserfs , 那麼你取用 /home/dmtsai/.bashrc 時,有特別指定要用的什麼檔案系統的模組來讀取嗎? 應該是沒有吧!這個就是 VFS 的功能啦!透過這個 VFS 的功能來管理所有的 filesystem, 省去我們需要自行設定讀取檔案系統的定義啊~方便很多!整個 VFS 可以約略用下圖來說明:

VFS 檔案系統的示意圖
圖7.1.6、VFS 檔案系統的示意圖

老實說,檔案系統真的不好懂! 如果你想要對檔案系統有更深入的瞭解,文末的相關連結(註5)務必要參考參考才好喔!

7.1.9 XFS 檔案系統簡介

CentOS 7 開始,預設的檔案系統已經由原本的 EXT4 變成了 XFS 檔案系統了!為啥 CentOS 要捨棄對 Linux 支援度最完整的 EXT 家族而改用 XFS 呢? 這是有一些原因存在的。

  • EXT 家族當前較傷腦筋的地方:支援度最廣,但格式化超慢!

Ext 檔案系統家族對於檔案格式化的處理方面,採用的是預先規劃出所有的 inode/block/meta data 等資料,未來系統可以直接取用, 不需要再進行動態配置的作法。這個作法在早期磁碟容量還不大的時候還算 OK 沒啥問題,但時至今日,磁碟容量越來越大,連傳統的 MBR 都已經被 GPT 所取代,連我們這些老人家以前聽到的超大 TB 容量也已經不夠看了!現在都已經說到 PB 或 EB 以上容量了呢!那妳可以想像得到,當你的 TB 以上等級的傳統 ext 家族檔案系統在格式化的時候,光是系統要預先分配 inode 與 block 就消耗你好多好多的人類時間了...

Tips 鳥哥 之前格式化過一個 70 TB 以上的磁碟陣列成為 ext4 檔案系統,按下格式化,去喝了咖啡、吃了便當才回來看做完了沒有... 所以,後來立刻改成 xfs 檔案系統了。

另外,由於虛擬化的應用越來越廣泛,而作為虛擬化磁碟來源的巨型檔案 (單一檔案好幾個 GB 以上!) 也就越來越常見了。 這種巨型檔案在處理上需要考慮到效能問題,否則虛擬磁碟的效率就會不太好看。因此,從 CentOS 7.x 開始, 檔案系統已經由預設的 Ext4 變成了 xfs 這一個較適合高容量磁碟與巨型檔案效能較佳的檔案系統了。

Tips 鳥哥 其實鳥哥有幾組虛擬電腦教室伺服器系統,裡面跑的確實是 EXT4 檔案系統,老實說,並不覺得比 xfs 慢!所以,對鳥哥來說, 效能並不是主要改變檔案系統的考量!對於檔案系統的復原速度、建置速度,可能才是鳥哥改換成 xfs 的思考點。
  • XFS 檔案系統的配置 (註6)

基本上 xfs 就是一個日誌式檔案系統,而 CentOS 7.x 拿它當預設的檔案系統,自然就是因為最早之前,這個 xfs 就是被開發來用於高容量磁碟以及高效能檔案系統之用, 因此,相當適合現在的系統環境。此外,幾乎所有 Ext4 檔案系統有的功能, xfs 都可以具備!也因此在本小節前幾部份談到檔案系統時, 其實大部份的操作依舊是在 xfs 檔案系統環境下介紹給各位的哩!

xfs 檔案系統在資料的分佈上,主要規劃為三個部份,一個資料區 (data section)、一個檔案系統活動登錄區 (log section)以及一個即時運作區 (realtime section)。 這三個區域的資料內容如下:

  • 資料區 (data section)

基本上,資料區就跟我們之前談到的 ext 家族一樣,包括 inode/data block/superblock 等資料,都放置在這個區塊。 這個資料區與 ext 家族的 block group 類似,也是分為多個儲存區群組 (allocation groups) 來分別放置檔案系統所需要的資料。 每個儲存區群組都包含了 (1)整個檔案系統的 superblock、 (2)剩餘空間的管理機制、 (3)inode的分配與追蹤。此外,inode與 block 都是系統需要用到時, 這才動態配置產生,所以格式化動作超級快!

另外,與 ext 家族不同的是, xfs 的 block 與 inode 有多種不同的容量可供設定,block 容量可由 512bytes ~ 64K 調配,不過,Linux 的環境下, 由於記憶體控制的關係 (分頁檔 pagesize 的容量之故),因此最高可以使用的 block 大小為 4K 而已!(鳥哥嘗試格式化 block 成為 16K 是沒問題的,不過,Linux 核心不給掛載! 所以格式化完成後也無法使用啦!) 至於 inode 容量可由 256bytes 到 2M 這麼大!不過,大概還是保留 256bytes 的預設值就很夠用了!

Tips 鳥哥 總之, xfs 的這個資料區的儲存區群組 (allocation groups, AG),你就將它想成是 ext 家族的 block 群組 (block groups) 就對了!本小節之前講的都可以在這個區塊內使用。 只是 inode 與 block 是動態產生,並非一開始於格式化就完成配置的。
  • 檔案系統活動登錄區 (log section)

在登錄區這個區域主要被用來紀錄檔案系統的變化,其實有點像是日誌區啦!檔案的變化會在這裡紀錄下來,直到該變化完整的寫入到資料區後, 該筆紀錄才會被終結。如果檔案系統因為某些緣故 (例如最常見的停電) 而損毀時,系統會拿這個登錄區塊來進行檢驗,看看系統掛掉之前, 檔案系統正在運作些啥動作,藉以快速的修復檔案系統。

因為系統所有動作的時候都會在這個區塊做個紀錄,因此這個區塊的磁碟活動是相當頻繁的!xfs 設計有點有趣,在這個區域中, 妳可以指定外部的磁碟來作為 xfs 檔案系統的日誌區塊喔!例如,妳可以將 SSD 磁碟作為 xfs 的登錄區,這樣當系統需要進行任何活動時, 就可以更快速的進行工作!相當有趣!

  • 即時運作區 (realtime section)

當有檔案要被建立時,xfs 會在這個區段裡面找一個到數個的 extent 區塊,將檔案放置在這個區塊內,等到分配完畢後,再寫入到 data section 的 inode 與 block 去! 這個 extent 區塊的大小得要在格式化的時候就先指定,最小值是 4K 最大可到 1G。一般非磁碟陣列的磁碟預設為 64K 容量,而具有類似磁碟陣列的 stripe 情況下,則建議 extent 設定為與 stripe 一樣大較佳。這個 extent 最好不要亂動,因為可能會影響到實體磁碟的效能喔。

  • XFS 檔案系統的描述資料觀察

剛剛講了這麼多,完全無法理會耶~有沒有像 EXT 家族的 dumpe2fs 去觀察 superblock 內容的相關指令可以查閱呢?有啦!可以使用 xfs_info 去觀察的! 詳細的指令作法可以參考如下:

[root@study ~]# xfs_info 掛載點|裝置檔名

範例一:找出系統 /boot 這個掛載點底下的檔案系統的 superblock 紀錄
[root@study ~]# df -T /boot
Filesystem     Type 1K-blocks   Used Available Use% Mounted on
/dev/vda2      xfs    1038336 133704    904632  13% /boot
# 沒錯!可以看得出來是 xfs 檔案系統的!來觀察一下內容吧!

[root@study ~]# xfs_info /dev/vda2
1  meta-data=/dev/vda2         isize=256    agcount=4, agsize=65536 blks
2           =                  sectsz=512   attr=2, projid32bit=1
3           =                  crc=0        finobt=0
4  data     =                  bsize=4096   blocks=262144, imaxpct=25
5           =                  sunit=0      swidth=0 blks
6  naming   =version 2         bsize=4096   ascii-ci=0 ftype=0
7  log      =internal          bsize=4096   blocks=2560, version=2
8           =                  sectsz=512   sunit=0 blks, lazy-count=1
9  realtime =none              extsz=4096   blocks=0, rtextents=0

上面的輸出訊息可以這樣解釋:

  • 第 1 行裡面的 isize 指的是 inode 的容量,每個有 256bytes 這麼大。至於 agcount 則是前面談到的儲存區群組 (allocation group) 的個數,共有 4 個, agsize 則是指每個儲存區群組具有 65536 個 block 。配合第 4 行的 block 設定為 4K,因此整個檔案系統的容量應該就是 4*65536*4K 這麼大!
  • 第 2 行裡面 sectsz 指的是邏輯磁區 (sector) 的容量設定為 512bytes 這麼大的意思。
  • 第 4 行裡面的 bsize 指的是 block 的容量,每個 block 為 4K 的意思,共有 262144 個 block 在這個檔案系統內。
  • 第 5 行裡面的 sunit 與 swidth 與磁碟陣列的 stripe 相關性較高。這部份我們底下格式化的時候會舉一個例子來說明。
  • 第 7 行裡面的 internal 指的是這個登錄區的位置在檔案系統內,而不是外部設備的意思。且佔用了 4K * 2560 個 block,總共約 10M 的容量。
  • 第 9 行裡面的 realtime 區域,裡面的 extent 容量為 4K。不過目前沒有使用。

由於我們並沒有使用磁碟陣列,因此上頭這個裝置裡頭的 sunit 與 extent 就沒有額外的指定特別的值。根據 xfs(5) 的說明,這兩個值會影響到你的檔案系統性能, 所以格式化的時候要特別留意喔!上面的說明大致上看看即可,比較重要的部份已經用特殊字體圈起來,你可以瞧一瞧先!

7.2 檔案系統的簡單操作

稍微瞭解了檔案系統後,再來我們得要知道如何查詢整體檔案系統的總容量與每個目錄所佔用的容量囉! 此外,前兩章談到的檔案類型中尚未講的很清楚的連結檔 (Link file) 也會在這一小節當中介紹的。

7.2.1 磁碟與目錄的容量

現在我們知道磁碟的整體資料是在 superblock 區塊中,但是每個各別檔案的容量則在 inode 當中記載的。 那在文字介面底下該如何叫出這幾個資料呢?底下就讓我們來談一談這兩個指令:

  • df:列出檔案系統的整體磁碟使用量;
  • du:評估檔案系統的磁碟使用量(常用在推估目錄所佔容量)
  • df
[root@study ~]# df [-ahikHTm] [目錄或檔名]
選項與參數:
-a  :列出所有的檔案系統,包括系統特有的 /proc 等檔案系統;
-k  :以 KBytes 的容量顯示各檔案系統;
-m  :以 MBytes 的容量顯示各檔案系統;
-h  :以人們較易閱讀的 GBytes, MBytes, KBytes 等格式自行顯示;
-H  :以 M=1000K 取代 M=1024K 的進位方式;
-T  :連同該 partition 的 filesystem 名稱 (例如 xfs) 也列出;
-i  :不用磁碟容量,而以 inode 的數量來顯示

範例一:將系統內所有的 filesystem 列出來!
[root@study ~]# df
Filesystem              1K-blocks    Used Available Use% Mounted on
/dev/mapper/centos-root  10475520 3409408   7066112  33% /
devtmpfs                   627700       0    627700   0% /dev
tmpfs                      637568      80    637488   1% /dev/shm
tmpfs                      637568   24684    612884   4% /run
tmpfs                      637568       0    637568   0% /sys/fs/cgroup
/dev/mapper/centos-home   5232640   67720   5164920   2% /home
/dev/vda2                 1038336  133704    904632  13% /boot
# 在 Linux 底下如果 df 沒有加任何選項,那麼預設會將系統內所有的 
# (不含特殊記憶體內的檔案系統與 swap) 都以 1 Kbytes 的容量來列出來!
# 至於那個 /dev/shm 是與記憶體有關的掛載,先不要理他!

先來說明一下範例一所輸出的結果訊息為:

  • Filesystem:代表該檔案系統是在哪個 partition ,所以列出裝置名稱;
  • 1k-blocks:說明底下的數字單位是 1KB 呦!可利用 -h 或 -m 來改變容量;
  • Used:顧名思義,就是使用掉的磁碟空間啦!
  • Available:也就是剩下的磁碟空間大小;
  • Use%:就是磁碟的使用率啦!如果使用率高達 90% 以上時, 最好需要注意一下了,免得容量不足造成系統問題喔!(例如最容易被灌爆的 /var/spool/mail 這個放置郵件的磁碟)
  • Mounted on:就是磁碟掛載的目錄所在啦!(掛載點啦!)
範例二:將容量結果以易讀的容量格式顯示出來
[root@study ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   10G  3.3G  6.8G  33% /
devtmpfs                 613M     0  613M   0% /dev
tmpfs                    623M   80K  623M   1% /dev/shm
tmpfs                    623M   25M  599M   4% /run
tmpfs                    623M     0  623M   0% /sys/fs/cgroup
/dev/mapper/centos-home  5.0G   67M  5.0G   2% /home
/dev/vda2               1014M  131M  884M  13% /boot
# 不同於範例一,這裡會以 G/M 等容量格式顯示出來,比較容易看啦!

範例三:將系統內的所有特殊檔案格式及名稱都列出來
[root@study ~]# df -aT
Filesystem              Type        1K-blocks    Used Available Use% Mounted on
rootfs                  rootfs       10475520 3409368   7066152  33% /
proc                    proc                0       0         0    - /proc
sysfs                   sysfs               0       0         0    - /sys
devtmpfs                devtmpfs       627700       0    627700   0% /dev
securityfs              securityfs          0       0         0    - /sys/kernel/security
tmpfs                   tmpfs          637568      80    637488   1% /dev/shm
devpts                  devpts              0       0         0    - /dev/pts
tmpfs                   tmpfs          637568   24684    612884   4% /run
tmpfs                   tmpfs          637568       0    637568   0% /sys/fs/cgroup
.....(中間省略).....
/dev/mapper/centos-root xfs          10475520 3409368   7066152  33% /
selinuxfs               selinuxfs           0       0         0    - /sys/fs/selinux
.....(中間省略).....
/dev/mapper/centos-home xfs           5232640   67720   5164920   2% /home
/dev/vda2               xfs           1038336  133704    904632  13% /boot
binfmt_misc             binfmt_misc         0       0         0    - /proc/sys/fs/binfmt_misc
# 系統裡面其實還有很多特殊的檔案系統存在的。那些比較特殊的檔案系統幾乎
# 都是在記憶體當中,例如 /proc 這個掛載點。因此,這些特殊的檔案系統
# 都不會佔據磁碟空間喔! ^_^

範例四:將 /etc 底下的可用的磁碟容量以易讀的容量格式顯示
[root@study ~]# df -h /etc
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   10G  3.3G  6.8G  33% /
# 這個範例比較有趣一點啦,在 df 後面加上目錄或者是檔案時, df
# 會自動的分析該目錄或檔案所在的 partition ,並將該 partition 的容量顯示出來,
# 所以,您就可以知道某個目錄底下還有多少容量可以使用了! ^_^

範例五:將目前各個 partition 當中可用的 inode 數量列出
[root@study ~]# df -ih 
Filesystem              Inodes IUsed IFree IUse% Mounted on
/dev/mapper/centos-root    10M  108K  9.9M    2% /
devtmpfs                  154K   397  153K    1% /dev
tmpfs                     156K     5  156K    1% /dev/shm
tmpfs                     156K   497  156K    1% /run
tmpfs                     156K    13  156K    1% /sys/fs/cgroup
# 這個範例則主要列出可用的 inode 剩餘量與總容量。分析一下與範例一的關係,
# 你可以清楚的發現到,通常 inode 的數量剩餘都比 block 還要多呢

由於 df 主要讀取的資料幾乎都是針對一整個檔案系統,因此讀取的範圍主要是在 Superblock 內的資訊, 所以這個指令顯示結果的速度非常的快速!在顯示的結果中你需要特別留意的是那個根目錄的剩餘容量! 因為我們所有的資料都是由根目錄衍生出來的,因此當根目錄的剩餘容量剩下 0 時,那你的 Linux 可能就問題很大了。

Tips 鳥哥 說個陳年老笑話!鳥哥還在唸書時,別的研究室有個管理 Sun 工作站的研究生發現, 他的磁碟明明還有好幾 GB ,但是就是沒有辦法將光碟內幾 MB 的資料 copy 進去, 他就去跟老闆講說機器壞了!嘿!明明才來維護過幾天而已為何會壞了! 結果他老闆就將維護商叫來罵了 2 小時左右吧!

後來,維護商發現原來磁碟的『總空間』還有很多, 只是某個分割槽填滿了,偏偏該研究生就是要將資料 copy 去那個分割槽!呵呵! 後來那個研究生就被命令『再也不許碰 Sun 主機』了~~

另外需要注意的是,如果使用 -a 這個參數時,系統會出現 /proc 這個掛載點,但是裡面的東西都是 0 ,不要緊張! /proc 的東西都是 Linux 系統所需要載入的系統資料,而且是掛載在『記憶體當中』的, 所以當然沒有佔任何的磁碟空間囉!

至於那個 /dev/shm/ 目錄,其實是利用記憶體虛擬出來的磁碟空間,通常是總實體記憶體的一半! 由於是透過記憶體模擬出來的磁碟,因此你在這個目錄底下建立任何資料檔案時,存取速度是非常快速的!(在記憶體內工作) 不過,也由於他是記憶體模擬出來的,因此這個檔案系統的大小在每部主機上都不一樣,而且建立的東西在下次開機時就消失了! 因為是在記憶體中嘛!

  • du
[root@study ~]# du [-ahskm] 檔案或目錄名稱
選項與參數:
-a  :列出所有的檔案與目錄容量,因為預設僅統計目錄底下的檔案量而已。
-h  :以人們較易讀的容量格式 (G/M) 顯示;
-s  :列出總量而已,而不列出每個各別的目錄佔用容量;
-S  :不包括子目錄下的總計,與 -s 有點差別。
-k  :以 KBytes 列出容量顯示;
-m  :以 MBytes 列出容量顯示;

範例一:列出目前目錄下的所有檔案容量
[root@study ~]# du
4       ./.cache/dconf  <==每個目錄都會列出來
4       ./.cache/abrt
8       ./.cache
....(中間省略)....
0       ./test4
4       ./.ssh          <==包括隱藏檔的目錄
76      .               <==這個目錄(.)所佔用的總量
# 直接輸入 du 沒有加任何選項時,則 du 會分析『目前所在目錄』
# 的檔案與目錄所佔用的磁碟空間。但是,實際顯示時,僅會顯示目錄容量(不含檔案),
# 因此 . 目錄有很多檔案沒有被列出來,所以全部的目錄相加不會等於 . 的容量喔!
# 此外,輸出的數值資料為 1K 大小的容量單位。

範例二:同範例一,但是將檔案的容量也列出來
[root@study ~]# du -a
4       ./.bash_logout         <==有檔案的列表了
4       ./.bash_profile
4       ./.bashrc
....(中間省略)....
4       ./.ssh/known_hosts
4       ./.ssh
76      .

範例三:檢查根目錄底下每個目錄所佔用的容量
[root@study ~]# du -sm /*
0       /bin
99      /boot
....(中間省略)....
du: cannot access ‘/proc/17772/task/17772/fd/4’: No such file or directory
du: cannot access ‘/proc/17772/fdinfo/4’: No such file or directory
0       /proc      <==不會佔用硬碟空間!
1       /root
25      /run
....(中間省略)....
3126    /usr       <==系統初期最大就是他了啦!
117     /var
# 這是個很常被使用的功能~利用萬用字元 * 來代表每個目錄,如果想要檢查某個目錄下,
# 哪個次目錄佔用最大的容量,可以用這個方法找出來。值得注意的是,如果剛剛安裝好 Linux 時,
# 那麼整個系統容量最大的應該是 /usr 。而 /proc 雖然有列出容量,但是那個容量是在記憶體中,
# 不佔磁碟空間。至於 /proc 裡頭會列出一堆『No such file or directory』 的錯誤,
# 別擔心!因為是記憶體內的程序,程序執行結束就會消失,因此會有些目錄找不到,是正確的!

與 df 不一樣的是,du 這個指令其實會直接到檔案系統內去搜尋所有的檔案資料, 所以上述第三個範例指令的運作會執行一小段時間!此外,在預設的情況下,容量的輸出是以 KB 來設計的, 如果你想要知道目錄佔了多少 MB ,那麼就使用 -m 這個參數即可囉!而, 如果你只想要知道該目錄佔了多少容量的話,使用 -s 就可以啦!

至於 -S 這個選項部分,由於 du 預設會將所有檔案的大小均列出,因此假設你在 /etc 底下使用 du 時, 所有的檔案大小,包括 /etc 底下的次目錄容量也會被計算一次。然後最終的容量 (/etc) 也會加總一次, 因此很多朋友都會誤會 du 分析的結果不太對勁。所以囉,如果想要列出某目錄下的全部資料, 或許也可以加上 -S 的選項,減少次目錄的加總喔!

7.2.2 實體連結與符號連結: ln

關於連結(link)資料我們第五章的Linux檔案屬性Linux檔案種類與副檔名當中提過一些資訊, 不過當時由於尚未講到檔案系統,因此無法較完整的介紹連結檔啦。不過在上一小節談完了檔案系統後, 我們可以來瞭解一下連結檔這玩意兒了。

在 Linux 底下的連結檔有兩種,一種是類似 Windows 的捷徑功能的檔案,可以讓你快速的連結到目標檔案(或目錄); 另一種則是透過檔案系統的 inode 連結來產生新檔名,而不是產生新檔案!這種稱為實體連結 (hard link)。 這兩種玩意兒是完全不一樣的東西呢!現在就分別來談談。

  • Hard Link (實體連結, 硬式連結或實際連結)

在前一小節當中,我們知道幾件重要的資訊,包括:

  • 每個檔案都會佔用一個 inode ,檔案內容由 inode 的記錄來指向;
  • 想要讀取該檔案,必須要經過目錄記錄的檔名來指向到正確的 inode 號碼才能讀取。

也就是說,其實檔名只與目錄有關,但是檔案內容則與 inode 有關。那麼想一想, 有沒有可能有多個檔名對應到同一個 inode 號碼呢?有的!那就是 hard link 的由來。 所以簡單的說:hard link 只是在某個目錄下新增一筆檔名連結到某 inode 號碼的關連記錄而已。

舉個例子來說,假設我系統有個 /root/crontab 他是 /etc/crontab 的實體連結,也就是說這兩個檔名連結到同一個 inode , 自然這兩個檔名的所有相關資訊都會一模一樣(除了檔名之外)。實際的情況可以如下所示:

[root@study ~]# ll -i /etc/crontab
34474855 -rw-r--r--. 1 root root 451 Jun 10  2014 /etc/crontab

[root@study ~]# ln /etc/crontab .   <==建立實體連結的指令
[root@study ~]# ll -i /etc/crontab crontab
34474855 -rw-r--r--. 2 root root 451 Jun 10  2014 crontab
34474855 -rw-r--r--. 2 root root 451 Jun 10  2014 /etc/crontab

你可以發現兩個檔名都連結到 34474855 這個 inode 號碼,所以您瞧瞧,是否檔案的權限/屬性完全一樣呢? 因為這兩個『檔名』其實是一模一樣的『檔案』啦!而且你也會發現第二個欄位由原本的 1 變成 2 了! 那個欄位稱為『連結』,這個欄位的意義為:『有多少個檔名連結到這個 inode 號碼』的意思。 如果將讀取到正確資料的方式畫成示意圖,就類似如下畫面:

實體連結的檔案讀取示意圖
圖7.2.1、實體連結的檔案讀取示意圖

上圖的意思是,你可以透過 1 或 2 的目錄之 inode 指定的 block 找到兩個不同的檔名,而不管使用哪個檔名均可以指到 real 那個 inode 去讀取到最終資料!那這樣有什麼好處呢?最大的好處就是『安全』!如同上圖中, 如果你將任何一個『檔名』刪除,其實 inode 與 block 都還是存在的! 此時你可以透過另一個『檔名』來讀取到正確的檔案資料喔!此外,不論你使用哪個『檔名』來編輯, 最終的結果都會寫入到相同的 inode 與 block 中,因此均能進行資料的修改哩!

一般來說,使用 hard link 設定連結檔時,磁碟的空間與 inode 的數目都不會改變! 我們還是由圖 7.2.1 來看,由圖中可以知道, hard link 只是在某個目錄下的 block 多寫入一個關連資料而已,既不會增加 inode 也不會耗用 block 數量哩!

Tips 鳥哥 hard link 的製作中,其實還是可能會改變系統的 block 的,那就是當你新增這筆資料卻剛好將目錄的 block 填滿時,就可能會新加一個 block 來記錄檔名關連性,而導致磁碟空間的變化!不過,一般 hard link 所用掉的關連資料量很小,所以通常不會改變 inode 與磁碟空間的大小喔!

由圖 7.2.1 其實我們也能夠知道,事實上 hard link 應該僅能在單一檔案系統中進行的,應該是不能夠跨檔案系統才對! 因為圖 7.2.1 就是在同一個 filesystem 上嘛!所以 hard link 是有限制的:

  • 不能跨 Filesystem;
  • 不能 link 目錄。

不能跨 Filesystem 還好理解,那不能 hard link 到目錄又是怎麼回事呢?這是因為如果使用 hard link 連結到目錄時, 連結的新目錄得要多出一個 . 以及 .. ,那個 .. 就會導致父目錄也多出一個新的連結計算,如果多重處理時, 很可能會導致目錄搜尋時的錯誤循環問題,導致一個名為死結 (打了死結,一直在裡面轉不出來) 的困境!同時, 如果是在不同的目錄底下建立目錄的 hard link 時,將可能會導致『同一個目錄會有好幾個父目錄』的存在! 因此, hard link 一個目錄不是做不到,而是建議不要做!避免產生檔案系統錯亂的困擾啊!舉例來說,底下為兩個互為 hard link 的目錄:

  • /some/aapdir/aadir/
  • /some/aapdir/aadir/.
  • /some/aapdir/aadir/..
  • /some/bbpdir/bbdir/
  • /some/bbpdir/bbdir/.
  • /some/bbpdir/bbdir/..

你在 aadir 看到的資料應該是要跟 bbdir 看到的一樣,但是 aadir 的 .. 會是 aapdir ,不過 bbdir 的 .. 卻變成 bbpdir, 明明是互為連結的 hard link 目錄,裡面的 .. 卻指向不同的地方~這就傷腦筋了!為了避免許多這方面的困擾,所以才建議不要使用 hard link 在目錄上的!

  • Symbolic Link (符號連結,亦即是捷徑)

相對於 hard link , Symbolic link 可就好理解多了,基本上, Symbolic link 就是在建立一個獨立的檔案,而這個檔案會讓資料的讀取指向他 link 的那個檔案的檔名!由於只是利用檔案來做為指向的動作, 所以,當來源檔被刪除之後,symbolic link 的檔案會『開不了』, 會一直說『無法開啟某檔案!』。實際上就是找不到原始『檔名』而已啦!

舉例來說,我們先建立一個符號連結檔連結到 /etc/crontab 去看看:

[root@study ~]# ln -s /etc/crontab crontab2
[root@study ~]# ll -i /etc/crontab /root/crontab2
34474855 -rw-r--r--. 2 root root 451 Jun 10  2014 /etc/crontab
53745909 lrwxrwxrwx. 1 root root  12 Jun 23 22:31 /root/crontab2 -> /etc/crontab

由上表的結果我們可以知道兩個檔案指向不同的 inode 號碼,當然就是兩個獨立的檔案存在! 而且連結檔的重要內容就是他會寫上目標檔案的『檔名』, 你可以發現為什麼上表中連結檔的大小為 12 bytes 呢? 因為箭頭(-->)右邊的檔名『/etc/crontab』總共有 12 個英文,每個英文佔用 1 個 bytes ,所以檔案大小就是 12bytes了!

關於上述的說明,我們以如下圖示來解釋:

符號連結的檔案讀取示意圖
圖7.2.2、符號連結的檔案讀取示意圖

由 1 號 inode 讀取到連結檔的內容僅有檔名,根據檔名連結到正確的目錄去取得目標檔案的 inode , 最終就能夠讀取到正確的資料了。你可以發現的是,如果目標檔案(/etc/crontab)被刪除了,那麼整個環節就會無法繼續進行下去, 所以就會發生無法透過連結檔讀取的問題了!

這裡還是得特別留意,這個 Symbolic Link 與 Windows 的捷徑可以給他劃上等號,由 Symbolic link 所建立的檔案為一個獨立的新的檔案,所以會佔用掉 inode 與 block 喔!


由上面的說明來看,似乎 hard link 比較安全,因為即使某一個目錄下的關連資料被殺掉了, 也沒有關係,只要有任何一個目錄下存在著關連資料,那麼該檔案就不會不見!舉上面的例子來說,我的 /etc/crontab 與 /root/crontab 指向同一個檔案,如果我刪除了 /etc/crontab 這個檔案,該刪除的動作其實只是將 /etc 目錄下關於 crontab 的關連資料拿掉而已, crontab 所在的 inode 與 block 其實都沒有被變動喔!

不過由於 Hard Link 的限制太多了,包括無法做『目錄』的 link , 所以在用途上面是比較受限的!反而是 Symbolic Link 的使用方面較廣喔!好了, 說的天花亂墜,看你也差不多快要昏倒了!沒關係,實作一下就知道怎麼回事了!要製作連結檔就必須要使用 ln 這個指令呢!

[root@study ~]# ln [-sf] 來源檔 目標檔
選項與參數:
-s  :如果不加任何參數就進行連結,那就是hard link,至於 -s 就是symbolic link
-f  :如果 目標檔 存在時,就主動的將目標檔直接移除後再建立!

範例一:將 /etc/passwd 複製到 /tmp 底下,並且觀察 inode 與 block
[root@study ~]# cd /tmp
[root@study tmp]# cp -a /etc/passwd .
[root@study tmp]# du -sb ; df -i .
6602    .   <==先注意一下這裡的容量是多少!
Filesystem                Inodes  IUsed    IFree IUse% Mounted on
/dev/mapper/centos-root 10485760 109748 10376012    2% /
# 利用 du 與 df 來檢查一下目前的參數~那個 du -sb 是計算整個 /tmp 底下有多少 bytes 的容量啦!

範例二:將 /tmp/passwd 製作 hard link 成為 passwd-hd 檔案,並觀察檔案與容量
[root@study tmp]# ln passwd passwd-hd
[root@study tmp]# du -sb ; df -i .
6602    .
Filesystem                Inodes  IUsed    IFree IUse% Mounted on
/dev/mapper/centos-root 10485760 109748 10376012    2% /
# 仔細看,即使多了一個檔案在 /tmp 底下,整個 inode 與 block 的容量並沒有改變!

[root@study tmp]# ls -il passwd*
2668897 -rw-r--r--. 2 root root 2092 Jun 17 00:20 passwd
2668897 -rw-r--r--. 2 root root 2092 Jun 17 00:20 passwd-hd
# 原來是指向同一個 inode 啊!這是個重點啊!另外,那個第二欄的連結數也會增加!

範例三:將 /tmp/passwd 建立一個符號連結
[root@study tmp]# ln -s passwd passwd-so
[root@study tmp]# ls -li passwd*
2668897 -rw-r--r--. 2 root root 2092 Jun 17 00:20 passwd
2668897 -rw-r--r--. 2 root root 2092 Jun 17 00:20 passwd-hd
2668898 lrwxrwxrwx. 1 root root    6 Jun 23 22:40 passwd-so -> passwd
# passwd-so 指向的 inode number 不同了!這是一個新的檔案~這個檔案的內容是指向 
# passwd 的。passwd-so 的大小是 6bytes ,因為 『passwd』 這個單字共有六個字元之故

[root@study tmp]# du -sb ; df -i .
6608    .
Filesystem                Inodes  IUsed    IFree IUse% Mounted on
/dev/mapper/centos-root 10485760 109749 10376011    2% /
# 呼呼!整個容量與 inode 使用數都改變囉~確實如此啊!

範例四:刪除原始檔案 passwd ,其他兩個檔案是否能夠開啟?
[root@study tmp]# rm passwd
[root@study tmp]# cat passwd-hd
.....(正常顯示完畢!)
[root@study tmp]# cat passwd-so
cat: passwd-so: No such file or directory
[root@study tmp]# ll passwd*
-rw-r--r--. 1 root root 2092 Jun 17 00:20 passwd-hd
lrwxrwxrwx. 1 root root    6 Jun 23 22:40 passwd-so -> passwd
# 怕了吧!符號連結果然無法開啟!另外,如果符號連結的目標檔案不存在,
# 其實檔名的部分就會有特殊的顏色顯示喔!
Tips 鳥哥 還記得第五章當中,我們提到的 /tmp 這個目錄是幹嘛用的嗎?是給大家作為暫存檔用的啊! 所以,您會發現,過去我們在進行測試時,都會將資料移動到 /tmp 底下去練習~ 嘿嘿!因此,有事沒事,記得將 /tmp 底下的一些怪異的資料清一清先!

要注意囉!使用 ln 如果不加任何參數的話,那麼就是 Hard Link 囉!如同範例二的情況,增加了 hard link 之後,可以發現使用 ls -l 時,顯示的 link 那一欄屬性增加了!而如果這個時候砍掉 passwd 會發生什麼事情呢?passwd-hd 的內容還是會跟原來 passwd 相同,但是 passwd-so 就會找不到該檔案啦!

而如果 ln 使用 -s 的參數時,就做成差不多是 Windows 底下的『捷徑』的意思。當你修改 Linux 下的 symbolic link 檔案時,則更動的其實是『原始檔』, 所以不論你的這個原始檔被連結到哪裡去,只要你修改了連結檔,原始檔就跟著變囉! 以上面為例,由於你使用 -s 的參數建立一個名為 passwd-so 的檔案,則你修改 passwd-so 時,其內容與 passwd 完全相同,並且,當你按下儲存之後,被改變的將是 passwd 這個檔案!

此外,如果你做了底下這樣的連結:

ln -s /bin /root/bin

那麼如果你進入 /root/bin 這個目錄下,『請注意呦!該目錄其實是 /bin 這個目錄,因為你做了連結檔了!』所以,如果你進入 /root/bin 這個剛剛建立的連結目錄, 並且將其中的資料殺掉時,嗯! /bin 裡面的資料就通通不見了!這點請千萬注意!所以趕緊利用『rm /root/bin 』 將這個連結檔刪除吧!

基本上, Symbolic link 的用途比較廣,所以您要特別留意 symbolic link 的用法呢!未來一定還會常常用到的啦!

  • 關於目錄的 link 數量:

或許您已經發現了,那就是,當我們以 hard link 進行『檔案的連結』時,可以發現,在 ls -l 所顯示的第二欄位會增加一才對,那麼請教,如果建立目錄時,他預設的 link 數量會是多少? 讓我們來想一想,一個『空目錄』裡面至少會存在些什麼?呵呵!就是存在 . 與 .. 這兩個目錄啊! 那麼,當我們建立一個新目錄名稱為 /tmp/testing 時,基本上會有三個東西,那就是:

  • /tmp/testing
  • /tmp/testing/.
  • /tmp/testing/..

而其中 /tmp/testing 與 /tmp/testing/. 其實是一樣的!都代表該目錄啊~而 /tmp/testing/.. 則代表 /tmp 這個目錄,所以說,當我們建立一個新的目錄時, 『新的目錄的 link 數為 2 ,而上層目錄的 link 數則會增加 1 』 不信的話,我們來作個測試看看:

[root@study ~]# ls -ld /tmp
drwxrwxrwt. 14 root root 4096 Jun 23 22:42 /tmp
[root@study ~]# mkdir /tmp/testing1
[root@study ~]# ls -ld /tmp
drwxrwxrwt. 15 root root 4096 Jun 23 22:45 /tmp  # 這裡的 link 數量加 1 了!
[root@study ~]# ls -ld /tmp/testing1
drwxr-xr-x. 2 root root 6 Jun 23 22:45 /tmp/testing1/

瞧!原本的所謂上層目錄 /tmp 的 link 數量由 14 增加為 15 ,至於新目錄 /tmp/testing 則為 2 ,這樣可以理解目錄的 link 數量的意義了嗎? ^_^

7.3 磁碟的分割、格式化、檢驗與掛載

對於一個系統管理者( root )而言,磁碟的的管理是相當重要的一環,尤其近來磁碟已經漸漸的被當成是消耗品了 ..... 如果我們想要在系統裡面新增一顆磁碟時,應該有哪些動作需要做的呢:

  1. 對磁碟進行分割,以建立可用的 partition ;
  2. 對該 partition 進行格式化 (format),以建立系統可用的 filesystem;
  3. 若想要仔細一點,則可對剛剛建立好的 filesystem 進行檢驗;
  4. 在 Linux 系統上,需要建立掛載點 (亦即是目錄),並將他掛載上來;

當然囉,在上述的過程當中,還有很多需要考慮的,例如磁碟分割槽 (partition) 需要定多大? 是否需要加入 journal 的功能?inode 與 block 的數量應該如何規劃等等的問題。但是這些問題的決定, 都需要與你的主機用途來加以考量的~所以,在這個小節裡面,鳥哥僅會介紹幾個動作而已, 更詳細的設定值,則需要以你未來的經驗來參考囉!

7.3.1 觀察磁碟分割狀態

由於目前磁碟分割主要有 MBR 以及 GPT 兩種格式,這兩種格式所使用的分割工具不太一樣!你當然可以使用本章預計最後才介紹的 parted 這個通通有支援的工具來處理,不過,我們還是比較習慣使用 fdisk 或者是 gdisk 來處理分割啊!因此,我們自然就得要去找一下目前系統有的磁碟有哪些? 這些磁碟是 MBR 還是 GPT 等等的!這樣才能處理啦!

  • lsblk 列出系統上的所有磁碟列表

lsblk 可以看成『 list block device 』的縮寫,就是列出所有儲存裝置的意思!這個工具軟體真的很好用喔!來瞧一瞧!

[root@study ~]# lsblk [-dfimpt] [device]
選項與參數:
-d  :僅列出磁碟本身,並不會列出該磁碟的分割資料
-f  :同時列出該磁碟內的檔案系統名稱
-i  :使用 ASCII 的線段輸出,不要使用複雜的編碼 (再某些環境下很有用)
-m  :同時輸出該裝置在 /dev 底下的權限資料 (rwx 的資料)
-p  :列出該裝置的完整檔名!而不是僅列出最後的名字而已。
-t  :列出該磁碟裝置的詳細資料,包括磁碟佇列機制、預讀寫的資料量大小等

範例一:列出本系統下的所有磁碟與磁碟內的分割資訊
[root@study ~]# lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1 1024M  0 rom
vda             252:0    0   40G  0 disk             # 一整顆磁碟
|-vda1          252:1    0    2M  0 part
|-vda2          252:2    0    1G  0 part /boot
`-vda3          252:3    0   30G  0 part
  |-centos-root 253:0    0   10G  0 lvm  /           # 在 vda3 內的其他檔案系統
  |-centos-swap 253:1    0    1G  0 lvm  [SWAP]
  `-centos-home 253:2    0    5G  0 lvm  /home

從上面的輸出我們可以很清楚的看到,目前的系統主要有個 sr0 以及一個 vda 的裝置,而 vda 的裝置底下又有三個分割, 其中 vda3 甚至還有因為 LVM 產生的檔案系統!相當的完整吧!從範例一我們來談談預設輸出的資訊有哪些。

  • NAME:就是裝置的檔名囉!會省略 /dev 等前導目錄!
  • MAJ:MIN:其實核心認識的裝置都是透過這兩個代碼來熟悉的!分別是主要:次要裝置代碼!
  • RM:是否為可卸載裝置 (removable device),如光碟、USB 磁碟等等
  • SIZE:當然就是容量囉!
  • RO:是否為唯讀裝置的意思
  • TYPE:是磁碟 (disk)、分割槽 (partition) 還是唯讀記憶體 (rom) 等輸出
  • MOUTPOINT:就是前一章談到的掛載點!
範例二:僅列出 /dev/vda 裝置內的所有資料的完整檔名
[root@study ~]# lsblk -ip /dev/vda
NAME                        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
/dev/vda                    252:0    0   40G  0 disk
|-/dev/vda1                 252:1    0    2M  0 part
|-/dev/vda2                 252:2    0    1G  0 part /boot
`-/dev/vda3                 252:3    0   30G  0 part
  |-/dev/mapper/centos-root 253:0    0   10G  0 lvm  /
  |-/dev/mapper/centos-swap 253:1    0    1G  0 lvm  [SWAP]
  `-/dev/mapper/centos-home 253:2    0    5G  0 lvm  /home        # 完整的檔名,由 / 開始寫
  • blkid 列出裝置的 UUID 等參數

雖然 lsblk 已經可以使用 -f 來列出檔案系統與裝置的 UUID 資料,不過,鳥哥還是比較習慣直接使用 blkid 來找出裝置的 UUID 喔! 什麼是 UUID 呢?UUID 是全域單一識別碼 (universally unique identifier),Linux 會將系統內所有的裝置都給予一個獨一無二的識別碼, 這個識別碼就可以拿來作為掛載或者是使用這個裝置/檔案系統之用了。

[root@study ~]# blkid
/dev/vda2: UUID="94ac5f77-cb8a-495e-a65b-2ef7442b837c" TYPE="xfs" 
/dev/vda3: UUID="WStYq1-P93d-oShM-JNe3-KeDl-bBf6-RSmfae" TYPE="LVM2_member"
/dev/sda1: UUID="35BC-6D6B" TYPE="vfat"
/dev/mapper/centos-root: UUID="299bdc5b-de6d-486a-a0d2-375402aaab27" TYPE="xfs"
/dev/mapper/centos-swap: UUID="905dc471-6c10-4108-b376-a802edbd862d" TYPE="swap"
/dev/mapper/centos-home: UUID="29979bf1-4a28-48e0-be4a-66329bf727d9" TYPE="xfs"

如上所示,每一行代表一個檔案系統,主要列出裝置名稱、UUID 名稱以及檔案系統的類型 (TYPE)!這對於管理員來說,相當有幫助! 對於系統上面的檔案系統觀察來說,真是一目了然!

  • parted 列出磁碟的分割表類型與分割資訊

雖然我們已經知道了系統上面的所有裝置,並且透過 blkid 也知道了所有的檔案系統!不過,還是不清楚磁碟的分割類型。 這時我們可以透過簡單的 parted 來輸出喔!我們這裡僅簡單的利用他的輸出而已~本章最後才會詳細介紹這個指令的用法的!

[root@study ~]# parted device_name print

範例一:列出 /dev/vda 磁碟的相關資料
[root@study ~]# parted /dev/vda print
Model: Virtio Block Device (virtblk)        # 磁碟的模組名稱(廠商)
Disk /dev/vda: 42.9GB                       # 磁碟的總容量
Sector size (logical/physical): 512B/512B   # 磁碟的每個邏輯/物理磁區容量
Partition Table: gpt                        # 分割表的格式 (MBR/GPT)
Disk Flags: pmbr_boot

Number  Start   End     Size    File system  Name  Flags      # 底下才是分割資料
 1      1049kB  3146kB  2097kB                     bios_grub
 2      3146kB  1077MB  1074MB  xfs
 3      1077MB  33.3GB  32.2GB                     lvm

看到上表的說明,你就知道啦!我們用的就是 GPT 的分割格式喔!這樣會觀察磁碟分割了嗎?接下來要來操作磁碟分割了喔!

7.3.2 磁碟分割: gdisk/fdisk

接下來我們想要進行磁碟分割囉!要注意的是:『MBR 分割表請使用 fdisk 分割, GPT 分割表請使用 gdisk 分割!』 這個不要搞錯~否則會分割失敗的!另外,這兩個工具軟體的操作很類似,執行了該軟體後,可以透過該軟體內部的說明資料來操作, 因此不需要硬背!只要知道方法即可。剛剛從上面 parted 的輸出結果,我們也知道鳥哥這個測試機使用的是 GPT 分割, 因此底下通通得要使用 gdisk 來分割才行!

  • gdisk
[root@study ~]# gdisk 裝置名稱

範例:由前一小節的 lsblk 輸出,我們知道系統有個 /dev/vda,請觀察該磁碟的分割與相關資料
[root@study ~]# gdisk /dev/vda  <==仔細看,不要加上數字喔!
GPT fdisk (gdisk) version 0.8.6

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.  <==找到了 GPT 的分割表!

Command (? for help):     <==這裡可以讓你輸入指令動作,可以按問號 (?) 來查看可用指令
Command (? for help): ?
b       back up GPT data to a file
c       change a partition's name
d       delete a partition           # 刪除一個分割
i       show detailed information on a partition
l       list known partition types
n       add a new partition          # 增加一個分割
o       create a new empty GUID partition table (GPT)
p       print the partition table    # 印出分割表 (常用)
q       quit without saving changes  # 不儲存分割就直接離開 gdisk
r       recovery and transformation options (experts only)
s       sort partitions
t       change a partition's type code
v       verify disk
w       write table to disk and exit # 儲存分割操作後離開 gdisk
x       extra functionality (experts only)
?       print this menu
Command (? for help):  

你應該要透過 lsblk 或 blkid 先找到磁碟,再用 parted /dev/xxx print 來找出內部的分割表類型,之後才用 gdisk 或 fdisk 來操作系統。 上表中可以發現 gdisk 會掃描 MBR 與 GPT 分割表,不過這個軟體還是單純使用在 GPT 分割表比較好啦!

老實說,使用 gdisk 這支程式是完全不需要背指令的!如同上面的表格中,你只要按下 ? 就能夠看到所有的動作! 比較重要的動作在上面已經用底線畫出來了,你可以參考看看。其中比較不一樣的是『q 與 w』這兩個玩意兒! 不管你進行了什麼動作,只要離開 gdisk 時按下『q』,那麼所有的動作『都不會生效!』相反的, 按下『w』就是動作生效的意思。所以,你可以隨便玩 gdisk ,只要離開時按下的是『q』即可。 ^_^! 好了,先來看看分割表資訊吧!

Command (? for help): p  <== 這裡可以輸出目前磁碟的狀態
Disk /dev/vda: 83886080 sectors, 40.0 GiB                     # 磁碟檔名/磁區數與總容量
Logical sector size: 512 bytes                                # 單一磁區大小為 512 bytes 
Disk identifier (GUID): A4C3C813-62AF-4BFE-BAC9-112EBD87A483  # 磁碟的 GPT 識別碼
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 83886046
Partitions will be aligned on 2048-sector boundaries
Total free space is 18862013 sectors (9.0 GiB)

Number  Start (sector)    End (sector)  Size       Code  Name # 底下為完整的分割資訊了!
   1            2048            6143   2.0 MiB     EF02       # 第一個分割槽資料
   2            6144         2103295   1024.0 MiB  0700
   3         2103296        65026047   30.0 GiB    8E00
# 分割編號 開始磁區號碼  結束磁區號碼  容量大小
Command (? for help): q
# 想要不儲存離開嗎?按下 q 就對了!不要隨便按 w 啊!

使用『 p 』可以列出目前這顆磁碟的分割表資訊,這個資訊的上半部在顯示整體磁碟的狀態。 以鳥哥這顆磁碟為例,這個磁碟共有 40GB 左右的容量,共有 83886080 個磁區,每個磁區的容量為 512bytes。 要注意的是,現在的分割主要是以磁區為最小的單位喔!

下半部的分割表資訊主要在列出每個分割槽的個別資訊項目。每個項目的意義為:

  • Number:分割槽編號,1 號指的是 /dev/vda1 這樣計算。
  • Start (sector):每一個分割槽的開始磁區號碼位置
  • End (sector):每一個分割的結束磁區號碼位置,與 start 之間可以算出分割槽的總容量
  • Size:就是分割槽的容量了
  • Code:在分割槽內的可能的檔案系統類型。Linux 為 8300,swap 為 8200。不過這個項目只是一個提示而已,不見得真的代表此分割槽內的檔案系統喔!
  • Name:檔案系統的名稱等等。

從上表我們可以發現幾件事情:

  • 整部磁碟還可以進行額外的分割,因為最大磁區為 83886080,但只使用到 65026047 號而已;
  • 分割槽的設計中,新分割通常選用上一個分割的結束磁區號碼數加 1 作為起始磁區號碼!

這個 gdisk 只有 root 才能執行,此外,請注意,使用的『裝置檔名』請不要加上數字,因為 partition 是針對『整個磁碟裝置』而不是某個 partition 呢!所以執行『 gdisk /dev/vda1 』 就會發生錯誤啦!要使用 gdisk /dev/vda 才對!

Tips 鳥哥 再次強調,你可以使用 gdisk 在您的磁碟上面胡搞瞎搞的進行實際操作,都不打緊,但是請『千萬記住,不要按下 w 即可!』離開的時候按下 q 就萬事無妨囉! 此外,不要在 MBR 分割上面使用 gdisk,因為如果指令按錯,恐怕你的分割紀錄會全部死光光!也不要在 GPT 上面使用 fdisk 啦!切記切記!
  • 用 gdisk 新增分割槽

如果你是按照鳥哥建議的方式去安裝你的 CentOS 7,那麼你的磁碟應該會預留一塊容量來做練習的。如果沒有的話, 那麼你可能需要找另外一顆磁碟來讓你練習才行呦!而經過上面的觀察,我們也確認系統還有剩下的容量可以來操作練習分割! 假設我需要有如下的分割需求:

  • 1GB 的 xfs 檔案系統 (Linux)
  • 1GB 的 vfat 檔案系統 (Windows)
  • 0.5GB 的 swap (Linux swap)(這個分割等一下會被刪除喔!)

那就來處理處理!

[root@study ~]# gdisk /dev/vda
Command (? for help): p
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            6143   2.0 MiB     EF02
   2            6144         2103295   1024.0 MiB  0700
   3         2103296        65026047   30.0 GiB    8E00
# 找出最後一個 sector 的號碼是很重要的!

Command (? for help): ?  # 查一下增加分割的指令為何
Command (? for help): n  # 就是這個!所以開始新增的行為!
Partition number (4-128, default 4): 4  # 預設就是 4 號,所以也能 enter 即可!
First sector (34-83886046, default = 65026048) or {+-}size{KMGTP}: 65026048  # 也能 enter
Last sector (65026048-83886046, default = 83886046) or {+-}size{KMGTP}: +1G  # 決不要 enter
# 這個地方可有趣了!我們不需要自己去計算磁區號碼,透過 +容量 的這個方式,
# 就可以讓 gdisk 主動去幫你算出最接近你需要的容量的磁區號碼喔!

Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): # 使用預設值即可~直接 enter 下去!
# 這裡在讓你選擇未來這個分割槽預計使用的檔案系統!預設都是 Linux 檔案系統的 8300 囉!

Command (? for help): p
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            6143   2.0 MiB     EF02
   2            6144         2103295   1024.0 MiB  0700
   3         2103296        65026047   30.0 GiB    8E00
   4        65026048        67123199   1024.0 MiB  8300  Linux filesystem

重點在『 Last sector 』那一行,那行絕對不要使用預設值!因為預設值會將所有的容量用光!因此它預設選擇最大的磁區號碼! 因為我們僅要 1GB 而已,所以你得要加上 +1G 這樣即可!不需要計算 sector 的數量,gdisk 會根據你填寫的數值, 直接計算出最接近該容量的磁區數!每次新增完畢後,請立即『 p 』查看一下結果喔!請繼續處理後續的兩個分割槽! 最終出現的畫面會有點像底下這樣才對!

Command (? for help): p
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            6143   2.0 MiB     EF02
   2            6144         2103295   1024.0 MiB  0700
   3         2103296        65026047   30.0 GiB    8E00
   4        65026048        67123199   1024.0 MiB  8300  Linux filesystem
   5        67123200        69220351   1024.0 MiB  0700  Microsoft basic data
   6        69220352        70244351   500.0 MiB   8200  Linux swap

基本上,幾乎都用預設值,然後透過 +1G, +500M 來建置所需要的另外兩個分割槽!比較有趣的是檔案系統的 ID 啦!一般來說, Linux 大概都是 8200/8300/8e00 等三種格式, Windows 幾乎都用 0700 這樣,如果忘記這些數字,可以在 gdisk 內按下:『 L 』來顯示喔! 如果一切的分割狀態都正常的話,那麼就直接寫入磁碟分割表吧!

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/vda.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot.
The operation has completed successfully.
# gdisk 會先警告你可能的問題,我們確定分割是對的,這時才按下 y !不過怎麼還有警告?
# 這是因為這顆磁碟目前正在使用當中,因此系統無法立即載入新的分割表~

[root@study ~]# cat /proc/partitions
major minor  #blocks  name

 252        0   41943040 vda
 252        1       2048 vda1
 252        2    1048576 vda2
 252        3   31461376 vda3
 253        0   10485760 dm-0
 253        1    1048576 dm-1
 253        2    5242880 dm-2
# 你可以發現,並沒有 vda4, vda5, vda6 喔!因為核心還沒有更新!

因為 Linux 此時還在使用這顆磁碟,為了擔心系統出問題,所以分割表並沒有被更新喔!這個時候我們有兩個方式可以來處理! 其中一個是重新開機,不過很討厭!另外一個則是透過 partprobe 這個指令來處理即可!

  • partprobe 更新 Linux 核心的分割表資訊
[root@study ~]# partprobe [-s]  # 你可以不要加 -s !那麼螢幕不會出現訊息!
[root@study ~]# partprobe -s    # 不過還是建議加上 -s 比較清晰!
/dev/vda: gpt partitions 1 2 3 4 5 6

[root@study ~]# lsblk /dev/vda  # 實際的磁碟分割狀態
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vda             252:0    0   40G  0 disk
|-vda1          252:1    0    2M  0 part
|-vda2          252:2    0    1G  0 part /boot
|-vda3          252:3    0   30G  0 part
| |-centos-root 253:0    0   10G  0 lvm  /
| |-centos-swap 253:1    0    1G  0 lvm  [SWAP]
| `-centos-home 253:2    0    5G  0 lvm  /home
|-vda4          252:4    0    1G  0 part
|-vda5          252:5    0    1G  0 part
`-vda6          252:6    0  500M  0 part

[root@study ~]# cat /proc/partitions  # 核心的分割紀錄
major minor  #blocks  name

 252        0   41943040 vda
 252        1       2048 vda1
 252        2    1048576 vda2
 252        3   31461376 vda3
 252        4    1048576 vda4
 252        5    1048576 vda5
 252        6     512000 vda6
# 現在核心也正確的抓到了分割參數了!
  • 用 gdisk 刪除一個分割槽

已經學會了新增分割,那麼刪除分割呢?好!現在讓我們將剛剛建立的 /dev/vda6 刪除!妳該如何進行呢?鳥哥底下很快的處理一遍, 大家趕緊來瞧一瞧先!

[root@study ~]# gdisk /dev/vda
Command (? for help): p
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            6143   2.0 MiB     EF02
   2            6144         2103295   1024.0 MiB  0700
   3         2103296        65026047   30.0 GiB    8E00
   4        65026048        67123199   1024.0 MiB  8300  Linux filesystem
   5        67123200        69220351   1024.0 MiB  0700  Microsoft basic data
   6        69220352        70244351   500.0 MiB   8200  Linux swap

Command (? for help): d
Partition number (1-6): 6

Command (? for help): p
# 你會發現 /dev/vda6 不見了!非常棒!沒問題就寫入吧!

Command (? for help): w
# 同樣會有一堆訊息!鳥哥就不重複輸出了!自己選擇 y 來處理吧!

[root@study ~]# lsblk
# 你會發現!怪了!怎麼還是有 /dev/vda6 呢?沒辦法!還沒有更新核心的分割表啊!所以當然有錯!

[root@study ~]# partprobe -s
[root@study ~]# lsblk
# 這個時候,那個 /dev/vda6 才真的消失不見了!了解吧!
Tips 鳥哥 萬分注意!不要去處理一個正在使用中的分割槽!例如,我們的系統現在已經使用了 /dev/vda2 ,那如果你要刪除 /dev/vda2 的話, 必須要先將 /dev/vda2 卸載,否則直接刪除該分割的話,雖然磁碟還是會寫入正確的分割資訊,但是核心會無法更新分割表的資訊的! 另外,檔案系統與 Linux 系統的穩定度,恐怕也會變得怪怪的!反正!千萬不要處理正在使用中的檔案系統就對了!
  • fdisk

雖然 MBR 分割表在未來應該會慢慢的被淘汰,畢竟現在磁碟容量隨便都大於 2T 以上了。而對於在 CentOS 7.x 中還無法完整支援 GPT 的 fdisk 來說, 這家伙真的英雄無用武之地了啦!不過依舊有些舊的系統,以及虛擬機器的使用上面,還是有小磁碟存在的空間!這時處理 MBR 分割表, 就得要使用 fdisk 囉!

因為 fdisk 跟 gdisk 使用的方式幾乎一樣!只是一個使用 ? 作為指令提示資料,一個使用 m 作為提示這樣而已。 此外,fdisk 有時會使用磁柱 (cylinder) 作為分割的最小單位,與 gdisk 預設使用 sector 不太一樣!大致上只是這點差別! 另外, MBR 分割是有限制的 (Primary, Extended, Logical...)!不要忘記了!鳥哥這裡不使用範例了,畢竟示範機上面也沒有 MBR 分割表... 這裡僅列出相關的指令給大家對照參考囉!

[root@study ~]# fdisk /dev/sda
Command (m for help): m   <== 輸入 m 後,就會看到底下這些指令介紹
Command action
   a   toggle a bootable flag
   b   edit bsd disklabel
   c   toggle the dos compatibility flag
   d   delete a partition            <==刪除一個partition
   l   list known partition types
   m   print this menu
   n   add a new partition           <==新增一個partition
   o   create a new empty DOS partition table
   p   print the partition table     <==在螢幕上顯示分割表
   q   quit without saving changes   <==不儲存離開fdisk程式
   s   create a new empty Sun disklabel
   t   change a partition's system id
   u   change display/entry units
   v   verify the partition table
   w   write table to disk and exit  <==將剛剛的動作寫入分割表
   x   extra functionality (experts only)

7.3.3 磁碟格式化(建置檔案系統)

分割完畢後自然就是要進行檔案系統的格式化囉!格式化的指令非常的簡單,那就是『make filesystem, mkfs』 這個指令啦!這個指令其實是個綜合的指令,他會去呼叫正確的檔案系統格式化工具軟體!因為 CentOS 7 使用 xfs 作為預設檔案系統, 底下我們會先介紹 mkfs.xfs ,之後介紹新一代的 EXT 家族成員 mkfs.ext4,最後再聊一聊 mkfs 這個綜合指令吧!

  • XFS 檔案系統 mkfs.xfs

我們常聽到的『格式化』其實應該稱為『建置檔案系統 (make filesystem)』才對啦!所以使用的指令是 mkfs 喔!那我們要建立的其實是 xfs 檔案系統, 因此使用的是 mkfs.xfs 這個指令才對。這個指令是這樣使用的:

[root@study ~]# mkfs.xfs [-b bsize] [-d parms] [-i parms] [-l parms] [-L label] [-f] \
                         [-r parms] 裝置名稱
選項與參數:
關於單位:底下只要談到『數值』時,沒有加單位則為 bytes 值,可以用 k,m,g,t,p (小寫)等來解釋
          比較特殊的是 s 這個單位,它指的是 sector 的『個數』喔!
-b  :後面接的是 block 容量,可由 512 到 64k,不過最大容量限制為 Linux 的 4k 喔!
-d  :後面接的是重要的 data section 的相關參數值,主要的值有:
      agcount=數值  :設定需要幾個儲存群組的意思(AG),通常與 CPU 有關
      agsize=數值   :每個 AG 設定為多少容量的意思,通常 agcount/agsize 只選一個設定即可
      file          :指的是『格式化的裝置是個檔案而不是個裝置』的意思!(例如虛擬磁碟)
      size=數值     :data section 的容量,亦即你可以不將全部的裝置容量用完的意思
      su=數值       :當有 RAID 時,那個 stripe 數值的意思,與底下的 sw 搭配使用
      sw=數值       :當有 RAID 時,用於儲存資料的磁碟數量(須扣除備份碟與備用碟)
      sunit=數值    :與 su 相當,不過單位使用的是『幾個 sector(512bytes大小)』的意思
      swidth=數值   :就是 su*sw 的數值,但是以『幾個 sector(512bytes大小)』來設定
-f  :如果裝置內已經有檔案系統,則需要使用這個 -f 來強制格式化才行!
-i  :與 inode 有較相關的設定,主要的設定值有:
      size=數值     :最小是 256bytes 最大是 2k,一般保留 256 就足夠使用了!
      internal=[0|1]:log 裝置是否為內建?預設為 1 內建,如果要用外部裝置,使用底下設定
      logdev=device :log 裝置為後面接的那個裝置上頭的意思,需設定 internal=0 才可!
      size=數值     :指定這塊登錄區的容量,通常最小得要有 512 個 block,大約 2M 以上才行!
-L  :後面接這個檔案系統的標頭名稱 Label name 的意思!
-r  :指定 realtime section 的相關設定值,常見的有:
      extsize=數值  :就是那個重要的 extent 數值,一般不須設定,但有 RAID 時,
                      最好設定與 swidth 的數值相同較佳!最小為 4K 最大為 1G 。

範例:將前一小節分割出來的 /dev/vda4 格式化為 xfs 檔案系統
[root@study ~]# mkfs.xfs /dev/vda4
meta-data=/dev/vda4       isize=256    agcount=4, agsize=65536 blks
         =                sectsz=512   attr=2, projid32bit=1
         =                crc=0        finobt=0
data     =                bsize=4096   blocks=262144, imaxpct=25
         =                sunit=0      swidth=0 blks
naming   =version 2       bsize=4096   ascii-ci=0 ftype=0
log      =internal log    bsize=4096   blocks=2560, version=2
         =                sectsz=512   sunit=0 blks, lazy-count=1
realtime =none            extsz=4096   blocks=0, rtextents=0
# 很快格是化完畢!都用預設值!較重要的是 inode 與 block 的數值

[root@study ~]# blkid /dev/vda4
/dev/vda4: UUID="39293f4f-627b-4dfd-a015-08340537709c" TYPE="xfs"
# 確定建置好 xfs 檔案系統了!

使用預設的 xfs 檔案系統參數來建置系統即可!速度非常快!如果我們有其他額外想要處理的項目,才需要加上一堆設定值!舉例來說,因為 xfs 可以使用多個資料流來讀寫系統,以增加速度,因此那個 agcount 可以跟 CPU 的核心數來做搭配!舉例來說,如果我的伺服器僅有一顆 4 核心,但是有啟動 Intel 超執行緒功能,則系統會模擬出 8 顆 CPU 時,那個 agcount 就可以設定為 8 喔!舉個例子來瞧瞧:

範例:找出你系統的 CPU 數,並據以設定你的 agcount 數值
[root@study ~]# grep 'processor' /proc/cpuinfo
processor       : 0
processor       : 1
# 所以就是有兩顆 CPU 的意思,那就來設定設定我們的 xfs 檔案系統格式化參數吧!!

[root@study ~]# mkfs.xfs -f -d agcount=2 /dev/vda4
meta-data=/dev/vda4       isize=256    agcount=2, agsize=131072 blks
         =                sectsz=512   attr=2, projid32bit=1
         =                crc=0        finobt=0
.....(底下省略).....
# 可以跟前一個範例對照看看,可以發現 agcount 變成 2 了喔!
# 此外,因為已經格式化過一次,因此 mkfs.xfs 可能會出現不給你格式化的警告!因此需要使用 -f
  • XFS 檔案系統 for RAID 效能優化 (Optional)

我們在第14章會持續談到進階檔案系統的設定,其中就有磁碟陣列這個東西!磁碟陣列是多顆磁碟組成一顆大磁碟的意思, 利用同步寫入到這些磁碟的技術,不但可以加快讀寫速度,還可以讓某一顆磁碟壞掉時,整個檔案系統還是可以持續運作的狀態!那就是所謂的容錯。

基本上,磁碟陣列 (RAID) 就是透過將檔案先細分為數個小型的分割區塊 (stripe) 之後,然後將眾多的 stripes 分別放到磁碟陣列裡面的所有磁碟, 所以一個檔案是被同時寫入到多個磁碟去,當然效能會好一些。為了檔案的保全性,所以在這些磁碟裡面,會保留數個 (與磁碟陣列的規劃有關) 備份磁碟 (parity disk), 以及可能會保留一個以上的備用磁碟 (spare disk),這些區塊基本上會佔用掉磁碟陣列的總容量,不過對於資料的保全會比較有保障!

那個分割區塊 stripe 的數值大多介於 4K 到 1M 之間,這與你的磁碟陣列卡支援的項目有關。stripe 與你的檔案資料容量以及效能相關性較高。 當你的系統大多是大型檔案時,一般建議 stripe 可以設定大一些,這樣磁碟陣列讀/寫的頻率會降低,效能會提昇。如果是用於系統, 那麼小檔案比較多的情況下, stripe 建議大約在 64K 左右可能會有較佳的效能。不過,還是都須要經過測試啦!完全是 case by case 的情況。 更多詳細的磁碟陣列我們在第 14 章再來談,這裡先有個大概的認識即可。14 章看完之後,再回來這個小節瞧瞧囉!

檔案系統的讀寫要能夠有最佳化,最好能夠搭配磁碟陣列的參數來設計,這樣效能才能夠起來!也就是說,你可以先在檔案系統就將 stripe 規劃好, 那交給 RAID 去存取時,它就無須重複進行檔案的 stripe 過程,效能當然會更好!那格式化時,最佳化效能與什麼咚咚有關呢?我們來假設個環境好了:

  • 我有兩個執行緒的 CPU 數量,所以 agcount 最好指定為 2
  • 當初設定 RAID 的 stripe 指定為 256K 這麼大,因此 su 最好設定為 256k
  • 設定的磁碟陣列有 8 顆,因為是 RAID5 的設定,所以有一個 parity (備份碟),因此指定 sw 為 7
  • 由上述的資料中,我們可以發現資料寬度 (swidth) 應該就是 256K*7 得到 1792K,可以指定 extsize 為 1792k

相關資料的來源可以參考文末(註7)的說明,這裡僅快速的使用 mkfs.xfs 的參數來處理格式化的動作喔!

[root@study ~]# mkfs.xfs -f -d agcount=2,su=256k,sw=7 -r extsize=1792k /dev/vda4
meta-data=/dev/vda4              isize=256    agcount=2, agsize=131072 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=64     swidth=448 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=64 blks, lazy-count=1
realtime =none                   extsz=1835008 blocks=0, rtextents=0

從輸出的結果來看, agcount 沒啥問題, sunit 結果是 64 個 block,因為每個 block 為 4K,所以算出來容量就是 256K 也沒錯! 那個 swidth 也相同!使用 448 * 4K 得到 1792K!那個 extsz 則是算成 bytes 的單位,換算結果也沒錯啦!上面是個方式,那如果使用 sunit 與 swidth 直接套用在 mkfs.xfs 當中呢?那你得小心了!因為指令中的這兩個參數用的是『幾個 512bytes 的 sector 數量』的意思! 是『數量』單位而不是『容量』單位!因此先計算為:

  • sunit = 256K/512byte*1024(bytes/K) = 512 個 sector
  • swidth = 7 個磁碟 * sunit = 7 * 512 = 3584 個 sector

所以指令就得要變成如下模樣:

[root@study ~]# mkfs.xfs -f -d agcount=2,sunit=512,swidth=3584 -r extsize=1792k /dev/vda4

再說一次,這邊你大概先有個概念即可,看不懂也沒關係!等到 14 章看完後,未來回到這裡,應該就能夠看得懂了! 多看幾次!多做幾次~作業系統的練習就是這樣才能學的會!看得懂! ^_^

  • EXT4 檔案系統 mkfs.ext4

如果想要格式化為 ext4 的傳統 Linux 檔案系統的話,可以使用 mkfs.ext4 這個指令即可!這個指令的參數快速的介紹一下!

[root@study ~]# mkfs.ext4 [-b size] [-L label] 裝置名稱
選項與參數:
-b  :設定 block 的大小,有 1K, 2K, 4K 的容量,
-L  :後面接這個裝置的標頭名稱。

範例:將 /dev/vda5 格式化為 ext4 檔案系統
[root@study ~]# mkfs.ext4 /dev/vda5
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=                                  # 顯示 Label name
OS type: Linux
Block size=4096 (log=2)                            # 每一個 block 的大小
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks             # 跟 RAID 相關性較高
65536 inodes, 262144 blocks                        # 總計 inode/block 的數量
13107 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups                                     # 共有 8 個 block groups 喔!
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

[root@study ~]# dumpe2fs -h /dev/vda5
dumpe2fs 1.42.9 (28-Dec-2013)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          3fd5cc6f-a47d-46c0-98c0-d43b072e0e12
....(中間省略)....
Inode count:              65536
Block count:              262144
Block size:               4096
Blocks per group:         32768
Inode size:               256
Journal size:             32M

由於資料量較大,因此鳥哥僅列出比較重要的項目而已,提供給你參考。另外,本章稍早之前介紹的 dumpe2fs 現在也可以測試練習了!查閱一下相關的資料吧! 因為 ext4 的預設值已經相當適合我們系統使用,大部分的預設值寫入於我們系統的 /etc/mke2fs.conf 這個檔案中,有興趣可以自行前往查閱。 也因此,我們無須額外指定 inode 的容量,系統都幫我們做好預設值囉!只需要得到 uuid 這個咚咚即可啦!

  • 其他檔案系統 mkfs

mkfs 其實是個綜合指令而已,當我們使用 mkfs -t xfs 時,它就會跑去找 mkfs.xfs 相關的參數給我們使用! 如果想要知道系統還支援哪種檔案系統的格式化功能,直接按 [tabl] 就很清楚了!

[root@study ~]# mkfs[tab][tab]
mkfs         mkfs.btrfs   mkfs.cramfs  mkfs.ext2    mkfs.ext3    mkfs.ext4    
mkfs.fat     mkfs.minix   mkfs.msdos   mkfs.vfat    mkfs.xfs

所以系統還有支援 ext2/ext3/vfat 等等多種常用的檔案系統喔!那如果要將剛剛的 /dev/vda5 重新格式化為 VFAT 檔案系統呢?

[root@study ~]# mkfs -t vfat /dev/vda5
[root@study ~]# blkid /dev/vda5
/dev/vda5: UUID="7130-6012" TYPE="vfat" PARTLABEL="Microsoft basic data"

[root@study ~]# mkfs.ext4 /dev/vda5
[root@study ~]# blkid /dev/vda4 /dev/vda5
/dev/vda4: UUID="e0a6af55-26e7-4cb7-a515-826a8bd29e90" TYPE="xfs" 
/dev/vda5: UUID="899b755b-1da4-4d1d-9b1c-f762adb798e1" TYPE="ext4" 

上面就是我們這個章節最後的結果了! /dev/vda4 是 xfs 檔案系統,而 /dev/vda5 是 ext4 檔案系統喔!都有練習妥當了嘛?

Tips 鳥哥 越來越多同學上課都不聽講,只是很單純的將鳥哥在螢幕操作的過程『拍照』下來而已~當鳥哥說『開始操作!等一下要檢查喔!』 大家就拼命的從手機裡面將剛剛的照片抓出來,一個一個指令照著打~

不過,螢幕並不能告訴你『 [tab] 按鈕其實不是按下 enter』的結果, 如上所示,同學拼命的按下 mkfs 之後,卻沒有辦法得到底下出現的眾多指令,就開始舉手...老師!我沒辦法作到你講的畫面...

拜託讀者們,請注意:『我們是要練習 Linux 系統,不是要練習 "英文打字"』啦!英文打字回家練就好了! @_@

7.3.4 檔案系統檢驗

由於系統在運作時誰也說不準啥時硬體或者是電源會有問題,所以『當機』可能是難免的情況(不管是硬體還是軟體)。 現在我們知道檔案系統運作時會有磁碟與記憶體資料非同步的狀況發生,因此莫名其妙的當機非常可能導致檔案系統的錯亂。 問題來啦,如果檔案系統真的發生錯亂的話,那該如何是好?就...挽救啊!不同的檔案系統救援的指令不太一樣,我們主要針對 xfs 及 ext4 這兩個主流來說明而已喔!

  • xfs_repair 處理 XFS 檔案系統

當有 xfs 檔案系統錯亂才需要使用這個指令!所以,這個指令最好是不要用到啦!但有問題發生時,這個指令卻又很重要...

[root@study ~]# xfs_repair [-fnd] 裝置名稱
選項與參數:
-f  :後面的裝置其實是個檔案而不是實體裝置
-n  :單純檢查並不修改檔案系統的任何資料 (檢查而已)
-d  :通常用在單人維護模式底下,針對根目錄 (/) 進行檢查與修復的動作!很危險!不要隨便使用

範例:檢查一下剛剛建立的 /dev/vda4 檔案系統
[root@study ~]# xfs_repair /dev/vda4
Phase 1 - find and verify superblock...
Phase 2 - using internal log
Phase 3 - for each AG...
Phase 4 - check for duplicate blocks...
Phase 5 - rebuild AG headers and trees...
Phase 6 - check inode connectivity...
Phase 7 - verify and correct link counts...
done
# 共有 7 個重要的檢查流程!詳細的流程介紹可以 man xfs_repair 即可!

範例:檢查一下系統原本就有的 /dev/centos/home 檔案系統
[root@study ~]# xfs_repair /dev/centos/home
xfs_repair: /dev/centos/home contains a mounted filesystem
xfs_repair: /dev/centos/home contains a mounted and writable filesystem

fatal error -- couldn't initialize XFS library

xfs_repair 可以檢查/修復檔案系統,不過,因為修復檔案系統是個很龐大的任務!因此,修復時該檔案系統不能被掛載! 所以,檢查與修復 /dev/vda4 沒啥問題,但是修復 /dev/centos/home 這個已經掛載的檔案系統時,嘿嘿!就出現上述的問題了! 沒關係,若可以卸載,卸載後再處理即可。

Linux 系統有個裝置無法被卸載,那就是根目錄啊!如果你的根目錄有問題怎辦?這時得要進入單人維護或救援模式,然後透過 -d 這個選項來處理! 加入 -d 這個選項後,系統會強制檢驗該裝置,檢驗完畢後就會自動重新開機囉!不過,鳥哥完全不打算要進行這個指令的實做... 永遠都不希望實做這東西...

  • fsck.ext4 處理 EXT4 檔案系統

fsck 是個綜合指令,如果是針對 ext4 的話,建議直接使用 fsck.ext4 來檢測比較妥當!那 fsck.ext4 的選項有底下幾個常見的項目:

[root@study ~]# fsck.ext4 [-pf] [-b superblock] 裝置名稱
選項與參數:
-p  :當檔案系統在修復時,若有需要回覆 y 的動作時,自動回覆 y 來繼續進行修復動作。
-f  :強制檢查!一般來說,如果 fsck 沒有發現任何 unclean 的旗標,不會主動進入
      細部檢查的,如果您想要強制 fsck 進入細部檢查,就得加上 -f 旗標囉!
-D  :針對檔案系統下的目錄進行最佳化配置。
-b  :後面接 superblock 的位置!一般來說這個選項用不到。但是如果你的 superblock 因故損毀時,
      透過這個參數即可利用檔案系統內備份的 superblock 來嘗試救援。一般來說,superblock 備份在:
      1K block 放在 8193, 2K block 放在 16384, 4K block 放在 32768

範例:找出剛剛建置的 /dev/vda5 的另一塊 superblock,並據以檢測系統
[root@study ~]# dumpe2fs -h /dev/vda5 | grep 'Blocks per group'
Blocks per group:         32768
# 看起來每個 block 群組會有 32768 個 block,因此第二個 superblock 應該就在 32768 上!
# 因為 block 號碼為 0 號開始編的!

[root@study ~]# fsck.ext4 -b 32768 /dev/vda5
e2fsck 1.42.9 (28-Dec-2013)
/dev/vda5 was not cleanly unmounted, check forced.
Pass 1: Checking inodes, blocks, and sizes
Deleted inode 1577 has zero dtime.  Fix<y>? yes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information

/dev/vda5: ***** FILE SYSTEM WAS MODIFIED *****  # 檔案系統被改過,所以這裡會有警告!
/dev/vda5: 11/65536 files (0.0% non-contiguous), 12955/262144 blocks
# 好巧合!鳥哥使用這個方式來檢驗系統,恰好遇到檔案系統出問題!於是可以有比較多的解釋方向!
# 當檔案系統出問題,它就會要你選擇是否修復~如果修復如上所示,按下 y 即可!
# 最終系統會告訴你,檔案系統已經被更改過,要注意該項目的意思!

範例:已預設設定強制檢查一次 /dev/vda5
[root@study ~]# fsck.ext4 /dev/vda5
e2fsck 1.42.9 (28-Dec-2013)
/dev/vda5: clean, 11/65536 files, 12955/262144 blocks
# 檔案系統狀態正常,它並不會進入強制檢查!會告訴你檔案系統沒問題 (clean)

[root@study ~]# fsck.ext4 -f /dev/vda5
e2fsck 1.42.9 (28-Dec-2013)
Pass 1: Checking inodes, blocks, and sizes
....(底下省略)....

無論是 xfs_repair 或 fsck.ext4,這都是用來檢查與修正檔案系統錯誤的指令。注意:通常只有身為 root 且你的檔案系統有問題的時候才使用這個指令,否則在正常狀況下使用此一指令, 可能會造成對系統的危害!通常使用這個指令的場合都是在系統出現極大的問題,導致你在 Linux 開機的時候得進入單人單機模式下進行維護的行為時,才必須使用此一指令!

另外,如果你懷疑剛剛格式化成功的磁碟有問題的時後,也可以使用 xfs_repair/fsck.ext4 來檢查一磁碟呦!其實就有點像是 Windows 的 scandisk 啦!此外,由於 xfs_repair/fsck.ext4 在掃瞄磁碟的時候,可能會造成部分 filesystem 的修訂,所以『執行 xfs_repair/fsck.ext4 時, 被檢查的 partition 務必不可掛載到系統上!亦即是需要在卸載的狀態喔!

7.3.5 檔案系統掛載與卸載

我們在本章一開始時的掛載點的意義當中提過掛載點是目錄, 而這個目錄是進入磁碟分割槽(其實是檔案系統啦!)的入口就是了。不過要進行掛載前,你最好先確定幾件事:

  • 單一檔案系統不應該被重複掛載在不同的掛載點(目錄)中;
  • 單一目錄不應該重複掛載多個檔案系統;
  • 要作為掛載點的目錄,理論上應該都是空目錄才是。

尤其是上述的後兩點!如果你要用來掛載的目錄裡面並不是空的,那麼掛載了檔案系統之後,原目錄下的東西就會暫時的消失。 舉個例子來說,假設你的 /home 原本與根目錄 (/) 在同一個檔案系統中,底下原本就有 /home/test 與 /home/vbird 兩個目錄。然後你想要加入新的磁碟,並且直接掛載 /home 底下,那麼當你掛載上新的分割槽時,則 /home 目錄顯示的是新分割槽內的資料,至於原先的 test 與 vbird 這兩個目錄就會暫時的被隱藏掉了!注意喔!並不是被覆蓋掉, 而是暫時的隱藏了起來,等到新分割槽被卸載之後,則 /home 原本的內容就會再次的跑出來啦!

而要將檔案系統掛載到我們的 Linux 系統上,就要使用 mount 這個指令啦! 不過,這個指令真的是博大精深~粉難啦!我們學簡單一點啊~ ^_^

[root@study ~]# mount -a
[root@study ~]# mount [-l]
[root@study ~]# mount [-t 檔案系統] LABEL=''  掛載點
[root@study ~]# mount [-t 檔案系統] UUID=''   掛載點  # 鳥哥近期建議用這種方式喔!
[root@study ~]# mount [-t 檔案系統] 裝置檔名  掛載點
選項與參數:
-a  :依照設定檔 /etc/fstab 的資料將所有未掛載的磁碟都掛載上來
-l  :單純的輸入 mount 會顯示目前掛載的資訊。加上 -l 可增列 Label 名稱!
-t  :可以加上檔案系統種類來指定欲掛載的類型。常見的 Linux 支援類型有:xfs, ext3, ext4,
      reiserfs, vfat, iso9660(光碟格式), nfs, cifs, smbfs (後三種為網路檔案系統類型)
-n  :在預設的情況下,系統會將實際掛載的情況即時寫入 /etc/mtab 中,以利其他程式的運作。
      但在某些情況下(例如單人維護模式)為了避免問題會刻意不寫入。此時就得要使用 -n 選項。
-o  :後面可以接一些掛載時額外加上的參數!比方說帳號、密碼、讀寫權限等:
      async, sync:   此檔案系統是否使用同步寫入 (sync) 或非同步 (async) 的
                     記憶體機制,請參考檔案系統運作方式。預設為 async。
      atime,noatime: 是否修訂檔案的讀取時間(atime)。為了效能,某些時刻可使用 noatime
      ro, rw:        掛載檔案系統成為唯讀(ro) 或可讀寫(rw)
      auto, noauto:  允許此 filesystem 被以 mount -a 自動掛載(auto)
      dev, nodev:    是否允許此 filesystem 上,可建立裝置檔案? dev 為可允許
      suid, nosuid:  是否允許此 filesystem 含有 suid/sgid 的檔案格式?
      exec, noexec:  是否允許此 filesystem 上擁有可執行 binary 檔案?
      user, nouser:  是否允許此 filesystem 讓任何使用者執行 mount ?一般來說,
                     mount 僅有 root 可以進行,但下達 user 參數,則可讓
                     一般 user 也能夠對此 partition 進行 mount 。
      defaults:      預設值為:rw, suid, dev, exec, auto, nouser, and async
      remount:       重新掛載,這在系統出錯,或重新更新參數時,很有用!

基本上,CentOS 7 已經太聰明了,因此你不需要加上 -t 這個選項,系統會自動的分析最恰當的檔案系統來嘗試掛載你需要的裝置! 這也是使用 blkid 就能夠顯示正確的檔案系統的緣故!那 CentOS 是怎麼找出檔案系統類型的呢? 由於檔案系統幾乎都有 superblock ,我們的 Linux 可以透過分析 superblock 搭配 Linux 自己的驅動程式去測試掛載, 如果成功的套和了,就立刻自動的使用該類型的檔案系統掛載起來啊!那麼系統有沒有指定哪些類型的 filesystem 才需要進行上述的掛載測試呢? 主要是參考底下這兩個檔案:

  • /etc/filesystems:系統指定的測試掛載檔案系統類型的優先順序;
  • /proc/filesystems:Linux系統已經載入的檔案系統類型。

那我怎麼知道我的 Linux 有沒有相關檔案系統類型的驅動程式呢?我們 Linux 支援的檔案系統之驅動程式都寫在如下的目錄中:

  • /lib/modules/$(uname -r)/kernel/fs/

例如 ext4 的驅動程式就寫在『/lib/modules/$(uname -r)/kernel/fs/ext4/』這個目錄下啦!

另外,過去我們都習慣使用裝置檔名然後直接用該檔名掛載, 不過近期以來鳥哥比較建議使用 UUID 來識別檔案系統,會比裝置名稱與標頭名稱還要更可靠!因為是獨一無二的啊!

  • 掛載 xfs/ext4/vfat 等檔案系統
範例:找出 /dev/vda4 的 UUID 後,用該 UUID 來掛載檔案系統到 /data/xfs 內
[root@study ~]# blkid /dev/vda4
/dev/vda4: UUID="e0a6af55-26e7-4cb7-a515-826a8bd29e90" TYPE="xfs"

[root@study ~]# mount UUID="e0a6af55-26e7-4cb7-a515-826a8bd29e90" /data/xfs
mount: mount point /data/xfs does not exist  # 非正規目錄!所以手動建立它!

[root@study ~]# mkdir -p /data/xfs
[root@study ~]# mount UUID="e0a6af55-26e7-4cb7-a515-826a8bd29e90" /data/xfs
[root@study ~]# df /data/xfs
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/vda4        1038336 32864   1005472   4% /data/xfs
# 順利掛載,且容量約為 1G 左右沒問題!

範例:使用相同的方式,將 /dev/vda5 掛載於 /data/ext4
[root@study ~]# blkid /dev/vda5
/dev/vda5: UUID="899b755b-1da4-4d1d-9b1c-f762adb798e1" TYPE="ext4"

[root@study ~]# mkdir /data/ext4
[root@study ~]# mount UUID="899b755b-1da4-4d1d-9b1c-f762adb798e1" /data/ext4
[root@study ~]# df /data/ext4
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/vda5         999320  2564    927944   1% /data/ext4
  • 掛載 CD 或 DVD 光碟

請拿出你的 CentOS 7 原版光碟出來,然後放入到光碟機當中,我們來測試一下這個玩意兒囉!

範例:將你用來安裝 Linux 的 CentOS 原版光碟拿出來掛載到 /data/cdrom!
[root@study ~]# blkid
.....(前面省略).....
/dev/sr0: UUID="2015-04-01-00-21-36-00" LABEL="CentOS 7 x86_64" TYPE="iso9660" PTTYPE="dos"

[root@study ~]# mkdir /data/cdrom
[root@study ~]# mount /dev/sr0 /data/cdrom
mount: /dev/sr0 is write-protected, mounting read-only

[root@study ~]# df /data/cdrom
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sr0         7413478 7413478         0 100% /data/cdrom
# 怎麼會使用掉 100% 呢?是啊!因為是 DVD 啊!所以無法再寫入了啊!

光碟機一掛載之後就無法退出光碟片了!除非你將他卸載才能夠退出! 從上面的資料你也可以發現,因為是光碟嘛!所以磁碟使用率達到 100% ,因為你無法直接寫入任何資料到光碟當中! 此外,如果你使用的是圖形界面,那麼系統會自動的幫你掛載這個光碟到 /media/ 裡面去喔!也可以不卸載就直接退出! 但是文字界面沒有這個福利就是了! ^_^

Tips 鳥哥 話說當時年紀小 (其實是剛接觸 Linux 的那一年, 1999 年前後),摸 Linux 到處碰壁!連將 CDROM 掛載後, 光碟機竟然都不讓我退片!那個時候難過的要死!還用迴紋針插入光碟機讓光碟退片耶!不過如此一來光碟就無法被使用了! 若要再次使用光碟機,當時的解決的方法竟然是『重新開機!』囧的可以啊!
  • 掛載 vfat 中文隨身碟 (USB磁碟)

請拿出你的隨身碟並插入 Linux 主機的 USB 槽中!注意,你的這個隨身碟不能夠是 NTFS 的檔案系統喔!接下來讓我們測試測試吧!

範例:找出你的隨身碟裝置的 UUID,並掛載到 /data/usb 目錄中
[root@study ~]# blkid
/dev/sda1: UUID="35BC-6D6B" TYPE="vfat"

[root@study ~]# mkdir /data/usb
[root@study ~]#   mount -o codepage=950,iocharset=utf8 UUID="35BC-6D6B" /data/usb
[root@study ~]# # mount -o codepage=950,iocharset=big5 UUID="35BC-6D6B" /data/usb
[root@study ~]# df /data/usb
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/sda1        2092344     4   2092340   1% /data/usb

如果帶有中文檔名的資料,那麼可以在掛載時指定一下掛載檔案系統所使用的語系資料。 在 man mount 找到 vfat 檔案格式當中可以使用 codepage 來處理!中文語系的代碼為 950 喔!另外,如果想要指定中文是萬國碼還是大五碼, 就得要使用 iocharset 為 utf8 還是 big5 兩者擇一了!因為鳥哥的隨身碟使用 utf8 編碼,因此將上述的 big5 前面加上 # 符號, 代表註解該行的意思囉!

萬一你使用的 USB 磁碟被格式化為 NTFS 時,那可能就得要動點手腳,因為預設的 CentOS 7 並沒有支援 NTFS 檔案系統格式! 所以你得要安裝 NTFS 檔案系統的驅動程式後,才有辦法處理的!這部份我們留待 22 章講到 yum 伺服器時再來談吧! 因為目前我們也還沒有網路、也沒有講軟體安裝啊! ^_^

  • 重新掛載根目錄與掛載不特定目錄

整個目錄樹最重要的地方就是根目錄了,所以根目錄根本就不能夠被卸載的!問題是,如果你的掛載參數要改變, 或者是根目錄出現『唯讀』狀態時,如何重新掛載呢?最可能的處理方式就是重新開機 (reboot)! 不過你也可以這樣做:

範例:將 / 重新掛載,並加入參數為 rw 與 auto
[root@study ~]# mount -o remount,rw,auto /

重點是那個『 -o remount,xx 』的選項與參數!請注意,要重新掛載 (remount) 時, 這是個非常重要的機制!尤其是當你進入單人維護模式時,你的根目錄常會被系統掛載為唯讀,這個時候這個指令就太重要了!

另外,我們也可以利用 mount 來將某個目錄掛載到另外一個目錄去喔!這並不是掛載檔案系統,而是額外掛載某個目錄的方法! 雖然底下的方法也可以使用 symbolic link 來連結,不過在某些不支援符號連結的程式運作中,還是得要透過這樣的方法才行。

範例:將 /var 這個目錄暫時掛載到 /data/var 底下:
[root@study ~]# mkdir /data/var
[root@study ~]# mount --bind /var /data/var
[root@study ~]# ls -lid /var /data/var
16777346 drwxr-xr-x. 22 root root 4096 Jun 15 23:43 /data/var
16777346 drwxr-xr-x. 22 root root 4096 Jun 15 23:43 /var
# 內容完全一模一樣啊!因為掛載目錄的緣故!

[root@study ~]# mount | grep var
/dev/mapper/centos-root on /data/var type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

看起來,其實兩者連結到同一個 inode 嘛! ^_^ 沒錯啦!透過這個 mount --bind 的功能, 您可以將某個目錄掛載到其他目錄去喔!而並不是整塊 filesystem 的啦!所以從此進入 /data/var 就是進入 /var 的意思喔!

  • umount (將裝置檔案卸載)
[root@study ~]# umount [-fn] 裝置檔名或掛載點
選項與參數:
-f  :強制卸載!可用在類似網路檔案系統 (NFS) 無法讀取到的情況下;
-l  :立刻卸載檔案系統,比 -f 還強!
-n  :不更新 /etc/mtab 情況下卸載。

就是直接將已掛載的檔案系統給他卸載即是!卸載之後,可以使用 df 或 mount 看看是否還存在目錄樹中? 卸載的方式,可以下達裝置檔名或掛載點,均可接受啦!底下的範例做看看吧!

範例:將本章之前自行掛載的檔案系統全部卸載:
[root@study ~]# mount
.....(前面省略).....
/dev/vda4 on /data/xfs type xfs (rw,relatime,seclabel,attr2,inode64,logbsize=256k,sunit=512,..)
/dev/vda5 on /data/ext4 type ext4 (rw,relatime,seclabel,data=ordered)
/dev/sr0 on /data/cdrom type iso9660 (ro,relatime)
/dev/sda1 on /data/usb type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=950,iocharset=...)
/dev/mapper/centos-root on /data/var type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
# 先找一下已經掛載的檔案系統,如上所示,特殊字體即為剛剛掛載的裝置囉!
# 基本上,卸載後面接裝置或掛載點都可以!不過最後一個 centos-root 由於有其他掛載,
# 因此,該項目一定要使用掛載點來卸載才行!

[root@study ~]# umount /dev/vda4      <==用裝置檔名來卸載
[root@study ~]# umount /data/ext4     <==用掛載點來卸載
[root@study ~]# umount /data/cdrom    <==因為掛載點比較好記憶!
[root@study ~]# umount /data/usb     
[root@study ~]# umount /data/var      <==一定要用掛載點!因為裝置有被其他方式掛載

由於通通卸載了,此時你才可以退出光碟片、軟碟片、USB隨身碟等設備喔!如果你遇到這樣的情況:

[root@study ~]# mount /dev/sr0 /data/cdrom
[root@study ~]# cd /data/cdrom
[root@study cdrom]# umount /data/cdrom
umount: /data/cdrom: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))

[root@study cdrom]# cd /
[root@study /]# umount /data/cdrom

由於你目前正在 /data/cdrom/ 的目錄內,也就是說其實『你正在使用該檔案系統』的意思!所以自然無法卸載這個裝置!那該如何是好?就『離開該檔案系統的掛載點』即可。以上述的案例來說, 你可以使用『 cd / 』回到根目錄,就能夠卸載 /data/cdrom 囉!簡單吧!

7.3.6 磁碟/檔案系統參數修訂

某些時刻,你可能會希望修改一下目前檔案系統的一些相關資訊,舉例來說,你可能要修改 Label name , 或者是 journal 的參數,或者是其他磁碟/檔案系統運作時的相關參數 (例如 DMA 啟動與否~)。 這個時候,就得需要底下這些相關的指令功能囉~

  • mknod

還記得我們說過,在 Linux 底下所有的裝置都以檔案來代表吧!但是那個檔案如何代表該裝置呢? 很簡單!就是透過檔案的 major 與 minor 數值來替代的~所以,那個 major 與 minor 數值是有特殊意義的,不是隨意設定的喔!我們在 lsblk 指令的用法裡面也談過這兩個數值呢!舉例來說,在鳥哥的這個測試機當中, 那個用到的磁碟 /dev/vda 的相關裝置代碼如下:

[root@study ~]# ll /dev/vda*
brw-rw----. 1 root disk 252, 0 Jun 24 02:30 /dev/vda
brw-rw----. 1 root disk 252, 1 Jun 24 02:30 /dev/vda1
brw-rw----. 1 root disk 252, 2 Jun 15 23:43 /dev/vda2
brw-rw----. 1 root disk 252, 3 Jun 15 23:43 /dev/vda3
brw-rw----. 1 root disk 252, 4 Jun 24 20:00 /dev/vda4
brw-rw----. 1 root disk 252, 5 Jun 24 21:15 /dev/vda5

上表當中 252 為主要裝置代碼 (Major) 而 0~5 則為次要裝置代碼 (Minor)。 我們的 Linux 核心認識的裝置資料就是透過這兩個數值來決定的!舉例來說,常見的磁碟檔名 /dev/sda 與 /dev/loop0 裝置代碼如下所示:

磁碟檔名MajorMinor
/dev/sda80-15
/dev/sdb816-31
/dev/loop070
/dev/loop171

如果你想要知道更多核心支援的硬體裝置代碼 (major, minor) 請參考核心官網的連結(註8)。 基本上,Linux 核心 2.6 版以後,硬體檔名已經都可以被系統自動的即時產生了,我們根本不需要手動建立裝置檔案。 不過某些情況底下我們可能還是得要手動處理裝置檔案的,例如在某些服務被關到特定目錄下時(chroot), 就需要這樣做了。此時這個 mknod 就得要知道如何操作才行!

[root@study ~]# mknod 裝置檔名 [bcp] [Major] [Minor]
選項與參數:
裝置種類:
   b  :設定裝置名稱成為一個周邊儲存設備檔案,例如磁碟等;
   c  :設定裝置名稱成為一個周邊輸入設備檔案,例如滑鼠/鍵盤等;
   p  :設定裝置名稱成為一個 FIFO 檔案;
Major :主要裝置代碼;
Minor :次要裝置代碼;

範例:由上述的介紹我們知道 /dev/vda10 裝置代碼 252, 10,請建立並查閱此裝置
[root@study ~]# mknod /dev/vda10 b 252 10
[root@study ~]# ll /dev/vda10
brw-r--r--. 1 root root 252, 10 Jun 24 23:40 /dev/vda10
# 上面那個 252 與 10 是有意義的,不要隨意設定啊!

範例:建立一個 FIFO 檔案,檔名為 /tmp/testpipe
[root@study ~]# mknod /tmp/testpipe p
[root@study ~]# ll /tmp/testpipe
prw-r--r--. 1 root root 0 Jun 24 23:44 /tmp/testpipe
# 注意啊!這個檔案可不是一般檔案,不可以隨便就放在這裡!
# 測試完畢之後請刪除這個檔案吧!看一下這個檔案的類型!是 p 喔!^_^

[root@study ~]# rm /dev/vda10 /tmp/testpipe
rm: remove block special file '/dev/vda10' ? y
rm: remove fifo '/tmp/testpipe' ? y
  • xfs_admin 修改 XFS 檔案系統的 UUID 與 Label name

如果你當初格式化的時候忘記加上標頭名稱,後來想要再次加入時,不需要重複格式化!直接使用這個 xfs_admin 即可。 這個指令直接拿來處理 LABEL name 以及 UUID 即可囉!

[root@study ~]# xfs_admin [-lu] [-L label] [-U uuid] 裝置檔名
選項與參數:
-l  :列出這個裝置的 label name
-u  :列出這個裝置的 UUID
-L  :設定這個裝置的 Label name
-U  :設定這個裝置的 UUID 喔!

範例:設定 /dev/vda4 的 label name 為 vbird_xfs,並測試掛載
[root@study ~]# xfs_admin -L vbird_xfs /dev/vda4
writing all SBs
new label = "vbird_xfs"                 # 產生新的 LABEL 名稱囉!
[root@study ~]# xfs_admin -l /dev/vda4
label = "vbird_xfs"
[root@study ~]# mount LABEL=vbird_xfs /data/xfs/

範例:利用 uuidgen 產生新 UUID 來設定 /dev/vda4,並測試掛載
[root@study ~]# umount /dev/vda4       # 使用前,請先卸載!
[root@study ~]# uuidgen
e0fa7252-b374-4a06-987a-3cb14f415488    # 很有趣的指令!可以產生新的 UUID 喔!
[root@study ~]# xfs_admin -u /dev/vda4
UUID = e0a6af55-26e7-4cb7-a515-826a8bd29e90
[root@study ~]# xfs_admin -U e0fa7252-b374-4a06-987a-3cb14f415488 /dev/vda4
Clearing log and setting UUID
writing all SBs
new UUID = e0fa7252-b374-4a06-987a-3cb14f415488
[root@study ~]# mount UUID=e0fa7252-b374-4a06-987a-3cb14f415488 /data/xfs

不知道你會不會有這樣的疑問:『鳥哥啊,既然 mount 後面使用裝置檔名 (/dev/vda4) 也可以掛載成功,那你為什麼要用很討厭的很長一串的 UUID 來作為你的掛載時寫入的裝置名稱啊?』問的好!原因是這樣的:『因為你沒有辦法指定這個磁碟在所有的 Linux 系統中,檔名一定都會是 /dev/vda !』

舉例來說,我們剛剛使用的隨身碟在鳥哥這個測試系統當中查詢到的檔名是 /dev/sda,但是當這個隨身碟放到其他的已經有 /dev/sda 檔名的 Linux 系統下,它的檔名就會被指定成為 /dev/sdb 或 /dev/sdc 等等。反正,不會是 /dev/sda 了!那我怎麼用同一個指令去掛載這隻隨身碟呢? 當然有問題吧!但是 UUID 可是很難重複的!看看上面 uuidgen 產生的結果你就知道了!所以你可以確定該名稱不會被重複! 這對系統管理上可是相當有幫助的!它也比 LABEL name 要更精準的多呢! ^_^

  • tune2fs 修改 ext4 的 label name 與 UUID
[root@study ~]# tune2fs [-l] [-L Label] [-U uuid] 裝置檔名
選項與參數:
-l  :類似 dumpe2fs -h 的功能~將 superblock 內的資料讀出來~
-L  :修改 LABEL name
-U  :修改 UUID 囉!

範例:列出 /dev/vda5 的 label name 之後,將它改成 vbird_ext4
[root@study ~]# dumpe2fs -h /dev/vda5 | grep name
dumpe2fs 1.42.9 (28-Dec-2013)
Filesystem volume name:   <none>   # 果然是沒有設定的!

[root@study ~]# tune2fs -L vbird_ext4 /dev/vda5
[root@study ~]# dumpe2fs -h /dev/vda5 | grep name
Filesystem volume name:   vbird_ext4
[root@study ~]# mount LABEL=vbird_ext4 /data/ext4

這個指令的功能其實很廣泛啦~上面鳥哥僅列出很簡單的一些參數而已,更多的用法請自行參考 man tune2fs 。

7.4 設定開機掛載

手動處理 mount 不是很人性化,我們總是需要讓系統『自動』在開機時進行掛載的!本小節就是在談這玩意兒! 另外,從 FTP 伺服器捉下來的映像檔能否不用燒錄就可以讀取內容?我們也需要談談先!

7.4.1 開機掛載 /etc/fstab 及 /etc/mtab

剛剛上面說了許多,那麼可不可以在開機的時候就將我要的檔案系統都掛好呢?這樣我就不需要每次進入 Linux 系統都還要在掛載一次呀!當然可以囉!那就直接到 /etc/fstab 裡面去修修就行囉!不過,在開始說明前,這裡要先跟大家說一說系統掛載的一些限制:

  • 根目錄 / 是必須掛載的﹐而且一定要先於其它 mount point 被掛載進來。
  • 其它 mount point 必須為已建立的目錄﹐可任意指定﹐但一定要遵守必須的系統目錄架構原則 (FHS)
  • 所有 mount point 在同一時間之內﹐只能掛載一次。
  • 所有 partition 在同一時間之內﹐只能掛載一次。
  • 如若進行卸載﹐您必須先將工作目錄移到 mount point(及其子目錄) 之外。

讓我們直接查閱一下 /etc/fstab 這個檔案的內容吧!

[root@study ~]# cat /etc/fstab
# Device                              Mount point  filesystem parameters    dump fsck
/dev/mapper/centos-root                   /       xfs     defaults            0 0
UUID=94ac5f77-cb8a-495e-a65b-2ef7442b837c /boot   xfs     defaults            0 0
/dev/mapper/centos-home                   /home   xfs     defaults            0 0
/dev/mapper/centos-swap                   swap    swap    defaults            0 0

其實 /etc/fstab (filesystem table) 就是將我們利用 mount 指令進行掛載時, 將所有的選項與參數寫入到這個檔案中就是了。除此之外, /etc/fstab 還加入了 dump 這個備份用指令的支援! 與開機時是否進行檔案系統檢驗 fsck 等指令有關。 這個檔案的內容共有六個欄位,這六個欄位非常的重要!你『一定要背起來』才好! 各個欄位的總結資料與詳細資料如下:

Tips 鳥哥 鳥哥比較龜毛一點,因為某些 distributions 的 /etc/fstab 檔案排列方式蠻醜的, 雖然每一欄之間只要以空白字元分開即可,但就是覺得醜,所以通常鳥哥就會自己排列整齊, 並加上註解符號(就是 # ),來幫我記憶這些資訊!
[裝置/UUID等]  [掛載點]  [檔案系統]  [檔案系統參數]  [dump]  [fsck]
  • 第一欄:磁碟裝置檔名/UUID/LABEL name:

這個欄位可以填寫的資料主要有三個項目:

  • 檔案系統或磁碟的裝置檔名,如 /dev/vda2 等
  • 檔案系統的 UUID 名稱,如 UUID=xxx
  • 檔案系統的 LABEL 名稱,例如 LABEL=xxx

因為每個檔案系統都可以有上面三個項目,所以你喜歡哪個項目就填哪個項目!無所謂的!只是從鳥哥測試機的 /etc/fstab 裡面看到的,在掛載點 /boot 使用的已經是 UUID 了喔!那你會說不是還有多個寫 /dev/mapper/xxx 的嗎?怎麼回事啊? 因為那個是 LVM 啊!LVM 的檔名在你的系統中也算是獨一無二的,這部份我們在後續章節再來談。 不過,如果為了一致性,你還是可以將他改成 UUID 也沒問題喔!(鳥哥還是比較建議使用 UUID 喔!) 要記得使用 blkid 或 xfs_admin 來查詢 UUID 喔!

  • 第二欄:掛載點 (mount point)::

就是掛載點啊!掛載點是什麼?一定是目錄啊~要知道啊!忘記的話,請回本章稍早之前的資料瞧瞧喔!

  • 第三欄:磁碟分割槽的檔案系統:

在手動掛載時可以讓系統自動測試掛載,但在這個檔案當中我們必須要手動寫入檔案系統才行! 包括 xfs, ext4, vfat, reiserfs, nfs 等等。

  • 第四欄:檔案系統參數:

記不記得我們在 mount 這個指令中談到很多特殊的檔案系統參數? 還有我們使用過的『-o codepage=950』?這些特殊的參數就是寫入在這個欄位啦! 雖然之前在 mount 已經提過一次,這裡我們利用表格的方式再彙整一下:

參數內容意義
async/sync
非同步/同步
設定磁碟是否以非同步方式運作!預設為 async(效能較佳)
auto/noauto
自動/非自動
當下達 mount -a 時,此檔案系統是否會被主動測試掛載。預設為 auto。
rw/ro
可讀寫/唯讀
讓該分割槽以可讀寫或者是唯讀的型態掛載上來,如果你想要分享的資料是不給使用者隨意變更的, 這裡也能夠設定為唯讀。則不論在此檔案系統的檔案是否設定 w 權限,都無法寫入喔!
exec/noexec
可執行/不可執行
限制在此檔案系統內是否可以進行『執行』的工作?如果是純粹用來儲存資料的目錄, 那麼可以設定為 noexec 會比較安全。不過,這個參數也不能隨便使用,因為你不知道該目錄下是否預設會有執行檔。
舉例來說,如果你將 noexec 設定在 /var ,當某些軟體將一些執行檔放置於 /var 下時,那就會產生很大的問題喔! 因此,建議這個 noexec 最多僅設定於你自訂或分享的一般資料目錄。
user/nouser
允許/不允許使用者掛載
是否允許使用者使用 mount 指令來掛載呢?一般而言,我們當然不希望一般身份的 user 能使用 mount 囉,因為太不安全了,因此這裡應該要設定為 nouser 囉!
suid/nosuid
具有/不具有 suid 權限
該檔案系統是否允許 SUID 的存在?如果不是執行檔放置目錄,也可以設定為 nosuid 來取消這個功能!
defaults 同時具有 rw, suid, dev, exec, auto, nouser, async 等參數。 基本上,預設情況使用 defaults 設定即可!
  • 第五欄:能否被 dump 備份指令作用:

dump 是一個用來做為備份的指令,不過現在有太多的備份方案了,所以這個項目可以不要理會啦!直接輸入 0 就好了!

  • 第六欄:是否以 fsck 檢驗磁區:

早期開機的流程中,會有一段時間去檢驗本機的檔案系統,看看檔案系統是否完整 (clean)。 不過這個方式使用的主要是透過 fsck 去做的,我們現在用的 xfs 檔案系統就沒有辦法適用,因為 xfs 會自己進行檢驗,不需要額外進行這個動作!所以直接填 0 就好了。

好了,那麼讓我們來處理一下我們的新建的檔案系統,看看能不能開機就掛載呢?

例題:
假設我們要將 /dev/vda4 每次開機都自動掛載到 /data/xfs ,該如何進行?
答:
首先,請用 nano 將底下這一行寫入 /etc/fstab 最後面中;
[root@study ~]# nano /etc/fstab
UUID="e0fa7252-b374-4a06-987a-3cb14f415488"  /data/xfs  xfs  defaults  0 0
再來看看 /dev/vda4 是否已經掛載,如果掛載了,請務必卸載再說!
[root@study ~]# df
Filesystem              1K-blocks    Used Available Use% Mounted on
/dev/vda4                 1038336   32864   1005472   4% /data/xfs
# 竟然不知道何時被掛載了?趕緊給他卸載先!
# 因為,如果要被掛載的檔案系統已經被掛載了(無論掛載在哪個目錄),那測試就不會進行喔!

[root@study ~]# umount /dev/vda4
最後測試一下剛剛我們寫入 /etc/fstab 的語法有沒有錯誤!這點很重要!因為這個檔案如果寫錯了, 則你的 Linux 很可能將無法順利開機完成!所以請務必要測試測試喔!
[root@study ~]# mount -a
[root@study ~]# df /data/xfs
最終有看到 /dev/vda4 被掛載起來的資訊才是成功的掛載了!而且以後每次開機都會順利的將此檔案系統掛載起來的! 現在,你可以下達 reboot 重新開機,然後看一下預設有沒有多一個 /dev/vda4 呢?

/etc/fstab 是開機時的設定檔,不過,實際 filesystem 的掛載是記錄到 /etc/mtab 與 /proc/mounts 這兩個檔案當中的。每次我們在更動 filesystem 的掛載時,也會同時更動這兩個檔案喔!但是,萬一發生你在 /etc/fstab 輸入的資料錯誤,導致無法順利開機成功,而進入單人維護模式當中,那時候的 / 可是 read only 的狀態,當然你就無法修改 /etc/fstab ,也無法更新 /etc/mtab 囉~那怎麼辦?沒關係,可以利用底下這一招:

[root@study ~]# mount -n -o remount,rw /

7.4.2 特殊裝置 loop 掛載 (映象檔不燒錄就掛載使用)

如果有光碟映像檔,或者是使用檔案作為磁碟的方式時,那就得要使用特別的方法來將他掛載起來,不需要燒錄啦!

  • 掛載光碟/DVD映象檔

想像一下如果今天我們從國家高速網路中心(http://ftp.twaren.net)或者是崑山科大(http://ftp.ksu.edu.tw)下載了 Linux 或者是其他所需光碟/DVD的映象檔後, 難道一定需要燒錄成為光碟才能夠使用該檔案裡面的資料嗎?當然不是啦!我們可以透過 loop 裝置來掛載的!

那要如何掛載呢?鳥哥將整個 CentOS 7.x 的 DVD 映象檔捉到測試機上面,然後利用這個檔案來掛載給大家參考看看囉!

[root@study ~]# ll -h /tmp/CentOS-7.0-1406-x86_64-DVD.iso
-rw-r--r--. 1 root root 3.9G Jul  7  2014 /tmp/CentOS-7.0-1406-x86_64-DVD.iso
# 看到上面的結果吧!這個檔案就是映象檔,檔案非常的大吧!

[root@study ~]# mkdir /data/centos_dvd
[root@study ~]# mount -o loop /tmp/CentOS-7.0-1406-x86_64-DVD.iso /data/centos_dvd
[root@study ~]# df /data/centos_dvd
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/loop0       4050860 4050860         0 100% /data/centos_dvd
# 就是這個項目! .iso 映象檔內的所有資料可以在 /data/centos_dvd 看到!

[root@study ~]# ll /data/centos_dvd
total 607
-rw-r--r--. 1  500  502     14 Jul  5  2014 CentOS_BuildTag <==瞧!就是DVD的內容啊!
drwxr-xr-x. 3  500  502   2048 Jul  4  2014 EFI
-rw-r--r--. 1  500  502    611 Jul  5  2014 EULA
-rw-r--r--. 1  500  502  18009 Jul  5  2014 GPL
drwxr-xr-x. 3  500  502   2048 Jul  4  2014 images
.....(底下省略).....

[root@study ~]# umount /data/centos_dvd/
# 測試完成!記得將資料給他卸載!同時這個映像檔也被鳥哥刪除了...測試機容量不夠大!

非常方便吧!如此一來我們不需要將這個檔案燒錄成為光碟或者是 DVD 就能夠讀取內部的資料了! 換句話說,你也可以在這個檔案內『動手腳』去修改檔案的!這也是為什麼很多映象檔提供後,還得要提供驗證碼 (MD5) 給使用者確認該映象檔沒有問題!

  • 建立大檔案以製作 loop 裝置檔案!

想一想,既然能夠掛載 DVD 的映象檔,那麼我能不能製作出一個大檔案,然後將這個檔案格式化後掛載呢? 好問題!這是個有趣的動作!而且還能夠幫助我們解決很多系統的分割不良的情況呢!舉例來說,如果當初在分割時, 你只有分割出一個根目錄,假設你已經沒有多餘的容量可以進行額外的分割的!偏偏根目錄的容量還很大! 此時你就能夠製作出一個大檔案,然後將這個檔案掛載!如此一來感覺上你就多了一個分割槽囉!用途非常的廣泛啦!

底下我們在 /srv 下建立一個 512MB 左右的大檔案,然後將這個大檔案格式化並且實際掛載來玩一玩! 這樣你會比較清楚鳥哥在講啥!

  • 建立大型檔案

首先,我們得先有一個大的檔案吧!怎麼建立這個大檔案呢?在 Linux 底下我們有一支很好用的程式 dd !他可以用來建立空的檔案喔!詳細的說明請先翻到下一章 壓縮指令的運用 來查閱,這裡鳥哥僅作一個簡單的範例而已。 假設我要建立一個空的檔案在 /srv/loopdev ,那可以這樣做:

[root@study ~]# dd if=/dev/zero of=/srv/loopdev bs=1M count=512
512+0 records in   <==讀入 512 筆資料
512+0 records out  <==輸出 512 筆資料
536870912 bytes (537 MB) copied, 12.3484 seconds, 43.5 MB/s
# 這個指令的簡單意義如下:
# if    是 input file ,輸入檔案。那個 /dev/zero 是會一直輸出 0 的裝置!
# of    是 output file ,將一堆零寫入到後面接的檔案中。
# bs    是每個 block 大小,就像檔案系統那樣的 block 意義;
# count 則是總共幾個 bs 的意思。所以 bs*count 就是這個檔案的容量了!

[root@study ~]# ll -h /srv/loopdev
-rw-r--r--. 1 root root 512M Jun 25 19:46 /srv/loopdev

dd 就好像在疊磚塊一樣,將 512 塊,每塊 1MB 的磚塊堆疊成為一個大檔案 (/srv/loopdev) ! 最終就會出現一個 512MB 的檔案!粉簡單吧!

  • 大型檔案的格式化

預設 xfs 不能夠格式化檔案的,所以要格式化檔案得要加入特別的參數才行喔!讓我們來瞧瞧!

[root@study ~]# mkfs.xfs -f /srv/loopdev
[root@study ~]# blkid /srv/loopdev
/srv/loopdev: UUID="7dd97bd2-4446-48fd-9d23-a8b03ffdd5ee" TYPE="xfs"

其實很簡單啦!所以鳥哥就不輸出格式化的結果了!要注意 UUID 的數值,未來會用到!

  • 掛載

那要如何掛載啊?利用 mount 的特殊參數,那個 -o loop 的參數來處理!

[root@study ~]# mount -o loop UUID="7dd97bd2-4446-48fd-9d23-a8b03ffdd5ee" /mnt
[root@study ~]# df /mnt
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/loop0        520876 26372    494504   6% /mnt

透過這個簡單的方法,感覺上你就可以在原本的分割槽在不更動原有的環境下製作出你想要的分割槽就是了! 這東西很好用的!尤其是想要玩 Linux 上面的『虛擬機器』的話, 也就是以一部 Linux 主機再切割成為數個獨立的主機系統時,類似 VMware 這類的軟體, 在 Linux 上使用 xen 這個軟體,他就可以配合這種 loop device 的檔案類型來進行根目錄的掛載,真的非常有用的喔! ^_^

比較特別的是,CentOS 7.x 越來越聰明了,現在你不需要下達 -o loop 這個選項與參數,它同樣可以被系統掛上來! 連直接輸入 blkid 都會列出這個檔案內部的檔案系統耶!相當有趣!不過,為了考量向下相容性,鳥哥還是建議你加上 loop 比較妥當喔! 現在,請將這個檔案系統永遠的自動掛載起來吧!

[root@study ~]# nano /etc/fstab
/srv/loopdev  /data/file  xfs  defaults,loop   0 0
# 畢竟系統大多僅查詢 block device 去找出 UUID 而已,因此使用檔案建置的 filesystem,
# 最好還是使用原本的檔名來處理,應該比較不容易出現錯誤訊息的!

[root@study ~]# umount /mnt
[root@study ~]# mkdir /data/file
[root@study ~]# mount -a
[root@study ~]# df /data/file
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/loop0        520876 26372    494504   6% /data/file

7.5 記憶體置換空間(swap)之建置

以前的年代因為記憶體不足,因此那個可以暫時將記憶體的程序拿到硬碟中暫放的記憶體置換空間 (swap) 就顯的非常的重要! 否則,如果突然間某支程式用掉你大部分的記憶體,那你的系統恐怕有損毀的情況發生喔!所以,早期在安裝 Linux 之前,大家常常會告訴你: 安裝時一定需要的兩個 partition ,一個是根目錄,另外一個就是 swap(記憶體置換空間)。關於記憶體置換空間的解釋在第三章安裝 Linux 內的磁碟分割時有約略提過,請你自行回頭瞧瞧吧!

一般來說,如果硬體的配備資源足夠的話,那麼 swap 應該不會被我們的系統所使用到, swap 會被利用到的時刻通常就是實體記憶體不足的情況了。從第零章的計算機概論當中,我們知道 CPU 所讀取的資料都來自於記憶體, 那當記憶體不足的時候,為了讓後續的程式可以順利的運作,因此在記憶體中暫不使用的程式與資料就會被挪到 swap 中了。 此時記憶體就會空出來給需要執行的程式載入。由於 swap 是用磁碟來暫時放置記憶體中的資訊,所以用到 swap 時,你的主機磁碟燈就會開始閃個不停啊!

雖然目前(2015)主機的記憶體都很大,至少都有 4GB 以上囉!因此在個人使用上,你不要設定 swap 在你的 Linux 應該也沒有什麼太大的問題。 不過伺服器可就不這麼想了~由於你不會知道何時會有大量來自網路的要求,因此最好還是能夠預留一些 swap 來緩衝一下系統的記憶體用量! 至少達到『備而不用』的地步啊!

現在想像一個情況,你已經將系統建立起來了,此時卻才發現你沒有建置 swap ~那該如何是好呢? 透過本章上面談到的方法,你可以使用如下的方式來建立你的 swap 囉!

  • 設定一個 swap partition
  • 建立一個虛擬記憶體的檔案

不囉唆,就立刻來處理處理吧!

7.5.1 使用實體分割槽建置swap

建立 swap 分割槽的方式也是非常的簡單的!透過底下幾個步驟就搞定囉:

  1. 分割:先使用 gdisk 在你的磁碟中分割出一個分割槽給系統作為 swap 。由於 Linux 的 gdisk 預設會將分割槽的 ID 設定為 Linux 的檔案系統,所以你可能還得要設定一下 system ID 就是了。
  2. 格式化:利用建立 swap 格式的『mkswap 裝置檔名』就能夠格式化該分割槽成為 swap 格式囉
  3. 使用:最後將該 swap 裝置啟動,方法為:『swapon 裝置檔名』。
  4. 觀察:最終透過 free 與 swapon -s 這個指令來觀察一下記憶體的用量吧!

不囉唆,立刻來實作看看!既然我們還有多餘的磁碟容量可以分割,那麼讓我們繼續分割出 512MB 的磁碟分割槽吧! 然後將這個磁碟分割槽做成 swap 吧!

  • 1. 先進行分割的行為囉!
[root@study ~]# gdisk /dev/vda
Command (? for help): n
Partition number (6-128, default 6):
First sector (34-83886046, default = 69220352) or {+-}size{KMGTP}:
Last sector (69220352-83886046, default = 83886046) or {+-}size{KMGTP}: +512M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 8200
Changed type of partition to 'Linux swap'

Command (? for help): p
Number  Start (sector)    End (sector)  Size       Code  Name
   6        69220352        70268927   512.0 MiB   8200  Linux swap  # 重點就是產生這東西!

Command (? for help): w

Do you want to proceed? (Y/N): y

[root@study ~]# partprobe
[root@study ~]# lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vda             252:0    0   40G  0 disk
.....(中間省略).....
`-vda6          252:6    0  512M  0 part   # 確定這裡是存在的才行!
# 鳥哥有簡化輸出喔!結果可以看到我們多了一個 /dev/vda6 可以使用於 swap 喔!
  • 2. 開始建置 swap 格式
[root@study ~]# mkswap /dev/vda6
Setting up swapspace version 1, size = 524284 KiB
no label, UUID=6b17e4ab-9bf9-43d6-88a0-73ab47855f9d
[root@study ~]# blkid /dev/vda6
/dev/vda6: UUID="6b17e4ab-9bf9-43d6-88a0-73ab47855f9d" TYPE="swap"
# 確定格式化成功!且使用 blkid 確實可以抓到這個裝置了喔!
  • 3. 開始觀察與載入看看吧!
[root@study ~]# free
              total        used        free      shared  buff/cache   available
Mem:        1275140      227244      330124        7804      717772      875536  # 實體記憶體
Swap:       1048572      101340      947232                                      # swap 相關
# 我有 1275140K 的實體記憶體,使用 227244K 剩餘 330124K ,使用掉的記憶體有
# 717772K 用在緩衝/快取的用途中。至於 swap 已經有 1048572K 囉!這樣會看了吧?!

[root@study ~]# swapon /dev/vda6
[root@study ~]# free
              total        used        free      shared  buff/cache   available
Mem:        1275140      227940      329256        7804      717944      874752
Swap:       1572856      101260     1471596   <==有看到增加了沒?

[root@study ~]# swapon -s
Filename                 Type            Size    Used    Priority
/dev/dm-1                partition       1048572 101260  -1
/dev/vda6                partition       524284  0       -2
# 上面列出目前使用的 swap 裝置有哪些的意思!

[root@study ~]# nano /etc/fstab
UUID="6b17e4ab-9bf9-43d6-88a0-73ab47855f9d"  swap  swap  defaults  0  0
# 當然要寫入設定檔,只不過不是檔案系統,所以沒有掛載點!第二個欄位寫入 swap 即可。

7.5.2 使用檔案建置swap

如果是在實體分割槽無法支援的環境下,此時前一小節提到的 loop 裝置建置方法就派的上用場啦! 與實體分割槽不一樣的,這個方法只是利用 dd 去建置一個大檔案而已。多說無益,我們就再透過檔案建置的方法建立一個 128 MB 的記憶體置換空間吧!

  • 1. 使用 dd 這個指令來新增一個 128MB 的檔案在 /tmp 底下:
[root@study ~]# dd if=/dev/zero of=/tmp/swap bs=1M count=128
128+0 records in
128+0 records out
134217728 bytes (134 MB) copied, 1.7066 seconds, 78.6 MB/s

[root@study ~]# ll -h /tmp/swap
-rw-r--r--. 1 root root 128M Jun 26 17:47 /tmp/swap

這樣一個 128MB 的檔案就建置妥當。若忘記上述的各項參數的意義,請回前一小節查閱一下囉!

  • 2. 使用 mkswap 將 /tmp/swap 這個檔案格式化為 swap 的檔案格式:
[root@study ~]# mkswap /tmp/swap
Setting up swapspace version 1, size = 131068 KiB
no label, UUID=4746c8ce-3f73-4f83-b883-33b12fa7337c
# 這個指令下達時請『特別小心』,因為下錯字元控制,將可能使您的檔案系統掛掉!
  • 3. 使用 swapon 來將 /tmp/swap 啟動囉!
[root@study ~]# swapon /tmp/swap
[root@study ~]# swapon -s
Filename            Type            Size    Used    Priority
/dev/dm-1           partition       1048572 100380  -1
/dev/vda6           partition       524284  0       -2
/tmp/swap           file            131068  0       -3
  • 4. 使用 swapoff 關掉 swap file,並設定自動啟用
[root@study ~]# nano /etc/fstab
/tmp/swap  swap  swap  defaults  0  0
# 為何這裡不要使用 UUID 呢?這是因為系統僅會查詢區塊裝置 (block device) 不會查詢檔案!
# 所以,這裡千萬不要使用 UUID,不然系統會查不到喔!

[root@study ~]# swapoff /tmp/swap /dev/vda6
[root@study ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-1                               partition       1048572 100380  -1
# 確定已經回復到原本的狀態了!然後準備來測試!!

[root@study ~]# swapon -a
[root@study ~]# swapon -s
# 最終你又會看正確的三個 swap 出現囉!這也才確定你的 /etc/fstab 設定無誤!

說實話,swap 在目前的桌上型電腦來講,存在的意義已經不大了!這是因為目前的 x86 主機所含的記憶體實在都太大了 (一般入門級至少也都有 4GB 了),所以,我們的 Linux 系統大概都用不到 swap 這個玩意兒的。不過, 如果是針對伺服器或者是工作站這些常年上線的系統來說的話,那麼,無論如何,swap 還是需要建立的。

因為 swap 主要的功能是當實體記憶體不夠時,則某些在記憶體當中所佔的程式會暫時被移動到 swap 當中,讓實體記憶體可以被需要的程式來使用。另外,如果你的主機支援電源管理模式, 也就是說,你的 Linux 主機系統可以進入『休眠』模式的話,那麼, 運作當中的程式狀態則會被紀錄到 swap 去,以作為『喚醒』主機的狀態依據! 另外,有某些程式在運作時,本來就會利用 swap 的特性來存放一些資料段, 所以, swap 來是需要建立的!只是不需要太大!

7.6 檔案系統的特殊觀察與操作

檔案系統實在是非常有趣的東西,鳥哥學了好幾年還是很多東西不很懂呢!在學習的過程中很多朋友在討論區都有提供一些想法! 這些想法將他歸納起來有底下幾點可以參考的資料呢!

7.6.1 磁碟空間之浪費問題

我們在前面的 EXT2 data block 介紹中談到了一個 block 只能放置一個檔案, 因此太多小檔案將會浪費非常多的磁碟容量。但你有沒有注意到,整個檔案系統中包括 superblock, inode table 與其他中介資料等其實都會浪費磁碟容量喔!所以當我們在 /dev/vda4, /dev/vda5 建立起 xfs/ext4 檔案系統時, 一掛載就立刻有很多容量被用掉了!

另外,不知道你有沒有發現到,當你使用 ls -l 去查詢某個目錄下的資料時,第一行都會出現一個『total』的字樣! 那是啥東西?其實那就是該目錄下的所有資料所耗用的實際 block 數量 * block 大小的值。 我們可以透過 ll -s 來觀察看看上述的意義:

[root@study ~]# ll -sh
total 12K
4.0K -rw-------. 1 root root 1.8K May  4 17:57 anaconda-ks.cfg
4.0K -rw-r--r--. 2 root root  451 Jun 10  2014 crontab
   0 lrwxrwxrwx. 1 root root   12 Jun 23 22:31 crontab2 -> /etc/crontab
4.0K -rw-r--r--. 1 root root 1.9K May  4 18:01 initial-setup-ks.cfg
   0 -rw-r--r--. 1 root root    0 Jun 16 01:11 test1
   0 drwxr-xr-x. 2 root root    6 Jun 16 01:11 test2
   0 -rw-rw-r--. 1 root root    0 Jun 16 01:12 test3
   0 drwxrwxr-x. 2 root root    6 Jun 16 01:12 test4

從上面的特殊字體部分,那就是每個檔案所使用掉 block 的容量!舉例來說,那個 crontab 雖然僅有 451bytes , 不過他卻佔用了整個 block (每個 block 為 4K),所以將所有的檔案的所有的 block 加總就得到 12Kbytes 那個數值了。 如果計算每個檔案實際容量的加總結果,其實只有不到 5K 而已~所以囉,這樣就耗費掉好多容量了!未來大家在討論小磁碟、 大磁碟,檔案容量的損耗時,要回想到這個區塊喔! ^_^

7.6.2 利用 GNU 的 parted 進行分割行為(Optional)

雖然你可以使用 gdisk/fdisk 很快速的將你的分割槽切割妥當,不過 gdisk 主要針對 GPT 而 fdisk 主要支援 MBR ,對 GPT 的支援還不夠! 所以使用不同的分割時,得要先查詢到正確的分割表才能用適合的指令,好麻煩!有沒有同時支援的指令呢?有的!那就是 parted 囉!

Tips 鳥哥 老實說,若不是後來有推出支援 GPT 的 gdisk,鳥哥其實已經愛用 parted 來進行分割行為了!雖然很多指令都需要同時開一個終端機去查 man page, 不過至少所有的分割表都能夠支援哩! ^_^

parted 可以直接在一行指令列就完成分割,是一個非常好用的指令!它常用的語法如下:

[root@study ~]# parted [裝置] [指令 [參數]]
選項與參數:
指令功能:
          新增分割:mkpart [primary|logical|extended] [ext4|vfat|xfs] 開始 結束
          顯示分割:print
          刪除分割:rm [partition]

範例一:以 parted 列出目前本機的分割表資料
[root@study ~]# parted /dev/vda print
Model: Virtio Block Device (virtblk)         <==磁碟介面與型號
Disk /dev/vda: 42.9GB                        <==磁碟檔名與容量
Sector size (logical/physical): 512B/512B    <==每個磁區的大小
Partition Table: gpt                         <==是 GPT 還是 MBR 分割
Disk Flags: pmbr_boot

Number  Start   End     Size    File system     Name                  Flags
 1      1049kB  3146kB  2097kB                                        bios_grub
 2      3146kB  1077MB  1074MB  xfs
 3      1077MB  33.3GB  32.2GB                                        lvm
 4      33.3GB  34.4GB  1074MB  xfs             Linux filesystem
 5      34.4GB  35.4GB  1074MB  ext4            Microsoft basic data
 6      35.4GB  36.0GB  537MB   linux-swap(v1)  Linux swap
[  1 ]  [  2 ]  [  3  ] [  4  ] [  5  ]         [  6  ]

上面是最簡單的 parted 指令功能簡介,你可以使用『 man parted 』,或者是『 parted /dev/vda help mkpart 』去查詢更詳細的資料。比較有趣的地方在於分割表的輸出。我們將上述的分割表示意拆成六部分來說明:

  1. Number:這個就是分割槽的號碼啦!舉例來說,1號代表的是 /dev/vda1 的意思;
  2. Start:分割的起始位置在這顆磁碟的多少 MB 處?有趣吧!他以容量作為單位喔!
  3. End:此分割的結束位置在這顆磁碟的多少 MB 處?
  4. Size:由上述兩者的分析,得到這個分割槽有多少容量;
  5. File system:分析可能的檔案系統類型為何的意思!
  6. Name:就如同 gdisk 的 System ID 之意。

不過 start 與 end 的單位竟然不一致!好煩~如果你想要固定單位,例如都用 MB 顯示的話,可以這樣做:

[root@study ~]# parted /dev/vda unit mb print

如果你想要將原本的 MBR 改成 GPT 分割表,或原本的 GPT 分割表改成 MBR 分割表,也能使用 parted ! 但是請不要使用 vda 來測試!因為分割表格式不能轉換!因此進行底下的測試後,在該磁碟的系統應該是會損毀的! 所以鳥哥拿一顆沒有使用的隨身碟來測試,所以檔名會變成 /dev/sda 喔!再講一次!不要惡搞喔!

範例二:將 /dev/sda 這個原本的 MBR 分割表變成 GPT 分割表!(危險!危險!勿亂搞!無法復原!)
[root@study ~]# parted /dev/sda print
Model: ATA QEMU HARDDISK (scsi)
Disk /dev/sda: 2148MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos    # 確實顯示的是 MBR 的 msdos 格式喔!

[root@study ~]# parted /dev/sda mklabel gpt
Warning: The existing disk label on /dev/sda will be destroyed and all data on 
this disk will be lost. Do you want to continue?
Yes/No? y

[root@study ~]# parted /dev/sda print
# 你應該就會看到變成 gpt 的模樣!只是...後續的分割就全部都死掉了!

接下來我們嘗試來建立一個全新的分割槽吧!再次的建立一個 512MB 的分割來格式化為 vfat,且掛載於 /data/win 喔!

範例三:建立一個約為 512MB 容量的分割槽
[root@study ~]# parted /dev/vda print
.....(前面省略).....
Number  Start   End     Size    File system     Name                  Flags
.....(中間省略).....
 6      35.4GB  36.0GB  537MB   linux-swap(v1)  Linux swap  # 要先找出來下一個分割的起始點!

[root@study ~]# parted /dev/vda mkpart primary fat32 36.0GB 36.5GB
# 由於新的分割的起始點在前一個分割的後面,所以當然要先找出前面那個分割的 End 位置!
# 然後再請參考 mkpart 的指令功能,就能夠處理好相關的動作!
[root@study ~]# parted /dev/vda print
.....(前面省略).....
Number  Start   End     Size    File system     Name                  Flags
 7      36.0GB  36.5GB  522MB                   primary

[root@study ~]# partprobe
[root@study ~]# lsblk /dev/vda7
NAME MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vda7 252:7    0  498M  0 part      # 要確定它是真的存在才行!

[root@study ~]# mkfs -t vfat /dev/vda7
[root@study ~]# blkid /dev/vda7
/dev/vda7: SEC_TYPE="msdos" UUID="6032-BF38" TYPE="vfat"

[root@study ~]# nano /etc/fstab
UUID="6032-BF38"  /data/win  vfat  defaults   0  0

[root@study ~]# mkdir /data/win
[root@study ~]# mount -a
[root@study ~]# df /data/win
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/vda7         509672     0    509672   0% /data/win

事實上,你應該使用 gdisk 來處理 GPT 分割就好了!不過,某些特殊時刻,例如你要自己寫一隻腳本,讓你的分割全部一口氣建立, 不需要 gdisk 一條一條指令去進行時,那麼 parted 就非常有效果了!因為他可以直接進行 partition 而不需要跟用戶互動!這就是它的最大好處! 鳥哥還是建議,至少你要操作過幾次 parted ,知道這傢伙的用途!未來有需要再回來查!或使用 man parted 去處理喔!

7.7 重點回顧

  • 一個可以被掛載的資料通常稱為『檔案系統, filesystem』而不是分割槽 (partition) 喔!
  • 基本上 Linux 的傳統檔案系統為 Ext2 ,該檔案系統內的資訊主要有:
    • superblock:記錄此 filesystem 的整體資訊,包括inode/block的總量、使用量、剩餘量, 以及檔案系統的格式與相關資訊等;
    • inode:記錄檔案的屬性,一個檔案佔用一個inode,同時記錄此檔案的資料所在的 block 號碼;
    • block:實際記錄檔案的內容,若檔案太大時,會佔用多個 block 。
  • Ext2 檔案系統的資料存取為索引式檔案系統(indexed allocation)
  • 需要磁碟重組的原因就是檔案寫入的 block 太過於離散了,此時檔案讀取的效能將會變的很差所致。 這個時候可以透過磁碟重組將同一個檔案所屬的 blocks 彙整在一起。
  • Ext2檔案系統主要有:boot sector, superblock, inode bitmap, block bitmap, inode table, data block 等六大部分。
  • data block 是用來放置檔案內容資料地方,在 Ext2 檔案系統中所支援的 block 大小有 1K, 2K 及 4K 三種而已
  • inode 記錄檔案的屬性/權限等資料,其他重要項目為: 每個 inode 大小均為固定,有 128/256bytes 兩種基本容量。每個檔案都僅會佔用一個 inode 而已; 因此檔案系統能夠建立的檔案數量與 inode 的數量有關;
  • 檔案的 block 在記錄檔案的實際資料,目錄的 block 則在記錄該目錄底下檔名與其 inode 號碼的對照表;
  • 日誌式檔案系統 (journal) 會多出一塊記錄區,隨時記載檔案系統的主要活動,可加快系統復原時間;
  • Linux 檔案系統為增加效能,會讓主記憶體作為大量的磁碟快取;
  • 實體連結只是多了一個檔名對該 inode 號碼的連結而已;
  • 符號連結就類似Windows的捷徑功能。
  • 磁碟的使用必需要經過:分割、格式化與掛載,分別慣用的指令為:gdisk, mkfs, mount三個指令
  • 分割時,應使用 parted 檢查分割表格式,再判斷使用 fdisk/gdisk 來分割,或直接使用 parted 分割
  • 為了考慮效能,XFS 檔案系統格式化時,可以考慮加上 agcount/su/sw/extsize 等參數較佳
  • 如果磁碟已無未分割的容量,可以考慮使用大型檔案取代磁碟裝置的處理方式,透過 dd 與格式化功能。
  • 開機自動掛載可參考/etc/fstab之設定,設定完畢務必使用 mount -a 測試語法正確否;

7.8 本章習題 - 第一題一定要做

( 要看答案請將滑鼠移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看 )
  • 情境模擬題一:復原本章的各例題練習,本章新增非常多 partition ,請將這些 partition 刪除,恢復到原本剛安裝好時的狀態。

    • 目標:瞭解到刪除分割槽需要注意的各項資訊;
    • 前提:本章的各項範例練習你都必須要做過,才會擁有 /dev/vda4 ~ /dev/vda7 出現;
    • 需求:熟悉 gdisk, parated, umount, swapoff 等指令。

    由於本章處理完畢後,將會有許多新增的 partition ,所以請刪除掉這兩個 partition 。刪除的過程需要注意的是:

    1. 需先以 free / swapon -s / mount 等指令查閱,要被處理的檔案系統不可以被使用! 如果有被使用,則你必須要使用 umount 卸載檔案系統。如果是記憶體置換空間,則需使用 swapon -s 找出被使用的分割槽, 再以 swapoff 去卸載他!
      [root@study ~]# umount /data/ext4 /data/xfs /data/file /data/win
      [root@study ~]# swapoff /dev/vda6 /tmp/swap
      
    2. 觀察 /etc/fstab ,該檔案新增的行全部刪除或註解!
      [root@study ~]# nano /etc/fstab
      .....(前面省略).....
      /dev/mapper/centos-swap swap                 swap    defaults        0 0  # 從這行之後全刪除
      UUID="e0fa7252-b374-4a06-987a-3cb14f415488"  /data/xfs  xfs   defaults      0 0
      /srv/loopdev                                 /data/file xfs   defaults,loop 0 0
      UUID="6b17e4ab-9bf9-43d6-88a0-73ab47855f9d"  swap       swap  defaults      0 0
      /tmp/swap                                    swap       swap  defaults      0 0
      UUID="6032-BF38"                             /data/win  vfat  defaults      0 0
      
    3. 使用『 gdisk /dev/vda 』刪除,也可以使用『 parted /dev/vda rm 號碼』刪除喔!
      [root@study ~]# parted /dev/vda rm 7
      [root@study ~]# parted /dev/vda rm 6
      [root@study ~]# parted /dev/vda rm 5
      [root@study ~]# parted /dev/vda rm 4
      [root@study ~]# partprobe
      [root@study ~]# rm /tmp/swap /srv/loopdev
      

  • 情境模擬題二:由於我的系統原本分割的不夠好,我的用戶希望能夠獨立一個 filesystem 附掛在 /srv/myproject 目錄下。 那你該如何建立新的 filesystem ,並且讓這個 filesystem 每次開機都能夠自動的掛載到 /srv/myproject , 且該目錄是給 project 這個群組共用的,其他人不可具有任何權限。且該 filesystem 具有 1GB 的容量。

    • 目標:理解檔案系統的建置、自動掛載檔案系統與專案開發必須要的權限;
    • 前提:你需要進行過第六章的情境模擬才可以繼續本章;
    • 需求:本章的所有概念必須要清楚!

    那就讓我們開始來處理這個流程吧!

    1. 首先,我們必須要使用 gdisk /dev/vda 來建立新的 partition。 然後按下『 n 』,按下『Enter』選擇預設的分割槽號碼,再按『Enter』選擇預設的啟始磁柱, 按下『+1G』建立 1GB 的磁碟分割槽,再按下『Enter』選擇預設的檔案系統 ID。 可以多按一次『p 』看看是否正確,若無問題則按下『w』寫入分割表;

    2. 避免重新開機,因此使用『 partprobe 』強制核心更新分割表;

    3. 建立完畢後,開始進行格式化的動作如下:『mkfs.xfs -f /dev/vda4』,這樣就 OK 了!

    4. 開始建立掛載點,利用:『 mkdir /srv/myproject 』來建立即可;

    5. 編寫自動掛載的設定檔:『 nano /etc/fstab 』,這個檔案最底下新增一行,內容如下:
      /dev/vda4 /srv/myproject xfs defaults 0 0

    6. 測試自動掛載:『 mount -a 』,然後使用『 df /srv/myproject 』觀察看看有無掛載即可!

    7. 設定最後的權限,使用:『 chgrp project /srv/myproject 』以及『 chmod 2770 /srv/myproject 』即可。

簡答題部分:
  • 我們常常說,開機的時候,『發現磁碟有問題』,請問,這個問題的產生是『filesystem 的損毀』,還是『磁碟的損毀』?
    特別需要注意的是,如果您某個 filesystem 裡面,由於操作不當,可能會造成 Superblock 資料的損毀, 或者是 inode 的架構損毀,或者是 block area 的記錄遺失等等,這些問題當中,其實您的『磁碟』還是好好的, 不過,在磁碟上面的『檔案系統』則已經無法再利用!一般來說,我們的 Linux 很少會造成 filesystem 的損毀, 所以,發生問題時,很可能整個磁碟都損毀了。但是,如果您的主機常常不正常斷電,那麼, 很可能磁碟是沒問題的,但是,檔案系統則有損毀之虞。此時,重建檔案系統 (reinstall) 即可! 不需要換掉磁碟啦! ^_^
  • 當我有兩個檔案,分別是 file1 與 file2 ,這兩個檔案互為 hard link 的檔案,請問, 若我將 file1 刪除,然後再以類似 vi 的方式重新建立一個名為 file1 的檔案, 則 file2 的內容是否會被更動?
    這是來自網友的疑問。當我刪除 file1 之後, file2 則為一個正規檔案,並不會與他人共同分享同一個 inode 與 block ,因此,當我重新建立一個檔名為 file1 時,他所利用的 inode 與 block 都是由我們的 filesystem 主動去搜尋 meta data ,找到空的 inode 與 block 來建立的, 與原本的 file1 並沒有任何關連性喔!所以,新建的 file1 並不會影響 file2 呢!

7.9 參考資料與延伸閱讀

修改歷史:
  • 2002/07/15:第一次完成
  • 2003/02/07:重新編排與加入 FAQ
  • 2004/03/15:修改 inode 的說明,並且將連結檔的說明移動至這個章節當中!
  • 2005/07/20:將舊的文章移動到 這裡
  • 2005/07/22:將原本的附錄一與附錄二移動成為附錄 B 啦!
  • 2005/07/26:做了一個比較完整的修訂,加入較完整的 ext3 的說明~
  • 2005/09/08:看到了一篇討論,說明 FC4 在預設的環境中,使用 mkswap 會有問題。
  • 2005/10/11:新增加了一個目錄的 link 數量說明!
  • 2005/11/11:增加了一個 fsck 的 -f 參數在裡頭!
  • 2006/03/02:參考:這裡的說明,將 ext2/ext3 最大檔案系統由 16TB 改為 32TB。
  • 2006/03/31:增加了虛擬記憶體的相關說明在 這裡
  • 2006/05/01:將磁碟磁區的圖做個修正,感謝網友 LiaoLiang 兄提供的資訊!並加入參考文獻!
  • 2006/06/09:增加 hard link 不能連結到目錄的原因,詳情參考:http://phorum.study-area.org/viewtopic.php?t=12235
  • 2006/06/28:增加關於 loop device 的相關說明吶!
  • 2006/09/08:加入 mknod 內的裝置代號說明 ,以及列出 Linux 核心網站的裝置代號查詢。
  • 2008/09/29:原本的FC4系列文章移動到此處
  • 2008/10/24:由於軟碟的使用已經越來越少了,所以將 fdformat 及 mkbootdisk 拿掉了!
  • 2008/10/31:這個月事情好多~花了一個月才將資料整理完畢!修改幅度非常的大喔!
  • 2008/11/01:最後一節的利用 GNU 的 parted 進行分割行為誤植為 GUN !感謝網友阿賢的來信告知!
  • 2008/12/05:感謝網友 ian_chen 的告知,之前將 flash 當成 flush 了!真抱歉!已更新!
  • 2009/04/01:感謝討論區網友提供的說明, 鳥哥之前 superblock 這裡寫得不夠好,有訂正說明,請幫忙看看。
  • 2009/08/19:加入兩題情境模擬,重新修訂一題簡答題。
  • 2009/08/30:加入 du 的 -S 說明中。
  • 2015/06/17:將舊的基於 CentOS5 的版本移動到這裡
  • 2015/10/26:加上 noexec 的額外說明!感謝網友在討論區的建議!
  • 2017/09/04:許多朋友都發現這個錯誤,就是 hardlink 不要 link 目錄的解釋怪怪的~今天終於修改了一下!不好意思啊!
2002/06/26以來統計人數
計數器
其他連結
環境工程模式篇
鳥園討論區
鳥哥舊站

今日 人數統計
昨日 人數統計
本月 人數統計
上月 人數統計