mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Illumos 5745 - zfs set allows only one dataset property to be set at a time
5745 zfs set allows only one dataset property to be set at a time Reviewed by: Christopher Siden <christopher.siden@delphix.com> Reviewed by: George Wilson <george@delphix.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Bayard Bell <buffer.g.overflow@gmail.com> Reviewed by: Richard PALO <richard@NetBSD.org> Reviewed by: Steven Hartland <killing@multiplay.co.uk> Approved by: Rich Lowe <richlowe@richlowe.net> References: https://www.illumos.org/issues/5745 https://github.com/illumos/illumos-gate/commit/3092556 Porting notes: - Fix the missing braces around initializer, zfs_cmd_t zc = {"\0"}; - Remove extra format argument in zfs_do_set() - Declare at the top: - zfs_prop_t prop; - nvpair_t *elem; - nvpair_t *next; - int i; - Additionally initialize: - int added_resv = 0; - zfs_prop_t prop = 0; - Assign 0 install of NULL for uint64_t types. - zc->zc_nvlist_conf = '\0'; - zc->zc_nvlist_src = '\0'; - zc->zc_nvlist_dst = '\0'; Ported-by: kernelOfTruth kerneloftruth@gmail.com Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3574
This commit is contained in:
committed by
Brian Behlendorf
parent
f5f087eb88
commit
23de906c72
+124
-48
@@ -1523,15 +1523,10 @@ zfs_is_namespace_prop(zfs_prop_t prop)
|
||||
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 = 0;
|
||||
nvlist_t *nvl = NULL;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
|
||||
@@ -1543,65 +1538,135 @@ 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,
|
||||
ret = zfs_prop_set_list(zhp, nvl);
|
||||
|
||||
error:
|
||||
nvlist_free(nvl);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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 = 0;
|
||||
zfs_prop_t prop = 0;
|
||||
nvpair_t *elem;
|
||||
|
||||
(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;
|
||||
|
||||
nvlist_free(nvl);
|
||||
nvl = realprops;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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 (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 (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 (elem = nvlist_next_nvpair(nvl, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(nvl, elem)) {
|
||||
|
||||
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 (elem = nvlist_next_nvpair(nvl, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(nvl, elem)) {
|
||||
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,
|
||||
@@ -1613,8 +1678,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;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/*
|
||||
@@ -1637,8 +1707,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);
|
||||
}
|
||||
|
||||
@@ -4094,6 +4169,7 @@ void
|
||||
zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
|
||||
{
|
||||
nvpair_t *curr;
|
||||
nvpair_t *next;
|
||||
|
||||
/*
|
||||
* Keep a reference to the props-table against which we prune the
|
||||
@@ -4105,7 +4181,7 @@ zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
|
||||
|
||||
while (curr) {
|
||||
zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
|
||||
nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
|
||||
next = nvlist_next_nvpair(zhp->zfs_props, curr);
|
||||
|
||||
/*
|
||||
* User properties will result in ZPROP_INVAL, and since we
|
||||
@@ -4136,7 +4212,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 (-1);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1069,8 +1069,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);
|
||||
@@ -1085,8 +1086,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);
|
||||
@@ -1101,6 +1103,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 = 0;
|
||||
zc->zc_nvlist_src = 0;
|
||||
zc->zc_nvlist_dst = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
Reference in New Issue
Block a user