自制文件系統 — 01 文件系統的樣子

前情提要

來一個硬核系列,得益於 Linux 一切皆文件的哲學,把文件系統玩轉的飛起。文件系統所有人都聽過,都用過,但是就很少有人深究。

對於文件系統,大家的態度可能是兩個極端,要麼就是覺得好深奧,好牛,你竟然懂這玩意!要麼就是,文件系統是什麼鬼?不就是那個。。。我在 Linux 用過無數次的。這玩意還用得着講?

這兩種態度可能都不合適,文件系統作爲一個深入我們生活的事物,我們不應去忽略它,也不要去抬高或者貶低。我們應該要去了解它,打破對它的恐懼,因爲恐懼是對未知事物產生的一種情緒。平視它,瞭解清楚脈絡,從而掌握它

小孩在爲什麼總是學習東西很快?因爲他們都是從形到意,先直觀的摸到,看到,嗅到,喫到,先感受到 “形”,然後我們教導他這些東西是的含義。他們很快就接受了。

我們這個自制文件系統,就是想從形意結合,讓讀者朋友能夠跟隨着筆者一起經歷一次文件系統由 0 到 1 的過程,構建好知識框架,後續的深造將會得心應手。

好,話不多說,我們先從什麼是文件系統講起,簡單介紹一些探索文件系統的基礎知識。

探索文件系統

 1   查看現有文件系統實例

Linux 文件系統相比大家都使用過。大家在自己的 Linux 上機器上執行 mount 命令就能看到當前系統上掛載的所有文件系統:

mount

示例如下:

root@localhost:~# mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
/dev/mapper/cl-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
....

比如通過這一行信息我們能看出來:

sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime)

信息拆解分析:

這裏蘊含的重要信息:

其實,mount 這個命令很強大,不僅能 list 所有的文件系統,還能掛載文件系統。如下:

掛載文件系統命令

# 把已經格式化好的 /dev/sdb1 盤掛到 /mnt 目錄上 mount -t ext4 /dev/sdb1 /mnt/

對應卸載文件系統命令

# 卸載 /mnt 的掛載點
umount /mnt

 2   查看目錄掛載的文件系統用量

mount 命令能看到所有的掛載列表,但是如果你想要看到所有文件系統的使用情況,則需要另一個命令:dfdf 命令用來查看當前操作系統掛載的文件系統和使用情況

df -Tha

示例如下:

root@localhost:~# df -ahT
Filesystem          Type             Size  Used Avail Use% Mounted on
sysfs               sysfs               0     0     0    - /sys
proc                proc                0     0     0    - /proc
/dev/mapper/cl-root xfs               17G   11G  7.0G  60% /
...

注意,如果 df 沒有加 -a 參數,類似於上面  sysfs,proc 這種用量 0 的會被過濾掉。這也是 mountdf 兩個命令默認顯式信息的區別。

 3   查看文件系統掛載配置

文件系統掛載可以通過 mount 命令直接掛載,但是 mount  命令掛載並沒有持久化,關機重啓就沒了。所以想要關機重啓之後,還能自動掛載到指定目錄,那麼就要把掛載規則寫到 /etc/fstab 文件中fstab 就是 fs table 的縮寫,很容易理解。

操作系統在啓動的時候,就會解析這個文件,並按照這個文件裏的配置,自動掛載文件系統了。

如下:

root@localhost:~# cat /etc/fstab 

/dev/mapper/cl-root     /                       xfs     defaults        0 0
UUID=600e3771-af4a-48ca-a557-02204c9a48a5 /boot                   ext4    defaults        1 2
/dev/mapper/cl-swap     swap                    swap    defaults        0 0

fstab 的文件格式:

<設備標識>        <掛載目錄>         <文件系統類型>    <掛載參數>             <dump選項> <fsck選項>

從左到右參數拆解:

 4   查看內核支持的文件系統

這個直接去看內核模塊即可:

ls /lib/modules/${kernel_version}/kernel/fs/

不同的 Linux 發行版略有不同,比如,centos 一般爲:

ls -l /lib/modules/4.18.0-80.el8.x86_64/kernel/fs/

