章節概述#

本章深入探討 Linux 系統中磁碟與檔案系統的運作方式。涵蓋磁碟分割 (partitioning)、檔案系統的建立與維護、swap space 的使用,以及 Logical Volume Manager (LVM) 的原理與操作。最後介紹傳統 Unix 檔案系統的內部結構,包含 inode 與 block allocation。

Linux 磁碟裝置的名稱如 /dev/sda,代表整顆磁碟的 block device。磁碟內部包含多個層次:partition table 定義分割區的位置,每個 partition 內含 filesystem data structures 與實際的檔案資料。

Figure 4-1: Typical Linux disk schematic

4.1 磁碟分割 (Partitioning Disk Devices)#

Partition Table 的類型#

磁碟上的 partition table 記載了磁碟區塊的劃分方式,主要有兩種:

  • MBR (Master Boot Record):傳統的分割表格式,源自 PC 時代,有許多限制
  • GPT (Globally Unique Identifier Partition Table):較新的標準,為現代系統所採用

常見的分割工具:

  • parted:文字介面工具,同時支援 MBR 與 GPT
  • gparted:parted 的圖形介面版本
  • fdisk:傳統的文字介面分割工具,近期版本支援 MBR、GPT 等多種格式

分割 (partitioning) 與檔案系統操作有本質上的差異:partition table 定義的是磁碟上的簡單邊界,而 filesystem 則是更複雜的資料系統。因此兩者使用不同的工具。

4.1.1 檢視 Partition Table#

使用 parted -l 可以檢視系統上的 partition table:

# parted -l

輸出會顯示每顆磁碟的型號、大小、partition table 類型(msdos 代表 MBR,gpt 代表 GPT),以及各分割區的編號、起始位置、大小、類型與檔案系統。

MBR 基本概念:

  • Primary partition:磁碟的一般子分割,MBR 最多支援 4 個
  • Extended partition:當需要超過 4 個分割區時,將其中一個指定為 extended partition
  • Logical partition:在 extended partition 內建立的分割區

4.1.2 修改 Partition Table#

修改分割表時需注意:

  • 變更 partition table 會使被刪除或重新定義的分割區上的資料難以復原
  • 確保目標磁碟上沒有正在使用的分割區

修改分割表前,務必確認磁碟上的重要資料已備份。刪除或重新定義分割區會清除其上的檔案系統位置資訊。

fdisk 與 parted 的關鍵差異:

  • fdisk:先設計好新的 partition table,退出時才寫入磁碟,可用 q 放棄變更
  • parted:指令執行時立即修改分割區,無法事後檢視再決定

修改後可透過以下方式確認核心已偵測到變更:

udevadm monitor --kernel
cat /proc/partitions

4.1.3 建立 Partition Table#

使用 fdisk 建立分割表的互動式流程:

# fdisk /dev/sdd

常用指令:

  • p:印出目前的 partition table
  • d:刪除分割區
  • n:建立新分割區
  • w:寫入變更並退出
  • q:放棄變更並退出

4.1.4 磁碟與分割區的幾何結構#

傳統硬碟由旋轉的 platter 與讀寫 head 組成,磁碟幾何結構稱為 CHS (Cylinder-Head-Sector)。但在現代硬碟上,CHS 的值是虛構的。

Figure 4-3: Top-down view of a hard disk

  • 現代磁碟使用 LBA (Logical Block Addressing) 以 block number 定址,較 CHS 直觀
  • 舊式的 cylinder boundary 對齊已不再重要,現代分割工具會自動合理配置

4.1.5 SSD 的讀取特性#

SSD (Solid-State Disk) 沒有機械零件,隨機存取不是問題。但 partition alignment 對 SSD 效能影響重大:

  • SSD 以 pages(4,096 或 8,192 bytes)為單位讀取資料
  • 若分割區未對齊 page 邊界,小型操作可能需要兩次讀取
  • 現代分割工具會自動在 1MB 邊界對齊,無需手動計算

可透過 /sys/block 確認分割區的起始位置:

$ cat /sys/block/sdf/sdf2/start

4.2 檔案系統 (Filesystems)#

Figure 4-2: Kernel schematic for disk access

Filesystem 是 kernel 與 user space 之間操作磁碟的最後一層連結。它將簡單的 block device 轉換為使用者熟悉的檔案與目錄階層結構。

  • VFS (Virtual File System) 抽象層確保所有檔案系統實作都支援統一的標準介面
  • FUSE (File System in User Space) 允許在 user space 實作檔案系統

4.2.1 檔案系統類型#

