summaryrefslogtreecommitdiff
path: root/usr/src
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
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')
-rw-r--r--usr/src/cmd/zfs/zfs_main.c83
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h3
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c157
-rw-r--r--usr/src/lib/libzfs/common/libzfs_sendrecv.c24
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c16
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers3
-rw-r--r--usr/src/lib/libzfs_core/common/libzfs_core.c22
-rw-r--r--usr/src/man/man1m/zfs.1m26
-rw-r--r--usr/src/man/man4/ike.config.44
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_send.c106
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu_send.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_dataset.h3
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c52
-rw-r--r--usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c28
14 files changed, 379 insertions, 152 deletions
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index 80af9e0361..e089d215c0 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -262,7 +262,7 @@ get_usage(zfs_help_t idx)
"\tsend [-Le] [-i snapshot|bookmark] "
"<filesystem|volume|snapshot>\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"));
@@ -477,15 +477,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';
@@ -610,7 +613,7 @@ zfs_do_clone(int argc, char **argv)
keeptrying = B_TRUE;
break;
case 'o':
- if (parseprop(props))
+ if (parseprop(props, optarg) != 0)
return (1);
break;
case 'p':
@@ -762,7 +765,7 @@ zfs_do_create(int argc, char **argv)
nomem();
break;
case 'o':
- if (parseprop(props))
+ if (parseprop(props, optarg))
goto error;
break;
case 's':
@@ -3521,21 +3524,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 "
@@ -3554,7 +3553,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 */
@@ -3566,36 +3566,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);
}
@@ -3655,7 +3670,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':
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 531ee14d61..ddb85646f7 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -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.
@@ -427,6 +427,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/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);
}
}
diff --git a/usr/src/lib/libzfs/common/libzfs_sendrecv.c b/usr/src/lib/libzfs/common/libzfs_sendrecv.c
index c4944438aa..9a34fb32ea 100644
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c
+++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c
@@ -806,7 +806,8 @@ typedef struct send_dump_data {
char prevsnap[ZFS_MAXNAMELEN];
uint64_t prevsnap_obj;
boolean_t seenfrom, seento, replicate, doall, fromorigin;
- boolean_t verbose, dryrun, parsable, progress, embed_data, large_block;
+ boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
+ boolean_t large_block;
int outfd;
boolean_t err;
nvlist_t *fss;
@@ -1034,6 +1035,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
int err;
boolean_t isfromsnap, istosnap, fromorigin;
boolean_t exclude = B_FALSE;
+ FILE *fout = sdd->std_out ? stdout : stderr;
err = 0;
thissnap = strchr(zhp->zfs_name, '@') + 1;
@@ -1108,30 +1110,30 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
if (sdd->parsable) {
if (sdd->prevsnap[0] != '\0') {
- (void) fprintf(stderr, "incremental\t%s\t%s",
+ (void) fprintf(fout, "incremental\t%s\t%s",
sdd->prevsnap, zhp->zfs_name);
} else {
- (void) fprintf(stderr, "full\t%s",
+ (void) fprintf(fout, "full\t%s",
zhp->zfs_name);
}
} else {
- (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
"send from @%s to %s"),
sdd->prevsnap, zhp->zfs_name);
}
if (err == 0) {
if (sdd->parsable) {
- (void) fprintf(stderr, "\t%llu\n",
+ (void) fprintf(fout, "\t%llu\n",
(longlong_t)size);
} else {
char buf[16];
zfs_nicenum(size, buf, sizeof (buf));
- (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
" estimated size is %s\n"), buf);
}
sdd->size += size;
} else {
- (void) fprintf(stderr, "\n");
+ (void) fprintf(fout, "\n");
}
}
@@ -1375,6 +1377,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
int pipefd[2];
dedup_arg_t dda = { 0 };
int featureflags = 0;
+ FILE *fout;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot send '%s'"), zhp->zfs_name);
@@ -1509,6 +1512,9 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sdd.filter_cb_arg = cb_arg;
if (debugnvp)
sdd.debugnv = *debugnvp;
+ if (sdd.verbose && sdd.dryrun)
+ sdd.std_out = B_TRUE;
+ fout = sdd.std_out ? stdout : stderr;
/*
* Some flags require that we place user holds on the datasets that are
@@ -1548,12 +1554,12 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
if (flags->verbose) {
if (flags->parsable) {
- (void) fprintf(stderr, "size\t%llu\n",
+ (void) fprintf(fout, "size\t%llu\n",
(longlong_t)sdd.size);
} else {
char buf[16];
zfs_nicenum(sdd.size, buf, sizeof (buf));
- (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
"total estimated size is %s\n"), buf);
}
}
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index 2dff496454..59b978cf16 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/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) 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
*/
/*
@@ -780,8 +780,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)) == 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);
@@ -796,9 +797,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);
@@ -813,6 +814,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
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index da1d82a67c..9ed5c461c0 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -20,7 +20,7 @@
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2011 Nexenta Systems, Inc. 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.
#
# MAPFILE HEADER START
@@ -125,6 +125,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_prop_is_string;
zfs_prop_readonly;
zfs_prop_set;
+ zfs_prop_set_list;
zfs_prop_string_to_index;
zfs_prop_to_name;
zfs_prop_user;
diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.c b/usr/src/lib/libzfs_core/common/libzfs_core.c
index 06221fab4a..22af0f4a7a 100644
--- a/usr/src/lib/libzfs_core/common/libzfs_core.c
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
*/
@@ -485,18 +485,30 @@ lzc_send(const char *snapname, const char *from, int fd,
}
/*
- * If fromsnap is NULL, a full (non-incremental) stream will be estimated.
+ * "from" can be NULL, a snapshot, or a bookmark.
+ *
+ * If from is NULL, a full (non-incremental) stream will be estimated. This
+ * is calculated very efficiently.
+ *
+ * If from is a snapshot, lzc_send_space uses the deadlists attached to
+ * each snapshot to efficiently estimate the stream size.
+ *
+ * If from is a bookmark, the indirect blocks in the destination snapshot
+ * are traversed, looking for blocks with a birth time since the creation TXG of
+ * the snapshot this bookmark was created from. This will result in
+ * significantly more I/O and be less efficient than a send space estimation on
+ * an equivalent snapshot.
*/
int
-lzc_send_space(const char *snapname, const char *fromsnap, uint64_t *spacep)
+lzc_send_space(const char *snapname, const char *from, uint64_t *spacep)
{
nvlist_t *args;
nvlist_t *result;
int err;
args = fnvlist_alloc();
- if (fromsnap != NULL)
- fnvlist_add_string(args, "fromsnap", fromsnap);
+ if (from != NULL)
+ fnvlist_add_string(args, "from", from);
err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
nvlist_free(args);
if (err == 0)
diff --git a/usr/src/man/man1m/zfs.1m b/usr/src/man/man1m/zfs.1m
index c23885503f..c71dfa5ab2 100644
--- a/usr/src/man/man1m/zfs.1m
+++ b/usr/src/man/man1m/zfs.1m
@@ -22,7 +22,7 @@
.\"
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
-.\" 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
@@ -2407,19 +2407,19 @@ Display numbers in parseable (exact) values.
.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
@@ -3108,7 +3108,9 @@ Include the dataset's properties in the stream. This flag is implicit when
.RS 4n
Do a dry-run ("No-op") send. Do not generate any actual send data. This is
useful in conjunction with the \fB-v\fR or \fB-P\fR flags to determine what
-data will be sent.
+data will be sent. In this case, the verbose output will be written to
+standard output (contrast with a non-dry-run, where the stream is written
+to standard output and the verbose output goes to standard error).
.RE
.sp
diff --git a/usr/src/man/man4/ike.config.4 b/usr/src/man/man4/ike.config.4
index c0c3b27a34..c8ff71888a 100644
--- a/usr/src/man/man4/ike.config.4
+++ b/usr/src/man/man4/ike.config.4
@@ -1195,3 +1195,7 @@ Group. May 2003.
.LP
Lepinksi, M. and Kent, S. \fIRFC 5114, Additional Diffie-Hellman Groups for Use
with IETF Standards\fR. BBN Technologies, January 2008.
+.sp
+.LP
+Fu, D. and Solinas, J. \fIRFC 5903, Elliptic Curve Groups modulo a Prime (ECP
+Groups) for IKE and IKEv2\fR. NSA, June 2010.
diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c
index 59c6385826..084a9f663a 100644
--- a/usr/src/uts/common/fs/zfs/dmu_send.c
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c
@@ -808,6 +808,40 @@ dmu_send(const char *tosnap, const char *fromsnap,
return (err);
}
+static int
+dmu_adjust_send_estimate_for_indirects(dsl_dataset_t *ds, uint64_t size,
+ uint64_t *sizep)
+{
+ int err;
+ /*
+ * Assume that space (both on-disk and in-stream) is dominated by
+ * data. We will adjust for indirect blocks and the copies property,
+ * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
+ */
+
+ /*
+ * Subtract out approximate space used by indirect blocks.
+ * Assume most space is used by data blocks (non-indirect, non-dnode).
+ * Assume all blocks are recordsize. Assume ditto blocks and
+ * internal fragmentation counter out compression.
+ *
+ * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
+ * block, which we observe in practice.
+ */
+ uint64_t recordsize;
+ err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
+ if (err != 0)
+ return (err);
+ size -= size / recordsize * sizeof (blkptr_t);
+
+ /* Add in the space for the record associated with each block. */
+ size += size / recordsize * sizeof (dmu_replay_record_t);
+
+ *sizep = size;
+
+ return (0);
+}
+
int
dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep)
{
@@ -839,33 +873,61 @@ dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep)
return (err);
}
- /*
- * Assume that space (both on-disk and in-stream) is dominated by
- * data. We will adjust for indirect blocks and the copies property,
- * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
- */
+ err = dmu_adjust_send_estimate_for_indirects(ds, size, sizep);
+ return (err);
+}
+
+/*
+ * Simple callback used to traverse the blocks of a snapshot and sum their
+ * uncompressed size
+ */
+/* ARGSUSED */
+static int
+dmu_calculate_send_traversal(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+ const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+ uint64_t *spaceptr = arg;
+ if (bp != NULL && !BP_IS_HOLE(bp)) {
+ *spaceptr += BP_GET_UCSIZE(bp);
+ }
+ return (0);
+}
+
+/*
+ * Given a desination snapshot and a TXG, calculate the approximate size of a
+ * send stream sent from that TXG. from_txg may be zero, indicating that the
+ * whole snapshot will be sent.
+ */
+int
+dmu_send_estimate_from_txg(dsl_dataset_t *ds, uint64_t from_txg,
+ uint64_t *sizep)
+{
+ dsl_pool_t *dp = ds->ds_dir->dd_pool;
+ int err;
+ uint64_t size = 0;
+
+ ASSERT(dsl_pool_config_held(dp));
+
+ /* tosnap must be a snapshot */
+ if (!dsl_dataset_is_snapshot(ds))
+ return (SET_ERROR(EINVAL));
+
+ /* verify that from_txg is before the provided snapshot was taken */
+ if (from_txg >= dsl_dataset_phys(ds)->ds_creation_txg) {
+ return (SET_ERROR(EXDEV));
+ }
/*
- * Subtract out approximate space used by indirect blocks.
- * Assume most space is used by data blocks (non-indirect, non-dnode).
- * Assume all blocks are recordsize. Assume ditto blocks and
- * internal fragmentation counter out compression.
- *
- * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
- * block, which we observe in practice.
+ * traverse the blocks of the snapshot with birth times after
+ * from_txg, summing their uncompressed size
*/
- uint64_t recordsize;
- err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
- if (err != 0)
+ err = traverse_dataset(ds, from_txg, TRAVERSE_POST,
+ dmu_calculate_send_traversal, &size);
+ if (err)
return (err);
- size -= size / recordsize * sizeof (blkptr_t);
-
- /* Add in the space for the record associated with each block. */
- size += size / recordsize * sizeof (dmu_replay_record_t);
-
- *sizep = size;
- return (0);
+ err = dmu_adjust_send_estimate_for_indirects(ds, size, sizep);
+ return (err);
}
typedef struct dmu_recv_begin_arg {
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu_send.h b/usr/src/uts/common/fs/zfs/sys/dmu_send.h
index 3a8dc89abd..2442a1f8aa 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu_send.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_send.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -42,6 +42,8 @@ int dmu_send(const char *tosnap, const char *fromsnap,
int outfd, struct vnode *vp, offset_t *off);
int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds,
uint64_t *sizep);
+int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg,
+ uint64_t *sizep);
int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
boolean_t embedok, boolean_t large_block_ok,
int outfd, struct vnode *vp, offset_t *off);
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
index 5bfc34ea63..7d490ec603 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
@@ -201,6 +201,9 @@ dsl_dataset_phys(dsl_dataset_t *ds)
*/
#define MAX_TAG_PREFIX_LEN 17
+#define dsl_dataset_is_snapshot(ds) \
+ (dsl_dataset_phys(ds)->ds_num_children != 0)
+
#define DS_UNIQUE_IS_ACCURATE(ds) \
((dsl_dataset_phys(ds)->ds_flags & DS_FLAG_UNIQUE_ACCURATE) != 0)
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 43f5c0d824..98c19c591d 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -5339,7 +5339,8 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
* of bytes that will be written to the fd supplied to zfs_ioc_send_new().
*
* innvl: {
- * (optional) "fromsnap" -> full snap name to send an incremental from
+ * (optional) "from" -> full snap or bookmark name to send an incremental
+ * from
* }
*
* outnvl: {
@@ -5350,7 +5351,6 @@ static int
zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
{
dsl_pool_t *dp;
- dsl_dataset_t *fromsnap = NULL;
dsl_dataset_t *tosnap;
int error;
char *fromname;
@@ -5366,27 +5366,55 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
return (error);
}
- error = nvlist_lookup_string(innvl, "fromsnap", &fromname);
+ error = nvlist_lookup_string(innvl, "from", &fromname);
if (error == 0) {
- error = dsl_dataset_hold(dp, fromname, FTAG, &fromsnap);
- if (error != 0) {
- dsl_dataset_rele(tosnap, FTAG);
- dsl_pool_rele(dp, FTAG);
- return (error);
+ if (strchr(fromname, '@') != NULL) {
+ /*
+ * If from is a snapshot, hold it and use the more
+ * efficient dmu_send_estimate to estimate send space
+ * size using deadlists.
+ */
+ dsl_dataset_t *fromsnap;
+ error = dsl_dataset_hold(dp, fromname, FTAG, &fromsnap);
+ if (error != 0)
+ goto out;
+ error = dmu_send_estimate(tosnap, fromsnap, &space);
+ dsl_dataset_rele(fromsnap, FTAG);
+ } else if (strchr(fromname, '#') != NULL) {
+ /*
+ * If from is a bookmark, fetch the creation TXG of the
+ * snapshot it was created from and use that to find
+ * blocks that were born after it.
+ */
+ zfs_bookmark_phys_t frombm;
+
+ error = dsl_bookmark_lookup(dp, fromname, tosnap,
+ &frombm);
+ if (error != 0)
+ goto out;
+ error = dmu_send_estimate_from_txg(tosnap,
+ frombm.zbm_creation_txg, &space);
+ } else {
+ /*
+ * from is not properly formatted as a snapshot or
+ * bookmark
+ */
+ error = SET_ERROR(EINVAL);
+ goto out;
}
+ } else {
+ // If estimating the size of a full send, use dmu_send_estimate
+ error = dmu_send_estimate(tosnap, NULL, &space);
}
- error = dmu_send_estimate(tosnap, fromsnap, &space);
fnvlist_add_uint64(outnvl, "space", space);
- if (fromsnap != NULL)
- dsl_dataset_rele(fromsnap, FTAG);
+out:
dsl_dataset_rele(tosnap, FTAG);
dsl_pool_rele(dp, FTAG);
return (error);
}
-
static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST];
static void
diff --git a/usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c b/usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c
index 2ce6bf0828..feaa907f4c 100644
--- a/usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c
+++ b/usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c
@@ -895,7 +895,8 @@ mrsas_tbolt_ioc_init(struct mrsas_instance *instance, dma_obj_t *mpi2_dma_obj)
Mpi2IOCInitRequest_t *init;
struct mrsas_cmd *cmd = NULL;
struct mrsas_drv_ver drv_ver_info;
- MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ MRSAS_REQUEST_DESCRIPTOR_UNION req_desc;
+ uint32_t timeout;
con_log(CL_ANN, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
@@ -1045,21 +1046,32 @@ mrsas_tbolt_ioc_init(struct mrsas_instance *instance, dma_obj_t *mpi2_dma_obj)
/* disable interrupts before sending INIT2 frame */
instance->func_ptr->disable_intr(instance);
- req_desc = (MRSAS_REQUEST_DESCRIPTOR_UNION *)
- instance->request_message_pool;
- req_desc->Words = cmd->scsi_io_request_phys_addr;
- req_desc->MFAIo.RequestFlags =
+ req_desc.Words = cmd->scsi_io_request_phys_addr;
+ req_desc.MFAIo.RequestFlags =
(MPI2_REQ_DESCRIPT_FLAGS_MFA << MPI2_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- cmd->request_desc = req_desc;
+ cmd->request_desc = &req_desc;
/* issue the init frame */
- instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd);
+
+ mutex_enter(&instance->reg_write_mtx);
+ WR_IB_LOW_QPORT((uint32_t)(req_desc.Words), instance);
+ WR_IB_HIGH_QPORT((uint32_t)(req_desc.Words >> 32), instance);
+ mutex_exit(&instance->reg_write_mtx);
con_log(CL_ANN1, (CE_CONT, "[cmd = %d] ", frame_hdr->cmd));
con_log(CL_ANN1, (CE_CONT, "[cmd Status= %x] ",
frame_hdr->cmd_status));
+ timeout = drv_usectohz(MFI_POLL_TIMEOUT_SECS * MICROSEC);
+ do {
+ if (ddi_get8(cmd->frame_dma_obj.acc_handle,
+ &mfiFrameInit2->cmd_status) != MFI_CMD_STATUS_POLL_MODE)
+ break;
+ delay(1);
+ timeout--;
+ } while (timeout > 0);
+
if (ddi_get8(instance->mpi2_frame_pool_dma_obj.acc_handle,
&mfiFrameInit2->cmd_status) == 0) {
con_log(CL_ANN, (CE_NOTE, "INIT2 Success"));
@@ -2043,6 +2055,8 @@ tbolt_issue_cmd_in_poll_mode(struct mrsas_instance *instance,
drv_usecwait(MILLISEC); /* wait for 1000 usecs */
}
+ DTRACE_PROBE1(tbolt_complete_poll_cmd, uint8_t, i);
+
if (ddi_get8(cmd->frame_dma_obj.acc_handle,
&frame_hdr->cmd_status) == MFI_CMD_STATUS_POLL_MODE) {
con_log(CL_ANN1, (CE_NOTE,