Relax (ref)reservation constraints on ZVOLs

This change allow (ref)reservation to be set larger than the current
ZVOL size: this is safe as we normally set refreservation > volsize
at ZVOL creation time when we account for metadata.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #2468 
Closes #6610
This commit is contained in:
LOLi 2017-09-12 20:33:22 +02:00 committed by Brian Behlendorf
parent d9549cba96
commit ded8f06a3c
4 changed files with 24 additions and 51 deletions

View File

@ -1451,25 +1451,11 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
* checks to enforce. * checks to enforce.
*/ */
if (type == ZFS_TYPE_VOLUME && zhp != NULL) { if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
uint64_t volsize = zfs_prop_get_int(zhp,
ZFS_PROP_VOLSIZE);
uint64_t blocksize = zfs_prop_get_int(zhp, uint64_t blocksize = zfs_prop_get_int(zhp,
ZFS_PROP_VOLBLOCKSIZE); ZFS_PROP_VOLBLOCKSIZE);
char buf[64]; char buf[64];
switch (prop) { switch (prop) {
case ZFS_PROP_RESERVATION:
case ZFS_PROP_REFRESERVATION:
if (intval > volsize) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s' is greater than current "
"volume size"), propname);
(void) zfs_error(hdl, EZFS_BADPROP,
errbuf);
goto error;
}
break;
case ZFS_PROP_VOLSIZE: case ZFS_PROP_VOLSIZE:
if (intval % blocksize != 0) { if (intval % blocksize != 0) {
zfs_nicebytes(blocksize, buf, zfs_nicebytes(blocksize, buf,

View File

@ -33,13 +33,12 @@
# #
# DESCRIPTION: # DESCRIPTION:
# Volume refreservation is limited by volsize # Volume (ref)reservation is not limited by volsize
# #
# STRATEGY: # STRATEGY:
# 1. Create volume on filesystem # 1. Create volume on filesystem
# 2. Setting quota for parent filesystem # 2. Setting quota for parent filesystem
# 3. Verify volume refreservation is only limited by volsize # 3. Verify volume (ref)reservation is not limited by volsize
# 4. Verify volume refreservation can be changed when volsize changed
# #
verify_runnable "global" verify_runnable "global"
@ -51,21 +50,24 @@ function cleanup
log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
} }
log_assert "Volume refreservation is limited by volsize" log_assert "Volume (ref)reservation is not limited by volsize"
log_onexit cleanup log_onexit cleanup
fs=$TESTPOOL/$TESTFS; vol=$fs/vol fs=$TESTPOOL/$TESTFS
vol=$fs/vol
log_must zfs create -V 10M $vol log_must zfs create -V 10M $vol
refreserv=`get_prop refreservation $vol`
fudge=1
# Verify the parent filesystem does not affect volume # Verify the parent filesystem does not affect volume
log_must zfs set quota=25M $fs log_must zfs set quota=25M $fs
log_must zfs set reservation=10M $vol
log_must zfs set refreservation=10M $vol log_must zfs set refreservation=10M $vol
avail=$(get_prop mountpoint $vol)
log_mustnot zfs set refreservation=$avail $vol
# Verify it is affected by volsize # Verify it is not affected by volsize
log_must zfs set volsize=15M $vol log_must zfs set reservation=$(($refreserv + $fudge)) $vol
log_must zfs set refreservation=15M $vol log_must zfs set reservation=$(($refreserv - $fudge)) $vol
log_mustnot zfs set refreservation=16M $vol log_must zfs set refreservation=$(($refreserv + $fudge)) $vol
log_must zfs set refreservation=$(($refreserv - $fudge)) $vol
log_pass "Volume refreservation is limited by volsize" log_pass "Volume (ref)reservation is not limited by volsize"

View File

@ -84,17 +84,9 @@ fi
for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do
space_avail=`get_prop available $TESTPOOL` space_avail=`get_prop available $obj`
resv_size_set=`expr $space_avail + $RESV_DELTA` resv_size_set=`expr $space_avail + $RESV_DELTA`
#
# For regular (non-sparse) volumes the upper limit is determined
# not by the space available in the pool but rather by the size
# of the volume itself.
#
[[ $obj == $TESTPOOL/$TESTVOL ]] && \
((resv_size_set = vol_set_size + RESV_DELTA))
log_must zero_reservation $obj log_must zero_reservation $obj
log_mustnot zfs set reservation=$resv_size_set $obj log_mustnot zfs set reservation=$resv_size_set $obj

View File

@ -79,30 +79,23 @@ fi
for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do
space_avail=`get_prop available $TESTPOOL` space_avail=`get_prop available $obj`
((quota_set_size = space_avail / 3)) ((quota_set_size = space_avail / 3))
# #
# A regular (non-sparse) volume's size is effectively # Volumes do not support quota so only need to explicitly
# its quota so only need to explicitly set quotas for # set quotas for filesystems.
# filesystems and datasets.
# #
# A volumes size is effectively its quota. The maximum # The maximum reservation value that can be set on a volume
# reservation value that can be set on a volume is # is determined by the quota set on its parent filesystems or
# determined by the size of the volume or the amount of # the amount of space in the pool, whichever is smaller.
# space in the pool, whichever is smaller.
# #
if [[ $obj == $TESTPOOL/$TESTFS ]]; then if [[ $obj == $TESTPOOL/$TESTFS ]]; then
log_must zfs set quota=$quota_set_size $obj log_must zfs set quota=$quota_set_size $obj
((resv_set_size = quota_set_size + RESV_SIZE)) ((resv_set_size = quota_set_size + RESV_SIZE))
elif [[ $obj == $TESTPOOL/$TESTVOL || $obj == $TESTPOOL/$TESTVOL2 ]]
elif [[ $obj == $TESTPOOL/$TESTVOL2 ]] ; then then
resv_set_size=`expr $space_avail + $RESV_DELTA`
((resv_set_size = sparse_vol_set_size + RESV_SIZE))
elif [[ $obj == $TESTPOOL/$TESTVOL ]] ; then
((resv_set_size = vol_set_size + RESV_SIZE))
fi fi
orig_quota=`get_prop quota $obj` orig_quota=`get_prop quota $obj`