Switching from Zevo to OpenZFS on OS X

I recently moved my last Mac from Greenbytes Zevo to OpenZFS on OS X, the reason for both sticking with Zevo & switching to OpenZFS were one and the same, CPU usage.
Prior to the development of OpenZFS on OS X, the two choices for using ZFS on OS X where Zevo or MacZFS, Zevo originally started out as a commercial product but switched to a freebie after Greenbytes picked it up. Zevo had much better integration with OS X e.g disk would be automatically mounted when connected to system just like any other disk with a supported file system and it supported a v28 of the filesystem whereas MacZFS supported a much older version.

When the OpenZFS on OS X development began just over a year ago, I ran the test builds that where made available, though these supported new features through feature flags it was very early days, attempting to scrub a zpool on a i7 MacBook Air with a USB 3 disk would spike the CPU for the duration and again the integration was still missing, you manually had to import & export pools. I continued to try newer builds on my MacBook Air but stuck with Zevo on my 2007 MacBook Pro.

The two things which where annoying about Zevo was that it was a dead end, development had stopped, the last version available wasn’t compatible with Mavericks available and its conservative memory setting meant that disk performance wasn’t that great, during playing audio files it would break to buffer audio in iTunes for example (luckily not in Serato as mid set would’ve been embarrassing).

As the MacBook Pro was running low on disk space I tried to move around 40GB of files in several chunks in parallel to my external USB3 disk & noticed the CPU pegged and fans started up with Zevo too. OpenZFS on OS X is fairly robust now (though still rough around the edges) so I decided to switch over.

The OpenZFS on OS X disk image comes with uninstall scripts for Zevo & though the main script was unable to detect the installed copy of Zevo, I was able to run the subsequent scripts individually to remove Zevo from my system and reboot (eject the disk containing the filesystem beforehand (export the zpool)).

The integration with OS X is still missing though it seems that on boot zpools are imported, I’ve not worked out if that’s because the system caches the state from previous boot or this is the preliminary support for auto mounting???

If you want to eject a disk, you still have to export the pool manually from terminal, pressing the eject button in finder will remove the disk icon but the filesystem is still mounted. That aside, OpenZFS on OS X performed well, scrubbing the zpool on the 2007 MacBook Pro did not cause the CPU to spike at all, there is now a shorter delay in iTunes when starting to play a track but haven’t noticed any drops in audio yet, so things are looking positive.

Scrubbing the zpool on a 2007 17″ MacBook Pro with 4GB RAM

pool: tank
state: ONLINE
scan: scrub in progress since Fri Jul 25 18:58:48 2014
28.2G scanned out of 579G at 30.1M/s, 5h11m to go
0 repaired, 4.87% done
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
disk1s2 ONLINE 0 0 0

errors: No known data errors

All properties on the zpool I was using:
NAME PROPERTY VALUE SOURCE
tank type filesystem -
tank creation Mon Jul 29 5:00 2013 -
tank used 579G -
tank available 1.22T -
tank referenced 579G -
tank compressratio 1.00x -
tank mounted yes -
tank quota none default
tank reservation none default
tank recordsize 128K default
tank mountpoint /tank default
tank sharenfs off default
tank checksum on default
tank compression off default
tank atime on default
tank devices on default
tank exec on default
tank setuid on default
tank readonly off default
tank zoned off default
tank snapdir hidden default
tank aclmode discard default
tank aclinherit restricted default
tank canmount on default
tank xattr on default
tank copies 1 default
tank version 5 -
tank utf8only on -
tank normalization formD -
tank casesensitivity sensitive -
tank vscan off default
tank nbmand off default
tank sharesmb off default
tank refquota none default
tank refreservation none default
tank primarycache all default
tank secondarycache all default
tank usedbysnapshots 0 -
tank usedbydataset 579G -
tank usedbychildren 4.48M -
tank usedbyrefreservation 0 -
tank logbias latency default
tank dedup off default
tank mlslabel none default
tank sync standard default
tank refcompressratio 1.00x -
tank written 579G -
tank logicalused 578G -
tank logicalreferenced 578G -
tank snapdev hidden default
tank com.apple.browse on default
tank com.apple.ignoreowner off default

