aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libzfs.h3
-rw-r--r--lib/libzfs/libzfs_sendrecv.c84
-rw-r--r--tests/runfiles/linux.run2
-rw-r--r--tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am1
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_-d.ksh62
5 files changed, 107 insertions, 45 deletions
diff --git a/include/libzfs.h b/include/libzfs.h
index bb0178eea..7828a2759 100644
--- a/include/libzfs.h
+++ b/include/libzfs.h
@@ -747,6 +747,9 @@ typedef struct recvflags {
/* skip receive of snapshot holds */
boolean_t skipholds;
+
+ /* mount the filesystem unless nomount is specified */
+ boolean_t domount;
} recvflags_t;
extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index 33d3eb6a5..702643882 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -3369,19 +3369,12 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
* sent datasets to their final locations in the dataset hierarchy.
*/
static int
-recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *destname,
+recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
nvlist_t *stream_nv, avl_tree_t *stream_avl)
{
int err;
nvpair_t *fselem = NULL;
nvlist_t *stream_fss;
- char *cp;
- char top_zfs[ZFS_MAX_DATASET_NAME_LEN];
-
- (void) strcpy(top_zfs, destname);
- cp = strrchr(top_zfs, '@');
- if (cp != NULL)
- *cp = '\0';
VERIFY(0 == nvlist_lookup_nvlist(stream_nv, "fss", &stream_fss));
@@ -3408,7 +3401,7 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *destname,
uint64_t guid;
VERIFY(0 == nvpair_value_uint64(snapel, &guid));
- err = guid_to_name(hdl, destname, guid, B_FALSE,
+ err = guid_to_name(hdl, top_zfs, guid, B_FALSE,
fsname);
if (err == 0)
break;
@@ -4009,8 +4002,8 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
stream_nv, stream_avl, NULL);
}
- if (raw && softerr == 0) {
- softerr = recv_fix_encryption_hierarchy(hdl, destname,
+ if (raw && softerr == 0 && *top_zfs != NULL) {
+ softerr = recv_fix_encryption_hierarchy(hdl, *top_zfs,
stream_nv, stream_avl);
}
@@ -4872,8 +4865,17 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
goto out;
}
- if (top_zfs && (*top_zfs == NULL || strcmp(*top_zfs, name) == 0))
+ /*
+ * If this is the top-level dataset, record it so we can use it
+ * for recursive operations later.
+ */
+ if (top_zfs != NULL &&
+ (*top_zfs == NULL || strcmp(*top_zfs, name) == 0)) {
toplevel = B_TRUE;
+ if (*top_zfs == NULL)
+ *top_zfs = zfs_strdup(hdl, name);
+ }
+
if (drrb->drr_type == DMU_OST_ZVOL) {
type = ZFS_TYPE_VOLUME;
} else if (drrb->drr_type == DMU_OST_ZFS) {
@@ -5127,35 +5129,15 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
* children of the target filesystem if we did a replication
* receive (indicated by stream_avl being non-NULL).
*/
- cp = strchr(destsnap, '@');
- if (cp && (ioctl_err == 0 || !newfs) && !redacted) {
- zfs_handle_t *h;
-
- *cp = '\0';
- h = zfs_open(hdl, destsnap,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
- if (h != NULL) {
- if (h->zfs_type == ZFS_TYPE_VOLUME) {
- *cp = '@';
- } else if (newfs || stream_avl) {
- /*
- * Track the first/top of hierarchy fs,
- * for mounting and sharing later.
- */
- if (top_zfs && *top_zfs == NULL)
- *top_zfs = zfs_strdup(hdl, destsnap);
- }
- zfs_close(h);
- }
- *cp = '@';
- }
-
if (clp) {
if (!flags->nomount)
err |= changelist_postfix(clp);
changelist_free(clp);
}
+ if ((newfs || stream_avl) && type == ZFS_TYPE_FILESYSTEM && !redacted)
+ flags->domount = B_TRUE;
+
if (prop_errflags & ZPROP_ERR_NOCLEAR) {
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
"failed to clear unreceived properties on %s"), name);
@@ -5454,24 +5436,38 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
VERIFY(0 == close(cleanup_fd));
- if (err == 0 && !flags->nomount && top_zfs) {
+ if (err == 0 && !flags->nomount && flags->domount && top_zfs) {
zfs_handle_t *zhp = NULL;
prop_changelist_t *clp = NULL;
- zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
- if (zhp != NULL) {
+ zhp = zfs_open(hdl, top_zfs,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL) {
+ err = -1;
+ goto out;
+ } else {
+ if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
+ zfs_close(zhp);
+ goto out;
+ }
+
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
CL_GATHER_MOUNT_ALWAYS, 0);
zfs_close(zhp);
- if (clp != NULL) {
- /* mount and share received datasets */
- err = changelist_postfix(clp);
- changelist_free(clp);
+ if (clp == NULL) {
+ err = -1;
+ goto out;
}
+
+ /* mount and share received datasets */
+ err = changelist_postfix(clp);
+ changelist_free(clp);
+ if (err != 0)
+ err = -1;
}
- if (zhp == NULL || clp == NULL || err)
- err = -1;
}
+
+out:
if (top_zfs)
free(top_zfs);
diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run
index 3e39c165e..5bc810803 100644
--- a/tests/runfiles/linux.run
+++ b/tests/runfiles/linux.run
@@ -212,7 +212,7 @@ tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
'zfs_receive_013_pos', 'zfs_receive_014_pos', 'zfs_receive_015_pos',
'receive-o-x_props_override', 'zfs_receive_from_encrypted',
'zfs_receive_to_encrypted', 'zfs_receive_raw',
- 'zfs_receive_raw_incremental', 'zfs_receive_-e']
+ 'zfs_receive_raw_incremental', 'zfs_receive_-e', 'zfs_receive_raw_-d']
tags = ['functional', 'cli_root', 'zfs_receive']
[tests/functional/cli_root/zfs_rename]
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
index bf112a77e..7b2037b9f 100644
--- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
@@ -22,4 +22,5 @@ dist_pkgdata_SCRIPTS = \
zfs_receive_to_encrypted.ksh \
zfs_receive_raw.ksh \
zfs_receive_raw_incremental.ksh \
+ zfs_receive_raw_-d.ksh \
zfs_receive_-e.ksh
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_-d.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_-d.ksh
new file mode 100755
index 000000000..a909f2788
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_-d.ksh
@@ -0,0 +1,62 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2019 Datto, Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# zfs receive -d should create the expected encryption hierarchy.
+#
+# STRATEGY:
+# 1. Create an encrypted dataset and a inheriting child
+# 2. Snapshot the child dataset
+# 2. Create a recursive raw send file from the snapshot
+# 3. Destroy the original child filesystem
+# 4. Receive the snapshot as a child of the second dataset with '-d'
+# 5. Verify the new child can be mounted
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+ datasetexists $TESTPOOL/$TESTFS1 && \
+ log_must zfs destroy -r $TESTPOOL/$TESTFS1
+ rm -f $sendfile
+}
+
+log_onexit cleanup
+
+log_assert "zfs receive -d should create the expected encryption hierarchy"
+
+typeset passphrase="password1"
+
+sendfile=$TEST_BASE_DIR/sendfile.$$
+
+log_must eval "echo $passphrase | zfs create -o encryption=on" \
+ "-o keyformat=passphrase $TESTPOOL/$TESTFS1"
+log_must zfs create $TESTPOOL/$TESTFS1/child
+log_must zfs snapshot $TESTPOOL/$TESTFS1/child@snap
+log_must eval "zfs send -Rw $TESTPOOL/$TESTFS1/child@snap > $sendfile"
+log_must zfs destroy -r $TESTPOOL/$TESTFS1/child
+log_must zfs receive -Fd $TESTPOOL < $sendfile
+log_must eval "echo $passphrase | zfs mount -l $TESTPOOL/$TESTFS1/child"
+
+log_pass "zfs receive -d creates the expected encryption hierarchy"