svn commit: r336945 - in head/cddl/contrib/opensolaris: cmd/zfs lib/libzfs/common

Alexander Motin mav at FreeBSD.org
Mon Jul 30 22:39:32 UTC 2018


Author: mav
Date: Mon Jul 30 22:39:30 2018
New Revision: 336945
URL: https://svnweb.freebsd.org/changeset/base/336945

Log:
  MFV r336944: 9286 want refreservation=auto
  
  When a ZFS volume is created with zfs create -V (but without -s), the
  refreservation property is set to a value that is volsize plus the maximum
  size of metadata. If refreservation is ever set to another value, it is
  impossible to set it back to the automatically determined value. There are
  other cases where refreservation may be wrong. These include receiving a
  volume that was sent without properties and zfs clone.
  
  We need:
  
  zfs set refreservation=auto <volume>
  zfs clone -o refreservation=auto <volume>
  
  Each one would use the same function used by zfs create -V to determine the
  proper value for refreservation.
  
  illumos/illumos-gate at 1c10ae76c0cb31326c320e7cef1d3f24a1f47125
  
  Reviewed by: Allan Jude <allanjude at freebsd.org>
  Reviewed by: Matthew Ahrens <mahrens at delphix.com>
  Reviewed by: John Kennedy <john.kennedy at delphix.com>
  Reviewed by: Andy Stormont <astormont at racktopsystems.com>
  Approved by: Richard Lowe <richlowe at richlowe.net>
  Author: Mike Gerdts <mike.gerdts at joyent.com>

Modified:
  head/cddl/contrib/opensolaris/cmd/zfs/zfs.8
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
Directory Properties:
  head/cddl/contrib/opensolaris/   (props changed)

Modified: head/cddl/contrib/opensolaris/cmd/zfs/zfs.8
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zfs/zfs.8	Mon Jul 30 22:10:15 2018	(r336944)
+++ head/cddl/contrib/opensolaris/cmd/zfs/zfs.8	Mon Jul 30 22:39:30 2018	(r336945)
@@ -28,6 +28,7 @@
 .\" Copyright (c) 2016 Nexenta Systems, Inc. All Rights Reserved.
 .\" Copyright (c) 2014, Xin LI <delphij at FreeBSD.org>
 .\" Copyright (c) 2014-2015, The FreeBSD Foundation, All Rights Reserved.
+.\" Copyright 2018 Joyent, Inc.
 .\"
 .\" $FreeBSD$
 .\"
@@ -1311,7 +1312,7 @@ The default value is
 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 Ar size | Cm none
+.It Sy refreservation Ns = Ns Ar size | Cm none | Cm 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 it were taking up the amount of space specified by
@@ -1327,6 +1328,18 @@ is set, a snapshot is only allowed if there is enough 
 of this reservation to accommodate the current number of "referenced" bytes in
 the dataset.
 .Pp
+If
+.Sy refreservation
+is set to
+.Sy auto ,
+a volume is thick provisioned or not sparse.
+.Sy refreservation Ns = Cm auto
+is only supported on volumes.
+See
+.Sy volsize
+in the 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 reservation Ns = Ns Ar size | Cm none
@@ -1459,18 +1472,33 @@ on how the volume is used. These effects can also occu
 changed while it is in use (particularly when shrinking the size). Extreme care
 should be used when adjusting the volume size.
 .Pp
-Though not recommended, a "sparse volume" (also known as "thin provisioning")
+Though not recommended, a "sparse volume" (also known as "thin provisioned")
 can be created by specifying the
 .Fl s
 option to the
 .Qq Nm Cm create Fl V
-command, or by changing the reservation after the volume has been created. A
-"sparse volume" is a volume where the reservation is less then the volume size.
+command, or by changing the value of the
+.Sy refreservation
+property, or
+.Sy reservation
+property on pool version 8 or earlier
+.Pc
+after the volume has been created.
+A "sparse volume" is a volume where the value of
+.Sy refreservation
+is less then the size of the volume plus the space required to store its
+metadata.
 Consequently, writes to a sparse volume can fail with
 .Sy 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 "thick provisioned".
+A sparse volume can become thick provisioned by setting
+.Sy refreservation
+to
+.Sy auto .
 .It Sy volmode Ns = Ns Cm default | geom | dev | none
 This property specifies how volumes should be exposed to the OS.
 Setting it to

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	Mon Jul 30 22:10:15 2018	(r336944)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	Mon Jul 30 22:39:30 2018	(r336945)
@@ -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, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
  * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
@@ -1407,7 +1407,6 @@ badlabel:
 
 			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 "
@@ -1418,6 +1417,17 @@ badlabel:
 				}
 				break;
 
+			case ZFS_PROP_REFRESERVATION:
+				if (intval > volsize && intval != UINT64_MAX) {
+					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:
 				if (intval % blocksize != 0) {
 					zfs_nicenum(blocksize, buf,
@@ -1519,6 +1529,61 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nv
 	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)
@@ -1685,6 +1750,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().
@@ -3715,6 +3786,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlis
 
 	if (props) {
 		zfs_type_t type;
+
 		if (ZFS_IS_VOLUME(zhp)) {
 			type = ZFS_TYPE_VOLUME;
 		} else {
@@ -3723,6 +3795,10 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlis
 		if ((props = zfs_valid_proplist(hdl, type, props, zoned,
 		    zhp, zhp->zpool_hdl, errbuf)) == NULL)
 			return (-1);
+		if (zfs_fix_auto_resv(zhp, props) == -1) {
+			nvlist_free(props);
+			return (-1);
+		}
 	}
 
 	ret = lzc_clone(target, zhp->zfs_name, props);

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c	Mon Jul 30 22:10:15 2018	(r336944)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c	Mon Jul 30 22:39:30 2018	(r336945)
@@ -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.
  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
  * Copyright (c) 2017 Datto Inc.
@@ -1227,6 +1227,7 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem
 	const char *propname;
 	char *value;
 	boolean_t isnone = B_FALSE;
+	boolean_t isauto = B_FALSE;
 
 	if (type == ZFS_TYPE_POOL) {
 		proptype = zpool_prop_get_type(prop);
@@ -1262,8 +1263,9 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem
 			(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) {
@@ -1293,6 +1295,31 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem
 		    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:


More information about the svn-src-head mailing list