Upgrading the zpool with OpenZFS on OS X
This system supports ZFS pool feature flags.

Successfully upgraded 'tank' from version 28 to feature flags.
pool_set_props
Enabled the following features on 'tank':
async_destroy
pool_set_props
empty_bpobj
pool_set_props
lz4_compress

Zvol backed bhyve guest

Things have moved forward in the world of bhyve since I last looked at it over a year ago, support for zvol backed guests where fixed long ago among other things such as the birth of vmrc by Michael Dexter.
To run a guest with a ZFS zvol as its disk is no different to running with a disk image, only thing is that my version of /usr/share/examples/bhyve/vmrun.sh (11.0-CURRENT r267869 at the time of writing) fails to start from the disk once the OS has been installed.

A typical deployment scenario would be

Create a zvol of some size, e.g. 10GB

zfs create -V 10g zroot/guest0

Start a guest which’ll boot from the FreeBSD install CD iso & install onto the zvol

# sh /usr/share/examples/bhyve/vmrun.sh -c 4 -m 1024M -t tap0 -d /dev/zvol/zroot/guest0 -i -I FreeBSD-10.0-RELEASE-amd64-disc1.iso guest0

Use the “ZFS – Automatic Root-on-ZFS” option from the Partitioning menu

As instructed in the bhyve section of the handbook, before rebooting, drop to the shell & edit /etc/ttys & replace the console line with

console "/usr/libexec/getty std.9600" xterm on secure

Shutdown the operating system
halt -p

Kill the guest
/usr/sbin/bhyvectl --destroy --vm=guest0

Create a new guest
bhyveload -m 4G -d /dev/zvol/zroot/guest0 guest0

Boot the new guest from the zvol
bhyve -c 1 -m 4G -A -H -P -s0:0,hostbridge -s 1:0,virtio-net,tap0 -s 2:0,ahci-hd,/dev/zvol/zroot/guest0 -s 31,lpc -l com1,stdio guest0

These instruction skip the creation of networking which is covered in the FreeBSD handbook as linked to above.

Copyright (c) 1992-2014 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 10.0-RELEASE #0 r260789: Thu Jan 16 22:34:59 UTC 2014
root@snap.freebsd.org:/usr/obj/usr/src/sys/GENERIC amd64
FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610
CPU: Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz (3399.54-MHz K8-class CPU)
Origin = "GenuineIntel" Id = 0x306a9 Family = 0x6 Model = 0x3a Stepping = 9
Features=0x8f83ab7f
Features2=0xfe9a6257
AMD Features=0x20100800
AMD Features2=0x1
Standard Extended Features=0x200
TSC: P-state invariant
real memory = 5368709120 (5120 MB)
avail memory = 4103143424 (3913 MB)
Event timer "LAPIC" quality 400
ACPI APIC Table:
ioapic0 irqs 0-23 on motherboard
random: initialized
module_register_init: MOD_LOAD (vesa, 0xffffffff80cfa5e0, 0) error 19
kbd1 at kbdmux0
acpi0: on motherboard
acpi0: Power Button (fixed)
atrtc0: port 0x70-0x71 irq 8 on acpi0
Event timer "HPET" frequency 10000000 Hz quality 550
Event timer "HPET1" frequency 10000000 Hz quality 450
Event timer "HPET2" frequency 10000000 Hz quality 450
Event timer "HPET3" frequency 10000000 Hz quality 450
Event timer "HPET4" frequency 10000000 Hz quality 450
Event timer "HPET5" frequency 10000000 Hz quality 450
Event timer "HPET6" frequency 10000000 Hz quality 450
Event timer "HPET7" frequency 10000000 Hz quality 450
Timecounter "ACPI-fast" frequency 3579545 Hz quality 900
acpi_timer0: port 0x408-0x40b on acpi0
pcib0: port 0xcf8-0xcff on acpi0
pci0: on pcib0
virtio_pci0: port 0x2000-0x201f mem 0xc0000000-0xc0001fff irq 16 at device 1.0 on pci0
vtnet0: on virtio_pci0
virtio_pci0: host features: 0x1018020
virtio_pci0: negotiated features: 0x18020
vtnet0: Ethernet address: 00:a0:98:7f:5a:41
virtio_pci1: port 0x2040-0x207f mem 0xc0002000-0xc0003fff irq 17 at device 2.0 on pci0
vtblk0: on virtio_pci1
virtio_pci1: host features: 0x10000044
virtio_pci1: negotiated features: 0x10000044
vtblk0: 40960MB (83886080 512 byte sectors)
isab0: at device 31.0 on pci0
isa0: on isab0
uart0: port 0x3f8-0x3ff irq 4 flags 0x10 on acpi0
uart0: console (9600,n,8,1)
uart1: port 0x2f8-0x2ff irq 3 on acpi0
sc0: at flags 0x100 on isa0
sc0: MDA
vga0: at port 0x3b0-0x3bb iomem 0xb0000-0xb7fff on isa0
atkbdc0: at port 0x60,0x64 on isa0
atkbd0: irq 1 on atkbdc0
kbd0 at atkbd0
atkbd0: [GIANT-LOCKED]
ppc0: cannot reserve I/O port range
ZFS NOTICE: Prefetch is disabled by default if less than 4GB of RAM is present;
to enable, add "vfs.zfs.prefetch_disable=0" to /boot/loader.conf.
ZFS filesystem version: 5
ZFS storage pool version: features support (5000)
Timecounters tick every 10.000 msec
random: unblocking device.
Netvsc initializing... Timecounter "TSC-low" frequency 1699769676 Hz quality 1000
Trying to mount root from zfs:zroot/ROOT/default []...

