Bookmark

Mở rộng overlay OpenWrt bằng extroot: USB, ext4 và đường cứu hộ

extroot dùng một thiết bị lưu trữ ngoài làm overlay ghi được, nhờ đó OpenWrt có thêm chỗ cài package và lưu dữ liệu mà không phải thay flash trong router. Bài này đi theo tài liệu OpenWrt từ lúc xác định thiết bị, tạo phân vùng, chuyển overlay, kiểm tra sau reboot cho tới các nhánh xử lý lỗi và tùy chọn nâng cao.1

Cảnh báo: Đây là thao tác với partition và filesystem. Hãy sao lưu cấu hình trước, xác định đúng /dev/sdX, và coi lệnh parted bên dưới là lệnh xóa toàn bộ đĩa. Không chạy nguyên mẫu trên một đĩa đang chứa dữ liệu.

1. Hiểu extroot và giới hạn của nó

Trên nhiều thiết bị, OpenWrt ghép rootfs chỉ đọc với rootfs_data hoặc ubifs ghi được thành overlay. Bảng khái niệm của tài liệu là:

Thành phầnMount pointNénGhi được
rootfs/romKhông
rootfs_data hoặc ubifs/overlay, /rom/overlayKhông
overlay/Tùy filesystem

Extroot thêm một overlay trên USB, SATA, SD card hoặc một block device khác và mount nó trong quá trình boot. Nếu tháo thiết bị ngoài, router vẫn còn overlay nội bộ nên có thể quay về trạng thái trước khi cấu hình extroot.1

Một số firmware không có overlay partition trong /proc/mtd có thể bỏ qua cấu hình fstab; tài liệu gợi ý dùng / làm mount point trong trường hợp đặc biệt đó. Đây không phải lựa chọn mặc định, vì vậy trước tiên hãy kiểm tra layout thật của model.

2. Chuẩn bị

Tài liệu giả định tôi đã đăng nhập được vào shell bằng SSH hoặc console UART. LuCI có thể sửa nhiều mục, nhưng OpenWrt khuyến cáo thực hiện phần chuẩn bị bằng shell để nhìn rõ device và output.1

  • Thiết bị có từ 8 MiB flash trở lên thường đủ chỗ cài package cần thiết. Với 4 MiB hoặc ít hơn, xem phần Custom image thay vì cố nhồi package vào overlay hiện tại.
  • Filesystem mà block hỗ trợ gồm ext2/3/4, f2fs, btrfs, ntfsubifs; FAT16/FAT32 không dùng được cho extroot theo tài liệu.
  • Ví dụ dưới đây dùng USB flash drive, một partition GPT và ext4. SSD USB có thể cần thêm kmod-usb-storage-uas.
  • Nếu flash gần đầy, gỡ package thừa trước. Cài các package chuẩn:
1
2
3
4
opkg update
opkg install block-mount kmod-fs-ext4 e2fsprogs parted kmod-usb-storage
# Với SSD USB, cài thêm:
opkg install kmod-usb-storage-uas

Xác định tên disk, không đoán từ ví dụ:

1
ls -l /sys/block

Tôi phải phân biệt disk như /dev/sda với partition như /dev/sda1. Ghi lại output và chắc chắn USB đã nhận trước khi chuyển sang bước xóa dữ liệu.

3. Partition và format USB

Đây là phương án tạo một GPT partition rồi format ext4 theo tài liệu nguồn:

1
2
3
4
DISK="/dev/sda"
parted -s ${DISK} -- mklabel gpt mkpart extroot 2048s -2048s
DEVICE="${DISK}1"
mkfs.ext4 -L extroot ${DEVICE}

Lệnh parted sẽ xóa partition table trên ${DISK}. Nếu đĩa không phải USB mới hoặc còn dữ liệu, dừng lại và thay bằng disk chính xác. Có thể dùng filesystem khác trong danh sách hỗ trợ, nhưng các lệnh format và package phải đổi theo filesystem đó; không được giữ mkfs.ext4 khi mục tiêu là f2fs hay btrfs.

