在 Linux 上建立一個有容量限制的資料夾
Toby
Toby

最近我在研究 mdadm 的時候無意中發現了一個可以依靠 losetup 和 partition 映像檔的神奇方法來建立一個具有容量限制的資料夾。所以就寫這篇來簡單記錄一下。

好,可是這有甚麼用?

之前我在開發 ArozOS 的時候想著給使用者建立一個 storage quota。本來想著用 linux 的 File System 來 implement 這個功能,可是找了很久之後發現方法都很麻煩或是過於複雜(例如依賴一些特別的 file system format / container)。所以如果剛好你想設置一個 hard limit 給一些軟體來做 buffer / upload 之類的,都可以考慮這個方法。

首先,建立一個映像檔

我們第一件事情要做的就是建立一個固定大小的映像檔。以我這裡為例,我建立了一個 64MB 的映像檔來模擬一個硬碟 partition。 bs 是 block size,就是系統會 buffer 多少 data 才會真正寫進去這個(block )device,這裡用的是 4MB。 count 是這個虛擬硬碟裡有多少個 block,16 個 4MB 的 block 加起來就是 64MB 啦

sudo dd if/dev/zero of=sdX.img bs=4M count=16

至於 /dev/zero 是甚麼,它是一個只會不斷吐出 0 的 byte stream。你可以把它當成一個無限大的檔案,裡面只存在無限個 0。透過 dd 指令,我們就可以把需要的 0 bit 從這個檔案裡 clone 出來來建立我們需要的映像檔大小。

之後:建立檔案系統

在建立了一個空白的映像檔之後,透過 ls 指令我們可以看到新鮮的 .img 檔出現了。

aroz@orangepizero2:~/raidtest$ ls
sdX.img

然後我們就是需要對它進行格式化,就古人所說

Everything is a file

Linus Torvalds did not say this

所以我們可以直接對它用 mkfs 跟 mount 指令。假設我們有一個叫 sdX/ 的資料夾,那我們就可以把映像檔格式化之後掛到那個資料夾。

// 建立掛載點
aroz@orangepizero2:~/raidtest$ mkdir sdX

//用 ext4 把映像檔格式化
aroz@orangepizero2:~/raidtest$ sudo mkfs.ext4 sdX.img
mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 65536 1k blocks and 16384 inodes
Filesystem UUID: bf600d34-c93a-48bc-ad27-27255fbd1333
Superblock backups stored on blocks:
        8193, 24577, 40961, 57345

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

//檢查看看是不是需要的資料夾和檔案都存在
aroz@orangepizero2:~/raidtest$ ls
sdX  sdX.img

//把映像檔掛上去
aroz@orangepizero2:~/raidtest$ sudo mount sdX.img ./sdX

之後我們就可以在 df 裡看到掛載的虛擬硬碟 / 映像檔了

aroz@orangepizero2:~/raidtest$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            386M     0  386M   0% /dev
tmpfs            92M  2.4M   90M   3% /run
/dev/mmcblk0p1   29G  3.8G   25G  14% /
tmpfs           460M     0  460M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           460M     0  460M   0% /tmp
/dev/zram1       47M   18M   26M  41% /var/log
tmpfs            92M     0   92M   0% /run/user/1000
/dev/loop0       55M   14K   51M   1% /home/aroz/raidtest/sdX <- 這裡

那 /dev/loop0 是甚麼!?

這個是 loopback device,如果你沒耐心的話關鍵字是 losetup (

嘛,簡單來說一個虛擬的 block device。它是一個 kernel driver 來提供 loopback 的 block device emulation,用途例如說把 .img 檔案掛成一個 storage device。

如果你想查看現有的 loopback device 的話可以用 losetup -a 指令

aroz@orangepizero2:~/raidtest$ sudo losetup -a
/dev/loop0: [45825]:268807 (/home/aroz/raidtest/sdX.img)

要移除的話(如果你是用 umount 指令的話它應該是會自動移除的,但是在一些奇怪情況下你可能會需要手動控制),你可以用它的 -d 指令。

大概就是這樣了,之後你就可以讓沒辦法控制 quota 的軟體用那個資料夾來當 data folder。這樣一但滿了的話它就會彈 storage full 的警告,同時間也不會把伺服器的實體硬碟塞滿,酷吧?