libzfs_dataset.c revision 5c5460e9570bdcad6b03b01c30ceb683a77ceb88
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER START
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file are subject to the terms of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Common Development and Distribution License, Version 1.0 only
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (the "License"). You may not use this file except in compliance
fa9e4066f08beec538e775443c5be79dd423fcabahrens * with the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * See the License for the specific language governing permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and limitations under the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When distributing Covered Code, include this CDDL HEADER in each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If applicable, add the following below this CDDL HEADER, with the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fields enclosed by brackets "[]" replaced with your own identifying
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information: Portions Copyright [yyyy] [name of copyright owner]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER END
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Use is subject to license terms.
fa9e4066f08beec538e775443c5be79dd423fcabahrens#pragma ident "%Z%%M% %I% %E% SMI"
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a single type (not a mask of types), return the type in a human
fa9e4066f08beec538e775443c5be79dd423fcabahrens * readable form.
fa9e4066f08beec538e775443c5be79dd423fcabahrensconst char *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a path and mask of ZFS types, return a string describing this dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This is used when we fail to open a dataset and we cannot get an exact type.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We guess what the type would have been based on the path and the mask of
fa9e4066f08beec538e775443c5be79dd423fcabahrens * acceptable types.
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic const char *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When given a single type, always report the exact type.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The user is requesting more than one type of dataset. If this is the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * case, consult the path itself. If we're looking for a snapshot, and
fa9e4066f08beec538e775443c5be79dd423fcabahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * snapshot attribute and try again.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The user has requested either filesystems or volumes.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We have no way of knowing a priori what type this would be, so always
fa9e4066f08beec538e775443c5be79dd423fcabahrens * report it as "filesystem" or "volume", our two primitive types.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Validate a ZFS path. This is used even before trying to open the dataset, to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * provide a more meaningful error message. We place a more useful message in
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'buf' detailing exactly why the name was not valid.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_validate_name(const char *path, int type, char *buf, size_t buflen)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Utility function to gather stats (objset and zpl) for the given object.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * get the generic DMU stats and per-type (zfs, zvol) stats
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens bcopy(&zc.zc_zfs_stats, &zhp->zfs_zplstats, sizeof (zc.zc_zfs_stats));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Refresh the properties currently stored in the handle.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Makes a handle from the given dataset name. Used by zfs_open() and
fa9e4066f08beec538e775443c5be79dd423fcabahrens * zfs_iter_* to create child handles on the fly.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_handle_t *zhp = zfs_malloc(sizeof (zfs_handle_t));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We've managed to open the dataset and gather statistics. Determine
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the high-level type.
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* we should never see any other dataset types */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Opens the given snapshot, filesystem, or volume. The 'types'
fa9e4066f08beec538e775443c5be79dd423fcabahrens * argument is a mask of acceptable types. The function will print an
fa9e4066f08beec538e775443c5be79dd423fcabahrens * appropriate error message and return NULL if it can't be opened.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Validate the name before we even try to open it. We don't care about
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the verbose invalid messages here; just report a generic error.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Try to get stats for the dataset, which will tell us if it exists.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The dataset doesn't exist.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We were able to open the dataset but couldn't
fa9e4066f08beec538e775443c5be79dd423fcabahrens * get the stats.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': operation "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Release a ZFS handle. Nothing to do but free the associated memory.
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *name;
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *name;
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *name;
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *name;
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *name;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a numeric suffix, convert the value into a number of bits that the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * resulting value must be shifted.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid "
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't
fa9e4066f08beec538e775443c5be79dd423fcabahrens * allow 'BB' - that's just weird.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (10*i);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid numeric "
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Convert a string of the form '100G' into a real number. Used when setting
fa9e4066f08beec538e775443c5be79dd423fcabahrens * properties or creating a volume. 'buf' is used to place an extended error
fa9e4066f08beec538e775443c5be79dd423fcabahrens * message for the caller to use.
fa9e4066f08beec538e775443c5be79dd423fcabahrensnicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Check to see if this looks like a number. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Rely on stroll() to process the numeric portion. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check for ERANGE, which indicates that the value is too large to fit
fa9e4066f08beec538e775443c5be79dd423fcabahrens * in a 64-bit value.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If we have a decimal value, then do the computation with floating
fa9e4066f08beec538e775443c5be79dd423fcabahrens * point arithmetic. Otherwise, use standard arithmetic.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Check for overflow */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (shift >= 64 || (*num << shift) >> shift != *num) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a property type and value, verify that the value is appropriate. Used
fa9e4066f08beec538e775443c5be79dd423fcabahrens * by zfs_prop_set() and some libzfs consumers.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check to see if this a read-only property.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot set %s property: read-only property"), propname);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* See if the property value is too long */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Perform basic checking based on property type */
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be 'on' or 'off'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* treat 'none' as 0 */
fa9e4066f08beec538e775443c5be79dd423fcabahrens sizeof (reason)) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* don't allow 0 for quota, use 'none' instead */
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': use '%s=none' to disable"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "must be power of 2 from %u to %uk"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The two writable string values, 'mountpoint' and
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'checksum' need special consideration. The 'index' types are
fa9e4066f08beec538e775443c5be79dd423fcabahrens * specified as strings by the user, but passed to the kernel as
fa9e4066f08beec538e775443c5be79dd423fcabahrens * integers.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be an absolute "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "path, 'none', or 'legacy'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be 'on', 'off', "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "'fletcher2', 'fletcher4', or 'sha256'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be 'on', 'off', "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "or 'lzjb'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be 'hidden' "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "or 'visible'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be 'discard', "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "'groupmask' or 'passthrough'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad %s value '%s': must be 'discard', "
de122929e7c37df60cbea70616404e22d20e025bmarks "'noallow', 'secure' or 'passthrough'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Nothing to do for 'sharenfs', this gets passed on to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * share(1M) verbatim.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a property name and value, set the property for the given dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check to see if the value applies to this type
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot set %s for '%s': property does not apply to %ss"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens propname, zhp->zfs_name, zfs_type_to_name(zhp->zfs_type));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * For the mountpoint and sharenfs properties, check if it can be set
fa9e4066f08beec538e775443c5be79dd423fcabahrens * in a global/non-global zone based on the zoned property value:
fa9e4066f08beec538e775443c5be79dd423fcabahrens * global zone non-global zone
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -----------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * zoned=on mountpoint (no) mountpoint (yes)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * sharenfs (no) sharenfs (no)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * zoned=off mountpoint (yes) N/A
fa9e4066f08beec538e775443c5be79dd423fcabahrens * sharenfs (yes)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "cannot set %s for '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "dataset is used in a non-global zone"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "cannot set %s for '%s': filesystems "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot be shared in a non-global zone"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If zoned property is 'off', this must be in
fa9e4066f08beec538e775443c5be79dd423fcabahrens * a globle zone. If not, something is wrong.
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "cannot set %s for '%s': dataset is "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "used in a non-global zone, but 'zoned' "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "property is not set"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for '%s', "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "child dataset with inherited mountpoint is used "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "in a non-global zone"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Execute the corresponding ioctl() to set this property.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * These properties are passed down as real strings.
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* LINTED - alignment */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot set %s for '%s': permission "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * For quotas and reservations, ENOSPC indicates
fa9e4066f08beec538e775443c5be79dd423fcabahrens * something different; setting a quota or reservation
fa9e4066f08beec538e775443c5be79dd423fcabahrens * doesn't use any disk space.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "for '%s': size is less than current "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "for '%s': size is greater than available "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot set %s for '%s': out of space"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot set %s for '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "volume already contains data"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This platform can't address a volume this big.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot set %s for '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "max volume size is 1TB on 32-bit systems"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Refresh the statistics so the new property value
fa9e4066f08beec538e775443c5be79dd423fcabahrens * is reflected.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a property, inherit the value from the parent dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Verify that this property is inheritable.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot inherit %s for '%s': property is read-only"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot inherit %s for '%s': property is not inheritable"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check to see if the value applies to this type
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot inherit %s for '%s': property does "
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', "
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine datasets which will be affected by this change, if any.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "child dataset with inherited mountpoint is "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "used in a non-global zone"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((ret = ioctl(zfs_fd, ZFS_IOC_SET_PROP, &zc)) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot inherit %s for '%s': permission "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot inherit %s for '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Refresh the statistics so the new property is reflected.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Internal function for getting a numeric property. Both zfs_prop_get() and
fa9e4066f08beec538e775443c5be79dd423fcabahrens * zfs_prop_get_int() are built using this interface.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Certain properties can be overridden using 'mount -o'. In this case, scan
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the contents of the /etc/mnttab entry, searching for the appropriate options.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If they differ from the on-disk values, report the current values and mark
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the source "temporary".
fa9e4066f08beec538e775443c5be79dd423fcabahrensget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
fa9e4066f08beec538e775443c5be79dd423fcabahrens } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && val) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens *source = zhp->zfs_dmustats.dds_compression_setpoint;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Using physical space and logical space, calculate the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * compression ratio. We return the number as a multiple of
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 100, so '2.5x' would be returned as 250.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (100ULL);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 /
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'referenced' refers to the amount of physical space
fa9e4066f08beec538e775443c5be79dd423fcabahrens * referenced (possibly shared) by this object.
fa9e4066f08beec538e775443c5be79dd423fcabahrens } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && val) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Unlike other properties, we defer calculation of 'MOUNTED'
fa9e4066f08beec538e775443c5be79dd423fcabahrens * until actually requested. This is because the getmntany()
fa9e4066f08beec538e775443c5be79dd423fcabahrens * call can be extremely expensive on systems with a large
fa9e4066f08beec538e775443c5be79dd423fcabahrens * number of filesystems, and the property isn't needed in
fa9e4066f08beec538e775443c5be79dd423fcabahrens * normal use cases.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Calculate the source type, given the raw source string.
fa9e4066f08beec538e775443c5be79dd423fcabahrensget_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source,
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Retrieve a property from the given object. If 'literal' is specified, then
fa9e4066f08beec538e775443c5be79dd423fcabahrens * numbers are left as exact values. Otherwise, numbers are converted to a
fa9e4066f08beec538e775443c5be79dd423fcabahrens * human-readable form.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Returns 0 on success, or -1 on error.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_source_t *src, char *statbuf, size_t statlen, int literal)
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *root;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check to see if this property applies to our object
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Basic boolean values are built on top of
fa9e4066f08beec538e775443c5be79dd423fcabahrens * get_numeric_property().
fa9e4066f08beec538e775443c5be79dd423fcabahrens nicebool(get_numeric_property(zhp, prop, src, &source),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Basic numeric values are built on top of
fa9e4066f08beec538e775443c5be79dd423fcabahrens * get_numeric_property().
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, compress_table[i].name, proplen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, checksum_table[i].name, proplen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, snapdir_table[i].name, proplen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, acl_mode_table[i].name, proplen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'creation' is a time_t stored in the statistics. We convert
fa9e4066f08beec538e775443c5be79dd423fcabahrens * this into a string unless 'literal' is specified.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Getting the precise mountpoint can be tricky.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - for 'none' or 'legacy', return those values.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - for default mountpoints, construct it as /zfs/<dataset>
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - for inherited mountpoints, we want to take everything
fa9e4066f08beec538e775443c5be79dd423fcabahrens * after our ancestor and append it to the inherited value.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If the pool has an alternate root, we want to prepend that
fa9e4066f08beec538e775443c5be79dd423fcabahrens * root to any values we return.
fa9e4066f08beec538e775443c5be79dd423fcabahrens } else if (zhp->zfs_zplstats.zs_mountpoint[0] == '/') {
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *mntpoint = zhp->zfs_zplstats.zs_mountpoint;
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* 'legacy' or 'none' */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, zhp->zfs_zplstats.zs_mountpoint,
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, zhp->zfs_zplstats.zs_sharenfs, proplen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If there is no parent at all, return failure to indicate that
fa9e4066f08beec538e775443c5be79dd423fcabahrens * it doesn't apply to this dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If quota or reservation is 0, we translate this into 'none'
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (unless literal is set), and indicate that it's the default
fa9e4066f08beec538e775443c5be79dd423fcabahrens * value. Otherwise, we print the number nicely and indicate
fa9e4066f08beec538e775443c5be79dd423fcabahrens * that its set locally.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (val == 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The 'mounted' property is a pseudo-property that described
fa9e4066f08beec538e775443c5be79dd423fcabahrens * whether the filesystem is currently mounted. Even though
fa9e4066f08beec538e775443c5be79dd423fcabahrens * it's a boolean value, the typical values of "on" and "off"
fa9e4066f08beec538e775443c5be79dd423fcabahrens * don't make sense, so we translate to "yes" and "no".
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, src, &source))
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The 'name' property is a pseudo-property derived from the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * dataset name. It is presented as a real property to simplify
fa9e4066f08beec538e775443c5be79dd423fcabahrens * consumers.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Utility function to get the given numeric property. Does no validation that
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the given property is the appropriate type; should only be used with
fa9e4066f08beec538e775443c5be79dd423fcabahrens * hard-coded property types.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (get_numeric_property(zhp, prop, &sourcetype, &source));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Similar to zfs_prop_get(), but returns the value as an integer.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check to see if this property applies to our object
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens *value = get_numeric_property(zhp, prop, src, &source);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Returns the name of the given zfs handle.
fa9e4066f08beec538e775443c5be79dd423fcabahrensconst char *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Returns the type of the given zfs handle.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Iterate over all children, datasets and snapshots.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
fa9e4066f08beec538e775443c5be79dd423fcabahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Ignore private dataset names.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Silently ignore errors, as the only plausible explanation is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * that the pool has since been removed.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * An errno value of ESRCH indicates normal completion. If ENOENT is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * returned, then the underlying dataset has been removed since we
fa9e4066f08beec538e775443c5be79dd423fcabahrens * obtained the handle.
fa9e4066f08beec538e775443c5be79dd423fcabahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * An errno value of ESRCH indicates normal completion. If ENOENT is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * returned, then the underlying dataset has been removed since we
fa9e4066f08beec538e775443c5be79dd423fcabahrens * obtained the handle. Silently ignore this case, and return success.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a complete name, return just the portion that refers to the parent.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Can return NULL if this is a pool.
fa9e4066f08beec538e775443c5be79dd423fcabahrensparent_name(const char *path, char *buf, size_t buflen)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Checks to make sure that the given path has a parent, and that it exists.
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* get parent, and check to see if this is just a pool */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (parent_name(path, parent, sizeof (parent)) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': missing dataset name"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens "use 'zpool create' to create a storage pool"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* check to see if the pool exists */
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': no such pool '%s'"), path, zc.zc_name);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* check to see if the parent dataset exists */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, parent, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* we are in a non-global zone, but parent is in the global zone */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (getzoneid() != GLOBAL_ZONEID && !zc.zc_objset_stats.dds_zoned) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* make sure parent is a filesystem */
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': parent is not a filesystem"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used
fa9e4066f08beec538e775443c5be79dd423fcabahrens * only for volumes, and indicate the size and blocksize of the volume.
fa9e4066f08beec538e775443c5be79dd423fcabahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* convert sizestr into integer size */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* convert blocksizestr into integer blocksize */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (blocksizestr != NULL && nicestrtonum(blocksizestr, &blocksize,
fa9e4066f08beec538e775443c5be79dd423fcabahrens "bad volume blocksize '%s': %s"), blocksizestr, reason);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* validate the path, taking care to note the extended error message */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!zfs_validate_name(path, type, reason, sizeof (reason))) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "use 'zfs snapshot' to create a snapshot"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* validate parents exist */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The failure modes when creating a dataset of a different type over
fa9e4066f08beec538e775443c5be79dd423fcabahrens * one that already exists is a little strange. In particular, if you
fa9e4066f08beec538e775443c5be79dd423fcabahrens * try to create a dataset on top of an existing dataset, the ioctl()
fa9e4066f08beec538e775443c5be79dd423fcabahrens * will return ENOENT, not EEXIST. To prevent this from happening, we
fa9e4066f08beec538e775443c5be79dd423fcabahrens * first try to see if the dataset exists.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock * If we are creating a volume, the size and block size must
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock * satisfy a few restraints. First, the blocksize must be a
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock * volsize must be a multiple of the block size, and cannot be
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (size == 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) {
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "bad volume block size '%s': "
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "must be power of 2 from %u to %uk"),
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock return (-1);
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "bad volume size '%s': "
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock "must be multiple of volume block size (%s)"),
5c5460e9570bdcad6b03b01c30ceb683a77ceb88eschrock return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* create the dataset */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* check for failure */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The parent dataset has been deleted since our
fa9e4066f08beec538e775443c5be79dd423fcabahrens * previous check.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': no such parent '%s'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The user doesn't have permission to create a new
fa9e4066f08beec538e775443c5be79dd423fcabahrens * dataset here.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The parent dataset does not have enough free space
fa9e4066f08beec538e775443c5be79dd423fcabahrens * to create a new dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': not enough space in '%s'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The target dataset already exists. We should have
fa9e4066f08beec538e775443c5be79dd423fcabahrens * caught this above, but there may be some unexplained
fa9e4066f08beec538e775443c5be79dd423fcabahrens * race condition.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The target dataset does not support children.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': children unsupported in '%s'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "bad %s value '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "must be power of 2 from %u to %uk"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This platform can't address a volume this big.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "max volume size is 1TB on 32-bit systems"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Destroys the given dataset. The caller must make sure that the filesystem
fa9e4066f08beec538e775443c5be79dd423fcabahrens * isn't mounted, and that there are no active dependents.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME
fa9e4066f08beec538e775443c5be79dd423fcabahrens * so that we do the right thing for snapshots of volumes.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We don't have permission to destroy this dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot destroy '%s': permission denied"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We've hit a race condition where the dataset has been
fa9e4066f08beec538e775443c5be79dd423fcabahrens * destroyed since we opened it.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot destroy '%s': no such %s"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Even if we destroy all children, there is a chance we
fa9e4066f08beec538e775443c5be79dd423fcabahrens * can hit this case if:
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - A child dataset has since been created
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - A filesystem is mounted
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This error message is awful, but hopefully we've
fa9e4066f08beec538e775443c5be79dd423fcabahrens * already caught the common cases (and aborted more
fa9e4066f08beec538e775443c5be79dd423fcabahrens * appropriately) before calling this function. There's
fa9e4066f08beec538e775443c5be79dd423fcabahrens * nothing else we can do at this point.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot destroy '%s': %s is busy"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Clones the given dataset. The target must be of the same type as the source.
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* validate the target name */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!zfs_validate_name(target, ZFS_TYPE_FILESYSTEM, reason,
fa9e4066f08beec538e775443c5be79dd423fcabahrens sizeof (reason))) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': %s in filesystem name"), target,
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* validate parents exist */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* do the clone */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename));
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The user doesn't have permission to create the clone.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': permission denied"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The parent doesn't exist. We should have caught this
fa9e4066f08beec538e775443c5be79dd423fcabahrens * above, but there may a race condition that has since
fa9e4066f08beec538e775443c5be79dd423fcabahrens * destroyed the parent.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * At this point, we don't know whether it's the source
fa9e4066f08beec538e775443c5be79dd423fcabahrens * that doesn't exist anymore, or whether the target
fa9e4066f08beec538e775443c5be79dd423fcabahrens * dataset doesn't exist.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': no such parent '%s'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * There is not enough space in the target dataset
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': not enough space in '%s'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The target already exists.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The source and target pools differ.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Takes a snapshot of the given dataset
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *delim;
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* validate the snapshot name */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!zfs_validate_name(path, ZFS_TYPE_SNAPSHOT, reason,
fa9e4066f08beec538e775443c5be79dd423fcabahrens sizeof (reason))) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* make sure we have a snapshot */
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot snapshot '%s': missing '@' delim in snapshot "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "use 'zfs create' to create a filesystem"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* make sure the parent exists and is of the appropriate type */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * User doesn't have permission to create a snapshot
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Out of space in parent.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Snapshot already exists.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Shouldn't happen because we verified the parent
fa9e4066f08beec538e775443c5be79dd423fcabahrens * above. But there may be a race condition where it
fa9e4066f08beec538e775443c5be79dd423fcabahrens * has since been removed.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_backup(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* do the ioctl() */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * User doesn't have permission to do a backup
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot backup '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot do incremental backup from %s:\n"
fa9e4066f08beec538e775443c5be79dd423fcabahrens "it is not an earlier snapshot from the "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "same fs as %s"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Shouldn't happen because we verified the parent
fa9e4066f08beec538e775443c5be79dd423fcabahrens * above. But there may be a race condition where it
fa9e4066f08beec538e775443c5be79dd423fcabahrens * has since been removed.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "no such snapshot"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot write backup stream: %s"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens "backup failed: signal recieved"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Restores a backup of tosnap from stdin.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_restore(const char *tosnap, int isprefix, int verbose, int dryrun)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* trim off snapname, if any */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* read in the BEGIN record */
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens } while (size > 0);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: invalid backup stream "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "(couldn't read first record)"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: invalid backup stream "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "(invalid magic number)"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: only backup version 0x%llx is supported, "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "stream is version %llx."),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine name of destination snapshot.
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "argument to -d must be a filesystem"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * they specified just a filesystem; tack on the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * snapname from the backup.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) {
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: invalid backup stream "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "(invalid snapshot name)"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* incremental backup stream */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* do the ioctl to the containing fs */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* make sure destination fs exists */
fa9e4066f08beec538e775443c5be79dd423fcabahrens h = zfs_open(zc.zc_name, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (h == NULL) {
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore incrememtal backup: destination\n"
fa9e4066f08beec538e775443c5be79dd423fcabahrens "filesystem %s does not exist"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens /* unmount destination fs or remove device link. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* full backup stream */
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens /* make sure they aren't trying to restore into the root */
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: destination fs %s already exists"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens /* make sure prefix exists */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (h == NULL) {
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "filesystem %s does not exist"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* create any necessary ancestors up to prefix */
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens * zc.zc_name is now the full name of the snap
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens * we're restoring into
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "couldn't create ancestor %s"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens /* Make sure destination fs does not exist */
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore full backup: "
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "destination filesystem %s already exists"),
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens return (-1);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens /* Do the recvbackup ioctl to the fs's parent. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens err = ioctl_err = ioctl(zfs_fd, ZFS_IOC_RECVBACKUP, &zc);
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: "
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "most recent snapshot does not "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "match incremental backup source"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: "
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "destination has been modified since "
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "most recent snapshot --\n"
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "use 'zfs rollback' to discard changes"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* it's the containing fs that exists */
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore to %s: destination already exists"),
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: destination does not exist"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: destination is in use"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: out of space"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: quota exceeded"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "restore failed: signal recieved"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: invalid backup stream"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens "cannot restore: permission denied"));
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens * Mount or recreate the /dev links for the target filesystem
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens * (if created, or if we tore them down to do an incremental
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens * restore), and the /dev links for the new snapshot (if
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens * created).
9b4f025ea51100e697da5c5d6afbcb60aee41c73ahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) printf("restored %sb backup in %lu seconds (%sb/sec)\n",
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Rollback the given dataset to the previous snapshot. It is up to the caller
fa9e4066f08beec538e775443c5be79dd423fcabahrens * to verify that there is a previous snapshot available.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We rely on the consumer to verify that there are no newer snapshots
fa9e4066f08beec538e775443c5be79dd423fcabahrens * for the given dataset. Given these constraints, we can simply pass
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the name on to the ioctl() call. There is still an unlikely race
fa9e4066f08beec538e775443c5be79dd423fcabahrens * condition where the user has taken a snapshot since we verified that
fa9e4066f08beec538e775443c5be79dd423fcabahrens * this was the most recent.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((ret = ioctl(zfs_fd, ZFS_IOC_ROLLBACK, &zc)) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The user doesn't have permission to rollback the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * given dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The parent dataset doesn't have enough space to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * rollback to the last snapshot.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The dataset doesn't exist. This shouldn't happen
fa9e4066f08beec538e775443c5be79dd423fcabahrens * except in race conditions.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The filesystem is busy. This should have been caught
fa9e4066f08beec538e775443c5be79dd423fcabahrens * by the caller before getting here, but there may be
fa9e4066f08beec538e775443c5be79dd423fcabahrens * an unexpected problem.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Iterate over all dependents for a given dataset. This includes both
fa9e4066f08beec538e775443c5be79dd423fcabahrens * hierarchical dependents (children) and data dependents (snapshots and
fa9e4066f08beec538e775443c5be79dd423fcabahrens * clones). The bulk of the processing occurs in get_dependents() in
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data)
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i < count; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((child = make_dataset_handle(dependents[i])) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i < count; i++)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Renames the given dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value));
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* if we have the same exact name, just return success */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Make sure the target name is valid
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!zfs_validate_name(target, zhp->zfs_type, reason,
fa9e4066f08beec538e775443c5be79dd423fcabahrens sizeof (reason))) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot create '%s': %s in %s name"), target, reason,
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Make sure we're renaming within the same dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot rename to '%s': snapshots must be part "
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* validate parents */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* make sure we're in the same pool */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot rename to '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "dataset is used in a non-global zone"), zhp->zfs_name);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens "cannot rename '%s': child dataset with inherited "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "mountpoint is used in a non-global zone"), zhp->zfs_name);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((ret = ioctl(zfs_fd, ZFS_IOC_RENAME, &zc)) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The user doesn't have permission to rename the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * given dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Not enough space in the parent dataset.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "rename '%s': not enough space in '%s'"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The destination doesn't exist.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "to '%s': destination doesn't exist"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The destination already exists.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' "
fa9e4066f08beec538e775443c5be79dd423fcabahrens "to '%s': destination already exists"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The filesystem is busy. This should have been caught
fa9e4066f08beec538e775443c5be79dd423fcabahrens * by the caller before getting here, but there may be
fa9e4066f08beec538e775443c5be79dd423fcabahrens * an unexpected problem.
fa9e4066f08beec538e775443c5be79dd423fcabahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': "
fa9e4066f08beec538e775443c5be79dd423fcabahrens * On failure, we still want to remount any filesystems that
fa9e4066f08beec538e775443c5be79dd423fcabahrens * were previously mounted, so we don't alter the system state.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * poke devfsadm to create the /dev link, and then wait for the link to appear.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Issue the appropriate ioctl.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "device links for '%s': permission denied"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Silently ignore the case where the link already
fa9e4066f08beec538e775443c5be79dd423fcabahrens * exists. This allows 'zfs volinit' to be run multiple
fa9e4066f08beec538e775443c5be79dd423fcabahrens * times without errors.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Call devfsadm and wait for the links to magically appear.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((hdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Remove a minor node for the given zvol and the associated /dev links.
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "device links for '%s': permission denied"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens "device links for '%s': volume is in use"),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Silently ignore the case where the link no longer
fa9e4066f08beec538e775443c5be79dd423fcabahrens * exists, so that 'zfs volfini' can be run multiple
fa9e4066f08beec538e775443c5be79dd423fcabahrens * times without errors.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);