System fails to boot with root on ZFS

I’d installed FreeBSD on my ThinkPad X61s when the head branch of the source tree was at 9-CURRENT, multi-booting it with Windows 7 & OpenBSD.
At the time I was not aware that it was possible to boot FreeBSD from a root file system on a ZFS volume from a disk partitioned using a MBR scheme. Instead, I opted to store /boot on a UFS filesystem.
This install existed for a couple of years, the ThinkPad got a roasting every once in a while to build a new release to install for updates. At some point support for 4K sectors in ZFS was improved, zpool status began to report degraded performance as the disk had been using 512byte sectors where in fact it could support 4K sized sectors.

Eventually, I deleted the existing slices in the FreeBSD partition & attempted to reinstall but found this time the system would not boot.
Booting from the install CD & issuing zpool import reported the new pool & old pool from the previous install.
Destroying a pool before deleting slices stopped this problem from re-occurring but the system still wouldn’t boot from a ZFS volume on a MBR partition.
The next step was to see if things would work if the whole disk was dedicated to FreeBSD, with a GPT partition scheme, things worked but switching to MBR, again, it failed to boot, hanging at a flashing cursor.
Over the next four months, many installs were attempted. On a MBR partitioned disk
FreeBSD failed to boot but PCBSD could by using GRUB.

I stopped trying any further at this point & took a break from it, one thing that had been raised at BSDCan was the possibility it could be lingering metadata, I’d thought as zpool(8) wasn’t reporting any existing pools when asked to import that this wasn’t the case. To give the benefit of a doubt, I ran dd on the disk with no difference in result.
This approach to clearing old pools seemed a little rough so over the weekend I looked into what other options are available.

The zpool(8) man page documents the labelclear option as

zpool labelclear [-f] device

Removes ZFS label information from the specified device. The device
must not be part of an active pool configuration.

-v Treat exported or foreign devices as inactive.

I still had the FreeBSD snapshot from the last attempt which I booted the X61s with, headed to the shell, deleted the existing partitions & issued
zpool labelclear -f /dev/ada0

Everything worked as intended after that.

Thanks to Allan Jude & everyone who chipped in at BSDCan.
Through the trial of getting this working Allan added the option to use a BSD partition scheme to the FreeBSD installer as well as MBR & GPT, which was previously unavailable.