vm-bhyveで使っているzvolをマウントする

#ネタ元
この記事の大部分はfreebsd-stableのアーカイブにある[reboot-less zfs volmode property refresh?](https://www.mail-archive.com/freebsd-stable@freebsd.org/msg134763.html)に基づいている。

#動機
vm-bhyveで仮想化しているVMのディスクイメージにZFS volumeを使っている時に、ホスト側からディスクの中身にアクセスしたいことがある。例えばインストールがうまく行っておらず、ブートローダの状況を確かめたい場合など。

#前提
* FreeBSD 11.1-RELEASE-p9

#問題点
vm-bhyveでZFS volume (zvol)をディスクイメージに使うと、`volmode=dev`で作成されているためそのままではGEOMベースのツールが使えない。たとえば`gpart`でGPTパーティションを見ることもできないし、マウントすることもできない。

#解決法
##volmode=geomを使う
`volmode=dev`になっているのがいけないので、`volmode=geom`にしてやればいい。ただ話はそんなに簡単ではなく、単に`zfs set volmode=geom`とするだけではダメ。

```shell-session
> zfs get volmode tank/vm/ubuntu/disk0
NAME                  PROPERTY  VALUE    SOURCE
tank/vm/ubuntu/disk0  volmode   dev      local
> gpart show /dev/zvol/tank/vm/ubuntu/disk0
gpart: No such geom: /dev/zvol/tank/vm/ubuntu/disk0.
> sudo zfs set volmode=geom tank/vm/ubuntu/disk0
> zfs get volmode tank/vm/ubuntu/disk0
NAME                  PROPERTY  VALUE    SOURCE
tank/vm/ubuntu/disk0  volmode   geom     local
> gpart show /dev/zvol/tank/vm/ubuntu/disk0
gpart: No such geom: /dev/zvol/tank/vm/ubuntu/disk0.
```

これはシステムがvolmodeプロパティを1回しか参照しないため。既にシステムから見えているzvolをvolmode=geomに変更しても、その時点ではGEOM providerとして認識されない。

###再起動する
システム自体を再起動してやれば、起動時にGEOM providerとして認識される。

```shell-session
> gpart show /dev/zvol/tank/vm/ubuntu/disk0
=>     34  8388541  zvol/tank/vm/ubuntu/disk0  GPT  (4.0G)
       34     2014                             - free -  (1.0M)
     2048  1048576                          1  efi  (512M)
  1050624  5335040                          2  linux-data  (2.5G)
  6385664  2000896                          3  linux-swap  (977M)
  8386560     2015                             - free -  (1.0M)

```

めでたしめでたし。

###クローンを使う（読み込み専用）
でも再起動したくない時もある。そんなときはクローンを作成する時にvolmode=geomとする方法がある。

```shell-session
> sudo zfs snapshot tank/vm/ubuntu/disk0@snap
> sudo zfs clone -o volmode=geom tank/vm/ubuntu/disk0@snap tank/vm/ubuntu/clone0
> gpart show /dev/zvol/tank/vm/ubuntu/clone0
=>     34  8388541  zvol/tank/vm/ubuntu/clone0  GPT  (4.0G)
       34     2014                              - free -  (1.0M)
     2048  1048576                           1  efi  (512M)
  1050624  5335040                           2  linux-data  (2.5G)
  6385664  2000896                           3  linux-swap  (977M)
  8386560     2015                              - free -  (1.0M)

> sudo mount -t msdosfs -o ro /dev/zvol/tank/vm/ubuntu/clone0p1 /mnt
> ls -la /mnt
total 17
drwxr-xr-x   1 root  wheel  4096 Jan  1  1980 ./
drwxr-xr-x  22 root  wheel    28 Apr 26 22:21 ../
drwxr-xr-x   1 root  wheel  4096 Apr 25 17:37 EFI/
> sudo umount /mnt
> sudo zfs destroy -R tank/vm/ubuntu/disk0@snap
```

ただこの方法は元々のzvolに書き込むことはできない。あくまでちょっと中身を覗きたい時向け。

##CAM Target Layerを使う
再起動せずにzvolの中身を書き換えたい場合は、ちょっと煩雑だがctl(4)を使ってGEOM providerを生成する方法がある。

```shell-session
> sudo ctladm create -b block -d zvol-for-write -o file=/dev/zvol/tank/vm/ubuntu/disk0
LUN created successfully
backend:       block
device type:   0
LUN size:      4294967296 bytes
blocksize      512 bytes
LUN ID:        0
Serial Number: MYSERIAL   0
Device ID;     zvol-for-write
> sudo ctladm port -p `sudo ctladm port -l | grep "camsim.*naa" | cut -w -f 1` -o on
Front End Ports enabled
> gpart show da0
=>     34  8388541  da0  GPT  (4.0G)
       34     2014       - free -  (1.0M)
     2048  1048576    1  efi  (512M)
  1050624  5335040    2  linux-data  (2.5G)
  6385664  2000896    3  linux-swap  (977M)
  8386560     2015       - free -  (1.0M)

> sudo mount -t msdosfs /dev/da0p1 /mnt
> ls -la /mnt
total 17
drwxr-xr-x   1 root  wheel  4096 Jan  1  1980 ./
drwxr-xr-x  22 root  wheel    28 Apr 26 22:21 ../
drwxr-xr-x   1 root  wheel  4096 Apr 25 17:37 EFI/
> sudo mkdir /mnt/test
> ls -la /mnt
total 21
drwxr-xr-x   1 root  wheel  4096 Jan  1  1980 ./
drwxr-xr-x  22 root  wheel    28 Apr 26 22:21 ../
drwxr-xr-x   1 root  wheel  4096 Apr 25 17:37 EFI/
drwxr-xr-x   1 root  wheel  4096 Apr 26 22:43 test/
> sudo umount /mnt
> sudo ctladm port -p `sudo ctladm port -l | grep "camsim.*naa" | cut -w -f 1` -o off
Front End Ports disabled
> sudo ctladm remove -b block -l `sudo ctladm devl | grep "zvol-for-write" | cut -w -f 2`
LUN 0 removed successfully
```