mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-04-13 07:01:46 +03:00
Fix the send --exclude option to work with encryption
When using --exclude, filtering needs to take place in two places: in zfs_main.c via the callback previously added to support the options, and in libzfs_sendrecv.c because it generates the nvlist during a first pass, and that results in it complaining if the excluded dataset is not available for sending. (eg, excluding an encrypted dataset so you don't have to use --raw wouldn't work, because the first pass would look at the dataset and decide you couldn't use it.) Add send --exclude tests, including one that tests excluding an encrypted hierarchy. Reviewed-by: Allan Jude <allan@klarasystems.com> Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Sean Eric Fagan <sef@kithrup.ie> Closes #18278
This commit is contained in:
parent
753f1e1e21
commit
06b0abfe62
@ -260,6 +260,8 @@ typedef struct send_data {
|
||||
boolean_t props;
|
||||
boolean_t no_preserve_encryption;
|
||||
|
||||
snapfilter_cb_t *filter_cb;
|
||||
void *filter_cb_arg;
|
||||
/*
|
||||
* The header nvlist is of the following format:
|
||||
* {
|
||||
@ -512,6 +514,10 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
|
||||
uint64_t fromsnap_txg_save = sd->fromsnap_txg;
|
||||
uint64_t tosnap_txg_save = sd->tosnap_txg;
|
||||
|
||||
if (sd->filter_cb &&
|
||||
(sd->filter_cb(zhp, sd->filter_cb_arg) == 0))
|
||||
return (0);
|
||||
|
||||
fromsnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->fromsnap);
|
||||
if (fromsnap_txg != 0)
|
||||
sd->fromsnap_txg = fromsnap_txg;
|
||||
@ -697,7 +703,8 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
|
||||
const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t doall,
|
||||
boolean_t replicate, boolean_t skipmissing, boolean_t verbose,
|
||||
boolean_t backup, boolean_t holds, boolean_t props,
|
||||
boolean_t no_preserve_encryption, nvlist_t **nvlp, avl_tree_t **avlp)
|
||||
boolean_t no_preserve_encryption, nvlist_t **nvlp, avl_tree_t **avlp,
|
||||
snapfilter_cb_t *filter_cb, void *filter_cb_arg)
|
||||
{
|
||||
zfs_handle_t *zhp;
|
||||
send_data_t sd = { 0 };
|
||||
@ -721,6 +728,8 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
|
||||
sd.holds = holds;
|
||||
sd.props = props;
|
||||
sd.no_preserve_encryption = no_preserve_encryption;
|
||||
sd.filter_cb = filter_cb;
|
||||
sd.filter_cb_arg = filter_cb_arg;
|
||||
|
||||
if ((error = send_iterate_fs(zhp, &sd)) != 0) {
|
||||
fnvlist_free(sd.fss);
|
||||
@ -2200,7 +2209,8 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
|
||||
boolean_t gather_props, boolean_t recursive, boolean_t verbose,
|
||||
boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t skipmissing,
|
||||
boolean_t backup, boolean_t holds, boolean_t props, boolean_t doall,
|
||||
boolean_t no_preserve_encryption, nvlist_t **fssp, avl_tree_t **fsavlp)
|
||||
boolean_t no_preserve_encryption, nvlist_t **fssp, avl_tree_t **fsavlp,
|
||||
snapfilter_cb_t filter_func, void *cb_arg)
|
||||
{
|
||||
int err = 0;
|
||||
char *packbuf = NULL;
|
||||
@ -2247,7 +2257,7 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
|
||||
if (gather_nvlist(zhp->zfs_hdl, tofs,
|
||||
from, tosnap, recursive, raw, doall, replicate, skipmissing,
|
||||
verbose, backup, holds, props, no_preserve_encryption,
|
||||
&fss, fsavlp) != 0) {
|
||||
&fss, fsavlp, filter_func, cb_arg) != 0) {
|
||||
return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,
|
||||
errbuf));
|
||||
}
|
||||
@ -2394,7 +2404,8 @@ zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||
flags->replicate, flags->verbosity > 0, flags->dryrun,
|
||||
flags->raw, flags->replicate, flags->skipmissing,
|
||||
flags->backup, flags->holds, flags->props, flags->doall,
|
||||
flags->no_preserve_encryption, &fss, &fsavl);
|
||||
flags->no_preserve_encryption, &fss, &fsavl,
|
||||
filter_func, cb_arg);
|
||||
zfs_close(tosnap);
|
||||
if (err != 0)
|
||||
goto err_out;
|
||||
@ -2738,7 +2749,7 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
|
||||
flags->verbosity > 0, flags->dryrun, flags->raw,
|
||||
flags->replicate, B_FALSE, flags->backup, flags->holds,
|
||||
flags->props, flags->doall, flags->no_preserve_encryption,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
}
|
||||
@ -3395,7 +3406,8 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
|
||||
/* Using top_zfs, gather the nvlists for all local filesystems. */
|
||||
if ((err = gather_nvlist(hdl, top_zfs, NULL, NULL,
|
||||
recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,
|
||||
B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl)) != 0)
|
||||
B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl,
|
||||
NULL, NULL)) != 0)
|
||||
return (err);
|
||||
|
||||
/*
|
||||
@ -3550,7 +3562,8 @@ again:
|
||||
|
||||
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
|
||||
recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,
|
||||
B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl)) != 0)
|
||||
B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl,
|
||||
NULL, NULL)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
@ -5141,7 +5154,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
*cp = '\0';
|
||||
if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,
|
||||
B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE,
|
||||
B_TRUE, B_FALSE, &local_nv, &local_avl) == 0) {
|
||||
B_TRUE, B_FALSE, &local_nv, &local_avl,
|
||||
NULL, NULL) == 0) {
|
||||
*cp = '@';
|
||||
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
|
||||
fsavl_destroy(local_avl);
|
||||
|
||||
@ -987,7 +987,8 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos',
|
||||
'rsend_014_pos', 'rsend_016_neg', 'rsend_019_pos', 'rsend_020_pos',
|
||||
'rsend_021_pos', 'rsend_022_pos', 'rsend_024_pos', 'rsend_025_pos',
|
||||
'rsend_026_neg', 'rsend_027_pos', 'rsend_028_neg', 'rsend_029_neg',
|
||||
'rsend_030_pos', 'rsend_031_pos', 'send-c_verify_ratio',
|
||||
'rsend_030_pos', 'rsend_031_pos', 'rsend-exclude_001_pos',
|
||||
'rsend-exclude_002_pos', 'send-c_verify_ratio',
|
||||
'send-c_verify_contents', 'send-c_props', 'send-c_incremental',
|
||||
'send-c_volume', 'send-c_zstream_recompress', 'send-c_zstreamdump',
|
||||
'send-c_lz4_disabled', 'send-c_recv_lz4_disabled',
|
||||
|
||||
@ -557,7 +557,8 @@ tags = ['functional', 'reservation']
|
||||
tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos',
|
||||
'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos', 'rsend_005_pos',
|
||||
'rsend_006_pos', 'rsend_009_pos', 'rsend_010_pos', 'rsend_011_pos',
|
||||
'rsend_014_pos', 'rsend_016_neg', 'send-c_verify_contents',
|
||||
'rsend_014_pos', 'rsend_016_neg', 'rsend-exclude_001_pos',
|
||||
'rsend-exclude_002_pos', 'send-c_verify_contents',
|
||||
'send-c_volume', 'send-c_zstreamdump', 'send-c_recv_dedup',
|
||||
'send-L_toggle', 'send_encrypted_hierarchy', 'send_encrypted_props',
|
||||
'send_encrypted_freeobjects',
|
||||
|
||||
@ -2051,6 +2051,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/rsend/rsend_029_neg.ksh \
|
||||
functional/rsend/rsend_030_pos.ksh \
|
||||
functional/rsend/rsend_031_pos.ksh \
|
||||
functional/rsend/rsend-exclude_001_pos.ksh \
|
||||
functional/rsend/rsend-exclude_002_pos.ksh \
|
||||
functional/rsend/send-c_embedded_blocks.ksh \
|
||||
functional/rsend/send-c_incremental.ksh \
|
||||
functional/rsend/send-c_longname.ksh \
|
||||
|
||||
68
tests/zfs-tests/tests/functional/rsend/rsend-exclude_001_pos.ksh
Executable file
68
tests/zfs-tests/tests/functional/rsend/rsend-exclude_001_pos.ksh
Executable file
@ -0,0 +1,68 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
|
||||
#
|
||||
# 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) 2023 by Delphix. All rights reserved.
|
||||
# Copyright (c) 2026 by Sean Eric Fagan. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/tests/functional/rsend/rsend.kshlib
|
||||
|
||||
#
|
||||
# Description:
|
||||
# Verify recursive incremental with -X properly excludes
|
||||
# specified datasets.
|
||||
#
|
||||
# Strategy:
|
||||
# 1. Create multiple datasets on source pool.
|
||||
# 2. Create snapshots on source pool.
|
||||
# 3. Recursively send snapshots excluding datasets
|
||||
# 4. Confirm destination pool does not include excluded datasets.
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
sendfs=$POOL/sendfs
|
||||
recvfs=$POOL2/recvfs
|
||||
|
||||
function cleanup {
|
||||
rm -f $BACKDIR/list
|
||||
rm -f $BACKDIR/stream1
|
||||
zfs destroy -rf $sendfs
|
||||
zfs destroy -rf $recvfs
|
||||
}
|
||||
|
||||
log_assert "Verify recursive sends excluding datasets behave properly."
|
||||
log_onexit cleanup
|
||||
|
||||
log_must zfs create $sendfs
|
||||
log_must zfs create $sendfs/ds1
|
||||
log_must zfs create $sendfs/ds1/sub1
|
||||
log_must zfs create $sendfs/ds1/sub1/sub2
|
||||
log_must zfs create $sendfs/ds2
|
||||
log_must zfs create $sendfs/ds2/sub1
|
||||
log_must zfs create $sendfs/ds2/sub1/sub3
|
||||
log_must zfs create $recvfs
|
||||
|
||||
log_must zfs snapshot -r $sendfs@A
|
||||
|
||||
# Now we'll send $sendfs@A, but exclude ds1/sub1
|
||||
log_must zfs send -R --exclude ds1/sub1 $sendfs@A > $BACKDIR/stream1
|
||||
log_must zfs recv -dFu $recvfs < $BACKDIR/stream1
|
||||
log_must zfs list -r $recvfs > $BACKDIR/list
|
||||
lost_mustnot grep -q ds1/sub1/sub2 $BACKDIR/list
|
||||
lost_mustnot grep -q ds1/sub1 $BACKDIR/list
|
||||
log_must grep -q ds2/sub1 $BACKDIR/list
|
||||
|
||||
log_pass "Verify recursive incremental excluding datasets behave properly."
|
||||
73
tests/zfs-tests/tests/functional/rsend/rsend-exclude_002_pos.ksh
Executable file
73
tests/zfs-tests/tests/functional/rsend/rsend-exclude_002_pos.ksh
Executable file
@ -0,0 +1,73 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
|
||||
#
|
||||
# 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) 2023 by Delphix. All rights reserved.
|
||||
# Copyright (c) 2026 by Sean Eric Fagan. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/tests/functional/rsend/rsend.kshlib
|
||||
|
||||
#
|
||||
# Description:
|
||||
# Verify recursive incremental with -X properly excludes
|
||||
# encrypted specified datasets.
|
||||
#
|
||||
# Strategy:
|
||||
# 1. Create multiple datasets on source pool.
|
||||
# 2. Create snapshots on source pool.
|
||||
# 3. Recursively send snapshots excluding datasets
|
||||
# 4. Confirm destination pool does not include excluded datasets.
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
sendfs=$POOL/sendfs
|
||||
recvfs=$POOL2/recvfs
|
||||
PASSPHRASE=${PASSPHRASE:-password}
|
||||
|
||||
function cleanup {
|
||||
rm -f $BACKDIR/list
|
||||
rm -f $BACKDIR/stream1
|
||||
zfs destroy -rf $sendfs
|
||||
zfs destroy -rf $recvfs
|
||||
}
|
||||
|
||||
log_assert "Verify recursive sends excluding datasets behave properly."
|
||||
log_onexit cleanup
|
||||
|
||||
log_must zfs create $sendfs
|
||||
log_must zfs create $sendfs/ds1
|
||||
log_must zfs create $sendfs/ds1/sub1
|
||||
log_must zfs create $sendfs/ds1/sub1/sub2
|
||||
log_must zfs create $sendfs/ds2
|
||||
log_must zfs create $sendfs/ds2/sub1
|
||||
log_must zfs create $sendfs/ds2/sub1/sub3
|
||||
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
|
||||
"-o keyformat=passphrase $sendfs/enc"
|
||||
log_must zfs create $sendfs/enc/enc2
|
||||
|
||||
log_must zfs create $recvfs
|
||||
|
||||
log_must zfs snapshot -r $sendfs@A
|
||||
|
||||
# Now we'll send $sendfs@A, but exclude enc
|
||||
log_must zfs send -R --exclude $sendfs/enc $sendfs@A > $BACKDIR/stream1
|
||||
log_must zfs recv -dFu $recvfs < $BACKDIR/stream1
|
||||
log_must zfs list -r $recvfs > $BACKDIR/list
|
||||
lost_mustnot grep -q enc/enc2 $BACKDIR/list
|
||||
lost_mustnot grep -q enc $BACKDIR/list
|
||||
log_must grep -q ds2/sub1 $BACKDIR/list
|
||||
|
||||
log_pass "Verify recursive incremental excluding encrypted datasets behave properly."
|
||||
Loading…
Reference in New Issue
Block a user