4. Tạo mount entry cho extroot

Trước khi ghi fstab, kiểm tra OpenWrt nhận UUID của ${DEVICE} và mount point overlay hiện tại:

1
2
echo $(block info ${DEVICE} | grep -o -e 'UUID="\S*"')
echo $(block info | grep -o -e 'MOUNT="\S*/overlay"')

Nếu một trong hai lệnh không trả output, đừng chạy tiếp; kiểm tra device, module filesystem và output của block info. Khi đã có output đúng, dùng chuỗi UCI của tài liệu để tạo mount entry:

1
2
3
4
5
6
7
eval $(block info ${DEVICE} | grep -o -e 'UUID="\S*"')
eval $(block info | grep -o -e 'MOUNT="\S*/overlay"')
uci -q delete fstab.extroot
uci set fstab.extroot="mount"
uci set fstab.extroot.uuid="${UUID}"
uci set fstab.extroot.target="${MOUNT}"
uci commit fstab

Ở đây ${UUID} được lấy từ partition ngoài còn ${MOUNT} là mount point overlay đang tồn tại. Không tự thay /overlay bằng một đường dẫn khác nếu chưa hiểu layout của firmware.

Cho phép truy cập overlay cũ

Phương án nguồn tiếp theo mount overlay cũ vào /rwm. Nó hữu ích khi cần đọc hoặc tùy chỉnh rootfs_data/ubifs sau khi extroot đã chiếm /overlay:

1
2
3
4
5
6
ORIG="$(block info | sed -n -e '/MOUNT="\S*\/overlay"/s/:\s.*$//p')"
uci -q delete fstab.rwm
uci set fstab.rwm="mount"
uci set fstab.rwm.device="${ORIG}"
uci set fstab.rwm.target="/rwm"
uci commit fstab

Sau đó overlay gốc có thể xuất hiện ở /rwm; file fstab tương ứng trong lớp upper là /rwm/upper/etc/config/fstab. Hãy dùng đúng layout mà block info trả về.

5. Chuyển dữ liệu và áp dụng

Mount partition ngoài tạm thời vào /mnt, sau đó copy nội dung overlay hiện tại sang đó bằng pipeline của tài liệu:

1
2
mount ${DEVICE} /mnt
tar -C ${MOUNT} -cvf - . | tar -C /mnt -xf -

Khi copy xong, reboot:

1
reboot

Không rút USB trước khi router boot lại hoàn tất. Nếu thao tác từ SSH qua Wi-Fi, nên chuyển sang Ethernet hoặc console để tránh mất kết nối giữa chừng.

6. Kiểm tra sau reboot

Qua LuCI

  • Vào System → Mount Points: partition USB phải được mount với vai trò overlay.
  • Vào System → Software: dung lượng trống của overlay phải tăng tương ứng với USB.

Qua command line

Partition ngoài phải mount tại /overlay, còn / là overlayfs dùng nó làm upper layer. Kiểm tra:

1
2
grep -e /overlay /etc/mtab
df /overlay /

Một output thành công sẽ cho thấy /dev/sda1 mount tại /overlay và dung lượng khả dụng của / trùng với /overlay; tên device và số liệu thực tế sẽ khác theo disk.

7. Troubleshooting và đường quay lại

Nếu boot log có vấn đề, xem block discovery, fstab và giai đoạn preinit:

1
2
3
block info
uci show fstab
logread | sed -n -e "/- preinit -/,/- init -/p"

Lỗi UUID mismatch sau nâng cấp

Nếu log ghi block: extroot: UUID mismatch, mount partition và xóa hai marker mà tài liệu nêu:

1
2
3
mount /dev/sda1 /mnt
rm -f /mnt/.extroot-uuid /mnt/etc/.extroot-uuid
umount /mnt

