5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013 by Delphix. All rights reserved.
25 * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 * Copyright (c) 2013 Martin Matuska. All rights reserved.
28 * Copyright (c) 2013 Steven Hartland. All rights reserved.
29 */
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <libintl.h>
34 #include <math.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <unistd.h>
39 #include <stddef.h>
40 #include <zone.h>
41 #include <fcntl.h>
42 #include <sys/mntent.h>
43 #include <sys/mount.h>
44 #include <priv.h>
45 #include <pwd.h>
1192 }
1193
1194 break;
1195 case ZFS_PROP_UTF8ONLY:
1196 chosen_utf = (int)intval;
1197 break;
1198 case ZFS_PROP_NORMALIZE:
1199 chosen_normal = (int)intval;
1200 break;
1201 }
1202
1203 /*
1204 * For changes to existing volumes, we have some additional
1205 * checks to enforce.
1206 */
1207 if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1208 uint64_t volsize = zfs_prop_get_int(zhp,
1209 ZFS_PROP_VOLSIZE);
1210 uint64_t blocksize = zfs_prop_get_int(zhp,
1211 ZFS_PROP_VOLBLOCKSIZE);
1212 char buf[64];
1213
1214 switch (prop) {
1215 case ZFS_PROP_RESERVATION:
1216 case ZFS_PROP_REFRESERVATION:
1217 if (intval > volsize) {
1218 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1219 "'%s' is greater than current "
1220 "volume size"), propname);
1221 (void) zfs_error(hdl, EZFS_BADPROP,
1222 errbuf);
1223 goto error;
1224 }
1225 break;
1226
1227 case ZFS_PROP_VOLSIZE:
1228 if (intval % blocksize != 0) {
1229 zfs_nicenum(blocksize, buf,
1230 sizeof (buf));
1231 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1232 "'%s' must be a multiple of "
1233 "volume block size (%s)"),
1234 propname, buf);
1235 (void) zfs_error(hdl, EZFS_BADPROP,
1236 errbuf);
1237 goto error;
1268 "'%s' must be set 'on' if normalization chosen"),
1269 zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1270 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1271 goto error;
1272 }
1273 return (ret);
1274
1275 error:
1276 nvlist_free(ret);
1277 return (NULL);
1278 }
1279
1280 int
1281 zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1282 {
1283 uint64_t old_volsize;
1284 uint64_t new_volsize;
1285 uint64_t old_reservation;
1286 uint64_t new_reservation;
1287 zfs_prop_t resv_prop;
1288 nvlist_t *props;
1289
1290 /*
1291 * If this is an existing volume, and someone is setting the volsize,
1292 * make sure that it matches the reservation, or add it if necessary.
1293 */
1294 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1295 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1296 return (-1);
1297 old_reservation = zfs_prop_get_int(zhp, resv_prop);
1298
1299 props = fnvlist_alloc();
1300 fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1301 zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
1302
1303 if ((zvol_volsize_to_reservation(old_volsize, props) !=
1304 old_reservation) || nvlist_exists(nvl,
1305 zfs_prop_to_name(resv_prop))) {
1306 fnvlist_free(props);
1307 return (0);
1308 }
1309 if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1310 &new_volsize) != 0) {
1311 fnvlist_free(props);
1312 return (-1);
1313 }
1314 new_reservation = zvol_volsize_to_reservation(new_volsize, props);
1315 fnvlist_free(props);
1316
1317 if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1318 new_reservation) != 0) {
1319 (void) no_memory(zhp->zfs_hdl);
1320 return (-1);
1321 }
1322 return (1);
1323 }
1324
1325 void
1326 zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1327 char *errbuf)
1328 {
1329 switch (err) {
1330
1331 case ENOSPC:
1332 /*
1333 * For quotas and reservations, ENOSPC indicates
1334 * something different; setting a quota or reservation
1335 * doesn't use any disk space.
4443 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4444 "pool must be upgraded"));
4445 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4446 break;
4447 case EINVAL:
4448 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4449 break;
4450 case ENOENT:
4451 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4452 break;
4453 default:
4454 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4455 break;
4456 }
4457 }
4458
4459 return (err);
4460 }
4461
4462 /*
4463 * Convert the zvol's volume size to an appropriate reservation.
4464 * Note: If this routine is updated, it is necessary to update the ZFS test
4465 * suite's shell version in reservation.kshlib.
4466 */
4467 uint64_t
4468 zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
4469 {
4470 uint64_t numdb;
4471 uint64_t nblocks, volblocksize;
4472 int ncopies;
4473 char *strval;
4474
4475 if (nvlist_lookup_string(props,
4476 zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
4477 ncopies = atoi(strval);
4478 else
4479 ncopies = 1;
4480 if (nvlist_lookup_uint64(props,
4481 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
4482 &volblocksize) != 0)
4483 volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
4484 nblocks = volsize/volblocksize;
4485 /* start with metadnode L0-L6 */
4486 numdb = 7;
4487 /* calculate number of indirects */
4488 while (nblocks > 1) {
4489 nblocks += DNODES_PER_LEVEL - 1;
4490 nblocks /= DNODES_PER_LEVEL;
4491 numdb += nblocks;
4492 }
4493 numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
4494 volsize *= ncopies;
4495 /*
4496 * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
4497 * compressed, but in practice they compress down to about
4498 * 1100 bytes
4499 */
4500 numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
4501 volsize += numdb;
4502 return (volsize);
4503 }
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013 by Delphix. All rights reserved.
25 * Copyright 2013 DEY Storage Systems, Inc.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 * Copyright (c) 2013 Martin Matuska. All rights reserved.
28 * Copyright (c) 2013 Steven Hartland. All rights reserved.
29 */
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <libintl.h>
34 #include <math.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <unistd.h>
39 #include <stddef.h>
40 #include <zone.h>
41 #include <fcntl.h>
42 #include <sys/mntent.h>
43 #include <sys/mount.h>
44 #include <priv.h>
45 #include <pwd.h>
1192 }
1193
1194 break;
1195 case ZFS_PROP_UTF8ONLY:
1196 chosen_utf = (int)intval;
1197 break;
1198 case ZFS_PROP_NORMALIZE:
1199 chosen_normal = (int)intval;
1200 break;
1201 }
1202
1203 /*
1204 * For changes to existing volumes, we have some additional
1205 * checks to enforce.
1206 */
1207 if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1208 uint64_t volsize = zfs_prop_get_int(zhp,
1209 ZFS_PROP_VOLSIZE);
1210 uint64_t blocksize = zfs_prop_get_int(zhp,
1211 ZFS_PROP_VOLBLOCKSIZE);
1212 int ncopies = zfs_prop_get_int(zhp, ZFS_PROP_COPIES);
1213 char buf[64];
1214
1215 switch (prop) {
1216 case ZFS_PROP_RESERVATION:
1217 case ZFS_PROP_REFRESERVATION:
1218 if (intval >
1219 zvol_volsize_to_reservation(volsize,
1220 blocksize, ncopies)) {
1221 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1222 "'%s' is greater than current "
1223 "volume size"), propname);
1224 (void) zfs_error(hdl, EZFS_BADPROP,
1225 errbuf);
1226 goto error;
1227 }
1228 break;
1229
1230 case ZFS_PROP_VOLSIZE:
1231 if (intval % blocksize != 0) {
1232 zfs_nicenum(blocksize, buf,
1233 sizeof (buf));
1234 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1235 "'%s' must be a multiple of "
1236 "volume block size (%s)"),
1237 propname, buf);
1238 (void) zfs_error(hdl, EZFS_BADPROP,
1239 errbuf);
1240 goto error;
1271 "'%s' must be set 'on' if normalization chosen"),
1272 zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1273 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1274 goto error;
1275 }
1276 return (ret);
1277
1278 error:
1279 nvlist_free(ret);
1280 return (NULL);
1281 }
1282
1283 int
1284 zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1285 {
1286 uint64_t old_volsize;
1287 uint64_t new_volsize;
1288 uint64_t old_reservation;
1289 uint64_t new_reservation;
1290 zfs_prop_t resv_prop;
1291 uint64_t volblocksize;
1292 int ncopies;
1293
1294 /*
1295 * If this is an existing volume, and someone is setting the volsize,
1296 * make sure that it matches the reservation, or add it if necessary.
1297 */
1298 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1299 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1300 return (-1);
1301 old_reservation = zfs_prop_get_int(zhp, resv_prop);
1302 volblocksize = zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE);
1303 ncopies = zfs_prop_get_int(zhp, ZFS_PROP_COPIES);
1304
1305 if ((zvol_volsize_to_reservation(old_volsize, volblocksize,
1306 ncopies) != old_reservation) || nvlist_exists(nvl,
1307 zfs_prop_to_name(resv_prop)))
1308 return (0);
1309 if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1310 &new_volsize) != 0)
1311 return (-1);
1312 new_reservation = zvol_volsize_to_reservation(new_volsize,
1313 volblocksize, ncopies);
1314
1315 if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1316 new_reservation) != 0) {
1317 (void) no_memory(zhp->zfs_hdl);
1318 return (-1);
1319 }
1320 return (1);
1321 }
1322
1323 void
1324 zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1325 char *errbuf)
1326 {
1327 switch (err) {
1328
1329 case ENOSPC:
1330 /*
1331 * For quotas and reservations, ENOSPC indicates
1332 * something different; setting a quota or reservation
1333 * doesn't use any disk space.
4441 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4442 "pool must be upgraded"));
4443 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4444 break;
4445 case EINVAL:
4446 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4447 break;
4448 case ENOENT:
4449 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4450 break;
4451 default:
4452 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4453 break;
4454 }
4455 }
4456
4457 return (err);
4458 }
4459
4460 /*
4461 * Computes the required reservation to completely contain all blocks of a
4462 * zvol at a given volsize.
4463 */
4464 uint64_t
4465 zvol_volsize_to_reservation(uint64_t volsize, uint64_t volblocksize,
4466 int ncopies)
4467 {
4468 uint64_t numdb;
4469 uint64_t nblocks;
4470
4471 nblocks = volsize/volblocksize;
4472 /* start with metadnode L0-L6 */
4473 numdb = 7;
4474 /* calculate number of indirects */
4475 while (nblocks > 1) {
4476 nblocks += DNODES_PER_LEVEL - 1;
4477 nblocks /= DNODES_PER_LEVEL;
4478 numdb += nblocks;
4479 }
4480 numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
4481 volsize *= ncopies;
4482 /*
4483 * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
4484 * compressed, but in practice they compress down to about
4485 * 1100 bytes
4486 */
4487 numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
4488 volsize += numdb;
4489 return (volsize);
4490 }
|