Upper limit of zfs set bounds check for refreservation on volumes is too low
When doing a zfs set refreservation on a volume, the upper bound of the value check is set too low. ATM the bounds check validates that the new refreservation value is <= volume size, but this may not be enough to reserve all space needed for the volume, as there is some metadata overhead. When non-sparse volumes are created, this is even explicitly handled by libzfs in zvol_volsize_to_reservation - the reservation is slightly overprovisioned (which is correct). However, once a volume is set to sparse (refreservation=0), it is not possible to go back to the original value, as we will bump up against the broken check in libzfs:
# zfs create -V 128M rpool/test # zfs get -p refreservation rpool/test NAME PROPERTY VALUE SOURCE rpool/test refreservation 138674176 local # zfs set refreservation=138674176 rpool/test cannot set property for 'rpool/test': 'refreservation' is greater than current volume size
The fix is simple: make the bounds check in libzfs check against the overprovisioned value as used at volume creation time.