Thay /dev/sda1 bằng device thật. Không xóa nhầm partition khác.

Không dùng FAT/FAT32

vfat và FAT32 không hoạt động cho extroot. Nếu USB đang format sẵn FAT, cần format lại bằng ext4 sau khi cài e2fsprogs:

1
mkfs.ext4 /dev/sda1

Lệnh này cũng xóa dữ liệu trên /dev/sda1.

USB mount quá muộn

Nếu partition mount được thủ công nhưng không mount lúc boot, tài liệu gợi ý tăng delay_root. Ví dụ 15 giây:

1
2
uci set fstab.@global[0].delay_root="15"
uci commit fstab

Chỉ tăng khi log và thử nghiệm cho thấy thiết bị lưu trữ sẵn sàng muộn; không dùng delay lớn như cách chữa mọi lỗi.

Firmware trước và sau 25.xx

Với release pre-25.xx, tài liệu cũ có hướng dẫn cho phép package lớn hơn phần còn trống trong /rom bằng:

1
echo option force_space >> /etc/opkg.conf

Đây không phải cách thay thế extroot và không nên áp dụng mù quáng. Với release post-25.xx, tài liệu trỏ sang hướng dẫn expand_root; hãy theo đúng tài liệu của release đang chạy thay vì trộn hai cơ chế.

Nếu một hệ rất cũ chỉ chạy được cách sửa /etc/rc.local, nguồn còn ghi phương án sau:

1
2
export PREINIT=1
mount_root

Đây là nhánh tương thích lịch sử, có thể gây side effect; ưu tiên extroot chuẩn hoặc expand_root của release hiện tại.

extroot trên MMC/SD

Nếu block device không phải USB, các module cần để thiết bị xuất hiện sớm phải nằm trong /etc/modules-boot.d. Ví dụ cho SDHCI trên MT7688/MT7628, tài liệu nêu file /etc/modules-boot.d/mmc cần có:

1
2
3
4
mmc_core
mmc_block
sdhci
mtk_sd

Tên module phụ thuộc SoC và driver thực tế; đây là ví dụ từ nguồn, không phải danh sách universal.

8. Các tiện ích sau khi có extroot

Lưu package list thay vì để trong RAM

Để package list sống qua reboot và giảm dùng RAM, chuyển thư mục list từ /var/opkg-lists sang /usr/lib/opkg/lists.

Trong LuCI: System → Software → Configuration, đổi lists_dir thành /usr/lib/opkg/lists, sau đó vào System → Software → Actions → Update lists.

Hoặc chạy:

1
2
sed -i -e "/^lists_dir\s/s:/var/opkg-lists$:/usr/lib/opkg/lists:" /etc/opkg.conf
opkg update

Tạo swap trên extroot

Nếu router chỉ có khoảng 32 MB RAM và package list không đọc được, nguồn đưa ra swap file 100 MiB trên extroot:

1
2
3
4
5
6
7
8
9
DIR="$(uci -q get fstab.extroot.target)"
dd if=/dev/zero of=${DIR}/swap bs=1M count=100
mkswap ${DIR}/swap
uci -q delete fstab.swap
uci set fstab.swap="swap"
uci set fstab.swap.device="${DIR}/swap"
uci commit fstab
service fstab boot
cat /proc/swaps

Swap làm tăng số lần ghi lên thiết bị flash/USB và không biến router thành máy có RAM lớn. Chọn storage bền, theo dõi lỗi I/O và không đặt secret trong file swap.

USB dongle và usb-modeswitch

Có thể thêm usb-modeswitch vào image, nhưng nguồn cảnh báo một loại dongle có CD-ROM, modem và card reader chung: nếu /overlay nằm trên thẻ nhớ trong dongle, quá trình chuyển mode có thể làm filesystem biến mất. An toàn hơn là dùng dongle đã cấu hình sẵn để bật modem/network adapter và card reader khi cấp nguồn, không cần switch mode trên router.

