]> granicus.if.org Git - zfs/commitdiff
OpenZFS 9286 - want refreservation=auto
authorMike Gerdts <mike.gerdts@joyent.com>
Wed, 11 Apr 2018 16:14:45 +0000 (10:14 -0600)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 11 Apr 2018 21:52:13 +0000 (14:52 -0700)
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

lib/libzfs/libzfs_dataset.c
lib/libzfs/libzfs_util.c
man/man8/zfs.8
tests/runfiles/linux.run
tests/zfs-tests/tests/functional/reservation/Makefile.am
tests/zfs-tests/tests/functional/reservation/reservation_019_pos.sh [new file with mode: 0755]
tests/zfs-tests/tests/functional/reservation/reservation_020_pos.sh [new file with mode: 0755]
tests/zfs-tests/tests/functional/reservation/reservation_021_neg.sh [new file with mode: 0755]
tests/zfs-tests/tests/functional/reservation/reservation_022_pos.sh [new file with mode: 0755]

index 1a8c294d2857f780cde39bf89bbf8e35c6c9c3ad..acfcb7491deae7dc23fcdec66d021206e5cfe0d8 100644 (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) {
index 6b9cfc27201b571f39bb585748e9e6452b371877..12f65a90c1bb3fd7b141171fb6b2533bc1078587 100644 (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:
index acebf64a357313eae4c3a73c101d4b15928ea0bc..a7edc8bccbf96569ebfbee947ae488e3808bc971 100644 (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
index b5d563d4f0c5db9e314f830c0a1d8e75b7c635d8..b53817b8ba17ea26f4fe4884caba383a2908c1df 100644 (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]
index 49c9f75343cd279bfba3f370377c458ea0661483..9b02867b9728c6b42903ff377240f8eaff3a7703 100644 (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 \
diff --git a/tests/zfs-tests/tests/functional/reservation/reservation_019_pos.sh b/tests/zfs-tests/tests/functional/reservation/reservation_019_pos.sh
new file mode 100755 (executable)
index 0000000..45da06a
--- /dev/null
@@ -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"
diff --git a/tests/zfs-tests/tests/functional/reservation/reservation_020_pos.sh b/tests/zfs-tests/tests/functional/reservation/reservation_020_pos.sh
new file mode 100755 (executable)
index 0000000..68d46d0
--- /dev/null
@@ -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"
diff --git a/tests/zfs-tests/tests/functional/reservation/reservation_021_neg.sh b/tests/zfs-tests/tests/functional/reservation/reservation_021_neg.sh
new file mode 100755 (executable)
index 0000000..c99a82c
--- /dev/null
@@ -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"
diff --git a/tests/zfs-tests/tests/functional/reservation/reservation_022_pos.sh b/tests/zfs-tests/tests/functional/reservation/reservation_022_pos.sh
new file mode 100755 (executable)
index 0000000..879dc5d
--- /dev/null
@@ -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"