OpenZFS 9286 - want refreservation=auto

Authored by: Mike Gerdts <mike.gerdts@joyent.com>
Reviewed by: Allan Jude <allanjude@freebsd.org>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Reviewed by: Andy Stormont <astormont@racktopsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Approved by: Richard Lowe <richlowe@richlowe.net>
Ported-by: Don Brady <don.brady@delphix.com>

Porting Notes:
* Adopted destroy_dataset in ZTS test cleanup
* Use ksh shebang instead of bash for new tests

OpenZFS-issue: https://www.illumos.org/issues/9286
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/723d0c85
Closes #7387
This commit is contained in:
Mike Gerdts 2018-04-11 10:14:45 -06:00 committed by Brian Behlendorf
parent 9966754ac5
commit d22f3a8244
9 changed files with 424 additions and 11 deletions

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc. All rights reserved.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
@ -1589,6 +1589,61 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
return (1);
}
/*
* Helper for 'zfs {set|clone} refreservation=auto'. Must be called after
* zfs_valid_proplist(), as it is what sets the UINT64_MAX sentinal value.
* Return codes must match zfs_add_synthetic_resv().
*/
static int
zfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl)
{
uint64_t volsize;
uint64_t resvsize;
zfs_prop_t prop;
nvlist_t *props;
if (!ZFS_IS_VOLUME(zhp)) {
return (0);
}
if (zfs_which_resv_prop(zhp, &prop) != 0) {
return (-1);
}
if (prop != ZFS_PROP_REFRESERVATION) {
return (0);
}
if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(prop), &resvsize) != 0) {
/* No value being set, so it can't be "auto" */
return (0);
}
if (resvsize != UINT64_MAX) {
/* Being set to a value other than "auto" */
return (0);
}
props = fnvlist_alloc();
fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
&volsize) != 0) {
volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
}
resvsize = zvol_volsize_to_reservation(volsize, props);
fnvlist_free(props);
(void) nvlist_remove_all(nvl, zfs_prop_to_name(prop));
if (nvlist_add_uint64(nvl, zfs_prop_to_name(prop), resvsize) != 0) {
(void) no_memory(zhp->zfs_hdl);
return (-1);
}
return (1);
}
void
zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
char *errbuf)
@ -1787,6 +1842,12 @@ zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
goto error;
}
}
if (added_resv != 1 &&
(added_resv = zfs_fix_auto_resv(zhp, nvl)) == -1) {
goto error;
}
/*
* Check how many properties we're setting and allocate an array to
* store changelist pointers for postfix().
@ -3879,6 +3940,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
if (props) {
zfs_type_t type;
if (ZFS_IS_VOLUME(zhp)) {
type = ZFS_TYPE_VOLUME;
} else {
@ -3887,6 +3949,10 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
zhp, zhp->zpool_hdl, B_TRUE, errbuf)) == NULL)
return (-1);
if (zfs_fix_auto_resv(zhp, props) == -1) {
nvlist_free(props);
return (-1);
}
}
if (zfs_crypto_clone_check(hdl, zhp, parent, props) != 0) {

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc. All rights reserved.
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright (c) 2017 Datto Inc.
@ -1806,6 +1806,7 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
const char *propname;
char *value;
boolean_t isnone = B_FALSE;
boolean_t isauto = B_FALSE;
int err = 0;
if (type == ZFS_TYPE_POOL) {
@ -1847,8 +1848,9 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
(void) nvpair_value_string(elem, &value);
if (strcmp(value, "none") == 0) {
isnone = B_TRUE;
} else if (zfs_nicestrtonum(hdl, value, ivalp)
!= 0) {
} else if (strcmp(value, "auto") == 0) {
isauto = B_TRUE;
} else if (zfs_nicestrtonum(hdl, value, ivalp) != 0) {
goto error;
}
} else if (datatype == DATA_TYPE_UINT64) {
@ -1878,6 +1880,31 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
prop == ZFS_PROP_SNAPSHOT_LIMIT)) {
*ivalp = UINT64_MAX;
}
/*
* Special handling for setting 'refreservation' to 'auto'. Use
* UINT64_MAX to tell the caller to use zfs_fix_auto_resv().
* 'auto' is only allowed on volumes.
*/
if (isauto) {
switch (prop) {
case ZFS_PROP_REFRESERVATION:
if ((type & ZFS_TYPE_VOLUME) == 0) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s=auto' only allowed on "
"volumes"), nvpair_name(elem));
goto error;
}
*ivalp = UINT64_MAX;
break;
default:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'auto' is invalid value for '%s'"),
nvpair_name(elem));
goto error;
}
}
break;
case PROP_TYPE_INDEX:

View File