Nguồn minh họa kiểm tra port bằng AT command:

1
2
3
at^setport?
^SETPORT:A1,A2;1,3,2,A1,A2
OK

Danh sách ý nghĩa port được truy vấn bằng:

1
at^setport=?

Ví dụ nguồn cho biết 1 là modem, 2 là PCUI, 3 là DIAG, 16 là NCM và A2 là SD. Không tắt PCUI (2) vì có thể tự khóa quyền truy cập dongle. Một chuỗi cấu hình mẫu của tài liệu là:

1
2
3
4
5
6
7
at^setport="ff;1,2,3,a2"
OK
at^reset
OK
at^setport?
^SETPORT:;1,2,3,A2
OK

Đây là lệnh cho dòng dongle tương thích AT command tương ứng, không dùng cho modem khác chỉ vì có cùng tên cổng. Nguồn ghi ví dụ pre-configuration cho Huawei E3131s-2 firmware v21.158.47.00.1094.

Filesystem từ xa

Tài liệu chỉ liên kết tới hướng dẫn xử lý fstab không mount CIFS lúc boot, không cung cấp một quy trình CIFS hoàn chỉnh ngay trong bài. Tôi không biến link tham khảo đó thành lệnh mount chung chung; hãy kiểm tra credential, network availability và thứ tự boot theo model/release.

9. LUKS encrypted extroot: nhánh nâng cao

OpenWrt 22.03 được nguồn ghi là chưa hỗ trợ tốt việc mở LUKS trước bước extroot. Trước khi làm, cần tạo LUKS container theo tài liệu disk encryption, còn rootfs_data phải đủ chỗ cài cryptsetup và dependency. Sau khi volume đã mở, mới làm các bước extroot với filesystem bên trong và copy dữ liệu từ /overlay.1

Phương án PREINIT ưu tiên

Tài liệu mô tả phương án sạch hơn: trong PREINIT, mount_root tìm block trên ROM/overlay rồi gọi block extroot. Cách này cho phép thay wrapper block để mở crypto device trước khi gọi binary thật.

Các điều kiện không được bỏ qua:

  1. Cài block-mountcryptsetup.
  2. Cài script decrypt.sh từ tài liệu disk encryption với quyền thực thi.
  3. Di chuyển binary thật /sbin/block thành /sbin/block.bin.
  4. Đặt wrapper block/upper/sbin/block trên UBIFS overlay, hoặc /sbin/block nếu đã ở overlayfs, rồi cấp quyền thực thi.
  5. Dùng marker /.use_crypt_extroot trên overlayfs hoặc /upper/.use_crypt_extroot trên /overlay để bật/tắt cơ chế.
  6. Đảm bảo /etc/crypttab đã khai báo volume trước khi reboot.

Khi marker không tồn tại, extroot mã hóa sẽ không được bật; đây là đường tắt để vô hiệu hóa nó từ failsafe. Tài liệu có code block wrapper đầy đủ, nhưng wrapper này chạm vào PREINIT, tạo device node và nạp module crypto theo kernel; không nên chép một script chưa đối chiếu vào model khác. Hãy giữ nguyên logic và tham khảo code block gốc trước khi áp dụng.

Phương án /etc/rc.local dự phòng

Nguồn có một cách khác nhiều side effect hơn: extroot fail ở đường boot bình thường, sau đó /etc/rc.local mở LUKS ở cuối boot rồi gọi lại mount_root. Ví dụ dùng keyfile /root/extroot.key:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Chỉ setup encrypted extroot khi marker tồn tại trên rootfs_data.
mkdir -p /mnt/tmp
if [ -e /.use_crypt_extroot ]; then
    cryptsetup open -d /root/extroot.key /dev/sda1 cextroot
    umount /overlay
    mount --bind /tmp /mnt/tmp
    sleep 5
    PREINIT=1 mount_root
    umount -l /tmp
    mount --bind /rom/mnt/tmp /tmp
    block mount
    rpcd reload
