2023年10月9日月曜日

FreeBSD で zfs をアップグレードした際に efi boot 領域を作り直した

 2023年9月に FreeBSD で使用している「zfs」に M.2 NVMe 接続の SSD を追加した。 その際,「zfs」ファイルシステムのアップグレードが必要であり,かつ元からあった 2.5 inch SSD の efi boot 領域を作り直さないといけなかった。 その件についてメモを兼ねて書いておこう。

 そもそも,なぜ zfs のアップグレードが必要になったというと,使用している 2.5 inch の SSD の容量が心もとなくなってきたから,だった。 現在,当該の FreeBSD は L社の Note PC に入っているが,HDD は遅いので SSD に置き換えている。 その際,1TB の 2.5 inch SSD を入れたのだが,web サーバーに写真やらを大量に置いていると徐々に SSD の容量を圧迫してきた。 実質 920GB ほどの領域で,空きが 180GB 程度になっていた。 さすがにこれはちょっと心もとない。ということで,ストレージを増やすことにした。

 ストレージを増やすには,一つの手段として 2.5 inch SSD をより大きな容量のものに変更する,という手が考えられる。 しかし,それだと新しい SSD にシステムを入れ直して,データも移動させないといけない。それは手間がかかる。 一方,現在使っている Note PC には空いている NVMe のスロットがある。それなら新たに NVMe の SSD を追加することもできる。 M.2 NVMe を追加するなら 2.5 inch SSD は特に何もしなくていいことになる。データの移動もさせなくてもいい。 そこで 1TB の M.2 NVMe SSD を買って追加することにした。 (M.2 NVMe SSD の追加の話は次の投稿で書くことにする

 ところで,現在 FreeBSD を入れているサーバーは,ファイルシステムとして「zfs」を使っている。 これはもともと Oracle 社の Solaris 用に開発されたものみたい。 zfs の便利な点は,複数のデバイス(複数の HDD や複数の SSD など)をストレージに使う際に,見た目は全体として1個のファイルシステムとして扱える点が挙げられる。 そのため,どんな物理デバイスがどのように使われているか,をあまり意識しなくていい。 デバイスを追加する際にも,いちいちスライスを切り直したりしなくてもいい。 また,既存のシステムのデバイスを交換する際にも,物理的にデバイスを接続した後の処理がシステムを止めずにできる。 デメリットとしては,ファイルシステムの管理用にある程度 CPU の能力を使う点が挙げられるが…。

 今回は既存のシステムに M.2 NVMe SSD を追加するだけなので,zfs の利点を活かせることになる。 そこで,まずは現時点での状況を確認してみることにした。 zfs では物理的に異なる HDD や SSD の代わりに「プール(pool)」という概念がストレージの単位として使われる。 言い換えると「プール」という大きな HDD が1個あるような感じである。 そのため,まず「プール」を1個作り,その中にデバイスを追加して,複数の(1個でもいいが)HDD や SSD で1個のプールを構成する。

 zfs の状況を把握するにはいくつか有用なコマンドがあるが,まずはどんなプールがあるかを調べるには「zpool list」を使う。
# zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zroot   920G   741G   179G        -         -    50%    80%  1.00x    ONLINE  -
ここで「zroot」というのがプールの名前であり,「zroot」という大きな HDD が1個あるイメージである。 使用できる容量が 920GB に対して,741GB を使用して,結果として 179GB の空きスペースがある。 つまり,容量の 80% を使ってしまっている。これはそろそろストレージを拡張しないといけないことを示している。

 zroot プールの状況を把握するには「zpool status」コマンドを使う(これは zfs のアップグレード後のもの)。
# zpool status zroot
  pool: zroot
   state: ONLINE
   config:

        NAME        STATE     READ WRITE CKSUM
        zroot       ONLINE       0     0     0
          ada0p4    ONLINE       0     0     0

errors: No known data errors
ここでは「zroot」プールに,「ada0p4」が使われている。 この「ada0p4」は,「ada0」デバイスのパーティション 4番を意味している。 「ada0」デバイスは SATA 接続のデバイスを意味し,ここでは 2.5 inch SSD をつないでいる。 また「ada0p4」の「p4」は「4番目のパーティション」を意味している。パーティションについては後で書こう。

この「zpool status」コマンドを使った結果が,今回は以下のようになった。
# zpool status zroot
  pool: zroot
 state: ONLINE
status: Some supported and requested features are not enabled on the pool.
        The pool can still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
        the pool may no longer be accessible by software that does not support
        the features. See zpool-features(7) for details.
config:

        NAME        STATE     READ WRITE CKSUM
        zroot       ONLINE       0     0     0
          ada0p4    ONLINE       0     0     0

errors: No known data errors
問題がない場合の結果(上記の結果)と比べると「status」と「action」なる項目が増えてる…。 そこを読むと,どうやら「zfs をアップグレードせよ」と書いてある。

 そこで zfs をアップグレードしてみたのが今回のお話のメイン。

zfs のアップグレード

 zfs をアップグレードするには
# zpool upgrade -a
または
# zpool upgrade zroot
を使う。 結果は,
# zpool upgrade -a
This system supports ZFS pool feature flags.

Enabled the following features on 'zroot':
  large_dnode
  userobj_accounting
  encryption
  project_quota
  spacemap_v2
  allocation_classes
  resilver_defer
  bookmark_v2
  redaction_bookmarks
  redacted_datasets
  bookmark_written
  log_spacemap
  livelist
  device_rebuild
  zstd_compress
  draid

Pool 'zroot' has the bootfs property set, you might need to update
the boot code. See gptzfsboot(8) and loader.efi(8) for details.
どうやらアップグレードは正常に終わったけど,まだ「boot code のアップデートが必要」みたい。

boot code のアップデート

 boot code のアップデートについて調べると,まずは UEFI から起動しているのか,昔からの BIOS を使っているのか,で多少異なるみたいだった。 そこでまずは使われている物理デバイス(ここでは 2.5 inch SATA 接続 SSD)のパーティションがどうなっているかを見てみる。 そのためには「gpart show」コマンドを使う。
# gpart show
=>        40  1953525088  ada0  GPT  (932G)
          40      409600     1  efi  (200M)
      409640        1024     2  freebsd-boot  (512K)
      410664         984        - free -  (492K)
      411648    20971520     3  freebsd-swap  (10G)
    21383168  1932140544     4  freebsd-zfs  (921G)
  1953523712        1416        - free -  (708K)
ここで左端の数字はパーティションの先頭のセクター番号を表し,左から2番目の数字が各パーティションの容量,「ada0」の下にある3番目の数字がパーティション番号を示している。 ここではパーティション 1 が UEFI 起動に使われる efi 領域で,パーティション 2 に boot 領域 (freebsd-boot 領域) がある。 パーティション 3 はスワップ領域で,パーティション 4 が zfs のデータ領域となっている。「- free -」となっている所は,サイズの都合で何にも使われていない「隙間」である。
 ここでは efi 領域があるので,このシステムでは UEFI 起動に対応している。ちなみに UEFI は「Unified Extensible Firmware Interface」のことらしい。 GUID Partition Table (GPT) と呼ばれる種類のパーティションで使えるらしい。

 boot code のアップデートは,まず以下の「gpart bootcode」コマンドを実行する。
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 2 ada0
partcode written to ada0p2
bootcode written to ada0
ここでは「ada0」デバイスのパーティション 2 番に boot code を書き込んでいるみたい。

 さらに efi パーティションのコードも更新しないといけないらしい。 手順は,efi 領域のパーティション 2 をマウントして,boot code をコピーしてからアンマウントするみたい。 というのでやってみたが,以下のように「エラー」がでてしまった。
# mount -t msdosfs /dev/ada0p1 /mnt
# cp -p /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
overwrite /mnt/EFI/BOOT/BOOTX64.efi? (y/n [n]) y
cp: /boot/loader.efi: Input/output error
[1]    58508 exit 1     cp -i -p /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
# umount /mnt
これは何?と思い,いろいろやってみたが,どうも 512 バイト以上は書き込めない状態になっているみたいだった。 efi 領域は 200 MB も取ってあるのに???

 そこで,下記のように efi パーティションを一度消してから作り直し,その後で boot code をコピーにしてみた。
# gpart delete -i 1 ada0
# gpart add -t efi -b 40 -s 409600 ada0
# newfs_msdos -F 32 -c 1 -L EFISYS /dev/ada0p1
/dev/ada0p1: 403266 sectors in 403266 FAT32 clusters (512 bytes/cluster)
BytesPerSec=512 SecPerClust=1 ResSectors=32 FATs=2 Media=0xf0 SecPerTrack=63 Heads=16 HiddenSecs=0 HugeSectors=409600 FATsecs=3151 RootCluster=2 FSInfo=1 Backup=2
まずは efi パーティションを削除し,「gpart show」コマンドで見た結果と同じサイズでパーティション 1 に efi パーティションを作る。 そして最後に efi パーティションに msdos ファイルシステムを構築している。パーティションを作ってもファイルシステムを構築しないとストレージとしては使えないのが注意点である。 またサイズは「409600」よりも「409560」の方が余分な「隙間」ができなくていいらしいが,ここでは既存のものを置き換えるので「409600」としている。

それから以下のように boot code をコピーしたらうまくいった。
# mount -t msdosfs /dev/ada0p1 /mnt
# mkdir /mnt/efi
# mkdir /mnt/efi/boot
# cp /boot/loader.efi /mnt/efi/boot/BOOTx64.efi
# echo "BOOTx64.efi" > /mnt/efi/boot/startup.nsh
# chmod 755 /mnt/efi/boot/startup.nsh
# umount /mnt
まずパーティション 1 (efi パーティション) をマウントし,そこに「/efi/boot/」というディレクトリを作っている。 そこに「/boot/loader.efi」をコピーして「BOOTx64.efi」という名前にしている。 さらに同じディレクトリに「startup.nsh」なるファイル(中身は BOOTx64.efi だけ)を置き,実行可能としてある。 startup.nsh はほんとに必要かどうかわからないが,既存のシステムに存在していたので作っておいた。

最後に

 これで「zfs」ファイルシステムのアップグレードができた。 ちゃんと再起動できることも確認しておいた。 そこで,次に Note PC に M.2 NVMe 接続の SSD を追加してみた(次回へ)

0 件のコメント: