PR

Armbianのrootfsをf2fsに変更する

PC

ArmbianのSDカードイメージをフラッシュメモリに最適化されたf2fsにして、ストレージの寿命向上を狙います。

サーバーOSの更新時期がやってきた

我が家のサーバーにはArmbaian(Debian)がインストールされています。ここしばらくほったらかしで使用してきて、流石にそろそろOSをバージョンアップしないとな、という時期になりました。

インストールされているArmbianはDebian12(bookworm)がベースのものです。これをDebian13(Trixie)ベースにアップグレードします。そのついでに、ストレージとして使用しているmicroSDの寿命を少しでも伸ばせるようにrootfsをf2fsに変更することにしました。

Armbian公式イメージはrootfsにext4を使用しています。今までこれで何ら問題無かったわけなのですが、最近は何もかも値段が高くなってきているのでmicroSDもなるたけ長く使い続けられるようにしたいわけです。

我が家のサーバマシンとして活躍中のOrangePi PC。もっぱら3Dプリンタサーバと一時ファイル置き場として使用していて、ヘビーな使い方はしていません。
まだDebian bookwormのままです。流石にtrixieのリリースから1年経過しているのでアップグレードすることにしました。

f2fsとは

f2fsはmicroSDやUSBメモリなどのNAND Flashメモリ向けのファイルシステムで、Flashメモリの書き換え寿命とパフォーマンスに配慮したものです。

microSDなどは搭載されているメモリコントローラがあまり賢くないようで、頻繁に書き換えを行うような使い方(OSのrootfsとか)をするとすぐに寿命を迎えて壊れてしまいます。f2fsはメモリコントローラが賢くない前提で、ファイルシステム側がこれを補うようになっています。つまり、同じ使い方をしても長寿命が期待出来るわけです。

ちなみに、f2fsはandroidの内部ストレージでも使用されています。

rootfsをf2fsに変更する

概要

Armbianで採用されているブートローダー(U-Boot)は標準でf2fsに対応していません。そのためrootfsをf2fsに変更するには少し作業が必要です。

大まかな作業工程は以下のとおりです。

  1. パーティション作成/フォーマット
    U-Bootからの起動に必要な”bootパーティション(ext4)”と、システム本体の”rootパーティション(f2fs)”に分割します。
  2. U-Bootのコピー
    元イメージから新しいイメージにU-Bootをコピーします。
  3. Armbianイメージ内のファイルを新イメージにコピー
    元イメージからファイルを丸ごとコピーします。
  4. 新ディスクイメージ書き込みとパーティション拡張
    作成したイメージをmicroSDへ書き込み、容量目一杯まで利用出来るようrootパーティションを拡張します。
Armbianイメージのパーティション。本家イメージはrootfsがext4ですが、これをbootとrootのパーティションに2分割します。

ツールのインストール

では、実際の作業に移ります。Armbian公式サイトから目的のイメージファイルをダウンロードして、それを元にf2fsのイメージを作成していきます。

まず、必要なツールをインストールします。ubuntu/debian環境でも同じようなパッケージ名があると思います。

また、元になるArmbianのイメージファイルをダウンロード/展開します。ここでは元イメージのファイル名:”Armbian_community_26.11.0-trunk.62_Orangepipc_trixie_current_6.18.54_minimal.img”になります。

# ツールのインストール
sudo emerge --ask sys-fs/f2fs-tools

# イメージファイルの展開
xz -d Armbian_community_26.11.0-trunk.62_Orangepipc_trixie_current_6.18.54_minimal.img.xz

新しいディスクイメージの作成

空のイメージファイルを作成し、パティーションの作成とフォーマットを行います。f2fsで透過オプションを使用する場合はcompressionオプション付きでフォーマットを行います。後から変更出来ないので、使うかどうか分からないなら付けておきましょう。

また、ここではイメージファイルは3GByteで作成していますが、ベースがUbuntuの場合は元イメージも大きいはずです。元イメージより少し大きめになるようにしてください。

# 3GiBの空イメージファイルを作成
truncate -s 3GiB armbian_f2fs.img

# パーティションテーブル作成とパーティションの分割
parted -s ./armbian_f2fs.img mklabel msdos
parted -s ./armbian_f2fs.img mkpart primary ext4 8192s 512MiB
parted -s ./armbian_f2fs.img mkpart primary f2fs 512MiB 100%

# ループバックデバイスとしてセットアップ(/dev/loop0などにマップされる)
udisksctl loop-setup -r -f ./armbian_f2fs.img

# 各パーティションのフォーマット
sudo mkfs.ext4 -L "armbian_boot" /dev/loop0p1
sudo mkfs.f2fs -O extra_attr,inode_checksum,sb_checksum,compression -f -l "armbian_root" /dev/loop0p2

U-Bootの書き込み

元イメージからU-bootを抽出し、作成中のイメージに書き込みます。