fi

Phương án này không đọc password tương tác trong /etc/rc.local; nguồn yêu cầu keyfile và nhắc phải tự đánh giá threat model khi lưu key tại /root/extroot.key. Web interface có thể xuất hiện muộn thêm khoảng 20–30 giây, trong khi SSH không nhất thiết bị trễ. Chỉ dùng đây khi phương án PREINIT không hoạt động và đã chuẩn bị failsafe.

10. Nâng cấp hệ thống và custom image

Không dùng opkg upgrade để nâng cả hệ thống

Nguồn cảnh báo không dùng opkg upgrade mù quáng trên snapshot: ABI uClibc có thể thay đổi, UUID của /rom hoặc /rwm có thể đổi làm extroot không mount, kernel/module mismatch có thể brick router, và nâng mọi package trừ kernel/module có thể làm package hỏng.1

Với stable release, hãy sysupgrade lên image đồng bộ. Sau nâng cấp, có thể phải lặp lại bước tạo mount entry và cài lại package, đặc biệt kernel module; kiểm tra UUID và cấu hình extroot trước reboot tiếp theo.

Custom image cho thiết bị 4 MiB

Với router 4 MiB hoặc nhỏ hơn, source hướng dẫn dùng Image Builder trên Linux 64-bit hoặc WSL:

  1. Tải Image Builder đúng target từ trang download của model.
  2. Giải nén và chạy:
1
make info
  1. Tìm profile đúng, ví dụ:
1
tl-wr1043nd-v1: TP-LINK TL-WR1043N/ND v1 Packages: kmod-usb-core kmod-usb2 kmod-ledtrig-usbdev
  1. Build image với profile và package cần thiết:
1
make image PROFILE=tl-wr1043nd-v1 PACKAGES="block-mount kmod-fs-ext4 kmod-usb-storage kmod-usb-ohci kmod-usb-uhci"
  1. Vào bin/target/<device-type>/generic/, chọn image factory hoặc sysupgrade phù hợp rồi cài.
  2. Format USB ext4 bằng Linux LiveCD hoặc GParted vì e2fsprogs quá lớn để nhét vào thiết bị 4 MiB theo ví dụ nguồn.

Automated setup và automated upgrade

  • openwrt-auto-extroot là frontend Image Builder có thể tự format và cấu hình extroot cho storage vừa cắm nhưng chưa setup.
  • Nhánh automated upgrade của nguồn kết hợp Hotplug extrasOpkg extras; package cần cho extroot được lưu trong profile init rồi khôi phục sau nâng cấp.
  • Script restore dùng /etc/uci-defaults/90-extroot-restore, kiểm tra fstab.extroot, /etc/opkg-restore-init, mount tạm, chuyển thư mục etc/upper, rồi reboot. Đây là code dành cho pipeline upgrade đã hiểu rõ layout; không chạy trên máy chưa backup.

Kết luận

Extroot không chỉ là cắm USB và chạy mount. Phần quan trọng là xác định đúng ${DEVICE}, giữ overlay cũ qua /rwm, copy đủ dữ liệu, kiểm tra /overlay sau reboot và chuẩn bị đường cứu hộ cho UUID mismatch hoặc storage mount quá muộn. Những nhánh usb-modeswitch, LUKS, custom image và automated upgrade có điều kiện riêng; nếu không chắc, hãy dừng ở extroot chuẩn và giữ bản backup ngoài router.

Nguồn


  1. OpenWrt Wiki – Extroot configuration , cập nhật 2026-07-30. Bài này là bản chuyển thể độc lập; không sao chép HTML, ảnh hoặc script nhị phân của nguồn. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎


0 Bình luận

Góp Ý / Bình Luận / Đánh giá