最近我在研究 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 的警告,同時間也不會把伺服器的實體硬碟塞滿,酷吧?