彷徨えるフジワラ

年がら年中さまよってます

beadm コマンドの舞台裏

本エントリは、Solaris Advent Calendar 2016 の 16 日目です。

「ENOSPC だと beadm destroy できない」問題

先日、久々に仮想環境ゲストの OpenSolaris 上で pkg update を実行したところ、新規ブート環境 (Boot Environment: BE) が作成された上で、大量の更新が実施されたことで、rpool の容量があふれてしまい:

  • "No space left on device" (ENOSPC) で pkg update が失敗
  • beadm destroy 新規BE も ENOSPC で失敗
  • 再起動すると、メンテナンスモードに突入
  • メンテナンスモードでも beadm destroy 新規BE は不可

上記のような、にっちもさっちもいかない状況に陥ってしまいました。

新規 BE はアクティブ化もされていない状況だったので、サクっと破棄できそうな気がするのですが、どうやら beadm destroy 新規BE の際に実施されるマウント処理が、ENOSPC で失敗してしまう模様です。

このような状況で、状態を正常化するには、beadm コマンドの内部的な実現方式を把握しておく必要があります。

BE 作成 〜 アクティブ化 〜 破棄に相当する操作

まずは、ZFS ブート環境において、現在稼働している(= アクティブな) BE の名前を OLDBE と仮定します。この時、zfs ファイルシステム rpool/ROOT/OLDBE が存在することになります。

この状態から、新規 BE として NEWBE を作成するために beadm create NEWBE コマンドを実行した場合、以下に相当する処理が実施されます。

  1. zfs snapshot rpool/ROOT/OLDBE@YYYY-mm-dd-HH:MM:SS でスナップショット作成
    スナップショット名はコマンド実行時の日付を元に作成
  2. zfs clone rpool/ROOT/OLDBE@YYYY-mm-dd-HH:MM:SS rpool/ROOT/NEWBE で複製ファイルシステムを作成
  3. /rpool/boot/grub/menu.list ファイルに NEWBE 用のエントリを追加

以上で、NEWBE が新規 BE として作成されたことになります。

beadm activate NEWBE による NEWBE アクティブ化は、以下の操作に相当します。

  1. zfs promote rpool/ROOT/NEWBE により、複製元スナップショット(群)の所有権を NEWBE 側に移譲
  2. /rpool/boot/grub/menu.list ファイルのデフォルト選択肢を NEWBE に変更

スナップショット @YYYY-mm-dd-HH:MM:SS をはじめとする rpool/ROOT/OLDBE 配下のスナップショットは、上記 zfs promote を境に、rpool/ROOT/NEWBE 配下に属するようになります。この状態は zfs list -r -t all rpool/ROOT で確認できます。

また、rpool/ROOT/OLDBE の内部的な扱いも、「rpool/ROOT/NEWBE@YYYY-mm-dd-HH:MM:SS から clone したもの」になります。この状態は、以下の属性から確認できます。

  • rpool/ROOT/OLDBE の origin 属性が rpool/ROOT/NEWBE@YYYY-mm-dd-HH:MM:SS
  • rpool/ROOT/NEWBE@YYYY-mm-dd-HH:MM:SS の clones 属性に rpool/ROOT/OLDBE が追加

この操作により、既存のスナップショットから OLDBE への依存がなくなるため、OLDBE を破棄することが可能になります。

beadm destroy OLDBE による OLDBE の破棄は、以下の操作に相当します。

  1. zfs destroy rpool/ROOT/OLDBE により、対応する zfs ファイルシステムを破棄
  2. /rpool/boot/grub/menu.list ファイル中の OLDBE 用のエントリを削除

非常時に手動で beadm destroy 相当の処理を実施

さて、冒頭で述べたような「beadm destroy が実行できない」問題は、beadm destroy の延長で実施される「削除対象 BE のマウント処理」が、ENOSPC のために失敗する点にあります。

しかし、beadm list で表示される BE 一覧情報は、単純に rpool/ROOT 直下の(ブート可能な)ァイルシステムを列挙しているだけです。裏を返せば、BE に相当するファイルシステムを rpool/ROOT 配下から削除できさえすれば良いわけです。

幸い、zfs destroy はマウント処理無しでも実施できます。直接 zfs destroy rpool/ROOT/新規BE を実行することで、ENOSPC によるマウント失敗云々の影響無しに、新規 BE に相当するファイルシステムが破棄できました。

beadm list でも新規 BE の破棄が確認できましたし、更新内容が詰まっていたであろうファイルシステムが破棄されたことで、rpool の未使用容量も大丈夫そうなサイズに戻っています。

後は /rpool/boot/grub/menu.list を編集すれば、状態正常化作業は完了です。

ちなみに、新規 BE を破棄して再起動できるようになった時点では、rpool の容量不足で pkg update が失敗する問題は解決されていません。

しかし、ZFS は新規ディスクを追加することで簡単に容量を拡張できるので、正常状態にさえ戻ってしまえばこっちのものです(笑)