From b9c07ec71b205c034e63f34fa3546437ea766b3b Mon Sep 17 00:00:00 2001 From: Cedric Maunoury <38213715+cedricmaunoury@users.noreply.github.com> Date: Wed, 24 Feb 2021 18:48:58 +0100 Subject: [PATCH] send_iterate_snap : doall send without fromsnap The behavior of a NULL fromsnap was inadvertently changed for a doall send when the send/recv logic in libzfs was updated. Restore the previous behavior by correcting send_iterate_snap() to include all the snapshots in the nvlist for this case. Reviewed-by: Brian Behlendorf Signed-off-by: Cedric Maunoury Closes #11608 --- configure.ac | 1 + lib/libzfs/libzfs_sendrecv.c | 9 ++ tests/runfiles/common.run | 2 +- tests/zfs-tests/cmd/Makefile.am | 1 + tests/zfs-tests/cmd/send_doall/.gitignore | 1 + tests/zfs-tests/cmd/send_doall/Makefile.am | 11 +++ tests/zfs-tests/cmd/send_doall/send_doall.c | 87 +++++++++++++++++++ tests/zfs-tests/include/commands.cfg | 1 + .../tests/functional/rsend/Makefile.am | 4 +- .../tests/functional/rsend/send_doall.ksh | 67 ++++++++++++++ 10 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 tests/zfs-tests/cmd/send_doall/.gitignore create mode 100644 tests/zfs-tests/cmd/send_doall/Makefile.am create mode 100644 tests/zfs-tests/cmd/send_doall/send_doall.c create mode 100755 tests/zfs-tests/tests/functional/rsend/send_doall.ksh diff --git a/configure.ac b/configure.ac index 4520a290a9..b2d88554ed 100644 --- a/configure.ac +++ b/configure.ac @@ -230,6 +230,7 @@ AC_CONFIG_FILES([ tests/zfs-tests/cmd/readmmap/Makefile tests/zfs-tests/cmd/rename_dir/Makefile tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile + tests/zfs-tests/cmd/send_doall/Makefile tests/zfs-tests/cmd/stride_dd/Makefile tests/zfs-tests/cmd/threadsappend/Makefile tests/zfs-tests/cmd/user_ns_exec/Makefile diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 62a9426449..1e3a0bf561 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -321,6 +321,15 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg) } if (!sd->recursive) { + + /* + * To allow a doall stream to work properly + * with a NULL fromsnap + */ + if (sd->doall && sd->fromsnap == NULL && !sd->seenfrom) { + sd->seenfrom = B_TRUE; + } + if (!sd->seenfrom && isfromsnap) { sd->seenfrom = B_TRUE; zfs_close(zhp); diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index e656785d95..2fffd7a452 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -807,7 +807,7 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos', 'send_freeobjects', 'send_realloc_files', 'send_realloc_encrypted_files', 'send_spill_block', 'send_holds', 'send_hole_birth', 'send_mixed_raw', 'send-wR_encrypted_zvol', - 'send_partial_dataset', 'send_invalid'] + 'send_partial_dataset', 'send_invalid', 'send_doall'] tags = ['functional', 'rsend'] [tests/functional/scrub_mirror] diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index 7fe9a2c571..2b965ca700 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -25,6 +25,7 @@ SUBDIRS = \ readmmap \ rename_dir \ rm_lnkcnt_zero_file \ + send_doall \ stride_dd \ threadsappend diff --git a/tests/zfs-tests/cmd/send_doall/.gitignore b/tests/zfs-tests/cmd/send_doall/.gitignore new file mode 100644 index 0000000000..6ba2e603f7 --- /dev/null +++ b/tests/zfs-tests/cmd/send_doall/.gitignore @@ -0,0 +1 @@ +/send_doall diff --git a/tests/zfs-tests/cmd/send_doall/Makefile.am b/tests/zfs-tests/cmd/send_doall/Makefile.am new file mode 100644 index 0000000000..33a6b83122 --- /dev/null +++ b/tests/zfs-tests/cmd/send_doall/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/config/Rules.am + +pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin + +pkgexec_PROGRAMS = send_doall + +send_doall_SOURCES = send_doall.c +send_doall_LDADD = \ + $(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \ + $(abs_top_builddir)/lib/libzfs/libzfs.la \ + $(abs_top_builddir)/lib/libnvpair/libnvpair.la diff --git a/tests/zfs-tests/cmd/send_doall/send_doall.c b/tests/zfs-tests/cmd/send_doall/send_doall.c new file mode 100644 index 0000000000..6f47df0474 --- /dev/null +++ b/tests/zfs-tests/cmd/send_doall/send_doall.c @@ -0,0 +1,87 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Portions Copyright 2020 iXsystems, Inc. + */ + +/* + * Test a corner case : a "doall" send without children datasets. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +static void +usage(const char *name) +{ + fprintf(stderr, "usage: %s snap\n", name); + exit(EX_USAGE); +} + +int +main(int argc, char const * const argv[]) +{ + sendflags_t flags = { 0 }; + libzfs_handle_t *zhdl; + zfs_handle_t *zhp; + const char *tofull, *fsname, *tosnap, *p; + int error; + + if (argc != 2) + usage(argv[0]); + + tofull = argv[1]; + + p = strchr(tofull, '@'); + if (p == NULL) + usage(argv[0]); + tosnap = p + 1; + + fsname = strndup(tofull, p - tofull); + + zhdl = libzfs_init(); + if (zhdl == NULL) + errx(EX_OSERR, "libzfs_init(): %s", libzfs_error_init(errno)); + + zhp = zfs_open(zhdl, fsname, ZFS_TYPE_FILESYSTEM); + if (zhp == NULL) + err(EX_OSERR, "zfs_open(\"%s\")", fsname); + + flags.doall = B_TRUE; + + error = zfs_send(zhp, NULL, tosnap, &flags, + STDOUT_FILENO, NULL, NULL, NULL); + + zfs_close(zhp); + + libzfs_fini(zhdl); + free((void *)fsname); + + return (error); +} diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg index 2996535477..a43ddd016f 100644 --- a/tests/zfs-tests/include/commands.cfg +++ b/tests/zfs-tests/include/commands.cfg @@ -217,6 +217,7 @@ export ZFSTEST_FILES='badsend readmmap rename_dir rm_lnkcnt_zero_file + send_doall threadsappend user_ns_exec xattrtest diff --git a/tests/zfs-tests/tests/functional/rsend/Makefile.am b/tests/zfs-tests/tests/functional/rsend/Makefile.am index 61be2ec188..94bdd26745 100644 --- a/tests/zfs-tests/tests/functional/rsend/Makefile.am +++ b/tests/zfs-tests/tests/functional/rsend/Makefile.am @@ -53,7 +53,8 @@ dist_pkgdata_SCRIPTS = \ send_hole_birth.ksh \ send_invalid.ksh \ send_mixed_raw.ksh \ - send-wR_encrypted_zvol.ksh + send-wR_encrypted_zvol.ksh \ + send_doall.ksh dist_pkgdata_DATA = \ dedup.zsend.bz2 \ @@ -62,3 +63,4 @@ dist_pkgdata_DATA = \ fs.tar.gz \ rsend.cfg \ rsend.kshlib + diff --git a/tests/zfs-tests/tests/functional/rsend/send_doall.ksh b/tests/zfs-tests/tests/functional/rsend/send_doall.ksh new file mode 100755 index 0000000000..e5c3490b32 --- /dev/null +++ b/tests/zfs-tests/tests/functional/rsend/send_doall.ksh @@ -0,0 +1,67 @@ +#!/bin/ksh + +# +# 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. +# + +# +# Copyright (c) 2019 by Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/rsend/rsend.kshlib + +# +# Description: +# Verify send_doall stream is properly received +# +# Strategy: +# 1) Create a set of snapshots. +# 2) Send these snapshots (from origin to the last one) to a file using send_doall. +# 3) Receive the file to newfs to test if the stream is properly handled. +# + +verify_runnable "both" + +log_assert "Verify send_doall stream is correct" + +function cleanup +{ + rm -f $BACKDIR/fs@* + destroy_dataset $POOL/fs "-rR" + destroy_dataset $POOL/newfs "-rR" +} + +log_onexit cleanup + +log_must zfs create $POOL/fs +log_must zfs create $POOL/fs/child + +# Create 3 files and a snapshot between each file creation. +for i in {1..3}; do + file="/$POOL/fs/file$i" + log_must mkfile 16384 $file + + file="/$POOL/fs/child/file$i" + log_must mkfile 16384 $file + + log_must zfs snapshot -r $POOL/fs@snap$i +done + +# Snapshot the pool and send it to the new dataset. +log_must eval "send_doall $POOL/fs@snap3 >$BACKDIR/fs@snap3" +log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs@snap3" + +zfs list $POOL/newfs/child +if [[ $? -eq 0 ]]; then + log_fail "Children dataset should not have been received" +fi + +log_pass "Verify send_doall stream is correct"