Changing a ZVOL block size while making it sparse and compressed

Ryan Babchishin - 2016-10-17

If you use ZFS with zvols, you may have discovered they can be slow. This can often be blamed on the volblocksize attribute, which is read-only after zvol creation. The default value on Linux is 8k and I've read that performance is best at 128k (specifically for Linux systems). On my pool, it is definitely faster to set this value to 128k. There are benchmarks out there showing the differences like this one: https://github.com/zfsonlinux/zfs/issues/824. Another positive factor in performance can be compression. I always enable lz4, which works quite well for me.

Changing the block size requires that you create a new zvol and copy the old one onto it. Tough there are different ways, I find this way preferable. As part of the process, you can zero out the free space on the original zvol and write it using dd as sparse to the new zvol with compression enabled. Think about it. You'll reclaim all the free space on the zvol, get a faster block size and compress the whole thing. Speed and free space.

The steps

Do a backup

If the zvol is important to you, back it up.

Mount the existing zvol's partitions that contain file systems and write free space with zeros

mount /dev/zvol/pool2/myvol_root-part1 /mnt

cd /mnt

dd if=/dev/zero of=allzeros.dat bs=1M

rm allzeros.dat

cd /

umount /mnt

Rename the zvol

zfs rename pool2/myvol_root pool2/myvol_root_20161014

Create a new zvol of the same size as the old one with new parameters, especially volblocksize=128k and I suggest compression=lz4

zfs create -V 64G -o compression=lz4 -o volblocksize=128k pool2/myvol_root

Write the old zvol to the new one with dd's conv=sparse option

dd conv=sparse if=/dev/zvol/pool2/myvol_root_20161014 of=/dev/zvol/pool2/myvol_root bs=1M status=progress

Check out your free space

zfs list pool2/myvol_root

NAME USED AVAIL REFER MOUNTPOINT

pool2/myvol_root 66.0G 1.74T 4.36G -

Go do some benchmarks on the new zvol!