# U-Boot抽出
$ dd if=./Armbian_community_26.11.0-trunk.62_Orangepipc_trixie_current_6.18.54_minimal.img of=uboot_extracted.bin bs=1k skip=8 count=1016

# U-Boot書き込み
$ dd if=uboot_extracted.bin of=./armbian_f2fs.img bs=1k seek=8 conv=fsync,notrunc

ファイルコピーと設定変更

元イメージからファイルをコピーし、f2fsで起動するための設定ファイルを書き換えます。ちょっと名前がややこしいのですが、ここでは各パーティションが以下のようにマウントされます。

  • 新イメージのboot: /run/media/username/armbian_boot
  • 新イメージのroot: /run/media/username/armbian_root
  • 元イメージのroot: /run/media/username/armbi_root
# 新イメージのパーティションをマウント
udisksctl mount -b /dev/loop0p1  # /run/media/username/armbian_boot
udisksctl mount -b /dev/loop0p2  # /run/media/username/armbian_root

# 元イメージをループバックデバイスとしてセットアップしマウント
udisksctl loop-setup -r -f ./Armbian_community_26.11.0-trunk.62_Orangepipc_trixie_current_6.18.54_minimal.img
udisksctl mount -b /dev/loop1p1  # /run/media/username/armbi_root

f2fsの透過圧縮を使用する場合は、ここで対象となるディレクトリにchattrコマンドを使ってC属性を設定します。私の場合、rootfsまるごと透過圧縮(*)の対象にしたかったためイメージの”/”にあたるディレクトリに属性設定しました。

(*)f2fsの透過圧縮機能は書き込むデータサイズを減らしてFlashメモリの寿命を伸ばすこと(+読み込み時パフォーマンスの向上)が目的です。デフォルトでは圧縮されて空いたスペースは解放されず、使用可能ディスク領域も増えません。マウントオプション次第で解放可能ですが制約があります。

# C属性(圧縮フラグ)の設定
sudo chattr +c /run/media/username/armbian_root/

# ファイルのコピー(boot)
sudo cp -a /run/media/username/armbi_root/boot/. /run/media/username/armbian_boot/

