Print this page
4012 Upper limit of zfs set bounds check for refreservation on volumes is too low

*** 20,30 **** */ /* * 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 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 Martin Matuska. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. */ --- 20,30 ---- */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. 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,1222 **** 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); char buf[64]; 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); --- 1207,1225 ---- 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 > ! 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,1320 **** uint64_t old_volsize; uint64_t new_volsize; uint64_t old_reservation; uint64_t new_reservation; zfs_prop_t resv_prop; ! nvlist_t *props; /* * 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); ! 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); return (0); - } if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), ! &new_volsize) != 0) { ! fnvlist_free(props); return (-1); ! } ! new_reservation = zvol_volsize_to_reservation(new_volsize, props); ! fnvlist_free(props); if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), new_reservation) != 0) { (void) no_memory(zhp->zfs_hdl); return (-1); --- 1286,1318 ---- uint64_t old_volsize; uint64_t new_volsize; uint64_t old_reservation; uint64_t new_reservation; zfs_prop_t resv_prop; ! 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); ! 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) return (-1); ! 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,4476 **** return (err); } /* ! * Convert the zvol's volume size to an appropriate reservation. * 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; int ncopies; char *strval; if (nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) --- 4456,4474 ---- return (err); } /* ! * 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 volblocksize; int ncopies; char *strval; if (nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
*** 4479,4488 **** --- 4477,4502 ---- 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) {