Skip to content

Root filesystem cho thiết bị nhúng

Root filesystem (rootfs) là filesystem được kernel mount tại / ngay sau khi khởi động, chứa init, thư viện, ứng dụng và cấu hình. Trên máy tính để bàn, rootfs là phân vùng đọc ghi thông thường. Thiết bị nhúng có các ràng buộc khác: có thể mất điện đột ngột, bộ nhớ flash chịu số lần ghi hữu hạn, thiết bị chạy nhiều năm không có người bảo trì, và firmware cần cập nhật từ xa. Trang này trình bày theo thứ tự: các filesystem thường dùng cho rootfs, mô hình tách rootfs chỉ đọc khỏi vùng dữ liệu ghi được, overlayfs, cách cấu hình trong Yocto và Buildroot, và bố cục phân vùng khi cần cập nhật A/B.

Các filesystem thường dùng cho rootfs

Filesystem Đặc điểm Thường dùng khi
ext4 Đọc ghi, có journal, chạy trên block device (eMMC, SD, SSD) Rootfs đơn giản trên eMMC hoặc SD, ưu tiên dễ phát triển
squashfs Nén, chỉ đọc. Tài liệu kernel nêu đây là filesystem phù hợp với hệ thống bị giới hạn về block device và bộ nhớ, ví dụ hệ nhúng, cần overhead thấp Rootfs cố định, cần giảm dung lượng và cần ký hoặc kiểm tra toàn vẹn cả image
UBIFS Đọc ghi, chạy trên volume UBI của raw NAND, xem UBI và UBIFS Thiết bị dùng raw NAND
initramfs (cpio) Rootfs nằm trong RAM, được kernel giải nén khi boot Thiết bị nhỏ hoặc tầng khởi động trung gian trước khi chuyển sang rootfs thật

Squashfs là filesystem chỉ đọc có nén, đóng gói bằng công cụ mksquashfs chứ không ghi trực tiếp từng file. Kích thước block mặc định là 128 KiB và có thể lên tới 1 MiB. Thuật toán nén gồm zlib, lzo, xz và zstd, tùy bản kernel và công cụ.

Mọi lựa chọn trên đều là lựa chọn cho phần chứa hệ thống. Khi thiết bị cần lưu cấu hình hoặc dữ liệu, cần một vùng ghi được riêng, như trình bày ở các mục sau.

Tách rootfs chỉ đọc khỏi vùng dữ liệu

Mô hình phổ biến trên thiết bị sản phẩm là rootfs chỉ đọc cộng với một phân vùng dữ liệu đọc ghi. Tài liệu của Digi Embedded Yocto nêu ba lợi ích của cách làm này: tách thay đổi của người dùng khỏi cấu hình hệ thống, factory reset bằng cách xóa phân vùng dữ liệu, và ký rồi xác thực được image rootfs lúc boot vì image không thay đổi.

Rootfs chỉ đọc không nghĩa là hệ thống không ghi được gì. Một số thư mục cần ghi lúc chạy:

  • /etc: cấu hình có thể được thay đổi bởi người dùng hoặc bởi ứng dụng (địa chỉ mạng, chứng chỉ).
  • /var, /tmp: trạng thái và file tạm. Thường mount tmpfs (filesystem trong RAM) để không ghi lên flash.
  • /home hoặc thư mục dữ liệu ứng dụng: nằm trên phân vùng dữ liệu.

Overlayfs

Overlayfs hợp nhất hai cây thư mục thành một: lớp dưới (lowerdir) và lớp trên (upperdir). Khi một tên tồn tại ở cả hai lớp, đối tượng ở lớp trên được thấy, còn đối tượng ở lớp dưới bị che. Với hai thư mục cùng tên, kết quả là thư mục hợp nhất. Theo tài liệu kernel, lớp dưới có thể là bất kỳ filesystem nào mà Linux hỗ trợ và không cần ghi được. Nếu bỏ upperdir và workdir, overlay ở chế độ chỉ đọc.

Rootfs chỉ đọc và phân vùng dữ liệu, overlayfs hợp nhất /etc

Overlayfs đặt phần ghi được của /etc lên phân vùng dữ liệu, rootfs squashfs không bị sửa.

Cú pháp mount theo tài liệu kernel:

mount -t overlay overlay -o lowerdir=/lower,upperdir=/upper,workdir=/work /merged

Các ràng buộc của hai thư mục ghi được:

  • workdir phải là thư mục rỗng nằm trên cùng filesystem với upperdir.
  • Filesystem chứa upperdir phải hỗ trợ extended attribute dạng trusted.* và trả về d_type hợp lệ trong readdir. Vì vậy NFS không phù hợp làm upperdir.

