diff options
-rw-r--r-- | cddl/contrib/opensolaris/cmd/zfs/zfs.8 | 14 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/cmd/zfs/zfs_main.c | 76 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h | 3 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c | 184 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c | 16 |
5 files changed, 194 insertions, 99 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8 index 9cfa4de..5eca00f 100644 --- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 +++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8 @@ -18,7 +18,7 @@ .\" information: Portions Copyright [yyyy] [name of copyright owner] .\" .\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved. -.\" Copyright (c) 2014 by Delphix. All rights reserved. +.\" Copyright (c) 2011, 2014 by Delphix. All rights reserved. .\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org> .\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org> .\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org> @@ -117,7 +117,7 @@ .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Nm .Cm set -.Ar property Ns = Ns Ar value +.Ar property Ns = Ns Ar value Oc ... .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ... .Nm .Cm get @@ -2121,14 +2121,14 @@ option, but sorts by property in descending order. .It Xo .Nm .Cm set -.Ar property Ns = Ns Ar value +.Ar property Ns = Ns Ar value Oc ... .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Xc .Pp -Sets the property to the given value for each dataset. Only some properties can -be edited. See the "Properties" section for more information on what properties -can be set and acceptable values. Numeric values can be specified as exact -values, or in a human-readable form with a suffix of +Sets the property or list of properties to the given value(s) for each dataset. +Only some properties can be edited. See the "Properties" section for more +information on what properties can be set and acceptable values. Numeric values +can be specified as exact values, or in a human-readable form with a suffix of .Sy B , K , M , G , T , P , E , Z (for bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes, exabytes, or zettabytes, respectively). User properties can be set on snapshots. For more diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c index 9b123ce..e3ac1ca 100644 --- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c +++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c @@ -283,7 +283,7 @@ get_usage(zfs_help_t idx) "<filesystem|volume|snapshot>\n" "\tsend [-nvPe] -t <receive_resume_token>\n")); case HELP_SET: - return (gettext("\tset <property=value> " + return (gettext("\tset <property=value> ... " "<filesystem|volume|snapshot> ...\n")); case HELP_SHARE: return (gettext("\tshare <-a | filesystem>\n")); @@ -498,6 +498,10 @@ usage(boolean_t requested) exit(requested ? 0 : 2); } +/* + * Take a property=value argument string and add it to the given nvlist. + * Modifies the argument inplace. + */ static int parseprop(nvlist_t *props, char *propname) { @@ -505,7 +509,7 @@ parseprop(nvlist_t *props, char *propname) if ((propval = strchr(propname, '=')) == NULL) { (void) fprintf(stderr, gettext("missing " - "'=' for -o option\n")); + "'=' for property=value argument\n")); return (-1); } *propval = '\0'; @@ -632,7 +636,7 @@ zfs_do_clone(int argc, char **argv) while ((c = getopt(argc, argv, "o:p")) != -1) { switch (c) { case 'o': - if (parseprop(props, optarg)) + if (parseprop(props, optarg) != 0) return (1); break; case 'p': @@ -3532,21 +3536,17 @@ out: } /* - * zfs set property=value { fs | snap | vol } ... + * zfs set property=value ... { fs | snap | vol } ... * - * Sets the given property for all datasets specified on the command line. + * Sets the given properties for all datasets specified on the command line. */ -typedef struct set_cbdata { - char *cb_propname; - char *cb_value; -} set_cbdata_t; static int set_callback(zfs_handle_t *zhp, void *data) { - set_cbdata_t *cbp = data; + nvlist_t *props = data; - if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) { + if (zfs_prop_set_list(zhp, props) != 0) { switch (libzfs_errno(g_zfs)) { case EZFS_MOUNTFAILED: (void) fprintf(stderr, gettext("property may be set " @@ -3565,7 +3565,8 @@ set_callback(zfs_handle_t *zhp, void *data) static int zfs_do_set(int argc, char **argv) { - set_cbdata_t cb; + nvlist_t *props = NULL; + int ds_start = -1; /* argv idx of first dataset arg */ int ret = 0; /* check for options */ @@ -3577,36 +3578,51 @@ zfs_do_set(int argc, char **argv) /* check number of arguments */ if (argc < 2) { - (void) fprintf(stderr, gettext("missing property=value " - "argument\n")); + (void) fprintf(stderr, gettext("missing arguments\n")); usage(B_FALSE); } if (argc < 3) { - (void) fprintf(stderr, gettext("missing dataset name\n")); + if (strchr(argv[1], '=') == NULL) { + (void) fprintf(stderr, gettext("missing property=value " + "argument(s)\n")); + } else { + (void) fprintf(stderr, gettext("missing dataset " + "name(s)\n")); + } usage(B_FALSE); } - /* validate property=value argument */ - cb.cb_propname = argv[1]; - if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) || - (cb.cb_value[1] == '\0')) { - (void) fprintf(stderr, gettext("missing value in " - "property=value argument\n")); + /* validate argument order: prop=val args followed by dataset args */ + for (int i = 1; i < argc; i++) { + if (strchr(argv[i], '=') != NULL) { + if (ds_start > 0) { + /* out-of-order prop=val argument */ + (void) fprintf(stderr, gettext("invalid " + "argument order\n"), i); + usage(B_FALSE); + } + } else if (ds_start < 0) { + ds_start = i; + } + } + if (ds_start < 0) { + (void) fprintf(stderr, gettext("missing dataset name(s)\n")); usage(B_FALSE); } - *cb.cb_value = '\0'; - cb.cb_value++; - - if (*cb.cb_propname == '\0') { - (void) fprintf(stderr, - gettext("missing property in property=value argument\n")); - usage(B_FALSE); + /* Populate a list of property settings */ + if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) + nomem(); + for (int i = 1; i < ds_start; i++) { + if ((ret = parseprop(props, argv[i])) != 0) + goto error; } - ret = zfs_for_each(argc - 2, argv + 2, 0, - ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb); + ret = zfs_for_each(argc - ds_start, argv + ds_start, 0, + ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, props); +error: + nvlist_free(props); return (ret); } diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h index 4841040..80a31c0 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -23,7 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>. * All rights reserved. - * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. @@ -430,6 +430,7 @@ extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t, extern const char *zfs_prop_to_name(zfs_prop_t); extern int zfs_prop_set(zfs_handle_t *, const char *, const char *); +extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *); extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t, zprop_source_t *, char *, size_t, boolean_t); extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t, diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c index f6c86cf..11b3df3 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -1534,15 +1534,10 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, int zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) { - zfs_cmd_t zc = { 0 }; int ret = -1; - prop_changelist_t *cl = NULL; char errbuf[1024]; libzfs_handle_t *hdl = zhp->zfs_hdl; - nvlist_t *nvl = NULL, *realprops; - zfs_prop_t prop; - boolean_t do_prefix = B_TRUE; - int added_resv; + nvlist_t *nvl = NULL; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), @@ -1554,79 +1549,148 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) goto error; } - if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, - zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) - goto error; + ret = zfs_prop_set_list(zhp, nvl); +error: nvlist_free(nvl); - nvl = realprops; + return (ret); +} - prop = zfs_name_to_prop(propname); - /* We don't support those properties on FreeBSD. */ - switch (prop) { - case ZFS_PROP_DEVICES: - case ZFS_PROP_ISCSIOPTIONS: - case ZFS_PROP_XATTR: - case ZFS_PROP_VSCAN: - case ZFS_PROP_NBMAND: - case ZFS_PROP_MLSLABEL: - (void) snprintf(errbuf, sizeof (errbuf), - "property '%s' not supported on FreeBSD", propname); - ret = zfs_error(hdl, EZFS_PERM, errbuf); - goto error; - } - if (prop == ZFS_PROP_VOLSIZE) { - if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) - goto error; - } +/* + * Given an nvlist of property names and values, set the properties for the + * given dataset. + */ +int +zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props) +{ + zfs_cmd_t zc = { 0 }; + int ret = -1; + prop_changelist_t **cls = NULL; + int cl_idx; + char errbuf[1024]; + libzfs_handle_t *hdl = zhp->zfs_hdl; + nvlist_t *nvl; + int nvl_len; + int added_resv; - if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) - goto error; + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), + zhp->zfs_name); - if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "child dataset with inherited mountpoint is used " - "in a non-global zone")); - ret = zfs_error(hdl, EZFS_ZONED, errbuf); + if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props, + zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) goto error; - } /* - * We don't want to unmount & remount the dataset when changing - * its canmount property to 'on' or 'noauto'. We only use - * the changelist logic to unmount when setting canmount=off. + * We have to check for any extra properties which need to be added + * before computing the length of the nvlist. */ - if (prop == ZFS_PROP_CANMOUNT) { - uint64_t idx; - int err = zprop_string_to_index(prop, propval, &idx, - ZFS_TYPE_DATASET); - if (err == 0 && idx != ZFS_CANMOUNT_OFF) - do_prefix = B_FALSE; + for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); + elem != NULL; + elem = nvlist_next_nvpair(nvl, elem)) { + if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE && + (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) { + goto error; + } } - - if (do_prefix && (ret = changelist_prefix(cl)) != 0) + /* + * Check how many properties we're setting and allocate an array to + * store changelist pointers for postfix(). + */ + nvl_len = 0; + for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); + elem != NULL; + elem = nvlist_next_nvpair(nvl, elem)) + nvl_len++; + if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL) goto error; + cl_idx = 0; + for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); + elem != NULL; + elem = nvlist_next_nvpair(nvl, elem)) { + + zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); + + assert(cl_idx < nvl_len); + /* + * We don't want to unmount & remount the dataset when changing + * its canmount property to 'on' or 'noauto'. We only use + * the changelist logic to unmount when setting canmount=off. + */ + if (!(prop == ZFS_PROP_CANMOUNT && + fnvpair_value_uint64(elem) != ZFS_CANMOUNT_OFF)) { + cls[cl_idx] = changelist_gather(zhp, prop, 0, 0); + if (cls[cl_idx] == NULL) + goto error; + } + + if (prop == ZFS_PROP_MOUNTPOINT && + changelist_haszonedchild(cls[cl_idx])) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "child dataset with inherited mountpoint is used " + "in a non-global zone")); + ret = zfs_error(hdl, EZFS_ZONED, errbuf); + goto error; + } + + /* We don't support those properties on FreeBSD. */ + switch (prop) { + case ZFS_PROP_DEVICES: + case ZFS_PROP_ISCSIOPTIONS: + case ZFS_PROP_XATTR: + case ZFS_PROP_VSCAN: + case ZFS_PROP_NBMAND: + case ZFS_PROP_MLSLABEL: + (void) snprintf(errbuf, sizeof (errbuf), + "property '%s' not supported on FreeBSD", + nvpair_name(elem)); + ret = zfs_error(hdl, EZFS_PERM, errbuf); + goto error; + } + + if (cls[cl_idx] != NULL && + (ret = changelist_prefix(cls[cl_idx])) != 0) + goto error; + + cl_idx++; + } + assert(cl_idx == nvl_len); + /* - * Execute the corresponding ioctl() to set this property. + * Execute the corresponding ioctl() to set this list of properties. */ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) + if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 || + (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0) goto error; ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); if (ret != 0) { - zfs_setprop_error(hdl, prop, errno, errbuf); + /* Get the list of unset properties back and report them. */ + nvlist_t *errorprops = NULL; + if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0) + goto error; + for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); + elem != NULL; + elem = nvlist_next_nvpair(nvl, elem)) { + zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); + zfs_setprop_error(hdl, prop, errno, errbuf); + } + nvlist_free(errorprops); + if (added_resv && errno == ENOSPC) { /* clean up the volsize property we tried to set */ uint64_t old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); nvlist_free(nvl); + nvl = NULL; zcmd_free_nvlists(&zc); + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) goto error; if (nvlist_add_uint64(nvl, @@ -1638,8 +1702,13 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); } } else { - if (do_prefix) - ret = changelist_postfix(cl); + for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { + if (cls[cl_idx] != NULL) { + int clp_err = changelist_postfix(cls[cl_idx]); + if (clp_err != 0) + ret = clp_err; + } + } /* * Refresh the statistics so the new property value @@ -1652,8 +1721,13 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) error: nvlist_free(nvl); zcmd_free_nvlists(&zc); - if (cl) - changelist_free(cl); + if (cls != NULL) { + for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { + if (cls[cl_idx] != NULL) + changelist_free(cls[cl_idx]); + } + free(cls); + } return (ret); } @@ -4203,7 +4277,7 @@ zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, if (cmd == ZFS_SMB_ACL_RENAME) { if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { (void) no_memory(hdl); - return (NULL); + return (0); } } diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c index ab8a9bf..7973888 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c @@ -22,7 +22,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2011, 2014 by Delphix. All rights reserved. */ /* @@ -782,8 +782,9 @@ zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len) if (len == 0) len = 16 * 1024; zc->zc_nvlist_dst_size = len; - if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t) - zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0) + zc->zc_nvlist_dst = + (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size); + if (zc->zc_nvlist_dst == 0) return (-1); return (0); @@ -798,9 +799,9 @@ int zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc) { free((void *)(uintptr_t)zc->zc_nvlist_dst); - if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t) - zfs_alloc(hdl, zc->zc_nvlist_dst_size)) - == 0) + zc->zc_nvlist_dst = + (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size); + if (zc->zc_nvlist_dst == 0) return (-1); return (0); @@ -815,6 +816,9 @@ zcmd_free_nvlists(zfs_cmd_t *zc) free((void *)(uintptr_t)zc->zc_nvlist_conf); free((void *)(uintptr_t)zc->zc_nvlist_src); free((void *)(uintptr_t)zc->zc_nvlist_dst); + zc->zc_nvlist_conf = NULL; + zc->zc_nvlist_src = NULL; + zc->zc_nvlist_dst = NULL; } static int |