Linux 支援的常見檔案系統:

  • ext4 (Fourth Extended Filesystem):Linux 原生檔案系統的主力,支援大檔案與大量子目錄
  • ext2/ext3:較舊版本,ext3 加入了 journal 功能
  • Btrfs (B-tree Filesystem):Linux 原生的新一代檔案系統,設計上超越 ext4
  • FAT filesystems (msdos, vfat, exfat):與 Microsoft 系統相關,常見於 USB 隨身碟與 SD 卡
  • XFS:高效能檔案系統,Red Hat Enterprise Linux 7+ 的預設選擇
  • HFS+ (hfsplus):Apple 的標準
  • ISO 9660 (iso9660):CD-ROM 標準

4.2.2 建立檔案系統#

使用 mkfs 建立檔案系統:

# mkfs -t ext4 /dev/sdf2
  • mkfs 實際上是各檔案系統建立程式的前端(例如 mkfs.ext4mke2fs 的 symbolic link)
  • 建立時會輸出 superblock 備份位置等診斷資訊,建議記錄下來以備不時之需

只在新增磁碟或重新分割後才應建立檔案系統。對已有資料的分割區建立新檔案系統會摧毀原有資料。

4.2.3 掛載檔案系統 (Mounting)#

在 Unix 中,將檔案系統附加到運行中系統的過程稱為 mounting。掛載需要知道:

  • 檔案系統的裝置、位置或識別碼
  • 檔案系統類型
  • Mount point:目錄階層中附加檔案系統的位置
# mount -t ext4 /dev/sdf2 /home/extra
# umount /home/extra

使用 mount 不帶參數可檢視目前所有已掛載的檔案系統。

4.2.4 Filesystem UUID#

裝置名稱可能因 kernel 偵測順序而改變,因此可使用 UUID (Universally Unique Identifier) 來識別檔案系統:

# blkid

以 UUID 掛載檔案系統:

# mount UUID=b600fe63-d2e9-461c-a5cd-d3b373a5e1d2 /home/extra

UUID 是 /etc/fstab 中掛載 non-LVM 檔案系統的首選方式。許多發行版在插入可移除媒體時也使用 UUID 作為掛載點。

4.2.5 磁碟緩衝、快取與檔案系統#

Linux kernel 會 buffer 寫入操作,將變更暫存在 RAM 中,待適當時機再寫入磁碟,這提供了顯著的效能提升。

  • umount 時 kernel 會自動 sync(同步)緩衝區的資料到磁碟
  • 可隨時執行 sync 指令強制同步
  • kernel 也會 cache 磁碟讀取的 block,減少重複讀取

4.2.6 檔案系統掛載選項#

mount 指令支援許多選項,分為 general optionsfilesystem-specific options

短選項:

  • -r:唯讀模式掛載
  • -n:不更新系統掛載資料庫 /etc/mtab
  • -t type:指定檔案系統類型

長選項(透過 -o 指定):

  • exec / noexec:啟用或停用程式執行
  • suid / nosuid:啟用或停用 setuid
  • ro / rw:唯讀或讀寫模式
# mount -t vfat /dev/sde1 /dos -o ro,uid=1000

4.2.7 重新掛載檔案系統#

常見情境是將唯讀的根目錄重新掛載為讀寫模式:

# mount -n -o remount /

4.2.8 /etc/fstab 檔案系統表#

/etc/fstab 是一個純文字檔,記錄系統開機時自動掛載的檔案系統清單。每行有六個欄位:

  1. 裝置或 UUID
  2. Mount point
  3. 檔案系統類型
  4. 掛載選項(以逗號分隔)
  5. dump 備份資訊(已過時,設為 0)
  6. fsck 檢查順序(根目錄設 1,其他設 2,不檢查設 0)

常見的 fstab 選項:defaultserrorsnoautouser

# mount -a   # 掛載 fstab 中所有未標記 noauto 的項目

4.2.9 /etc/fstab 的替代方案#

  • /etc/fstab.d 目錄:每個檔案系統一個設定檔
  • systemd units:將檔案系統設定為 systemd 的 mount unit(通常由 /etc/fstab 生成)

4.2.10 檔案系統容量#

使用 df 檢視已掛載檔案系統的容量與使用狀況:

$ df
  • 容量數字可能看起來不合理,因為有 5% 的空間被保留為 reserved blocks,僅 superuser 可使用
  • 使用 du 可查看目錄的磁碟使用量:
$ du -s *

4.2.11 檢查與修復檔案系統#

fsck 工具用於檢查檔案系統完整性。對 ext2/ext3/ext4 系列,fsck 會偵測類型並呼叫 e2fsck

# fsck /dev/sdb1

