みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

YoctoProject 最後のパーティションを目一杯まで広げる

はじめに

YoctoProjectではwicツールを使用することで、SDなどのストレージに直接書き込めるイメージを作成することができる。 wicイメージを作成する時点では書き込むストレージのサイズがわからないため、基本的には必要最低限のサイズでイメージは作成される様になっている。

データ領域などを多めに取りたい場合は、IMAGE_ROOTFS_EXTRA_SPACEなどの変数でファイルシステムの領域を確保することができるが、 その場合でも、実際に書き込むストレージのサイズはわからないため目一杯というのは難しい。

systemd-growfsを使用すると、初回システム起動時に指定したデバイスファイルシステムパーティションサイズいっぱいに拡張することができるが、パーティションサイズ自体は拡張されない。

そのため、ストレージ全体を使うためには少し工夫が必要となる。 meta-rauc-communityにその実装のヒントがあるため参考にしてみる。

環境構築

作業環境

$ mkdir -p ~/yocto/rpi-kirkstone
$ cd ~/yocto/rpi-kirkstone

pokyの取得

$ git clone git://git.yoctoproject.org/poky.git -b kirkstone 

環境変数の設定

$ source poky/oe-init-build-env

meta-raspberrypiの取得

$ bitbake-layers layerindex-fetch meta-raspberrypi

local.confを編集

MACHINE = "raspberrypi4-64"
DL_DIR = "${TOPDIR}/../downloads"

# systemd
DISTRO_FEATURES:append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# enable uart
ENABLE_UART = "1"

レイヤを作成

meta-workを作成

$ bitbake-layers create-layer meta-work
$ rm -rf ./meta-work/recipes-example
$ mkdir -p ./meta-work/recipes-support/repart/files ./meta-work/wic
$ bitbake-layers add-layer ./meta-work

レシピ作成

サービスファイル

systemdのサービスを作成するが、一部はbitbakeするまで内容が未確定なので、 変数にしておき、レシピを処理する過程で内容を確定させる。

そのためには次のようにsystemdのユニットそのものではなくテンプレートを作成する。

[Unit]
Description=Service to resizing parition
DefaultDependencies=no
Before=local-fs.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/parted --script @repart-dev@ resizepart @repart-no@ 100%

[Install]
WantedBy=local-fs.target

[2023/1/28 追記]システムの2回目以降の起動時間を改良したバージョンをYoctoProject systemdでシステム起動時間計測で紹介している.

この内容をmeta-work/recipes-support/repart/files/repart.service.inとして保存する。 最後の.inは慣例的にそのファイルがテンプレートであるということを示している。 つまり、.inがついているファイルに何らかの加工を加えることで、.inのないファイル(ここでは「repart.service」)が出来上がることを示している。

これの本体は下記の部分で、指定のパーティションストレージ目一杯に拡張する。

ExecStart=/usr/sbin/parted --script @repart-dev@ resizepart @repart-no@ 100%

repart.bb

meta-work/recipes-support/repart/repart.bbを以下の内容で作成する。

SUMMARY = "resize partition for data"
DESCRIPTION = "Recipe for resizin the partition and filesystem"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

REPART_DEV ??= ""
REPART_NO ??= ""
REPART_MOUNTPOINT ??= ""

ALLOW_EMPTY:${PN} = "1"

SRC_URI = "file://repart.service.in"

RDEPENDS:${PN} = "parted"

inherit systemd features_check
REQUIRED_DISTRO_FEATURES = "systemd"

S = "${WORKDIR}"

do_compile() {
    if [ -z "${REPART_DEV}" ]; then
        bbfatal "REPART_DEV should be set."
    fi
    if [ -z "${REPART_NO}" ]; then
        bbfatal "REPART_NO should be set."
    fi
    sed -e "s#@repart-dev@#/dev/${REPART_DEV}#g; s#@repart-no@#${REPART_NO}#g" \
    repart.service.in > repart.service
}

do_install() {
    if [ -n "${REPART_MOUNTPOINT}" ]; then
        install -d ${D}${REPART_MOUNTPOINT}
    fi

    install -d ${D}${systemd_unitdir}/system/
    install -m 0644 ${S}/repart.service ${D}${systemd_system_unitdir}
}

SYSTEMD_SERVICE:${PN} = "repart.service"

FILES:${PN} = "\
  ${systemd_system_unitdir} \
  ${REPART_MOUNTPOINT} \
"

下記の3つの変数は、必要に応じてlocal.confなどで設定する。

