zfs - MacBook Air (13-inch, Late 2010) をオクタブート化

勇者がいないなら、自分が勇者になればいいのに。

[前回記事]
> 勇者はぜひ上記に macOS と illumos も加えたクアッドブートディスクをこさえてみてください。

[前回記事]: http://qiita.com/dankogai/items/fee382b14277de1f66a9

というわけでやりました。 illumos は後述の理由でないけどクワッドどころかオクタブートです。それもベアメタルで。

![refind.jpg](https://qiita-image-store.s3.amazonaws.com/0/19227/4807b430-5b4b-b074-f67c-669e296be19d.jpeg)

[MacBook Air (13-inch, Late 2010)]。6年以上前の[ノートブックの未来]、かつて私のメインノートで、その後長女のメインノート。だから裏蓋はこんな。

[MacBook Air (13-inch, Late 2010)]: https://support.apple.com/kb/SP618

[ノートブックの未来]: http://blog.livedoor.jp/dankogai/archives/51743116.html

![macbookair3,2.jpg](https://qiita-image-store.s3.amazonaws.com/0/19227/b69b028d-64d9-c42b-56c2-0ce35df42f7c.jpeg)

その長女のメインノートも、私と同じ MacBook Pro (Retina, 13-inch, Mid 2014) に変わって以来、しばらくお蔵入りしていたのを引っ張り出して来ました。

USB3はおろか、Thunderboltもない、CPUパワーは今日日のiPhoneに負けてしまうロートルですが、 Sierra も Windows 10 も動きます。もちろん Ubuntu だって FreeBSD だって。

というわけでこの子は

1. ふつうの HFS+ 上の macOS Sierra
2. ふつうの macOS Recovery[^1]
3. ふつうの Boot Camp な Windows 10[^2]
4. ZFS上の macOS Sierra
5. ZFS上の Ubuntu 16.04
6. ZFS上の Ubuntu 16.10
7. ZFS上の FreeBSD 11.0-RELEASE
8. ZFS上の FreeBSD 12-CURRENT

という8種類のブートを現在サポートしています。

[^1]: ふつうにcmd-Rで上がります
[^2]: 厳密にはAppleのサポート切れ。BIOSエミュレーションのBoot CampはWindows 10をサポートしていないことになっている。がふつうにWindows 7をアップグレードすればほぼ無問題。

実は1から3までは、ふつうにBoot Camp化したMacと変わらず、OS X改めmacOSもWindowsもそのままアップグレードし続けて現在に至っています。つまり、元々あったものは何も失われていないのです。さすがに長女から戻って来たときにアカウントとユーザーは作り直していますが。

## パーティション構成

しかしこの子には、パーティションはEFIを含めても6つしかありません。

### macOS: `diskutil list`
````
/dev/disk0 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *251.0 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS root@dan-mba32          64.0 GB    disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
   4:       Microsoft Basic Data BOOTCAMP                64.0 GB    disk0s4
   5: 516E7CBA-6ECF-11D6-8FF8-00022D09712B               121.3 GB   disk0s5
   6:                 Apple_Boot boot                    650.0 MB   disk0s6

/dev/disk1 (external, virtual):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                            Sierra                 +549.8 GB   disk1
````
### Windows: `diskpart`
````
DISKPART> list partition

  Partition ###  Type              Size     Offset
  -------------  ----------------  -------  -------
  Partition 1    Primary            200 MB    512 B
  Partition 2    Primary             59 GB   200 MB
  Partition 3    Primary            619 MB    59 GB
  Partition 4    Primary             59 GB    60 GB
````
### Linux: `fdisk -l`
````
Device         Start       End   Sectors   Size Type
/dev/sda1         40    409639    409600   200M EFI System
/dev/sda2     409640 125409639 125000000  59.6G Apple HFS/HFS+
/dev/sda3  125409640 126679175   1269536 619.9M Apple boot
/dev/sda4  126679176 251679175 125000000  59.6G Microsoft basic data
/dev/sda5  251679176 488657351 236978176   113G FreeBSD ZFS
/dev/sda6  488657352 489926887   1269536 619.9M Apple boot
````
### FreeBSD: `gpart show`
````
=>       34  490234685  diskid/DISK-906A52MPK0YK  GPT  (234G)
         34          6                            - free -  (3.0K)
         40     409600                         1  efi  (200M)
     409640  125000000                         2  apple-hfs  (60G)
  125409640    1269536                         3  apple-boot  (620M)
  126679176  125000000                         4  ms-basic-data  (60G)
  251679176  236978176                         5  freebsd-zfs  (113G)
  488657352    1269536                         6  apple-boot  (620M)
  489926888     307831                            - free -  (150M)
````

そして8つあるブート環境(boot environment)のうち5つは、ZFSパーティションの中に存在します。

### `zfs list`
````
NAME                    USED  AVAIL  REFER  MOUNTPOINT
rpool                  30.4G  78.1G    88K  none
rpool/ROOT             30.3G  78.1G    88K  none
rpool/ROOT/Sierra      11.3G  78.1G  10.6G  /
rpool/ROOT/freebsd11r  3.39G  78.1G  3.31G  /
rpool/ROOT/freebsd12c  9.43G  78.1G  8.76G  /
rpool/ROOT/xenial      2.76G  78.1G  2.41G  /
rpool/ROOT/yakkety     3.42G  78.1G  3.69G  /
rpool/Users             352K  78.1G    88K  /Users
rpool/Users/Shared       88K  78.1G    88K  /Users/Shared
rpool/Users/dankogai     88K  78.1G    88K  /Users/dankogai
rpool/home             36.0M  78.1G   332K  /home
rpool/home/dankogai    32.2M  78.1G  24.6M  /home/dankogai
rpool/home/root         876K  78.1G   608K  /root
rpool/tmp                88K  78.1G    88K  /tmp
rpool/usr               464K  78.1G    88K  /usr
rpool/usr/local          88K  78.1G    88K  /usr/local
rpool/usr/obj            96K  78.1G    96K  /usr/obj
rpool/usr/ports          96K  78.1G    96K  /usr/ports
rpool/usr/src            96K  78.1G    96K  /usr/src
rpool/var                88K  78.1G    88K  /var
````

### `zfs get -t filesystem canmount`
````
NAME                   PROPERTY  VALUE     SOURCE
rpool                  canmount  off       local
rpool/ROOT             canmount  off       local
rpool/ROOT/Sierra      canmount  noauto    local
rpool/ROOT/freebsd11r  canmount  noauto    local
rpool/ROOT/freebsd12c  canmount  noauto    local
rpool/ROOT/xenial      canmount  noauto    local
rpool/ROOT/yakkety     canmount  noauto    local
rpool/Users            canmount  off       local
rpool/Users/Shared     canmount  off       local
rpool/Users/dankogai   canmount  off       local
rpool/home             canmount  on        default
rpool/home/dankogai    canmount  on        default
rpool/home/root        canmount  on        default
rpool/tmp              canmount  off       local
rpool/usr              canmount  off       local
rpool/usr/local        canmount  off       local
rpool/usr/obj          canmount  off       local
rpool/usr/ports        canmount  off       local
rpool/usr/src          canmount  off       local
rpool/var              canmount  off       local
````

実のところ、UEFIとZFS rootをサポートしたOSであれば、`rpool`にいくらでも足して行けます。今回illumosを見送ったのは、残念ながら現状ではUEFIがサポートされていないから。

https://wiki.illumos.org/display/illumos/Architecture
> Currently not ported as Illumos kernel does not support UEFI. The UEFI boot will read efi boot program from EFI System partition (fat file system), and efi boot program will load the loader.

BIOS方式だと、使えるパーティションはBoot Campまでで食い潰されちゃってるわけです。

## レシピ

ざっくりこんな感じで。

### HFS+パーティションの縮小

ふつうに Disk Utility でできます。ボリュームのライブ縮小は、HFS+やNTFSにあってZFSにない数少ない機能ですね。APFSはどうなんだろう…

### Windowsパーティションの引越し

`dd`と`gparted`[^3]を駆使しても出来るのですが、私はたまたま昔買った[Winclone]を使いました。これだと Bootcamp Partition を圧縮して保管してくれるのでずいぶんと楽です。余談ですが、Windows 10からやっとライセンスの紐付けがハードウェア単位からユーザー単位になったようなので、(DSP版とかでなければ)この方法で別種のMacにもBoot Campを引っ越せるかもしれません[^4]。

[^4]: cf. http://pc.watch.impress.co.jp/docs/topic/review/1008323.html

[Winclone]: https://twocanoes.com/products/mac/winclone
[^3]: UbuntuのライブDVD/USBスティックに標準で入ってます。

### ZFSプールおよびmacOS on ZFS root用のブートパーティションの準備

基本的に[o3x]のWikiページ[ZFS on Boot]の通りです。ZFS on Bootとはいっても、厳密にはZFS on Rootまでで、カーネルはHFS+なブートパーティションから読みます。私の場合、macOS Recoveryと全く同じサイズのパーティションを作りました。そして残った部分をすべてZFS用に。

[o3x]: https://openzfsonosx.org/
[ZFS on Boot]: https://openzfsonosx.org/wiki/ZFS_on_Boot

* macOS on ZFS root環境構築

これまたほぼ[ZFS on Boot]の通りなのですが、相違点もいくつか。

* `rpool`作成時に、`-O casesensitivity=insensitive`はつけない。他のOSとの共存で問題になるので。一方`-O normalization=formD`はmacOSのために必須。ファイルネーム的にはHFSXとほぼ同等。
* ZFSのインストールは、o3x 1.6.1があればビルド不要
* `mount_zfs`コマンドを`/Library/Filesystems/zfs.fs/Contents/Resources`ディレクトリ内に用意しておかないとrootマウントに失敗する。環境構築時に`/Volumes/Sierra`にmacOS on ZFS rootがマウントしてあるとして

````
$ cd /Volumes/Sierra/Library/Filesystems/zfs.fs
$ sudo cp -a /usr/local/bin/mount_zfs ./Contents/Resources
$ sudo ln -s ./Contents/Resources/mount_zfs .
````

として修正。

### 残りのOSのインストール

あとはちょろいものです。OSは「インスートル」せず、すでに出来上がっている環境(仮想マシンでもUSBメモリーでもOK)を`zfs send`して`rpool/ROOT`以下にreceiveすればいいのですから。

やや難しいのはブートローダーの構築なのですが、UEFIと[rEFInd]おかげで少し楽です。基本的にEFIパーティションの中にブートローダー放り込むだけでOKなので。

[rEFInd]: http://rodsbooks.com/refind/ 

#### FreeBSD

````
# mkdir /boot/efi
# mount -t msdosfs /dev/ada0p1 /boot/efi
# mkdir -p /boot/efi/EFI/freebsd
# cp -a /boot/boot1.efi /boot/efi/EFI/freebsd
````

てな感じでいけます。なお、バージョン違いのFreeBSDをインストールする際には

````
# pkg install beadm
# beadm create freebsd12c
# beadm activate freebsd12c
````

などとしてBoot Environmentをcloneしてから再起動してからアップグレードすると楽です。

#### Ubuntu (and other Linuxen)

[Ubuntu 16.04 Root on ZFS]のTroubleshootingの方法にのっとって`chroot`した後に、grubを再構築すればOK。その際に

````
# bootid=xenial
# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=$bootid --recheck --no-floppy
````

などとして、distroごとに`grubx64.efi`が別ディレクトリーに入るようにしておくと、rEFIndで容易に切り替えられるようになります。

[Ubuntu 16.04 Root on ZFS]: https://github.com/zfsonlinux/zfs/wiki/Ubuntu-16.04-Root-on-ZFS

FreeBSDと違い、ZFS on Linux の grub は Boot Environment をサポートしておらず、root datasetは`grub.cfg`に決め打ちになるのですが、rEFIndのおかげでかえってラクかも。

FreeBSD同様、root datasetをcloneしてから`dist-upgrade`すると楽ちんです。

## CAVEAT

* macOSとFreeBSDのブートローダーはプールの`bootfs`プロパティを見てどのデータセットを`/`にマウントするかを決めているので、これの変更を忘れてOSを切り替えると泣きを見ます。変更前に

````
# zpool set bootfs=rpool/ROOT/$nextboot rpool
````

しておくこと。

* 他OSからLinuxに切り替えると、busyboxに落ちます。これはZFS on Linuxではブートごとにルートプールを`import`し、シャットダウンごとに`export`しているため、「まだ`export`されていないプールは`import`しませんっ」ってのが理由なので、`zpool import -f -N -R / rpool`と呪文を唱えてからctrl-Dすればおk。

## OSごとの所感

### macOS

ZFS上でも無問題。o3xのバージョンアップ以外なら、ふつうにソフトウェアアップデートもかけられますし、o3xのバージョンアップの場合にも、HFS+側をアップデートしてから`/Library/Filesystems`と`/usr/local`を`rsync`してから`boot`パーティションを再構築すればいけるはず。

### Windows

UEFI時代前のWindows 7時代のBoot Campだけあって、BIOSモードでブートしているのですが、その点を除けばふつうに使えます。Windows 10の「メイジャーアップデート」(例えばAnniversary Editionとか)の際にトラックパッドを見失うのですが、この場合はDevice Managerで再設定してやれば元どおりになります。

cf. http://www.msitgeek.com/fixing-windows-8-trackpad-driver-in-bootcamp/

### Ubuntu

さすがに枯れたマシンだけあって、wifi含め問題なし。唯一の問題はサスペンド時にディスプレイが戻らないことですが、これも`/etc/pm/config.d/defaults`に

````
ADD_PARAMETERS="--quirk-reset-brightness"
DROP_PARAMETERS="--quirks-none"
````

を追記するだけでOK。こちらをメインに使いたい人も結構いるのでは。でもキーボード叩いてる時にトラックパッドきちんと無視してくれない…

### FreeBSD

内臓wifiはダメですが、あとはまあまあ動きます。一応`wsp`ドライバーのおかげでマルチタッチもいけるはいけるのですが、Ubuntuほど自然ではないです。USB EthernetはAX88178A/AX88179を使ってるものであれば[axge]ドライバーで動きます。私の場合[LUA4-U3-AGT]を使ってます。`/etc/rc.conf`に

[LUA4-U3-AGT]: http://amzn.to/2lS7lET
[axge]: https://www.freebsd.org/cgi/man.cgi?query=axge&sektion=4

````
ifconfig_ue0="DHCP"
````

としてから再起動するなり`service netif restart`するなりすればOK。

macOSでもWindows 10でも使えますし、純正のThunderbolt Ethernet Adapterと違ってMac以外でも抜き差しOKでしかも安価(いずれも2000円弱)なので、一つ用意しておくといざという時「こんなこともあろうかと」できます。

## さいごに

仮想マシンが散歩だとするとベアメタルは登山という感じですが、これくらいなら高尾山ぐらいかな。大昔のOSごとに実パーティションを切るマルチブートと比べたら、ZFSのマルチブートはほんとラク。

仮想マシンとコンテナに慣れきったみなさんも、たまにはベアメタルと戯れましょう。

Dan the Unofficial ZFS Advocate