summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common/libzfs_dataset.c
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2015-04-09 11:45:19 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2015-04-09 11:45:19 +0000
commit2b223b8361851779edb84f2c1e0b6eb6be89cebe (patch)
tree5aa00d1bdfee7bd8c537449a78f1ab93044f3a12 /usr/src/lib/libzfs/common/libzfs_dataset.c
parent52d1e941a3244efb8ae46e42c7d2d6ec9ec3f188 (diff)
parent30925561c223021e91d15899cbe75f80e54d8889 (diff)
downloadillumos-joyent-2b223b8361851779edb84f2c1e0b6eb6be89cebe.tar.gz
[illumos-gate merge]
commit 30925561c223021e91d15899cbe75f80e54d8889 5745 zfs set allows only one dataset property to be set at a time commit 643da460c8ca583e39ce053081754e24087f84c8 5765 add support for estimating send stream size with lzc_send_space when source is a bookmark commit dc5f28a3c341db7c241bba77ddc109c141072f27 5764 "zfs send -nv" directs output to stderr commit 1c445679611e2f17e31e163f4eeb49f65c99d191 5794 Add reference to RFC 5903 to ike.config(4) commit 4bc492d2bb45bc1a51b553ae441cfee4289cb3ee 5775 mr_sas initialisation pauses unecessarily for 60 seconds.
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_dataset.c')
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c157
1 files changed, 115 insertions, 42 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index f2dd13f1af..c69fad8174 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -1497,15 +1497,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'"),
@@ -1517,65 +1512,133 @@ 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);
- 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.
+ * 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;
+ }
+
+ 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,
@@ -1587,8 +1650,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
@@ -1601,8 +1669,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);
}
@@ -4127,7 +4200,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);
}
}