REPART_DEV ??= ""
REPART_NO ??= ""
REPART_MOUNTPOINT ??= ""

do_compileタスクでは、先程のrepart.service.inを処理し、repart.serviceを作成する。

wksファイルを作成

meta-work/wic/sdimage-raspberrypi-growfs.wks.inを下記の内容で作成し、/homeにx-systemd.growfsを指定することにより、システム起動時にパーティションジいっぱいに拡張されるようにする。

part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20
part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4096
part /home --source rootfs --rootfs-dir=${IMAGE_ROOTFS}/home --ondisk mmcblk0 --fstype=ext4 --label homefs --align 1024 --size 500 --fsoptions "x-systemd.growfs"

拡張子をwksではなくwks.inとすることで、wksファイルの中でbitbakeの変数を使用することができる。

local.confの修正

local.confに下記を追加する。

IMAGE_INSTALL:append = " repart"
REPART_DEV ?= "mmcblk0"
REPART_NO ?= "3"
#REPART_MOUNTPOINT ?= ""
WKS_FILE = "sdimage-raspberrypi-growfs.wks.in"

今回は既存の/homeを拡張するためREPART_MOUNTPOINTは指定しない。

動作確認

ビルド

$ bitbake core-image-base

動作確認

出来上がったイメージでラスベリーパイ4を起動する。

root@raspberrypi4-64:~# fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 3768 MB, 3951034368 bytes, 7716864 sectors
120576 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  64,0,1      1023,3,32         8192     152543     144352 70.4M  c Win95 FAT32 (LBA)
/dev/mmcblk0p2    1023,3,32   1023,3,32       155648     624229     468582  228M 83 Linux
/dev/mmcblk0p3    1023,3,32   1023,7,32       624640    7716863    7092224 3463M 83 Linux

/dev/mmcblk0p3が3463Mになっていることがわかる。

下記mountの結果

root@raspberrypi4-64:~# mount | grep home
/dev/mmcblk0p3 on /home type ext4 (rw,relatime,x-systemd.growfs)

次にdfの結果

root@raspberrypi4-64:~#  df -h | grep home
/dev/mmcblk0p3            3.4G     89.5M      3.2G   3% /home

/dev/mmcblk0p3がext4でフォーマットされ、3.4Gとして認識されている。また、/homeにマウントされていることが確認できる。

パーティションを追加

wksとlocal.confの修正

第4パーティションとして/dataを追加してみる。sdimage-raspberrypi-growfs.wks.inを下記のように修正する。

part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20
part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4096
part /home --source rootfs --rootfs-dir=${IMAGE_ROOTFS}/home --ondisk mmcblk0 --fstype=ext4 --label homefs --align 1024 --size=100M
part /data --ondisk ${REPART_DEV} --fstype=ext4 --label data --align 4096 --size=1024 --fsoptions "x-systemd.growfs"

/dataは既存のルートファイルシステムには存在しないのでlocal.confでREPART_MOUNTPOINTを設定する。

IMAGE_INSTALL:append = " repart"
REPART_DEV ?= "mmcblk0"
REPART_NO ?= "4"
REPART_MOUNTPOINT ?= "/data"

動作確認

fdiskの結果

root@raspberrypi4-64:~# fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 3768 MB, 3951034368 bytes, 7716864 sectors
120576 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  64,0,1      1023,3,32         8192     152543     144352 70.4M  c Win95 FAT32 (LBA)
/dev/mmcblk0p2    1023,3,32   1023,3,32       155648     624229     468582  228M 83 Linux
/dev/mmcblk0p3    1023,3,32   1023,3,32       624640     890879     266240  130M 83 Linux
/dev/mmcblk0p4    1023,3,32   1023,7,32       892928    7716863    6823936 3332M 83 Linux

mountの結果

root@raspberrypi4-64:~# mount | grep mmc
/dev/mmcblk0p2 on / type ext4 (rw,relatime)
/dev/mmcblk0p3 on /home type ext4 (rw,relatime)
/dev/mmcblk0p1 on /boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
/dev/mmcblk0p4 on /data type ext4 (rw,relatime,x-systemd.growfs)

まとめ

meta-rauc-communityの実装にヒントを得てrepart.bbを実装してみた。

指定したデバイスの最後のパーティションを指定することで、そのパーティションおよびファイルシステムがストレージの残り目一杯まで拡張されることを確認した。

もちろん途中のパーティションを指定しても拡張することはできない。