# ファイルのコピー(root)、不要ファイルの削除
sudo cp -a /run/media/username/armbi_root/. /run/media/username/armbian_root/
sudo rm -rf /run/media/username/armbian_root/boot/*

設定ファイル変更

以下のファイルを編集します。

  • armbian_boot/armbianEnv.txt
  • armbian_root/etc/fstab

まず、新イメージにあるパーティションのUUIDを確認します。

$ lsblk -f
NAME        FSTYPE FSVER LABEL        UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
loop0
├─loop0p1   ext4   1.0   armbian_boot fc000d26-1389-47d0-aba7-f237560ee1c6  387.8M    10% /run/media/username/armbian_boot
└─loop0p2   f2fs   1.16  armbian_root 48688e1b-a850-4ea7-a5f5-a51a9833f13a    1.3G    49% /run/media/username/armbian_root

armbianEnv.txt
以下の3行を追加/修正します。UUIDは上記で確認したarmbian_root(f2fs)のUUIDをセットします。”rootflags=atgc”はf2fsのガベージコレクションに関するオプションです。このオプションを使用する場合はarmbianEnv.txtと/etc/fstabの両方で設定する必要があります。指定しなかった場合、rootfsが読み込み専用(ro)でマウントされてしまいます。

...
rootdev=UUID=48688e1b-a850-4ea7-a5f5-a51a9833f13a
rootfstype=f2fs
extraargs=rootflags=atgc

/etc/fstab
以下のようにfstabを修正します。UUIDは上記で確認したものに置き換えてください。

ここでは、f2fsのマウントオプションとして”compress_algorithm=lz4″を指定して透過圧縮を有効にしました。OrangePi PCのCPUは非力なので圧縮ブロックのチェックサム確認(compress_chksum)は無効にしてあります。

後に続く大量の”nocompress_extension=”で圧縮対象から除外するファイル拡張子を指定しています。もう少しスマートな記述方法が無いのかと思ったのですが、一個ずつ指定するものらしいです(他の指定方法をご存知の方がおられたら教えてください)。お好みで修正してください。

UUID=48688e1b-a850-4ea7-a5f5-a51a9833f13a / f2fs compress_algorithm=lz4,atgc,gc_merge,checkpoint_merge,noatime,lazytime,nocompress_extension=zip,nocompress_extension=gz,nocompress_extension=bz2,nocompress_extension=xz,nocompress_extension=7z,nocompress_extension=deb,nocompress_extension=jpg,nocompress_extension=jpeg,nocompress_extension=png,nocompress_extension=gif,nocompress_extension=webp,nocompress_extension=mp4,nocompress_extension=mkv,nocompress_extension=mp3,nocompress_extension=ogg 0 1

UUID=fc000d26-1389-47d0-aba7-f237560ee1c6 /boot ext4 defaults,noatime,commit=120,errors=remount-ro 0 1

tmpfs /tmp tmpfs defaults,nosuid 0 0

ここまでで、イメージの作成作業は完了です。

SDカードへの書き込み

まず、ループバックデバイスのマウントを解除します。

# マウント解除とループデバイスの削除
udisksctl unmount -b /dev/loop0p1
udisksctl unmount -b /dev/loop0p2
udisksctl unmount -b /dev/loop1p1
udisksctl loop-delete -b /dev/loop0
udisksctl loop-delete -b /dev/loop1

続いて、作成したイメージをSDカードに書き込みます。書き込み先は各環境にあわせてください。
うっかり間違ったデバイス(PCのシステムドライブとか)に書き込まないようご注意を。

# SDカードへ書き込み
sudo dd if=./armbian_f2fs.img of=/dev/sdx bs=4M conv=fsync

次に、書き込んだイメージのarmbian_rootパーティションをSDカード目一杯まで領域を広げます。本来はarmbianの初回起動時にパーティションを自動的に広げてくれるのですが、f2fsに変更した影響で機能しません。なので、このタイミングで手動で広げてください。

# パーティションをディスク最大まで拡張
sudo parted -s /dev/sdx resizepart 2 100%

# f2fsファイルシステムのチェックとリサイズ
sudo fsck.f2fs -f /dev/sdx2
sudo resize.f2fs /dev/sdx2

これで完了です。あとはSDカードをOrangePi PC等のシングルボードコンピュータに挿入して起動すれば初期設定が行われるはずです。

Armbian起動後の設定について

動作確認

初期設定を終えてログイン後、ブロックデバイスを確認すると以下のようになっていました。問題なさそうですね。

~$ lsblk -f
NAME        FSTYPE FSVER LABEL        UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
mmcblk0                                                                                   
├─mmcblk0p1 ext4   1.0   armbian_boot fc000d26-1389-47d0-aba7-f237560ee1c6  382.1M    12% /boot
└─mmcblk0p2 f2fs   1.16  armbian_root 48688e1b-a850-4ea7-a5f5-a51a9833f13a   25.4G    10% /var/log.hdd
                                                                                          /
zram0       swap   1                  e1e16704-d916-46a9-b668-f68fabad1013                [SWAP]
zram1       ext4   1.0   log2ram      be0dc741-3561-4cf2-911f-16f1faa6b958   40.5M     6% /var/log
zram2

~$ findmnt -t ext4,f2fs
TARGET SOURCE                  FSTYPE OPTIONS
/      /dev/mmcblk0p2          f2fs   rw,noatime,lazytime,background_gc=on,gc_merge,discard,discard_unit=block,user_xattr,inline_xattr,a
├─/boot
│      /dev/mmcblk0p1          ext4   rw,noatime,errors=remount-ro,commit=120
├─/var/log.hdd
│      /dev/mmcblk0p2[/var/log]
│                              f2fs   rw,noatime,lazytime,background_gc=on,gc_merge,discard,discard_unit=block,user_xattr,inline_xattr,a
└─/var/log
       /dev/zram1              ext4   rw,nosuid,nodev,noexec,relatime,discard                              
無事に起動しました。

apt-eatmydataの導入

最後に、apt-eatmydataをインストールします。これはaptを使用してパッケージをインストールする際に途中で発行されるfsync()等を無効にして速度アップするためのものです。

なぜこんなものをインストールするのかというと、SDカード上のrootfsにf2fsを導入した環境ではapt installが猛烈に遅くなるからです。aptは更新作業中にfsync()を連発するらしく、そのたびにf2fsのcheckpoint処理が行われます。加えてSDカードはランダムアクセスが遅いためI/O Waitで処理が全く進みません。

apt-eatmydataを導入すれば、これを防げます。

# apt-eatmydataのインストール
sudo apt install apt-eatmydata

あとは普通にaptコマンドを使用するだけです。

sudo apt update
sudo apt upgrade

所感

ちょっと面倒くさい作業が必要ですが、無事にarmbianのディスクイメージをf2fsに変更することが出来ました。

実は、最初は一発でf2fsイメージの生成までやってくれるスクリプトを作ろうとしていたのですが、sudo付けて得体のしれないスクリプト実行するのは嫌だろう、とこんな感じの記事になりました。
(AIとあーだこーだやり取りしながらlibguestfsを使ったいい感じのスクリプトも出来たのですが、gentooのlibguestfsはf2fs未対応のようで頓挫しました…)

元々armbianはログファイルをzram上に一時保存するなどしてSDカード寿命に気を使ってくれていますが、何年も運用しているとアップデートやらで書き込み量は増えてきます。いずれ駄目になるとしても、これで多少は長生きしてくれるでしょう。

SDカードの書き換え回数を減らし寿命向上を狙いたい方は、このf2fs化の手順でストレージ環境を最適化してみては如何でしょうか。

参考

この記事は以下の内容を参考にしました。

PC
スポンサーリンク

コメント