summaryrefslogtreecommitdiffstats
path: root/cddl/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib')
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.886
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_main.c216
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_main.c49
-rw-r--r--cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c5
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h15
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c3
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c288
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c10
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c5
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c11
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c133
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c457
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c16
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c69
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h6
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/kernel.c4
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c4
17 files changed, 1005 insertions, 372 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
index e534ae9..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
@@ -189,17 +189,25 @@
.Op Fl i Ar snapshot Ns | Ns bookmark
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Nm
+.Cm send
+.Op Fl Penv
+.Fl t Ar receive_resume_token
+.Nm
.Cm receive Ns | Ns Cm recv
-.Op Fl vnFu
+.Op Fl vnsFu
.Op Fl o Sy origin Ns = Ns Ar snapshot
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Nm
.Cm receive Ns | Ns Cm recv
-.Op Fl vnFu
+.Op Fl vnsFu
.Op Fl d | e
.Op Fl o Sy origin Ns = Ns Ar snapshot
.Ar filesystem
.Nm
+.Cm receive Ns | Ns Cm recv
+.Fl A
+.Ar filesystem Ns | Ns Ar volume
+.Nm
.Cm allow
.Ar filesystem Ns | Ns Ar volume
.Nm
@@ -597,6 +605,13 @@ For cloned file systems or volumes, the snapshot from which the clone was
created. See also the
.Sy clones
property.
+.It Sy receive_resume_token
+For filesystems or volumes which have saved partially-completed state from
+.Sy zfs receive -s ,
+this opaque token can be provided to
+.Sy zfs send -t
+to resume and complete the
+.Sy zfs receive .
.It Sy referenced
The amount of data that is accessible by this dataset, which may or may not be
shared with other datasets in the pool. When a snapshot or clone is created, it
@@ -2106,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
@@ -2630,6 +2645,9 @@ useful in conjunction with the
or
.Fl P
flags to determine what 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).
.It Fl P
Print machine-parsable verbose information about the stream package generated.
.It Fl v
@@ -2711,15 +2729,28 @@ feature.
.El
.It Xo
.Nm
+.Cm send
+.Op Fl Penv
+.Fl t
+.Ar receive_resume_token
+.Xc
+Creates a send stream which resumes an interrupted receive. The
+.Ar receive_resume_token
+is the value of this property on the filesystem
+or volume that was being received into. See the documentation for
+.Sy zfs receive -s
+for more details.
+.It Xo
+.Nm
.Cm receive Ns | Ns Cm recv
-.Op Fl vnFu
+.Op Fl vnsFu
.Op Fl o Sy origin Ns = Ns Ar snapshot
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Xc
.It Xo
.Nm
.Cm receive Ns | Ns Cm recv
-.Op Fl vnFu
+.Op Fl vnsFu
.Op Fl d | e
.Op Fl o Sy origin Ns = Ns Ar snapshot
.Ar filesystem
@@ -2816,9 +2847,42 @@ performing the receive operation. If receiving an incremental replication
stream (for example, one generated by
.Qq Nm Cm send Fl R Bro Fl i | Fl I Brc ) ,
destroy snapshots and file systems that do not exist on the sending side.
+.It Fl s
+If the receive is interrupted, save the partially received state, rather
+than deleting it. Interruption may be due to premature termination of
+the stream
+.Po e.g. due to network failure or failure of the remote system
+if the stream is being read over a network connection
+.Pc ,
+a checksum error in the stream, termination of the
+.Nm zfs Cm receive
+process, or unclean shutdown of the system.
+.Pp
+The receive can be resumed with a stream generated by
+.Nm zfs Cm send Fl t Ar token ,
+where the
+.Ar token
+is the value of the
+.Sy receive_resume_token
+property of the filesystem or volume which is received into.
+.Pp
+To use this flag, the storage pool must have the
+.Sy extensible_dataset
+feature enabled. See
+.Xr zpool-features 5
+for details on ZFS feature flags.
.El
.It Xo
.Nm
+.Cm receive Ns | Ns Cm recv
+.Fl A
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+Abort an interrupted
+.Nm zfs Cm receive Fl s ,
+deleting its saved partially received state.
+.It Xo
+.Nm
.Cm allow
.Ar filesystem Ns | Ns Ar volume
.Xc
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
index e35ce01..e0fb953 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
@@ -263,10 +263,11 @@ get_usage(zfs_help_t idx)
case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n"));
case HELP_RECEIVE:
- return (gettext("\treceive|recv [-vnFu] <filesystem|volume|"
+ return (gettext("\treceive|recv [-vnsFu] <filesystem|volume|"
"snapshot>\n"
- "\treceive|recv [-vnFu] [-o origin=<snapshot>] [-d | -e] "
- "<filesystem>\n"));
+ "\treceive|recv [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
+ "<filesystem>\n"
+ "\treceive|recv -A <filesystem|volume>\n"));
case HELP_RENAME:
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n"
@@ -279,9 +280,10 @@ get_usage(zfs_help_t idx)
return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] "
"<snapshot>\n"
"\tsend [-Le] [-i snapshot|bookmark] "
- "<filesystem|volume|snapshot>\n"));
+ "<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"));
@@ -496,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)
{
@@ -503,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';
@@ -630,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':
@@ -839,10 +845,12 @@ zfs_do_create(int argc, char **argv)
if (type == ZFS_TYPE_VOLUME && !noreserve) {
zpool_handle_t *zpool_handle;
+ nvlist_t *real_props;
uint64_t spa_version;
char *p;
zfs_prop_t resv_prop;
char *strval;
+ char msg[1024];
if (p = strchr(argv[0], '/'))
*p = '\0';
@@ -853,12 +861,22 @@ zfs_do_create(int argc, char **argv)
goto error;
spa_version = zpool_get_prop_int(zpool_handle,
ZPOOL_PROP_VERSION, NULL);
- zpool_close(zpool_handle);
if (spa_version >= SPA_VERSION_REFRESERVATION)
resv_prop = ZFS_PROP_REFRESERVATION;
else
resv_prop = ZFS_PROP_RESERVATION;
- volsize = zvol_volsize_to_reservation(volsize, props);
+
+ (void) snprintf(msg, sizeof (msg),
+ gettext("cannot create '%s'"), argv[0]);
+ if (props && (real_props = zfs_valid_proplist(g_zfs, type,
+ props, 0, NULL, zpool_handle, msg)) == NULL) {
+ zpool_close(zpool_handle);
+ goto error;
+ }
+ zpool_close(zpool_handle);
+
+ volsize = zvol_volsize_to_reservation(volsize, real_props);
+ nvlist_free(real_props);
if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
&strval) != 0) {
@@ -3530,21 +3548,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 "
@@ -3563,8 +3577,9 @@ set_callback(zfs_handle_t *zhp, void *data)
static int
zfs_do_set(int argc, char **argv)
{
- set_cbdata_t cb;
- int ret = 0;
+ nvlist_t *props = NULL;
+ int ds_start = -1; /* argv idx of first dataset arg */
+ int i, ret = 0;
/* check for options */
if (argc > 1 && argv[1][0] == '-') {
@@ -3575,36 +3590,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 (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 (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);
}
@@ -3728,6 +3758,7 @@ zfs_do_send(int argc, char **argv)
{
char *fromname = NULL;
char *toname = NULL;
+ char *resume_token = NULL;
char *cp;
zfs_handle_t *zhp;
sendflags_t flags = { 0 };
@@ -3736,7 +3767,7 @@ zfs_do_send(int argc, char **argv)
boolean_t extraverbose = B_FALSE;
/* check options */
- while ((c = getopt(argc, argv, ":i:I:RDpvnPLe")) != -1) {
+ while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:")) != -1) {
switch (c) {
case 'i':
if (fromname)
@@ -3777,6 +3808,9 @@ zfs_do_send(int argc, char **argv)
case 'e':
flags.embed_data = B_TRUE;
break;
+ case 't':
+ resume_token = optarg;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@@ -3792,14 +3826,28 @@ zfs_do_send(int argc, char **argv)
argc -= optind;
argv += optind;
- /* check number of arguments */
- if (argc < 1) {
- (void) fprintf(stderr, gettext("missing snapshot argument\n"));
- usage(B_FALSE);
- }
- if (argc > 1) {
- (void) fprintf(stderr, gettext("too many arguments\n"));
- usage(B_FALSE);
+ if (resume_token != NULL) {
+ if (fromname != NULL || flags.replicate || flags.props ||
+ flags.dedup) {
+ (void) fprintf(stderr,
+ gettext("invalid flags combined with -t\n"));
+ usage(B_FALSE);
+ }
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("no additional "
+ "arguments are permitted with -t\n"));
+ usage(B_FALSE);
+ }
+ } else {
+ if (argc < 1) {
+ (void) fprintf(stderr,
+ gettext("missing snapshot argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
}
if (!flags.dryrun && isatty(STDOUT_FILENO)) {
@@ -3809,6 +3857,11 @@ zfs_do_send(int argc, char **argv)
return (1);
}
+ if (resume_token != NULL) {
+ return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
+ resume_token));
+ }
+
/*
* Special case sending a filesystem, or from a bookmark.
*/
@@ -3914,8 +3967,6 @@ zfs_do_send(int argc, char **argv)
}
/*
- * zfs receive [-vnFu] [-d | -e] <fs@snap>
- *
* Restore a backup stream from stdin.
*/
static int
@@ -3923,6 +3974,8 @@ zfs_do_receive(int argc, char **argv)
{
int c, err;
recvflags_t flags = { 0 };
+ boolean_t abort_resumable = B_FALSE;
+
nvlist_t *props;
nvpair_t *nvp = NULL;
@@ -3930,7 +3983,7 @@ zfs_do_receive(int argc, char **argv)
nomem();
/* check options */
- while ((c = getopt(argc, argv, ":o:denuvF")) != -1) {
+ while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
switch (c) {
case 'o':
if (parseprop(props, optarg) != 0)
@@ -3952,9 +4005,15 @@ zfs_do_receive(int argc, char **argv)
case 'v':
flags.verbose = B_TRUE;
break;
+ case 's':
+ flags.resumable = B_TRUE;
+ break;
case 'F':
flags.force = B_TRUE;
break;
+ case 'A':
+ abort_resumable = B_TRUE;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@@ -3987,6 +4046,44 @@ zfs_do_receive(int argc, char **argv)
}
}
+ if (abort_resumable) {
+ if (flags.isprefix || flags.istail || flags.dryrun ||
+ flags.resumable || flags.nomount) {
+ (void) fprintf(stderr, gettext("invalid option"));
+ usage(B_FALSE);
+ }
+
+ char namebuf[ZFS_MAXNAMELEN];
+ (void) snprintf(namebuf, sizeof (namebuf),
+ "%s/%%recv", argv[0]);
+
+ if (zfs_dataset_exists(g_zfs, namebuf,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
+ zfs_handle_t *zhp = zfs_open(g_zfs,
+ namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return (1);
+ err = zfs_destroy(zhp, B_FALSE);
+ } else {
+ zfs_handle_t *zhp = zfs_open(g_zfs,
+ argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ usage(B_FALSE);
+ if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
+ zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
+ (void) fprintf(stderr,
+ gettext("'%s' does not have any "
+ "resumable receive state to abort\n"),
+ argv[0]);
+ return (1);
+ }
+ err = zfs_destroy(zhp, B_FALSE);
+ }
+
+ return (err != 0);
+ }
+
if (isatty(STDIN_FILENO)) {
(void) fprintf(stderr,
gettext("Error: Backup stream can not be read "
@@ -3994,7 +4091,6 @@ zfs_do_receive(int argc, char **argv)
"You must redirect standard input.\n"));
return (1);
}
-
err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
return (err != 0);
@@ -5816,6 +5912,24 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
}
/*
+ * If this filesystem is inconsistent and has a receive resume
+ * token, we can not mount it.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+ zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "Contains partially-completed state from "
+ "\"zfs receive -r\", which can be resumed with "
+ "\"zfs send -t\"\n"),
+ cmdname, zfs_get_name(zhp));
+ return (1);
+ }
+
+ /*
* At this point, we have verified that the mountpoint and/or
* shareopts are appropriate for auto management. If the
* filesystem is already mounted or shared, return (failing
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
index a3eabd1..6e1670e 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
@@ -199,7 +199,8 @@ static boolean_t log_history = B_TRUE;
static uint_t timestamp_fmt = NODATE;
static const char *
-get_usage(zpool_help_t idx) {
+get_usage(zpool_help_t idx)
+{
switch (idx) {
case HELP_ADD:
return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
@@ -2940,6 +2941,9 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
uint_t c, children;
char *vname;
boolean_t scripted = cb->cb_scripted;
+ uint64_t islog = B_FALSE;
+ boolean_t haslog = B_FALSE;
+ char *dashes = "%-*s - - - - - -\n";
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
@@ -2990,24 +2994,47 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
continue;
+ if (nvlist_lookup_uint64(child[c],
+ ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
+ haslog = B_TRUE;
+ continue;
+ }
+
vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
print_list_stats(zhp, vname, child[c], cb, depth + 2);
free(vname);
}
- /*
- * Include level 2 ARC devices in iostat output
- */
+ if (haslog == B_TRUE) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "log");
+ for (c = 0; c < children; c++) {
+ if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &islog) != 0 || !islog)
+ continue;
+ vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+ }
+
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
- &child, &children) != 0)
- return;
+ &child, &children) == 0 && children > 0) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "cache");
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+ }
- if (children > 0) {
- (void) printf("%-*s - - - - - "
- "-\n", cb->cb_namewidth, "cache");
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
+ &children) == 0 && children > 0) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "spare");
for (c = 0; c < children; c++) {
- vname = zpool_vdev_name(g_zfs, zhp, child[c],
- B_FALSE);
+ vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
print_list_stats(zhp, vname, child[c], cb, depth + 2);
free(vname);
}
diff --git a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
index f6dedc2..83a5b54 100644
--- a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
+++ b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
@@ -125,7 +125,7 @@ read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
saved_cksum.zc_word[1],
saved_cksum.zc_word[2],
saved_cksum.zc_word[3]);
- exit(1);
+ return (0);
}
return (sizeof (*drr));
}
@@ -346,8 +346,7 @@ main(int argc, char *argv[])
if (verbose)
(void) printf("\n");
- if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
- DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
+ if (drr->drr_payloadlen != 0) {
nvlist_t *nv;
int sz = drr->drr_payloadlen;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
index 44bd58b..246449c 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, 2015 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.
@@ -426,10 +426,11 @@ extern const char *zfs_prop_column_name(zfs_prop_t);
extern boolean_t zfs_prop_align_right(zfs_prop_t);
extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
- nvlist_t *, uint64_t, zfs_handle_t *, const char *);
+ nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
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,
@@ -621,6 +622,10 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
extern int zfs_send(zfs_handle_t *, const char *, const char *,
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags);
+extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
+ const char *);
+extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
+ const char *token);
extern int zfs_promote(zfs_handle_t *);
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
@@ -661,6 +666,12 @@ typedef struct recvflags {
/* set "canmount=off" on all modified filesystems */
boolean_t canmountoff;
+ /*
+ * Mark the file systems as "resumable" and do not destroy them if the
+ * receive is interrupted
+ */
+ boolean_t resumable;
+
/* byteswap flag is used internally; callers need not specify */
boolean_t byteswap;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
index a3f6129..833e1b6 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
@@ -74,6 +74,9 @@ zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) {
switch (zfs_ioctl_version) {
+ case ZFS_IOCVER_EDBP:
+ cflag = ZFS_CMD_COMPAT_EDBP;
+ break;
case ZFS_IOCVER_ZCMD:
cflag = ZFS_CMD_COMPAT_ZCMD;
break;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
index 343f258..44a9f00 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.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) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
@@ -890,7 +890,8 @@ zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
*/
nvlist_t *
zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
- uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
+ uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
+ const char *errbuf)
{
nvpair_t *elem;
uint64_t intval;
@@ -1084,8 +1085,8 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
case ZFS_PROP_RECORDSIZE:
{
int maxbs = SPA_MAXBLOCKSIZE;
- if (zhp != NULL) {
- maxbs = zpool_get_prop_int(zhp->zpool_hdl,
+ if (zpool_hdl != NULL) {
+ maxbs = zpool_get_prop_int(zpool_hdl,
ZPOOL_PROP_MAXBLOCKSIZE, NULL);
}
/*
@@ -1403,6 +1404,7 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
uint64_t old_reservation;
uint64_t new_reservation;
zfs_prop_t resv_prop;
+ nvlist_t *props;
/*
* If this is an existing volume, and someone is setting the volsize,
@@ -1412,16 +1414,25 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
return (-1);
old_reservation = zfs_prop_get_int(zhp, resv_prop);
- if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) !=
- old_reservation) || nvlist_lookup_uint64(nvl,
- zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) {
+
+ props = fnvlist_alloc();
+ fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
+
+ if ((zvol_volsize_to_reservation(old_volsize, props) !=
+ old_reservation) || nvlist_exists(nvl,
+ zfs_prop_to_name(resv_prop))) {
+ fnvlist_free(props);
return (0);
}
if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
- &new_volsize) != 0)
+ &new_volsize) != 0) {
+ fnvlist_free(props);
return (-1);
- new_reservation = zvol_volsize_to_reservation(new_volsize,
- zhp->zfs_props);
+ }
+ new_reservation = zvol_volsize_to_reservation(new_volsize, props);
+ fnvlist_free(props);
+
if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
new_reservation) != 0) {
(void) no_memory(zhp->zfs_hdl);
@@ -1487,6 +1498,12 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
"property setting is not allowed on "
"bootable datasets"));
(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
+ } else if (prop == ZFS_PROP_CHECKSUM ||
+ prop == ZFS_PROP_DEDUP) {
+ (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property setting is not allowed on "
+ "root pools"));
+ (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
} else {
(void) zfs_standard_error(hdl, err, errbuf);
}
@@ -1522,15 +1539,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'"),
@@ -1542,79 +1554,149 @@ 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, zhp->zpool_hdl,
+ 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,
@@ -1626,8 +1708,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
@@ -1640,8 +1727,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);
}
@@ -1772,22 +1864,21 @@ getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
return (value);
}
-static char *
+static const char *
getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
{
nvlist_t *nv;
- char *value;
+ const char *value;
*source = NULL;
if (nvlist_lookup_nvlist(zhp->zfs_props,
zfs_prop_to_name(prop), &nv) == 0) {
- verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
+ value = fnvlist_lookup_string(nv, ZPROP_VALUE);
(void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
} else {
verify(!zhp->zfs_props_table ||
zhp->zfs_props_table[prop] == B_TRUE);
- if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
- value = "";
+ value = zfs_prop_default_string(prop);
*source = "";
}
@@ -2189,7 +2280,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
{
char *source = NULL;
uint64_t val;
- char *str;
+ const char *str;
const char *strval;
boolean_t received = zfs_is_recvd_props_mode(zhp);
@@ -2294,14 +2385,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
case ZFS_PROP_ORIGIN:
- (void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
- proplen);
- /*
- * If there is no parent at all, return failure to indicate that
- * it doesn't apply to this dataset.
- */
- if (propbuf[0] == '\0')
+ str = getprop_string(zhp, prop, &source);
+ if (str == NULL)
return (-1);
+ (void) strlcpy(propbuf, str, proplen);
break;
case ZFS_PROP_CLONES:
@@ -2482,8 +2569,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
case PROP_TYPE_STRING:
- (void) strlcpy(propbuf,
- getprop_string(zhp, prop, &source), proplen);
+ str = getprop_string(zhp, prop, &source);
+ if (str == NULL)
+ return (-1);
+ (void) strlcpy(propbuf, str, proplen);
break;
case PROP_TYPE_INDEX:
@@ -3161,9 +3250,23 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
else
ost = DMU_OST_ZFS;
+ /* open zpool handle for prop validation */
+ char pool_path[MAXNAMELEN];
+ (void) strlcpy(pool_path, path, sizeof (pool_path));
+
+ /* truncate pool_path at first slash */
+ char *p = strchr(pool_path, '/');
+ if (p != NULL)
+ *p = '\0';
+
+ zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path);
+
if (props && (props = zfs_valid_proplist(hdl, type, props,
- zoned, NULL, errbuf)) == 0)
+ zoned, NULL, zpool_handle, errbuf)) == 0) {
+ zpool_close(zpool_handle);
return (-1);
+ }
+ zpool_close(zpool_handle);
if (type == ZFS_TYPE_VOLUME) {
/*
@@ -3231,13 +3334,6 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
"parent '%s' is not a filesystem"), parent);
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
- case EDOM:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "volume block size must be power of 2 from "
- "512B to 128KB"));
-
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
-
case ENOTSUP:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pool must be upgraded to set this "
@@ -3432,7 +3528,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
type = ZFS_TYPE_FILESYSTEM;
}
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
- zhp, errbuf)) == NULL)
+ zhp, zhp->zpool_hdl, errbuf)) == NULL)
return (-1);
}
@@ -3576,11 +3672,23 @@ zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
}
}
+ /*
+ * get pool handle for prop validation. assumes all snaps are in the
+ * same pool, as does lzc_snapshot (below).
+ */
+ char pool[MAXNAMELEN];
+ elem = nvlist_next_nvpair(snaps, NULL);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/@")] = '\0';
+ zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
+
if (props != NULL &&
(props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
- props, B_FALSE, NULL, errbuf)) == NULL) {
+ props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
+ zpool_close(zpool_hdl);
return (-1);
}
+ zpool_close(zpool_hdl);
ret = lzc_snapshot(snaps, props, &errors);
@@ -4194,7 +4302,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_diff.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
index ab2007d..3b17579 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -624,9 +625,12 @@ get_snapshot_names(differ_info_t *di, const char *fromsnap,
zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
while (zhp != NULL) {
- (void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
- origin, sizeof (origin), &src, NULL, 0, B_FALSE);
-
+ if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
+ sizeof (origin), &src, NULL, 0, B_FALSE) != 0) {
+ (void) zfs_close(zhp);
+ zhp = NULL;
+ break;
+ }
if (strncmp(origin, fromsnap, fsnlen) == 0)
break;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
index aadc1f9..b6f6e73 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
@@ -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) 2013, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
@@ -315,7 +315,8 @@ typedef struct {
} snapspec_arg_t;
static int
-snapspec_cb(zfs_handle_t *zhp, void *arg) {
+snapspec_cb(zfs_handle_t *zhp, void *arg)
+{
snapspec_arg_t *ssa = arg;
char *shortsnapname;
int err = 0;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
index f8596ed..b94af5b 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
@@ -1072,6 +1072,17 @@ mount_cb(zfs_handle_t *zhp, void *data)
return (0);
}
+ /*
+ * If this filesystem is inconsistent and has a receive resume
+ * token, we can not mount it.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+ zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
libzfs_add_handle(cbp, zhp);
if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
zfs_close(zhp);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
index c677822..5fd9612 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
@@ -22,7 +22,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -402,29 +402,6 @@ bootfs_name_valid(const char *pool, char *bootfs)
return (B_FALSE);
}
-/*
- * Inspect the configuration to determine if any of the devices contain
- * an EFI label.
- */
-static boolean_t
-pool_uses_efi(nvlist_t *config)
-{
-#ifdef sun
- nvlist_t **child;
- uint_t c, children;
-
- if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
- &child, &children) != 0)
- return (read_efi_label(config, NULL) >= 0);
-
- for (c = 0; c < children; c++) {
- if (pool_uses_efi(child[c]))
- return (B_TRUE);
- }
-#endif /* sun */
- return (B_FALSE);
-}
-
boolean_t
zpool_is_bootable(zpool_handle_t *zhp)
{
@@ -453,7 +430,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
char *slash, *check;
struct stat64 statbuf;
zpool_handle_t *zhp;
- nvlist_t *nvroot;
if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
(void) no_memory(hdl);
@@ -572,23 +548,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
goto error;
}
- verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
- ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
-
-#ifdef sun
- /*
- * bootfs property cannot be set on a disk which has
- * been EFI labeled.
- */
- if (pool_uses_efi(nvroot)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' not supported on "
- "EFI labeled devices"), propname);
- (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
- zpool_close(zhp);
- goto error;
- }
-#endif /* sun */
zpool_close(zhp);
break;
@@ -1164,8 +1123,8 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
strcmp(zonestr, "on") == 0);
- if ((zc_fsprops = zfs_valid_proplist(hdl,
- ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
+ if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
+ fsprops, zoned, NULL, NULL, msg)) == NULL) {
goto create_failed;
}
if (!zc_props &&
@@ -1201,6 +1160,21 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
"one or more vdevs refer to the same device"));
return (zfs_error(hdl, EZFS_BADDEV, msg));
+ case ERANGE:
+ /*
+ * This happens if the record size is smaller or larger
+ * than the allowed size range, or not a power of 2.
+ *
+ * NOTE: although zfs_valid_proplist is called earlier,
+ * this case may have slipped through since the
+ * pool does not exist yet and it is therefore
+ * impossible to read properties e.g. max blocksize
+ * from the pool.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "record size invalid"));
+ return (zfs_error(hdl, EZFS_BADPROP, msg));
+
case EOVERFLOW:
/*
* This occurs when one of the devices is below
@@ -1311,25 +1285,6 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
return (zfs_error(hdl, EZFS_BADVERSION, msg));
}
- if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
- ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
- uint64_t s;
-
- for (s = 0; s < nspares; s++) {
- char *path;
-
- if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
- &path) == 0 && pool_uses_efi(spares[s])) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "device '%s' contains an EFI label and "
- "cannot be used on root pools."),
- zpool_vdev_name(hdl, NULL, spares[s],
- B_FALSE));
- return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
- }
- }
- }
-
if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
SPA_VERSION_L2CACHE &&
nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
@@ -1930,7 +1885,8 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func)
* and the like.
*/
static int
-ctd_check_path(char *str) {
+ctd_check_path(char *str)
+{
/*
* If it starts with a slash, check the last component.
*/
@@ -2350,11 +2306,9 @@ zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
return (EZFS_INVALCONFIG);
/*
- * root pool can not have EFI labeled disks and can only have
- * a single top-level vdev.
+ * root pool can only have a single top-level vdev.
*/
- if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
- pool_uses_efi(vdev_root))
+ if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1)
return (EZFS_POOL_INVALARG);
(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
@@ -2658,16 +2612,6 @@ zpool_vdev_attach(zpool_handle_t *zhp,
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
"cannot attach %s to %s"), new_disk, old_disk);
- /*
- * If this is a root pool, make sure that we're not attaching an
- * EFI labeled device.
- */
- if (rootpool && pool_uses_efi(nvroot)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "EFI labeled devices are not supported on root pools."));
- return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
- }
-
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
&islog)) == 0)
@@ -3786,17 +3730,18 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
int
zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
{
- char *buf = NULL;
- uint64_t bufsize = HIS_BUF_LEN_DEF;
+ char *buf;
+ uint64_t buflen = HIS_BUF_LEN_DEF;
uint64_t off = 0;
nvlist_t **records = NULL;
uint_t numrecords = 0;
int err, i;
- if ((buf = malloc(bufsize)) == NULL)
+ buf = malloc(buflen);
+ if (buf == NULL)
return (ENOMEM);
do {
- uint64_t bytes_read = bufsize;
+ uint64_t bytes_read = buflen;
uint64_t leftover;
if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
@@ -3810,18 +3755,16 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
&leftover, &records, &numrecords)) != 0)
break;
off -= leftover;
-
- /*
- * If the history block is too big, double the buffer
- * size and try again.
- */
if (leftover == bytes_read) {
+ /*
+ * no progress made, because buffer is not big enough
+ * to hold this record; resize and retry.
+ */
+ buflen *= 2;
free(buf);
buf = NULL;
-
- bufsize <<= 1;
- if ((bufsize >= HIS_BUF_LEN_MAX) ||
- ((buf = malloc(bufsize)) == NULL)) {
+ if ((buflen >= HIS_BUF_LEN_MAX) ||
+ ((buf = malloc(buflen)) == NULL)) {
err = ENOMEM;
break;
}
@@ -3829,6 +3772,7 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
/* CONSTCOND */
} while (1);
+
free(buf);
if (!err) {
@@ -3981,13 +3925,6 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
if (zhp) {
nvlist_t *nvroot;
- if (zpool_is_bootable(zhp)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "EFI labeled devices are not supported on root "
- "pools."));
- return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
- }
-
verify(nvlist_lookup_nvlist(zhp->zpool_config,
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
index e44ccfd..e99231d 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
@@ -51,6 +51,7 @@
#include "zfs_prop.h"
#include "zfs_fletcher.h"
#include "libzfs_impl.h"
+#include <zlib.h>
#include <sha2.h>
#include <sys/zio_checksum.h>
#include <sys/ddt.h>
@@ -67,6 +68,8 @@ extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
uint64_t *);
+static int guid_to_name(libzfs_handle_t *, const char *,
+ uint64_t, boolean_t, char *);
static const zio_cksum_t zero_cksum = { 0 };
@@ -284,8 +287,7 @@ cksummer(void *arg)
DMU_BACKUP_FEATURE_DEDUPPROPS);
DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
- if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
- DMU_COMPOUNDSTREAM && drr->drr_payloadlen != 0) {
+ if (drr->drr_payloadlen != 0) {
sz = drr->drr_payloadlen;
if (sz > SPA_MAXBLOCKSIZE) {
@@ -818,7 +820,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;
@@ -994,17 +997,14 @@ static void *
send_progress_thread(void *arg)
{
progress_arg_t *pa = arg;
-
zfs_cmd_t zc = { 0 };
zfs_handle_t *zhp = pa->pa_zhp;
libzfs_handle_t *hdl = zhp->zfs_hdl;
unsigned long long bytes;
char buf[16];
-
time_t t;
struct tm *tm;
- assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (!pa->pa_parsable)
@@ -1037,6 +1037,51 @@ send_progress_thread(void *arg)
}
}
+static void
+send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,
+ uint64_t size, boolean_t parsable)
+{
+ if (parsable) {
+ if (fromsnap != NULL) {
+ (void) fprintf(fout, "incremental\t%s\t%s",
+ fromsnap, tosnap);
+ } else {
+ (void) fprintf(fout, "full\t%s",
+ tosnap);
+ }
+ } else {
+ if (fromsnap != NULL) {
+ if (strchr(fromsnap, '@') == NULL &&
+ strchr(fromsnap, '#') == NULL) {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "send from @%s to %s"),
+ fromsnap, tosnap);
+ } else {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "send from %s to %s"),
+ fromsnap, tosnap);
+ }
+ } else {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "full send of %s"),
+ tosnap);
+ }
+ }
+
+ if (size != 0) {
+ if (parsable) {
+ (void) fprintf(fout, "\t%llu",
+ (longlong_t)size);
+ } else {
+ char buf[16];
+ zfs_nicenum(size, buf, sizeof (buf));
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ " estimated size is %s"), buf);
+ }
+ }
+ (void) fprintf(fout, "\n");
+}
+
static int
dump_snapshot(zfs_handle_t *zhp, void *arg)
{
@@ -1047,6 +1092,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;
@@ -1115,37 +1161,14 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
(sdd->fromorigin || sdd->replicate);
if (sdd->verbose) {
- uint64_t size;
- err = estimate_ioctl(zhp, sdd->prevsnap_obj,
+ uint64_t size = 0;
+ (void) estimate_ioctl(zhp, sdd->prevsnap_obj,
fromorigin, &size);
- if (sdd->parsable) {
- if (sdd->prevsnap[0] != '\0') {
- (void) fprintf(stderr, "incremental\t%s\t%s",
- sdd->prevsnap, zhp->zfs_name);
- } else {
- (void) fprintf(stderr, "full\t%s",
- zhp->zfs_name);
- }
- } else {
- (void) fprintf(stderr, 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",
- (longlong_t)size);
- } else {
- char buf[16];
- zfs_nicenum(size, buf, sizeof (buf));
- (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
- " estimated size is %s\n"), buf);
- }
- sdd->size += size;
- } else {
- (void) fprintf(stderr, "\n");
- }
+ send_print_verbose(fout, zhp->zfs_name,
+ sdd->prevsnap[0] ? sdd->prevsnap : NULL,
+ size, sdd->parsable);
+ sdd->size += size;
}
if (!sdd->dryrun) {
@@ -1356,6 +1379,233 @@ again:
return (0);
}
+nvlist_t *
+zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
+{
+ unsigned int version;
+ int nread;
+ unsigned long long checksum, packed_len;
+
+ /*
+ * Decode token header, which is:
+ * <token version>-<checksum of payload>-<uncompressed payload length>
+ * Note that the only supported token version is 1.
+ */
+ nread = sscanf(token, "%u-%llx-%llx-",
+ &version, &checksum, &packed_len);
+ if (nread != 3) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (invalid format)"));
+ return (NULL);
+ }
+
+ if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (invalid version %u)"),
+ version);
+ return (NULL);
+ }
+
+ /* convert hexadecimal representation to binary */
+ token = strrchr(token, '-') + 1;
+ int len = strlen(token) / 2;
+ unsigned char *compressed = zfs_alloc(hdl, len);
+ for (int i = 0; i < len; i++) {
+ nread = sscanf(token + i * 2, "%2hhx", compressed + i);
+ if (nread != 1) {
+ free(compressed);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt "
+ "(payload is not hex-encoded)"));
+ return (NULL);
+ }
+ }
+
+ /* verify checksum */
+ zio_cksum_t cksum;
+ fletcher_4_native(compressed, len, NULL, &cksum);
+ if (cksum.zc_word[0] != checksum) {
+ free(compressed);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (incorrect checksum)"));
+ return (NULL);
+ }
+
+ /* uncompress */
+ void *packed = zfs_alloc(hdl, packed_len);
+ uLongf packed_len_long = packed_len;
+ if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||
+ packed_len_long != packed_len) {
+ free(packed);
+ free(compressed);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (decompression failed)"));
+ return (NULL);
+ }
+
+ /* unpack nvlist */
+ nvlist_t *nv;
+ int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);
+ free(packed);
+ free(compressed);
+ if (error != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (nvlist_unpack failed)"));
+ return (NULL);
+ }
+ return (nv);
+}
+
+int
+zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
+ const char *resume_token)
+{
+ char errbuf[1024];
+ char *toname;
+ char *fromname = NULL;
+ uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;
+ zfs_handle_t *zhp;
+ int error = 0;
+ char name[ZFS_MAXNAMELEN];
+ enum lzc_send_flags lzc_flags = 0;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot resume send"));
+
+ nvlist_t *resume_nvl =
+ zfs_send_resume_token_to_nvlist(hdl, resume_token);
+ if (resume_nvl == NULL) {
+ /*
+ * zfs_error_aux has already been set by
+ * zfs_send_resume_token_to_nvlist
+ */
+ return (zfs_error(hdl, EZFS_FAULT, errbuf));
+ }
+ if (flags->verbose) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "resume token contents:\n"));
+ nvlist_print(stderr, resume_nvl);
+ }
+
+ if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt"));
+ return (zfs_error(hdl, EZFS_FAULT, errbuf));
+ }
+ fromguid = 0;
+ (void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);
+
+ if (flags->embed_data || nvlist_exists(resume_nvl, "embedok"))
+ lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+
+ if (guid_to_name(hdl, toname, toguid, B_FALSE, name) != 0) {
+ if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is no longer the same snapshot used in "
+ "the initial send"), toname);
+ } else {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' used in the initial send no longer exists"),
+ toname);
+ }
+ return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+ }
+ zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+ if (zhp == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "unable to access '%s'"), name);
+ return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+ }
+
+ if (fromguid != 0) {
+ if (guid_to_name(hdl, toname, fromguid, B_TRUE, name) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source %#llx no longer exists"),
+ (longlong_t)fromguid);
+ return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+ }
+ fromname = name;
+ }
+
+ if (flags->verbose) {
+ uint64_t size = 0;
+ error = lzc_send_space(zhp->zfs_name, fromname, &size);
+ if (error == 0)
+ size = MAX(0, (int64_t)(size - bytes));
+ send_print_verbose(stderr, zhp->zfs_name, fromname,
+ size, flags->parsable);
+ }
+
+ if (!flags->dryrun) {
+ progress_arg_t pa = { 0 };
+ pthread_t tid;
+ /*
+ * If progress reporting is requested, spawn a new thread to
+ * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
+ */
+ if (flags->progress) {
+ pa.pa_zhp = zhp;
+ pa.pa_fd = outfd;
+ pa.pa_parsable = flags->parsable;
+
+ error = pthread_create(&tid, NULL,
+ send_progress_thread, &pa);
+ if (error != 0) {
+ zfs_close(zhp);
+ return (error);
+ }
+ }
+
+ error = lzc_send_resume(zhp->zfs_name, fromname, outfd,
+ lzc_flags, resumeobj, resumeoff);
+
+ if (flags->progress) {
+ (void) pthread_cancel(tid);
+ (void) pthread_join(tid, NULL);
+ }
+
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot send '%s'"), zhp->zfs_name);
+
+ zfs_close(zhp);
+
+ switch (error) {
+ case 0:
+ return (0);
+ case EXDEV:
+ case ENOENT:
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+#ifdef illumos
+ case ENOSTR:
+#endif
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+
+
+ zfs_close(zhp);
+
+ return (error);
+}
+
/*
* Generate a send stream for the dataset identified by the argument zhp.
*
@@ -1388,6 +1638,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);
@@ -1515,6 +1766,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
@@ -1554,12 +1808,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);
}
}
@@ -1891,6 +2145,7 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
typedef struct guid_to_name_data {
uint64_t guid;
+ boolean_t bookmark_ok;
char *name;
char *skip;
} guid_to_name_data_t;
@@ -1899,20 +2154,25 @@ static int
guid_to_name_cb(zfs_handle_t *zhp, void *arg)
{
guid_to_name_data_t *gtnd = arg;
+ const char *slash;
int err;
if (gtnd->skip != NULL &&
- strcmp(zhp->zfs_name, gtnd->skip) == 0) {
+ (slash = strrchr(zhp->zfs_name, '/')) != NULL &&
+ strcmp(slash + 1, gtnd->skip) == 0) {
+ zfs_close(zhp);
return (0);
}
- if (zhp->zfs_dmustats.dds_guid == gtnd->guid) {
+ if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid) {
(void) strcpy(gtnd->name, zhp->zfs_name);
zfs_close(zhp);
return (EEXIST);
}
err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
+ if (err != EEXIST && gtnd->bookmark_ok)
+ err = zfs_iter_bookmarks(zhp, guid_to_name_cb, gtnd);
zfs_close(zhp);
return (err);
}
@@ -1926,45 +2186,48 @@ guid_to_name_cb(zfs_handle_t *zhp, void *arg)
*/
static int
guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
- char *name)
+ boolean_t bookmark_ok, char *name)
{
- /* exhaustive search all local snapshots */
char pname[ZFS_MAXNAMELEN];
guid_to_name_data_t gtnd;
- int err = 0;
- zfs_handle_t *zhp;
- char *cp;
gtnd.guid = guid;
+ gtnd.bookmark_ok = bookmark_ok;
gtnd.name = name;
gtnd.skip = NULL;
- (void) strlcpy(pname, parent, sizeof (pname));
-
/*
- * Search progressively larger portions of the hierarchy. This will
+ * Search progressively larger portions of the hierarchy, starting
+ * with the filesystem specified by 'parent'. This will
* select the "most local" version of the origin snapshot in the case
* that there are multiple matching snapshots in the system.
*/
- while ((cp = strrchr(pname, '/')) != NULL) {
-
+ (void) strlcpy(pname, parent, sizeof (pname));
+ char *cp = strrchr(pname, '@');
+ if (cp == NULL)
+ cp = strchr(pname, '\0');
+ for (; cp != NULL; cp = strrchr(pname, '/')) {
/* Chop off the last component and open the parent */
*cp = '\0';
- zhp = make_dataset_handle(hdl, pname);
+ zfs_handle_t *zhp = make_dataset_handle(hdl, pname);
if (zhp == NULL)
continue;
-
- err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
+ int err = guid_to_name_cb(zfs_handle_dup(zhp), &gtnd);
+ if (err != EEXIST)
+ err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
+ if (err != EEXIST && bookmark_ok)
+ err = zfs_iter_bookmarks(zhp, guid_to_name_cb, &gtnd);
zfs_close(zhp);
if (err == EEXIST)
return (0);
/*
- * Remember the dataset that we already searched, so we
- * skip it next time through.
+ * Remember the last portion of the dataset so we skip it next
+ * time through (as we've already searched that portion of the
+ * hierarchy).
*/
- gtnd.skip = pname;
+ gtnd.skip = strrchr(pname, '/') + 1;
}
return (ENOENT);
@@ -2562,11 +2825,9 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
switch (drr->drr_type) {
case DRR_BEGIN:
- /* NB: not to be used on v2 stream packages */
if (drr->drr_payloadlen != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid substream header"));
- return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+ (void) recv_read(hdl, fd, buf,
+ drr->drr_payloadlen, B_FALSE, NULL);
}
break;
@@ -2627,6 +2888,40 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
return (-1);
}
+static void
+recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
+ boolean_t resumable)
+{
+ char target_fs[ZFS_MAXNAMELEN];
+
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "checksum mismatch or incomplete stream"));
+
+ if (!resumable)
+ return;
+ (void) strlcpy(target_fs, target_snap, sizeof (target_fs));
+ *strchr(target_fs, '@') = '\0';
+ zfs_handle_t *zhp = zfs_open(hdl, target_fs,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return;
+
+ char token_buf[ZFS_MAXPROPLEN];
+ int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ token_buf, sizeof (token_buf),
+ NULL, NULL, 0, B_TRUE);
+ if (error == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "checksum mismatch or incomplete stream.\n"
+ "Partially received snapshot is saved.\n"
+ "A resuming stream can be generated on the sending "
+ "system by running:\n"
+ " zfs send -t %s"),
+ token_buf);
+ }
+ zfs_close(zhp);
+}
+
/*
* Restores a backup of tosnap from the file descriptor specified by infd.
*/
@@ -2790,7 +3085,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*/
if (drrb->drr_flags & DRR_FLAG_CLONE) {
if (guid_to_name(hdl, zc.zc_value,
- drrb->drr_fromguid, zc.zc_string) != 0) {
+ drrb->drr_fromguid, B_FALSE, zc.zc_string) != 0) {
zcmd_free_nvlists(&zc);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"local origin for clone %s does not exist"),
@@ -2806,8 +3101,10 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
zc.zc_string);
}
+ boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+ DMU_BACKUP_FEATURE_RESUMING;
stream_wantsnewfs = (drrb->drr_fromguid == 0 ||
- (drrb->drr_flags & DRR_FLAG_CLONE) || originsnap);
+ (drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;
if (stream_wantsnewfs) {
/*
@@ -2826,7 +3123,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
char suffix[ZFS_MAXNAMELEN];
(void) strcpy(suffix, strrchr(zc.zc_value, '/'));
if (guid_to_name(hdl, zc.zc_name, parent_snapguid,
- zc.zc_value) == 0) {
+ B_FALSE, zc.zc_value) == 0) {
*strchr(zc.zc_value, '@') = '\0';
(void) strcat(zc.zc_value, suffix);
}
@@ -2853,7 +3150,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
char snap[ZFS_MAXNAMELEN];
(void) strcpy(snap, strchr(zc.zc_value, '@'));
if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid,
- zc.zc_value) == 0) {
+ B_FALSE, zc.zc_value) == 0) {
*strchr(zc.zc_value, '@') = '\0';
(void) strcat(zc.zc_value, snap);
}
@@ -2867,11 +3164,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
zfs_handle_t *zhp;
/*
- * Destination fs exists. Therefore this should either
- * be an incremental, or the stream specifies a new fs
- * (full stream or clone) and they want us to blow it
- * away (and have therefore specified -F and removed any
- * snapshots).
+ * Destination fs exists. It must be one of these cases:
+ * - an incremental send stream
+ * - the stream specifies a new fs (full stream or clone)
+ * and they want us to blow away the existing fs (and
+ * have therefore specified -F and removed any snapshots)
+ * - we are resuming a failed receive.
*/
if (stream_wantsnewfs) {
if (!flags->force) {
@@ -2926,6 +3224,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
return (-1);
}
}
+
+ /*
+ * If we are resuming a newfs, set newfs here so that we will
+ * mount it if the recv succeeds this time. We can tell
+ * that it was a newfs on the first recv because the fs
+ * itself will be inconsistent (if the fs existed when we
+ * did the first recv, we would have received it into
+ * .../%recv).
+ */
+ if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))
+ newfs = B_TRUE;
+
zfs_close(zhp);
} else {
/*
@@ -2958,9 +3268,10 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
newfs = B_TRUE;
}
- zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
+ zc.zc_begin_record = *drr_noswap;
zc.zc_cookie = infd;
zc.zc_guid = flags->force;
+ zc.zc_resumable = flags->resumable;
if (flags->verbose) {
(void) printf("%s %s stream of %s into %s\n",
flags->dryrun ? "would receive" : "receiving",
@@ -3097,8 +3408,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
case ECKSUM:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid stream (checksum mismatch)"));
+ recv_ecksum_set_aux(hdl, zc.zc_value, flags->resumable);
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
case ENOTSUP:
@@ -3300,7 +3610,8 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
* Restores a backup of tosnap from the file descriptor specified by infd.
* Return 0 on total success, -2 if some things couldn't be
* destroyed/renamed/promoted, -1 if some things couldn't be received.
- * (-1 will override -2).
+ * (-1 will override -2, if -1 and the resumable flag was specified the
+ * transfer can be resumed if the sending side supports it).
*/
int
zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
index 8ca4738..6f70604 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, 2015 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
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
index 5ba660d..69d332a 100644
--- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
@@ -515,6 +515,13 @@ int
lzc_send(const char *snapname, const char *from, int fd,
enum lzc_send_flags flags)
{
+ return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
+}
+
+int
+lzc_send_resume(const char *snapname, const char *from, int fd,
+ enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
+{
nvlist_t *args;
int err;
@@ -526,6 +533,10 @@ lzc_send(const char *snapname, const char *from, int fd,
fnvlist_add_boolean(args, "largeblockok");
if (flags & LZC_SEND_FLAG_EMBED_DATA)
fnvlist_add_boolean(args, "embedok");
+ if (resumeobj != 0 || resumeoff != 0) {
+ fnvlist_add_uint64(args, "resume_object", resumeobj);
+ fnvlist_add_uint64(args, "resume_offset", resumeoff);
+ }
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
nvlist_free(args);
return (err);
@@ -583,22 +594,9 @@ recv_read(int fd, void *buf, int ilen)
return (0);
}
-/*
- * The simplest receive case: receive from the specified fd, creating the
- * specified snapshot. Apply the specified properties a "received" properties
- * (which can be overridden by locally-set properties). If the stream is a
- * clone, its origin snapshot must be specified by 'origin'. The 'force'
- * flag will cause the target filesystem to be rolled back or destroyed if
- * necessary to receive.
- *
- * Return 0 on success or an errno on failure.
- *
- * Note: this interface does not work on dedup'd streams
- * (those with DMU_BACKUP_FEATURE_DEDUP).
- */
-int
-lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
- boolean_t force, int fd)
+static int
+lzc_receive_impl(const char *snapname, nvlist_t *props, const char *origin,
+ boolean_t force, boolean_t resumable, int fd)
{
/*
* The receive ioctl is still legacy, so we need to construct our own
@@ -608,7 +606,6 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
char *atp;
char *packed = NULL;
size_t size;
- dmu_replay_record_t drr;
int error;
ASSERT3S(g_refcount, >, 0);
@@ -644,10 +641,9 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
/* zc_begin_record is non-byteswapped BEGIN record */
- error = recv_read(fd, &drr, sizeof (drr));
+ error = recv_read(fd, &zc.zc_begin_record, sizeof (zc.zc_begin_record));
if (error != 0)
goto out;
- zc.zc_begin_record = drr.drr_u.drr_begin;
/* zc_cookie is fd to read from */
zc.zc_cookie = fd;
@@ -655,6 +651,8 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
/* zc guid is force flag */
zc.zc_guid = force;
+ zc.zc_resumable = resumable;
+
/* zc_cleanup_fd is unused */
zc.zc_cleanup_fd = -1;
@@ -670,6 +668,39 @@ out:
}
/*
+ * The simplest receive case: receive from the specified fd, creating the
+ * specified snapshot. Apply the specified properties as "received" properties
+ * (which can be overridden by locally-set properties). If the stream is a
+ * clone, its origin snapshot must be specified by 'origin'. The 'force'
+ * flag will cause the target filesystem to be rolled back or destroyed if
+ * necessary to receive.
+ *
+ * Return 0 on success or an errno on failure.
+ *
+ * Note: this interface does not work on dedup'd streams
+ * (those with DMU_BACKUP_FEATURE_DEDUP).
+ */
+int
+lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
+ boolean_t force, int fd)
+{
+ return (lzc_receive_impl(snapname, props, origin, force, B_FALSE, fd));
+}
+
+/*
+ * Like lzc_receive, but if the receive fails due to premature stream
+ * termination, the intermediate state will be preserved on disk. In this
+ * case, ECKSUM will be returned. The receive may subsequently be resumed
+ * with a resuming send stream generated by lzc_send_resume().
+ */
+int
+lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
+ boolean_t force, int fd)
+{
+ return (lzc_receive_impl(snapname, props, origin, force, B_TRUE, fd));
+}
+
+/*
* Roll back this filesystem or volume to its most recent snapshot.
* If snapnamebuf is not NULL, it will be filled in with the name
* of the most recent snapshot.
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
index b6a4c12..b9235d1 100644
--- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
@@ -59,7 +59,11 @@ enum lzc_send_flags {
};
int lzc_send(const char *, const char *, int, enum lzc_send_flags);
+int lzc_send_resume(const char *, const char *, int,
+ enum lzc_send_flags, uint64_t, uint64_t);
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
+int lzc_receive_resumable(const char *, nvlist_t *, const char *,
+ boolean_t, int);
int lzc_send_space(const char *, const char *, uint64_t *);
boolean_t lzc_exists(const char *);
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
index 5556e6d..986b0c1 100644
--- a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -523,7 +523,7 @@ vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
/*ARGSUSED*/
int
vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
- int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
+ int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
{
ssize_t iolen, split;
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
index 1c5f644..63d4d1e 100644
--- a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
@@ -675,6 +675,10 @@ tdesc_array_create(dwarf_t *dw, Dwarf_Die dim, tdesc_t *arrtdp,
ar->ad_nelems = uval + 1;
else if (die_signed(dw, dim, DW_AT_upper_bound, &sval, 0))
ar->ad_nelems = sval + 1;
+ else if (die_unsigned(dw, dim, DW_AT_count, &uval, 0))
+ ar->ad_nelems = uval;
+ else if (die_signed(dw, dim, DW_AT_count, &sval, 0))
+ ar->ad_nelems = sval;
else
ar->ad_nelems = 0;
OpenPOWER on IntegriCloud