@ -28,6 +28,7 @@
.\" Copyright (c) 2014 Integros [integros.com]
.\" Copyright 2016 Richard Laager. All rights reserved.
.\" Copyright 2017 Nexenta Systems, Inc.
.\" Copyright 2018 Joyent, Inc.
.\"
.Dd January 10, 2018
.Dt ZFS 8 SMM
@ -1790,7 +1791,7 @@ Limits the amount of space a dataset can consume.
This property enforces a hard limit on the amount of space used.
This hard limit does not include space used by descendents, including file
systems and snapshots.
.It Sy refreservation Ns = Ns Em size Ns | Ns Sy none
.It Sy refreservation Ns = Ns Em size Ns | Ns Sy none Ns | Ns Sy auto
The minimum amount of space guaranteed to a dataset, not including its
descendents.
When the amount of space used is below this value, the dataset is treated as if
@ -1808,6 +1809,22 @@ this reservation to accommodate the current number of
.Qq referenced
bytes in the dataset.
.Pp
If
.Sy refreservation
is set to
.Sy auto ,
a volume is thick provisioned
.Po or
.Qq not sparse
.Pc .
.Sy refreservation Ns = Ns Sy auto
is only supported on volumes.
See
.Sy volsize
in the
.Sx Native Properties
section for more information about sparse volumes.
.Pp
This property can also be referred to by its shortened column name,
.Sy refreserv .
.It Sy relatime Ns = Ns Sy on Ns | Ns Sy off
@ -2022,22 +2039,39 @@ Extreme care should be used when adjusting the volume size.
Though not recommended, a
.Qq sparse volume
.Po also known as
.Qq thin provisioning
.Qq thin provisioned
.Pc
can be created by specifying the
.Fl s
option to the
.Nm zfs Cm create Fl V
command, or by changing the reservation after the volume has been created.
command, or by changing the value of the
.Sy refreservation
property
.Po or
.Sy reservation
property on pool version 8 or earlier
.Pc
after the volume has been created.
A
.Qq sparse volume
is a volume where the reservation is less then the volume size.
is a volume where the value of
.Sy refreservation
is less than the size of the volume plus the space required to store its
metadata.
Consequently, writes to a sparse volume can fail with
.Er ENOSPC
when the pool is low on space.
For a sparse volume, changes to
.Sy volsize
are not reflected in the reservation.
are not reflected in the
.Sy refreservation.
A volume that is not sparse is said to be
.Qq thick provisioned .
A sparse volume can become thick provisioned by setting
.Sy refreservation
to
.Sy auto .
.It Sy volmode Ns = Ns Cm default | full | geom | dev | none
This property specifies how volumes should be exposed to the OS.
Setting it to

View File

@ -675,7 +675,8 @@ tests = ['reservation_001_pos', 'reservation_002_pos', 'reservation_003_pos',
'reservation_007_pos', 'reservation_008_pos', 'reservation_009_pos',
'reservation_010_pos', 'reservation_011_pos', 'reservation_012_pos',
'reservation_013_pos', 'reservation_014_pos', 'reservation_015_pos',
'reservation_016_pos', 'reservation_017_pos']
'reservation_016_pos', 'reservation_017_pos', 'reservation_019_pos',
'reservation_020_pos', 'reservation_021_neg', 'reservation_022_pos']
tags = ['functional', 'reservation']
[tests/functional/rootpool]

View File

@ -19,7 +19,11 @@ dist_pkgdata_SCRIPTS = \
reservation_015_pos.sh \
reservation_016_pos.sh \
reservation_017_pos.sh \
reservation_018_pos.sh
reservation_018_pos.sh \
reservation_019_pos.sh \
reservation_020_pos.sh \
reservation_021_neg.sh \
reservation_022_pos.sh
dist_pkgdata_DATA = \
reservation.cfg \

View File

@ -0,0 +1,63 @@
#!/bin/ksh -p
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright 2018 Joyent, Inc.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/reservation/reservation.shlib
#
# DESCRIPTION:
#
# A thin provisioned volume can become thick provisioned with 'zfs set
# refreservation=auto'.
#
# STRATEGY:
# 1) Create a sparse value.
# 2) Use zfs set refreservation=auto to make it thick provisioned.
# 3) Verify that refreservation is now the size predicted by
# volsize_to_reservation().
#
verify_runnable "global"
function cleanup
{
destroy_dataset "$TESTPOOL/$TESTVOL" "-f"
}
log_onexit cleanup
log_assert "A thin provisioned volume can become thick provisioned with" \
"'zfs set refreservation=auto'."
space_avail=$(get_prop available $TESTPOOL)
(( vol_size = (space_avail / 2) & ~(1024 * 1024 - 1) ))
vol=$TESTPOOL/$TESTVOL
# Create sparse vol and verify
log_must zfs create -V $vol_size -s $vol
resv=$(get_prop refreservation $vol)
log_must test $resv -eq 0
# Set refreservation
log_must zfs set refreservation=auto $vol
# Verify
resv=$(get_prop refreservation $vol)
expected=$(volsize_to_reservation $vol $vol_size)
log_must test $resv -eq $expected
log_pass "Setting refreservation=auto set refreservation to expected value"

View File