ubuntu 一般爲:

ls -l /lib/modules/4.4.0-142-generic/kernel/fs/

在對應的目錄找到對應的 .ko 模塊,比如 ext4.ko ,如果想看內核已經加載的內核模塊,可以調用 lsmod 看到。

簡單普及一下 .ko 模塊的知識:

ko 其實是 kernel object 的縮寫,這類文件存在的意義其實和用戶態的 .so 庫類似,都是爲了模塊化的編程實踐。內核把核心主幹框架之外的功能拆解成模塊,需要的時候就加載 ko 模塊,不需要的時候卸載即可。這樣帶來的好處就是方便開發和使用,保持內核的核心代碼極度精煉。

類似於文件系統,硬件驅動等等,都是以這種形式來加載使用的。

開發文件系統爲什麼難?

爲什麼文件系統的開發大家會覺得非常難?原因其實不在於實現,而在於調試和排障,因爲早期文件系統的開發只能在內核之中,這個帶來了非常高的門檻。

 1   內核文件系統

因爲在此之前我們看到了文件系統是位於內核之中, vfs 之下,塊存儲模塊之上的一個位置。對外呈現文件存儲實現,對下管理裸塊設備。劃重點,文件系統是位於內核的一個模塊,那就可以理解了,內核模塊的開發之所以艱難就是難在調試和排障,用戶態的程序你可以隨意 debug,出問題最多也就是 panic,coredump,內核態的程序出了文件就是宕機,所有現場都丟失,你只能通過日誌,kdump 等手段來排查。並且內核態程序的編寫是要注意非常多的規範的,比如內存分配,比用戶態的要謹慎的多。

那怎麼辦?我們本次的目標是要自制實現一個極簡的文件系統,但總不能帶大家趟一次內核開發的坑吧!那可是要嚇退 99% 的小夥伴。

有辦法的,內核開發者考慮到了這個問題,又考慮到文件系統的需求是千變萬化的,所以提供了一種手段,把 IO 路徑導向用戶態,由用戶態程序捕獲到 IO ,從而實現文件的存儲,這個機制就叫 FUSE 機制。

 2   FUSE 文件系統

作爲自制 FS 系列第一篇,我們不講 FUSE 的實現,而是通過一個動畫來演示 IO 的旅途:

這裏的路徑做了一些簡化,簡化了用戶態之上的邏輯處理,爲什麼路徑是這樣子?什麼是 FUSE ?下篇專題解釋。

總結

本篇文章是爲後續鋪墊一些基礎知識,從的方面,系統介紹了一些命令,告訴你文件系統怎麼配置,怎麼掛載,怎麼查看,怎麼獲取到使用詳情。這些基礎知識在後面自制文件系統的時候,都要用上。這些 Linux 命令都是幫助我們從文件系統的外圍去用,去摸,去嗅,從而再去深入理解

我們目標不止如此,我們是要親手做一個文件系統,動手做過一遍的東西,你對它理解也將會突飛猛進,更加深刻。

下面總結一下上面的基礎以上的知識:

  1. mount 用來列舉查看當前所有文件系統實例,也能支持掛載命令(但 mount  掛載不會持久化,重啓就沒了),umount 用來卸載;

  2. /etc/fstab 是用來配置文件系統掛載規則的,是持久化的配置,重啓不丟;

  3. df -aTh 用來查看每個文件系統掛載目錄的詳情,包括空間使用量,總量,掛載點等信息;

  4. 內核模塊的功能以 ko 文件的形式體現,在 /lib/modules/${kernel_version}/kernel/fs/ 目錄可以看到支持的內核文件系統模塊,lsmod 命令可以看到已經加載的內核模塊;

  5. 文件系統開發之所以難?是因爲之前在內核中開發,內核開發最難的在於調試和排障手段不方便。那文件系統還有出路嗎?有,奇伢帶你自制一個極簡的文件系統,基於 Linux 系統使用純 Go 語言來做哦,敬請期待後續,自己動手,理解更深;

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/0FpQGDzFh_D7IJi6z7oXjg