From owner-svn-src-vendor@freebsd.org Sun Oct 18 08:12:07 2015 Return-Path: Delivered-To: svn-src-vendor@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 850CCA18D13; Sun, 18 Oct 2015 08:12:07 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4774C1B9; Sun, 18 Oct 2015 08:12:07 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t9I8C6aP080394; Sun, 18 Oct 2015 08:12:06 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t9I8C535080389; Sun, 18 Oct 2015 08:12:05 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201510180812.t9I8C535080389@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Sun, 18 Oct 2015 08:12:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r289493 - in vendor/illumos/dist: cmd/zfs lib/libzfs/common man/man1m X-SVN-Group: vendor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-vendor@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the vendor work area tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 18 Oct 2015 08:12:07 -0000 Author: mav Date: Sun Oct 18 08:12:05 2015 New Revision: 289493 URL: https://svnweb.freebsd.org/changeset/base/289493 Log: 5745 zfs set allows only one dataset property to be set at a time Reviewed by: Christopher Siden Reviewed by: George Wilson Reviewed by: Matthew Ahrens Reviewed by: Bayard Bell Reviewed by: Richard PALO Reviewed by: Steven Hartland Approved by: Rich Lowe Author: Chris Williamson illumos/illumos-gate@30925561c223021e91d15899cbe75f80e54d8889 Modified: vendor/illumos/dist/cmd/zfs/zfs_main.c vendor/illumos/dist/lib/libzfs/common/libzfs.h vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c vendor/illumos/dist/lib/libzfs/common/libzfs_util.c vendor/illumos/dist/man/man1m/zfs.1m Modified: vendor/illumos/dist/cmd/zfs/zfs_main.c ============================================================================== --- vendor/illumos/dist/cmd/zfs/zfs_main.c Sun Oct 18 08:08:37 2015 (r289492) +++ vendor/illumos/dist/cmd/zfs/zfs_main.c Sun Oct 18 08:12:05 2015 (r289493) @@ -265,7 +265,7 @@ get_usage(zfs_help_t idx) "\n" "\tsend [-nvPe] -t \n")); case HELP_SET: - return (gettext("\tset " + return (gettext("\tset ... " " ...\n")); case HELP_SHARE: return (gettext("\tshare <-a | filesystem>\n")); @@ -480,15 +480,18 @@ 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) +parseprop(nvlist_t *props, char *propname) { - char *propname = optarg; char *propval, *strval; if ((propval = strchr(propname, '=')) == NULL) { (void) fprintf(stderr, gettext("missing " - "'=' for -o option\n")); + "'=' for property=value argument\n")); return (-1); } *propval = '\0'; @@ -604,7 +607,7 @@ zfs_do_clone(int argc, char **argv) while ((c = getopt(argc, argv, "o:p")) != -1) { switch (c) { case 'o': - if (parseprop(props)) + if (parseprop(props, optarg) != 0) return (1); break; case 'p': @@ -751,7 +754,7 @@ zfs_do_create(int argc, char **argv) nomem(); break; case 'o': - if (parseprop(props)) + if (parseprop(props, optarg)) goto error; break; case 's': @@ -3444,21 +3447,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 " @@ -3477,7 +3476,8 @@ set_callback(zfs_handle_t *zhp, void *da 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 */ @@ -3489,36 +3489,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, NULL, - 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); } @@ -3578,7 +3593,7 @@ zfs_do_snapshot(int argc, char **argv) while ((c = getopt(argc, argv, "ro:")) != -1) { switch (c) { case 'o': - if (parseprop(props)) + if (parseprop(props, optarg)) return (1); break; case 'r': Modified: vendor/illumos/dist/lib/libzfs/common/libzfs.h ============================================================================== --- vendor/illumos/dist/lib/libzfs/common/libzfs.h Sun Oct 18 08:08:37 2015 (r289492) +++ vendor/illumos/dist/lib/libzfs/common/libzfs.h Sun Oct 18 08:12:05 2015 (r289493) @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014 by Delphix. All rights reserved. + * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. @@ -425,6 +425,7 @@ extern nvlist_t *zfs_valid_proplist(libz 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, Modified: vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c ============================================================================== --- vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c Sun Oct 18 08:08:37 2015 (r289492) +++ vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c Sun Oct 18 08:12:05 2015 (r289493) @@ -1499,15 +1499,10 @@ zfs_setprop_error(libzfs_handle_t *hdl, 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'"), @@ -1519,65 +1514,133 @@ zfs_prop_set(zfs_handle_t *zhp, const ch 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); - if (prop == ZFS_PROP_VOLSIZE) { - if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) - goto error; - } - if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) - 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 (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); + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), + zhp->zfs_name); + + 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. - */ - 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; + * We have to check for any extra properties which need to be added + * before computing the length of the nvlist. + */ + 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; + } + + 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, @@ -1589,8 +1652,13 @@ zfs_prop_set(zfs_handle_t *zhp, const ch (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 @@ -1603,8 +1671,13 @@ zfs_prop_set(zfs_handle_t *zhp, const ch 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); } @@ -4110,7 +4183,7 @@ zfs_smb_acl_mgmt(libzfs_handle_t *hdl, c if (cmd == ZFS_SMB_ACL_RENAME) { if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { (void) no_memory(hdl); - return (NULL); + return (0); } } Modified: vendor/illumos/dist/lib/libzfs/common/libzfs_util.c ============================================================================== --- vendor/illumos/dist/lib/libzfs/common/libzfs_util.c Sun Oct 18 08:08:37 2015 (r289492) +++ vendor/illumos/dist/lib/libzfs/common/libzfs_util.c Sun Oct 18 08:12:05 2015 (r289493) @@ -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) 2014 by Delphix. All rights reserved. + * Copyright (c) 2011, 2014 by Delphix. All rights reserved. */ /* @@ -739,8 +739,9 @@ zcmd_alloc_dst_nvlist(libzfs_handle_t *h 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)) == NULL) + 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); @@ -755,9 +756,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)) - == NULL) + 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); @@ -772,6 +773,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 Modified: vendor/illumos/dist/man/man1m/zfs.1m ============================================================================== --- vendor/illumos/dist/man/man1m/zfs.1m Sun Oct 18 08:08:37 2015 (r289492) +++ vendor/illumos/dist/man/man1m/zfs.1m Sun Oct 18 08:12:05 2015 (r289493) @@ -22,7 +22,7 @@ .\" .\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. .\" Copyright 2011 Joshua M. Clulow -.\" Copyright (c) 2014 by Delphix. All rights reserved. +.\" Copyright (c) 2011, 2014 by Delphix. All rights reserved. .\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved. .\" Copyright (c) 2014, Joyent, Inc. All rights reserved. .\" Copyright (c) 2014 by Adam Stevko. All rights reserved. @@ -107,7 +107,7 @@ zfs \- configures ZFS file systems .LP .nf -\fBzfs\fR \fBset\fR \fIproperty\fR=\fIvalue\fR \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR... +\fBzfs\fR \fBset\fR \fIproperty\fR=\fIvalue\fR... \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR... .fi .LP @@ -2385,19 +2385,19 @@ For example, specifying \fB-t snapshot\f .sp .ne 2 .na -\fB\fBzfs set\fR \fIproperty\fR=\fIvalue\fR +\fB\fBzfs set\fR \fIproperty\fR=\fIvalue\fR[ \fIproperty\fR=\fIvalue\fR]... \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR...\fR .ad .sp .6 .RS 4n -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 \fBB\fR, \fBK\fR, \fBM\fR, -\fBG\fR, \fBT\fR, \fBP\fR, \fBE\fR, \fBZ\fR (for bytes, kilobytes, megabytes, -gigabytes, terabytes, petabytes, exabytes, or zettabytes, respectively). User -properties can be set on snapshots. For more information, see the "User -Properties" section. +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 +\fBB\fR, \fBK\fR, \fBM\fR, \fBG\fR, \fBT\fR, \fBP\fR, \fBE\fR, \fBZ\fR (for +bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes, exabytes, or +zettabytes, respectively). User properties can be set on snapshots. For more +information, see the "User Properties" section. .RE .sp