Print this page
4012 Upper limit of zfs set bounds check for refreservation on volumes is too low
@@ -20,11 +20,11 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
- * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
+ * Copyright 2013 DEY Storage Systems, Inc.
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 Martin Matuska. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
*/
@@ -1207,16 +1207,19 @@
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,
ZFS_PROP_VOLBLOCKSIZE);
+ int ncopies = zfs_prop_get_int(zhp, ZFS_PROP_COPIES);
char buf[64];
switch (prop) {
case ZFS_PROP_RESERVATION:
case ZFS_PROP_REFRESERVATION:
- if (intval > volsize) {
+ if (intval >
+ zvol_volsize_to_reservation_impl(volsize,
+ blocksize, ncopies)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s' is greater than current "
"volume size"), propname);
(void) zfs_error(hdl, EZFS_BADPROP,
errbuf);
@@ -1283,38 +1286,33 @@
uint64_t old_volsize;
uint64_t new_volsize;
uint64_t old_reservation;
uint64_t new_reservation;
zfs_prop_t resv_prop;
- nvlist_t *props;
+ uint64_t volblocksize;
+ int ncopies;
/*
* If this is an existing volume, and someone is setting the volsize,
* make sure that it matches the reservation, or add it if necessary.
*/
old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
return (-1);
old_reservation = zfs_prop_get_int(zhp, resv_prop);
+ volblocksize = zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE);
+ ncopies = zfs_prop_get_int(zhp, ZFS_PROP_COPIES);
- props = fnvlist_alloc();
- fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
-
- if ((zvol_volsize_to_reservation(old_volsize, props) !=
- old_reservation) || nvlist_exists(nvl,
- zfs_prop_to_name(resv_prop))) {
- fnvlist_free(props);
+ if ((zvol_volsize_to_reservation_impl(old_volsize, volblocksize,
+ ncopies) != old_reservation) || nvlist_exists(nvl,
+ zfs_prop_to_name(resv_prop)))
return (0);
- }
if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
- &new_volsize) != 0) {
- fnvlist_free(props);
+ &new_volsize) != 0)
return (-1);
- }
- new_reservation = zvol_volsize_to_reservation(new_volsize, props);
- fnvlist_free(props);
+ new_reservation = zvol_volsize_to_reservation_impl(new_volsize,
+ volblocksize, ncopies);
if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
new_reservation) != 0) {
(void) no_memory(zhp->zfs_hdl);
return (-1);
@@ -4458,19 +4456,19 @@
return (err);
}
/*
- * Convert the zvol's volume size to an appropriate reservation.
+ * Convert the zvol's volume size to an appropriate reservation. This is a
+ * convenience front-end to zvol_volsize_to_reservation_impl.
* Note: If this routine is updated, it is necessary to update the ZFS test
* suite's shell version in reservation.kshlib.
*/
uint64_t
zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
{
- uint64_t numdb;
- uint64_t nblocks, volblocksize;
+ uint64_t volblocksize;
int ncopies;
char *strval;
if (nvlist_lookup_string(props,
zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
@@ -4479,10 +4477,26 @@
ncopies = 1;
if (nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
&volblocksize) != 0)
volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
+
+ return (zvol_volsize_to_reservation_impl(volsize, volblocksize,
+ ncopies));
+}
+
+/*
+ * Computes the required reservation to completely contain all blocks of a
+ * zvol at a given volsize.
+ */
+uint64_t
+zvol_volsize_to_reservation_impl(uint64_t volsize, uint64_t volblocksize,
+ int ncopies)
+{
+ uint64_t numdb;
+ uint64_t nblocks;
+
nblocks = volsize/volblocksize;
/* start with metadnode L0-L6 */
numdb = 7;
/* calculate number of indirects */
while (nblocks > 1) {