絕對不要在已掛載的檔案系統上執行 fsck,否則可能導致系統崩潰與檔案損毀。唯一例外是在 single-user mode 下以唯讀方式掛載的根分割區。

fsck 的運作:

  • 手動模式下會逐步報告檢查進度(inodes、directory structure 等)
  • 發現問題時會詢問修復方式
  • -p 選項自動修復一般問題,遇到嚴重錯誤時中止
  • -n 選項僅檢查不修改

ext3/ext4 的 journal 確保資料完整性,通常不需手動檢查。可用以下指令 flush journal:

# e2fsck -fy /dev/disk_device

嚴重損壞時的處理:

  • dd 提取整個檔案系統映像到另一顆磁碟
  • 嘗試用 debugfs 工具瀏覽與複製檔案
  • 最後手段是尋求專業的資料復原服務

4.2.12 特殊用途檔案系統#

並非所有檔案系統都代表實體儲存,有些作為系統介面使用:

  • proc:掛載於 /proc,提供 process 資訊與 kernel/硬體資訊(如 /proc/cpuinfo
  • sysfs:掛載於 /sys
  • tmpfs:掛載於 /run 等位置,使用 RAM 與 swap 作為暫存空間
  • squashfs:唯讀壓縮檔案系統,常用於 snap 套件管理系統
  • overlay:將多個目錄合併為一個,常用於容器 (container) 技術

4.3 Swap Space#

Swap space 用於擴充系統記憶體。當實體 RAM 不足時,Linux 虛擬記憶體系統會自動將閒置程式的記憶體頁面搬移到磁碟上的 swap 區域。

$ free   # 檢視 swap 使用狀況

4.3.1 使用磁碟分割區作為 Swap#

# mkswap /dev/sda5       # 建立 swap signature
# swapon /dev/sda5       # 啟用 swap

/etc/fstab 中加入 swap 項目以便開機自動啟用:

/dev/sda5  none  swap  sw  0  0

4.3.2 使用檔案作為 Swap#

當不想重新分割磁碟時,可用一般檔案作為 swap:

# dd if=/dev/zero of=swap_file bs=1024k count=num_mb
# mkswap swap_file
# swapon swap_file

使用 swapoff 可將 swap 分割區或檔案從活動的 swap pool 中移除。

4.3.3 決定 Swap 大小#

  • 傳統建議是實體 RAM 的兩倍,但在現代系統中未必適用
  • 若頻繁使用 swap,代表系統記憶體不足,效能會嚴重下降
  • 高效能伺服器可能完全不配置 swap,以避免任何磁碟 I/O

在一般用途的機器上不配置 swap 是危險的。若 RAM 與 swap 都耗盡,Linux kernel 會啟動 OOM (Out-of-Memory) killer 強制終止 process 以釋放記憶體。

4.4 Logical Volume Manager (LVM)#

LVM 在實體 block device 與檔案系統之間加入一層抽象,解決了傳統直接分割方式的彈性不足問題。

LVM 的核心概念#

LVM 的三層架構:

Figure 4-4: How PVs and logical volumes fit together in a volume group

  • Physical Volume (PV):實體 block device(通常是磁碟分割區)
  • Volume Group (VG):由一個或多個 PV 組成的通用資料池
  • Logical Volume (LV):從 VG 中劃分出的邏輯分割區,可包含 filesystem 或 swap

LVM 的強大功能:

  • 動態新增 PV 到 VG 以擴充容量
  • 移除 PV(只要剩餘空間足夠容納現有 LV)
  • 調整 LV 大小(並同時調整其上的 filesystem)
  • 以上操作大多不需重開機或卸載檔案系統

4.4.2 操作 LVM#

檢視 Volume Group:

# vgs           # 簡要列表
# vgdisplay     # 詳細資訊

VG 的空間以 Physical Extent (PE) 為單位管理(通常 4MB),類似 block 但更大。

檢視 Logical Volume:

# lvs           # 簡要列表
# lvdisplay /dev/ubuntu-vg/root   # 詳細資訊

LV 的裝置路徑是 symbolic link,實際指向 /dev/dm-* 裝置。/dev/mapper/ 目錄下也有基於 VG 與 LV 名稱的 symbolic link。

檢視 Physical Volume:

# pvs           # 簡要列表
# pvdisplay     # 詳細資訊

建構 Logical Volume 系統實例#

完整的 LVM 建構流程:

Figure 4-5: Constructing a logical volume system

# vgcreate myvg /dev/sdb1                        # 建立 VG 並加入第一個 PV
# vgextend myvg /dev/sdc1                         # 加入第二個 PV
# lvcreate --size 10g --type linear -n mylv1 myvg # 建立 LV
# mkfs -t ext4 /dev/mapper/myvg-mylv1             # 建立檔案系統
# mount /dev/mapper/myvg-mylv1 /mnt               # 掛載

Figure 4-6: Results of reconfiguring logical volumes

移除與調整 LV:

# lvremove myvg/mylv2                              # 移除 LV
# lvresize -l +2602 myvg/mylv1                     # 擴充 LV
# fsadm -v resize /dev/mapper/myvg-mylv1           # 擴充檔案系統

使用 lvresize -r 選項可同時調整 LV 與其上的 filesystem 大小。更簡潔的寫法:lvresize -r -l +100%FREE myvg/mylv1

執行 lvremove 時要注意語法。若誤用空格代替斜線(如 lvremove myvg mylv2),LVM 會將其解讀為要移除 VG 上的所有 LV。

注意事項:

  • ext2/ext3/ext4 檔案系統可以在掛載狀態下擴充,但不能在掛載狀態下縮小
  • 縮小 LV 時必須先卸載並縮小檔案系統,再縮小 LV

Figure 4-8: The arrangement after we remove mylv2 and expand mylv1

4.4.3 LVM 的實作方式#

LVM 的架構分為 user space 與 kernel space:

  • User space:LVM 工具(如 pvscanlvsvgcreate)負責掃描 PV、解析 metadata、管理 VG 與 LV 的結構
  • Kernel spacedevice mapper 驅動程式負責將 LV 上的位址轉換為實際 PV 上的位置

Figure 4-7: How LVM arranges mylv1 and mylv2

Device mapper 的工作流程:

  1. LVM 工具掃描所有 PV,讀取其上的 metadata
  2. 確認 VG 完整後,透過 ioctl/dev/mapper/control 通訊
  3. 在 kernel 中建立 block device 並載入位址映射表
# dmsetup info     # 檢視 device mapper 資訊
# dmsetup table    # 檢視映射表

device mapper 也被用於 software RAID 與加密磁碟等功能。

4.5 磁碟與 User Space 的展望#

在磁碟相關元件中,kernel 與 user space 的界線是模糊的:

  • Kernel 負責:raw block I/O、filesystem 支援、swap 的虛擬記憶體管理
  • User space 負責:初始化操作(分割、建立檔案系統、建立 swap)
  • 日常使用中,user space 僅透過 kernel 提供的 filesystem 支援來存取磁碟

4.6 傳統檔案系統的內部結構#

傳統 Unix 檔案系統有兩個主要組成:

Figure 4-9: User-level representation of a filesystem

  • Data pool:儲存實際資料的區塊池
  • Inode table:管理 data pool 的資料庫系統

Inode 的概念#

Inode 是描述特定檔案的資料集合,包含檔案類型、權限,以及最重要的——檔案資料在 data pool 中的位置。Inode 以編號識別,列在 inode table 中。

Figure 4-10: Inode structure of the filesystem

  • 目錄也是 inode,其資料內容是檔案名稱與對應 inode 編號的列表
  • 每個目錄包含 .(自身)與 ..(父目錄)的 inode 參考
  • ext2/3/4 檔案系統的 root inode 編號為 2

kernel 解析路徑(如 dir_1/file_2)的過程:

  1. 從 root inode 開始,循其資料找到目錄內容
  2. 在目錄中找到 dir_1 對應的 inode
  3. 循該 inode 找到子目錄內容
  4. 在子目錄中找到 file_2 對應的 inode
  5. 透過該 inode 的資料連結存取檔案
$ ls -i    # 檢視 inode 編號

Link count 表示指向某個 inode 的目錄項目總數:

  • 一般檔案的 link count 通常為 1
  • Hard linkln 指令建立)會使多個目錄項目指向同一個 inode,增加 link count
  • 刪除檔案(unlinking)是移除目錄項目並將 link count 減 1,當 count 為 0 時 kernel 才真正刪除 inode 與資料
  • 目錄的 link count 至少為 2(父目錄中的項目 + 自身的 . 項目),每增加一個子目錄就 +1

4.6.2 Block Allocation#

檔案系統使用 block bitmap 來追蹤哪些 data pool block 正在使用:

  • 每個 bit 對應一個 block,0 表示空閒、1 表示使用中
  • 配置與釋放 block 就是翻轉 bit 的操作

當 inode 資料與 block allocation 不一致時(例如不正常關機),fsck 會:

  1. 走訪整個 inode table 與目錄結構
  2. 重新計算 link count 與 block allocation map
  3. 與磁碟上的資料比對,修復不一致之處
  4. 將無主的 inode 與資料放入 lost+found 目錄