本篇介紹如何在 Linux 中縮減磁碟分割區大小,剪裁磁碟影像檔,讓影像檔可以寫入較小的 MicroSD 記憶卡中。
樹莓派可以使用 以 dd
指令備份與回復影像檔,如果備份與回復所使用的 MicroSD 卡都是同一張卡的話,使用簡單的 dd
指令就可以處理所有的工作了,但是如果我們想要從一張 MicroSD 卡備份影像檔,然後將影像檔寫入另外一張卡,也就是複製一張一模一樣的 MicroSD 卡,在這樣的狀況下回復影像檔時就有可能會出現 MicroSD 卡空間不足的問題,造成 dd
在寫入時出現錯誤。
這個問題發生的原因是由於不同廠牌、型號的 MicroSD 卡,即使規格相同(例如都是 16 GB 的 MicroSD),實際上的除從空間大小都會有一點點的差異,有個卡稍微大一點、有的稍微小一點,如果剛好從比較小的卡備份影像檔,回復至比較大的卡,就不會有問題,但若是反過來的話,就會因為差一點點的空間大小,導致影像檔尾端的資料寫不進小的 MicroSD 卡,造成錯誤。
解決的方法是把備份出來的影像檔修改一下,把分割區稍微調小一些,然後裁剪影像檔,讓 dd
指令可以把影像檔順利寫入,以下是在 Linux 系統上縮小影像檔的操作步驟。
建立 Loopback 設備
若想要修改磁碟分割表,就必須先讓 Linux 核心載入磁碟,才能使用各種磁碟分割工具來修改,但是現在我們的磁碟不是一般的實體磁碟,而是一個影像檔,若要讓 Linux 核心可以載入這個磁碟,就必須使用 loopback 設備來處理。
首先啟用 Linux 核心 的 loopback 模組:
sudo modprobe loop
接著找尋尚未被使用的 loopback 設備:
sudo losetup -f
/dev/loop0
這個輸出表示 /dev/loop0
這個設備尚未被使用,所以我們可以使用這個名稱來建立一個影像檔的 loopback 設備:
sudo losetup /dev/loop0 my_image.img
其中 my_image.img
就是從 MicroSD 卡備份下來的影像檔,現在 /dev/loop0
就代表了 my_image.img
影像檔中的磁碟,接著要讓 Linux 核心也載入這個磁碟:
sudo partprobe /dev/loop0
這時候在系統上應該就可以看得到這個磁碟了(但是應該是處於未掛載的狀態)。
調整分割區
在使用 loopback 載入影像檔中的的磁碟之後,就可以使用普通的磁碟工具來修改它了。
一開始要調整分割區的大小,讓磁碟末端騰出一些空間,這個動作可以使用 GParted 的操作介面來處理:
sudo gparted /dev/loop0
原本的磁碟分割狀態會類似這樣,整個磁碟幾乎都用滿了,但某些分割區裡面還有些空間:
使用 GParted 的介面調整一下分割區的大小或位置,讓磁碟末端騰出一些空間,通常這個空間也不需要很大,就看影像檔的大小與 MicroSD 卡的容量相差多少,就騰出多少即可,如果磁碟分割區內的資料很少,多騰出一點空間也沒有關係:
使用 GParted 調整磁碟分割區時,結果會直接寫入我們的影像檔,修改好影像檔之後,即可卸載 loopback 設備:
sudo losetup -d /dev/loop0
裁剪影像檔
現在我們的影像檔的狀態應該就會像 GParted 介面中顯示的那樣,末端是沒有使用的空間,最後只要將那段沒用的空間裁剪掉即可。
首先以 fdisk
檢查影像檔內部使用的狀況:
fdisk -l my_image.img
Disk my_image.img: 14.9 GiB, 15987638272 bytes, 31225856 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x03ca9076 Device Boot Start End Sectors Size Id Type my_image.img1 8192 96453 88262 43.1M c W95 FAT32 (LBA) my_image.img2 98304 27054079 26955776 12.9G 83 Linux
從這個輸出中可以看出每個分割區在磁碟中的開始位置(Start
)與結束位置(End
),最後一個分割區結束的位置是 26955776
,也就是說在這個位置之後的空間,就是沒有使用到的部份,也就是可以裁剪掉的部份。
這裡的輸出中也有說明一個 sector 的大小是 512 位元組(bytes),而 sector 的計算方式是從 0
開始起算的,所以整個磁碟從開頭算起,一直到有資料的最末端,總共的大小應該是 (26955776+1)*512
位元組(bytes)。
計算出資料在磁碟中最末端的位置之後,就可以使用 truncate
裁剪影像檔,只留下前面有資料的部份:
# 裁剪影像檔 truncate --size=$[(27054079+1)*512] my_image.img
裁剪影像檔必須很謹慎,萬一弄錯資料就毀了,若是不確定的話,記得先備份影像檔,以免出錯造成資料損毀救不回來。
這樣裁剪完之後的影像檔,通常都或比任何同規格的 MicroSD 卡容量要小很多,所以使用 dd
指令寫入的話一定沒問題,不過寫入完成後,末端也會出現一些未使用的空間(因為當初騰出了不少空間),這部份就再用 GParted 調整一下即可,或是在樹莓派開機後,用 raspi-config
的 expand filesystem 功能也可以自動擴張磁碟分割區的大小,善用未使用的空間。
參考資料:Softwarebakery