1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy 22eda14cbcSMatt Macy /* 23eda14cbcSMatt Macy * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24eda14cbcSMatt Macy * Copyright 2019 Joyent, Inc. 25eda14cbcSMatt Macy * Copyright (c) 2011, 2020 by Delphix. All rights reserved. 26eda14cbcSMatt Macy * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. 27eda14cbcSMatt Macy * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>. 28eda14cbcSMatt Macy * Copyright (c) 2013 Martin Matuska. All rights reserved. 29eda14cbcSMatt Macy * Copyright (c) 2013 Steven Hartland. All rights reserved. 30eda14cbcSMatt Macy * Copyright 2017 Nexenta Systems, Inc. 31eda14cbcSMatt Macy * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> 32eda14cbcSMatt Macy * Copyright 2017-2018 RackTop Systems. 33eda14cbcSMatt Macy * Copyright (c) 2019 Datto Inc. 34eda14cbcSMatt Macy * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com> 3516038816SMartin Matuska * Copyright (c) 2021 Matt Fiddaman 36eda14cbcSMatt Macy */ 37eda14cbcSMatt Macy 38eda14cbcSMatt Macy #include <ctype.h> 39eda14cbcSMatt Macy #include <errno.h> 40eda14cbcSMatt Macy #include <libintl.h> 41eda14cbcSMatt Macy #include <stdio.h> 42eda14cbcSMatt Macy #include <stdlib.h> 43eda14cbcSMatt Macy #include <strings.h> 44eda14cbcSMatt Macy #include <unistd.h> 45eda14cbcSMatt Macy #include <stddef.h> 46eda14cbcSMatt Macy #include <zone.h> 47eda14cbcSMatt Macy #include <fcntl.h> 48eda14cbcSMatt Macy #include <sys/mntent.h> 49eda14cbcSMatt Macy #include <sys/mount.h> 50eda14cbcSMatt Macy #include <pwd.h> 51eda14cbcSMatt Macy #include <grp.h> 52eda14cbcSMatt Macy #ifdef HAVE_IDMAP 53eda14cbcSMatt Macy #include <idmap.h> 54eda14cbcSMatt Macy #include <aclutils.h> 55eda14cbcSMatt Macy #include <directory.h> 56eda14cbcSMatt Macy #endif /* HAVE_IDMAP */ 57eda14cbcSMatt Macy 58eda14cbcSMatt Macy #include <sys/dnode.h> 59eda14cbcSMatt Macy #include <sys/spa.h> 60eda14cbcSMatt Macy #include <sys/zap.h> 61eda14cbcSMatt Macy #include <sys/dsl_crypt.h> 62eda14cbcSMatt Macy #include <libzfs.h> 63eda14cbcSMatt Macy #include <libzutil.h> 64eda14cbcSMatt Macy 65eda14cbcSMatt Macy #include "zfs_namecheck.h" 66eda14cbcSMatt Macy #include "zfs_prop.h" 67eda14cbcSMatt Macy #include "libzfs_impl.h" 68eda14cbcSMatt Macy #include "zfs_deleg.h" 69eda14cbcSMatt Macy 70eda14cbcSMatt Macy static int userquota_propname_decode(const char *propname, boolean_t zoned, 71eda14cbcSMatt Macy zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 72eda14cbcSMatt Macy 73eda14cbcSMatt Macy /* 74eda14cbcSMatt Macy * Given a single type (not a mask of types), return the type in a human 75eda14cbcSMatt Macy * readable form. 76eda14cbcSMatt Macy */ 77eda14cbcSMatt Macy const char * 78eda14cbcSMatt Macy zfs_type_to_name(zfs_type_t type) 79eda14cbcSMatt Macy { 80eda14cbcSMatt Macy switch (type) { 81eda14cbcSMatt Macy case ZFS_TYPE_FILESYSTEM: 82eda14cbcSMatt Macy return (dgettext(TEXT_DOMAIN, "filesystem")); 83eda14cbcSMatt Macy case ZFS_TYPE_SNAPSHOT: 84eda14cbcSMatt Macy return (dgettext(TEXT_DOMAIN, "snapshot")); 85eda14cbcSMatt Macy case ZFS_TYPE_VOLUME: 86eda14cbcSMatt Macy return (dgettext(TEXT_DOMAIN, "volume")); 87eda14cbcSMatt Macy case ZFS_TYPE_POOL: 88eda14cbcSMatt Macy return (dgettext(TEXT_DOMAIN, "pool")); 89eda14cbcSMatt Macy case ZFS_TYPE_BOOKMARK: 90eda14cbcSMatt Macy return (dgettext(TEXT_DOMAIN, "bookmark")); 91eda14cbcSMatt Macy default: 92eda14cbcSMatt Macy assert(!"unhandled zfs_type_t"); 93eda14cbcSMatt Macy } 94eda14cbcSMatt Macy 95eda14cbcSMatt Macy return (NULL); 96eda14cbcSMatt Macy } 97eda14cbcSMatt Macy 98eda14cbcSMatt Macy /* 99eda14cbcSMatt Macy * Validate a ZFS path. This is used even before trying to open the dataset, to 100eda14cbcSMatt Macy * provide a more meaningful error message. We call zfs_error_aux() to 101eda14cbcSMatt Macy * explain exactly why the name was not valid. 102eda14cbcSMatt Macy */ 103eda14cbcSMatt Macy int 104eda14cbcSMatt Macy zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 105eda14cbcSMatt Macy boolean_t modifying) 106eda14cbcSMatt Macy { 107eda14cbcSMatt Macy namecheck_err_t why; 108eda14cbcSMatt Macy char what; 109eda14cbcSMatt Macy 110eda14cbcSMatt Macy if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 111eda14cbcSMatt Macy if (hdl != NULL) 112eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 113eda14cbcSMatt Macy "snapshot delimiter '@' is not expected here")); 114eda14cbcSMatt Macy return (0); 115eda14cbcSMatt Macy } 116eda14cbcSMatt Macy 117eda14cbcSMatt Macy if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 118eda14cbcSMatt Macy if (hdl != NULL) 119eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 120eda14cbcSMatt Macy "missing '@' delimiter in snapshot name")); 121eda14cbcSMatt Macy return (0); 122eda14cbcSMatt Macy } 123eda14cbcSMatt Macy 124eda14cbcSMatt Macy if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) { 125eda14cbcSMatt Macy if (hdl != NULL) 126eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 127eda14cbcSMatt Macy "bookmark delimiter '#' is not expected here")); 128eda14cbcSMatt Macy return (0); 129eda14cbcSMatt Macy } 130eda14cbcSMatt Macy 131eda14cbcSMatt Macy if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) { 132eda14cbcSMatt Macy if (hdl != NULL) 133eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 134eda14cbcSMatt Macy "missing '#' delimiter in bookmark name")); 135eda14cbcSMatt Macy return (0); 136eda14cbcSMatt Macy } 137eda14cbcSMatt Macy 138eda14cbcSMatt Macy if (modifying && strchr(path, '%') != NULL) { 139eda14cbcSMatt Macy if (hdl != NULL) 140eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 141eda14cbcSMatt Macy "invalid character %c in name"), '%'); 142eda14cbcSMatt Macy return (0); 143eda14cbcSMatt Macy } 144eda14cbcSMatt Macy 145eda14cbcSMatt Macy if (entity_namecheck(path, &why, &what) != 0) { 146eda14cbcSMatt Macy if (hdl != NULL) { 147eda14cbcSMatt Macy switch (why) { 148eda14cbcSMatt Macy case NAME_ERR_TOOLONG: 149eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 150eda14cbcSMatt Macy "name is too long")); 151eda14cbcSMatt Macy break; 152eda14cbcSMatt Macy 153eda14cbcSMatt Macy case NAME_ERR_LEADING_SLASH: 154eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 155eda14cbcSMatt Macy "leading slash in name")); 156eda14cbcSMatt Macy break; 157eda14cbcSMatt Macy 158eda14cbcSMatt Macy case NAME_ERR_EMPTY_COMPONENT: 159eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 160eda14cbcSMatt Macy "empty component or misplaced '@'" 161eda14cbcSMatt Macy " or '#' delimiter in name")); 162eda14cbcSMatt Macy break; 163eda14cbcSMatt Macy 164eda14cbcSMatt Macy case NAME_ERR_TRAILING_SLASH: 165eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 166eda14cbcSMatt Macy "trailing slash in name")); 167eda14cbcSMatt Macy break; 168eda14cbcSMatt Macy 169eda14cbcSMatt Macy case NAME_ERR_INVALCHAR: 170eda14cbcSMatt Macy zfs_error_aux(hdl, 171eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "invalid character " 172eda14cbcSMatt Macy "'%c' in name"), what); 173eda14cbcSMatt Macy break; 174eda14cbcSMatt Macy 175eda14cbcSMatt Macy case NAME_ERR_MULTIPLE_DELIMITERS: 176eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 177eda14cbcSMatt Macy "multiple '@' and/or '#' delimiters in " 178eda14cbcSMatt Macy "name")); 179eda14cbcSMatt Macy break; 180eda14cbcSMatt Macy 181eda14cbcSMatt Macy case NAME_ERR_NOLETTER: 182eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 183eda14cbcSMatt Macy "pool doesn't begin with a letter")); 184eda14cbcSMatt Macy break; 185eda14cbcSMatt Macy 186eda14cbcSMatt Macy case NAME_ERR_RESERVED: 187eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 188eda14cbcSMatt Macy "name is reserved")); 189eda14cbcSMatt Macy break; 190eda14cbcSMatt Macy 191eda14cbcSMatt Macy case NAME_ERR_DISKLIKE: 192eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 193eda14cbcSMatt Macy "reserved disk name")); 194eda14cbcSMatt Macy break; 195eda14cbcSMatt Macy 196eda14cbcSMatt Macy case NAME_ERR_SELF_REF: 197eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 198eda14cbcSMatt Macy "self reference, '.' is found in name")); 199eda14cbcSMatt Macy break; 200eda14cbcSMatt Macy 201eda14cbcSMatt Macy case NAME_ERR_PARENT_REF: 202eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 203eda14cbcSMatt Macy "parent reference, '..' is found in name")); 204eda14cbcSMatt Macy break; 205eda14cbcSMatt Macy 206eda14cbcSMatt Macy default: 207eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 208eda14cbcSMatt Macy "(%d) not defined"), why); 209eda14cbcSMatt Macy break; 210eda14cbcSMatt Macy } 211eda14cbcSMatt Macy } 212eda14cbcSMatt Macy 213eda14cbcSMatt Macy return (0); 214eda14cbcSMatt Macy } 215eda14cbcSMatt Macy 216eda14cbcSMatt Macy return (-1); 217eda14cbcSMatt Macy } 218eda14cbcSMatt Macy 219eda14cbcSMatt Macy int 220eda14cbcSMatt Macy zfs_name_valid(const char *name, zfs_type_t type) 221eda14cbcSMatt Macy { 222eda14cbcSMatt Macy if (type == ZFS_TYPE_POOL) 223eda14cbcSMatt Macy return (zpool_name_valid(NULL, B_FALSE, name)); 224eda14cbcSMatt Macy return (zfs_validate_name(NULL, name, type, B_FALSE)); 225eda14cbcSMatt Macy } 226eda14cbcSMatt Macy 227eda14cbcSMatt Macy /* 228eda14cbcSMatt Macy * This function takes the raw DSL properties, and filters out the user-defined 229eda14cbcSMatt Macy * properties into a separate nvlist. 230eda14cbcSMatt Macy */ 231eda14cbcSMatt Macy static nvlist_t * 232eda14cbcSMatt Macy process_user_props(zfs_handle_t *zhp, nvlist_t *props) 233eda14cbcSMatt Macy { 234eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 235eda14cbcSMatt Macy nvpair_t *elem; 236eda14cbcSMatt Macy nvlist_t *nvl; 237eda14cbcSMatt Macy 238eda14cbcSMatt Macy if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 239eda14cbcSMatt Macy (void) no_memory(hdl); 240eda14cbcSMatt Macy return (NULL); 241eda14cbcSMatt Macy } 242eda14cbcSMatt Macy 243eda14cbcSMatt Macy elem = NULL; 244eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 245eda14cbcSMatt Macy if (!zfs_prop_user(nvpair_name(elem))) 246eda14cbcSMatt Macy continue; 247eda14cbcSMatt Macy 248da5137abSMartin Matuska nvlist_t *propval = fnvpair_value_nvlist(elem); 249eda14cbcSMatt Macy if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 250eda14cbcSMatt Macy nvlist_free(nvl); 251eda14cbcSMatt Macy (void) no_memory(hdl); 252eda14cbcSMatt Macy return (NULL); 253eda14cbcSMatt Macy } 254eda14cbcSMatt Macy } 255eda14cbcSMatt Macy 256eda14cbcSMatt Macy return (nvl); 257eda14cbcSMatt Macy } 258eda14cbcSMatt Macy 259eda14cbcSMatt Macy static zpool_handle_t * 260eda14cbcSMatt Macy zpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 261eda14cbcSMatt Macy { 262eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 263eda14cbcSMatt Macy zpool_handle_t *zph; 264eda14cbcSMatt Macy 265eda14cbcSMatt Macy if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 266eda14cbcSMatt Macy if (hdl->libzfs_pool_handles != NULL) 267eda14cbcSMatt Macy zph->zpool_next = hdl->libzfs_pool_handles; 268eda14cbcSMatt Macy hdl->libzfs_pool_handles = zph; 269eda14cbcSMatt Macy } 270eda14cbcSMatt Macy return (zph); 271eda14cbcSMatt Macy } 272eda14cbcSMatt Macy 273eda14cbcSMatt Macy static zpool_handle_t * 274eda14cbcSMatt Macy zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 275eda14cbcSMatt Macy { 276eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 277eda14cbcSMatt Macy zpool_handle_t *zph = hdl->libzfs_pool_handles; 278eda14cbcSMatt Macy 279eda14cbcSMatt Macy while ((zph != NULL) && 280eda14cbcSMatt Macy (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 281eda14cbcSMatt Macy zph = zph->zpool_next; 282eda14cbcSMatt Macy return (zph); 283eda14cbcSMatt Macy } 284eda14cbcSMatt Macy 285eda14cbcSMatt Macy /* 286eda14cbcSMatt Macy * Returns a handle to the pool that contains the provided dataset. 287eda14cbcSMatt Macy * If a handle to that pool already exists then that handle is returned. 288eda14cbcSMatt Macy * Otherwise, a new handle is created and added to the list of handles. 289eda14cbcSMatt Macy */ 290eda14cbcSMatt Macy static zpool_handle_t * 291eda14cbcSMatt Macy zpool_handle(zfs_handle_t *zhp) 292eda14cbcSMatt Macy { 293eda14cbcSMatt Macy char *pool_name; 294eda14cbcSMatt Macy int len; 295eda14cbcSMatt Macy zpool_handle_t *zph; 296eda14cbcSMatt Macy 297eda14cbcSMatt Macy len = strcspn(zhp->zfs_name, "/@#") + 1; 298eda14cbcSMatt Macy pool_name = zfs_alloc(zhp->zfs_hdl, len); 299eda14cbcSMatt Macy (void) strlcpy(pool_name, zhp->zfs_name, len); 300eda14cbcSMatt Macy 301eda14cbcSMatt Macy zph = zpool_find_handle(zhp, pool_name, len); 302eda14cbcSMatt Macy if (zph == NULL) 303eda14cbcSMatt Macy zph = zpool_add_handle(zhp, pool_name); 304eda14cbcSMatt Macy 305eda14cbcSMatt Macy free(pool_name); 306eda14cbcSMatt Macy return (zph); 307eda14cbcSMatt Macy } 308eda14cbcSMatt Macy 309eda14cbcSMatt Macy void 310eda14cbcSMatt Macy zpool_free_handles(libzfs_handle_t *hdl) 311eda14cbcSMatt Macy { 312eda14cbcSMatt Macy zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 313eda14cbcSMatt Macy 314eda14cbcSMatt Macy while (zph != NULL) { 315eda14cbcSMatt Macy next = zph->zpool_next; 316eda14cbcSMatt Macy zpool_close(zph); 317eda14cbcSMatt Macy zph = next; 318eda14cbcSMatt Macy } 319eda14cbcSMatt Macy hdl->libzfs_pool_handles = NULL; 320eda14cbcSMatt Macy } 321eda14cbcSMatt Macy 322eda14cbcSMatt Macy /* 323eda14cbcSMatt Macy * Utility function to gather stats (objset and zpl) for the given object. 324eda14cbcSMatt Macy */ 325eda14cbcSMatt Macy static int 326eda14cbcSMatt Macy get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 327eda14cbcSMatt Macy { 328eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 329eda14cbcSMatt Macy 330eda14cbcSMatt Macy (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 331eda14cbcSMatt Macy 332eda14cbcSMatt Macy while (zfs_ioctl(hdl, ZFS_IOC_OBJSET_STATS, zc) != 0) { 333716fd348SMartin Matuska if (errno == ENOMEM) 334716fd348SMartin Matuska zcmd_expand_dst_nvlist(hdl, zc); 335716fd348SMartin Matuska else 336eda14cbcSMatt Macy return (-1); 337eda14cbcSMatt Macy } 338eda14cbcSMatt Macy return (0); 339eda14cbcSMatt Macy } 340eda14cbcSMatt Macy 341eda14cbcSMatt Macy /* 342eda14cbcSMatt Macy * Utility function to get the received properties of the given object. 343eda14cbcSMatt Macy */ 344eda14cbcSMatt Macy static int 345eda14cbcSMatt Macy get_recvd_props_ioctl(zfs_handle_t *zhp) 346eda14cbcSMatt Macy { 347eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 348eda14cbcSMatt Macy nvlist_t *recvdprops; 349eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 350eda14cbcSMatt Macy int err; 351eda14cbcSMatt Macy 352716fd348SMartin Matuska zcmd_alloc_dst_nvlist(hdl, &zc, 0); 353eda14cbcSMatt Macy 354eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 355eda14cbcSMatt Macy 356eda14cbcSMatt Macy while (zfs_ioctl(hdl, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 357716fd348SMartin Matuska if (errno == ENOMEM) 358716fd348SMartin Matuska zcmd_expand_dst_nvlist(hdl, &zc); 359716fd348SMartin Matuska else { 360eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 361eda14cbcSMatt Macy return (-1); 362eda14cbcSMatt Macy } 363eda14cbcSMatt Macy } 364eda14cbcSMatt Macy 365eda14cbcSMatt Macy err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 366eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 367eda14cbcSMatt Macy if (err != 0) 368eda14cbcSMatt Macy return (-1); 369eda14cbcSMatt Macy 370eda14cbcSMatt Macy nvlist_free(zhp->zfs_recvd_props); 371eda14cbcSMatt Macy zhp->zfs_recvd_props = recvdprops; 372eda14cbcSMatt Macy 373eda14cbcSMatt Macy return (0); 374eda14cbcSMatt Macy } 375eda14cbcSMatt Macy 376eda14cbcSMatt Macy static int 377eda14cbcSMatt Macy put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 378eda14cbcSMatt Macy { 379eda14cbcSMatt Macy nvlist_t *allprops, *userprops; 380eda14cbcSMatt Macy 381eda14cbcSMatt Macy zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 382eda14cbcSMatt Macy 383eda14cbcSMatt Macy if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 384eda14cbcSMatt Macy return (-1); 385eda14cbcSMatt Macy } 386eda14cbcSMatt Macy 387eda14cbcSMatt Macy /* 388eda14cbcSMatt Macy * XXX Why do we store the user props separately, in addition to 389eda14cbcSMatt Macy * storing them in zfs_props? 390eda14cbcSMatt Macy */ 391eda14cbcSMatt Macy if ((userprops = process_user_props(zhp, allprops)) == NULL) { 392eda14cbcSMatt Macy nvlist_free(allprops); 393eda14cbcSMatt Macy return (-1); 394eda14cbcSMatt Macy } 395eda14cbcSMatt Macy 396eda14cbcSMatt Macy nvlist_free(zhp->zfs_props); 397eda14cbcSMatt Macy nvlist_free(zhp->zfs_user_props); 398eda14cbcSMatt Macy 399eda14cbcSMatt Macy zhp->zfs_props = allprops; 400eda14cbcSMatt Macy zhp->zfs_user_props = userprops; 401eda14cbcSMatt Macy 402eda14cbcSMatt Macy return (0); 403eda14cbcSMatt Macy } 404eda14cbcSMatt Macy 405eda14cbcSMatt Macy static int 406eda14cbcSMatt Macy get_stats(zfs_handle_t *zhp) 407eda14cbcSMatt Macy { 408eda14cbcSMatt Macy int rc = 0; 409eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 410eda14cbcSMatt Macy 411716fd348SMartin Matuska zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0); 412716fd348SMartin Matuska 413eda14cbcSMatt Macy if (get_stats_ioctl(zhp, &zc) != 0) 414eda14cbcSMatt Macy rc = -1; 415eda14cbcSMatt Macy else if (put_stats_zhdl(zhp, &zc) != 0) 416eda14cbcSMatt Macy rc = -1; 417eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 418eda14cbcSMatt Macy return (rc); 419eda14cbcSMatt Macy } 420eda14cbcSMatt Macy 421eda14cbcSMatt Macy /* 422eda14cbcSMatt Macy * Refresh the properties currently stored in the handle. 423eda14cbcSMatt Macy */ 424eda14cbcSMatt Macy void 425eda14cbcSMatt Macy zfs_refresh_properties(zfs_handle_t *zhp) 426eda14cbcSMatt Macy { 427eda14cbcSMatt Macy (void) get_stats(zhp); 428eda14cbcSMatt Macy } 429eda14cbcSMatt Macy 430eda14cbcSMatt Macy /* 431eda14cbcSMatt Macy * Makes a handle from the given dataset name. Used by zfs_open() and 432eda14cbcSMatt Macy * zfs_iter_* to create child handles on the fly. 433eda14cbcSMatt Macy */ 434eda14cbcSMatt Macy static int 435eda14cbcSMatt Macy make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 436eda14cbcSMatt Macy { 437eda14cbcSMatt Macy if (put_stats_zhdl(zhp, zc) != 0) 438eda14cbcSMatt Macy return (-1); 439eda14cbcSMatt Macy 440eda14cbcSMatt Macy /* 441eda14cbcSMatt Macy * We've managed to open the dataset and gather statistics. Determine 442eda14cbcSMatt Macy * the high-level type. 443eda14cbcSMatt Macy */ 444c03c5b1cSMartin Matuska if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 445eda14cbcSMatt Macy zhp->zfs_head_type = ZFS_TYPE_VOLUME; 446c03c5b1cSMartin Matuska } else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) { 447eda14cbcSMatt Macy zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 448c03c5b1cSMartin Matuska } else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER) { 449c03c5b1cSMartin Matuska errno = EINVAL; 450eda14cbcSMatt Macy return (-1); 451c03c5b1cSMartin Matuska } else if (zhp->zfs_dmustats.dds_inconsistent) { 452c03c5b1cSMartin Matuska errno = EBUSY; 453c03c5b1cSMartin Matuska return (-1); 454c03c5b1cSMartin Matuska } else { 455eda14cbcSMatt Macy abort(); 456c03c5b1cSMartin Matuska } 457eda14cbcSMatt Macy 458eda14cbcSMatt Macy if (zhp->zfs_dmustats.dds_is_snapshot) 459eda14cbcSMatt Macy zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 460eda14cbcSMatt Macy else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 461eda14cbcSMatt Macy zhp->zfs_type = ZFS_TYPE_VOLUME; 462eda14cbcSMatt Macy else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 463eda14cbcSMatt Macy zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 464eda14cbcSMatt Macy else 465eda14cbcSMatt Macy abort(); /* we should never see any other types */ 466eda14cbcSMatt Macy 467eda14cbcSMatt Macy if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 468eda14cbcSMatt Macy return (-1); 469eda14cbcSMatt Macy 470eda14cbcSMatt Macy return (0); 471eda14cbcSMatt Macy } 472eda14cbcSMatt Macy 473eda14cbcSMatt Macy zfs_handle_t * 474eda14cbcSMatt Macy make_dataset_handle(libzfs_handle_t *hdl, const char *path) 475eda14cbcSMatt Macy { 476eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 477eda14cbcSMatt Macy 478eda14cbcSMatt Macy zfs_handle_t *zhp = calloc(1, sizeof (zfs_handle_t)); 479eda14cbcSMatt Macy 480eda14cbcSMatt Macy if (zhp == NULL) 481eda14cbcSMatt Macy return (NULL); 482eda14cbcSMatt Macy 483eda14cbcSMatt Macy zhp->zfs_hdl = hdl; 484eda14cbcSMatt Macy (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 485716fd348SMartin Matuska zcmd_alloc_dst_nvlist(hdl, &zc, 0); 486716fd348SMartin Matuska 487eda14cbcSMatt Macy if (get_stats_ioctl(zhp, &zc) == -1) { 488eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 489eda14cbcSMatt Macy free(zhp); 490eda14cbcSMatt Macy return (NULL); 491eda14cbcSMatt Macy } 492eda14cbcSMatt Macy if (make_dataset_handle_common(zhp, &zc) == -1) { 493eda14cbcSMatt Macy free(zhp); 494eda14cbcSMatt Macy zhp = NULL; 495eda14cbcSMatt Macy } 496eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 497eda14cbcSMatt Macy return (zhp); 498eda14cbcSMatt Macy } 499eda14cbcSMatt Macy 500eda14cbcSMatt Macy zfs_handle_t * 501eda14cbcSMatt Macy make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 502eda14cbcSMatt Macy { 503eda14cbcSMatt Macy zfs_handle_t *zhp = calloc(1, sizeof (zfs_handle_t)); 504eda14cbcSMatt Macy 505eda14cbcSMatt Macy if (zhp == NULL) 506eda14cbcSMatt Macy return (NULL); 507eda14cbcSMatt Macy 508eda14cbcSMatt Macy zhp->zfs_hdl = hdl; 509eda14cbcSMatt Macy (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 510eda14cbcSMatt Macy if (make_dataset_handle_common(zhp, zc) == -1) { 511eda14cbcSMatt Macy free(zhp); 512eda14cbcSMatt Macy return (NULL); 513eda14cbcSMatt Macy } 514eda14cbcSMatt Macy return (zhp); 515eda14cbcSMatt Macy } 516eda14cbcSMatt Macy 517eda14cbcSMatt Macy zfs_handle_t * 518eda14cbcSMatt Macy make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 519eda14cbcSMatt Macy { 520eda14cbcSMatt Macy zfs_handle_t *zhp = calloc(1, sizeof (zfs_handle_t)); 521eda14cbcSMatt Macy 522eda14cbcSMatt Macy if (zhp == NULL) 523eda14cbcSMatt Macy return (NULL); 524eda14cbcSMatt Macy 525eda14cbcSMatt Macy zhp->zfs_hdl = pzhp->zfs_hdl; 526eda14cbcSMatt Macy (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 527eda14cbcSMatt Macy zhp->zfs_head_type = pzhp->zfs_type; 528eda14cbcSMatt Macy zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 529eda14cbcSMatt Macy zhp->zpool_hdl = zpool_handle(zhp); 530*15f0b8c3SMartin Matuska 531*15f0b8c3SMartin Matuska if (zc->zc_objset_stats.dds_creation_txg != 0) { 532*15f0b8c3SMartin Matuska /* structure assignment */ 533271171e0SMartin Matuska zhp->zfs_dmustats = zc->zc_objset_stats; 534*15f0b8c3SMartin Matuska } else { 535*15f0b8c3SMartin Matuska if (get_stats_ioctl(zhp, zc) == -1) { 536*15f0b8c3SMartin Matuska zcmd_free_nvlists(zc); 537*15f0b8c3SMartin Matuska free(zhp); 538*15f0b8c3SMartin Matuska return (NULL); 539*15f0b8c3SMartin Matuska } 540*15f0b8c3SMartin Matuska if (make_dataset_handle_common(zhp, zc) == -1) { 541*15f0b8c3SMartin Matuska zcmd_free_nvlists(zc); 542*15f0b8c3SMartin Matuska free(zhp); 543*15f0b8c3SMartin Matuska return (NULL); 544*15f0b8c3SMartin Matuska } 545*15f0b8c3SMartin Matuska } 546*15f0b8c3SMartin Matuska 547*15f0b8c3SMartin Matuska if (zhp->zfs_dmustats.dds_is_snapshot || 548*15f0b8c3SMartin Matuska strchr(zc->zc_name, '@') != NULL) 549*15f0b8c3SMartin Matuska zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 550*15f0b8c3SMartin Matuska else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 551*15f0b8c3SMartin Matuska zhp->zfs_type = ZFS_TYPE_VOLUME; 552*15f0b8c3SMartin Matuska else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 553*15f0b8c3SMartin Matuska zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 554eda14cbcSMatt Macy 555eda14cbcSMatt Macy return (zhp); 556eda14cbcSMatt Macy } 557eda14cbcSMatt Macy 558eda14cbcSMatt Macy zfs_handle_t * 559eda14cbcSMatt Macy zfs_handle_dup(zfs_handle_t *zhp_orig) 560eda14cbcSMatt Macy { 561eda14cbcSMatt Macy zfs_handle_t *zhp = calloc(1, sizeof (zfs_handle_t)); 562eda14cbcSMatt Macy 563eda14cbcSMatt Macy if (zhp == NULL) 564eda14cbcSMatt Macy return (NULL); 565eda14cbcSMatt Macy 566eda14cbcSMatt Macy zhp->zfs_hdl = zhp_orig->zfs_hdl; 567eda14cbcSMatt Macy zhp->zpool_hdl = zhp_orig->zpool_hdl; 568eda14cbcSMatt Macy (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 569eda14cbcSMatt Macy sizeof (zhp->zfs_name)); 570eda14cbcSMatt Macy zhp->zfs_type = zhp_orig->zfs_type; 571eda14cbcSMatt Macy zhp->zfs_head_type = zhp_orig->zfs_head_type; 572eda14cbcSMatt Macy zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 573eda14cbcSMatt Macy if (zhp_orig->zfs_props != NULL) { 574eda14cbcSMatt Macy if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 575eda14cbcSMatt Macy (void) no_memory(zhp->zfs_hdl); 576eda14cbcSMatt Macy zfs_close(zhp); 577eda14cbcSMatt Macy return (NULL); 578eda14cbcSMatt Macy } 579eda14cbcSMatt Macy } 580eda14cbcSMatt Macy if (zhp_orig->zfs_user_props != NULL) { 581eda14cbcSMatt Macy if (nvlist_dup(zhp_orig->zfs_user_props, 582eda14cbcSMatt Macy &zhp->zfs_user_props, 0) != 0) { 583eda14cbcSMatt Macy (void) no_memory(zhp->zfs_hdl); 584eda14cbcSMatt Macy zfs_close(zhp); 585eda14cbcSMatt Macy return (NULL); 586eda14cbcSMatt Macy } 587eda14cbcSMatt Macy } 588eda14cbcSMatt Macy if (zhp_orig->zfs_recvd_props != NULL) { 589eda14cbcSMatt Macy if (nvlist_dup(zhp_orig->zfs_recvd_props, 590eda14cbcSMatt Macy &zhp->zfs_recvd_props, 0)) { 591eda14cbcSMatt Macy (void) no_memory(zhp->zfs_hdl); 592eda14cbcSMatt Macy zfs_close(zhp); 593eda14cbcSMatt Macy return (NULL); 594eda14cbcSMatt Macy } 595eda14cbcSMatt Macy } 596eda14cbcSMatt Macy zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 597eda14cbcSMatt Macy if (zhp_orig->zfs_mntopts != NULL) { 598eda14cbcSMatt Macy zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 599eda14cbcSMatt Macy zhp_orig->zfs_mntopts); 600eda14cbcSMatt Macy } 601eda14cbcSMatt Macy zhp->zfs_props_table = zhp_orig->zfs_props_table; 602eda14cbcSMatt Macy return (zhp); 603eda14cbcSMatt Macy } 604eda14cbcSMatt Macy 605eda14cbcSMatt Macy boolean_t 606eda14cbcSMatt Macy zfs_bookmark_exists(const char *path) 607eda14cbcSMatt Macy { 608eda14cbcSMatt Macy nvlist_t *bmarks; 609eda14cbcSMatt Macy nvlist_t *props; 610eda14cbcSMatt Macy char fsname[ZFS_MAX_DATASET_NAME_LEN]; 611eda14cbcSMatt Macy char *bmark_name; 612eda14cbcSMatt Macy char *pound; 613eda14cbcSMatt Macy int err; 614eda14cbcSMatt Macy boolean_t rv; 615eda14cbcSMatt Macy 616eda14cbcSMatt Macy (void) strlcpy(fsname, path, sizeof (fsname)); 617eda14cbcSMatt Macy pound = strchr(fsname, '#'); 618eda14cbcSMatt Macy if (pound == NULL) 619eda14cbcSMatt Macy return (B_FALSE); 620eda14cbcSMatt Macy 621eda14cbcSMatt Macy *pound = '\0'; 622eda14cbcSMatt Macy bmark_name = pound + 1; 623eda14cbcSMatt Macy props = fnvlist_alloc(); 624eda14cbcSMatt Macy err = lzc_get_bookmarks(fsname, props, &bmarks); 625eda14cbcSMatt Macy nvlist_free(props); 626eda14cbcSMatt Macy if (err != 0) { 627eda14cbcSMatt Macy nvlist_free(bmarks); 628eda14cbcSMatt Macy return (B_FALSE); 629eda14cbcSMatt Macy } 630eda14cbcSMatt Macy 631eda14cbcSMatt Macy rv = nvlist_exists(bmarks, bmark_name); 632eda14cbcSMatt Macy nvlist_free(bmarks); 633eda14cbcSMatt Macy return (rv); 634eda14cbcSMatt Macy } 635eda14cbcSMatt Macy 636eda14cbcSMatt Macy zfs_handle_t * 637eda14cbcSMatt Macy make_bookmark_handle(zfs_handle_t *parent, const char *path, 638eda14cbcSMatt Macy nvlist_t *bmark_props) 639eda14cbcSMatt Macy { 640eda14cbcSMatt Macy zfs_handle_t *zhp = calloc(1, sizeof (zfs_handle_t)); 641eda14cbcSMatt Macy 642eda14cbcSMatt Macy if (zhp == NULL) 643eda14cbcSMatt Macy return (NULL); 644eda14cbcSMatt Macy 645eda14cbcSMatt Macy /* Fill in the name. */ 646eda14cbcSMatt Macy zhp->zfs_hdl = parent->zfs_hdl; 647eda14cbcSMatt Macy (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 648eda14cbcSMatt Macy 649eda14cbcSMatt Macy /* Set the property lists. */ 650eda14cbcSMatt Macy if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { 651eda14cbcSMatt Macy free(zhp); 652eda14cbcSMatt Macy return (NULL); 653eda14cbcSMatt Macy } 654eda14cbcSMatt Macy 655eda14cbcSMatt Macy /* Set the types. */ 656eda14cbcSMatt Macy zhp->zfs_head_type = parent->zfs_head_type; 657eda14cbcSMatt Macy zhp->zfs_type = ZFS_TYPE_BOOKMARK; 658eda14cbcSMatt Macy 659eda14cbcSMatt Macy if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { 660eda14cbcSMatt Macy nvlist_free(zhp->zfs_props); 661eda14cbcSMatt Macy free(zhp); 662eda14cbcSMatt Macy return (NULL); 663eda14cbcSMatt Macy } 664eda14cbcSMatt Macy 665eda14cbcSMatt Macy return (zhp); 666eda14cbcSMatt Macy } 667eda14cbcSMatt Macy 668eda14cbcSMatt Macy struct zfs_open_bookmarks_cb_data { 669eda14cbcSMatt Macy const char *path; 670eda14cbcSMatt Macy zfs_handle_t *zhp; 671eda14cbcSMatt Macy }; 672eda14cbcSMatt Macy 673eda14cbcSMatt Macy static int 674eda14cbcSMatt Macy zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data) 675eda14cbcSMatt Macy { 676eda14cbcSMatt Macy struct zfs_open_bookmarks_cb_data *dp = data; 677eda14cbcSMatt Macy 678eda14cbcSMatt Macy /* 679eda14cbcSMatt Macy * Is it the one we are looking for? 680eda14cbcSMatt Macy */ 681eda14cbcSMatt Macy if (strcmp(dp->path, zfs_get_name(zhp)) == 0) { 682eda14cbcSMatt Macy /* 683eda14cbcSMatt Macy * We found it. Save it and let the caller know we are done. 684eda14cbcSMatt Macy */ 685eda14cbcSMatt Macy dp->zhp = zhp; 686eda14cbcSMatt Macy return (EEXIST); 687eda14cbcSMatt Macy } 688eda14cbcSMatt Macy 689eda14cbcSMatt Macy /* 690eda14cbcSMatt Macy * Not found. Close the handle and ask for another one. 691eda14cbcSMatt Macy */ 692eda14cbcSMatt Macy zfs_close(zhp); 693eda14cbcSMatt Macy return (0); 694eda14cbcSMatt Macy } 695eda14cbcSMatt Macy 696eda14cbcSMatt Macy /* 697eda14cbcSMatt Macy * Opens the given snapshot, bookmark, filesystem, or volume. The 'types' 698eda14cbcSMatt Macy * argument is a mask of acceptable types. The function will print an 699eda14cbcSMatt Macy * appropriate error message and return NULL if it can't be opened. 700eda14cbcSMatt Macy */ 701eda14cbcSMatt Macy zfs_handle_t * 702eda14cbcSMatt Macy zfs_open(libzfs_handle_t *hdl, const char *path, int types) 703eda14cbcSMatt Macy { 704eda14cbcSMatt Macy zfs_handle_t *zhp; 7051f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 706eda14cbcSMatt Macy char *bookp; 707eda14cbcSMatt Macy 708eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 709eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 710eda14cbcSMatt Macy 711eda14cbcSMatt Macy /* 712eda14cbcSMatt Macy * Validate the name before we even try to open it. 713eda14cbcSMatt Macy */ 714eda14cbcSMatt Macy if (!zfs_validate_name(hdl, path, types, B_FALSE)) { 715eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 716*15f0b8c3SMartin Matuska errno = EINVAL; 717eda14cbcSMatt Macy return (NULL); 718eda14cbcSMatt Macy } 719eda14cbcSMatt Macy 720eda14cbcSMatt Macy /* 721eda14cbcSMatt Macy * Bookmarks needs to be handled separately. 722eda14cbcSMatt Macy */ 723eda14cbcSMatt Macy bookp = strchr(path, '#'); 724eda14cbcSMatt Macy if (bookp == NULL) { 725eda14cbcSMatt Macy /* 726eda14cbcSMatt Macy * Try to get stats for the dataset, which will tell us if it 727eda14cbcSMatt Macy * exists. 728eda14cbcSMatt Macy */ 729eda14cbcSMatt Macy errno = 0; 730eda14cbcSMatt Macy if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 731eda14cbcSMatt Macy (void) zfs_standard_error(hdl, errno, errbuf); 732eda14cbcSMatt Macy return (NULL); 733eda14cbcSMatt Macy } 734eda14cbcSMatt Macy } else { 735eda14cbcSMatt Macy char dsname[ZFS_MAX_DATASET_NAME_LEN]; 736eda14cbcSMatt Macy zfs_handle_t *pzhp; 737eda14cbcSMatt Macy struct zfs_open_bookmarks_cb_data cb_data = {path, NULL}; 738eda14cbcSMatt Macy 739eda14cbcSMatt Macy /* 740eda14cbcSMatt Macy * We need to cut out '#' and everything after '#' 741eda14cbcSMatt Macy * to get the parent dataset name only. 742eda14cbcSMatt Macy */ 743eda14cbcSMatt Macy assert(bookp - path < sizeof (dsname)); 744be181ee2SMartin Matuska (void) strlcpy(dsname, path, 745be181ee2SMartin Matuska MIN(sizeof (dsname), bookp - path + 1)); 746eda14cbcSMatt Macy 747eda14cbcSMatt Macy /* 748eda14cbcSMatt Macy * Create handle for the parent dataset. 749eda14cbcSMatt Macy */ 750eda14cbcSMatt Macy errno = 0; 751eda14cbcSMatt Macy if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) { 752eda14cbcSMatt Macy (void) zfs_standard_error(hdl, errno, errbuf); 753eda14cbcSMatt Macy return (NULL); 754eda14cbcSMatt Macy } 755eda14cbcSMatt Macy 756eda14cbcSMatt Macy /* 757eda14cbcSMatt Macy * Iterate bookmarks to find the right one. 758eda14cbcSMatt Macy */ 759eda14cbcSMatt Macy errno = 0; 760*15f0b8c3SMartin Matuska if ((zfs_iter_bookmarks(pzhp, 0, zfs_open_bookmarks_cb, 761eda14cbcSMatt Macy &cb_data) == 0) && (cb_data.zhp == NULL)) { 762eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_NOENT, errbuf); 763eda14cbcSMatt Macy zfs_close(pzhp); 764*15f0b8c3SMartin Matuska errno = ENOENT; 765eda14cbcSMatt Macy return (NULL); 766eda14cbcSMatt Macy } 767eda14cbcSMatt Macy if (cb_data.zhp == NULL) { 768eda14cbcSMatt Macy (void) zfs_standard_error(hdl, errno, errbuf); 769eda14cbcSMatt Macy zfs_close(pzhp); 770eda14cbcSMatt Macy return (NULL); 771eda14cbcSMatt Macy } 772eda14cbcSMatt Macy zhp = cb_data.zhp; 773eda14cbcSMatt Macy 774eda14cbcSMatt Macy /* 775eda14cbcSMatt Macy * Cleanup. 776eda14cbcSMatt Macy */ 777eda14cbcSMatt Macy zfs_close(pzhp); 778eda14cbcSMatt Macy } 779eda14cbcSMatt Macy 780eda14cbcSMatt Macy if (!(types & zhp->zfs_type)) { 781eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 782eda14cbcSMatt Macy zfs_close(zhp); 783*15f0b8c3SMartin Matuska errno = EINVAL; 784eda14cbcSMatt Macy return (NULL); 785eda14cbcSMatt Macy } 786eda14cbcSMatt Macy 787eda14cbcSMatt Macy return (zhp); 788eda14cbcSMatt Macy } 789eda14cbcSMatt Macy 790eda14cbcSMatt Macy /* 791eda14cbcSMatt Macy * Release a ZFS handle. Nothing to do but free the associated memory. 792eda14cbcSMatt Macy */ 793eda14cbcSMatt Macy void 794eda14cbcSMatt Macy zfs_close(zfs_handle_t *zhp) 795eda14cbcSMatt Macy { 796eda14cbcSMatt Macy if (zhp->zfs_mntopts) 797eda14cbcSMatt Macy free(zhp->zfs_mntopts); 798eda14cbcSMatt Macy nvlist_free(zhp->zfs_props); 799eda14cbcSMatt Macy nvlist_free(zhp->zfs_user_props); 800eda14cbcSMatt Macy nvlist_free(zhp->zfs_recvd_props); 801eda14cbcSMatt Macy free(zhp); 802eda14cbcSMatt Macy } 803eda14cbcSMatt Macy 804eda14cbcSMatt Macy typedef struct mnttab_node { 805eda14cbcSMatt Macy struct mnttab mtn_mt; 806eda14cbcSMatt Macy avl_node_t mtn_node; 807eda14cbcSMatt Macy } mnttab_node_t; 808eda14cbcSMatt Macy 809eda14cbcSMatt Macy static int 810eda14cbcSMatt Macy libzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 811eda14cbcSMatt Macy { 812eda14cbcSMatt Macy const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1; 813eda14cbcSMatt Macy const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2; 814eda14cbcSMatt Macy int rv; 815eda14cbcSMatt Macy 816eda14cbcSMatt Macy rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 817eda14cbcSMatt Macy 818eda14cbcSMatt Macy return (TREE_ISIGN(rv)); 819eda14cbcSMatt Macy } 820eda14cbcSMatt Macy 821eda14cbcSMatt Macy void 822eda14cbcSMatt Macy libzfs_mnttab_init(libzfs_handle_t *hdl) 823eda14cbcSMatt Macy { 824eda14cbcSMatt Macy pthread_mutex_init(&hdl->libzfs_mnttab_cache_lock, NULL); 825eda14cbcSMatt Macy assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 826eda14cbcSMatt Macy avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 827eda14cbcSMatt Macy sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 828eda14cbcSMatt Macy } 829eda14cbcSMatt Macy 830eda14cbcSMatt Macy static int 831eda14cbcSMatt Macy libzfs_mnttab_update(libzfs_handle_t *hdl) 832eda14cbcSMatt Macy { 83316038816SMartin Matuska FILE *mnttab; 834eda14cbcSMatt Macy struct mnttab entry; 835eda14cbcSMatt Macy 83616038816SMartin Matuska if ((mnttab = fopen(MNTTAB, "re")) == NULL) 837eda14cbcSMatt Macy return (ENOENT); 838eda14cbcSMatt Macy 83916038816SMartin Matuska while (getmntent(mnttab, &entry) == 0) { 840eda14cbcSMatt Macy mnttab_node_t *mtn; 841eda14cbcSMatt Macy avl_index_t where; 842eda14cbcSMatt Macy 843eda14cbcSMatt Macy if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 844eda14cbcSMatt Macy continue; 845eda14cbcSMatt Macy 846eda14cbcSMatt Macy mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 847eda14cbcSMatt Macy mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 848eda14cbcSMatt Macy mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 849eda14cbcSMatt Macy mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 850eda14cbcSMatt Macy mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 851eda14cbcSMatt Macy 852eda14cbcSMatt Macy /* Exclude duplicate mounts */ 853eda14cbcSMatt Macy if (avl_find(&hdl->libzfs_mnttab_cache, mtn, &where) != NULL) { 854eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_special); 855eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_mountp); 856eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_fstype); 857eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_mntopts); 858eda14cbcSMatt Macy free(mtn); 859eda14cbcSMatt Macy continue; 860eda14cbcSMatt Macy } 861eda14cbcSMatt Macy 862eda14cbcSMatt Macy avl_add(&hdl->libzfs_mnttab_cache, mtn); 863eda14cbcSMatt Macy } 864eda14cbcSMatt Macy 86516038816SMartin Matuska (void) fclose(mnttab); 866eda14cbcSMatt Macy return (0); 867eda14cbcSMatt Macy } 868eda14cbcSMatt Macy 869eda14cbcSMatt Macy void 870eda14cbcSMatt Macy libzfs_mnttab_fini(libzfs_handle_t *hdl) 871eda14cbcSMatt Macy { 872eda14cbcSMatt Macy void *cookie = NULL; 873eda14cbcSMatt Macy mnttab_node_t *mtn; 874eda14cbcSMatt Macy 875eda14cbcSMatt Macy while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) 876eda14cbcSMatt Macy != NULL) { 877eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_special); 878eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_mountp); 879eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_fstype); 880eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_mntopts); 881eda14cbcSMatt Macy free(mtn); 882eda14cbcSMatt Macy } 883eda14cbcSMatt Macy avl_destroy(&hdl->libzfs_mnttab_cache); 884eda14cbcSMatt Macy (void) pthread_mutex_destroy(&hdl->libzfs_mnttab_cache_lock); 885eda14cbcSMatt Macy } 886eda14cbcSMatt Macy 887eda14cbcSMatt Macy void 888eda14cbcSMatt Macy libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 889eda14cbcSMatt Macy { 890eda14cbcSMatt Macy hdl->libzfs_mnttab_enable = enable; 891eda14cbcSMatt Macy } 892eda14cbcSMatt Macy 893eda14cbcSMatt Macy int 894eda14cbcSMatt Macy libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 895eda14cbcSMatt Macy struct mnttab *entry) 896eda14cbcSMatt Macy { 89716038816SMartin Matuska FILE *mnttab; 898eda14cbcSMatt Macy mnttab_node_t find; 899eda14cbcSMatt Macy mnttab_node_t *mtn; 900eda14cbcSMatt Macy int ret = ENOENT; 901eda14cbcSMatt Macy 902eda14cbcSMatt Macy if (!hdl->libzfs_mnttab_enable) { 903eda14cbcSMatt Macy struct mnttab srch = { 0 }; 904eda14cbcSMatt Macy 905eda14cbcSMatt Macy if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 906eda14cbcSMatt Macy libzfs_mnttab_fini(hdl); 907eda14cbcSMatt Macy 90816038816SMartin Matuska if ((mnttab = fopen(MNTTAB, "re")) == NULL) 909eda14cbcSMatt Macy return (ENOENT); 910eda14cbcSMatt Macy 911eda14cbcSMatt Macy srch.mnt_special = (char *)fsname; 912a0b956f5SMartin Matuska srch.mnt_fstype = (char *)MNTTYPE_ZFS; 91316038816SMartin Matuska ret = getmntany(mnttab, entry, &srch) ? ENOENT : 0; 91416038816SMartin Matuska (void) fclose(mnttab); 91516038816SMartin Matuska return (ret); 916eda14cbcSMatt Macy } 917eda14cbcSMatt Macy 918eda14cbcSMatt Macy pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock); 919eda14cbcSMatt Macy if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) { 920eda14cbcSMatt Macy int error; 921eda14cbcSMatt Macy 922eda14cbcSMatt Macy if ((error = libzfs_mnttab_update(hdl)) != 0) { 923eda14cbcSMatt Macy pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 924eda14cbcSMatt Macy return (error); 925eda14cbcSMatt Macy } 926eda14cbcSMatt Macy } 927eda14cbcSMatt Macy 928eda14cbcSMatt Macy find.mtn_mt.mnt_special = (char *)fsname; 929eda14cbcSMatt Macy mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 930eda14cbcSMatt Macy if (mtn) { 931eda14cbcSMatt Macy *entry = mtn->mtn_mt; 932eda14cbcSMatt Macy ret = 0; 933eda14cbcSMatt Macy } 934eda14cbcSMatt Macy pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 935eda14cbcSMatt Macy return (ret); 936eda14cbcSMatt Macy } 937eda14cbcSMatt Macy 938eda14cbcSMatt Macy void 939eda14cbcSMatt Macy libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 940eda14cbcSMatt Macy const char *mountp, const char *mntopts) 941eda14cbcSMatt Macy { 942eda14cbcSMatt Macy mnttab_node_t *mtn; 943eda14cbcSMatt Macy 944eda14cbcSMatt Macy pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock); 945eda14cbcSMatt Macy if (avl_numnodes(&hdl->libzfs_mnttab_cache) != 0) { 946eda14cbcSMatt Macy mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 947eda14cbcSMatt Macy mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 948eda14cbcSMatt Macy mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 949eda14cbcSMatt Macy mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 950eda14cbcSMatt Macy mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 951eda14cbcSMatt Macy /* 952eda14cbcSMatt Macy * Another thread may have already added this entry 953eda14cbcSMatt Macy * via libzfs_mnttab_update. If so we should skip it. 954eda14cbcSMatt Macy */ 955eda14cbcSMatt Macy if (avl_find(&hdl->libzfs_mnttab_cache, mtn, NULL) != NULL) { 956eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_special); 957eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_mountp); 958eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_fstype); 959eda14cbcSMatt Macy free(mtn->mtn_mt.mnt_mntopts); 960eda14cbcSMatt Macy free(mtn); 961eda14cbcSMatt Macy } else { 962eda14cbcSMatt Macy avl_add(&hdl->libzfs_mnttab_cache, mtn); 963eda14cbcSMatt Macy } 964eda14cbcSMatt Macy } 965eda14cbcSMatt Macy pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 966eda14cbcSMatt Macy } 967eda14cbcSMatt Macy 968eda14cbcSMatt Macy void 969eda14cbcSMatt Macy libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 970eda14cbcSMatt Macy { 971eda14cbcSMatt Macy mnttab_node_t find; 972eda14cbcSMatt Macy mnttab_node_t *ret; 973eda14cbcSMatt Macy 974eda14cbcSMatt Macy pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock); 975eda14cbcSMatt Macy find.mtn_mt.mnt_special = (char *)fsname; 976eda14cbcSMatt Macy if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) 977eda14cbcSMatt Macy != NULL) { 978eda14cbcSMatt Macy avl_remove(&hdl->libzfs_mnttab_cache, ret); 979eda14cbcSMatt Macy free(ret->mtn_mt.mnt_special); 980eda14cbcSMatt Macy free(ret->mtn_mt.mnt_mountp); 981eda14cbcSMatt Macy free(ret->mtn_mt.mnt_fstype); 982eda14cbcSMatt Macy free(ret->mtn_mt.mnt_mntopts); 983eda14cbcSMatt Macy free(ret); 984eda14cbcSMatt Macy } 985eda14cbcSMatt Macy pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 986eda14cbcSMatt Macy } 987eda14cbcSMatt Macy 988eda14cbcSMatt Macy int 989eda14cbcSMatt Macy zfs_spa_version(zfs_handle_t *zhp, int *spa_version) 990eda14cbcSMatt Macy { 991eda14cbcSMatt Macy zpool_handle_t *zpool_handle = zhp->zpool_hdl; 992eda14cbcSMatt Macy 993eda14cbcSMatt Macy if (zpool_handle == NULL) 994eda14cbcSMatt Macy return (-1); 995eda14cbcSMatt Macy 996eda14cbcSMatt Macy *spa_version = zpool_get_prop_int(zpool_handle, 997eda14cbcSMatt Macy ZPOOL_PROP_VERSION, NULL); 998eda14cbcSMatt Macy return (0); 999eda14cbcSMatt Macy } 1000eda14cbcSMatt Macy 1001eda14cbcSMatt Macy /* 1002eda14cbcSMatt Macy * The choice of reservation property depends on the SPA version. 1003eda14cbcSMatt Macy */ 1004eda14cbcSMatt Macy static int 1005eda14cbcSMatt Macy zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 1006eda14cbcSMatt Macy { 1007eda14cbcSMatt Macy int spa_version; 1008eda14cbcSMatt Macy 1009eda14cbcSMatt Macy if (zfs_spa_version(zhp, &spa_version) < 0) 1010eda14cbcSMatt Macy return (-1); 1011eda14cbcSMatt Macy 1012eda14cbcSMatt Macy if (spa_version >= SPA_VERSION_REFRESERVATION) 1013eda14cbcSMatt Macy *resv_prop = ZFS_PROP_REFRESERVATION; 1014eda14cbcSMatt Macy else 1015eda14cbcSMatt Macy *resv_prop = ZFS_PROP_RESERVATION; 1016eda14cbcSMatt Macy 1017eda14cbcSMatt Macy return (0); 1018eda14cbcSMatt Macy } 1019eda14cbcSMatt Macy 1020eda14cbcSMatt Macy /* 1021eda14cbcSMatt Macy * Given an nvlist of properties to set, validates that they are correct, and 1022eda14cbcSMatt Macy * parses any numeric properties (index, boolean, etc) if they are specified as 1023eda14cbcSMatt Macy * strings. 1024eda14cbcSMatt Macy */ 1025eda14cbcSMatt Macy nvlist_t * 1026eda14cbcSMatt Macy zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 1027eda14cbcSMatt Macy uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl, 1028eda14cbcSMatt Macy boolean_t key_params_ok, const char *errbuf) 1029eda14cbcSMatt Macy { 1030eda14cbcSMatt Macy nvpair_t *elem; 1031eda14cbcSMatt Macy uint64_t intval; 1032eda14cbcSMatt Macy char *strval; 1033eda14cbcSMatt Macy zfs_prop_t prop; 1034eda14cbcSMatt Macy nvlist_t *ret; 1035eda14cbcSMatt Macy int chosen_normal = -1; 1036eda14cbcSMatt Macy int chosen_utf = -1; 1037eda14cbcSMatt Macy 1038eda14cbcSMatt Macy if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 1039eda14cbcSMatt Macy (void) no_memory(hdl); 1040eda14cbcSMatt Macy return (NULL); 1041eda14cbcSMatt Macy } 1042eda14cbcSMatt Macy 1043eda14cbcSMatt Macy /* 1044eda14cbcSMatt Macy * Make sure this property is valid and applies to this type. 1045eda14cbcSMatt Macy */ 1046eda14cbcSMatt Macy 1047eda14cbcSMatt Macy elem = NULL; 1048eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1049eda14cbcSMatt Macy const char *propname = nvpair_name(elem); 1050eda14cbcSMatt Macy 1051eda14cbcSMatt Macy prop = zfs_name_to_prop(propname); 10521f1e2261SMartin Matuska if (prop == ZPROP_USERPROP && zfs_prop_user(propname)) { 1053eda14cbcSMatt Macy /* 1054eda14cbcSMatt Macy * This is a user property: make sure it's a 1055eda14cbcSMatt Macy * string, and that it's less than ZAP_MAXNAMELEN. 1056eda14cbcSMatt Macy */ 1057eda14cbcSMatt Macy if (nvpair_type(elem) != DATA_TYPE_STRING) { 1058eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1059eda14cbcSMatt Macy "'%s' must be a string"), propname); 1060eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1061eda14cbcSMatt Macy goto error; 1062eda14cbcSMatt Macy } 1063eda14cbcSMatt Macy 1064eda14cbcSMatt Macy if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 1065eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1066eda14cbcSMatt Macy "property name '%s' is too long"), 1067eda14cbcSMatt Macy propname); 1068eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1069eda14cbcSMatt Macy goto error; 1070eda14cbcSMatt Macy } 1071eda14cbcSMatt Macy 1072eda14cbcSMatt Macy (void) nvpair_value_string(elem, &strval); 1073eda14cbcSMatt Macy if (nvlist_add_string(ret, propname, strval) != 0) { 1074eda14cbcSMatt Macy (void) no_memory(hdl); 1075eda14cbcSMatt Macy goto error; 1076eda14cbcSMatt Macy } 1077eda14cbcSMatt Macy continue; 1078eda14cbcSMatt Macy } 1079eda14cbcSMatt Macy 1080eda14cbcSMatt Macy /* 1081eda14cbcSMatt Macy * Currently, only user properties can be modified on 1082eda14cbcSMatt Macy * snapshots. 1083eda14cbcSMatt Macy */ 1084eda14cbcSMatt Macy if (type == ZFS_TYPE_SNAPSHOT) { 1085eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1086eda14cbcSMatt Macy "this property can not be modified for snapshots")); 1087eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1088eda14cbcSMatt Macy goto error; 1089eda14cbcSMatt Macy } 1090eda14cbcSMatt Macy 10911f1e2261SMartin Matuska if (prop == ZPROP_USERPROP && zfs_prop_userquota(propname)) { 1092eda14cbcSMatt Macy zfs_userquota_prop_t uqtype; 1093eda14cbcSMatt Macy char *newpropname = NULL; 1094eda14cbcSMatt Macy char domain[128]; 1095eda14cbcSMatt Macy uint64_t rid; 1096eda14cbcSMatt Macy uint64_t valary[3]; 1097eda14cbcSMatt Macy int rc; 1098eda14cbcSMatt Macy 1099eda14cbcSMatt Macy if (userquota_propname_decode(propname, zoned, 1100eda14cbcSMatt Macy &uqtype, domain, sizeof (domain), &rid) != 0) { 1101eda14cbcSMatt Macy zfs_error_aux(hdl, 1102eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 1103eda14cbcSMatt Macy "'%s' has an invalid user/group name"), 1104eda14cbcSMatt Macy propname); 1105eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1106eda14cbcSMatt Macy goto error; 1107eda14cbcSMatt Macy } 1108eda14cbcSMatt Macy 1109eda14cbcSMatt Macy if (uqtype != ZFS_PROP_USERQUOTA && 1110eda14cbcSMatt Macy uqtype != ZFS_PROP_GROUPQUOTA && 1111eda14cbcSMatt Macy uqtype != ZFS_PROP_USEROBJQUOTA && 1112eda14cbcSMatt Macy uqtype != ZFS_PROP_GROUPOBJQUOTA && 1113eda14cbcSMatt Macy uqtype != ZFS_PROP_PROJECTQUOTA && 1114eda14cbcSMatt Macy uqtype != ZFS_PROP_PROJECTOBJQUOTA) { 1115eda14cbcSMatt Macy zfs_error_aux(hdl, 1116eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1117eda14cbcSMatt Macy propname); 1118eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_PROPREADONLY, 1119eda14cbcSMatt Macy errbuf); 1120eda14cbcSMatt Macy goto error; 1121eda14cbcSMatt Macy } 1122eda14cbcSMatt Macy 1123eda14cbcSMatt Macy if (nvpair_type(elem) == DATA_TYPE_STRING) { 1124eda14cbcSMatt Macy (void) nvpair_value_string(elem, &strval); 1125eda14cbcSMatt Macy if (strcmp(strval, "none") == 0) { 1126eda14cbcSMatt Macy intval = 0; 1127eda14cbcSMatt Macy } else if (zfs_nicestrtonum(hdl, 1128eda14cbcSMatt Macy strval, &intval) != 0) { 1129eda14cbcSMatt Macy (void) zfs_error(hdl, 1130eda14cbcSMatt Macy EZFS_BADPROP, errbuf); 1131eda14cbcSMatt Macy goto error; 1132eda14cbcSMatt Macy } 1133eda14cbcSMatt Macy } else if (nvpair_type(elem) == 1134eda14cbcSMatt Macy DATA_TYPE_UINT64) { 1135eda14cbcSMatt Macy (void) nvpair_value_uint64(elem, &intval); 1136eda14cbcSMatt Macy if (intval == 0) { 1137eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1138eda14cbcSMatt Macy "use 'none' to disable " 1139eda14cbcSMatt Macy "{user|group|project}quota")); 1140eda14cbcSMatt Macy goto error; 1141eda14cbcSMatt Macy } 1142eda14cbcSMatt Macy } else { 1143eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1144eda14cbcSMatt Macy "'%s' must be a number"), propname); 1145eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1146eda14cbcSMatt Macy goto error; 1147eda14cbcSMatt Macy } 1148eda14cbcSMatt Macy 1149eda14cbcSMatt Macy /* 1150eda14cbcSMatt Macy * Encode the prop name as 1151eda14cbcSMatt Macy * userquota@<hex-rid>-domain, to make it easy 1152eda14cbcSMatt Macy * for the kernel to decode. 1153eda14cbcSMatt Macy */ 1154eda14cbcSMatt Macy rc = asprintf(&newpropname, "%s%llx-%s", 1155eda14cbcSMatt Macy zfs_userquota_prop_prefixes[uqtype], 1156eda14cbcSMatt Macy (longlong_t)rid, domain); 1157eda14cbcSMatt Macy if (rc == -1 || newpropname == NULL) { 1158eda14cbcSMatt Macy (void) no_memory(hdl); 1159eda14cbcSMatt Macy goto error; 1160eda14cbcSMatt Macy } 1161eda14cbcSMatt Macy 1162eda14cbcSMatt Macy valary[0] = uqtype; 1163eda14cbcSMatt Macy valary[1] = rid; 1164eda14cbcSMatt Macy valary[2] = intval; 1165eda14cbcSMatt Macy if (nvlist_add_uint64_array(ret, newpropname, 1166eda14cbcSMatt Macy valary, 3) != 0) { 1167eda14cbcSMatt Macy free(newpropname); 1168eda14cbcSMatt Macy (void) no_memory(hdl); 1169eda14cbcSMatt Macy goto error; 1170eda14cbcSMatt Macy } 1171eda14cbcSMatt Macy free(newpropname); 1172eda14cbcSMatt Macy continue; 11731f1e2261SMartin Matuska } else if (prop == ZPROP_USERPROP && 11741f1e2261SMartin Matuska zfs_prop_written(propname)) { 1175eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1176eda14cbcSMatt Macy "'%s' is readonly"), 1177eda14cbcSMatt Macy propname); 1178eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1179eda14cbcSMatt Macy goto error; 1180eda14cbcSMatt Macy } 1181eda14cbcSMatt Macy 1182eda14cbcSMatt Macy if (prop == ZPROP_INVAL) { 1183eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1184eda14cbcSMatt Macy "invalid property '%s'"), propname); 1185eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1186eda14cbcSMatt Macy goto error; 1187eda14cbcSMatt Macy } 1188eda14cbcSMatt Macy 1189eda14cbcSMatt Macy if (!zfs_prop_valid_for_type(prop, type, B_FALSE)) { 1190eda14cbcSMatt Macy zfs_error_aux(hdl, 1191eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "'%s' does not " 1192eda14cbcSMatt Macy "apply to datasets of this type"), propname); 1193eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1194eda14cbcSMatt Macy goto error; 1195eda14cbcSMatt Macy } 1196eda14cbcSMatt Macy 1197eda14cbcSMatt Macy if (zfs_prop_readonly(prop) && 1198eda14cbcSMatt Macy !(zfs_prop_setonce(prop) && zhp == NULL) && 1199eda14cbcSMatt Macy !(zfs_prop_encryption_key_param(prop) && key_params_ok)) { 1200eda14cbcSMatt Macy zfs_error_aux(hdl, 1201eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1202eda14cbcSMatt Macy propname); 1203eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1204eda14cbcSMatt Macy goto error; 1205eda14cbcSMatt Macy } 1206eda14cbcSMatt Macy 1207eda14cbcSMatt Macy if (zprop_parse_value(hdl, elem, prop, type, ret, 1208eda14cbcSMatt Macy &strval, &intval, errbuf) != 0) 1209eda14cbcSMatt Macy goto error; 1210eda14cbcSMatt Macy 1211eda14cbcSMatt Macy /* 1212eda14cbcSMatt Macy * Perform some additional checks for specific properties. 1213eda14cbcSMatt Macy */ 1214eda14cbcSMatt Macy switch (prop) { 1215eda14cbcSMatt Macy case ZFS_PROP_VERSION: 1216eda14cbcSMatt Macy { 1217eda14cbcSMatt Macy int version; 1218eda14cbcSMatt Macy 1219eda14cbcSMatt Macy if (zhp == NULL) 1220eda14cbcSMatt Macy break; 1221eda14cbcSMatt Macy version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1222eda14cbcSMatt Macy if (intval < version) { 1223eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1224eda14cbcSMatt Macy "Can not downgrade; already at version %u"), 1225eda14cbcSMatt Macy version); 1226eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1227eda14cbcSMatt Macy goto error; 1228eda14cbcSMatt Macy } 1229eda14cbcSMatt Macy break; 1230eda14cbcSMatt Macy } 1231eda14cbcSMatt Macy 1232eda14cbcSMatt Macy case ZFS_PROP_VOLBLOCKSIZE: 1233eda14cbcSMatt Macy case ZFS_PROP_RECORDSIZE: 1234eda14cbcSMatt Macy { 1235eda14cbcSMatt Macy int maxbs = SPA_MAXBLOCKSIZE; 1236eda14cbcSMatt Macy char buf[64]; 1237eda14cbcSMatt Macy 1238eda14cbcSMatt Macy if (zpool_hdl != NULL) { 1239eda14cbcSMatt Macy maxbs = zpool_get_prop_int(zpool_hdl, 1240eda14cbcSMatt Macy ZPOOL_PROP_MAXBLOCKSIZE, NULL); 1241eda14cbcSMatt Macy } 1242eda14cbcSMatt Macy /* 1243eda14cbcSMatt Macy * The value must be a power of two between 1244eda14cbcSMatt Macy * SPA_MINBLOCKSIZE and maxbs. 1245eda14cbcSMatt Macy */ 1246eda14cbcSMatt Macy if (intval < SPA_MINBLOCKSIZE || 1247eda14cbcSMatt Macy intval > maxbs || !ISP2(intval)) { 1248eda14cbcSMatt Macy zfs_nicebytes(maxbs, buf, sizeof (buf)); 1249eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1250eda14cbcSMatt Macy "'%s' must be power of 2 from 512B " 1251eda14cbcSMatt Macy "to %s"), propname, buf); 1252eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1253eda14cbcSMatt Macy goto error; 1254eda14cbcSMatt Macy } 1255eda14cbcSMatt Macy break; 1256eda14cbcSMatt Macy } 1257eda14cbcSMatt Macy 1258eda14cbcSMatt Macy case ZFS_PROP_SPECIAL_SMALL_BLOCKS: 1259eda14cbcSMatt Macy { 1260eda14cbcSMatt Macy int maxbs = SPA_OLD_MAXBLOCKSIZE; 1261eda14cbcSMatt Macy char buf[64]; 1262eda14cbcSMatt Macy 1263eda14cbcSMatt Macy if (zpool_hdl != NULL) { 1264eda14cbcSMatt Macy char state[64] = ""; 1265eda14cbcSMatt Macy 1266eda14cbcSMatt Macy maxbs = zpool_get_prop_int(zpool_hdl, 1267eda14cbcSMatt Macy ZPOOL_PROP_MAXBLOCKSIZE, NULL); 1268eda14cbcSMatt Macy 1269eda14cbcSMatt Macy /* 1270eda14cbcSMatt Macy * Issue a warning but do not fail so that 1271eda14cbcSMatt Macy * tests for settable properties succeed. 1272eda14cbcSMatt Macy */ 1273eda14cbcSMatt Macy if (zpool_prop_get_feature(zpool_hdl, 1274eda14cbcSMatt Macy "feature@allocation_classes", state, 1275eda14cbcSMatt Macy sizeof (state)) != 0 || 1276eda14cbcSMatt Macy strcmp(state, ZFS_FEATURE_ACTIVE) != 0) { 1277eda14cbcSMatt Macy (void) fprintf(stderr, gettext( 1278eda14cbcSMatt Macy "%s: property requires a special " 1279eda14cbcSMatt Macy "device in the pool\n"), propname); 1280eda14cbcSMatt Macy } 1281eda14cbcSMatt Macy } 1282eda14cbcSMatt Macy if (intval != 0 && 1283eda14cbcSMatt Macy (intval < SPA_MINBLOCKSIZE || 1284eda14cbcSMatt Macy intval > maxbs || !ISP2(intval))) { 1285eda14cbcSMatt Macy zfs_nicebytes(maxbs, buf, sizeof (buf)); 1286eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 128716038816SMartin Matuska "invalid '%s=%llu' property: must be zero " 128816038816SMartin Matuska "or a power of 2 from 512B to %s"), 128916038816SMartin Matuska propname, (unsigned long long)intval, buf); 1290eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1291eda14cbcSMatt Macy goto error; 1292eda14cbcSMatt Macy } 1293eda14cbcSMatt Macy break; 1294eda14cbcSMatt Macy } 1295eda14cbcSMatt Macy 1296eda14cbcSMatt Macy case ZFS_PROP_MLSLABEL: 1297eda14cbcSMatt Macy { 1298eda14cbcSMatt Macy #ifdef HAVE_MLSLABEL 1299eda14cbcSMatt Macy /* 1300eda14cbcSMatt Macy * Verify the mlslabel string and convert to 1301eda14cbcSMatt Macy * internal hex label string. 1302eda14cbcSMatt Macy */ 1303eda14cbcSMatt Macy 1304eda14cbcSMatt Macy m_label_t *new_sl; 1305eda14cbcSMatt Macy char *hex = NULL; /* internal label string */ 1306eda14cbcSMatt Macy 1307eda14cbcSMatt Macy /* Default value is already OK. */ 1308eda14cbcSMatt Macy if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1309eda14cbcSMatt Macy break; 1310eda14cbcSMatt Macy 1311eda14cbcSMatt Macy /* Verify the label can be converted to binary form */ 1312eda14cbcSMatt Macy if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1313eda14cbcSMatt Macy (str_to_label(strval, &new_sl, MAC_LABEL, 1314eda14cbcSMatt Macy L_NO_CORRECTION, NULL) == -1)) { 1315eda14cbcSMatt Macy goto badlabel; 1316eda14cbcSMatt Macy } 1317eda14cbcSMatt Macy 1318eda14cbcSMatt Macy /* Now translate to hex internal label string */ 1319eda14cbcSMatt Macy if (label_to_str(new_sl, &hex, M_INTERNAL, 1320eda14cbcSMatt Macy DEF_NAMES) != 0) { 1321eda14cbcSMatt Macy if (hex) 1322eda14cbcSMatt Macy free(hex); 1323eda14cbcSMatt Macy goto badlabel; 1324eda14cbcSMatt Macy } 1325eda14cbcSMatt Macy m_label_free(new_sl); 1326eda14cbcSMatt Macy 1327eda14cbcSMatt Macy /* If string is already in internal form, we're done. */ 1328eda14cbcSMatt Macy if (strcmp(strval, hex) == 0) { 1329eda14cbcSMatt Macy free(hex); 1330eda14cbcSMatt Macy break; 1331eda14cbcSMatt Macy } 1332eda14cbcSMatt Macy 1333eda14cbcSMatt Macy /* Replace the label string with the internal form. */ 1334eda14cbcSMatt Macy (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1335eda14cbcSMatt Macy DATA_TYPE_STRING); 1336da5137abSMartin Matuska fnvlist_add_string(ret, zfs_prop_to_name(prop), hex); 1337eda14cbcSMatt Macy free(hex); 1338eda14cbcSMatt Macy 1339eda14cbcSMatt Macy break; 1340eda14cbcSMatt Macy 1341eda14cbcSMatt Macy badlabel: 1342eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1343eda14cbcSMatt Macy "invalid mlslabel '%s'"), strval); 1344eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1345eda14cbcSMatt Macy m_label_free(new_sl); /* OK if null */ 1346eda14cbcSMatt Macy goto error; 1347eda14cbcSMatt Macy #else 1348eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1349eda14cbcSMatt Macy "mlslabels are unsupported")); 1350eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1351eda14cbcSMatt Macy goto error; 1352eda14cbcSMatt Macy #endif /* HAVE_MLSLABEL */ 1353eda14cbcSMatt Macy } 1354eda14cbcSMatt Macy 1355eda14cbcSMatt Macy case ZFS_PROP_MOUNTPOINT: 1356eda14cbcSMatt Macy { 1357eda14cbcSMatt Macy namecheck_err_t why; 1358eda14cbcSMatt Macy 1359eda14cbcSMatt Macy if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1360eda14cbcSMatt Macy strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1361eda14cbcSMatt Macy break; 1362eda14cbcSMatt Macy 1363eda14cbcSMatt Macy if (mountpoint_namecheck(strval, &why)) { 1364eda14cbcSMatt Macy switch (why) { 1365eda14cbcSMatt Macy case NAME_ERR_LEADING_SLASH: 1366eda14cbcSMatt Macy zfs_error_aux(hdl, 1367eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 1368eda14cbcSMatt Macy "'%s' must be an absolute path, " 1369eda14cbcSMatt Macy "'none', or 'legacy'"), propname); 1370eda14cbcSMatt Macy break; 1371eda14cbcSMatt Macy case NAME_ERR_TOOLONG: 1372eda14cbcSMatt Macy zfs_error_aux(hdl, 1373eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 1374eda14cbcSMatt Macy "component of '%s' is too long"), 1375eda14cbcSMatt Macy propname); 1376eda14cbcSMatt Macy break; 1377eda14cbcSMatt Macy 1378eda14cbcSMatt Macy default: 1379eda14cbcSMatt Macy zfs_error_aux(hdl, 1380eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 1381eda14cbcSMatt Macy "(%d) not defined"), 1382eda14cbcSMatt Macy why); 1383eda14cbcSMatt Macy break; 1384eda14cbcSMatt Macy } 1385eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1386eda14cbcSMatt Macy goto error; 1387eda14cbcSMatt Macy } 1388c03c5b1cSMartin Matuska zfs_fallthrough; 1389eda14cbcSMatt Macy } 1390eda14cbcSMatt Macy 1391eda14cbcSMatt Macy case ZFS_PROP_SHARESMB: 1392eda14cbcSMatt Macy case ZFS_PROP_SHARENFS: 1393eda14cbcSMatt Macy /* 1394eda14cbcSMatt Macy * For the mountpoint and sharenfs or sharesmb 1395eda14cbcSMatt Macy * properties, check if it can be set in a 1396eda14cbcSMatt Macy * global/non-global zone based on 1397eda14cbcSMatt Macy * the zoned property value: 1398eda14cbcSMatt Macy * 1399eda14cbcSMatt Macy * global zone non-global zone 1400eda14cbcSMatt Macy * -------------------------------------------------- 1401eda14cbcSMatt Macy * zoned=on mountpoint (no) mountpoint (yes) 1402eda14cbcSMatt Macy * sharenfs (no) sharenfs (no) 1403eda14cbcSMatt Macy * sharesmb (no) sharesmb (no) 1404eda14cbcSMatt Macy * 1405eda14cbcSMatt Macy * zoned=off mountpoint (yes) N/A 1406eda14cbcSMatt Macy * sharenfs (yes) 1407eda14cbcSMatt Macy * sharesmb (yes) 1408eda14cbcSMatt Macy */ 1409eda14cbcSMatt Macy if (zoned) { 1410eda14cbcSMatt Macy if (getzoneid() == GLOBAL_ZONEID) { 1411eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1412eda14cbcSMatt Macy "'%s' cannot be set on " 1413eda14cbcSMatt Macy "dataset in a non-global zone"), 1414eda14cbcSMatt Macy propname); 1415eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_ZONED, 1416eda14cbcSMatt Macy errbuf); 1417eda14cbcSMatt Macy goto error; 1418eda14cbcSMatt Macy } else if (prop == ZFS_PROP_SHARENFS || 1419eda14cbcSMatt Macy prop == ZFS_PROP_SHARESMB) { 1420eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1421eda14cbcSMatt Macy "'%s' cannot be set in " 1422eda14cbcSMatt Macy "a non-global zone"), propname); 1423eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_ZONED, 1424eda14cbcSMatt Macy errbuf); 1425eda14cbcSMatt Macy goto error; 1426eda14cbcSMatt Macy } 1427eda14cbcSMatt Macy } else if (getzoneid() != GLOBAL_ZONEID) { 1428eda14cbcSMatt Macy /* 1429eda14cbcSMatt Macy * If zoned property is 'off', this must be in 1430eda14cbcSMatt Macy * a global zone. If not, something is wrong. 1431eda14cbcSMatt Macy */ 1432eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1433eda14cbcSMatt Macy "'%s' cannot be set while dataset " 1434eda14cbcSMatt Macy "'zoned' property is set"), propname); 1435eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1436eda14cbcSMatt Macy goto error; 1437eda14cbcSMatt Macy } 1438eda14cbcSMatt Macy 1439eda14cbcSMatt Macy /* 1440eda14cbcSMatt Macy * At this point, it is legitimate to set the 1441eda14cbcSMatt Macy * property. Now we want to make sure that the 1442eda14cbcSMatt Macy * property value is valid if it is sharenfs. 1443eda14cbcSMatt Macy */ 1444eda14cbcSMatt Macy if ((prop == ZFS_PROP_SHARENFS || 1445eda14cbcSMatt Macy prop == ZFS_PROP_SHARESMB) && 1446eda14cbcSMatt Macy strcmp(strval, "on") != 0 && 1447eda14cbcSMatt Macy strcmp(strval, "off") != 0) { 1448716fd348SMartin Matuska enum sa_protocol proto; 1449eda14cbcSMatt Macy 1450eda14cbcSMatt Macy if (prop == ZFS_PROP_SHARESMB) 1451716fd348SMartin Matuska proto = SA_PROTOCOL_SMB; 1452eda14cbcSMatt Macy else 1453716fd348SMartin Matuska proto = SA_PROTOCOL_NFS; 1454eda14cbcSMatt Macy 1455716fd348SMartin Matuska if (sa_validate_shareopts(strval, proto) != 1456716fd348SMartin Matuska SA_OK) { 1457eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1458eda14cbcSMatt Macy "'%s' cannot be set to invalid " 1459eda14cbcSMatt Macy "options"), propname); 1460eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, 1461eda14cbcSMatt Macy errbuf); 1462eda14cbcSMatt Macy goto error; 1463eda14cbcSMatt Macy } 1464eda14cbcSMatt Macy } 1465eda14cbcSMatt Macy 1466eda14cbcSMatt Macy break; 1467eda14cbcSMatt Macy 1468eda14cbcSMatt Macy case ZFS_PROP_KEYLOCATION: 1469eda14cbcSMatt Macy if (!zfs_prop_valid_keylocation(strval, B_FALSE)) { 1470eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1471eda14cbcSMatt Macy "invalid keylocation")); 1472eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1473eda14cbcSMatt Macy goto error; 1474eda14cbcSMatt Macy } 1475eda14cbcSMatt Macy 1476eda14cbcSMatt Macy if (zhp != NULL) { 1477eda14cbcSMatt Macy uint64_t crypt = 1478eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION); 1479eda14cbcSMatt Macy 1480eda14cbcSMatt Macy if (crypt == ZIO_CRYPT_OFF && 1481eda14cbcSMatt Macy strcmp(strval, "none") != 0) { 1482eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1483eda14cbcSMatt Macy "keylocation must be 'none' " 1484eda14cbcSMatt Macy "for unencrypted datasets")); 1485eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, 1486eda14cbcSMatt Macy errbuf); 1487eda14cbcSMatt Macy goto error; 1488eda14cbcSMatt Macy } else if (crypt != ZIO_CRYPT_OFF && 1489eda14cbcSMatt Macy strcmp(strval, "none") == 0) { 1490eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1491eda14cbcSMatt Macy "keylocation must not be 'none' " 1492eda14cbcSMatt Macy "for encrypted datasets")); 1493eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, 1494eda14cbcSMatt Macy errbuf); 1495eda14cbcSMatt Macy goto error; 1496eda14cbcSMatt Macy } 1497eda14cbcSMatt Macy } 1498eda14cbcSMatt Macy break; 1499eda14cbcSMatt Macy 1500eda14cbcSMatt Macy case ZFS_PROP_PBKDF2_ITERS: 1501eda14cbcSMatt Macy if (intval < MIN_PBKDF2_ITERATIONS) { 1502eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1503eda14cbcSMatt Macy "minimum pbkdf2 iterations is %u"), 1504eda14cbcSMatt Macy MIN_PBKDF2_ITERATIONS); 1505eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1506eda14cbcSMatt Macy goto error; 1507eda14cbcSMatt Macy } 1508eda14cbcSMatt Macy break; 1509eda14cbcSMatt Macy 1510eda14cbcSMatt Macy case ZFS_PROP_UTF8ONLY: 1511eda14cbcSMatt Macy chosen_utf = (int)intval; 1512eda14cbcSMatt Macy break; 1513eda14cbcSMatt Macy 1514eda14cbcSMatt Macy case ZFS_PROP_NORMALIZE: 1515eda14cbcSMatt Macy chosen_normal = (int)intval; 1516eda14cbcSMatt Macy break; 1517eda14cbcSMatt Macy 1518eda14cbcSMatt Macy default: 1519eda14cbcSMatt Macy break; 1520eda14cbcSMatt Macy } 1521eda14cbcSMatt Macy 1522eda14cbcSMatt Macy /* 1523eda14cbcSMatt Macy * For changes to existing volumes, we have some additional 1524eda14cbcSMatt Macy * checks to enforce. 1525eda14cbcSMatt Macy */ 1526eda14cbcSMatt Macy if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1527eda14cbcSMatt Macy uint64_t blocksize = zfs_prop_get_int(zhp, 1528eda14cbcSMatt Macy ZFS_PROP_VOLBLOCKSIZE); 1529eda14cbcSMatt Macy char buf[64]; 1530eda14cbcSMatt Macy 1531eda14cbcSMatt Macy switch (prop) { 1532eda14cbcSMatt Macy case ZFS_PROP_VOLSIZE: 1533eda14cbcSMatt Macy if (intval % blocksize != 0) { 1534eda14cbcSMatt Macy zfs_nicebytes(blocksize, buf, 1535eda14cbcSMatt Macy sizeof (buf)); 1536eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1537eda14cbcSMatt Macy "'%s' must be a multiple of " 1538eda14cbcSMatt Macy "volume block size (%s)"), 1539eda14cbcSMatt Macy propname, buf); 1540eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, 1541eda14cbcSMatt Macy errbuf); 1542eda14cbcSMatt Macy goto error; 1543eda14cbcSMatt Macy } 1544eda14cbcSMatt Macy 1545eda14cbcSMatt Macy if (intval == 0) { 1546eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1547eda14cbcSMatt Macy "'%s' cannot be zero"), 1548eda14cbcSMatt Macy propname); 1549eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, 1550eda14cbcSMatt Macy errbuf); 1551eda14cbcSMatt Macy goto error; 1552eda14cbcSMatt Macy } 1553eda14cbcSMatt Macy break; 1554eda14cbcSMatt Macy 1555eda14cbcSMatt Macy default: 1556eda14cbcSMatt Macy break; 1557eda14cbcSMatt Macy } 1558eda14cbcSMatt Macy } 1559eda14cbcSMatt Macy 1560eda14cbcSMatt Macy /* check encryption properties */ 1561eda14cbcSMatt Macy if (zhp != NULL) { 1562eda14cbcSMatt Macy int64_t crypt = zfs_prop_get_int(zhp, 1563eda14cbcSMatt Macy ZFS_PROP_ENCRYPTION); 1564eda14cbcSMatt Macy 1565eda14cbcSMatt Macy switch (prop) { 1566eda14cbcSMatt Macy case ZFS_PROP_COPIES: 1567eda14cbcSMatt Macy if (crypt != ZIO_CRYPT_OFF && intval > 2) { 1568eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1569eda14cbcSMatt Macy "encrypted datasets cannot have " 1570eda14cbcSMatt Macy "3 copies")); 1571eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, 1572eda14cbcSMatt Macy errbuf); 1573eda14cbcSMatt Macy goto error; 1574eda14cbcSMatt Macy } 1575eda14cbcSMatt Macy break; 1576eda14cbcSMatt Macy default: 1577eda14cbcSMatt Macy break; 1578eda14cbcSMatt Macy } 1579eda14cbcSMatt Macy } 1580eda14cbcSMatt Macy } 1581eda14cbcSMatt Macy 1582eda14cbcSMatt Macy /* 1583eda14cbcSMatt Macy * If normalization was chosen, but no UTF8 choice was made, 1584eda14cbcSMatt Macy * enforce rejection of non-UTF8 names. 1585eda14cbcSMatt Macy * 1586eda14cbcSMatt Macy * If normalization was chosen, but rejecting non-UTF8 names 1587eda14cbcSMatt Macy * was explicitly not chosen, it is an error. 158881b22a98SMartin Matuska * 158981b22a98SMartin Matuska * If utf8only was turned off, but the parent has normalization, 159081b22a98SMartin Matuska * turn off normalization. 1591eda14cbcSMatt Macy */ 1592eda14cbcSMatt Macy if (chosen_normal > 0 && chosen_utf < 0) { 1593eda14cbcSMatt Macy if (nvlist_add_uint64(ret, 1594eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1595eda14cbcSMatt Macy (void) no_memory(hdl); 1596eda14cbcSMatt Macy goto error; 1597eda14cbcSMatt Macy } 1598eda14cbcSMatt Macy } else if (chosen_normal > 0 && chosen_utf == 0) { 1599eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1600eda14cbcSMatt Macy "'%s' must be set 'on' if normalization chosen"), 1601eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1602eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1603eda14cbcSMatt Macy goto error; 160481b22a98SMartin Matuska } else if (chosen_normal < 0 && chosen_utf == 0) { 160581b22a98SMartin Matuska if (nvlist_add_uint64(ret, 160681b22a98SMartin Matuska zfs_prop_to_name(ZFS_PROP_NORMALIZE), 0) != 0) { 160781b22a98SMartin Matuska (void) no_memory(hdl); 160881b22a98SMartin Matuska goto error; 160981b22a98SMartin Matuska } 1610eda14cbcSMatt Macy } 1611eda14cbcSMatt Macy return (ret); 1612eda14cbcSMatt Macy 1613eda14cbcSMatt Macy error: 1614eda14cbcSMatt Macy nvlist_free(ret); 1615eda14cbcSMatt Macy return (NULL); 1616eda14cbcSMatt Macy } 1617eda14cbcSMatt Macy 1618eda14cbcSMatt Macy static int 1619eda14cbcSMatt Macy zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1620eda14cbcSMatt Macy { 1621eda14cbcSMatt Macy uint64_t old_volsize; 1622eda14cbcSMatt Macy uint64_t new_volsize; 1623eda14cbcSMatt Macy uint64_t old_reservation; 1624eda14cbcSMatt Macy uint64_t new_reservation; 1625eda14cbcSMatt Macy zfs_prop_t resv_prop; 1626eda14cbcSMatt Macy nvlist_t *props; 1627eda14cbcSMatt Macy zpool_handle_t *zph = zpool_handle(zhp); 1628eda14cbcSMatt Macy 1629eda14cbcSMatt Macy /* 1630eda14cbcSMatt Macy * If this is an existing volume, and someone is setting the volsize, 1631eda14cbcSMatt Macy * make sure that it matches the reservation, or add it if necessary. 1632eda14cbcSMatt Macy */ 1633eda14cbcSMatt Macy old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1634eda14cbcSMatt Macy if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1635eda14cbcSMatt Macy return (-1); 1636eda14cbcSMatt Macy old_reservation = zfs_prop_get_int(zhp, resv_prop); 1637eda14cbcSMatt Macy 1638eda14cbcSMatt Macy props = fnvlist_alloc(); 1639eda14cbcSMatt Macy fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1640eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1641eda14cbcSMatt Macy 1642eda14cbcSMatt Macy if ((zvol_volsize_to_reservation(zph, old_volsize, props) != 1643eda14cbcSMatt Macy old_reservation) || nvlist_exists(nvl, 1644eda14cbcSMatt Macy zfs_prop_to_name(resv_prop))) { 1645eda14cbcSMatt Macy fnvlist_free(props); 1646eda14cbcSMatt Macy return (0); 1647eda14cbcSMatt Macy } 1648eda14cbcSMatt Macy if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1649eda14cbcSMatt Macy &new_volsize) != 0) { 1650eda14cbcSMatt Macy fnvlist_free(props); 1651eda14cbcSMatt Macy return (-1); 1652eda14cbcSMatt Macy } 1653eda14cbcSMatt Macy new_reservation = zvol_volsize_to_reservation(zph, new_volsize, props); 1654eda14cbcSMatt Macy fnvlist_free(props); 1655eda14cbcSMatt Macy 1656eda14cbcSMatt Macy if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1657eda14cbcSMatt Macy new_reservation) != 0) { 1658eda14cbcSMatt Macy (void) no_memory(zhp->zfs_hdl); 1659eda14cbcSMatt Macy return (-1); 1660eda14cbcSMatt Macy } 1661eda14cbcSMatt Macy return (1); 1662eda14cbcSMatt Macy } 1663eda14cbcSMatt Macy 1664eda14cbcSMatt Macy /* 1665eda14cbcSMatt Macy * Helper for 'zfs {set|clone} refreservation=auto'. Must be called after 1666eda14cbcSMatt Macy * zfs_valid_proplist(), as it is what sets the UINT64_MAX sentinel value. 1667eda14cbcSMatt Macy * Return codes must match zfs_add_synthetic_resv(). 1668eda14cbcSMatt Macy */ 1669eda14cbcSMatt Macy static int 1670eda14cbcSMatt Macy zfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1671eda14cbcSMatt Macy { 1672eda14cbcSMatt Macy uint64_t volsize; 1673eda14cbcSMatt Macy uint64_t resvsize; 1674eda14cbcSMatt Macy zfs_prop_t prop; 1675eda14cbcSMatt Macy nvlist_t *props; 1676eda14cbcSMatt Macy 1677eda14cbcSMatt Macy if (!ZFS_IS_VOLUME(zhp)) { 1678eda14cbcSMatt Macy return (0); 1679eda14cbcSMatt Macy } 1680eda14cbcSMatt Macy 1681eda14cbcSMatt Macy if (zfs_which_resv_prop(zhp, &prop) != 0) { 1682eda14cbcSMatt Macy return (-1); 1683eda14cbcSMatt Macy } 1684eda14cbcSMatt Macy 1685eda14cbcSMatt Macy if (prop != ZFS_PROP_REFRESERVATION) { 1686eda14cbcSMatt Macy return (0); 1687eda14cbcSMatt Macy } 1688eda14cbcSMatt Macy 1689eda14cbcSMatt Macy if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(prop), &resvsize) != 0) { 1690eda14cbcSMatt Macy /* No value being set, so it can't be "auto" */ 1691eda14cbcSMatt Macy return (0); 1692eda14cbcSMatt Macy } 1693eda14cbcSMatt Macy if (resvsize != UINT64_MAX) { 1694eda14cbcSMatt Macy /* Being set to a value other than "auto" */ 1695eda14cbcSMatt Macy return (0); 1696eda14cbcSMatt Macy } 1697eda14cbcSMatt Macy 1698eda14cbcSMatt Macy props = fnvlist_alloc(); 1699eda14cbcSMatt Macy 1700eda14cbcSMatt Macy fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1701eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1702eda14cbcSMatt Macy 1703eda14cbcSMatt Macy if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1704eda14cbcSMatt Macy &volsize) != 0) { 1705eda14cbcSMatt Macy volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1706eda14cbcSMatt Macy } 1707eda14cbcSMatt Macy 1708eda14cbcSMatt Macy resvsize = zvol_volsize_to_reservation(zpool_handle(zhp), volsize, 1709eda14cbcSMatt Macy props); 1710eda14cbcSMatt Macy fnvlist_free(props); 1711eda14cbcSMatt Macy 1712eda14cbcSMatt Macy (void) nvlist_remove_all(nvl, zfs_prop_to_name(prop)); 1713eda14cbcSMatt Macy if (nvlist_add_uint64(nvl, zfs_prop_to_name(prop), resvsize) != 0) { 1714eda14cbcSMatt Macy (void) no_memory(zhp->zfs_hdl); 1715eda14cbcSMatt Macy return (-1); 1716eda14cbcSMatt Macy } 1717eda14cbcSMatt Macy return (1); 1718eda14cbcSMatt Macy } 1719eda14cbcSMatt Macy 1720eda14cbcSMatt Macy static boolean_t 1721eda14cbcSMatt Macy zfs_is_namespace_prop(zfs_prop_t prop) 1722eda14cbcSMatt Macy { 1723eda14cbcSMatt Macy switch (prop) { 1724eda14cbcSMatt Macy 1725eda14cbcSMatt Macy case ZFS_PROP_ATIME: 1726eda14cbcSMatt Macy case ZFS_PROP_RELATIME: 1727eda14cbcSMatt Macy case ZFS_PROP_DEVICES: 1728eda14cbcSMatt Macy case ZFS_PROP_EXEC: 1729eda14cbcSMatt Macy case ZFS_PROP_SETUID: 1730eda14cbcSMatt Macy case ZFS_PROP_READONLY: 1731eda14cbcSMatt Macy case ZFS_PROP_XATTR: 1732eda14cbcSMatt Macy case ZFS_PROP_NBMAND: 1733eda14cbcSMatt Macy return (B_TRUE); 1734eda14cbcSMatt Macy 1735eda14cbcSMatt Macy default: 1736eda14cbcSMatt Macy return (B_FALSE); 1737eda14cbcSMatt Macy } 1738eda14cbcSMatt Macy } 1739eda14cbcSMatt Macy 1740eda14cbcSMatt Macy /* 1741eda14cbcSMatt Macy * Given a property name and value, set the property for the given dataset. 1742eda14cbcSMatt Macy */ 1743eda14cbcSMatt Macy int 1744eda14cbcSMatt Macy zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1745eda14cbcSMatt Macy { 1746eda14cbcSMatt Macy int ret = -1; 17471f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 1748eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 1749eda14cbcSMatt Macy nvlist_t *nvl = NULL; 1750eda14cbcSMatt Macy 1751eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1752eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1753eda14cbcSMatt Macy zhp->zfs_name); 1754eda14cbcSMatt Macy 1755eda14cbcSMatt Macy if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1756eda14cbcSMatt Macy nvlist_add_string(nvl, propname, propval) != 0) { 1757eda14cbcSMatt Macy (void) no_memory(hdl); 1758eda14cbcSMatt Macy goto error; 1759eda14cbcSMatt Macy } 1760eda14cbcSMatt Macy 1761eda14cbcSMatt Macy ret = zfs_prop_set_list(zhp, nvl); 1762eda14cbcSMatt Macy 1763eda14cbcSMatt Macy error: 1764eda14cbcSMatt Macy nvlist_free(nvl); 1765eda14cbcSMatt Macy return (ret); 1766eda14cbcSMatt Macy } 1767eda14cbcSMatt Macy 1768eda14cbcSMatt Macy 1769eda14cbcSMatt Macy 1770eda14cbcSMatt Macy /* 1771eda14cbcSMatt Macy * Given an nvlist of property names and values, set the properties for the 1772eda14cbcSMatt Macy * given dataset. 1773eda14cbcSMatt Macy */ 1774eda14cbcSMatt Macy int 1775eda14cbcSMatt Macy zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props) 1776eda14cbcSMatt Macy { 1777eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 1778eda14cbcSMatt Macy int ret = -1; 1779eda14cbcSMatt Macy prop_changelist_t **cls = NULL; 1780eda14cbcSMatt Macy int cl_idx; 17811f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 1782eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 1783eda14cbcSMatt Macy nvlist_t *nvl; 1784eda14cbcSMatt Macy int nvl_len = 0; 1785eda14cbcSMatt Macy int added_resv = 0; 1786eda14cbcSMatt Macy zfs_prop_t prop = 0; 1787eda14cbcSMatt Macy nvpair_t *elem; 1788eda14cbcSMatt Macy 1789eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1790eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1791eda14cbcSMatt Macy zhp->zfs_name); 1792eda14cbcSMatt Macy 1793eda14cbcSMatt Macy if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props, 1794eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl, 1795eda14cbcSMatt Macy B_FALSE, errbuf)) == NULL) 1796eda14cbcSMatt Macy goto error; 1797eda14cbcSMatt Macy 1798eda14cbcSMatt Macy /* 1799eda14cbcSMatt Macy * We have to check for any extra properties which need to be added 1800eda14cbcSMatt Macy * before computing the length of the nvlist. 1801eda14cbcSMatt Macy */ 1802eda14cbcSMatt Macy for (elem = nvlist_next_nvpair(nvl, NULL); 1803eda14cbcSMatt Macy elem != NULL; 1804eda14cbcSMatt Macy elem = nvlist_next_nvpair(nvl, elem)) { 1805eda14cbcSMatt Macy if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE && 1806eda14cbcSMatt Macy (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) { 1807eda14cbcSMatt Macy goto error; 1808eda14cbcSMatt Macy } 1809eda14cbcSMatt Macy } 1810eda14cbcSMatt Macy 1811eda14cbcSMatt Macy if (added_resv != 1 && 1812eda14cbcSMatt Macy (added_resv = zfs_fix_auto_resv(zhp, nvl)) == -1) { 1813eda14cbcSMatt Macy goto error; 1814eda14cbcSMatt Macy } 1815eda14cbcSMatt Macy 1816eda14cbcSMatt Macy /* 1817eda14cbcSMatt Macy * Check how many properties we're setting and allocate an array to 1818eda14cbcSMatt Macy * store changelist pointers for postfix(). 1819eda14cbcSMatt Macy */ 1820eda14cbcSMatt Macy for (elem = nvlist_next_nvpair(nvl, NULL); 1821eda14cbcSMatt Macy elem != NULL; 1822eda14cbcSMatt Macy elem = nvlist_next_nvpair(nvl, elem)) 1823eda14cbcSMatt Macy nvl_len++; 1824eda14cbcSMatt Macy if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL) 1825eda14cbcSMatt Macy goto error; 1826eda14cbcSMatt Macy 1827eda14cbcSMatt Macy cl_idx = 0; 1828eda14cbcSMatt Macy for (elem = nvlist_next_nvpair(nvl, NULL); 1829eda14cbcSMatt Macy elem != NULL; 1830eda14cbcSMatt Macy elem = nvlist_next_nvpair(nvl, elem)) { 1831eda14cbcSMatt Macy 1832eda14cbcSMatt Macy prop = zfs_name_to_prop(nvpair_name(elem)); 1833eda14cbcSMatt Macy 1834eda14cbcSMatt Macy assert(cl_idx < nvl_len); 1835eda14cbcSMatt Macy /* 1836eda14cbcSMatt Macy * We don't want to unmount & remount the dataset when changing 1837eda14cbcSMatt Macy * its canmount property to 'on' or 'noauto'. We only use 1838eda14cbcSMatt Macy * the changelist logic to unmount when setting canmount=off. 1839eda14cbcSMatt Macy */ 1840eda14cbcSMatt Macy if (prop != ZFS_PROP_CANMOUNT || 1841eda14cbcSMatt Macy (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF && 1842eda14cbcSMatt Macy zfs_is_mounted(zhp, NULL))) { 1843eda14cbcSMatt Macy cls[cl_idx] = changelist_gather(zhp, prop, 0, 0); 1844eda14cbcSMatt Macy if (cls[cl_idx] == NULL) 1845eda14cbcSMatt Macy goto error; 1846eda14cbcSMatt Macy } 1847eda14cbcSMatt Macy 1848eda14cbcSMatt Macy if (prop == ZFS_PROP_MOUNTPOINT && 1849eda14cbcSMatt Macy changelist_haszonedchild(cls[cl_idx])) { 1850eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1851eda14cbcSMatt Macy "child dataset with inherited mountpoint is used " 1852eda14cbcSMatt Macy "in a non-global zone")); 1853eda14cbcSMatt Macy ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1854eda14cbcSMatt Macy goto error; 1855eda14cbcSMatt Macy } 1856eda14cbcSMatt Macy 1857eda14cbcSMatt Macy if (cls[cl_idx] != NULL && 1858eda14cbcSMatt Macy (ret = changelist_prefix(cls[cl_idx])) != 0) 1859eda14cbcSMatt Macy goto error; 1860eda14cbcSMatt Macy 1861eda14cbcSMatt Macy cl_idx++; 1862eda14cbcSMatt Macy } 1863eda14cbcSMatt Macy assert(cl_idx == nvl_len); 1864eda14cbcSMatt Macy 1865eda14cbcSMatt Macy /* 1866eda14cbcSMatt Macy * Execute the corresponding ioctl() to set this list of properties. 1867eda14cbcSMatt Macy */ 1868eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1869eda14cbcSMatt Macy 1870716fd348SMartin Matuska zcmd_write_src_nvlist(hdl, &zc, nvl); 1871716fd348SMartin Matuska zcmd_alloc_dst_nvlist(hdl, &zc, 0); 1872eda14cbcSMatt Macy 1873eda14cbcSMatt Macy ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1874eda14cbcSMatt Macy 1875eda14cbcSMatt Macy if (ret != 0) { 1876eda14cbcSMatt Macy if (zc.zc_nvlist_dst_filled == B_FALSE) { 1877eda14cbcSMatt Macy (void) zfs_standard_error(hdl, errno, errbuf); 1878eda14cbcSMatt Macy goto error; 1879eda14cbcSMatt Macy } 1880eda14cbcSMatt Macy 1881eda14cbcSMatt Macy /* Get the list of unset properties back and report them. */ 1882eda14cbcSMatt Macy nvlist_t *errorprops = NULL; 1883eda14cbcSMatt Macy if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0) 1884eda14cbcSMatt Macy goto error; 1885eda14cbcSMatt Macy for (nvpair_t *elem = nvlist_next_nvpair(errorprops, NULL); 1886eda14cbcSMatt Macy elem != NULL; 1887eda14cbcSMatt Macy elem = nvlist_next_nvpair(errorprops, elem)) { 1888eda14cbcSMatt Macy prop = zfs_name_to_prop(nvpair_name(elem)); 1889eda14cbcSMatt Macy zfs_setprop_error(hdl, prop, errno, errbuf); 1890eda14cbcSMatt Macy } 1891eda14cbcSMatt Macy nvlist_free(errorprops); 1892eda14cbcSMatt Macy 1893eda14cbcSMatt Macy if (added_resv && errno == ENOSPC) { 1894eda14cbcSMatt Macy /* clean up the volsize property we tried to set */ 1895eda14cbcSMatt Macy uint64_t old_volsize = zfs_prop_get_int(zhp, 1896eda14cbcSMatt Macy ZFS_PROP_VOLSIZE); 1897eda14cbcSMatt Macy nvlist_free(nvl); 1898eda14cbcSMatt Macy nvl = NULL; 1899eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 1900eda14cbcSMatt Macy 1901eda14cbcSMatt Macy if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1902eda14cbcSMatt Macy goto error; 1903eda14cbcSMatt Macy if (nvlist_add_uint64(nvl, 1904eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1905eda14cbcSMatt Macy old_volsize) != 0) 1906eda14cbcSMatt Macy goto error; 1907716fd348SMartin Matuska zcmd_write_src_nvlist(hdl, &zc, nvl); 1908eda14cbcSMatt Macy (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1909eda14cbcSMatt Macy } 1910eda14cbcSMatt Macy } else { 1911eda14cbcSMatt Macy for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1912eda14cbcSMatt Macy if (cls[cl_idx] != NULL) { 1913eda14cbcSMatt Macy int clp_err = changelist_postfix(cls[cl_idx]); 1914eda14cbcSMatt Macy if (clp_err != 0) 1915eda14cbcSMatt Macy ret = clp_err; 1916eda14cbcSMatt Macy } 1917eda14cbcSMatt Macy } 1918eda14cbcSMatt Macy 1919eda14cbcSMatt Macy if (ret == 0) { 1920eda14cbcSMatt Macy /* 1921eda14cbcSMatt Macy * Refresh the statistics so the new property 1922eda14cbcSMatt Macy * value is reflected. 1923eda14cbcSMatt Macy */ 1924eda14cbcSMatt Macy (void) get_stats(zhp); 1925eda14cbcSMatt Macy 1926eda14cbcSMatt Macy /* 1927eda14cbcSMatt Macy * Remount the filesystem to propagate the change 1928eda14cbcSMatt Macy * if one of the options handled by the generic 1929eda14cbcSMatt Macy * Linux namespace layer has been modified. 1930eda14cbcSMatt Macy */ 1931eda14cbcSMatt Macy if (zfs_is_namespace_prop(prop) && 1932eda14cbcSMatt Macy zfs_is_mounted(zhp, NULL)) 1933eda14cbcSMatt Macy ret = zfs_mount(zhp, MNTOPT_REMOUNT, 0); 1934eda14cbcSMatt Macy } 1935eda14cbcSMatt Macy } 1936eda14cbcSMatt Macy 1937eda14cbcSMatt Macy error: 1938eda14cbcSMatt Macy nvlist_free(nvl); 1939eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 1940eda14cbcSMatt Macy if (cls != NULL) { 1941eda14cbcSMatt Macy for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1942eda14cbcSMatt Macy if (cls[cl_idx] != NULL) 1943eda14cbcSMatt Macy changelist_free(cls[cl_idx]); 1944eda14cbcSMatt Macy } 1945eda14cbcSMatt Macy free(cls); 1946eda14cbcSMatt Macy } 1947eda14cbcSMatt Macy return (ret); 1948eda14cbcSMatt Macy } 1949eda14cbcSMatt Macy 1950eda14cbcSMatt Macy /* 1951eda14cbcSMatt Macy * Given a property, inherit the value from the parent dataset, or if received 1952eda14cbcSMatt Macy * is TRUE, revert to the received value, if any. 1953eda14cbcSMatt Macy */ 1954eda14cbcSMatt Macy int 1955eda14cbcSMatt Macy zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1956eda14cbcSMatt Macy { 1957eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 1958eda14cbcSMatt Macy int ret; 1959eda14cbcSMatt Macy prop_changelist_t *cl; 1960eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 19611f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 1962eda14cbcSMatt Macy zfs_prop_t prop; 1963eda14cbcSMatt Macy 1964eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1965eda14cbcSMatt Macy "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1966eda14cbcSMatt Macy 1967eda14cbcSMatt Macy zc.zc_cookie = received; 19681f1e2261SMartin Matuska if ((prop = zfs_name_to_prop(propname)) == ZPROP_USERPROP) { 1969eda14cbcSMatt Macy /* 1970eda14cbcSMatt Macy * For user properties, the amount of work we have to do is very 1971eda14cbcSMatt Macy * small, so just do it here. 1972eda14cbcSMatt Macy */ 1973eda14cbcSMatt Macy if (!zfs_prop_user(propname)) { 1974eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1975eda14cbcSMatt Macy "invalid property")); 1976eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1977eda14cbcSMatt Macy } 1978eda14cbcSMatt Macy 1979eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1980eda14cbcSMatt Macy (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1981eda14cbcSMatt Macy 1982eda14cbcSMatt Macy if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1983eda14cbcSMatt Macy return (zfs_standard_error(hdl, errno, errbuf)); 1984eda14cbcSMatt Macy 198516038816SMartin Matuska (void) get_stats(zhp); 1986eda14cbcSMatt Macy return (0); 1987eda14cbcSMatt Macy } 1988eda14cbcSMatt Macy 1989eda14cbcSMatt Macy /* 1990eda14cbcSMatt Macy * Verify that this property is inheritable. 1991eda14cbcSMatt Macy */ 1992eda14cbcSMatt Macy if (zfs_prop_readonly(prop)) 1993eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1994eda14cbcSMatt Macy 1995eda14cbcSMatt Macy if (!zfs_prop_inheritable(prop) && !received) 1996eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1997eda14cbcSMatt Macy 1998eda14cbcSMatt Macy /* 1999eda14cbcSMatt Macy * Check to see if the value applies to this type 2000eda14cbcSMatt Macy */ 2001eda14cbcSMatt Macy if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) 2002eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 2003eda14cbcSMatt Macy 2004eda14cbcSMatt Macy /* 2005eda14cbcSMatt Macy * Normalize the name, to get rid of shorthand abbreviations. 2006eda14cbcSMatt Macy */ 2007eda14cbcSMatt Macy propname = zfs_prop_to_name(prop); 2008eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2009eda14cbcSMatt Macy (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 2010eda14cbcSMatt Macy 2011eda14cbcSMatt Macy if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 2012eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 2013eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2014eda14cbcSMatt Macy "dataset is used in a non-global zone")); 2015eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_ZONED, errbuf)); 2016eda14cbcSMatt Macy } 2017eda14cbcSMatt Macy 2018eda14cbcSMatt Macy /* 2019eda14cbcSMatt Macy * Determine datasets which will be affected by this change, if any. 2020eda14cbcSMatt Macy */ 2021eda14cbcSMatt Macy if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 2022eda14cbcSMatt Macy return (-1); 2023eda14cbcSMatt Macy 2024eda14cbcSMatt Macy if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 2025eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2026eda14cbcSMatt Macy "child dataset with inherited mountpoint is used " 2027eda14cbcSMatt Macy "in a non-global zone")); 2028eda14cbcSMatt Macy ret = zfs_error(hdl, EZFS_ZONED, errbuf); 2029eda14cbcSMatt Macy goto error; 2030eda14cbcSMatt Macy } 2031eda14cbcSMatt Macy 2032eda14cbcSMatt Macy if ((ret = changelist_prefix(cl)) != 0) 2033eda14cbcSMatt Macy goto error; 2034eda14cbcSMatt Macy 2035dbd5678dSMartin Matuska if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) { 2036be181ee2SMartin Matuska changelist_free(cl); 2037eda14cbcSMatt Macy return (zfs_standard_error(hdl, errno, errbuf)); 2038eda14cbcSMatt Macy } else { 2039eda14cbcSMatt Macy 2040eda14cbcSMatt Macy if ((ret = changelist_postfix(cl)) != 0) 2041eda14cbcSMatt Macy goto error; 2042eda14cbcSMatt Macy 2043eda14cbcSMatt Macy /* 2044eda14cbcSMatt Macy * Refresh the statistics so the new property is reflected. 2045eda14cbcSMatt Macy */ 2046eda14cbcSMatt Macy (void) get_stats(zhp); 2047eda14cbcSMatt Macy 2048eda14cbcSMatt Macy /* 2049eda14cbcSMatt Macy * Remount the filesystem to propagate the change 2050eda14cbcSMatt Macy * if one of the options handled by the generic 2051eda14cbcSMatt Macy * Linux namespace layer has been modified. 2052eda14cbcSMatt Macy */ 2053eda14cbcSMatt Macy if (zfs_is_namespace_prop(prop) && 2054eda14cbcSMatt Macy zfs_is_mounted(zhp, NULL)) 2055eda14cbcSMatt Macy ret = zfs_mount(zhp, MNTOPT_REMOUNT, 0); 2056eda14cbcSMatt Macy } 2057eda14cbcSMatt Macy 2058eda14cbcSMatt Macy error: 2059eda14cbcSMatt Macy changelist_free(cl); 2060eda14cbcSMatt Macy return (ret); 2061eda14cbcSMatt Macy } 2062eda14cbcSMatt Macy 2063eda14cbcSMatt Macy /* 2064eda14cbcSMatt Macy * True DSL properties are stored in an nvlist. The following two functions 2065eda14cbcSMatt Macy * extract them appropriately. 2066eda14cbcSMatt Macy */ 2067eda14cbcSMatt Macy uint64_t 2068eda14cbcSMatt Macy getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 2069eda14cbcSMatt Macy { 2070eda14cbcSMatt Macy nvlist_t *nv; 2071eda14cbcSMatt Macy uint64_t value; 2072eda14cbcSMatt Macy 2073eda14cbcSMatt Macy *source = NULL; 2074eda14cbcSMatt Macy if (nvlist_lookup_nvlist(zhp->zfs_props, 2075eda14cbcSMatt Macy zfs_prop_to_name(prop), &nv) == 0) { 2076da5137abSMartin Matuska value = fnvlist_lookup_uint64(nv, ZPROP_VALUE); 2077eda14cbcSMatt Macy (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 2078eda14cbcSMatt Macy } else { 2079eda14cbcSMatt Macy verify(!zhp->zfs_props_table || 2080eda14cbcSMatt Macy zhp->zfs_props_table[prop] == B_TRUE); 2081eda14cbcSMatt Macy value = zfs_prop_default_numeric(prop); 2082a0b956f5SMartin Matuska *source = (char *)""; 2083eda14cbcSMatt Macy } 2084eda14cbcSMatt Macy 2085eda14cbcSMatt Macy return (value); 2086eda14cbcSMatt Macy } 2087eda14cbcSMatt Macy 2088eda14cbcSMatt Macy static const char * 2089eda14cbcSMatt Macy getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 2090eda14cbcSMatt Macy { 2091eda14cbcSMatt Macy nvlist_t *nv; 2092eda14cbcSMatt Macy const char *value; 2093eda14cbcSMatt Macy 2094eda14cbcSMatt Macy *source = NULL; 2095eda14cbcSMatt Macy if (nvlist_lookup_nvlist(zhp->zfs_props, 2096eda14cbcSMatt Macy zfs_prop_to_name(prop), &nv) == 0) { 2097eda14cbcSMatt Macy value = fnvlist_lookup_string(nv, ZPROP_VALUE); 2098eda14cbcSMatt Macy (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 2099eda14cbcSMatt Macy } else { 2100eda14cbcSMatt Macy verify(!zhp->zfs_props_table || 2101eda14cbcSMatt Macy zhp->zfs_props_table[prop] == B_TRUE); 2102eda14cbcSMatt Macy value = zfs_prop_default_string(prop); 2103a0b956f5SMartin Matuska *source = (char *)""; 2104eda14cbcSMatt Macy } 2105eda14cbcSMatt Macy 2106eda14cbcSMatt Macy return (value); 2107eda14cbcSMatt Macy } 2108eda14cbcSMatt Macy 2109eda14cbcSMatt Macy static boolean_t 2110eda14cbcSMatt Macy zfs_is_recvd_props_mode(zfs_handle_t *zhp) 2111eda14cbcSMatt Macy { 2112*15f0b8c3SMartin Matuska return (zhp->zfs_props != NULL && 2113*15f0b8c3SMartin Matuska zhp->zfs_props == zhp->zfs_recvd_props); 2114eda14cbcSMatt Macy } 2115eda14cbcSMatt Macy 2116eda14cbcSMatt Macy static void 2117dbd5678dSMartin Matuska zfs_set_recvd_props_mode(zfs_handle_t *zhp, uintptr_t *cookie) 2118eda14cbcSMatt Macy { 2119dbd5678dSMartin Matuska *cookie = (uintptr_t)zhp->zfs_props; 2120eda14cbcSMatt Macy zhp->zfs_props = zhp->zfs_recvd_props; 2121eda14cbcSMatt Macy } 2122eda14cbcSMatt Macy 2123eda14cbcSMatt Macy static void 2124dbd5678dSMartin Matuska zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uintptr_t *cookie) 2125eda14cbcSMatt Macy { 2126dbd5678dSMartin Matuska zhp->zfs_props = (nvlist_t *)*cookie; 2127eda14cbcSMatt Macy *cookie = 0; 2128eda14cbcSMatt Macy } 2129eda14cbcSMatt Macy 2130eda14cbcSMatt Macy /* 2131eda14cbcSMatt Macy * Internal function for getting a numeric property. Both zfs_prop_get() and 2132eda14cbcSMatt Macy * zfs_prop_get_int() are built using this interface. 2133eda14cbcSMatt Macy * 2134eda14cbcSMatt Macy * Certain properties can be overridden using 'mount -o'. In this case, scan 2135eda14cbcSMatt Macy * the contents of the /proc/self/mounts entry, searching for the 2136eda14cbcSMatt Macy * appropriate options. If they differ from the on-disk values, report the 2137eda14cbcSMatt Macy * current values and mark the source "temporary". 2138eda14cbcSMatt Macy */ 2139eda14cbcSMatt Macy static int 2140eda14cbcSMatt Macy get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 2141eda14cbcSMatt Macy char **source, uint64_t *val) 2142eda14cbcSMatt Macy { 2143eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 2144eda14cbcSMatt Macy nvlist_t *zplprops = NULL; 2145eda14cbcSMatt Macy struct mnttab mnt; 2146a0b956f5SMartin Matuska const char *mntopt_on = NULL; 2147a0b956f5SMartin Matuska const char *mntopt_off = NULL; 2148eda14cbcSMatt Macy boolean_t received = zfs_is_recvd_props_mode(zhp); 2149eda14cbcSMatt Macy 2150eda14cbcSMatt Macy *source = NULL; 2151eda14cbcSMatt Macy 2152eda14cbcSMatt Macy /* 2153eda14cbcSMatt Macy * If the property is being fetched for a snapshot, check whether 2154eda14cbcSMatt Macy * the property is valid for the snapshot's head dataset type. 2155eda14cbcSMatt Macy */ 2156eda14cbcSMatt Macy if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT && 2157eda14cbcSMatt Macy !zfs_prop_valid_for_type(prop, zhp->zfs_head_type, B_TRUE)) { 2158eda14cbcSMatt Macy *val = zfs_prop_default_numeric(prop); 2159eda14cbcSMatt Macy return (-1); 2160eda14cbcSMatt Macy } 2161eda14cbcSMatt Macy 2162eda14cbcSMatt Macy switch (prop) { 2163eda14cbcSMatt Macy case ZFS_PROP_ATIME: 2164eda14cbcSMatt Macy mntopt_on = MNTOPT_ATIME; 2165eda14cbcSMatt Macy mntopt_off = MNTOPT_NOATIME; 2166eda14cbcSMatt Macy break; 2167eda14cbcSMatt Macy 2168eda14cbcSMatt Macy case ZFS_PROP_RELATIME: 2169eda14cbcSMatt Macy mntopt_on = MNTOPT_RELATIME; 2170eda14cbcSMatt Macy mntopt_off = MNTOPT_NORELATIME; 2171eda14cbcSMatt Macy break; 2172eda14cbcSMatt Macy 2173eda14cbcSMatt Macy case ZFS_PROP_DEVICES: 2174eda14cbcSMatt Macy mntopt_on = MNTOPT_DEVICES; 2175eda14cbcSMatt Macy mntopt_off = MNTOPT_NODEVICES; 2176eda14cbcSMatt Macy break; 2177eda14cbcSMatt Macy 2178eda14cbcSMatt Macy case ZFS_PROP_EXEC: 2179eda14cbcSMatt Macy mntopt_on = MNTOPT_EXEC; 2180eda14cbcSMatt Macy mntopt_off = MNTOPT_NOEXEC; 2181eda14cbcSMatt Macy break; 2182eda14cbcSMatt Macy 2183eda14cbcSMatt Macy case ZFS_PROP_READONLY: 2184eda14cbcSMatt Macy mntopt_on = MNTOPT_RO; 2185eda14cbcSMatt Macy mntopt_off = MNTOPT_RW; 2186eda14cbcSMatt Macy break; 2187eda14cbcSMatt Macy 2188eda14cbcSMatt Macy case ZFS_PROP_SETUID: 2189eda14cbcSMatt Macy mntopt_on = MNTOPT_SETUID; 2190eda14cbcSMatt Macy mntopt_off = MNTOPT_NOSETUID; 2191eda14cbcSMatt Macy break; 2192eda14cbcSMatt Macy 2193eda14cbcSMatt Macy case ZFS_PROP_XATTR: 2194eda14cbcSMatt Macy mntopt_on = MNTOPT_XATTR; 2195eda14cbcSMatt Macy mntopt_off = MNTOPT_NOXATTR; 2196eda14cbcSMatt Macy break; 2197eda14cbcSMatt Macy 2198eda14cbcSMatt Macy case ZFS_PROP_NBMAND: 2199eda14cbcSMatt Macy mntopt_on = MNTOPT_NBMAND; 2200eda14cbcSMatt Macy mntopt_off = MNTOPT_NONBMAND; 2201eda14cbcSMatt Macy break; 2202eda14cbcSMatt Macy 2203eda14cbcSMatt Macy default: 2204eda14cbcSMatt Macy break; 2205eda14cbcSMatt Macy } 2206eda14cbcSMatt Macy 2207eda14cbcSMatt Macy /* 2208eda14cbcSMatt Macy * Because looking up the mount options is potentially expensive 2209eda14cbcSMatt Macy * (iterating over all of /proc/self/mounts), we defer its 2210eda14cbcSMatt Macy * calculation until we're looking up a property which requires 2211eda14cbcSMatt Macy * its presence. 2212eda14cbcSMatt Macy */ 2213eda14cbcSMatt Macy if (!zhp->zfs_mntcheck && 2214eda14cbcSMatt Macy (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 2215eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 2216eda14cbcSMatt Macy struct mnttab entry; 2217eda14cbcSMatt Macy 2218716fd348SMartin Matuska if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) 2219eda14cbcSMatt Macy zhp->zfs_mntopts = zfs_strdup(hdl, 2220eda14cbcSMatt Macy entry.mnt_mntopts); 2221eda14cbcSMatt Macy 2222eda14cbcSMatt Macy zhp->zfs_mntcheck = B_TRUE; 2223eda14cbcSMatt Macy } 2224eda14cbcSMatt Macy 2225eda14cbcSMatt Macy if (zhp->zfs_mntopts == NULL) 2226a0b956f5SMartin Matuska mnt.mnt_mntopts = (char *)""; 2227eda14cbcSMatt Macy else 2228eda14cbcSMatt Macy mnt.mnt_mntopts = zhp->zfs_mntopts; 2229eda14cbcSMatt Macy 2230eda14cbcSMatt Macy switch (prop) { 2231eda14cbcSMatt Macy case ZFS_PROP_ATIME: 2232eda14cbcSMatt Macy case ZFS_PROP_RELATIME: 2233eda14cbcSMatt Macy case ZFS_PROP_DEVICES: 2234eda14cbcSMatt Macy case ZFS_PROP_EXEC: 2235eda14cbcSMatt Macy case ZFS_PROP_READONLY: 2236eda14cbcSMatt Macy case ZFS_PROP_SETUID: 2237eda14cbcSMatt Macy #ifndef __FreeBSD__ 2238eda14cbcSMatt Macy case ZFS_PROP_XATTR: 2239eda14cbcSMatt Macy #endif 2240eda14cbcSMatt Macy case ZFS_PROP_NBMAND: 2241eda14cbcSMatt Macy *val = getprop_uint64(zhp, prop, source); 2242eda14cbcSMatt Macy 2243eda14cbcSMatt Macy if (received) 2244eda14cbcSMatt Macy break; 2245eda14cbcSMatt Macy 2246eda14cbcSMatt Macy if (hasmntopt(&mnt, mntopt_on) && !*val) { 2247eda14cbcSMatt Macy *val = B_TRUE; 2248eda14cbcSMatt Macy if (src) 2249eda14cbcSMatt Macy *src = ZPROP_SRC_TEMPORARY; 2250eda14cbcSMatt Macy } else if (hasmntopt(&mnt, mntopt_off) && *val) { 2251eda14cbcSMatt Macy *val = B_FALSE; 2252eda14cbcSMatt Macy if (src) 2253eda14cbcSMatt Macy *src = ZPROP_SRC_TEMPORARY; 2254eda14cbcSMatt Macy } 2255eda14cbcSMatt Macy break; 2256eda14cbcSMatt Macy 2257eda14cbcSMatt Macy case ZFS_PROP_CANMOUNT: 2258eda14cbcSMatt Macy case ZFS_PROP_VOLSIZE: 2259eda14cbcSMatt Macy case ZFS_PROP_QUOTA: 2260eda14cbcSMatt Macy case ZFS_PROP_REFQUOTA: 2261eda14cbcSMatt Macy case ZFS_PROP_RESERVATION: 2262eda14cbcSMatt Macy case ZFS_PROP_REFRESERVATION: 2263eda14cbcSMatt Macy case ZFS_PROP_FILESYSTEM_LIMIT: 2264eda14cbcSMatt Macy case ZFS_PROP_SNAPSHOT_LIMIT: 2265eda14cbcSMatt Macy case ZFS_PROP_FILESYSTEM_COUNT: 2266eda14cbcSMatt Macy case ZFS_PROP_SNAPSHOT_COUNT: 2267eda14cbcSMatt Macy *val = getprop_uint64(zhp, prop, source); 2268eda14cbcSMatt Macy 2269eda14cbcSMatt Macy if (*source == NULL) { 2270eda14cbcSMatt Macy /* not default, must be local */ 2271eda14cbcSMatt Macy *source = zhp->zfs_name; 2272eda14cbcSMatt Macy } 2273eda14cbcSMatt Macy break; 2274eda14cbcSMatt Macy 2275eda14cbcSMatt Macy case ZFS_PROP_MOUNTED: 2276eda14cbcSMatt Macy *val = (zhp->zfs_mntopts != NULL); 2277eda14cbcSMatt Macy break; 2278eda14cbcSMatt Macy 2279eda14cbcSMatt Macy case ZFS_PROP_NUMCLONES: 2280eda14cbcSMatt Macy *val = zhp->zfs_dmustats.dds_num_clones; 2281eda14cbcSMatt Macy break; 2282eda14cbcSMatt Macy 2283eda14cbcSMatt Macy case ZFS_PROP_VERSION: 2284eda14cbcSMatt Macy case ZFS_PROP_NORMALIZE: 2285eda14cbcSMatt Macy case ZFS_PROP_UTF8ONLY: 2286eda14cbcSMatt Macy case ZFS_PROP_CASE: 2287716fd348SMartin Matuska zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0); 2288716fd348SMartin Matuska 2289eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2290eda14cbcSMatt Macy if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 2291eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 2292eda14cbcSMatt Macy if (prop == ZFS_PROP_VERSION && 2293eda14cbcSMatt Macy zhp->zfs_type == ZFS_TYPE_VOLUME) 2294eda14cbcSMatt Macy *val = zfs_prop_default_numeric(prop); 2295eda14cbcSMatt Macy return (-1); 2296eda14cbcSMatt Macy } 2297eda14cbcSMatt Macy if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 2298eda14cbcSMatt Macy nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 2299eda14cbcSMatt Macy val) != 0) { 2300eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 2301eda14cbcSMatt Macy return (-1); 2302eda14cbcSMatt Macy } 2303eda14cbcSMatt Macy nvlist_free(zplprops); 2304eda14cbcSMatt Macy zcmd_free_nvlists(&zc); 2305eda14cbcSMatt Macy break; 2306eda14cbcSMatt Macy 2307eda14cbcSMatt Macy case ZFS_PROP_INCONSISTENT: 2308eda14cbcSMatt Macy *val = zhp->zfs_dmustats.dds_inconsistent; 2309eda14cbcSMatt Macy break; 2310eda14cbcSMatt Macy 2311eda14cbcSMatt Macy case ZFS_PROP_REDACTED: 2312eda14cbcSMatt Macy *val = zhp->zfs_dmustats.dds_redacted; 2313eda14cbcSMatt Macy break; 2314eda14cbcSMatt Macy 2315*15f0b8c3SMartin Matuska case ZFS_PROP_GUID: 2316*15f0b8c3SMartin Matuska if (zhp->zfs_dmustats.dds_guid != 0) 2317*15f0b8c3SMartin Matuska *val = zhp->zfs_dmustats.dds_guid; 2318*15f0b8c3SMartin Matuska else 2319*15f0b8c3SMartin Matuska *val = getprop_uint64(zhp, prop, source); 2320*15f0b8c3SMartin Matuska break; 2321*15f0b8c3SMartin Matuska 2322271171e0SMartin Matuska case ZFS_PROP_CREATETXG: 2323271171e0SMartin Matuska /* 2324271171e0SMartin Matuska * We can directly read createtxg property from zfs 2325271171e0SMartin Matuska * handle for Filesystem, Snapshot and ZVOL types. 2326271171e0SMartin Matuska */ 2327*15f0b8c3SMartin Matuska if (((zhp->zfs_type == ZFS_TYPE_FILESYSTEM) || 2328271171e0SMartin Matuska (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) || 2329*15f0b8c3SMartin Matuska (zhp->zfs_type == ZFS_TYPE_VOLUME)) && 2330*15f0b8c3SMartin Matuska (zhp->zfs_dmustats.dds_creation_txg != 0)) { 2331271171e0SMartin Matuska *val = zhp->zfs_dmustats.dds_creation_txg; 2332271171e0SMartin Matuska break; 2333*15f0b8c3SMartin Matuska } else { 2334*15f0b8c3SMartin Matuska *val = getprop_uint64(zhp, prop, source); 2335271171e0SMartin Matuska } 2336271171e0SMartin Matuska zfs_fallthrough; 2337eda14cbcSMatt Macy default: 2338eda14cbcSMatt Macy switch (zfs_prop_get_type(prop)) { 2339eda14cbcSMatt Macy case PROP_TYPE_NUMBER: 2340eda14cbcSMatt Macy case PROP_TYPE_INDEX: 2341eda14cbcSMatt Macy *val = getprop_uint64(zhp, prop, source); 2342eda14cbcSMatt Macy /* 2343eda14cbcSMatt Macy * If we tried to use a default value for a 2344eda14cbcSMatt Macy * readonly property, it means that it was not 2345eda14cbcSMatt Macy * present. Note this only applies to "truly" 2346eda14cbcSMatt Macy * readonly properties, not set-once properties 2347eda14cbcSMatt Macy * like volblocksize. 2348eda14cbcSMatt Macy */ 2349eda14cbcSMatt Macy if (zfs_prop_readonly(prop) && 2350eda14cbcSMatt Macy !zfs_prop_setonce(prop) && 2351eda14cbcSMatt Macy *source != NULL && (*source)[0] == '\0') { 2352eda14cbcSMatt Macy *source = NULL; 2353eda14cbcSMatt Macy return (-1); 2354eda14cbcSMatt Macy } 2355eda14cbcSMatt Macy break; 2356eda14cbcSMatt Macy 2357eda14cbcSMatt Macy case PROP_TYPE_STRING: 2358eda14cbcSMatt Macy default: 2359eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2360eda14cbcSMatt Macy "cannot get non-numeric property")); 2361eda14cbcSMatt Macy return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 2362eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "internal error"))); 2363eda14cbcSMatt Macy } 2364eda14cbcSMatt Macy } 2365eda14cbcSMatt Macy 2366eda14cbcSMatt Macy return (0); 2367eda14cbcSMatt Macy } 2368eda14cbcSMatt Macy 2369eda14cbcSMatt Macy /* 2370eda14cbcSMatt Macy * Calculate the source type, given the raw source string. 2371eda14cbcSMatt Macy */ 2372eda14cbcSMatt Macy static void 2373eda14cbcSMatt Macy get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 2374eda14cbcSMatt Macy char *statbuf, size_t statlen) 2375eda14cbcSMatt Macy { 2376eda14cbcSMatt Macy if (statbuf == NULL || 2377eda14cbcSMatt Macy srctype == NULL || *srctype == ZPROP_SRC_TEMPORARY) { 2378eda14cbcSMatt Macy return; 2379eda14cbcSMatt Macy } 2380eda14cbcSMatt Macy 2381eda14cbcSMatt Macy if (source == NULL) { 2382eda14cbcSMatt Macy *srctype = ZPROP_SRC_NONE; 2383eda14cbcSMatt Macy } else if (source[0] == '\0') { 2384eda14cbcSMatt Macy *srctype = ZPROP_SRC_DEFAULT; 2385eda14cbcSMatt Macy } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 2386eda14cbcSMatt Macy *srctype = ZPROP_SRC_RECEIVED; 2387eda14cbcSMatt Macy } else { 2388eda14cbcSMatt Macy if (strcmp(source, zhp->zfs_name) == 0) { 2389eda14cbcSMatt Macy *srctype = ZPROP_SRC_LOCAL; 2390eda14cbcSMatt Macy } else { 2391eda14cbcSMatt Macy (void) strlcpy(statbuf, source, statlen); 2392eda14cbcSMatt Macy *srctype = ZPROP_SRC_INHERITED; 2393eda14cbcSMatt Macy } 2394eda14cbcSMatt Macy } 2395eda14cbcSMatt Macy 2396eda14cbcSMatt Macy } 2397eda14cbcSMatt Macy 2398eda14cbcSMatt Macy int 2399eda14cbcSMatt Macy zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 2400eda14cbcSMatt Macy size_t proplen, boolean_t literal) 2401eda14cbcSMatt Macy { 2402eda14cbcSMatt Macy zfs_prop_t prop; 2403eda14cbcSMatt Macy int err = 0; 2404eda14cbcSMatt Macy 2405eda14cbcSMatt Macy if (zhp->zfs_recvd_props == NULL) 2406eda14cbcSMatt Macy if (get_recvd_props_ioctl(zhp) != 0) 2407eda14cbcSMatt Macy return (-1); 2408eda14cbcSMatt Macy 2409eda14cbcSMatt Macy prop = zfs_name_to_prop(propname); 2410eda14cbcSMatt Macy 24111f1e2261SMartin Matuska if (prop != ZPROP_USERPROP) { 2412dbd5678dSMartin Matuska uintptr_t cookie; 2413eda14cbcSMatt Macy if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 2414eda14cbcSMatt Macy return (-1); 2415eda14cbcSMatt Macy zfs_set_recvd_props_mode(zhp, &cookie); 2416eda14cbcSMatt Macy err = zfs_prop_get(zhp, prop, propbuf, proplen, 2417eda14cbcSMatt Macy NULL, NULL, 0, literal); 2418eda14cbcSMatt Macy zfs_unset_recvd_props_mode(zhp, &cookie); 2419eda14cbcSMatt Macy } else { 2420eda14cbcSMatt Macy nvlist_t *propval; 2421eda14cbcSMatt Macy char *recvdval; 2422eda14cbcSMatt Macy if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 2423eda14cbcSMatt Macy propname, &propval) != 0) 2424eda14cbcSMatt Macy return (-1); 2425da5137abSMartin Matuska recvdval = fnvlist_lookup_string(propval, ZPROP_VALUE); 2426eda14cbcSMatt Macy (void) strlcpy(propbuf, recvdval, proplen); 2427eda14cbcSMatt Macy } 2428eda14cbcSMatt Macy 2429eda14cbcSMatt Macy return (err == 0 ? 0 : -1); 2430eda14cbcSMatt Macy } 2431eda14cbcSMatt Macy 2432eda14cbcSMatt Macy static int 2433eda14cbcSMatt Macy get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2434eda14cbcSMatt Macy { 2435eda14cbcSMatt Macy nvlist_t *value; 2436eda14cbcSMatt Macy nvpair_t *pair; 2437eda14cbcSMatt Macy 2438eda14cbcSMatt Macy value = zfs_get_clones_nvl(zhp); 243916038816SMartin Matuska if (value == NULL || nvlist_empty(value)) 2440eda14cbcSMatt Macy return (-1); 2441eda14cbcSMatt Macy 2442eda14cbcSMatt Macy propbuf[0] = '\0'; 2443eda14cbcSMatt Macy for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 2444eda14cbcSMatt Macy pair = nvlist_next_nvpair(value, pair)) { 2445eda14cbcSMatt Macy if (propbuf[0] != '\0') 2446eda14cbcSMatt Macy (void) strlcat(propbuf, ",", proplen); 2447eda14cbcSMatt Macy (void) strlcat(propbuf, nvpair_name(pair), proplen); 2448eda14cbcSMatt Macy } 2449eda14cbcSMatt Macy 2450eda14cbcSMatt Macy return (0); 2451eda14cbcSMatt Macy } 2452eda14cbcSMatt Macy 2453eda14cbcSMatt Macy struct get_clones_arg { 2454eda14cbcSMatt Macy uint64_t numclones; 2455eda14cbcSMatt Macy nvlist_t *value; 2456eda14cbcSMatt Macy const char *origin; 2457eda14cbcSMatt Macy char buf[ZFS_MAX_DATASET_NAME_LEN]; 2458eda14cbcSMatt Macy }; 2459eda14cbcSMatt Macy 2460eda14cbcSMatt Macy static int 2461eda14cbcSMatt Macy get_clones_cb(zfs_handle_t *zhp, void *arg) 2462eda14cbcSMatt Macy { 2463eda14cbcSMatt Macy struct get_clones_arg *gca = arg; 2464eda14cbcSMatt Macy 2465eda14cbcSMatt Macy if (gca->numclones == 0) { 2466eda14cbcSMatt Macy zfs_close(zhp); 2467eda14cbcSMatt Macy return (0); 2468eda14cbcSMatt Macy } 2469eda14cbcSMatt Macy 2470eda14cbcSMatt Macy if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2471eda14cbcSMatt Macy NULL, NULL, 0, B_TRUE) != 0) 2472eda14cbcSMatt Macy goto out; 2473eda14cbcSMatt Macy if (strcmp(gca->buf, gca->origin) == 0) { 2474eda14cbcSMatt Macy fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2475eda14cbcSMatt Macy gca->numclones--; 2476eda14cbcSMatt Macy } 2477eda14cbcSMatt Macy 2478eda14cbcSMatt Macy out: 2479*15f0b8c3SMartin Matuska (void) zfs_iter_children(zhp, 0, get_clones_cb, gca); 2480eda14cbcSMatt Macy zfs_close(zhp); 2481eda14cbcSMatt Macy return (0); 2482eda14cbcSMatt Macy } 2483eda14cbcSMatt Macy 2484eda14cbcSMatt Macy nvlist_t * 2485eda14cbcSMatt Macy zfs_get_clones_nvl(zfs_handle_t *zhp) 2486eda14cbcSMatt Macy { 2487eda14cbcSMatt Macy nvlist_t *nv, *value; 2488eda14cbcSMatt Macy 2489eda14cbcSMatt Macy if (nvlist_lookup_nvlist(zhp->zfs_props, 2490eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2491eda14cbcSMatt Macy struct get_clones_arg gca; 2492eda14cbcSMatt Macy 2493eda14cbcSMatt Macy /* 2494eda14cbcSMatt Macy * if this is a snapshot, then the kernel wasn't able 2495eda14cbcSMatt Macy * to get the clones. Do it by slowly iterating. 2496eda14cbcSMatt Macy */ 2497eda14cbcSMatt Macy if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2498eda14cbcSMatt Macy return (NULL); 2499eda14cbcSMatt Macy if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2500eda14cbcSMatt Macy return (NULL); 2501eda14cbcSMatt Macy if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2502eda14cbcSMatt Macy nvlist_free(nv); 2503eda14cbcSMatt Macy return (NULL); 2504eda14cbcSMatt Macy } 2505eda14cbcSMatt Macy 2506eda14cbcSMatt Macy gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2507eda14cbcSMatt Macy gca.value = value; 2508eda14cbcSMatt Macy gca.origin = zhp->zfs_name; 2509eda14cbcSMatt Macy 2510eda14cbcSMatt Macy if (gca.numclones != 0) { 2511eda14cbcSMatt Macy zfs_handle_t *root; 2512eda14cbcSMatt Macy char pool[ZFS_MAX_DATASET_NAME_LEN]; 2513eda14cbcSMatt Macy char *cp = pool; 2514eda14cbcSMatt Macy 2515eda14cbcSMatt Macy /* get the pool name */ 2516eda14cbcSMatt Macy (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2517eda14cbcSMatt Macy (void) strsep(&cp, "/@"); 2518eda14cbcSMatt Macy root = zfs_open(zhp->zfs_hdl, pool, 2519eda14cbcSMatt Macy ZFS_TYPE_FILESYSTEM); 2520eda14cbcSMatt Macy if (root == NULL) { 2521eda14cbcSMatt Macy nvlist_free(nv); 2522eda14cbcSMatt Macy nvlist_free(value); 2523eda14cbcSMatt Macy return (NULL); 2524eda14cbcSMatt Macy } 2525eda14cbcSMatt Macy 2526eda14cbcSMatt Macy (void) get_clones_cb(root, &gca); 2527eda14cbcSMatt Macy } 2528eda14cbcSMatt Macy 2529eda14cbcSMatt Macy if (gca.numclones != 0 || 2530eda14cbcSMatt Macy nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2531eda14cbcSMatt Macy nvlist_add_nvlist(zhp->zfs_props, 2532eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2533eda14cbcSMatt Macy nvlist_free(nv); 2534eda14cbcSMatt Macy nvlist_free(value); 2535eda14cbcSMatt Macy return (NULL); 2536eda14cbcSMatt Macy } 2537eda14cbcSMatt Macy nvlist_free(nv); 2538eda14cbcSMatt Macy nvlist_free(value); 2539da5137abSMartin Matuska nv = fnvlist_lookup_nvlist(zhp->zfs_props, 2540da5137abSMartin Matuska zfs_prop_to_name(ZFS_PROP_CLONES)); 2541eda14cbcSMatt Macy } 2542eda14cbcSMatt Macy 2543da5137abSMartin Matuska return (fnvlist_lookup_nvlist(nv, ZPROP_VALUE)); 2544eda14cbcSMatt Macy } 2545eda14cbcSMatt Macy 2546eda14cbcSMatt Macy static int 2547eda14cbcSMatt Macy get_rsnaps_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2548eda14cbcSMatt Macy { 2549eda14cbcSMatt Macy nvlist_t *value; 2550eda14cbcSMatt Macy uint64_t *snaps; 2551eda14cbcSMatt Macy uint_t nsnaps; 2552eda14cbcSMatt Macy 2553eda14cbcSMatt Macy if (nvlist_lookup_nvlist(zhp->zfs_props, 2554eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS), &value) != 0) 2555eda14cbcSMatt Macy return (-1); 2556eda14cbcSMatt Macy if (nvlist_lookup_uint64_array(value, ZPROP_VALUE, &snaps, 2557eda14cbcSMatt Macy &nsnaps) != 0) 2558eda14cbcSMatt Macy return (-1); 2559eda14cbcSMatt Macy if (nsnaps == 0) { 2560eda14cbcSMatt Macy /* There's no redaction snapshots; pass a special value back */ 2561eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "none"); 2562eda14cbcSMatt Macy return (0); 2563eda14cbcSMatt Macy } 2564eda14cbcSMatt Macy propbuf[0] = '\0'; 2565eda14cbcSMatt Macy for (int i = 0; i < nsnaps; i++) { 2566eda14cbcSMatt Macy char buf[128]; 2567eda14cbcSMatt Macy if (propbuf[0] != '\0') 2568eda14cbcSMatt Macy (void) strlcat(propbuf, ",", proplen); 2569eda14cbcSMatt Macy (void) snprintf(buf, sizeof (buf), "%llu", 2570eda14cbcSMatt Macy (u_longlong_t)snaps[i]); 2571eda14cbcSMatt Macy (void) strlcat(propbuf, buf, proplen); 2572eda14cbcSMatt Macy } 2573eda14cbcSMatt Macy 2574eda14cbcSMatt Macy return (0); 2575eda14cbcSMatt Macy } 2576eda14cbcSMatt Macy 2577eda14cbcSMatt Macy /* 2578eda14cbcSMatt Macy * Accepts a property and value and checks that the value 2579eda14cbcSMatt Macy * matches the one found by the channel program. If they are 2580eda14cbcSMatt Macy * not equal, print both of them. 2581eda14cbcSMatt Macy */ 2582eda14cbcSMatt Macy static void 2583eda14cbcSMatt Macy zcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval, 2584eda14cbcSMatt Macy const char *strval) 2585eda14cbcSMatt Macy { 2586eda14cbcSMatt Macy if (!zhp->zfs_hdl->libzfs_prop_debug) 2587eda14cbcSMatt Macy return; 2588eda14cbcSMatt Macy int error; 2589eda14cbcSMatt Macy char *poolname = zhp->zpool_hdl->zpool_name; 2590eda14cbcSMatt Macy const char *prop_name = zfs_prop_to_name(prop); 2591eda14cbcSMatt Macy const char *program = 2592eda14cbcSMatt Macy "args = ...\n" 2593eda14cbcSMatt Macy "ds = args['dataset']\n" 2594eda14cbcSMatt Macy "prop = args['property']\n" 2595eda14cbcSMatt Macy "value, setpoint = zfs.get_prop(ds, prop)\n" 2596eda14cbcSMatt Macy "return {value=value, setpoint=setpoint}\n"; 2597eda14cbcSMatt Macy nvlist_t *outnvl; 2598eda14cbcSMatt Macy nvlist_t *retnvl; 2599eda14cbcSMatt Macy nvlist_t *argnvl = fnvlist_alloc(); 2600eda14cbcSMatt Macy 2601eda14cbcSMatt Macy fnvlist_add_string(argnvl, "dataset", zhp->zfs_name); 2602eda14cbcSMatt Macy fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop)); 2603eda14cbcSMatt Macy 2604eda14cbcSMatt Macy error = lzc_channel_program_nosync(poolname, program, 2605eda14cbcSMatt Macy 10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl); 2606eda14cbcSMatt Macy 2607eda14cbcSMatt Macy if (error == 0) { 2608eda14cbcSMatt Macy retnvl = fnvlist_lookup_nvlist(outnvl, "return"); 2609eda14cbcSMatt Macy if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) { 2610eda14cbcSMatt Macy int64_t ans; 2611eda14cbcSMatt Macy error = nvlist_lookup_int64(retnvl, "value", &ans); 2612eda14cbcSMatt Macy if (error != 0) { 2613eda14cbcSMatt Macy (void) fprintf(stderr, "%s: zcp check error: " 2614eda14cbcSMatt Macy "%u\n", prop_name, error); 2615eda14cbcSMatt Macy return; 2616eda14cbcSMatt Macy } 2617eda14cbcSMatt Macy if (ans != intval) { 2618eda14cbcSMatt Macy (void) fprintf(stderr, "%s: zfs found %llu, " 2619eda14cbcSMatt Macy "but zcp found %llu\n", prop_name, 2620eda14cbcSMatt Macy (u_longlong_t)intval, (u_longlong_t)ans); 2621eda14cbcSMatt Macy } 2622eda14cbcSMatt Macy } else { 2623eda14cbcSMatt Macy char *str_ans; 2624eda14cbcSMatt Macy error = nvlist_lookup_string(retnvl, "value", &str_ans); 2625eda14cbcSMatt Macy if (error != 0) { 2626eda14cbcSMatt Macy (void) fprintf(stderr, "%s: zcp check error: " 2627eda14cbcSMatt Macy "%u\n", prop_name, error); 2628eda14cbcSMatt Macy return; 2629eda14cbcSMatt Macy } 2630eda14cbcSMatt Macy if (strcmp(strval, str_ans) != 0) { 2631eda14cbcSMatt Macy (void) fprintf(stderr, 2632eda14cbcSMatt Macy "%s: zfs found '%s', but zcp found '%s'\n", 2633eda14cbcSMatt Macy prop_name, strval, str_ans); 2634eda14cbcSMatt Macy } 2635eda14cbcSMatt Macy } 2636eda14cbcSMatt Macy } else { 2637eda14cbcSMatt Macy (void) fprintf(stderr, "%s: zcp check failed, channel program " 2638eda14cbcSMatt Macy "error: %u\n", prop_name, error); 2639eda14cbcSMatt Macy } 2640eda14cbcSMatt Macy nvlist_free(argnvl); 2641eda14cbcSMatt Macy nvlist_free(outnvl); 2642eda14cbcSMatt Macy } 2643eda14cbcSMatt Macy 2644eda14cbcSMatt Macy /* 2645eda14cbcSMatt Macy * Retrieve a property from the given object. If 'literal' is specified, then 2646eda14cbcSMatt Macy * numbers are left as exact values. Otherwise, numbers are converted to a 2647eda14cbcSMatt Macy * human-readable form. 2648eda14cbcSMatt Macy * 2649eda14cbcSMatt Macy * Returns 0 on success, or -1 on error. 2650eda14cbcSMatt Macy */ 2651eda14cbcSMatt Macy int 2652eda14cbcSMatt Macy zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2653eda14cbcSMatt Macy zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2654eda14cbcSMatt Macy { 2655eda14cbcSMatt Macy char *source = NULL; 2656eda14cbcSMatt Macy uint64_t val; 2657eda14cbcSMatt Macy const char *str; 2658eda14cbcSMatt Macy const char *strval; 2659eda14cbcSMatt Macy boolean_t received = zfs_is_recvd_props_mode(zhp); 2660eda14cbcSMatt Macy 2661eda14cbcSMatt Macy /* 2662eda14cbcSMatt Macy * Check to see if this property applies to our object 2663eda14cbcSMatt Macy */ 2664eda14cbcSMatt Macy if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) 2665eda14cbcSMatt Macy return (-1); 2666eda14cbcSMatt Macy 2667eda14cbcSMatt Macy if (received && zfs_prop_readonly(prop)) 2668eda14cbcSMatt Macy return (-1); 2669eda14cbcSMatt Macy 2670eda14cbcSMatt Macy if (src) 2671eda14cbcSMatt Macy *src = ZPROP_SRC_NONE; 2672eda14cbcSMatt Macy 2673eda14cbcSMatt Macy switch (prop) { 2674eda14cbcSMatt Macy case ZFS_PROP_CREATION: 2675eda14cbcSMatt Macy /* 2676eda14cbcSMatt Macy * 'creation' is a time_t stored in the statistics. We convert 2677eda14cbcSMatt Macy * this into a string unless 'literal' is specified. 2678eda14cbcSMatt Macy */ 2679eda14cbcSMatt Macy { 2680eda14cbcSMatt Macy val = getprop_uint64(zhp, prop, &source); 2681eda14cbcSMatt Macy time_t time = (time_t)val; 2682eda14cbcSMatt Macy struct tm t; 2683eda14cbcSMatt Macy 2684eda14cbcSMatt Macy if (literal || 2685eda14cbcSMatt Macy localtime_r(&time, &t) == NULL || 2686eda14cbcSMatt Macy strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2687eda14cbcSMatt Macy &t) == 0) 2688eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 2689eda14cbcSMatt Macy (u_longlong_t)val); 2690eda14cbcSMatt Macy } 2691eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 2692eda14cbcSMatt Macy break; 2693eda14cbcSMatt Macy 2694eda14cbcSMatt Macy case ZFS_PROP_MOUNTPOINT: 2695eda14cbcSMatt Macy /* 2696eda14cbcSMatt Macy * Getting the precise mountpoint can be tricky. 2697eda14cbcSMatt Macy * 2698eda14cbcSMatt Macy * - for 'none' or 'legacy', return those values. 2699eda14cbcSMatt Macy * - for inherited mountpoints, we want to take everything 2700eda14cbcSMatt Macy * after our ancestor and append it to the inherited value. 2701eda14cbcSMatt Macy * 2702eda14cbcSMatt Macy * If the pool has an alternate root, we want to prepend that 2703eda14cbcSMatt Macy * root to any values we return. 2704eda14cbcSMatt Macy */ 2705eda14cbcSMatt Macy 2706eda14cbcSMatt Macy str = getprop_string(zhp, prop, &source); 2707eda14cbcSMatt Macy 2708eda14cbcSMatt Macy if (str[0] == '/') { 2709eda14cbcSMatt Macy char buf[MAXPATHLEN]; 2710eda14cbcSMatt Macy char *root = buf; 2711eda14cbcSMatt Macy const char *relpath; 2712eda14cbcSMatt Macy 2713eda14cbcSMatt Macy /* 2714eda14cbcSMatt Macy * If we inherit the mountpoint, even from a dataset 2715eda14cbcSMatt Macy * with a received value, the source will be the path of 2716eda14cbcSMatt Macy * the dataset we inherit from. If source is 2717eda14cbcSMatt Macy * ZPROP_SOURCE_VAL_RECVD, the received value is not 2718eda14cbcSMatt Macy * inherited. 2719eda14cbcSMatt Macy */ 2720eda14cbcSMatt Macy if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2721eda14cbcSMatt Macy relpath = ""; 2722eda14cbcSMatt Macy } else { 2723eda14cbcSMatt Macy relpath = zhp->zfs_name + strlen(source); 2724eda14cbcSMatt Macy if (relpath[0] == '/') 2725eda14cbcSMatt Macy relpath++; 2726eda14cbcSMatt Macy } 2727eda14cbcSMatt Macy 2728eda14cbcSMatt Macy if ((zpool_get_prop(zhp->zpool_hdl, 2729eda14cbcSMatt Macy ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL, 2730eda14cbcSMatt Macy B_FALSE)) || (strcmp(root, "-") == 0)) 2731eda14cbcSMatt Macy root[0] = '\0'; 2732eda14cbcSMatt Macy /* 2733eda14cbcSMatt Macy * Special case an alternate root of '/'. This will 2734eda14cbcSMatt Macy * avoid having multiple leading slashes in the 2735eda14cbcSMatt Macy * mountpoint path. 2736eda14cbcSMatt Macy */ 2737eda14cbcSMatt Macy if (strcmp(root, "/") == 0) 2738eda14cbcSMatt Macy root++; 2739eda14cbcSMatt Macy 2740eda14cbcSMatt Macy /* 2741eda14cbcSMatt Macy * If the mountpoint is '/' then skip over this 2742eda14cbcSMatt Macy * if we are obtaining either an alternate root or 2743eda14cbcSMatt Macy * an inherited mountpoint. 2744eda14cbcSMatt Macy */ 2745eda14cbcSMatt Macy if (str[1] == '\0' && (root[0] != '\0' || 2746eda14cbcSMatt Macy relpath[0] != '\0')) 2747eda14cbcSMatt Macy str++; 2748eda14cbcSMatt Macy 2749eda14cbcSMatt Macy if (relpath[0] == '\0') 2750eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%s%s", 2751eda14cbcSMatt Macy root, str); 2752eda14cbcSMatt Macy else 2753eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%s%s%s%s", 2754eda14cbcSMatt Macy root, str, relpath[0] == '@' ? "" : "/", 2755eda14cbcSMatt Macy relpath); 2756eda14cbcSMatt Macy } else { 2757eda14cbcSMatt Macy /* 'legacy' or 'none' */ 2758eda14cbcSMatt Macy (void) strlcpy(propbuf, str, proplen); 2759eda14cbcSMatt Macy } 2760eda14cbcSMatt Macy zcp_check(zhp, prop, 0, propbuf); 2761eda14cbcSMatt Macy break; 2762eda14cbcSMatt Macy 2763eda14cbcSMatt Macy case ZFS_PROP_ORIGIN: 2764*15f0b8c3SMartin Matuska if (*zhp->zfs_dmustats.dds_origin != '\0') { 2765*15f0b8c3SMartin Matuska str = (char *)&zhp->zfs_dmustats.dds_origin; 2766*15f0b8c3SMartin Matuska } else { 2767eda14cbcSMatt Macy str = getprop_string(zhp, prop, &source); 2768*15f0b8c3SMartin Matuska } 2769*15f0b8c3SMartin Matuska if (str == NULL || *str == '\0') 2770*15f0b8c3SMartin Matuska str = zfs_prop_default_string(prop); 2771eda14cbcSMatt Macy if (str == NULL) 2772eda14cbcSMatt Macy return (-1); 2773eda14cbcSMatt Macy (void) strlcpy(propbuf, str, proplen); 2774eda14cbcSMatt Macy zcp_check(zhp, prop, 0, str); 2775eda14cbcSMatt Macy break; 2776eda14cbcSMatt Macy 2777eda14cbcSMatt Macy case ZFS_PROP_REDACT_SNAPS: 2778eda14cbcSMatt Macy if (get_rsnaps_string(zhp, propbuf, proplen) != 0) 2779eda14cbcSMatt Macy return (-1); 2780eda14cbcSMatt Macy break; 2781eda14cbcSMatt Macy 2782eda14cbcSMatt Macy case ZFS_PROP_CLONES: 2783eda14cbcSMatt Macy if (get_clones_string(zhp, propbuf, proplen) != 0) 2784eda14cbcSMatt Macy return (-1); 2785eda14cbcSMatt Macy break; 2786eda14cbcSMatt Macy 2787eda14cbcSMatt Macy case ZFS_PROP_QUOTA: 2788eda14cbcSMatt Macy case ZFS_PROP_REFQUOTA: 2789eda14cbcSMatt Macy case ZFS_PROP_RESERVATION: 2790eda14cbcSMatt Macy case ZFS_PROP_REFRESERVATION: 2791eda14cbcSMatt Macy 2792eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2793eda14cbcSMatt Macy return (-1); 2794eda14cbcSMatt Macy /* 2795eda14cbcSMatt Macy * If quota or reservation is 0, we translate this into 'none' 2796eda14cbcSMatt Macy * (unless literal is set), and indicate that it's the default 2797eda14cbcSMatt Macy * value. Otherwise, we print the number nicely and indicate 2798eda14cbcSMatt Macy * that its set locally. 2799eda14cbcSMatt Macy */ 2800eda14cbcSMatt Macy if (val == 0) { 2801eda14cbcSMatt Macy if (literal) 2802eda14cbcSMatt Macy (void) strlcpy(propbuf, "0", proplen); 2803eda14cbcSMatt Macy else 2804eda14cbcSMatt Macy (void) strlcpy(propbuf, "none", proplen); 2805eda14cbcSMatt Macy } else { 2806eda14cbcSMatt Macy if (literal) 2807eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 2808eda14cbcSMatt Macy (u_longlong_t)val); 2809eda14cbcSMatt Macy else 2810eda14cbcSMatt Macy zfs_nicebytes(val, propbuf, proplen); 2811eda14cbcSMatt Macy } 2812eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 2813eda14cbcSMatt Macy break; 2814eda14cbcSMatt Macy 2815eda14cbcSMatt Macy case ZFS_PROP_FILESYSTEM_LIMIT: 2816eda14cbcSMatt Macy case ZFS_PROP_SNAPSHOT_LIMIT: 2817eda14cbcSMatt Macy case ZFS_PROP_FILESYSTEM_COUNT: 2818eda14cbcSMatt Macy case ZFS_PROP_SNAPSHOT_COUNT: 2819eda14cbcSMatt Macy 2820eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2821eda14cbcSMatt Macy return (-1); 2822eda14cbcSMatt Macy 2823eda14cbcSMatt Macy /* 282481b22a98SMartin Matuska * If limit is UINT64_MAX, we translate this into 'none', and 282581b22a98SMartin Matuska * indicate that it's the default value. Otherwise, we print 282681b22a98SMartin Matuska * the number nicely and indicate that it's set locally. 2827eda14cbcSMatt Macy */ 282881b22a98SMartin Matuska if (val == UINT64_MAX) { 282981b22a98SMartin Matuska (void) strlcpy(propbuf, "none", proplen); 283081b22a98SMartin Matuska } else if (literal) { 2831eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 2832eda14cbcSMatt Macy (u_longlong_t)val); 2833eda14cbcSMatt Macy } else { 2834eda14cbcSMatt Macy zfs_nicenum(val, propbuf, proplen); 2835eda14cbcSMatt Macy } 2836eda14cbcSMatt Macy 2837eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 2838eda14cbcSMatt Macy break; 2839eda14cbcSMatt Macy 2840eda14cbcSMatt Macy case ZFS_PROP_REFRATIO: 2841eda14cbcSMatt Macy case ZFS_PROP_COMPRESSRATIO: 2842eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2843eda14cbcSMatt Macy return (-1); 2844eda14cbcSMatt Macy if (literal) 2845eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu.%02llu", 2846eda14cbcSMatt Macy (u_longlong_t)(val / 100), 2847eda14cbcSMatt Macy (u_longlong_t)(val % 100)); 2848eda14cbcSMatt Macy else 2849eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu.%02llux", 2850eda14cbcSMatt Macy (u_longlong_t)(val / 100), 2851eda14cbcSMatt Macy (u_longlong_t)(val % 100)); 2852eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 2853eda14cbcSMatt Macy break; 2854eda14cbcSMatt Macy 2855eda14cbcSMatt Macy case ZFS_PROP_TYPE: 2856eda14cbcSMatt Macy switch (zhp->zfs_type) { 2857eda14cbcSMatt Macy case ZFS_TYPE_FILESYSTEM: 2858eda14cbcSMatt Macy str = "filesystem"; 2859eda14cbcSMatt Macy break; 2860eda14cbcSMatt Macy case ZFS_TYPE_VOLUME: 2861eda14cbcSMatt Macy str = "volume"; 2862eda14cbcSMatt Macy break; 2863eda14cbcSMatt Macy case ZFS_TYPE_SNAPSHOT: 2864eda14cbcSMatt Macy str = "snapshot"; 2865eda14cbcSMatt Macy break; 2866eda14cbcSMatt Macy case ZFS_TYPE_BOOKMARK: 2867eda14cbcSMatt Macy str = "bookmark"; 2868eda14cbcSMatt Macy break; 2869eda14cbcSMatt Macy default: 2870eda14cbcSMatt Macy abort(); 2871eda14cbcSMatt Macy } 2872eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%s", str); 2873eda14cbcSMatt Macy zcp_check(zhp, prop, 0, propbuf); 2874eda14cbcSMatt Macy break; 2875eda14cbcSMatt Macy 2876eda14cbcSMatt Macy case ZFS_PROP_MOUNTED: 2877eda14cbcSMatt Macy /* 2878eda14cbcSMatt Macy * The 'mounted' property is a pseudo-property that described 2879eda14cbcSMatt Macy * whether the filesystem is currently mounted. Even though 2880eda14cbcSMatt Macy * it's a boolean value, the typical values of "on" and "off" 2881eda14cbcSMatt Macy * don't make sense, so we translate to "yes" and "no". 2882eda14cbcSMatt Macy */ 2883eda14cbcSMatt Macy if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2884eda14cbcSMatt Macy src, &source, &val) != 0) 2885eda14cbcSMatt Macy return (-1); 2886eda14cbcSMatt Macy if (val) 2887eda14cbcSMatt Macy (void) strlcpy(propbuf, "yes", proplen); 2888eda14cbcSMatt Macy else 2889eda14cbcSMatt Macy (void) strlcpy(propbuf, "no", proplen); 2890eda14cbcSMatt Macy break; 2891eda14cbcSMatt Macy 2892eda14cbcSMatt Macy case ZFS_PROP_NAME: 2893eda14cbcSMatt Macy /* 2894eda14cbcSMatt Macy * The 'name' property is a pseudo-property derived from the 2895eda14cbcSMatt Macy * dataset name. It is presented as a real property to simplify 2896eda14cbcSMatt Macy * consumers. 2897eda14cbcSMatt Macy */ 2898eda14cbcSMatt Macy (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2899eda14cbcSMatt Macy zcp_check(zhp, prop, 0, propbuf); 2900eda14cbcSMatt Macy break; 2901eda14cbcSMatt Macy 2902eda14cbcSMatt Macy case ZFS_PROP_MLSLABEL: 2903eda14cbcSMatt Macy { 2904eda14cbcSMatt Macy #ifdef HAVE_MLSLABEL 2905eda14cbcSMatt Macy m_label_t *new_sl = NULL; 2906eda14cbcSMatt Macy char *ascii = NULL; /* human readable label */ 2907eda14cbcSMatt Macy 2908eda14cbcSMatt Macy (void) strlcpy(propbuf, 2909eda14cbcSMatt Macy getprop_string(zhp, prop, &source), proplen); 2910eda14cbcSMatt Macy 2911eda14cbcSMatt Macy if (literal || (strcasecmp(propbuf, 2912eda14cbcSMatt Macy ZFS_MLSLABEL_DEFAULT) == 0)) 2913eda14cbcSMatt Macy break; 2914eda14cbcSMatt Macy 2915eda14cbcSMatt Macy /* 2916eda14cbcSMatt Macy * Try to translate the internal hex string to 2917eda14cbcSMatt Macy * human-readable output. If there are any 2918eda14cbcSMatt Macy * problems just use the hex string. 2919eda14cbcSMatt Macy */ 2920eda14cbcSMatt Macy 2921eda14cbcSMatt Macy if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2922eda14cbcSMatt Macy L_NO_CORRECTION, NULL) == -1) { 2923eda14cbcSMatt Macy m_label_free(new_sl); 2924eda14cbcSMatt Macy break; 2925eda14cbcSMatt Macy } 2926eda14cbcSMatt Macy 2927eda14cbcSMatt Macy if (label_to_str(new_sl, &ascii, M_LABEL, 2928eda14cbcSMatt Macy DEF_NAMES) != 0) { 2929eda14cbcSMatt Macy if (ascii) 2930eda14cbcSMatt Macy free(ascii); 2931eda14cbcSMatt Macy m_label_free(new_sl); 2932eda14cbcSMatt Macy break; 2933eda14cbcSMatt Macy } 2934eda14cbcSMatt Macy m_label_free(new_sl); 2935eda14cbcSMatt Macy 2936eda14cbcSMatt Macy (void) strlcpy(propbuf, ascii, proplen); 2937eda14cbcSMatt Macy free(ascii); 2938eda14cbcSMatt Macy #else 2939eda14cbcSMatt Macy (void) strlcpy(propbuf, 2940eda14cbcSMatt Macy getprop_string(zhp, prop, &source), proplen); 2941eda14cbcSMatt Macy #endif /* HAVE_MLSLABEL */ 2942eda14cbcSMatt Macy } 2943eda14cbcSMatt Macy break; 2944eda14cbcSMatt Macy 2945eda14cbcSMatt Macy case ZFS_PROP_GUID: 2946c03c5b1cSMartin Matuska case ZFS_PROP_KEY_GUID: 2947c03c5b1cSMartin Matuska case ZFS_PROP_IVSET_GUID: 2948eda14cbcSMatt Macy case ZFS_PROP_CREATETXG: 2949eda14cbcSMatt Macy case ZFS_PROP_OBJSETID: 29502c48331dSMatt Macy case ZFS_PROP_PBKDF2_ITERS: 2951eda14cbcSMatt Macy /* 2952eda14cbcSMatt Macy * These properties are stored as numbers, but they are 29532c48331dSMatt Macy * identifiers or counters. 2954eda14cbcSMatt Macy * We don't want them to be pretty printed, because pretty 29552c48331dSMatt Macy * printing truncates their values making them useless. 2956eda14cbcSMatt Macy */ 2957eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2958eda14cbcSMatt Macy return (-1); 2959eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2960eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 2961eda14cbcSMatt Macy break; 2962eda14cbcSMatt Macy 2963eda14cbcSMatt Macy case ZFS_PROP_REFERENCED: 2964eda14cbcSMatt Macy case ZFS_PROP_AVAILABLE: 2965eda14cbcSMatt Macy case ZFS_PROP_USED: 2966eda14cbcSMatt Macy case ZFS_PROP_USEDSNAP: 2967eda14cbcSMatt Macy case ZFS_PROP_USEDDS: 2968eda14cbcSMatt Macy case ZFS_PROP_USEDREFRESERV: 2969eda14cbcSMatt Macy case ZFS_PROP_USEDCHILD: 2970eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2971eda14cbcSMatt Macy return (-1); 2972eda14cbcSMatt Macy if (literal) { 2973eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 2974eda14cbcSMatt Macy (u_longlong_t)val); 2975eda14cbcSMatt Macy } else { 2976eda14cbcSMatt Macy zfs_nicebytes(val, propbuf, proplen); 2977eda14cbcSMatt Macy } 2978eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 2979eda14cbcSMatt Macy break; 2980eda14cbcSMatt Macy 2981271171e0SMartin Matuska case ZFS_PROP_SNAPSHOTS_CHANGED: 2982271171e0SMartin Matuska { 2983271171e0SMartin Matuska if ((get_numeric_property(zhp, prop, src, &source, 2984271171e0SMartin Matuska &val) != 0) || val == 0) { 2985271171e0SMartin Matuska return (-1); 2986271171e0SMartin Matuska } 2987271171e0SMartin Matuska 2988271171e0SMartin Matuska time_t time = (time_t)val; 2989271171e0SMartin Matuska struct tm t; 2990271171e0SMartin Matuska 2991271171e0SMartin Matuska if (literal || 2992271171e0SMartin Matuska localtime_r(&time, &t) == NULL || 299308aba0aeSMartin Matuska strftime(propbuf, proplen, "%a %b %e %k:%M:%S %Y", 2994271171e0SMartin Matuska &t) == 0) 2995271171e0SMartin Matuska (void) snprintf(propbuf, proplen, "%llu", 2996271171e0SMartin Matuska (u_longlong_t)val); 2997271171e0SMartin Matuska } 2998271171e0SMartin Matuska zcp_check(zhp, prop, val, NULL); 2999271171e0SMartin Matuska break; 3000271171e0SMartin Matuska 3001eda14cbcSMatt Macy default: 3002eda14cbcSMatt Macy switch (zfs_prop_get_type(prop)) { 3003eda14cbcSMatt Macy case PROP_TYPE_NUMBER: 3004eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, 3005eda14cbcSMatt Macy &source, &val) != 0) { 3006eda14cbcSMatt Macy return (-1); 3007eda14cbcSMatt Macy } 3008eda14cbcSMatt Macy 3009eda14cbcSMatt Macy if (literal) { 3010eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 3011eda14cbcSMatt Macy (u_longlong_t)val); 3012eda14cbcSMatt Macy } else { 3013eda14cbcSMatt Macy zfs_nicenum(val, propbuf, proplen); 3014eda14cbcSMatt Macy } 3015eda14cbcSMatt Macy zcp_check(zhp, prop, val, NULL); 3016eda14cbcSMatt Macy break; 3017eda14cbcSMatt Macy 3018eda14cbcSMatt Macy case PROP_TYPE_STRING: 3019eda14cbcSMatt Macy str = getprop_string(zhp, prop, &source); 3020eda14cbcSMatt Macy if (str == NULL) 3021eda14cbcSMatt Macy return (-1); 3022eda14cbcSMatt Macy 3023eda14cbcSMatt Macy (void) strlcpy(propbuf, str, proplen); 3024eda14cbcSMatt Macy zcp_check(zhp, prop, 0, str); 3025eda14cbcSMatt Macy break; 3026eda14cbcSMatt Macy 3027eda14cbcSMatt Macy case PROP_TYPE_INDEX: 3028eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, 3029eda14cbcSMatt Macy &source, &val) != 0) 3030eda14cbcSMatt Macy return (-1); 3031eda14cbcSMatt Macy if (zfs_prop_index_to_string(prop, val, &strval) != 0) 3032eda14cbcSMatt Macy return (-1); 3033eda14cbcSMatt Macy 3034eda14cbcSMatt Macy (void) strlcpy(propbuf, strval, proplen); 3035eda14cbcSMatt Macy zcp_check(zhp, prop, 0, strval); 3036eda14cbcSMatt Macy break; 3037eda14cbcSMatt Macy 3038eda14cbcSMatt Macy default: 3039eda14cbcSMatt Macy abort(); 3040eda14cbcSMatt Macy } 3041eda14cbcSMatt Macy } 3042eda14cbcSMatt Macy 3043eda14cbcSMatt Macy get_source(zhp, src, source, statbuf, statlen); 3044eda14cbcSMatt Macy 3045eda14cbcSMatt Macy return (0); 3046eda14cbcSMatt Macy } 3047eda14cbcSMatt Macy 3048eda14cbcSMatt Macy /* 3049eda14cbcSMatt Macy * Utility function to get the given numeric property. Does no validation that 3050eda14cbcSMatt Macy * the given property is the appropriate type; should only be used with 3051eda14cbcSMatt Macy * hard-coded property types. 3052eda14cbcSMatt Macy */ 3053eda14cbcSMatt Macy uint64_t 3054eda14cbcSMatt Macy zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 3055eda14cbcSMatt Macy { 3056eda14cbcSMatt Macy char *source; 3057eda14cbcSMatt Macy uint64_t val = 0; 3058eda14cbcSMatt Macy 3059eda14cbcSMatt Macy (void) get_numeric_property(zhp, prop, NULL, &source, &val); 3060eda14cbcSMatt Macy 3061eda14cbcSMatt Macy return (val); 3062eda14cbcSMatt Macy } 3063eda14cbcSMatt Macy 3064eda14cbcSMatt Macy static int 3065eda14cbcSMatt Macy zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 3066eda14cbcSMatt Macy { 3067eda14cbcSMatt Macy char buf[64]; 3068eda14cbcSMatt Macy 3069eda14cbcSMatt Macy (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 3070eda14cbcSMatt Macy return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 3071eda14cbcSMatt Macy } 3072eda14cbcSMatt Macy 3073eda14cbcSMatt Macy /* 3074eda14cbcSMatt Macy * Similar to zfs_prop_get(), but returns the value as an integer. 3075eda14cbcSMatt Macy */ 3076eda14cbcSMatt Macy int 3077eda14cbcSMatt Macy zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 3078eda14cbcSMatt Macy zprop_source_t *src, char *statbuf, size_t statlen) 3079eda14cbcSMatt Macy { 3080eda14cbcSMatt Macy char *source; 3081eda14cbcSMatt Macy 3082eda14cbcSMatt Macy /* 3083eda14cbcSMatt Macy * Check to see if this property applies to our object 3084eda14cbcSMatt Macy */ 3085eda14cbcSMatt Macy if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) { 3086eda14cbcSMatt Macy return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 3087eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 3088eda14cbcSMatt Macy zfs_prop_to_name(prop))); 3089eda14cbcSMatt Macy } 3090eda14cbcSMatt Macy 3091eda14cbcSMatt Macy if (src) 3092eda14cbcSMatt Macy *src = ZPROP_SRC_NONE; 3093eda14cbcSMatt Macy 3094eda14cbcSMatt Macy if (get_numeric_property(zhp, prop, src, &source, value) != 0) 3095eda14cbcSMatt Macy return (-1); 3096eda14cbcSMatt Macy 3097eda14cbcSMatt Macy get_source(zhp, src, source, statbuf, statlen); 3098eda14cbcSMatt Macy 3099eda14cbcSMatt Macy return (0); 3100eda14cbcSMatt Macy } 3101eda14cbcSMatt Macy 3102eda14cbcSMatt Macy #ifdef HAVE_IDMAP 3103eda14cbcSMatt Macy static int 3104eda14cbcSMatt Macy idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 3105eda14cbcSMatt Macy char **domainp, idmap_rid_t *ridp) 3106eda14cbcSMatt Macy { 3107eda14cbcSMatt Macy idmap_get_handle_t *get_hdl = NULL; 3108eda14cbcSMatt Macy idmap_stat status; 3109eda14cbcSMatt Macy int err = EINVAL; 3110eda14cbcSMatt Macy 3111eda14cbcSMatt Macy if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 3112eda14cbcSMatt Macy goto out; 3113eda14cbcSMatt Macy 3114eda14cbcSMatt Macy if (isuser) { 3115eda14cbcSMatt Macy err = idmap_get_sidbyuid(get_hdl, id, 3116eda14cbcSMatt Macy IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 3117eda14cbcSMatt Macy } else { 3118eda14cbcSMatt Macy err = idmap_get_sidbygid(get_hdl, id, 3119eda14cbcSMatt Macy IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 3120eda14cbcSMatt Macy } 3121eda14cbcSMatt Macy if (err == IDMAP_SUCCESS && 3122eda14cbcSMatt Macy idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 3123eda14cbcSMatt Macy status == IDMAP_SUCCESS) 3124eda14cbcSMatt Macy err = 0; 3125eda14cbcSMatt Macy else 3126eda14cbcSMatt Macy err = EINVAL; 3127eda14cbcSMatt Macy out: 3128eda14cbcSMatt Macy if (get_hdl) 3129eda14cbcSMatt Macy idmap_get_destroy(get_hdl); 3130eda14cbcSMatt Macy return (err); 3131eda14cbcSMatt Macy } 3132eda14cbcSMatt Macy #endif /* HAVE_IDMAP */ 3133eda14cbcSMatt Macy 3134eda14cbcSMatt Macy /* 3135eda14cbcSMatt Macy * convert the propname into parameters needed by kernel 3136eda14cbcSMatt Macy * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 3137eda14cbcSMatt Macy * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 3138eda14cbcSMatt Macy * Eg: groupquota@staff -> ZFS_PROP_GROUPQUOTA, "", 1234 3139eda14cbcSMatt Macy * Eg: groupused@staff -> ZFS_PROP_GROUPUSED, "", 1234 3140eda14cbcSMatt Macy * Eg: projectquota@123 -> ZFS_PROP_PROJECTQUOTA, "", 123 3141eda14cbcSMatt Macy * Eg: projectused@789 -> ZFS_PROP_PROJECTUSED, "", 789 3142eda14cbcSMatt Macy */ 3143eda14cbcSMatt Macy static int 3144eda14cbcSMatt Macy userquota_propname_decode(const char *propname, boolean_t zoned, 3145eda14cbcSMatt Macy zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 3146eda14cbcSMatt Macy { 3147eda14cbcSMatt Macy zfs_userquota_prop_t type; 3148eda14cbcSMatt Macy char *cp; 3149eda14cbcSMatt Macy boolean_t isuser; 3150eda14cbcSMatt Macy boolean_t isgroup; 3151eda14cbcSMatt Macy boolean_t isproject; 3152eda14cbcSMatt Macy struct passwd *pw; 3153eda14cbcSMatt Macy struct group *gr; 3154eda14cbcSMatt Macy 3155eda14cbcSMatt Macy domain[0] = '\0'; 3156eda14cbcSMatt Macy 3157eda14cbcSMatt Macy /* Figure out the property type ({user|group|project}{quota|space}) */ 3158eda14cbcSMatt Macy for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 3159eda14cbcSMatt Macy if (strncmp(propname, zfs_userquota_prop_prefixes[type], 3160eda14cbcSMatt Macy strlen(zfs_userquota_prop_prefixes[type])) == 0) 3161eda14cbcSMatt Macy break; 3162eda14cbcSMatt Macy } 3163eda14cbcSMatt Macy if (type == ZFS_NUM_USERQUOTA_PROPS) 3164eda14cbcSMatt Macy return (EINVAL); 3165eda14cbcSMatt Macy *typep = type; 3166eda14cbcSMatt Macy 3167eda14cbcSMatt Macy isuser = (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_USERUSED || 3168eda14cbcSMatt Macy type == ZFS_PROP_USEROBJQUOTA || 3169eda14cbcSMatt Macy type == ZFS_PROP_USEROBJUSED); 3170eda14cbcSMatt Macy isgroup = (type == ZFS_PROP_GROUPQUOTA || type == ZFS_PROP_GROUPUSED || 3171eda14cbcSMatt Macy type == ZFS_PROP_GROUPOBJQUOTA || 3172eda14cbcSMatt Macy type == ZFS_PROP_GROUPOBJUSED); 3173eda14cbcSMatt Macy isproject = (type == ZFS_PROP_PROJECTQUOTA || 3174eda14cbcSMatt Macy type == ZFS_PROP_PROJECTUSED || type == ZFS_PROP_PROJECTOBJQUOTA || 3175eda14cbcSMatt Macy type == ZFS_PROP_PROJECTOBJUSED); 3176eda14cbcSMatt Macy 3177eda14cbcSMatt Macy cp = strchr(propname, '@') + 1; 3178eda14cbcSMatt Macy 3179eda14cbcSMatt Macy if (isuser && (pw = getpwnam(cp)) != NULL) { 3180eda14cbcSMatt Macy if (zoned && getzoneid() == GLOBAL_ZONEID) 3181eda14cbcSMatt Macy return (ENOENT); 3182eda14cbcSMatt Macy *ridp = pw->pw_uid; 3183eda14cbcSMatt Macy } else if (isgroup && (gr = getgrnam(cp)) != NULL) { 3184eda14cbcSMatt Macy if (zoned && getzoneid() == GLOBAL_ZONEID) 3185eda14cbcSMatt Macy return (ENOENT); 3186eda14cbcSMatt Macy *ridp = gr->gr_gid; 3187eda14cbcSMatt Macy } else if (!isproject && strchr(cp, '@')) { 3188eda14cbcSMatt Macy #ifdef HAVE_IDMAP 3189eda14cbcSMatt Macy /* 3190eda14cbcSMatt Macy * It's a SID name (eg "user@domain") that needs to be 3191eda14cbcSMatt Macy * turned into S-1-domainID-RID. 3192eda14cbcSMatt Macy */ 3193eda14cbcSMatt Macy directory_error_t e; 3194eda14cbcSMatt Macy char *numericsid = NULL; 3195eda14cbcSMatt Macy char *end; 3196eda14cbcSMatt Macy 3197eda14cbcSMatt Macy if (zoned && getzoneid() == GLOBAL_ZONEID) 3198eda14cbcSMatt Macy return (ENOENT); 3199eda14cbcSMatt Macy if (isuser) { 3200eda14cbcSMatt Macy e = directory_sid_from_user_name(NULL, 3201eda14cbcSMatt Macy cp, &numericsid); 3202eda14cbcSMatt Macy } else { 3203eda14cbcSMatt Macy e = directory_sid_from_group_name(NULL, 3204eda14cbcSMatt Macy cp, &numericsid); 3205eda14cbcSMatt Macy } 3206eda14cbcSMatt Macy if (e != NULL) { 3207eda14cbcSMatt Macy directory_error_free(e); 3208eda14cbcSMatt Macy return (ENOENT); 3209eda14cbcSMatt Macy } 3210eda14cbcSMatt Macy if (numericsid == NULL) 3211eda14cbcSMatt Macy return (ENOENT); 3212eda14cbcSMatt Macy cp = numericsid; 3213eda14cbcSMatt Macy (void) strlcpy(domain, cp, domainlen); 3214eda14cbcSMatt Macy cp = strrchr(domain, '-'); 3215eda14cbcSMatt Macy *cp = '\0'; 3216eda14cbcSMatt Macy cp++; 3217eda14cbcSMatt Macy 3218eda14cbcSMatt Macy errno = 0; 3219eda14cbcSMatt Macy *ridp = strtoull(cp, &end, 10); 3220eda14cbcSMatt Macy free(numericsid); 3221eda14cbcSMatt Macy 3222eda14cbcSMatt Macy if (errno != 0 || *end != '\0') 3223eda14cbcSMatt Macy return (EINVAL); 3224eda14cbcSMatt Macy #else 3225e92ffd9bSMartin Matuska (void) domainlen; 3226eda14cbcSMatt Macy return (ENOSYS); 3227eda14cbcSMatt Macy #endif /* HAVE_IDMAP */ 3228eda14cbcSMatt Macy } else { 3229eda14cbcSMatt Macy /* It's a user/group/project ID (eg "12345"). */ 3230eda14cbcSMatt Macy uid_t id; 3231eda14cbcSMatt Macy char *end; 3232eda14cbcSMatt Macy id = strtoul(cp, &end, 10); 3233eda14cbcSMatt Macy if (*end != '\0') 3234eda14cbcSMatt Macy return (EINVAL); 3235eda14cbcSMatt Macy if (id > MAXUID && !isproject) { 3236eda14cbcSMatt Macy #ifdef HAVE_IDMAP 3237eda14cbcSMatt Macy /* It's an ephemeral ID. */ 3238eda14cbcSMatt Macy idmap_rid_t rid; 3239eda14cbcSMatt Macy char *mapdomain; 3240eda14cbcSMatt Macy 3241eda14cbcSMatt Macy if (idmap_id_to_numeric_domain_rid(id, isuser, 3242eda14cbcSMatt Macy &mapdomain, &rid) != 0) 3243eda14cbcSMatt Macy return (ENOENT); 3244eda14cbcSMatt Macy (void) strlcpy(domain, mapdomain, domainlen); 3245eda14cbcSMatt Macy *ridp = rid; 3246eda14cbcSMatt Macy #else 3247eda14cbcSMatt Macy return (ENOSYS); 3248eda14cbcSMatt Macy #endif /* HAVE_IDMAP */ 3249eda14cbcSMatt Macy } else { 3250eda14cbcSMatt Macy *ridp = id; 3251eda14cbcSMatt Macy } 3252eda14cbcSMatt Macy } 3253eda14cbcSMatt Macy 3254eda14cbcSMatt Macy return (0); 3255eda14cbcSMatt Macy } 3256eda14cbcSMatt Macy 3257eda14cbcSMatt Macy static int 3258eda14cbcSMatt Macy zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 3259eda14cbcSMatt Macy uint64_t *propvalue, zfs_userquota_prop_t *typep) 3260eda14cbcSMatt Macy { 3261eda14cbcSMatt Macy int err; 3262eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 3263eda14cbcSMatt Macy 3264eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3265eda14cbcSMatt Macy 3266eda14cbcSMatt Macy err = userquota_propname_decode(propname, 3267eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 3268eda14cbcSMatt Macy typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 3269eda14cbcSMatt Macy zc.zc_objset_type = *typep; 3270eda14cbcSMatt Macy if (err) 3271eda14cbcSMatt Macy return (err); 3272eda14cbcSMatt Macy 3273eda14cbcSMatt Macy err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_USERSPACE_ONE, &zc); 3274eda14cbcSMatt Macy if (err) 3275eda14cbcSMatt Macy return (err); 3276eda14cbcSMatt Macy 3277eda14cbcSMatt Macy *propvalue = zc.zc_cookie; 3278eda14cbcSMatt Macy return (0); 3279eda14cbcSMatt Macy } 3280eda14cbcSMatt Macy 3281eda14cbcSMatt Macy int 3282eda14cbcSMatt Macy zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 3283eda14cbcSMatt Macy uint64_t *propvalue) 3284eda14cbcSMatt Macy { 3285eda14cbcSMatt Macy zfs_userquota_prop_t type; 3286eda14cbcSMatt Macy 3287eda14cbcSMatt Macy return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 3288eda14cbcSMatt Macy &type)); 3289eda14cbcSMatt Macy } 3290eda14cbcSMatt Macy 3291eda14cbcSMatt Macy int 3292eda14cbcSMatt Macy zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 3293eda14cbcSMatt Macy char *propbuf, int proplen, boolean_t literal) 3294eda14cbcSMatt Macy { 3295eda14cbcSMatt Macy int err; 3296eda14cbcSMatt Macy uint64_t propvalue; 3297eda14cbcSMatt Macy zfs_userquota_prop_t type; 3298eda14cbcSMatt Macy 3299eda14cbcSMatt Macy err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 3300eda14cbcSMatt Macy &type); 3301eda14cbcSMatt Macy 3302eda14cbcSMatt Macy if (err) 3303eda14cbcSMatt Macy return (err); 3304eda14cbcSMatt Macy 3305eda14cbcSMatt Macy if (literal) { 3306eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 3307eda14cbcSMatt Macy (u_longlong_t)propvalue); 3308eda14cbcSMatt Macy } else if (propvalue == 0 && 3309eda14cbcSMatt Macy (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA || 3310eda14cbcSMatt Macy type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA || 3311eda14cbcSMatt Macy type == ZFS_PROP_PROJECTQUOTA || 3312eda14cbcSMatt Macy type == ZFS_PROP_PROJECTOBJQUOTA)) { 3313eda14cbcSMatt Macy (void) strlcpy(propbuf, "none", proplen); 3314eda14cbcSMatt Macy } else if (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA || 3315eda14cbcSMatt Macy type == ZFS_PROP_USERUSED || type == ZFS_PROP_GROUPUSED || 3316eda14cbcSMatt Macy type == ZFS_PROP_PROJECTUSED || type == ZFS_PROP_PROJECTQUOTA) { 3317eda14cbcSMatt Macy zfs_nicebytes(propvalue, propbuf, proplen); 3318eda14cbcSMatt Macy } else { 3319eda14cbcSMatt Macy zfs_nicenum(propvalue, propbuf, proplen); 3320eda14cbcSMatt Macy } 3321eda14cbcSMatt Macy return (0); 3322eda14cbcSMatt Macy } 3323eda14cbcSMatt Macy 3324eda14cbcSMatt Macy /* 3325eda14cbcSMatt Macy * propname must start with "written@" or "written#". 3326eda14cbcSMatt Macy */ 3327eda14cbcSMatt Macy int 3328eda14cbcSMatt Macy zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 3329eda14cbcSMatt Macy uint64_t *propvalue) 3330eda14cbcSMatt Macy { 3331eda14cbcSMatt Macy int err; 3332eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 3333eda14cbcSMatt Macy const char *snapname; 3334eda14cbcSMatt Macy 3335eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3336eda14cbcSMatt Macy 3337eda14cbcSMatt Macy assert(zfs_prop_written(propname)); 3338eda14cbcSMatt Macy snapname = propname + strlen("written@"); 3339eda14cbcSMatt Macy if (strchr(snapname, '@') != NULL || strchr(snapname, '#') != NULL) { 3340eda14cbcSMatt Macy /* full snapshot or bookmark name specified */ 3341eda14cbcSMatt Macy (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3342eda14cbcSMatt Macy } else { 3343eda14cbcSMatt Macy /* snapname is the short name, append it to zhp's fsname */ 3344eda14cbcSMatt Macy char *cp; 3345eda14cbcSMatt Macy 3346eda14cbcSMatt Macy (void) strlcpy(zc.zc_value, zhp->zfs_name, 3347eda14cbcSMatt Macy sizeof (zc.zc_value)); 3348eda14cbcSMatt Macy cp = strchr(zc.zc_value, '@'); 3349eda14cbcSMatt Macy if (cp != NULL) 3350eda14cbcSMatt Macy *cp = '\0'; 3351eda14cbcSMatt Macy (void) strlcat(zc.zc_value, snapname - 1, sizeof (zc.zc_value)); 3352eda14cbcSMatt Macy } 3353eda14cbcSMatt Macy 3354eda14cbcSMatt Macy err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SPACE_WRITTEN, &zc); 3355eda14cbcSMatt Macy if (err) 3356eda14cbcSMatt Macy return (err); 3357eda14cbcSMatt Macy 3358eda14cbcSMatt Macy *propvalue = zc.zc_cookie; 3359eda14cbcSMatt Macy return (0); 3360eda14cbcSMatt Macy } 3361eda14cbcSMatt Macy 3362eda14cbcSMatt Macy int 3363eda14cbcSMatt Macy zfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 3364eda14cbcSMatt Macy char *propbuf, int proplen, boolean_t literal) 3365eda14cbcSMatt Macy { 3366eda14cbcSMatt Macy int err; 3367eda14cbcSMatt Macy uint64_t propvalue; 3368eda14cbcSMatt Macy 3369eda14cbcSMatt Macy err = zfs_prop_get_written_int(zhp, propname, &propvalue); 3370eda14cbcSMatt Macy 3371eda14cbcSMatt Macy if (err) 3372eda14cbcSMatt Macy return (err); 3373eda14cbcSMatt Macy 3374eda14cbcSMatt Macy if (literal) { 3375eda14cbcSMatt Macy (void) snprintf(propbuf, proplen, "%llu", 3376eda14cbcSMatt Macy (u_longlong_t)propvalue); 3377eda14cbcSMatt Macy } else { 3378eda14cbcSMatt Macy zfs_nicebytes(propvalue, propbuf, proplen); 3379eda14cbcSMatt Macy } 3380eda14cbcSMatt Macy 3381eda14cbcSMatt Macy return (0); 3382eda14cbcSMatt Macy } 3383eda14cbcSMatt Macy 3384eda14cbcSMatt Macy /* 3385eda14cbcSMatt Macy * Returns the name of the given zfs handle. 3386eda14cbcSMatt Macy */ 3387eda14cbcSMatt Macy const char * 3388eda14cbcSMatt Macy zfs_get_name(const zfs_handle_t *zhp) 3389eda14cbcSMatt Macy { 3390eda14cbcSMatt Macy return (zhp->zfs_name); 3391eda14cbcSMatt Macy } 3392eda14cbcSMatt Macy 3393eda14cbcSMatt Macy /* 3394eda14cbcSMatt Macy * Returns the name of the parent pool for the given zfs handle. 3395eda14cbcSMatt Macy */ 3396eda14cbcSMatt Macy const char * 3397eda14cbcSMatt Macy zfs_get_pool_name(const zfs_handle_t *zhp) 3398eda14cbcSMatt Macy { 3399eda14cbcSMatt Macy return (zhp->zpool_hdl->zpool_name); 3400eda14cbcSMatt Macy } 3401eda14cbcSMatt Macy 3402eda14cbcSMatt Macy /* 3403eda14cbcSMatt Macy * Returns the type of the given zfs handle. 3404eda14cbcSMatt Macy */ 3405eda14cbcSMatt Macy zfs_type_t 3406eda14cbcSMatt Macy zfs_get_type(const zfs_handle_t *zhp) 3407eda14cbcSMatt Macy { 3408eda14cbcSMatt Macy return (zhp->zfs_type); 3409eda14cbcSMatt Macy } 3410eda14cbcSMatt Macy 3411eda14cbcSMatt Macy /* 341216038816SMartin Matuska * Returns the type of the given zfs handle, 341316038816SMartin Matuska * or, if a snapshot, the type of the snapshotted dataset. 341416038816SMartin Matuska */ 341516038816SMartin Matuska zfs_type_t 341616038816SMartin Matuska zfs_get_underlying_type(const zfs_handle_t *zhp) 341716038816SMartin Matuska { 341816038816SMartin Matuska return (zhp->zfs_head_type); 341916038816SMartin Matuska } 342016038816SMartin Matuska 342116038816SMartin Matuska /* 3422eda14cbcSMatt Macy * Is one dataset name a child dataset of another? 3423eda14cbcSMatt Macy * 3424eda14cbcSMatt Macy * Needs to handle these cases: 3425eda14cbcSMatt Macy * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 3426eda14cbcSMatt Macy * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 3427eda14cbcSMatt Macy * Descendant? No. No. No. Yes. 3428eda14cbcSMatt Macy */ 3429eda14cbcSMatt Macy static boolean_t 3430eda14cbcSMatt Macy is_descendant(const char *ds1, const char *ds2) 3431eda14cbcSMatt Macy { 3432eda14cbcSMatt Macy size_t d1len = strlen(ds1); 3433eda14cbcSMatt Macy 3434eda14cbcSMatt Macy /* ds2 can't be a descendant if it's smaller */ 3435eda14cbcSMatt Macy if (strlen(ds2) < d1len) 3436eda14cbcSMatt Macy return (B_FALSE); 3437eda14cbcSMatt Macy 3438eda14cbcSMatt Macy /* otherwise, compare strings and verify that there's a '/' char */ 3439eda14cbcSMatt Macy return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 3440eda14cbcSMatt Macy } 3441eda14cbcSMatt Macy 3442eda14cbcSMatt Macy /* 3443eda14cbcSMatt Macy * Given a complete name, return just the portion that refers to the parent. 3444eda14cbcSMatt Macy * Will return -1 if there is no parent (path is just the name of the 3445eda14cbcSMatt Macy * pool). 3446eda14cbcSMatt Macy */ 3447eda14cbcSMatt Macy static int 3448eda14cbcSMatt Macy parent_name(const char *path, char *buf, size_t buflen) 3449eda14cbcSMatt Macy { 3450eda14cbcSMatt Macy char *slashp; 3451eda14cbcSMatt Macy 3452eda14cbcSMatt Macy (void) strlcpy(buf, path, buflen); 3453eda14cbcSMatt Macy 3454eda14cbcSMatt Macy if ((slashp = strrchr(buf, '/')) == NULL) 3455eda14cbcSMatt Macy return (-1); 3456eda14cbcSMatt Macy *slashp = '\0'; 3457eda14cbcSMatt Macy 3458eda14cbcSMatt Macy return (0); 3459eda14cbcSMatt Macy } 3460eda14cbcSMatt Macy 3461eda14cbcSMatt Macy int 3462eda14cbcSMatt Macy zfs_parent_name(zfs_handle_t *zhp, char *buf, size_t buflen) 3463eda14cbcSMatt Macy { 3464eda14cbcSMatt Macy return (parent_name(zfs_get_name(zhp), buf, buflen)); 3465eda14cbcSMatt Macy } 3466eda14cbcSMatt Macy 3467eda14cbcSMatt Macy /* 3468eda14cbcSMatt Macy * If accept_ancestor is false, then check to make sure that the given path has 3469eda14cbcSMatt Macy * a parent, and that it exists. If accept_ancestor is true, then find the 3470eda14cbcSMatt Macy * closest existing ancestor for the given path. In prefixlen return the 3471eda14cbcSMatt Macy * length of already existing prefix of the given path. We also fetch the 3472eda14cbcSMatt Macy * 'zoned' property, which is used to validate property settings when creating 3473eda14cbcSMatt Macy * new datasets. 3474eda14cbcSMatt Macy */ 3475eda14cbcSMatt Macy static int 3476eda14cbcSMatt Macy check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 3477eda14cbcSMatt Macy boolean_t accept_ancestor, int *prefixlen) 3478eda14cbcSMatt Macy { 3479eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 3480eda14cbcSMatt Macy char parent[ZFS_MAX_DATASET_NAME_LEN]; 3481eda14cbcSMatt Macy char *slash; 3482eda14cbcSMatt Macy zfs_handle_t *zhp; 34831f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 3484eda14cbcSMatt Macy uint64_t is_zoned; 3485eda14cbcSMatt Macy 3486eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 3487eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 3488eda14cbcSMatt Macy 3489eda14cbcSMatt Macy /* get parent, and check to see if this is just a pool */ 3490eda14cbcSMatt Macy if (parent_name(path, parent, sizeof (parent)) != 0) { 3491eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3492eda14cbcSMatt Macy "missing dataset name")); 3493eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3494eda14cbcSMatt Macy } 3495eda14cbcSMatt Macy 3496eda14cbcSMatt Macy /* check to see if the pool exists */ 3497eda14cbcSMatt Macy if ((slash = strchr(parent, '/')) == NULL) 3498eda14cbcSMatt Macy slash = parent + strlen(parent); 3499be181ee2SMartin Matuska (void) strlcpy(zc.zc_name, parent, 3500be181ee2SMartin Matuska MIN(sizeof (zc.zc_name), slash - parent + 1)); 3501eda14cbcSMatt Macy if (zfs_ioctl(hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 3502eda14cbcSMatt Macy errno == ENOENT) { 3503eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3504eda14cbcSMatt Macy "no such pool '%s'"), zc.zc_name); 3505eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3506eda14cbcSMatt Macy } 3507eda14cbcSMatt Macy 3508eda14cbcSMatt Macy /* check to see if the parent dataset exists */ 3509eda14cbcSMatt Macy while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 3510eda14cbcSMatt Macy if (errno == ENOENT && accept_ancestor) { 3511eda14cbcSMatt Macy /* 3512eda14cbcSMatt Macy * Go deeper to find an ancestor, give up on top level. 3513eda14cbcSMatt Macy */ 3514eda14cbcSMatt Macy if (parent_name(parent, parent, sizeof (parent)) != 0) { 3515eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3516eda14cbcSMatt Macy "no such pool '%s'"), zc.zc_name); 3517eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3518eda14cbcSMatt Macy } 3519eda14cbcSMatt Macy } else if (errno == ENOENT) { 3520eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3521eda14cbcSMatt Macy "parent does not exist")); 3522eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3523eda14cbcSMatt Macy } else 3524eda14cbcSMatt Macy return (zfs_standard_error(hdl, errno, errbuf)); 3525eda14cbcSMatt Macy } 3526eda14cbcSMatt Macy 3527eda14cbcSMatt Macy is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 3528eda14cbcSMatt Macy if (zoned != NULL) 3529eda14cbcSMatt Macy *zoned = is_zoned; 3530eda14cbcSMatt Macy 3531eda14cbcSMatt Macy /* we are in a non-global zone, but parent is in the global zone */ 3532eda14cbcSMatt Macy if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 3533eda14cbcSMatt Macy (void) zfs_standard_error(hdl, EPERM, errbuf); 3534eda14cbcSMatt Macy zfs_close(zhp); 3535eda14cbcSMatt Macy return (-1); 3536eda14cbcSMatt Macy } 3537eda14cbcSMatt Macy 3538eda14cbcSMatt Macy /* make sure parent is a filesystem */ 3539eda14cbcSMatt Macy if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 3540eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3541eda14cbcSMatt Macy "parent is not a filesystem")); 3542eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3543eda14cbcSMatt Macy zfs_close(zhp); 3544eda14cbcSMatt Macy return (-1); 3545eda14cbcSMatt Macy } 3546eda14cbcSMatt Macy 3547eda14cbcSMatt Macy zfs_close(zhp); 3548eda14cbcSMatt Macy if (prefixlen != NULL) 3549eda14cbcSMatt Macy *prefixlen = strlen(parent); 3550eda14cbcSMatt Macy return (0); 3551eda14cbcSMatt Macy } 3552eda14cbcSMatt Macy 3553eda14cbcSMatt Macy /* 3554eda14cbcSMatt Macy * Finds whether the dataset of the given type(s) exists. 3555eda14cbcSMatt Macy */ 3556eda14cbcSMatt Macy boolean_t 3557eda14cbcSMatt Macy zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 3558eda14cbcSMatt Macy { 3559eda14cbcSMatt Macy zfs_handle_t *zhp; 3560eda14cbcSMatt Macy 3561eda14cbcSMatt Macy if (!zfs_validate_name(hdl, path, types, B_FALSE)) 3562eda14cbcSMatt Macy return (B_FALSE); 3563eda14cbcSMatt Macy 3564eda14cbcSMatt Macy /* 3565eda14cbcSMatt Macy * Try to get stats for the dataset, which will tell us if it exists. 3566eda14cbcSMatt Macy */ 3567eda14cbcSMatt Macy if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 3568eda14cbcSMatt Macy int ds_type = zhp->zfs_type; 3569eda14cbcSMatt Macy 3570eda14cbcSMatt Macy zfs_close(zhp); 3571eda14cbcSMatt Macy if (types & ds_type) 3572eda14cbcSMatt Macy return (B_TRUE); 3573eda14cbcSMatt Macy } 3574eda14cbcSMatt Macy return (B_FALSE); 3575eda14cbcSMatt Macy } 3576eda14cbcSMatt Macy 3577eda14cbcSMatt Macy /* 3578eda14cbcSMatt Macy * Given a path to 'target', create all the ancestors between 3579eda14cbcSMatt Macy * the prefixlen portion of the path, and the target itself. 3580eda14cbcSMatt Macy * Fail if the initial prefixlen-ancestor does not already exist. 3581eda14cbcSMatt Macy */ 3582eda14cbcSMatt Macy int 3583eda14cbcSMatt Macy create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 3584eda14cbcSMatt Macy { 3585eda14cbcSMatt Macy zfs_handle_t *h; 3586eda14cbcSMatt Macy char *cp; 3587eda14cbcSMatt Macy const char *opname; 3588eda14cbcSMatt Macy 3589eda14cbcSMatt Macy /* make sure prefix exists */ 3590eda14cbcSMatt Macy cp = target + prefixlen; 3591eda14cbcSMatt Macy if (*cp != '/') { 3592eda14cbcSMatt Macy assert(strchr(cp, '/') == NULL); 3593eda14cbcSMatt Macy h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3594eda14cbcSMatt Macy } else { 3595eda14cbcSMatt Macy *cp = '\0'; 3596eda14cbcSMatt Macy h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3597eda14cbcSMatt Macy *cp = '/'; 3598eda14cbcSMatt Macy } 3599eda14cbcSMatt Macy if (h == NULL) 3600eda14cbcSMatt Macy return (-1); 3601eda14cbcSMatt Macy zfs_close(h); 3602eda14cbcSMatt Macy 3603eda14cbcSMatt Macy /* 3604eda14cbcSMatt Macy * Attempt to create, mount, and share any ancestor filesystems, 3605eda14cbcSMatt Macy * up to the prefixlen-long one. 3606eda14cbcSMatt Macy */ 3607eda14cbcSMatt Macy for (cp = target + prefixlen + 1; 3608eda14cbcSMatt Macy (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) { 3609eda14cbcSMatt Macy 3610eda14cbcSMatt Macy *cp = '\0'; 3611eda14cbcSMatt Macy 3612eda14cbcSMatt Macy h = make_dataset_handle(hdl, target); 3613eda14cbcSMatt Macy if (h) { 3614eda14cbcSMatt Macy /* it already exists, nothing to do here */ 3615eda14cbcSMatt Macy zfs_close(h); 3616eda14cbcSMatt Macy continue; 3617eda14cbcSMatt Macy } 3618eda14cbcSMatt Macy 3619eda14cbcSMatt Macy if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 3620eda14cbcSMatt Macy NULL) != 0) { 3621eda14cbcSMatt Macy opname = dgettext(TEXT_DOMAIN, "create"); 3622eda14cbcSMatt Macy goto ancestorerr; 3623eda14cbcSMatt Macy } 3624eda14cbcSMatt Macy 3625eda14cbcSMatt Macy h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3626eda14cbcSMatt Macy if (h == NULL) { 3627eda14cbcSMatt Macy opname = dgettext(TEXT_DOMAIN, "open"); 3628eda14cbcSMatt Macy goto ancestorerr; 3629eda14cbcSMatt Macy } 3630eda14cbcSMatt Macy 3631eda14cbcSMatt Macy if (zfs_mount(h, NULL, 0) != 0) { 3632eda14cbcSMatt Macy opname = dgettext(TEXT_DOMAIN, "mount"); 3633eda14cbcSMatt Macy goto ancestorerr; 3634eda14cbcSMatt Macy } 3635eda14cbcSMatt Macy 3636716fd348SMartin Matuska if (zfs_share(h, NULL) != 0) { 3637eda14cbcSMatt Macy opname = dgettext(TEXT_DOMAIN, "share"); 3638eda14cbcSMatt Macy goto ancestorerr; 3639eda14cbcSMatt Macy } 3640eda14cbcSMatt Macy 3641eda14cbcSMatt Macy zfs_close(h); 3642eda14cbcSMatt Macy } 3643716fd348SMartin Matuska zfs_commit_shares(NULL); 3644eda14cbcSMatt Macy 3645eda14cbcSMatt Macy return (0); 3646eda14cbcSMatt Macy 3647eda14cbcSMatt Macy ancestorerr: 3648eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3649eda14cbcSMatt Macy "failed to %s ancestor '%s'"), opname, target); 3650eda14cbcSMatt Macy return (-1); 3651eda14cbcSMatt Macy } 3652eda14cbcSMatt Macy 3653eda14cbcSMatt Macy /* 3654eda14cbcSMatt Macy * Creates non-existing ancestors of the given path. 3655eda14cbcSMatt Macy */ 3656eda14cbcSMatt Macy int 3657eda14cbcSMatt Macy zfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 3658eda14cbcSMatt Macy { 3659eda14cbcSMatt Macy int prefix; 3660eda14cbcSMatt Macy char *path_copy; 36611f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 3662eda14cbcSMatt Macy int rc = 0; 3663eda14cbcSMatt Macy 3664eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3665eda14cbcSMatt Macy "cannot create '%s'"), path); 3666eda14cbcSMatt Macy 3667eda14cbcSMatt Macy /* 3668eda14cbcSMatt Macy * Check that we are not passing the nesting limit 3669eda14cbcSMatt Macy * before we start creating any ancestors. 3670eda14cbcSMatt Macy */ 3671eda14cbcSMatt Macy if (dataset_nestcheck(path) != 0) { 3672eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3673eda14cbcSMatt Macy "maximum name nesting depth exceeded")); 3674eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3675eda14cbcSMatt Macy } 3676eda14cbcSMatt Macy 3677eda14cbcSMatt Macy if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 3678eda14cbcSMatt Macy return (-1); 3679eda14cbcSMatt Macy 3680eda14cbcSMatt Macy if ((path_copy = strdup(path)) != NULL) { 3681eda14cbcSMatt Macy rc = create_parents(hdl, path_copy, prefix); 3682eda14cbcSMatt Macy free(path_copy); 3683eda14cbcSMatt Macy } 3684eda14cbcSMatt Macy if (path_copy == NULL || rc != 0) 3685eda14cbcSMatt Macy return (-1); 3686eda14cbcSMatt Macy 3687eda14cbcSMatt Macy return (0); 3688eda14cbcSMatt Macy } 3689eda14cbcSMatt Macy 3690eda14cbcSMatt Macy /* 3691eda14cbcSMatt Macy * Create a new filesystem or volume. 3692eda14cbcSMatt Macy */ 3693eda14cbcSMatt Macy int 3694eda14cbcSMatt Macy zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 3695eda14cbcSMatt Macy nvlist_t *props) 3696eda14cbcSMatt Macy { 3697eda14cbcSMatt Macy int ret; 3698eda14cbcSMatt Macy uint64_t size = 0; 3699eda14cbcSMatt Macy uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 3700eda14cbcSMatt Macy uint64_t zoned; 3701eda14cbcSMatt Macy enum lzc_dataset_type ost; 3702eda14cbcSMatt Macy zpool_handle_t *zpool_handle; 3703eda14cbcSMatt Macy uint8_t *wkeydata = NULL; 3704eda14cbcSMatt Macy uint_t wkeylen = 0; 37051f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 3706eda14cbcSMatt Macy char parent[ZFS_MAX_DATASET_NAME_LEN]; 3707eda14cbcSMatt Macy 3708eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3709eda14cbcSMatt Macy "cannot create '%s'"), path); 3710eda14cbcSMatt Macy 3711eda14cbcSMatt Macy /* validate the path, taking care to note the extended error message */ 3712eda14cbcSMatt Macy if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3713eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3714eda14cbcSMatt Macy 3715eda14cbcSMatt Macy if (dataset_nestcheck(path) != 0) { 3716eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3717eda14cbcSMatt Macy "maximum name nesting depth exceeded")); 3718eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3719eda14cbcSMatt Macy } 3720eda14cbcSMatt Macy 3721eda14cbcSMatt Macy /* validate parents exist */ 3722eda14cbcSMatt Macy if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3723eda14cbcSMatt Macy return (-1); 3724eda14cbcSMatt Macy 3725eda14cbcSMatt Macy /* 3726eda14cbcSMatt Macy * The failure modes when creating a dataset of a different type over 3727eda14cbcSMatt Macy * one that already exists is a little strange. In particular, if you 3728eda14cbcSMatt Macy * try to create a dataset on top of an existing dataset, the ioctl() 3729eda14cbcSMatt Macy * will return ENOENT, not EEXIST. To prevent this from happening, we 3730eda14cbcSMatt Macy * first try to see if the dataset exists. 3731eda14cbcSMatt Macy */ 3732eda14cbcSMatt Macy if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3733eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3734eda14cbcSMatt Macy "dataset already exists")); 3735eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3736eda14cbcSMatt Macy } 3737eda14cbcSMatt Macy 3738eda14cbcSMatt Macy if (type == ZFS_TYPE_VOLUME) 3739eda14cbcSMatt Macy ost = LZC_DATSET_TYPE_ZVOL; 3740eda14cbcSMatt Macy else 3741eda14cbcSMatt Macy ost = LZC_DATSET_TYPE_ZFS; 3742eda14cbcSMatt Macy 3743eda14cbcSMatt Macy /* open zpool handle for prop validation */ 3744eda14cbcSMatt Macy char pool_path[ZFS_MAX_DATASET_NAME_LEN]; 3745eda14cbcSMatt Macy (void) strlcpy(pool_path, path, sizeof (pool_path)); 3746eda14cbcSMatt Macy 3747eda14cbcSMatt Macy /* truncate pool_path at first slash */ 3748eda14cbcSMatt Macy char *p = strchr(pool_path, '/'); 3749eda14cbcSMatt Macy if (p != NULL) 3750eda14cbcSMatt Macy *p = '\0'; 3751eda14cbcSMatt Macy 3752eda14cbcSMatt Macy if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL) 3753eda14cbcSMatt Macy return (-1); 3754eda14cbcSMatt Macy 3755eda14cbcSMatt Macy if (props && (props = zfs_valid_proplist(hdl, type, props, 3756eda14cbcSMatt Macy zoned, NULL, zpool_handle, B_TRUE, errbuf)) == 0) { 3757eda14cbcSMatt Macy zpool_close(zpool_handle); 3758eda14cbcSMatt Macy return (-1); 3759eda14cbcSMatt Macy } 3760eda14cbcSMatt Macy zpool_close(zpool_handle); 3761eda14cbcSMatt Macy 3762eda14cbcSMatt Macy if (type == ZFS_TYPE_VOLUME) { 3763eda14cbcSMatt Macy /* 3764eda14cbcSMatt Macy * If we are creating a volume, the size and block size must 3765eda14cbcSMatt Macy * satisfy a few restraints. First, the blocksize must be a 3766eda14cbcSMatt Macy * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3767eda14cbcSMatt Macy * volsize must be a multiple of the block size, and cannot be 3768eda14cbcSMatt Macy * zero. 3769eda14cbcSMatt Macy */ 3770eda14cbcSMatt Macy if (props == NULL || nvlist_lookup_uint64(props, 3771eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3772eda14cbcSMatt Macy nvlist_free(props); 3773eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3774eda14cbcSMatt Macy "missing volume size")); 3775eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3776eda14cbcSMatt Macy } 3777eda14cbcSMatt Macy 3778eda14cbcSMatt Macy if ((ret = nvlist_lookup_uint64(props, 3779eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3780eda14cbcSMatt Macy &blocksize)) != 0) { 3781eda14cbcSMatt Macy if (ret == ENOENT) { 3782eda14cbcSMatt Macy blocksize = zfs_prop_default_numeric( 3783eda14cbcSMatt Macy ZFS_PROP_VOLBLOCKSIZE); 3784eda14cbcSMatt Macy } else { 3785eda14cbcSMatt Macy nvlist_free(props); 3786eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3787eda14cbcSMatt Macy "missing volume block size")); 3788eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3789eda14cbcSMatt Macy } 3790eda14cbcSMatt Macy } 3791eda14cbcSMatt Macy 3792eda14cbcSMatt Macy if (size == 0) { 3793eda14cbcSMatt Macy nvlist_free(props); 3794eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3795eda14cbcSMatt Macy "volume size cannot be zero")); 3796eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3797eda14cbcSMatt Macy } 3798eda14cbcSMatt Macy 3799eda14cbcSMatt Macy if (size % blocksize != 0) { 3800eda14cbcSMatt Macy nvlist_free(props); 3801eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3802eda14cbcSMatt Macy "volume size must be a multiple of volume block " 3803eda14cbcSMatt Macy "size")); 3804eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3805eda14cbcSMatt Macy } 3806eda14cbcSMatt Macy } 3807eda14cbcSMatt Macy 3808eda14cbcSMatt Macy (void) parent_name(path, parent, sizeof (parent)); 3809eda14cbcSMatt Macy if (zfs_crypto_create(hdl, parent, props, NULL, B_TRUE, 3810eda14cbcSMatt Macy &wkeydata, &wkeylen) != 0) { 3811eda14cbcSMatt Macy nvlist_free(props); 3812eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf)); 3813eda14cbcSMatt Macy } 3814eda14cbcSMatt Macy 3815eda14cbcSMatt Macy /* create the dataset */ 3816eda14cbcSMatt Macy ret = lzc_create(path, ost, props, wkeydata, wkeylen); 3817eda14cbcSMatt Macy nvlist_free(props); 3818eda14cbcSMatt Macy if (wkeydata != NULL) 3819eda14cbcSMatt Macy free(wkeydata); 3820eda14cbcSMatt Macy 3821eda14cbcSMatt Macy /* check for failure */ 3822eda14cbcSMatt Macy if (ret != 0) { 3823eda14cbcSMatt Macy switch (errno) { 3824eda14cbcSMatt Macy case ENOENT: 3825eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3826eda14cbcSMatt Macy "no such parent '%s'"), parent); 3827eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3828eda14cbcSMatt Macy 3829eda14cbcSMatt Macy case ENOTSUP: 3830eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3831eda14cbcSMatt Macy "pool must be upgraded to set this " 3832eda14cbcSMatt Macy "property or value")); 3833eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3834eda14cbcSMatt Macy 3835eda14cbcSMatt Macy case EACCES: 3836eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3837eda14cbcSMatt Macy "encryption root's key is not loaded " 3838eda14cbcSMatt Macy "or provided")); 3839eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf)); 3840eda14cbcSMatt Macy 3841eda14cbcSMatt Macy case ERANGE: 3842eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3843eda14cbcSMatt Macy "invalid property value(s) specified")); 3844eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3845eda14cbcSMatt Macy #ifdef _ILP32 3846eda14cbcSMatt Macy case EOVERFLOW: 3847eda14cbcSMatt Macy /* 3848eda14cbcSMatt Macy * This platform can't address a volume this big. 3849eda14cbcSMatt Macy */ 3850eda14cbcSMatt Macy if (type == ZFS_TYPE_VOLUME) 3851eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_VOLTOOBIG, 3852eda14cbcSMatt Macy errbuf)); 3853c03c5b1cSMartin Matuska zfs_fallthrough; 3854eda14cbcSMatt Macy #endif 3855eda14cbcSMatt Macy default: 3856eda14cbcSMatt Macy return (zfs_standard_error(hdl, errno, errbuf)); 3857eda14cbcSMatt Macy } 3858eda14cbcSMatt Macy } 3859eda14cbcSMatt Macy 3860eda14cbcSMatt Macy return (0); 3861eda14cbcSMatt Macy } 3862eda14cbcSMatt Macy 3863eda14cbcSMatt Macy /* 3864eda14cbcSMatt Macy * Destroys the given dataset. The caller must make sure that the filesystem 3865eda14cbcSMatt Macy * isn't mounted, and that there are no active dependents. If the file system 3866eda14cbcSMatt Macy * does not exist this function does nothing. 3867eda14cbcSMatt Macy */ 3868eda14cbcSMatt Macy int 3869eda14cbcSMatt Macy zfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3870eda14cbcSMatt Macy { 3871eda14cbcSMatt Macy int error; 3872eda14cbcSMatt Macy 3873eda14cbcSMatt Macy if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && defer) 3874eda14cbcSMatt Macy return (EINVAL); 3875eda14cbcSMatt Macy 3876eda14cbcSMatt Macy if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 3877eda14cbcSMatt Macy nvlist_t *nv = fnvlist_alloc(); 3878eda14cbcSMatt Macy fnvlist_add_boolean(nv, zhp->zfs_name); 3879eda14cbcSMatt Macy error = lzc_destroy_bookmarks(nv, NULL); 3880eda14cbcSMatt Macy fnvlist_free(nv); 3881eda14cbcSMatt Macy if (error != 0) { 3882eda14cbcSMatt Macy return (zfs_standard_error_fmt(zhp->zfs_hdl, error, 3883eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3884eda14cbcSMatt Macy zhp->zfs_name)); 3885eda14cbcSMatt Macy } 3886eda14cbcSMatt Macy return (0); 3887eda14cbcSMatt Macy } 3888eda14cbcSMatt Macy 3889eda14cbcSMatt Macy if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3890eda14cbcSMatt Macy nvlist_t *nv = fnvlist_alloc(); 3891eda14cbcSMatt Macy fnvlist_add_boolean(nv, zhp->zfs_name); 3892eda14cbcSMatt Macy error = lzc_destroy_snaps(nv, defer, NULL); 3893eda14cbcSMatt Macy fnvlist_free(nv); 3894eda14cbcSMatt Macy } else { 3895eda14cbcSMatt Macy error = lzc_destroy(zhp->zfs_name); 3896eda14cbcSMatt Macy } 3897eda14cbcSMatt Macy 3898eda14cbcSMatt Macy if (error != 0 && error != ENOENT) { 3899eda14cbcSMatt Macy return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3900eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3901eda14cbcSMatt Macy zhp->zfs_name)); 3902eda14cbcSMatt Macy } 3903eda14cbcSMatt Macy 3904eda14cbcSMatt Macy remove_mountpoint(zhp); 3905eda14cbcSMatt Macy 3906eda14cbcSMatt Macy return (0); 3907eda14cbcSMatt Macy } 3908eda14cbcSMatt Macy 3909eda14cbcSMatt Macy struct destroydata { 3910eda14cbcSMatt Macy nvlist_t *nvl; 3911eda14cbcSMatt Macy const char *snapname; 3912eda14cbcSMatt Macy }; 3913eda14cbcSMatt Macy 3914eda14cbcSMatt Macy static int 3915eda14cbcSMatt Macy zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3916eda14cbcSMatt Macy { 3917eda14cbcSMatt Macy struct destroydata *dd = arg; 3918eda14cbcSMatt Macy char name[ZFS_MAX_DATASET_NAME_LEN]; 3919eda14cbcSMatt Macy int rv = 0; 3920eda14cbcSMatt Macy 3921eda14cbcSMatt Macy if (snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, 3922eda14cbcSMatt Macy dd->snapname) >= sizeof (name)) 3923eda14cbcSMatt Macy return (EINVAL); 3924eda14cbcSMatt Macy 3925eda14cbcSMatt Macy if (lzc_exists(name)) 3926da5137abSMartin Matuska fnvlist_add_boolean(dd->nvl, name); 3927eda14cbcSMatt Macy 3928*15f0b8c3SMartin Matuska rv = zfs_iter_filesystems(zhp, 0, zfs_check_snap_cb, dd); 3929eda14cbcSMatt Macy zfs_close(zhp); 3930eda14cbcSMatt Macy return (rv); 3931eda14cbcSMatt Macy } 3932eda14cbcSMatt Macy 3933eda14cbcSMatt Macy /* 3934eda14cbcSMatt Macy * Destroys all snapshots with the given name in zhp & descendants. 3935eda14cbcSMatt Macy */ 3936eda14cbcSMatt Macy int 3937eda14cbcSMatt Macy zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3938eda14cbcSMatt Macy { 3939eda14cbcSMatt Macy int ret; 3940eda14cbcSMatt Macy struct destroydata dd = { 0 }; 3941eda14cbcSMatt Macy 3942eda14cbcSMatt Macy dd.snapname = snapname; 3943da5137abSMartin Matuska dd.nvl = fnvlist_alloc(); 3944eda14cbcSMatt Macy (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3945eda14cbcSMatt Macy 3946eda14cbcSMatt Macy if (nvlist_empty(dd.nvl)) { 3947eda14cbcSMatt Macy ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3948eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3949eda14cbcSMatt Macy zhp->zfs_name, snapname); 3950eda14cbcSMatt Macy } else { 3951eda14cbcSMatt Macy ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3952eda14cbcSMatt Macy } 3953da5137abSMartin Matuska fnvlist_free(dd.nvl); 3954eda14cbcSMatt Macy return (ret); 3955eda14cbcSMatt Macy } 3956eda14cbcSMatt Macy 3957eda14cbcSMatt Macy /* 3958eda14cbcSMatt Macy * Destroys all the snapshots named in the nvlist. 3959eda14cbcSMatt Macy */ 3960eda14cbcSMatt Macy int 3961eda14cbcSMatt Macy zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3962eda14cbcSMatt Macy { 3963eda14cbcSMatt Macy nvlist_t *errlist = NULL; 3964eda14cbcSMatt Macy nvpair_t *pair; 3965eda14cbcSMatt Macy 39666ba2210eSMartin Matuska int ret = zfs_destroy_snaps_nvl_os(hdl, snaps); 39676ba2210eSMartin Matuska if (ret != 0) 39686ba2210eSMartin Matuska return (ret); 39696ba2210eSMartin Matuska 3970eda14cbcSMatt Macy ret = lzc_destroy_snaps(snaps, defer, &errlist); 3971eda14cbcSMatt Macy 3972eda14cbcSMatt Macy if (ret == 0) { 3973eda14cbcSMatt Macy nvlist_free(errlist); 3974eda14cbcSMatt Macy return (0); 3975eda14cbcSMatt Macy } 3976eda14cbcSMatt Macy 3977eda14cbcSMatt Macy if (nvlist_empty(errlist)) { 39781f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 3979eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 3980eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3981eda14cbcSMatt Macy 3982eda14cbcSMatt Macy ret = zfs_standard_error(hdl, ret, errbuf); 3983eda14cbcSMatt Macy } 3984eda14cbcSMatt Macy for (pair = nvlist_next_nvpair(errlist, NULL); 3985eda14cbcSMatt Macy pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 39861f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 3987eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 3988eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3989eda14cbcSMatt Macy nvpair_name(pair)); 3990eda14cbcSMatt Macy 3991eda14cbcSMatt Macy switch (fnvpair_value_int32(pair)) { 3992eda14cbcSMatt Macy case EEXIST: 3993eda14cbcSMatt Macy zfs_error_aux(hdl, 3994eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3995eda14cbcSMatt Macy ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3996eda14cbcSMatt Macy break; 3997eda14cbcSMatt Macy default: 3998eda14cbcSMatt Macy ret = zfs_standard_error(hdl, errno, errbuf); 3999eda14cbcSMatt Macy break; 4000eda14cbcSMatt Macy } 4001eda14cbcSMatt Macy } 4002eda14cbcSMatt Macy 4003eda14cbcSMatt Macy nvlist_free(errlist); 4004eda14cbcSMatt Macy return (ret); 4005eda14cbcSMatt Macy } 4006eda14cbcSMatt Macy 4007eda14cbcSMatt Macy /* 4008eda14cbcSMatt Macy * Clones the given dataset. The target must be of the same type as the source. 4009eda14cbcSMatt Macy */ 4010eda14cbcSMatt Macy int 4011eda14cbcSMatt Macy zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 4012eda14cbcSMatt Macy { 4013eda14cbcSMatt Macy char parent[ZFS_MAX_DATASET_NAME_LEN]; 4014eda14cbcSMatt Macy int ret; 40151f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4016eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 4017eda14cbcSMatt Macy uint64_t zoned; 4018eda14cbcSMatt Macy 4019eda14cbcSMatt Macy assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 4020eda14cbcSMatt Macy 4021eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4022eda14cbcSMatt Macy "cannot create '%s'"), target); 4023eda14cbcSMatt Macy 4024eda14cbcSMatt Macy /* validate the target/clone name */ 4025eda14cbcSMatt Macy if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 4026eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4027eda14cbcSMatt Macy 4028eda14cbcSMatt Macy /* validate parents exist */ 4029eda14cbcSMatt Macy if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 4030eda14cbcSMatt Macy return (-1); 4031eda14cbcSMatt Macy 4032eda14cbcSMatt Macy (void) parent_name(target, parent, sizeof (parent)); 4033eda14cbcSMatt Macy 4034eda14cbcSMatt Macy /* do the clone */ 4035eda14cbcSMatt Macy 4036eda14cbcSMatt Macy if (props) { 4037c03c5b1cSMartin Matuska zfs_type_t type = ZFS_TYPE_FILESYSTEM; 4038eda14cbcSMatt Macy 4039c03c5b1cSMartin Matuska if (ZFS_IS_VOLUME(zhp)) 4040eda14cbcSMatt Macy type = ZFS_TYPE_VOLUME; 4041eda14cbcSMatt Macy if ((props = zfs_valid_proplist(hdl, type, props, zoned, 4042eda14cbcSMatt Macy zhp, zhp->zpool_hdl, B_TRUE, errbuf)) == NULL) 4043eda14cbcSMatt Macy return (-1); 4044eda14cbcSMatt Macy if (zfs_fix_auto_resv(zhp, props) == -1) { 4045eda14cbcSMatt Macy nvlist_free(props); 4046eda14cbcSMatt Macy return (-1); 4047eda14cbcSMatt Macy } 4048eda14cbcSMatt Macy } 4049eda14cbcSMatt Macy 4050eda14cbcSMatt Macy if (zfs_crypto_clone_check(hdl, zhp, parent, props) != 0) { 4051eda14cbcSMatt Macy nvlist_free(props); 4052eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf)); 4053eda14cbcSMatt Macy } 4054eda14cbcSMatt Macy 4055eda14cbcSMatt Macy ret = lzc_clone(target, zhp->zfs_name, props); 4056eda14cbcSMatt Macy nvlist_free(props); 4057eda14cbcSMatt Macy 4058eda14cbcSMatt Macy if (ret != 0) { 4059eda14cbcSMatt Macy switch (errno) { 4060eda14cbcSMatt Macy 4061eda14cbcSMatt Macy case ENOENT: 4062eda14cbcSMatt Macy /* 4063eda14cbcSMatt Macy * The parent doesn't exist. We should have caught this 4064eda14cbcSMatt Macy * above, but there may a race condition that has since 4065eda14cbcSMatt Macy * destroyed the parent. 4066eda14cbcSMatt Macy * 4067eda14cbcSMatt Macy * At this point, we don't know whether it's the source 4068eda14cbcSMatt Macy * that doesn't exist anymore, or whether the target 4069eda14cbcSMatt Macy * dataset doesn't exist. 4070eda14cbcSMatt Macy */ 4071eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4072eda14cbcSMatt Macy "no such parent '%s'"), parent); 4073eda14cbcSMatt Macy return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 4074eda14cbcSMatt Macy 4075eda14cbcSMatt Macy case EXDEV: 4076eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4077eda14cbcSMatt Macy "source and target pools differ")); 4078eda14cbcSMatt Macy return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 4079eda14cbcSMatt Macy errbuf)); 4080eda14cbcSMatt Macy 4081eda14cbcSMatt Macy default: 4082eda14cbcSMatt Macy return (zfs_standard_error(zhp->zfs_hdl, errno, 4083eda14cbcSMatt Macy errbuf)); 4084eda14cbcSMatt Macy } 4085eda14cbcSMatt Macy } 4086eda14cbcSMatt Macy 4087eda14cbcSMatt Macy return (ret); 4088eda14cbcSMatt Macy } 4089eda14cbcSMatt Macy 4090eda14cbcSMatt Macy /* 4091eda14cbcSMatt Macy * Promotes the given clone fs to be the clone parent. 4092eda14cbcSMatt Macy */ 4093eda14cbcSMatt Macy int 4094eda14cbcSMatt Macy zfs_promote(zfs_handle_t *zhp) 4095eda14cbcSMatt Macy { 4096eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 4097eda14cbcSMatt Macy char snapname[ZFS_MAX_DATASET_NAME_LEN]; 4098eda14cbcSMatt Macy int ret; 40991f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4100eda14cbcSMatt Macy 4101eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4102eda14cbcSMatt Macy "cannot promote '%s'"), zhp->zfs_name); 4103eda14cbcSMatt Macy 4104eda14cbcSMatt Macy if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 4105eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4106eda14cbcSMatt Macy "snapshots can not be promoted")); 4107eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4108eda14cbcSMatt Macy } 4109eda14cbcSMatt Macy 4110eda14cbcSMatt Macy if (zhp->zfs_dmustats.dds_origin[0] == '\0') { 4111eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4112eda14cbcSMatt Macy "not a cloned filesystem")); 4113eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4114eda14cbcSMatt Macy } 4115eda14cbcSMatt Macy 4116eda14cbcSMatt Macy if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE)) 4117eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4118eda14cbcSMatt Macy 4119eda14cbcSMatt Macy ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname)); 4120eda14cbcSMatt Macy 4121eda14cbcSMatt Macy if (ret != 0) { 4122eda14cbcSMatt Macy switch (ret) { 4123eda14cbcSMatt Macy case EACCES: 4124eda14cbcSMatt Macy /* 4125eda14cbcSMatt Macy * Promoting encrypted dataset outside its 4126eda14cbcSMatt Macy * encryption root. 4127eda14cbcSMatt Macy */ 4128eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4129eda14cbcSMatt Macy "cannot promote dataset outside its " 4130eda14cbcSMatt Macy "encryption root")); 4131eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 4132eda14cbcSMatt Macy 4133eda14cbcSMatt Macy case EEXIST: 4134eda14cbcSMatt Macy /* There is a conflicting snapshot name. */ 4135eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4136eda14cbcSMatt Macy "conflicting snapshot '%s' from parent '%s'"), 4137eda14cbcSMatt Macy snapname, zhp->zfs_dmustats.dds_origin); 4138eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 4139eda14cbcSMatt Macy 4140eda14cbcSMatt Macy default: 4141eda14cbcSMatt Macy return (zfs_standard_error(hdl, ret, errbuf)); 4142eda14cbcSMatt Macy } 4143eda14cbcSMatt Macy } 4144eda14cbcSMatt Macy return (ret); 4145eda14cbcSMatt Macy } 4146eda14cbcSMatt Macy 4147eda14cbcSMatt Macy typedef struct snapdata { 4148eda14cbcSMatt Macy nvlist_t *sd_nvl; 4149eda14cbcSMatt Macy const char *sd_snapname; 4150eda14cbcSMatt Macy } snapdata_t; 4151eda14cbcSMatt Macy 4152eda14cbcSMatt Macy static int 4153eda14cbcSMatt Macy zfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 4154eda14cbcSMatt Macy { 4155eda14cbcSMatt Macy snapdata_t *sd = arg; 4156eda14cbcSMatt Macy char name[ZFS_MAX_DATASET_NAME_LEN]; 4157eda14cbcSMatt Macy int rv = 0; 4158eda14cbcSMatt Macy 4159eda14cbcSMatt Macy if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 4160eda14cbcSMatt Macy if (snprintf(name, sizeof (name), "%s@%s", zfs_get_name(zhp), 4161eda14cbcSMatt Macy sd->sd_snapname) >= sizeof (name)) 4162eda14cbcSMatt Macy return (EINVAL); 4163eda14cbcSMatt Macy 4164eda14cbcSMatt Macy fnvlist_add_boolean(sd->sd_nvl, name); 4165eda14cbcSMatt Macy 4166*15f0b8c3SMartin Matuska rv = zfs_iter_filesystems(zhp, 0, zfs_snapshot_cb, sd); 4167eda14cbcSMatt Macy } 4168eda14cbcSMatt Macy zfs_close(zhp); 4169eda14cbcSMatt Macy 4170eda14cbcSMatt Macy return (rv); 4171eda14cbcSMatt Macy } 4172eda14cbcSMatt Macy 4173eda14cbcSMatt Macy /* 4174eda14cbcSMatt Macy * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 4175eda14cbcSMatt Macy * created. 4176eda14cbcSMatt Macy */ 4177eda14cbcSMatt Macy int 4178eda14cbcSMatt Macy zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 4179eda14cbcSMatt Macy { 4180eda14cbcSMatt Macy int ret; 41811f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4182eda14cbcSMatt Macy nvpair_t *elem; 4183eda14cbcSMatt Macy nvlist_t *errors; 4184eda14cbcSMatt Macy zpool_handle_t *zpool_hdl; 4185eda14cbcSMatt Macy char pool[ZFS_MAX_DATASET_NAME_LEN]; 4186eda14cbcSMatt Macy 4187eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4188eda14cbcSMatt Macy "cannot create snapshots ")); 4189eda14cbcSMatt Macy 4190eda14cbcSMatt Macy elem = NULL; 4191eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 4192eda14cbcSMatt Macy const char *snapname = nvpair_name(elem); 4193eda14cbcSMatt Macy 4194eda14cbcSMatt Macy /* validate the target name */ 4195eda14cbcSMatt Macy if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 4196eda14cbcSMatt Macy B_TRUE)) { 4197eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 4198eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 4199eda14cbcSMatt Macy "cannot create snapshot '%s'"), snapname); 4200eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4201eda14cbcSMatt Macy } 4202eda14cbcSMatt Macy } 4203eda14cbcSMatt Macy 4204eda14cbcSMatt Macy /* 4205eda14cbcSMatt Macy * get pool handle for prop validation. assumes all snaps are in the 4206eda14cbcSMatt Macy * same pool, as does lzc_snapshot (below). 4207eda14cbcSMatt Macy */ 4208eda14cbcSMatt Macy elem = nvlist_next_nvpair(snaps, NULL); 4209be181ee2SMartin Matuska if (elem == NULL) 4210be181ee2SMartin Matuska return (-1); 4211eda14cbcSMatt Macy (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); 4212eda14cbcSMatt Macy pool[strcspn(pool, "/@")] = '\0'; 4213eda14cbcSMatt Macy zpool_hdl = zpool_open(hdl, pool); 4214eda14cbcSMatt Macy if (zpool_hdl == NULL) 4215eda14cbcSMatt Macy return (-1); 4216eda14cbcSMatt Macy 4217eda14cbcSMatt Macy if (props != NULL && 4218eda14cbcSMatt Macy (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 4219eda14cbcSMatt Macy props, B_FALSE, NULL, zpool_hdl, B_FALSE, errbuf)) == NULL) { 4220eda14cbcSMatt Macy zpool_close(zpool_hdl); 4221eda14cbcSMatt Macy return (-1); 4222eda14cbcSMatt Macy } 4223eda14cbcSMatt Macy zpool_close(zpool_hdl); 4224eda14cbcSMatt Macy 4225eda14cbcSMatt Macy ret = lzc_snapshot(snaps, props, &errors); 4226eda14cbcSMatt Macy 4227eda14cbcSMatt Macy if (ret != 0) { 4228eda14cbcSMatt Macy boolean_t printed = B_FALSE; 4229eda14cbcSMatt Macy for (elem = nvlist_next_nvpair(errors, NULL); 4230eda14cbcSMatt Macy elem != NULL; 4231eda14cbcSMatt Macy elem = nvlist_next_nvpair(errors, elem)) { 4232eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 4233eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 4234eda14cbcSMatt Macy "cannot create snapshot '%s'"), nvpair_name(elem)); 4235eda14cbcSMatt Macy (void) zfs_standard_error(hdl, 4236eda14cbcSMatt Macy fnvpair_value_int32(elem), errbuf); 4237eda14cbcSMatt Macy printed = B_TRUE; 4238eda14cbcSMatt Macy } 4239eda14cbcSMatt Macy if (!printed) { 4240eda14cbcSMatt Macy switch (ret) { 4241eda14cbcSMatt Macy case EXDEV: 4242eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4243eda14cbcSMatt Macy "multiple snapshots of same " 4244eda14cbcSMatt Macy "fs not allowed")); 4245eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4246eda14cbcSMatt Macy 4247eda14cbcSMatt Macy break; 4248eda14cbcSMatt Macy default: 4249eda14cbcSMatt Macy (void) zfs_standard_error(hdl, ret, errbuf); 4250eda14cbcSMatt Macy } 4251eda14cbcSMatt Macy } 4252eda14cbcSMatt Macy } 4253eda14cbcSMatt Macy 4254eda14cbcSMatt Macy nvlist_free(props); 4255eda14cbcSMatt Macy nvlist_free(errors); 4256eda14cbcSMatt Macy return (ret); 4257eda14cbcSMatt Macy } 4258eda14cbcSMatt Macy 4259eda14cbcSMatt Macy int 4260eda14cbcSMatt Macy zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 4261eda14cbcSMatt Macy nvlist_t *props) 4262eda14cbcSMatt Macy { 4263eda14cbcSMatt Macy int ret; 4264eda14cbcSMatt Macy snapdata_t sd = { 0 }; 4265eda14cbcSMatt Macy char fsname[ZFS_MAX_DATASET_NAME_LEN]; 4266eda14cbcSMatt Macy char *cp; 4267eda14cbcSMatt Macy zfs_handle_t *zhp; 42681f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4269eda14cbcSMatt Macy 4270eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4271eda14cbcSMatt Macy "cannot snapshot %s"), path); 4272eda14cbcSMatt Macy 4273eda14cbcSMatt Macy if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 4274eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4275eda14cbcSMatt Macy 4276eda14cbcSMatt Macy (void) strlcpy(fsname, path, sizeof (fsname)); 4277eda14cbcSMatt Macy cp = strchr(fsname, '@'); 4278eda14cbcSMatt Macy *cp = '\0'; 4279eda14cbcSMatt Macy sd.sd_snapname = cp + 1; 4280eda14cbcSMatt Macy 4281eda14cbcSMatt Macy if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 4282eda14cbcSMatt Macy ZFS_TYPE_VOLUME)) == NULL) { 4283eda14cbcSMatt Macy return (-1); 4284eda14cbcSMatt Macy } 4285eda14cbcSMatt Macy 4286da5137abSMartin Matuska sd.sd_nvl = fnvlist_alloc(); 4287eda14cbcSMatt Macy if (recursive) { 4288eda14cbcSMatt Macy (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 4289eda14cbcSMatt Macy } else { 4290eda14cbcSMatt Macy fnvlist_add_boolean(sd.sd_nvl, path); 4291eda14cbcSMatt Macy } 4292eda14cbcSMatt Macy 4293eda14cbcSMatt Macy ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 4294da5137abSMartin Matuska fnvlist_free(sd.sd_nvl); 4295eda14cbcSMatt Macy zfs_close(zhp); 4296eda14cbcSMatt Macy return (ret); 4297eda14cbcSMatt Macy } 4298eda14cbcSMatt Macy 4299eda14cbcSMatt Macy /* 4300eda14cbcSMatt Macy * Destroy any more recent snapshots. We invoke this callback on any dependents 4301eda14cbcSMatt Macy * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 4302eda14cbcSMatt Macy * is a dependent and we should just destroy it without checking the transaction 4303eda14cbcSMatt Macy * group. 4304eda14cbcSMatt Macy */ 4305eda14cbcSMatt Macy typedef struct rollback_data { 4306eda14cbcSMatt Macy const char *cb_target; /* the snapshot */ 4307eda14cbcSMatt Macy uint64_t cb_create; /* creation time reference */ 4308eda14cbcSMatt Macy boolean_t cb_error; 4309eda14cbcSMatt Macy boolean_t cb_force; 4310eda14cbcSMatt Macy } rollback_data_t; 4311eda14cbcSMatt Macy 4312eda14cbcSMatt Macy static int 4313eda14cbcSMatt Macy rollback_destroy_dependent(zfs_handle_t *zhp, void *data) 4314eda14cbcSMatt Macy { 4315eda14cbcSMatt Macy rollback_data_t *cbp = data; 4316eda14cbcSMatt Macy prop_changelist_t *clp; 4317eda14cbcSMatt Macy 4318eda14cbcSMatt Macy /* We must destroy this clone; first unmount it */ 4319eda14cbcSMatt Macy clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 4320eda14cbcSMatt Macy cbp->cb_force ? MS_FORCE: 0); 4321eda14cbcSMatt Macy if (clp == NULL || changelist_prefix(clp) != 0) { 4322eda14cbcSMatt Macy cbp->cb_error = B_TRUE; 4323eda14cbcSMatt Macy zfs_close(zhp); 4324eda14cbcSMatt Macy return (0); 4325eda14cbcSMatt Macy } 4326eda14cbcSMatt Macy if (zfs_destroy(zhp, B_FALSE) != 0) 4327eda14cbcSMatt Macy cbp->cb_error = B_TRUE; 4328eda14cbcSMatt Macy else 4329eda14cbcSMatt Macy changelist_remove(clp, zhp->zfs_name); 4330eda14cbcSMatt Macy (void) changelist_postfix(clp); 4331eda14cbcSMatt Macy changelist_free(clp); 4332eda14cbcSMatt Macy 4333eda14cbcSMatt Macy zfs_close(zhp); 4334eda14cbcSMatt Macy return (0); 4335eda14cbcSMatt Macy } 4336eda14cbcSMatt Macy 4337eda14cbcSMatt Macy static int 4338eda14cbcSMatt Macy rollback_destroy(zfs_handle_t *zhp, void *data) 4339eda14cbcSMatt Macy { 4340eda14cbcSMatt Macy rollback_data_t *cbp = data; 4341eda14cbcSMatt Macy 4342eda14cbcSMatt Macy if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { 4343*15f0b8c3SMartin Matuska cbp->cb_error |= zfs_iter_dependents(zhp, 0, B_FALSE, 4344eda14cbcSMatt Macy rollback_destroy_dependent, cbp); 4345eda14cbcSMatt Macy 4346eda14cbcSMatt Macy cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 4347eda14cbcSMatt Macy } 4348eda14cbcSMatt Macy 4349eda14cbcSMatt Macy zfs_close(zhp); 4350eda14cbcSMatt Macy return (0); 4351eda14cbcSMatt Macy } 4352eda14cbcSMatt Macy 4353eda14cbcSMatt Macy /* 4354eda14cbcSMatt Macy * Given a dataset, rollback to a specific snapshot, discarding any 4355eda14cbcSMatt Macy * data changes since then and making it the active dataset. 4356eda14cbcSMatt Macy * 4357eda14cbcSMatt Macy * Any snapshots and bookmarks more recent than the target are 4358eda14cbcSMatt Macy * destroyed, along with their dependents (i.e. clones). 4359eda14cbcSMatt Macy */ 4360eda14cbcSMatt Macy int 4361eda14cbcSMatt Macy zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 4362eda14cbcSMatt Macy { 4363eda14cbcSMatt Macy rollback_data_t cb = { 0 }; 4364eda14cbcSMatt Macy int err; 4365eda14cbcSMatt Macy boolean_t restore_resv = 0; 4366eda14cbcSMatt Macy uint64_t old_volsize = 0, new_volsize; 4367eda14cbcSMatt Macy zfs_prop_t resv_prop = { 0 }; 4368eda14cbcSMatt Macy uint64_t min_txg = 0; 4369eda14cbcSMatt Macy 4370eda14cbcSMatt Macy assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 4371eda14cbcSMatt Macy zhp->zfs_type == ZFS_TYPE_VOLUME); 4372eda14cbcSMatt Macy 4373eda14cbcSMatt Macy /* 4374eda14cbcSMatt Macy * Destroy all recent snapshots and their dependents. 4375eda14cbcSMatt Macy */ 4376eda14cbcSMatt Macy cb.cb_force = force; 4377eda14cbcSMatt Macy cb.cb_target = snap->zfs_name; 4378eda14cbcSMatt Macy cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 4379eda14cbcSMatt Macy 4380eda14cbcSMatt Macy if (cb.cb_create > 0) 4381eda14cbcSMatt Macy min_txg = cb.cb_create; 4382eda14cbcSMatt Macy 4383*15f0b8c3SMartin Matuska (void) zfs_iter_snapshots(zhp, 0, rollback_destroy, &cb, 4384eda14cbcSMatt Macy min_txg, 0); 4385eda14cbcSMatt Macy 4386*15f0b8c3SMartin Matuska (void) zfs_iter_bookmarks(zhp, 0, rollback_destroy, &cb); 4387eda14cbcSMatt Macy 4388eda14cbcSMatt Macy if (cb.cb_error) 4389eda14cbcSMatt Macy return (-1); 4390eda14cbcSMatt Macy 4391eda14cbcSMatt Macy /* 4392eda14cbcSMatt Macy * Now that we have verified that the snapshot is the latest, 4393eda14cbcSMatt Macy * rollback to the given snapshot. 4394eda14cbcSMatt Macy */ 4395eda14cbcSMatt Macy 4396eda14cbcSMatt Macy if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 4397eda14cbcSMatt Macy if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 4398eda14cbcSMatt Macy return (-1); 4399eda14cbcSMatt Macy old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 4400eda14cbcSMatt Macy restore_resv = 4401eda14cbcSMatt Macy (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 4402eda14cbcSMatt Macy } 4403eda14cbcSMatt Macy 4404eda14cbcSMatt Macy /* 4405eda14cbcSMatt Macy * Pass both the filesystem and the wanted snapshot names, 4406eda14cbcSMatt Macy * we would get an error back if the snapshot is destroyed or 4407eda14cbcSMatt Macy * a new snapshot is created before this request is processed. 4408eda14cbcSMatt Macy */ 4409eda14cbcSMatt Macy err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name); 4410eda14cbcSMatt Macy if (err != 0) { 44111f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4412eda14cbcSMatt Macy 4413eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 4414eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 4415eda14cbcSMatt Macy zhp->zfs_name); 4416eda14cbcSMatt Macy switch (err) { 4417eda14cbcSMatt Macy case EEXIST: 4418eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4419eda14cbcSMatt Macy "there is a snapshot or bookmark more recent " 4420eda14cbcSMatt Macy "than '%s'"), snap->zfs_name); 4421eda14cbcSMatt Macy (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf); 4422eda14cbcSMatt Macy break; 4423eda14cbcSMatt Macy case ESRCH: 4424eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4425eda14cbcSMatt Macy "'%s' is not found among snapshots of '%s'"), 4426eda14cbcSMatt Macy snap->zfs_name, zhp->zfs_name); 4427eda14cbcSMatt Macy (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf); 4428eda14cbcSMatt Macy break; 4429eda14cbcSMatt Macy case EINVAL: 4430eda14cbcSMatt Macy (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf); 4431eda14cbcSMatt Macy break; 4432eda14cbcSMatt Macy default: 4433eda14cbcSMatt Macy (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf); 4434eda14cbcSMatt Macy } 4435eda14cbcSMatt Macy return (err); 4436eda14cbcSMatt Macy } 4437eda14cbcSMatt Macy 4438eda14cbcSMatt Macy /* 4439eda14cbcSMatt Macy * For volumes, if the pre-rollback volsize matched the pre- 4440eda14cbcSMatt Macy * rollback reservation and the volsize has changed then set 4441eda14cbcSMatt Macy * the reservation property to the post-rollback volsize. 4442eda14cbcSMatt Macy * Make a new handle since the rollback closed the dataset. 4443eda14cbcSMatt Macy */ 4444eda14cbcSMatt Macy if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 4445eda14cbcSMatt Macy (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 4446eda14cbcSMatt Macy if (restore_resv) { 4447eda14cbcSMatt Macy new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 4448eda14cbcSMatt Macy if (old_volsize != new_volsize) 4449eda14cbcSMatt Macy err = zfs_prop_set_int(zhp, resv_prop, 4450eda14cbcSMatt Macy new_volsize); 4451eda14cbcSMatt Macy } 4452eda14cbcSMatt Macy zfs_close(zhp); 4453eda14cbcSMatt Macy } 4454eda14cbcSMatt Macy return (err); 4455eda14cbcSMatt Macy } 4456eda14cbcSMatt Macy 4457eda14cbcSMatt Macy /* 4458eda14cbcSMatt Macy * Renames the given dataset. 4459eda14cbcSMatt Macy */ 4460eda14cbcSMatt Macy int 4461eac7052fSMatt Macy zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags) 4462eda14cbcSMatt Macy { 4463eda14cbcSMatt Macy int ret = 0; 4464eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 4465eda14cbcSMatt Macy char *delim; 4466eda14cbcSMatt Macy prop_changelist_t *cl = NULL; 4467eda14cbcSMatt Macy char parent[ZFS_MAX_DATASET_NAME_LEN]; 4468eac7052fSMatt Macy char property[ZFS_MAXPROPLEN]; 4469eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 44701f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4471eda14cbcSMatt Macy 4472eda14cbcSMatt Macy /* if we have the same exact name, just return success */ 4473eda14cbcSMatt Macy if (strcmp(zhp->zfs_name, target) == 0) 4474eda14cbcSMatt Macy return (0); 4475eda14cbcSMatt Macy 4476eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4477eda14cbcSMatt Macy "cannot rename to '%s'"), target); 4478eda14cbcSMatt Macy 4479eda14cbcSMatt Macy /* make sure source name is valid */ 4480eda14cbcSMatt Macy if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE)) 4481eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4482eda14cbcSMatt Macy 4483eda14cbcSMatt Macy /* 4484eda14cbcSMatt Macy * Make sure the target name is valid 4485eda14cbcSMatt Macy */ 4486eda14cbcSMatt Macy if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 4487eda14cbcSMatt Macy if ((strchr(target, '@') == NULL) || 4488eda14cbcSMatt Macy *target == '@') { 4489eda14cbcSMatt Macy /* 4490eda14cbcSMatt Macy * Snapshot target name is abbreviated, 4491eda14cbcSMatt Macy * reconstruct full dataset name 4492eda14cbcSMatt Macy */ 4493eda14cbcSMatt Macy (void) strlcpy(parent, zhp->zfs_name, 4494eda14cbcSMatt Macy sizeof (parent)); 4495eda14cbcSMatt Macy delim = strchr(parent, '@'); 4496eda14cbcSMatt Macy if (strchr(target, '@') == NULL) 4497eda14cbcSMatt Macy *(++delim) = '\0'; 4498eda14cbcSMatt Macy else 4499eda14cbcSMatt Macy *delim = '\0'; 4500eda14cbcSMatt Macy (void) strlcat(parent, target, sizeof (parent)); 4501eda14cbcSMatt Macy target = parent; 4502eda14cbcSMatt Macy } else { 4503eda14cbcSMatt Macy /* 4504eda14cbcSMatt Macy * Make sure we're renaming within the same dataset. 4505eda14cbcSMatt Macy */ 4506eda14cbcSMatt Macy delim = strchr(target, '@'); 4507eda14cbcSMatt Macy if (strncmp(zhp->zfs_name, target, delim - target) 4508eda14cbcSMatt Macy != 0 || zhp->zfs_name[delim - target] != '@') { 4509eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4510eda14cbcSMatt Macy "snapshots must be part of same " 4511eda14cbcSMatt Macy "dataset")); 4512eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_CROSSTARGET, 4513eda14cbcSMatt Macy errbuf)); 4514eda14cbcSMatt Macy } 4515eda14cbcSMatt Macy } 4516eda14cbcSMatt Macy 4517eda14cbcSMatt Macy if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 4518eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4519eda14cbcSMatt Macy } else { 4520eac7052fSMatt Macy if (flags.recursive) { 4521eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4522eda14cbcSMatt Macy "recursive rename must be a snapshot")); 4523eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4524eda14cbcSMatt Macy } 4525eda14cbcSMatt Macy 4526eda14cbcSMatt Macy if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 4527eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4528eda14cbcSMatt Macy 4529eda14cbcSMatt Macy /* validate parents */ 4530eda14cbcSMatt Macy if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 4531eda14cbcSMatt Macy return (-1); 4532eda14cbcSMatt Macy 4533eda14cbcSMatt Macy /* make sure we're in the same pool */ 4534eda14cbcSMatt Macy verify((delim = strchr(target, '/')) != NULL); 4535eda14cbcSMatt Macy if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 4536eda14cbcSMatt Macy zhp->zfs_name[delim - target] != '/') { 4537eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4538eda14cbcSMatt Macy "datasets must be within same pool")); 4539eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 4540eda14cbcSMatt Macy } 4541eda14cbcSMatt Macy 4542eda14cbcSMatt Macy /* new name cannot be a child of the current dataset name */ 4543eda14cbcSMatt Macy if (is_descendant(zhp->zfs_name, target)) { 4544eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4545eda14cbcSMatt Macy "New dataset name cannot be a descendant of " 4546eda14cbcSMatt Macy "current dataset name")); 4547eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4548eda14cbcSMatt Macy } 4549eda14cbcSMatt Macy } 4550eda14cbcSMatt Macy 4551eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 4552eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 4553eda14cbcSMatt Macy 4554eda14cbcSMatt Macy if (getzoneid() == GLOBAL_ZONEID && 4555eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 4556eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4557eda14cbcSMatt Macy "dataset is used in a non-global zone")); 4558eda14cbcSMatt Macy return (zfs_error(hdl, EZFS_ZONED, errbuf)); 4559eda14cbcSMatt Macy } 4560eda14cbcSMatt Macy 4561eac7052fSMatt Macy /* 4562eac7052fSMatt Macy * Avoid unmounting file systems with mountpoint property set to 4563eac7052fSMatt Macy * 'legacy' or 'none' even if -u option is not given. 4564eac7052fSMatt Macy */ 4565eac7052fSMatt Macy if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 4566eac7052fSMatt Macy !flags.recursive && !flags.nounmount && 4567eac7052fSMatt Macy zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 4568eac7052fSMatt Macy sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 4569eac7052fSMatt Macy (strcmp(property, "legacy") == 0 || 4570eac7052fSMatt Macy strcmp(property, "none") == 0)) { 4571eac7052fSMatt Macy flags.nounmount = B_TRUE; 4572eac7052fSMatt Macy } 4573eac7052fSMatt Macy if (flags.recursive) { 4574eda14cbcSMatt Macy char *parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 4575eda14cbcSMatt Macy delim = strchr(parentname, '@'); 4576eda14cbcSMatt Macy *delim = '\0'; 4577eac7052fSMatt Macy zfs_handle_t *zhrp = zfs_open(zhp->zfs_hdl, parentname, 4578eac7052fSMatt Macy ZFS_TYPE_DATASET); 4579eda14cbcSMatt Macy free(parentname); 4580eda14cbcSMatt Macy if (zhrp == NULL) { 4581eda14cbcSMatt Macy ret = -1; 4582eda14cbcSMatt Macy goto error; 4583eda14cbcSMatt Macy } 4584eda14cbcSMatt Macy zfs_close(zhrp); 4585eda14cbcSMatt Macy } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) { 4586eda14cbcSMatt Macy if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 4587eac7052fSMatt Macy flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 4588eda14cbcSMatt Macy CL_GATHER_ITER_MOUNTED, 4589eac7052fSMatt Macy flags.forceunmount ? MS_FORCE : 0)) == NULL) 4590eda14cbcSMatt Macy return (-1); 4591eda14cbcSMatt Macy 4592eda14cbcSMatt Macy if (changelist_haszonedchild(cl)) { 4593eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4594eda14cbcSMatt Macy "child dataset with inherited mountpoint is used " 4595eda14cbcSMatt Macy "in a non-global zone")); 4596eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_ZONED, errbuf); 4597eda14cbcSMatt Macy ret = -1; 4598eda14cbcSMatt Macy goto error; 4599eda14cbcSMatt Macy } 4600eda14cbcSMatt Macy 4601eda14cbcSMatt Macy if ((ret = changelist_prefix(cl)) != 0) 4602eda14cbcSMatt Macy goto error; 4603eda14cbcSMatt Macy } 4604eda14cbcSMatt Macy 4605eda14cbcSMatt Macy if (ZFS_IS_VOLUME(zhp)) 4606eda14cbcSMatt Macy zc.zc_objset_type = DMU_OST_ZVOL; 4607eda14cbcSMatt Macy else 4608eda14cbcSMatt Macy zc.zc_objset_type = DMU_OST_ZFS; 4609eda14cbcSMatt Macy 4610eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4611eda14cbcSMatt Macy (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 4612eda14cbcSMatt Macy 4613eac7052fSMatt Macy zc.zc_cookie = !!flags.recursive; 4614eac7052fSMatt Macy zc.zc_cookie |= (!!flags.nounmount) << 1; 4615eda14cbcSMatt Macy 4616eda14cbcSMatt Macy if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 4617eda14cbcSMatt Macy /* 4618eda14cbcSMatt Macy * if it was recursive, the one that actually failed will 4619eda14cbcSMatt Macy * be in zc.zc_name 4620eda14cbcSMatt Macy */ 4621eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4622eda14cbcSMatt Macy "cannot rename '%s'"), zc.zc_name); 4623eda14cbcSMatt Macy 4624eac7052fSMatt Macy if (flags.recursive && errno == EEXIST) { 4625eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4626eda14cbcSMatt Macy "a child dataset already has a snapshot " 4627eda14cbcSMatt Macy "with the new name")); 4628eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4629eda14cbcSMatt Macy } else if (errno == EACCES) { 4630eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4631eda14cbcSMatt Macy "cannot move encrypted child outside of " 4632eda14cbcSMatt Macy "its encryption root")); 4633eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf); 4634eda14cbcSMatt Macy } else { 4635eda14cbcSMatt Macy (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 4636eda14cbcSMatt Macy } 4637eda14cbcSMatt Macy 4638eda14cbcSMatt Macy /* 4639eda14cbcSMatt Macy * On failure, we still want to remount any filesystems that 4640eda14cbcSMatt Macy * were previously mounted, so we don't alter the system state. 4641eda14cbcSMatt Macy */ 4642eda14cbcSMatt Macy if (cl != NULL) 4643eda14cbcSMatt Macy (void) changelist_postfix(cl); 4644eda14cbcSMatt Macy } else { 4645eda14cbcSMatt Macy if (cl != NULL) { 4646eda14cbcSMatt Macy changelist_rename(cl, zfs_get_name(zhp), target); 4647eda14cbcSMatt Macy ret = changelist_postfix(cl); 4648eda14cbcSMatt Macy } 4649eda14cbcSMatt Macy } 4650eda14cbcSMatt Macy 4651eda14cbcSMatt Macy error: 4652eda14cbcSMatt Macy if (cl != NULL) { 4653eda14cbcSMatt Macy changelist_free(cl); 4654eda14cbcSMatt Macy } 4655eda14cbcSMatt Macy return (ret); 4656eda14cbcSMatt Macy } 4657eda14cbcSMatt Macy 4658eda14cbcSMatt Macy nvlist_t * 4659eda14cbcSMatt Macy zfs_get_all_props(zfs_handle_t *zhp) 4660eda14cbcSMatt Macy { 4661eda14cbcSMatt Macy return (zhp->zfs_props); 4662eda14cbcSMatt Macy } 4663eda14cbcSMatt Macy 4664eda14cbcSMatt Macy nvlist_t * 4665eda14cbcSMatt Macy zfs_get_recvd_props(zfs_handle_t *zhp) 4666eda14cbcSMatt Macy { 4667eda14cbcSMatt Macy if (zhp->zfs_recvd_props == NULL) 4668eda14cbcSMatt Macy if (get_recvd_props_ioctl(zhp) != 0) 4669eda14cbcSMatt Macy return (NULL); 4670eda14cbcSMatt Macy return (zhp->zfs_recvd_props); 4671eda14cbcSMatt Macy } 4672eda14cbcSMatt Macy 4673eda14cbcSMatt Macy nvlist_t * 4674eda14cbcSMatt Macy zfs_get_user_props(zfs_handle_t *zhp) 4675eda14cbcSMatt Macy { 4676eda14cbcSMatt Macy return (zhp->zfs_user_props); 4677eda14cbcSMatt Macy } 4678eda14cbcSMatt Macy 4679eda14cbcSMatt Macy /* 4680eda14cbcSMatt Macy * This function is used by 'zfs list' to determine the exact set of columns to 4681eda14cbcSMatt Macy * display, and their maximum widths. This does two main things: 4682eda14cbcSMatt Macy * 4683eda14cbcSMatt Macy * - If this is a list of all properties, then expand the list to include 4684eda14cbcSMatt Macy * all native properties, and set a flag so that for each dataset we look 4685eda14cbcSMatt Macy * for new unique user properties and add them to the list. 4686eda14cbcSMatt Macy * 4687eda14cbcSMatt Macy * - For non fixed-width properties, keep track of the maximum width seen 4688eda14cbcSMatt Macy * so that we can size the column appropriately. If the user has 4689eda14cbcSMatt Macy * requested received property values, we also need to compute the width 4690eda14cbcSMatt Macy * of the RECEIVED column. 4691eda14cbcSMatt Macy */ 4692eda14cbcSMatt Macy int 4693eda14cbcSMatt Macy zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received, 4694eda14cbcSMatt Macy boolean_t literal) 4695eda14cbcSMatt Macy { 4696eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 4697eda14cbcSMatt Macy zprop_list_t *entry; 4698eda14cbcSMatt Macy zprop_list_t **last, **start; 4699eda14cbcSMatt Macy nvlist_t *userprops, *propval; 4700eda14cbcSMatt Macy nvpair_t *elem; 4701eda14cbcSMatt Macy char *strval; 4702eda14cbcSMatt Macy char buf[ZFS_MAXPROPLEN]; 4703eda14cbcSMatt Macy 4704eda14cbcSMatt Macy if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 4705eda14cbcSMatt Macy return (-1); 4706eda14cbcSMatt Macy 4707eda14cbcSMatt Macy userprops = zfs_get_user_props(zhp); 4708eda14cbcSMatt Macy 4709eda14cbcSMatt Macy entry = *plp; 4710eda14cbcSMatt Macy if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 4711eda14cbcSMatt Macy /* 4712eda14cbcSMatt Macy * Go through and add any user properties as necessary. We 4713eda14cbcSMatt Macy * start by incrementing our list pointer to the first 4714eda14cbcSMatt Macy * non-native property. 4715eda14cbcSMatt Macy */ 4716eda14cbcSMatt Macy start = plp; 4717eda14cbcSMatt Macy while (*start != NULL) { 47181f1e2261SMartin Matuska if ((*start)->pl_prop == ZPROP_USERPROP) 4719eda14cbcSMatt Macy break; 4720eda14cbcSMatt Macy start = &(*start)->pl_next; 4721eda14cbcSMatt Macy } 4722eda14cbcSMatt Macy 4723eda14cbcSMatt Macy elem = NULL; 4724eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 4725eda14cbcSMatt Macy /* 4726eda14cbcSMatt Macy * See if we've already found this property in our list. 4727eda14cbcSMatt Macy */ 4728eda14cbcSMatt Macy for (last = start; *last != NULL; 4729eda14cbcSMatt Macy last = &(*last)->pl_next) { 4730eda14cbcSMatt Macy if (strcmp((*last)->pl_user_prop, 4731eda14cbcSMatt Macy nvpair_name(elem)) == 0) 4732eda14cbcSMatt Macy break; 4733eda14cbcSMatt Macy } 4734eda14cbcSMatt Macy 4735eda14cbcSMatt Macy if (*last == NULL) { 4736716fd348SMartin Matuska entry = zfs_alloc(hdl, sizeof (zprop_list_t)); 4737716fd348SMartin Matuska entry->pl_user_prop = 4738716fd348SMartin Matuska zfs_strdup(hdl, nvpair_name(elem)); 47391f1e2261SMartin Matuska entry->pl_prop = ZPROP_USERPROP; 4740eda14cbcSMatt Macy entry->pl_width = strlen(nvpair_name(elem)); 4741eda14cbcSMatt Macy entry->pl_all = B_TRUE; 4742eda14cbcSMatt Macy *last = entry; 4743eda14cbcSMatt Macy } 4744eda14cbcSMatt Macy } 4745eda14cbcSMatt Macy } 4746eda14cbcSMatt Macy 4747eda14cbcSMatt Macy /* 4748eda14cbcSMatt Macy * Now go through and check the width of any non-fixed columns 4749eda14cbcSMatt Macy */ 4750eda14cbcSMatt Macy for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4751eda14cbcSMatt Macy if (entry->pl_fixed && !literal) 4752eda14cbcSMatt Macy continue; 4753eda14cbcSMatt Macy 47541f1e2261SMartin Matuska if (entry->pl_prop != ZPROP_USERPROP) { 4755eda14cbcSMatt Macy if (zfs_prop_get(zhp, entry->pl_prop, 4756eda14cbcSMatt Macy buf, sizeof (buf), NULL, NULL, 0, literal) == 0) { 4757eda14cbcSMatt Macy if (strlen(buf) > entry->pl_width) 4758eda14cbcSMatt Macy entry->pl_width = strlen(buf); 4759eda14cbcSMatt Macy } 4760eda14cbcSMatt Macy if (received && zfs_prop_get_recvd(zhp, 4761eda14cbcSMatt Macy zfs_prop_to_name(entry->pl_prop), 4762eda14cbcSMatt Macy buf, sizeof (buf), literal) == 0) 4763eda14cbcSMatt Macy if (strlen(buf) > entry->pl_recvd_width) 4764eda14cbcSMatt Macy entry->pl_recvd_width = strlen(buf); 4765eda14cbcSMatt Macy } else { 4766eda14cbcSMatt Macy if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 4767eda14cbcSMatt Macy &propval) == 0) { 4768da5137abSMartin Matuska strval = fnvlist_lookup_string(propval, 4769da5137abSMartin Matuska ZPROP_VALUE); 4770eda14cbcSMatt Macy if (strlen(strval) > entry->pl_width) 4771eda14cbcSMatt Macy entry->pl_width = strlen(strval); 4772eda14cbcSMatt Macy } 4773eda14cbcSMatt Macy if (received && zfs_prop_get_recvd(zhp, 4774eda14cbcSMatt Macy entry->pl_user_prop, 4775eda14cbcSMatt Macy buf, sizeof (buf), literal) == 0) 4776eda14cbcSMatt Macy if (strlen(buf) > entry->pl_recvd_width) 4777eda14cbcSMatt Macy entry->pl_recvd_width = strlen(buf); 4778eda14cbcSMatt Macy } 4779eda14cbcSMatt Macy } 4780eda14cbcSMatt Macy 4781eda14cbcSMatt Macy return (0); 4782eda14cbcSMatt Macy } 4783eda14cbcSMatt Macy 4784eda14cbcSMatt Macy void 4785eda14cbcSMatt Macy zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4786eda14cbcSMatt Macy { 4787eda14cbcSMatt Macy nvpair_t *curr; 4788eda14cbcSMatt Macy nvpair_t *next; 4789eda14cbcSMatt Macy 4790eda14cbcSMatt Macy /* 4791eda14cbcSMatt Macy * Keep a reference to the props-table against which we prune the 4792eda14cbcSMatt Macy * properties. 4793eda14cbcSMatt Macy */ 4794eda14cbcSMatt Macy zhp->zfs_props_table = props; 4795eda14cbcSMatt Macy 4796eda14cbcSMatt Macy curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4797eda14cbcSMatt Macy 4798eda14cbcSMatt Macy while (curr) { 4799eda14cbcSMatt Macy zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4800eda14cbcSMatt Macy next = nvlist_next_nvpair(zhp->zfs_props, curr); 4801eda14cbcSMatt Macy 4802eda14cbcSMatt Macy /* 48031f1e2261SMartin Matuska * User properties will result in ZPROP_USERPROP (an alias 48041f1e2261SMartin Matuska * for ZPROP_INVAL), and since we 4805eda14cbcSMatt Macy * only know how to prune standard ZFS properties, we always 4806eda14cbcSMatt Macy * leave these in the list. This can also happen if we 4807eda14cbcSMatt Macy * encounter an unknown DSL property (when running older 4808eda14cbcSMatt Macy * software, for example). 4809eda14cbcSMatt Macy */ 48101f1e2261SMartin Matuska if (zfs_prop != ZPROP_USERPROP && props[zfs_prop] == B_FALSE) 4811eda14cbcSMatt Macy (void) nvlist_remove(zhp->zfs_props, 4812eda14cbcSMatt Macy nvpair_name(curr), nvpair_type(curr)); 4813eda14cbcSMatt Macy curr = next; 4814eda14cbcSMatt Macy } 4815eda14cbcSMatt Macy } 4816eda14cbcSMatt Macy 4817eda14cbcSMatt Macy static int 4818eda14cbcSMatt Macy zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4819eda14cbcSMatt Macy zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4820eda14cbcSMatt Macy { 4821eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 4822eda14cbcSMatt Macy nvlist_t *nvlist = NULL; 4823eda14cbcSMatt Macy int error; 4824eda14cbcSMatt Macy 4825eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4826eda14cbcSMatt Macy (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4827eda14cbcSMatt Macy zc.zc_cookie = (uint64_t)cmd; 4828eda14cbcSMatt Macy 4829eda14cbcSMatt Macy if (cmd == ZFS_SMB_ACL_RENAME) { 4830eda14cbcSMatt Macy if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4831eda14cbcSMatt Macy (void) no_memory(hdl); 4832eda14cbcSMatt Macy return (0); 4833eda14cbcSMatt Macy } 4834eda14cbcSMatt Macy } 4835eda14cbcSMatt Macy 4836eda14cbcSMatt Macy switch (cmd) { 4837eda14cbcSMatt Macy case ZFS_SMB_ACL_ADD: 4838eda14cbcSMatt Macy case ZFS_SMB_ACL_REMOVE: 4839eda14cbcSMatt Macy (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4840eda14cbcSMatt Macy break; 4841eda14cbcSMatt Macy case ZFS_SMB_ACL_RENAME: 4842eda14cbcSMatt Macy if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4843eda14cbcSMatt Macy resource1) != 0) { 4844eda14cbcSMatt Macy (void) no_memory(hdl); 4845eda14cbcSMatt Macy return (-1); 4846eda14cbcSMatt Macy } 4847eda14cbcSMatt Macy if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4848eda14cbcSMatt Macy resource2) != 0) { 4849eda14cbcSMatt Macy (void) no_memory(hdl); 4850eda14cbcSMatt Macy return (-1); 4851eda14cbcSMatt Macy } 4852716fd348SMartin Matuska zcmd_write_src_nvlist(hdl, &zc, nvlist); 4853eda14cbcSMatt Macy break; 4854eda14cbcSMatt Macy case ZFS_SMB_ACL_PURGE: 4855eda14cbcSMatt Macy break; 4856eda14cbcSMatt Macy default: 4857eda14cbcSMatt Macy return (-1); 4858eda14cbcSMatt Macy } 4859eda14cbcSMatt Macy error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4860eda14cbcSMatt Macy nvlist_free(nvlist); 4861eda14cbcSMatt Macy return (error); 4862eda14cbcSMatt Macy } 4863eda14cbcSMatt Macy 4864eda14cbcSMatt Macy int 4865eda14cbcSMatt Macy zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4866eda14cbcSMatt Macy char *path, char *resource) 4867eda14cbcSMatt Macy { 4868eda14cbcSMatt Macy return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4869eda14cbcSMatt Macy resource, NULL)); 4870eda14cbcSMatt Macy } 4871eda14cbcSMatt Macy 4872eda14cbcSMatt Macy int 4873eda14cbcSMatt Macy zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4874eda14cbcSMatt Macy char *path, char *resource) 4875eda14cbcSMatt Macy { 4876eda14cbcSMatt Macy return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4877eda14cbcSMatt Macy resource, NULL)); 4878eda14cbcSMatt Macy } 4879eda14cbcSMatt Macy 4880eda14cbcSMatt Macy int 4881eda14cbcSMatt Macy zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4882eda14cbcSMatt Macy { 4883eda14cbcSMatt Macy return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4884eda14cbcSMatt Macy NULL, NULL)); 4885eda14cbcSMatt Macy } 4886eda14cbcSMatt Macy 4887eda14cbcSMatt Macy int 4888eda14cbcSMatt Macy zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4889eda14cbcSMatt Macy char *oldname, char *newname) 4890eda14cbcSMatt Macy { 4891eda14cbcSMatt Macy return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4892eda14cbcSMatt Macy oldname, newname)); 4893eda14cbcSMatt Macy } 4894eda14cbcSMatt Macy 4895eda14cbcSMatt Macy int 4896eda14cbcSMatt Macy zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4897eda14cbcSMatt Macy zfs_userspace_cb_t func, void *arg) 4898eda14cbcSMatt Macy { 4899eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 4900eda14cbcSMatt Macy zfs_useracct_t buf[100]; 4901eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 4902eda14cbcSMatt Macy int ret; 4903eda14cbcSMatt Macy 4904eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4905eda14cbcSMatt Macy 4906eda14cbcSMatt Macy zc.zc_objset_type = type; 4907eda14cbcSMatt Macy zc.zc_nvlist_dst = (uintptr_t)buf; 4908eda14cbcSMatt Macy 4909eda14cbcSMatt Macy for (;;) { 4910eda14cbcSMatt Macy zfs_useracct_t *zua = buf; 4911eda14cbcSMatt Macy 4912eda14cbcSMatt Macy zc.zc_nvlist_dst_size = sizeof (buf); 4913eda14cbcSMatt Macy if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4914eda14cbcSMatt Macy if ((errno == ENOTSUP && 4915eda14cbcSMatt Macy (type == ZFS_PROP_USEROBJUSED || 4916eda14cbcSMatt Macy type == ZFS_PROP_GROUPOBJUSED || 4917eda14cbcSMatt Macy type == ZFS_PROP_USEROBJQUOTA || 4918eda14cbcSMatt Macy type == ZFS_PROP_GROUPOBJQUOTA || 4919eda14cbcSMatt Macy type == ZFS_PROP_PROJECTOBJUSED || 4920eda14cbcSMatt Macy type == ZFS_PROP_PROJECTOBJQUOTA || 4921eda14cbcSMatt Macy type == ZFS_PROP_PROJECTUSED || 4922eda14cbcSMatt Macy type == ZFS_PROP_PROJECTQUOTA))) 4923eda14cbcSMatt Macy break; 4924eda14cbcSMatt Macy 492516038816SMartin Matuska return (zfs_standard_error_fmt(hdl, errno, 4926eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 492716038816SMartin Matuska "cannot get used/quota for %s"), zc.zc_name)); 4928eda14cbcSMatt Macy } 4929eda14cbcSMatt Macy if (zc.zc_nvlist_dst_size == 0) 4930eda14cbcSMatt Macy break; 4931eda14cbcSMatt Macy 4932eda14cbcSMatt Macy while (zc.zc_nvlist_dst_size > 0) { 4933eda14cbcSMatt Macy if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4934eda14cbcSMatt Macy zua->zu_space)) != 0) 4935eda14cbcSMatt Macy return (ret); 4936eda14cbcSMatt Macy zua++; 4937eda14cbcSMatt Macy zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4938eda14cbcSMatt Macy } 4939eda14cbcSMatt Macy } 4940eda14cbcSMatt Macy 4941eda14cbcSMatt Macy return (0); 4942eda14cbcSMatt Macy } 4943eda14cbcSMatt Macy 4944eda14cbcSMatt Macy struct holdarg { 4945eda14cbcSMatt Macy nvlist_t *nvl; 4946eda14cbcSMatt Macy const char *snapname; 4947eda14cbcSMatt Macy const char *tag; 4948eda14cbcSMatt Macy boolean_t recursive; 4949eda14cbcSMatt Macy int error; 4950eda14cbcSMatt Macy }; 4951eda14cbcSMatt Macy 4952eda14cbcSMatt Macy static int 4953eda14cbcSMatt Macy zfs_hold_one(zfs_handle_t *zhp, void *arg) 4954eda14cbcSMatt Macy { 4955eda14cbcSMatt Macy struct holdarg *ha = arg; 4956eda14cbcSMatt Macy char name[ZFS_MAX_DATASET_NAME_LEN]; 4957eda14cbcSMatt Macy int rv = 0; 4958eda14cbcSMatt Macy 4959eda14cbcSMatt Macy if (snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, 4960eda14cbcSMatt Macy ha->snapname) >= sizeof (name)) 4961eda14cbcSMatt Macy return (EINVAL); 4962eda14cbcSMatt Macy 4963eda14cbcSMatt Macy if (lzc_exists(name)) 4964eda14cbcSMatt Macy fnvlist_add_string(ha->nvl, name, ha->tag); 4965eda14cbcSMatt Macy 4966eda14cbcSMatt Macy if (ha->recursive) 4967*15f0b8c3SMartin Matuska rv = zfs_iter_filesystems(zhp, 0, zfs_hold_one, ha); 4968eda14cbcSMatt Macy zfs_close(zhp); 4969eda14cbcSMatt Macy return (rv); 4970eda14cbcSMatt Macy } 4971eda14cbcSMatt Macy 4972eda14cbcSMatt Macy int 4973eda14cbcSMatt Macy zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4974eda14cbcSMatt Macy boolean_t recursive, int cleanup_fd) 4975eda14cbcSMatt Macy { 4976eda14cbcSMatt Macy int ret; 4977eda14cbcSMatt Macy struct holdarg ha; 4978eda14cbcSMatt Macy 4979eda14cbcSMatt Macy ha.nvl = fnvlist_alloc(); 4980eda14cbcSMatt Macy ha.snapname = snapname; 4981eda14cbcSMatt Macy ha.tag = tag; 4982eda14cbcSMatt Macy ha.recursive = recursive; 4983eda14cbcSMatt Macy (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4984eda14cbcSMatt Macy 4985eda14cbcSMatt Macy if (nvlist_empty(ha.nvl)) { 49861f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 4987eda14cbcSMatt Macy 4988eda14cbcSMatt Macy fnvlist_free(ha.nvl); 4989eda14cbcSMatt Macy ret = ENOENT; 4990eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 4991eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 4992eda14cbcSMatt Macy "cannot hold snapshot '%s@%s'"), 4993eda14cbcSMatt Macy zhp->zfs_name, snapname); 4994eda14cbcSMatt Macy (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4995eda14cbcSMatt Macy return (ret); 4996eda14cbcSMatt Macy } 4997eda14cbcSMatt Macy 4998eda14cbcSMatt Macy ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4999eda14cbcSMatt Macy fnvlist_free(ha.nvl); 5000eda14cbcSMatt Macy 5001eda14cbcSMatt Macy return (ret); 5002eda14cbcSMatt Macy } 5003eda14cbcSMatt Macy 5004eda14cbcSMatt Macy int 5005eda14cbcSMatt Macy zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 5006eda14cbcSMatt Macy { 5007eda14cbcSMatt Macy int ret; 5008eda14cbcSMatt Macy nvlist_t *errors; 5009eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 50101f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 5011eda14cbcSMatt Macy nvpair_t *elem; 5012eda14cbcSMatt Macy 5013eda14cbcSMatt Macy errors = NULL; 5014eda14cbcSMatt Macy ret = lzc_hold(holds, cleanup_fd, &errors); 5015eda14cbcSMatt Macy 5016eda14cbcSMatt Macy if (ret == 0) { 5017eda14cbcSMatt Macy /* There may be errors even in the success case. */ 5018eda14cbcSMatt Macy fnvlist_free(errors); 5019eda14cbcSMatt Macy return (0); 5020eda14cbcSMatt Macy } 5021eda14cbcSMatt Macy 5022eda14cbcSMatt Macy if (nvlist_empty(errors)) { 5023eda14cbcSMatt Macy /* no hold-specific errors */ 5024eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5025eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot hold")); 5026eda14cbcSMatt Macy switch (ret) { 5027eda14cbcSMatt Macy case ENOTSUP: 5028eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5029eda14cbcSMatt Macy "pool must be upgraded")); 5030eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 5031eda14cbcSMatt Macy break; 5032eda14cbcSMatt Macy case EINVAL: 5033eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 5034eda14cbcSMatt Macy break; 5035eda14cbcSMatt Macy default: 5036eda14cbcSMatt Macy (void) zfs_standard_error(hdl, ret, errbuf); 5037eda14cbcSMatt Macy } 5038eda14cbcSMatt Macy } 5039eda14cbcSMatt Macy 5040eda14cbcSMatt Macy for (elem = nvlist_next_nvpair(errors, NULL); 5041eda14cbcSMatt Macy elem != NULL; 5042eda14cbcSMatt Macy elem = nvlist_next_nvpair(errors, elem)) { 5043eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5044eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 5045eda14cbcSMatt Macy "cannot hold snapshot '%s'"), nvpair_name(elem)); 5046eda14cbcSMatt Macy switch (fnvpair_value_int32(elem)) { 5047eda14cbcSMatt Macy case E2BIG: 5048eda14cbcSMatt Macy /* 5049eda14cbcSMatt Macy * Temporary tags wind up having the ds object id 5050eda14cbcSMatt Macy * prepended. So even if we passed the length check 5051eda14cbcSMatt Macy * above, it's still possible for the tag to wind 5052eda14cbcSMatt Macy * up being slightly too long. 5053eda14cbcSMatt Macy */ 5054eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 5055eda14cbcSMatt Macy break; 5056eda14cbcSMatt Macy case EINVAL: 5057eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 5058eda14cbcSMatt Macy break; 5059eda14cbcSMatt Macy case EEXIST: 5060eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 5061eda14cbcSMatt Macy break; 5062eda14cbcSMatt Macy default: 5063eda14cbcSMatt Macy (void) zfs_standard_error(hdl, 5064eda14cbcSMatt Macy fnvpair_value_int32(elem), errbuf); 5065eda14cbcSMatt Macy } 5066eda14cbcSMatt Macy } 5067eda14cbcSMatt Macy 5068eda14cbcSMatt Macy fnvlist_free(errors); 5069eda14cbcSMatt Macy return (ret); 5070eda14cbcSMatt Macy } 5071eda14cbcSMatt Macy 5072eda14cbcSMatt Macy static int 5073eda14cbcSMatt Macy zfs_release_one(zfs_handle_t *zhp, void *arg) 5074eda14cbcSMatt Macy { 5075eda14cbcSMatt Macy struct holdarg *ha = arg; 5076eda14cbcSMatt Macy char name[ZFS_MAX_DATASET_NAME_LEN]; 5077eda14cbcSMatt Macy int rv = 0; 5078eda14cbcSMatt Macy nvlist_t *existing_holds; 5079eda14cbcSMatt Macy 5080eda14cbcSMatt Macy if (snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, 5081eda14cbcSMatt Macy ha->snapname) >= sizeof (name)) { 5082eda14cbcSMatt Macy ha->error = EINVAL; 5083eda14cbcSMatt Macy rv = EINVAL; 5084eda14cbcSMatt Macy } 5085eda14cbcSMatt Macy 5086eda14cbcSMatt Macy if (lzc_get_holds(name, &existing_holds) != 0) { 5087eda14cbcSMatt Macy ha->error = ENOENT; 5088eda14cbcSMatt Macy } else if (!nvlist_exists(existing_holds, ha->tag)) { 5089eda14cbcSMatt Macy ha->error = ESRCH; 5090eda14cbcSMatt Macy } else { 5091eda14cbcSMatt Macy nvlist_t *torelease = fnvlist_alloc(); 5092eda14cbcSMatt Macy fnvlist_add_boolean(torelease, ha->tag); 5093eda14cbcSMatt Macy fnvlist_add_nvlist(ha->nvl, name, torelease); 5094eda14cbcSMatt Macy fnvlist_free(torelease); 5095eda14cbcSMatt Macy } 5096eda14cbcSMatt Macy 5097eda14cbcSMatt Macy if (ha->recursive) 5098*15f0b8c3SMartin Matuska rv = zfs_iter_filesystems(zhp, 0, zfs_release_one, ha); 5099eda14cbcSMatt Macy zfs_close(zhp); 5100eda14cbcSMatt Macy return (rv); 5101eda14cbcSMatt Macy } 5102eda14cbcSMatt Macy 5103eda14cbcSMatt Macy int 5104eda14cbcSMatt Macy zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 5105eda14cbcSMatt Macy boolean_t recursive) 5106eda14cbcSMatt Macy { 5107eda14cbcSMatt Macy int ret; 5108eda14cbcSMatt Macy struct holdarg ha; 5109eda14cbcSMatt Macy nvlist_t *errors = NULL; 5110eda14cbcSMatt Macy nvpair_t *elem; 5111eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 51121f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 5113eda14cbcSMatt Macy 5114eda14cbcSMatt Macy ha.nvl = fnvlist_alloc(); 5115eda14cbcSMatt Macy ha.snapname = snapname; 5116eda14cbcSMatt Macy ha.tag = tag; 5117eda14cbcSMatt Macy ha.recursive = recursive; 5118eda14cbcSMatt Macy ha.error = 0; 5119eda14cbcSMatt Macy (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 5120eda14cbcSMatt Macy 5121eda14cbcSMatt Macy if (nvlist_empty(ha.nvl)) { 5122eda14cbcSMatt Macy fnvlist_free(ha.nvl); 5123eda14cbcSMatt Macy ret = ha.error; 5124eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5125eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 5126eda14cbcSMatt Macy "cannot release hold from snapshot '%s@%s'"), 5127eda14cbcSMatt Macy zhp->zfs_name, snapname); 5128eda14cbcSMatt Macy if (ret == ESRCH) { 5129eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 5130eda14cbcSMatt Macy } else { 5131eda14cbcSMatt Macy (void) zfs_standard_error(hdl, ret, errbuf); 5132eda14cbcSMatt Macy } 5133eda14cbcSMatt Macy return (ret); 5134eda14cbcSMatt Macy } 5135eda14cbcSMatt Macy 5136eda14cbcSMatt Macy ret = lzc_release(ha.nvl, &errors); 5137eda14cbcSMatt Macy fnvlist_free(ha.nvl); 5138eda14cbcSMatt Macy 5139eda14cbcSMatt Macy if (ret == 0) { 5140eda14cbcSMatt Macy /* There may be errors even in the success case. */ 5141eda14cbcSMatt Macy fnvlist_free(errors); 5142eda14cbcSMatt Macy return (0); 5143eda14cbcSMatt Macy } 5144eda14cbcSMatt Macy 5145eda14cbcSMatt Macy if (nvlist_empty(errors)) { 5146eda14cbcSMatt Macy /* no hold-specific errors */ 5147eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 5148eda14cbcSMatt Macy "cannot release")); 5149eda14cbcSMatt Macy switch (errno) { 5150eda14cbcSMatt Macy case ENOTSUP: 5151eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5152eda14cbcSMatt Macy "pool must be upgraded")); 5153eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 5154eda14cbcSMatt Macy break; 5155eda14cbcSMatt Macy default: 515616038816SMartin Matuska (void) zfs_standard_error(hdl, errno, errbuf); 5157eda14cbcSMatt Macy } 5158eda14cbcSMatt Macy } 5159eda14cbcSMatt Macy 5160eda14cbcSMatt Macy for (elem = nvlist_next_nvpair(errors, NULL); 5161eda14cbcSMatt Macy elem != NULL; 5162eda14cbcSMatt Macy elem = nvlist_next_nvpair(errors, elem)) { 5163eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5164eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, 5165eda14cbcSMatt Macy "cannot release hold from snapshot '%s'"), 5166eda14cbcSMatt Macy nvpair_name(elem)); 5167eda14cbcSMatt Macy switch (fnvpair_value_int32(elem)) { 5168eda14cbcSMatt Macy case ESRCH: 5169eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 5170eda14cbcSMatt Macy break; 5171eda14cbcSMatt Macy case EINVAL: 5172eda14cbcSMatt Macy (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 5173eda14cbcSMatt Macy break; 5174eda14cbcSMatt Macy default: 517516038816SMartin Matuska (void) zfs_standard_error(hdl, 5176eda14cbcSMatt Macy fnvpair_value_int32(elem), errbuf); 5177eda14cbcSMatt Macy } 5178eda14cbcSMatt Macy } 5179eda14cbcSMatt Macy 5180eda14cbcSMatt Macy fnvlist_free(errors); 5181eda14cbcSMatt Macy return (ret); 5182eda14cbcSMatt Macy } 5183eda14cbcSMatt Macy 5184eda14cbcSMatt Macy int 5185eda14cbcSMatt Macy zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 5186eda14cbcSMatt Macy { 5187eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 5188eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 5189eda14cbcSMatt Macy int nvsz = 2048; 5190eda14cbcSMatt Macy void *nvbuf; 5191eda14cbcSMatt Macy int err = 0; 51921f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 5193eda14cbcSMatt Macy 5194eda14cbcSMatt Macy assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 5195eda14cbcSMatt Macy zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 5196eda14cbcSMatt Macy 5197eda14cbcSMatt Macy tryagain: 5198eda14cbcSMatt Macy 5199eda14cbcSMatt Macy nvbuf = malloc(nvsz); 5200eda14cbcSMatt Macy if (nvbuf == NULL) { 5201eda14cbcSMatt Macy err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 5202eda14cbcSMatt Macy goto out; 5203eda14cbcSMatt Macy } 5204eda14cbcSMatt Macy 5205eda14cbcSMatt Macy zc.zc_nvlist_dst_size = nvsz; 5206eda14cbcSMatt Macy zc.zc_nvlist_dst = (uintptr_t)nvbuf; 5207eda14cbcSMatt Macy 5208eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 5209eda14cbcSMatt Macy 5210eda14cbcSMatt Macy if (zfs_ioctl(hdl, ZFS_IOC_GET_FSACL, &zc) != 0) { 5211eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5212eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 5213eda14cbcSMatt Macy zc.zc_name); 5214eda14cbcSMatt Macy switch (errno) { 5215eda14cbcSMatt Macy case ENOMEM: 5216eda14cbcSMatt Macy free(nvbuf); 5217eda14cbcSMatt Macy nvsz = zc.zc_nvlist_dst_size; 5218eda14cbcSMatt Macy goto tryagain; 5219eda14cbcSMatt Macy 5220eda14cbcSMatt Macy case ENOTSUP: 5221eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5222eda14cbcSMatt Macy "pool must be upgraded")); 5223eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5224eda14cbcSMatt Macy break; 5225eda14cbcSMatt Macy case EINVAL: 5226eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5227eda14cbcSMatt Macy break; 5228eda14cbcSMatt Macy case ENOENT: 5229eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_NOENT, errbuf); 5230eda14cbcSMatt Macy break; 5231eda14cbcSMatt Macy default: 523216038816SMartin Matuska err = zfs_standard_error(hdl, errno, errbuf); 5233eda14cbcSMatt Macy break; 5234eda14cbcSMatt Macy } 5235eda14cbcSMatt Macy } else { 5236eda14cbcSMatt Macy /* success */ 5237eda14cbcSMatt Macy int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 5238eda14cbcSMatt Macy if (rc) { 523916038816SMartin Matuska err = zfs_standard_error_fmt(hdl, rc, dgettext( 5240eda14cbcSMatt Macy TEXT_DOMAIN, "cannot get permissions on '%s'"), 5241eda14cbcSMatt Macy zc.zc_name); 5242eda14cbcSMatt Macy } 5243eda14cbcSMatt Macy } 5244eda14cbcSMatt Macy 5245eda14cbcSMatt Macy free(nvbuf); 5246eda14cbcSMatt Macy out: 5247eda14cbcSMatt Macy return (err); 5248eda14cbcSMatt Macy } 5249eda14cbcSMatt Macy 5250eda14cbcSMatt Macy int 5251eda14cbcSMatt Macy zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 5252eda14cbcSMatt Macy { 5253eda14cbcSMatt Macy zfs_cmd_t zc = {"\0"}; 5254eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 5255eda14cbcSMatt Macy char *nvbuf; 52561f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 5257eda14cbcSMatt Macy size_t nvsz; 5258eda14cbcSMatt Macy int err; 5259eda14cbcSMatt Macy 5260eda14cbcSMatt Macy assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 5261eda14cbcSMatt Macy zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 5262eda14cbcSMatt Macy 5263eda14cbcSMatt Macy err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 5264eda14cbcSMatt Macy assert(err == 0); 5265eda14cbcSMatt Macy 5266eda14cbcSMatt Macy nvbuf = malloc(nvsz); 5267eda14cbcSMatt Macy 5268eda14cbcSMatt Macy err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 5269eda14cbcSMatt Macy assert(err == 0); 5270eda14cbcSMatt Macy 5271eda14cbcSMatt Macy zc.zc_nvlist_src_size = nvsz; 5272eda14cbcSMatt Macy zc.zc_nvlist_src = (uintptr_t)nvbuf; 5273eda14cbcSMatt Macy zc.zc_perm_action = un; 5274eda14cbcSMatt Macy 5275eda14cbcSMatt Macy (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 5276eda14cbcSMatt Macy 5277eda14cbcSMatt Macy if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 5278eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5279eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 5280eda14cbcSMatt Macy zc.zc_name); 5281eda14cbcSMatt Macy switch (errno) { 5282eda14cbcSMatt Macy case ENOTSUP: 5283eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5284eda14cbcSMatt Macy "pool must be upgraded")); 5285eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5286eda14cbcSMatt Macy break; 5287eda14cbcSMatt Macy case EINVAL: 5288eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5289eda14cbcSMatt Macy break; 5290eda14cbcSMatt Macy case ENOENT: 5291eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_NOENT, errbuf); 5292eda14cbcSMatt Macy break; 5293eda14cbcSMatt Macy default: 529416038816SMartin Matuska err = zfs_standard_error(hdl, errno, errbuf); 5295eda14cbcSMatt Macy break; 5296eda14cbcSMatt Macy } 5297eda14cbcSMatt Macy } 5298eda14cbcSMatt Macy 5299eda14cbcSMatt Macy free(nvbuf); 5300eda14cbcSMatt Macy 5301eda14cbcSMatt Macy return (err); 5302eda14cbcSMatt Macy } 5303eda14cbcSMatt Macy 5304eda14cbcSMatt Macy int 5305eda14cbcSMatt Macy zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 5306eda14cbcSMatt Macy { 5307eda14cbcSMatt Macy int err; 53081f1e2261SMartin Matuska char errbuf[ERRBUFLEN]; 5309eda14cbcSMatt Macy 5310eda14cbcSMatt Macy err = lzc_get_holds(zhp->zfs_name, nvl); 5311eda14cbcSMatt Macy 5312eda14cbcSMatt Macy if (err != 0) { 5313eda14cbcSMatt Macy libzfs_handle_t *hdl = zhp->zfs_hdl; 5314eda14cbcSMatt Macy 5315eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 5316eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 5317eda14cbcSMatt Macy zhp->zfs_name); 5318eda14cbcSMatt Macy switch (err) { 5319eda14cbcSMatt Macy case ENOTSUP: 5320eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5321eda14cbcSMatt Macy "pool must be upgraded")); 5322eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5323eda14cbcSMatt Macy break; 5324eda14cbcSMatt Macy case EINVAL: 5325eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5326eda14cbcSMatt Macy break; 5327eda14cbcSMatt Macy case ENOENT: 5328eda14cbcSMatt Macy err = zfs_error(hdl, EZFS_NOENT, errbuf); 5329eda14cbcSMatt Macy break; 5330eda14cbcSMatt Macy default: 533116038816SMartin Matuska err = zfs_standard_error(hdl, errno, errbuf); 5332eda14cbcSMatt Macy break; 5333eda14cbcSMatt Macy } 5334eda14cbcSMatt Macy } 5335eda14cbcSMatt Macy 5336eda14cbcSMatt Macy return (err); 5337eda14cbcSMatt Macy } 5338eda14cbcSMatt Macy 5339eda14cbcSMatt Macy /* 5340eda14cbcSMatt Macy * The theory of raidz space accounting 5341eda14cbcSMatt Macy * 5342eda14cbcSMatt Macy * The "referenced" property of RAIDZ vdevs is scaled such that a 128KB block 5343eda14cbcSMatt Macy * will "reference" 128KB, even though it allocates more than that, to store the 5344eda14cbcSMatt Macy * parity information (and perhaps skip sectors). This concept of the 5345eda14cbcSMatt Macy * "referenced" (and other DMU space accounting) being lower than the allocated 5346eda14cbcSMatt Macy * space by a constant factor is called "raidz deflation." 5347eda14cbcSMatt Macy * 5348eda14cbcSMatt Macy * As mentioned above, the constant factor for raidz deflation assumes a 128KB 5349eda14cbcSMatt Macy * block size. However, zvols typically have a much smaller block size (default 5350eda14cbcSMatt Macy * 8KB). These smaller blocks may require proportionally much more parity 5351eda14cbcSMatt Macy * information (and perhaps skip sectors). In this case, the change to the 5352eda14cbcSMatt Macy * "referenced" property may be much more than the logical block size. 5353eda14cbcSMatt Macy * 5354eda14cbcSMatt Macy * Suppose a raidz vdev has 5 disks with ashift=12. A 128k block may be written 5355eda14cbcSMatt Macy * as follows. 5356eda14cbcSMatt Macy * 5357eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5358eda14cbcSMatt Macy * | disk1 | disk2 | disk3 | disk4 | disk5 | 5359eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5360eda14cbcSMatt Macy * | P0 | D0 | D8 | D16 | D24 | 5361eda14cbcSMatt Macy * | P1 | D1 | D9 | D17 | D25 | 5362eda14cbcSMatt Macy * | P2 | D2 | D10 | D18 | D26 | 5363eda14cbcSMatt Macy * | P3 | D3 | D11 | D19 | D27 | 5364eda14cbcSMatt Macy * | P4 | D4 | D12 | D20 | D28 | 5365eda14cbcSMatt Macy * | P5 | D5 | D13 | D21 | D29 | 5366eda14cbcSMatt Macy * | P6 | D6 | D14 | D22 | D30 | 5367eda14cbcSMatt Macy * | P7 | D7 | D15 | D23 | D31 | 5368eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5369eda14cbcSMatt Macy * 5370eda14cbcSMatt Macy * Above, notice that 160k was allocated: 8 x 4k parity sectors + 32 x 4k data 5371eda14cbcSMatt Macy * sectors. The dataset's referenced will increase by 128k and the pool's 5372eda14cbcSMatt Macy * allocated and free properties will be adjusted by 160k. 5373eda14cbcSMatt Macy * 5374eda14cbcSMatt Macy * A 4k block written to the same raidz vdev will require two 4k sectors. The 5375eda14cbcSMatt Macy * blank cells represent unallocated space. 5376eda14cbcSMatt Macy * 5377eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5378eda14cbcSMatt Macy * | disk1 | disk2 | disk3 | disk4 | disk5 | 5379eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5380eda14cbcSMatt Macy * | P0 | D0 | | | | 5381eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5382eda14cbcSMatt Macy * 5383eda14cbcSMatt Macy * Above, notice that the 4k block required one sector for parity and another 5384eda14cbcSMatt Macy * for data. vdev_raidz_asize() will return 8k and as such the pool's allocated 5385eda14cbcSMatt Macy * and free properties will be adjusted by 8k. The dataset will not be charged 5386eda14cbcSMatt Macy * 8k. Rather, it will be charged a value that is scaled according to the 5387eda14cbcSMatt Macy * overhead of the 128k block on the same vdev. This 8k allocation will be 5388eda14cbcSMatt Macy * charged 8k * 128k / 160k. 128k is from SPA_OLD_MAXBLOCKSIZE and 160k is as 5389eda14cbcSMatt Macy * calculated in the 128k block example above. 5390eda14cbcSMatt Macy * 5391eda14cbcSMatt Macy * Every raidz allocation is sized to be a multiple of nparity+1 sectors. That 5392eda14cbcSMatt Macy * is, every raidz1 allocation will be a multiple of 2 sectors, raidz2 5393eda14cbcSMatt Macy * allocations are a multiple of 3 sectors, and raidz3 allocations are a 5394eda14cbcSMatt Macy * multiple of of 4 sectors. When a block does not fill the required number of 5395eda14cbcSMatt Macy * sectors, skip blocks (sectors) are used. 5396eda14cbcSMatt Macy * 5397eda14cbcSMatt Macy * An 8k block being written to a raidz vdev may be written as follows: 5398eda14cbcSMatt Macy * 5399eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5400eda14cbcSMatt Macy * | disk1 | disk2 | disk3 | disk4 | disk5 | 5401eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5402eda14cbcSMatt Macy * | P0 | D0 | D1 | S0 | | 5403eda14cbcSMatt Macy * +-------+-------+-------+-------+-------+ 5404eda14cbcSMatt Macy * 5405eda14cbcSMatt Macy * In order to maintain the nparity+1 allocation size, a skip block (S0) was 5406eda14cbcSMatt Macy * added. For this 8k block, the pool's allocated and free properties are 5407eda14cbcSMatt Macy * adjusted by 16k and the dataset's referenced is increased by 16k * 128k / 5408eda14cbcSMatt Macy * 160k. Again, 128k is from SPA_OLD_MAXBLOCKSIZE and 160k is as calculated in 5409eda14cbcSMatt Macy * the 128k block example above. 5410eda14cbcSMatt Macy * 541116038816SMartin Matuska * The situation is slightly different for dRAID since the minimum allocation 54127877fdebSMatt Macy * size is the full group width. The same 8K block above would be written as 54137877fdebSMatt Macy * follows in a dRAID group: 54147877fdebSMatt Macy * 54157877fdebSMatt Macy * +-------+-------+-------+-------+-------+ 54167877fdebSMatt Macy * | disk1 | disk2 | disk3 | disk4 | disk5 | 54177877fdebSMatt Macy * +-------+-------+-------+-------+-------+ 54187877fdebSMatt Macy * | P0 | D0 | D1 | S0 | S1 | 54197877fdebSMatt Macy * +-------+-------+-------+-------+-------+ 54207877fdebSMatt Macy * 5421eda14cbcSMatt Macy * Compression may lead to a variety of block sizes being written for the same 5422eda14cbcSMatt Macy * volume or file. There is no clear way to reserve just the amount of space 5423eda14cbcSMatt Macy * that will be required, so the worst case (no compression) is assumed. 5424eda14cbcSMatt Macy * Note that metadata blocks will typically be compressed, so the reservation 5425eda14cbcSMatt Macy * size returned by zvol_volsize_to_reservation() will generally be slightly 5426eda14cbcSMatt Macy * larger than the maximum that the volume can reference. 5427eda14cbcSMatt Macy */ 5428eda14cbcSMatt Macy 5429eda14cbcSMatt Macy /* 5430eda14cbcSMatt Macy * Derived from function of same name in module/zfs/vdev_raidz.c. Returns the 5431eda14cbcSMatt Macy * amount of space (in bytes) that will be allocated for the specified block 5432eda14cbcSMatt Macy * size. Note that the "referenced" space accounted will be less than this, but 5433eda14cbcSMatt Macy * not necessarily equal to "blksize", due to RAIDZ deflation. 5434eda14cbcSMatt Macy */ 5435eda14cbcSMatt Macy static uint64_t 5436eda14cbcSMatt Macy vdev_raidz_asize(uint64_t ndisks, uint64_t nparity, uint64_t ashift, 5437eda14cbcSMatt Macy uint64_t blksize) 5438eda14cbcSMatt Macy { 5439eda14cbcSMatt Macy uint64_t asize, ndata; 5440eda14cbcSMatt Macy 5441eda14cbcSMatt Macy ASSERT3U(ndisks, >, nparity); 5442eda14cbcSMatt Macy ndata = ndisks - nparity; 5443eda14cbcSMatt Macy asize = ((blksize - 1) >> ashift) + 1; 5444eda14cbcSMatt Macy asize += nparity * ((asize + ndata - 1) / ndata); 5445eda14cbcSMatt Macy asize = roundup(asize, nparity + 1) << ashift; 5446eda14cbcSMatt Macy 5447eda14cbcSMatt Macy return (asize); 5448eda14cbcSMatt Macy } 5449eda14cbcSMatt Macy 5450eda14cbcSMatt Macy /* 54517877fdebSMatt Macy * Derived from function of same name in module/zfs/vdev_draid.c. Returns the 54527877fdebSMatt Macy * amount of space (in bytes) that will be allocated for the specified block 54537877fdebSMatt Macy * size. 54547877fdebSMatt Macy */ 54557877fdebSMatt Macy static uint64_t 54567877fdebSMatt Macy vdev_draid_asize(uint64_t ndisks, uint64_t nparity, uint64_t ashift, 54577877fdebSMatt Macy uint64_t blksize) 54587877fdebSMatt Macy { 54597877fdebSMatt Macy ASSERT3U(ndisks, >, nparity); 54607877fdebSMatt Macy uint64_t ndata = ndisks - nparity; 54617877fdebSMatt Macy uint64_t rows = ((blksize - 1) / (ndata << ashift)) + 1; 54627877fdebSMatt Macy uint64_t asize = (rows * ndisks) << ashift; 54637877fdebSMatt Macy 54647877fdebSMatt Macy return (asize); 54657877fdebSMatt Macy } 54667877fdebSMatt Macy 54677877fdebSMatt Macy /* 5468eda14cbcSMatt Macy * Determine how much space will be allocated if it lands on the most space- 5469eda14cbcSMatt Macy * inefficient top-level vdev. Returns the size in bytes required to store one 5470eda14cbcSMatt Macy * copy of the volume data. See theory comment above. 5471eda14cbcSMatt Macy */ 5472eda14cbcSMatt Macy static uint64_t 5473eda14cbcSMatt Macy volsize_from_vdevs(zpool_handle_t *zhp, uint64_t nblocks, uint64_t blksize) 5474eda14cbcSMatt Macy { 5475eda14cbcSMatt Macy nvlist_t *config, *tree, **vdevs; 54767877fdebSMatt Macy uint_t nvdevs; 5477eda14cbcSMatt Macy uint64_t ret = 0; 5478eda14cbcSMatt Macy 5479eda14cbcSMatt Macy config = zpool_get_config(zhp, NULL); 5480eda14cbcSMatt Macy if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) != 0 || 5481eda14cbcSMatt Macy nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, 5482eda14cbcSMatt Macy &vdevs, &nvdevs) != 0) { 5483eda14cbcSMatt Macy return (nblocks * blksize); 5484eda14cbcSMatt Macy } 5485eda14cbcSMatt Macy 54867877fdebSMatt Macy for (int v = 0; v < nvdevs; v++) { 5487eda14cbcSMatt Macy char *type; 5488eda14cbcSMatt Macy uint64_t nparity, ashift, asize, tsize; 5489eda14cbcSMatt Macy uint64_t volsize; 5490eda14cbcSMatt Macy 5491eda14cbcSMatt Macy if (nvlist_lookup_string(vdevs[v], ZPOOL_CONFIG_TYPE, 54927877fdebSMatt Macy &type) != 0) 5493eda14cbcSMatt Macy continue; 54947877fdebSMatt Macy 54957877fdebSMatt Macy if (strcmp(type, VDEV_TYPE_RAIDZ) != 0 && 54967877fdebSMatt Macy strcmp(type, VDEV_TYPE_DRAID) != 0) 54977877fdebSMatt Macy continue; 54987877fdebSMatt Macy 54997877fdebSMatt Macy if (nvlist_lookup_uint64(vdevs[v], 55007877fdebSMatt Macy ZPOOL_CONFIG_NPARITY, &nparity) != 0) 55017877fdebSMatt Macy continue; 55027877fdebSMatt Macy 55037877fdebSMatt Macy if (nvlist_lookup_uint64(vdevs[v], 55047877fdebSMatt Macy ZPOOL_CONFIG_ASHIFT, &ashift) != 0) 55057877fdebSMatt Macy continue; 55067877fdebSMatt Macy 55077877fdebSMatt Macy if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) { 55087877fdebSMatt Macy nvlist_t **disks; 55097877fdebSMatt Macy uint_t ndisks; 55107877fdebSMatt Macy 55117877fdebSMatt Macy if (nvlist_lookup_nvlist_array(vdevs[v], 55127877fdebSMatt Macy ZPOOL_CONFIG_CHILDREN, &disks, &ndisks) != 0) 55137877fdebSMatt Macy continue; 5514eda14cbcSMatt Macy 5515eda14cbcSMatt Macy /* allocation size for the "typical" 128k block */ 5516eda14cbcSMatt Macy tsize = vdev_raidz_asize(ndisks, nparity, ashift, 5517eda14cbcSMatt Macy SPA_OLD_MAXBLOCKSIZE); 55187877fdebSMatt Macy 5519eda14cbcSMatt Macy /* allocation size for the blksize block */ 55207877fdebSMatt Macy asize = vdev_raidz_asize(ndisks, nparity, ashift, 55217877fdebSMatt Macy blksize); 55227877fdebSMatt Macy } else { 55237877fdebSMatt Macy uint64_t ndata; 55247877fdebSMatt Macy 55257877fdebSMatt Macy if (nvlist_lookup_uint64(vdevs[v], 55267877fdebSMatt Macy ZPOOL_CONFIG_DRAID_NDATA, &ndata) != 0) 55277877fdebSMatt Macy continue; 55287877fdebSMatt Macy 55297877fdebSMatt Macy /* allocation size for the "typical" 128k block */ 55307877fdebSMatt Macy tsize = vdev_draid_asize(ndata + nparity, nparity, 55317877fdebSMatt Macy ashift, SPA_OLD_MAXBLOCKSIZE); 55327877fdebSMatt Macy 55337877fdebSMatt Macy /* allocation size for the blksize block */ 55347877fdebSMatt Macy asize = vdev_draid_asize(ndata + nparity, nparity, 55357877fdebSMatt Macy ashift, blksize); 55367877fdebSMatt Macy } 5537eda14cbcSMatt Macy 5538eda14cbcSMatt Macy /* 55397877fdebSMatt Macy * Scale this size down as a ratio of 128k / tsize. 55407877fdebSMatt Macy * See theory statement above. 5541eda14cbcSMatt Macy */ 5542eda14cbcSMatt Macy volsize = nblocks * asize * SPA_OLD_MAXBLOCKSIZE / tsize; 5543eda14cbcSMatt Macy if (volsize > ret) { 5544eda14cbcSMatt Macy ret = volsize; 5545eda14cbcSMatt Macy } 5546eda14cbcSMatt Macy } 5547eda14cbcSMatt Macy 5548eda14cbcSMatt Macy if (ret == 0) { 5549eda14cbcSMatt Macy ret = nblocks * blksize; 5550eda14cbcSMatt Macy } 5551eda14cbcSMatt Macy 5552eda14cbcSMatt Macy return (ret); 5553eda14cbcSMatt Macy } 5554eda14cbcSMatt Macy 5555eda14cbcSMatt Macy /* 5556eda14cbcSMatt Macy * Convert the zvol's volume size to an appropriate reservation. See theory 5557eda14cbcSMatt Macy * comment above. 5558eda14cbcSMatt Macy * 5559eda14cbcSMatt Macy * Note: If this routine is updated, it is necessary to update the ZFS test 5560eda14cbcSMatt Macy * suite's shell version in reservation.shlib. 5561eda14cbcSMatt Macy */ 5562eda14cbcSMatt Macy uint64_t 5563eda14cbcSMatt Macy zvol_volsize_to_reservation(zpool_handle_t *zph, uint64_t volsize, 5564eda14cbcSMatt Macy nvlist_t *props) 5565eda14cbcSMatt Macy { 5566eda14cbcSMatt Macy uint64_t numdb; 5567eda14cbcSMatt Macy uint64_t nblocks, volblocksize; 5568eda14cbcSMatt Macy int ncopies; 5569eda14cbcSMatt Macy char *strval; 5570eda14cbcSMatt Macy 5571eda14cbcSMatt Macy if (nvlist_lookup_string(props, 5572eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 5573eda14cbcSMatt Macy ncopies = atoi(strval); 5574eda14cbcSMatt Macy else 5575eda14cbcSMatt Macy ncopies = 1; 5576eda14cbcSMatt Macy if (nvlist_lookup_uint64(props, 5577eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 5578eda14cbcSMatt Macy &volblocksize) != 0) 5579eda14cbcSMatt Macy volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 5580eda14cbcSMatt Macy 5581eda14cbcSMatt Macy nblocks = volsize / volblocksize; 5582eda14cbcSMatt Macy /* 5583eda14cbcSMatt Macy * Metadata defaults to using 128k blocks, not volblocksize blocks. For 5584eda14cbcSMatt Macy * this reason, only the data blocks are scaled based on vdev config. 5585eda14cbcSMatt Macy */ 5586eda14cbcSMatt Macy volsize = volsize_from_vdevs(zph, nblocks, volblocksize); 5587eda14cbcSMatt Macy 5588eda14cbcSMatt Macy /* start with metadnode L0-L6 */ 5589eda14cbcSMatt Macy numdb = 7; 5590eda14cbcSMatt Macy /* calculate number of indirects */ 5591eda14cbcSMatt Macy while (nblocks > 1) { 5592eda14cbcSMatt Macy nblocks += DNODES_PER_LEVEL - 1; 5593eda14cbcSMatt Macy nblocks /= DNODES_PER_LEVEL; 5594eda14cbcSMatt Macy numdb += nblocks; 5595eda14cbcSMatt Macy } 5596eda14cbcSMatt Macy numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 5597eda14cbcSMatt Macy volsize *= ncopies; 5598eda14cbcSMatt Macy /* 5599eda14cbcSMatt Macy * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 5600eda14cbcSMatt Macy * compressed, but in practice they compress down to about 5601eda14cbcSMatt Macy * 1100 bytes 5602eda14cbcSMatt Macy */ 5603eda14cbcSMatt Macy numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 5604eda14cbcSMatt Macy volsize += numdb; 5605eda14cbcSMatt Macy return (volsize); 5606eda14cbcSMatt Macy } 5607eda14cbcSMatt Macy 5608eda14cbcSMatt Macy /* 5609eda14cbcSMatt Macy * Wait for the given activity and return the status of the wait (whether or not 5610eda14cbcSMatt Macy * any waiting was done) in the 'waited' parameter. Non-existent fses are 5611eda14cbcSMatt Macy * reported via the 'missing' parameter, rather than by printing an error 5612eda14cbcSMatt Macy * message. This is convenient when this function is called in a loop over a 5613eda14cbcSMatt Macy * long period of time (as it is, for example, by zfs's wait cmd). In that 5614eda14cbcSMatt Macy * scenario, a fs being exported or destroyed should be considered a normal 5615eda14cbcSMatt Macy * event, so we don't want to print an error when we find that the fs doesn't 5616eda14cbcSMatt Macy * exist. 5617eda14cbcSMatt Macy */ 5618eda14cbcSMatt Macy int 5619eda14cbcSMatt Macy zfs_wait_status(zfs_handle_t *zhp, zfs_wait_activity_t activity, 5620eda14cbcSMatt Macy boolean_t *missing, boolean_t *waited) 5621eda14cbcSMatt Macy { 5622eda14cbcSMatt Macy int error = lzc_wait_fs(zhp->zfs_name, activity, waited); 5623eda14cbcSMatt Macy *missing = (error == ENOENT); 5624eda14cbcSMatt Macy if (*missing) 5625eda14cbcSMatt Macy return (0); 5626eda14cbcSMatt Macy 5627eda14cbcSMatt Macy if (error != 0) { 5628eda14cbcSMatt Macy (void) zfs_standard_error_fmt(zhp->zfs_hdl, error, 5629eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "error waiting in fs '%s'"), 5630eda14cbcSMatt Macy zhp->zfs_name); 5631eda14cbcSMatt Macy } 5632eda14cbcSMatt Macy 5633eda14cbcSMatt Macy return (error); 5634eda14cbcSMatt Macy } 5635