Ví dụ phủ phần ghi được lên /etc, với phân vùng dữ liệu đã mount tại /data:

mkdir -p /data/overlay/etc/upper /data/overlay/etc/work
mount -t overlay overlay \
    -o lowerdir=/etc,upperdir=/data/overlay/etc/upper,workdir=/data/overlay/etc/work \
    /etc

Thử nghiệm trên một cây thư mục tạm (không phải trên board) cho kết quả đúng như mô tả: sửa a.conf có sẵn và tạo b.conf mới đều xuất hiện trong thư mục hợp nhất và trong upperdir, trong khi lowerdir giữ nguyên nội dung cũ. Lần ghi đầu tiên vào một file của lớp dưới sao chép (copy-up) file đó sang lớp trên.

Todo

Chưa kiểm chứng trên board thật: độ bền của upperdir khi mất điện đột ngột và mức mòn flash khi ứng dụng ghi thường xuyên vào /etc. Cần thử cắt nguồn lặp lại trên phân vùng dữ liệu ext4 và UBIFS.

Cấu hình trong Yocto

Yocto có IMAGE_FEATURE read-only-rootfs. Theo tài liệu Digi, tính năng này làm Yocto thay đổi một số recipe để chúng không sửa file trong rootfs lúc chạy. Định dạng image do IMAGE_FSTYPES quyết định; bản dựng của Digi tạo ra image squashfs.

Để có overlay cho /etc, Yocto có IMAGE_FEATURE overlayfs-etc. Cấu hình mẫu trong conf/local.conf:

EXTRA_IMAGE_FEATURES += "read-only-rootfs overlayfs-etc"
IMAGE_FEATURES:remove = "package-management"
OVERLAYFS_ETC_MOUNT_POINT = "/mnt/data"
OVERLAYFS_ETC_DEVICE = "/dev/mmcblk0p7"
OVERLAYFS_ETC_FSTYPE = "ext4"

Ba biến OVERLAYFS_ETC_* chỉ định điểm mount, thiết bị và loại filesystem của phân vùng dữ liệu chứa upperdir. Với thiết bị dùng UBI, thiết bị có dạng ubi1:data và loại filesystem là ubifs. Gỡ package-management vì trình quản lý gói cần ghi vào rootfs.

Cấu hình trong Buildroot

Buildroot chọn định dạng image bằng các tùy chọn BR2_TARGET_ROOTFS_*, ví dụ BR2_TARGET_ROOTFS_SQUASHFS và BR2_TARGET_ROOTFS_UBIFS. Danh sách định dạng nằm trong thư mục fs/ của source tree, xem Buildroot.

Phân biệt hai khái niệm overlay

BR2_ROOTFS_OVERLAY của Buildroot là cây thư mục được sao chép đè lên rootfs ở thời điểm build, không liên quan đến overlayfs của kernel. Xem mục "Tùy biến rootfs" trong trang Buildroot.

Chỉ định rootfs trên kernel command line

Kernel nhận rootfs qua tham số root= và rootfstype=. Với rootfs chỉ đọc, thêm ro. Bảng ví dụ cho eMMC, UBIFS và squashfs trên NOR nằm ở mục Mount rootfs từ flash.

Khi rootfs là squashfs và cần overlay cho /etc, overlay phải được mount rất sớm, trước khi các service đọc cấu hình. Việc này thường do initramfs hoặc script init sớm đảm nhận. Trong Yocto, tính năng overlayfs-etc đã bao gồm bước này.

Bố cục phân vùng khi cập nhật A/B

Khi dùng cập nhật A/B (hai bản rootfs luân phiên, xem OTA Update), bố cục thường gồm phân vùng boot, hai phân vùng rootfs và một phân vùng dữ liệu dùng chung:

Phân vùng Nội dung Ghi được lúc chạy
boot Bootloader, biến môi trường, kernel và DTB Chỉ khi cập nhật
rootfs A Rootfs đang chạy Không
rootfs B Rootfs bản cập nhật Chỉ khi cập nhật
data Cấu hình, upperdir của overlay, dữ liệu ứng dụng Có

Phân vùng dữ liệu nằm ngoài vùng bị thay thế khi cập nhật, nên cấu hình và dữ liệu người dùng được giữ nguyên qua các lần cập nhật. Cần kiểm tra tương thích định dạng dữ liệu giữa phiên bản cũ và mới của ứng dụng.

Liên quan

Tài liệu tham khảo