@ -0,0 +1,64 @@
#!/bin/ksh -p
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright 2018 Joyent, Inc.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/reservation/reservation.shlib
#
# DESCRIPTION:
#
# Cloning a thick provisioned volume results in a sparse volume
#
# STRATEGY:
# 1) Create a thick provisioned volume.
# 2) Snapshot and clone it.
# 3) Verify that the clone is sparse.
#
verify_runnable "global"
function cleanup
{
# Destroy first vol and descendants in one go.
destroy_dataset "$TESTPOOL/$TESTVOL" "-Rf"
}
log_onexit cleanup
log_assert "Cloning a thick provisioned volume results in a sparse volume"
space_avail=$(get_prop available $TESTPOOL)
(( vol_size = (space_avail / 4) & ~(1024 * 1024 - 1) ))
vol=$TESTPOOL/$TESTVOL
snap=$vol@clone
vol2=$TESTPOOL/$TESTVOL2
# Create sparse vol and verify
log_must zfs create -V $vol_size $vol
resv=$(get_prop refreservation $vol)
expected=$(volsize_to_reservation $vol $vol_size)
log_must test $resv -eq $expected
# Clone it
log_must zfs snapshot $snap
log_must zfs clone $snap $vol2
# Verify
resv=$(get_prop refreservation $vol2)
log_must test $resv -eq 0
log_pass "Cloning a thick provisioned volume results in a sparse volume"

View File

@ -0,0 +1,72 @@
#!/bin/ksh -p
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright 2018 Joyent, Inc.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/reservation/reservation.shlib
#
# DESCRIPTION:
#
# The use of refreservation=auto on a filesystem does not change the
# refreservation and results in an error.
#
# STRATEGY:
# 1) Create a filesystem
# 2) Verify that zfs set refreservation=auto fails without changing
# refreservation from none.
# 3) Set refreservation to a valid value.
# 4) Verify that zfs set refreservation=auto fails without changing
# refreservation from the previous value.
#
verify_runnable "both"
fs=$TESTPOOL/$TESTFS/$(basename $0).$$
function cleanup
{
destroy_dataset "$fs" "-f"
}
log_onexit cleanup
log_assert "refreservation=auto on a filesystem generates an error without" \
"changing refreservation"
space_avail=$(get_prop available $TESTPOOL)
(( fs_size = space_avail / 4 ))
# Create a filesystem with no refreservation
log_must zfs create $fs
resv=$(get_prop refreservation $fs)
log_must test $resv -eq 0
# Verify that refreservation=auto fails without altering refreservation
log_mustnot zfs set refreservation=auto $fs
resv=$(get_prop refreservation $fs)
log_must test $resv -eq 0
# Set refreservation and verify
log_must zfs set refreservation=$fs_size $fs
resv=$(get_prop refreservation $fs)
log_must test $resv -eq $fs_size
# Verify that refreservation=auto fails without altering refreservation
log_mustnot zfs set refreservation=auto $fs
resv=$(get_prop refreservation $fs)
log_must test $resv -eq $fs_size
log_pass "refreservation=auto does not work on filesystems, as expected"

View File

@ -0,0 +1,82 @@
#!/bin/ksh -p
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright 2018 Joyent, Inc.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/reservation/reservation.shlib
#
# DESCRIPTION:
#
# Cloning a volume with -o refreservation=auto creates a thick provisioned
# volume
#
# STRATEGY:
# 1) Create a sparse volume.
# 2) Snapshot and clone it, using clone -o refreservation=auto.
# 3) Verify that the clone has refreservation that matches the size predicted by
# volsize_to_reservation().
# 4) Snapshot this second volume and clone it, using clone -o
# refreservation=auto.
# 5) Verify that the second clone has refreservation that matches the size
# predicted by volsize_to_reservation().
#
verify_runnable "global"
function cleanup
{
# Destroy first vol and descendants in one go.
destroy_dataset "$TESTPOOL/$TESTVOL" "-Rf"
}
log_onexit cleanup
log_assert "Cloning a volume with -o refreservation=auto creates a thick" \
"provisioned volume"
space_avail=$(get_prop available $TESTPOOL)
(( vol_size = (space_avail / 4) & ~(1024 * 1024 - 1) ))
vol=$TESTPOOL/$TESTVOL
vol2=$TESTPOOL/$TESTVOL2
vol3=$TESTPOOL/$TESTVOL2-again
# Create sparse vol and verify
log_must zfs create -s -V $vol_size $vol
resv=$(get_prop refreservation $vol)
log_must test $resv -eq 0
# Clone it
snap=$vol@clone
log_must zfs snapshot $snap
log_must zfs clone -o refreservation=auto $snap $vol2
# Verify it is thick provisioned
resv=$(get_prop refreservation $vol2)
expected=$(volsize_to_reservation $vol2 $vol_size)
log_must test $resv -eq $expected
# Clone the thick provisioned volume
snap=$vol2@clone
log_must zfs snapshot $snap
log_must zfs clone -o refreservation=auto $snap $vol3
# Verify new newest clone is also thick provisioned
resv=$(get_prop refreservation $vol3)
expected=$(volsize_to_reservation $vol3 $vol_size)
log_must test $resv -eq $expected
log_pass "Cloning a thick provisioned volume results in a sparse volume"