Skip to content

Commit c217393

Browse files
committed
optimize recv_fix_encryption_hierarchy()
Signed-off-by: George Amanakis <[email protected]>
1 parent dc0324b commit c217393

File tree

2 files changed

+172
-62
lines changed

2 files changed

+172
-62
lines changed

lib/libzfs/libzfs_sendrecv.c

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3376,30 +3376,28 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
33763376
*/
33773377
static int
33783378
recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
3379-
nvlist_t *stream_nv)
3379+
nvlist_t *stream_nv, avl_tree_t *stream_avl)
33803380
{
33813381
int err;
3382-
nvpair_t *fselem = NULL;
3383-
nvlist_t *stream_fss;
3382+
nvpair_t *fselem = NULL, *nextfselem;
3383+
nvlist_t *local_nv, *stream_fss;
3384+
avl_tree_t *local_avl;
3385+
boolean_t recursive;
3386+
char fsname[ZFS_MAX_DATASET_NAME_LEN], *cp;
33843387

3385-
stream_fss = fnvlist_lookup_nvlist(stream_nv, "fss");
3388+
recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
3389+
ENOENT);
33863390

3391+
/*
3392+
* Go through the send stream and find a snapshot that exists
3393+
* locally.
3394+
*/
3395+
stream_fss = fnvlist_lookup_nvlist(stream_nv, "fss");
33873396
while ((fselem = nvlist_next_nvpair(stream_fss, fselem)) != NULL) {
3388-
zfs_handle_t *zhp = NULL;
3389-
uint64_t crypt;
3390-
nvlist_t *snaps, *props, *stream_nvfs = NULL;
3397+
nvlist_t *snaps, *stream_nvfs;
33913398
nvpair_t *snapel = NULL;
3392-
boolean_t is_encroot, is_clone, stream_encroot;
3393-
char *cp;
3394-
const char *stream_keylocation = NULL;
3395-
char keylocation[MAXNAMELEN];
3396-
char fsname[ZFS_MAX_DATASET_NAME_LEN];
3397-
3398-
keylocation[0] = '\0';
33993399
stream_nvfs = fnvpair_value_nvlist(fselem);
34003400
snaps = fnvlist_lookup_nvlist(stream_nvfs, "snaps");
3401-
props = fnvlist_lookup_nvlist(stream_nvfs, "props");
3402-
stream_encroot = nvlist_exists(stream_nvfs, "is_encroot");
34033401

34043402
/* find a snapshot from the stream that exists locally */
34053403
err = ENOENT;
@@ -3413,45 +3411,99 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
34133411
break;
34143412
}
34153413

3416-
if (err != 0)
3417-
continue;
3414+
if (err == 0)
3415+
break;
3416+
}
34183417

3419-
cp = strchr(fsname, '@');
3420-
if (cp != NULL)
3421-
*cp = '\0';
3418+
/* If we failed to find a snapshot that exists locally return. */
3419+
if (err != 0)
3420+
return (0);
34223421

3423-
zhp = zfs_open(hdl, fsname, ZFS_TYPE_DATASET);
3422+
/* Convert the snapshot to fs name */
3423+
cp = strchr(fsname, '@');
3424+
if (cp != NULL)
3425+
*cp = '\0';
3426+
3427+
/* Using the fs name, gather the nvlists for all local filesystems. */
3428+
if ((err = gather_nvlist(hdl, fsname, NULL, NULL,
3429+
recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,
3430+
B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)
3431+
return (err);
3432+
3433+
/*
3434+
* Go through the nvlists of the local filesystems and check for
3435+
* encryption roots.
3436+
*/
3437+
for (fselem = nvlist_next_nvpair(local_nv, NULL); fselem;
3438+
fselem = nextfselem) {
3439+
zfs_handle_t *zhp = NULL;
3440+
uint64_t crypt;
3441+
nvlist_t *stream_props, *snaps, *stream_nvfs = NULL,
3442+
*nvfs = NULL;
3443+
boolean_t is_encroot, is_clone, stream_encroot;
3444+
const char *stream_keylocation = NULL, *fs;
3445+
char keylocation[MAXNAMELEN];
3446+
nvpair_t *snapelem;
3447+
3448+
nextfselem = nvlist_next_nvpair(local_nv, fselem);
3449+
3450+
nvfs = fnvpair_value_nvlist(fselem);
3451+
snaps = fnvlist_lookup_nvlist(nvfs, "snaps");
3452+
fs = fnvlist_lookup_string(nvfs, "name");
3453+
zhp = zfs_open(hdl, fs, ZFS_TYPE_DATASET);
34243454
if (zhp == NULL) {
34253455
err = ENOENT;
34263456
goto error;
34273457
}
34283458

3429-
crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
3430-
is_clone = zhp->zfs_dmustats.dds_origin[0] != '\0';
3431-
(void) zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);
3432-
34333459
/* we don't need to do anything for unencrypted datasets */
3460+
crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
34343461
if (crypt == ZIO_CRYPT_OFF) {
34353462
zfs_close(zhp);
34363463
continue;
34373464
}
34383465

3466+
is_clone = zhp->zfs_dmustats.dds_origin[0] != '\0';
3467+
(void) zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);
3468+
keylocation[0] = '\0';
3469+
3470+
/*
3471+
* Go through the snapshots of the local filesystem and find
3472+
* the stream's filesystem.
3473+
*/
3474+
for (snapelem = nvlist_next_nvpair(snaps, NULL);
3475+
snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {
3476+
uint64_t thisguid;
3477+
3478+
thisguid = fnvpair_value_uint64(snapelem);
3479+
stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);
3480+
3481+
if (stream_nvfs != NULL)
3482+
break;
3483+
}
3484+
3485+
if (stream_nvfs == NULL)
3486+
continue;
3487+
3488+
stream_props = fnvlist_lookup_nvlist(stream_nvfs, "props");
3489+
stream_encroot = nvlist_exists(stream_nvfs, "is_encroot");
3490+
34393491
/*
34403492
* If the dataset is flagged as an encryption root, was not
34413493
* received as a clone and is not currently an encryption root,
34423494
* force it to become one. Fixup the keylocation if necessary.
34433495
*/
34443496
if (stream_encroot) {
34453497
if (!is_clone && !is_encroot) {
3446-
err = lzc_change_key(fsname,
3498+
err = lzc_change_key(fs,
34473499
DCP_CMD_FORCE_NEW_KEY, NULL, NULL, 0);
34483500
if (err != 0) {
34493501
zfs_close(zhp);
34503502
goto error;
34513503
}
34523504
}
34533505

3454-
stream_keylocation = fnvlist_lookup_string(props,
3506+
stream_keylocation = fnvlist_lookup_string(stream_props,
34553507
zfs_prop_to_name(ZFS_PROP_KEYLOCATION));
34563508

34573509
/*
@@ -3485,8 +3537,8 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
34853537
* force-inherited.
34863538
*/
34873539
if (!stream_encroot && is_encroot &&
3488-
strcmp(top_zfs, fsname) != 0) {
3489-
err = lzc_change_key(fsname, DCP_CMD_FORCE_INHERIT,
3540+
strcmp(top_zfs, fs) != 0) {
3541+
err = lzc_change_key(fs, DCP_CMD_FORCE_INHERIT,
34903542
NULL, NULL, 0);
34913543
if (err != 0) {
34923544
zfs_close(zhp);
@@ -3518,14 +3570,14 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
35183570
boolean_t needagain, progress, recursive;
35193571
const char *s1, *s2;
35203572

3573+
if (flags->dryrun)
3574+
return (0);
3575+
35213576
fromsnap = fnvlist_lookup_string(stream_nv, "fromsnap");
35223577

35233578
recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
35243579
ENOENT);
35253580

3526-
if (flags->dryrun)
3527-
return (0);
3528-
35293581
again:
35303582
needagain = progress = B_FALSE;
35313583

@@ -3999,9 +4051,9 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
39994051
stream_nv, stream_avl, NULL);
40004052
}
40014053

4002-
if (raw && softerr == 0 && *top_zfs != NULL) {
4054+
if (raw && softerr == 0 && *top_zfs != NULL && !flags->dryrun) {
40034055
softerr = recv_fix_encryption_hierarchy(hdl, *top_zfs,
4004-
stream_nv);
4056+
stream_nv, stream_avl);
40054057
}
40064058

40074059
out:

tests/zfs-tests/tests/functional/rsend/send_encrypted_hierarchy.ksh

Lines changed: 85 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,49 +48,107 @@ log_onexit cleanup
4848

4949
# Create the filesystem hierarchy
5050
log_must cleanup_pool $POOL
51+
log_must zfs create $POOL/fs1
52+
log_must zfs create $POOL2/fs2
5153
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
52-
"-o keyformat=passphrase $POOL/$FS"
53-
log_must zfs snapshot $POOL/$FS@snap
54-
log_must zfs clone $POOL/$FS@snap $POOL/clone
55-
log_must zfs create $POOL/$FS/child
54+
"-o keyformat=passphrase $POOL/fs1/$FS"
55+
log_must zfs snapshot $POOL/fs1/$FS@snap
56+
log_must zfs clone $POOL/fs1/$FS@snap $POOL/clone
57+
log_must zfs create $POOL/fs1/$FS/child
58+
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
59+
"-o keyformat=passphrase $POOL/fs1/a"
60+
log_must zfs snapshot $POOL/fs1/a@snapa
61+
log_must zfs clone $POOL/fs1/a@snapa $POOL/clonea
62+
log_must zfs create $POOL/fs1/a/childa
5663

5764
# Back up the tree and verify the structure
5865
log_must zfs snapshot -r $POOL@before
5966
log_must eval "zfs send -wR $POOL@before > $BACKDIR/fs-before-R"
60-
log_must eval "zfs receive -d -F $POOL2 < $BACKDIR/fs-before-R"
61-
dstds=$(get_dst_ds $POOL/$FS $POOL2)
62-
log_must cmp_ds_subs $POOL/$FS $dstds
63-
64-
log_must verify_encryption_root $POOL/$FS $POOL/$FS
65-
log_must verify_keylocation $POOL/$FS "prompt"
66-
log_must verify_origin $POOL/$FS "-"
67-
68-
log_must verify_encryption_root $POOL/clone $POOL/$FS
69-
log_must verify_keylocation $POOL/clone "none"
70-
log_must verify_origin $POOL/clone "$POOL/$FS@snap"
71-
72-
log_must verify_encryption_root $POOL/$FS/child $POOL/$FS
73-
log_must verify_keylocation $POOL/$FS/child "none"
67+
log_must eval "zfs receive -d -F $POOL2/fs2 < $BACKDIR/fs-before-R"
68+
dstds=$(get_dst_ds $POOL/fs1/$FS $POOL2/fs2)
69+
dstdsa=$(get_dst_ds $POOL/fs1/a $POOL2/fs2)
70+
log_must cmp_ds_subs $POOL/fs1/$FS $dstds
71+
log_must cmp_ds_subs $POOL/fs1/a $dstdsa
72+
73+
log_must verify_encryption_root $POOL2/fs2/fs1/$FS $POOL2/fs2/fs1/$FS
74+
log_must verify_keylocation $POOL2/fs2/fs1/$FS "prompt"
75+
log_must verify_origin $POOL2/fs2/fs1/$FS "-"
76+
log_must verify_encryption_root $POOL2/fs2/fs1/a $POOL2/fs2/fs1/a
77+
log_must verify_keylocation $POOL2/fs2/fs1/a "prompt"
78+
log_must verify_origin $POOL2/fs2/fs1/a "-"
79+
80+
log_must verify_encryption_root $POOL2/fs2/clone $POOL2/fs2/fs1/$FS
81+
log_must verify_keylocation $POOL2/fs2/clone "none"
82+
log_must verify_origin $POOL2/fs2/clone "$POOL2/fs2/fs1/$FS@snap"
83+
log_must verify_encryption_root $POOL2/fs2/clonea $POOL2/fs2/fs1/a
84+
log_must verify_keylocation $POOL2/fs2/clonea "none"
85+
log_must verify_origin $POOL2/fs2/clonea "$POOL2/fs2/fs1/a@snapa"
86+
87+
log_must verify_encryption_root $POOL/fs1/$FS/child $POOL/fs1/$FS
88+
log_must verify_encryption_root $POOL2/fs2/fs1/$FS/child $POOL2/fs2/fs1/$FS
89+
log_must verify_keylocation $POOL2/fs2/fs1/$FS/child "none"
90+
log_must verify_encryption_root $POOL2/fs2/fs1/a/childa $POOL2/fs2/fs1/a
91+
log_must verify_keylocation $POOL2/fs2/fs1/a/childa "none"
7492

7593
# Alter the hierarchy and re-send
7694
log_must eval "echo $PASSPHRASE1 | zfs change-key -o keyformat=passphrase" \
77-
"$POOL/$FS/child"
95+
"$POOL/fs1/$FS/child"
96+
log_must eval "echo $PASSPHRASE1 | zfs change-key -o keyformat=passphrase" \
97+
"$POOL/fs1/a/childa"
7898
log_must zfs promote $POOL/clone
99+
log_must zfs promote $POOL/clonea
79100
log_must zfs snapshot -r $POOL@after
80101
log_must eval "zfs send -wR -i $POOL@before $POOL@after >" \
81102
"$BACKDIR/fs-after-R"
82-
log_must eval "zfs receive -d -F $POOL2 < $BACKDIR/fs-after-R"
83-
log_must cmp_ds_subs $POOL/$FS $dstds
103+
log_must eval "zfs receive -d -F $POOL2/fs2 < $BACKDIR/fs-after-R"
104+
log_must cmp_ds_subs $POOL/fs1/$FS $dstds
105+
log_must cmp_ds_subs $POOL/fs1/a $dstdsa
84106

85-
log_must verify_encryption_root $POOL/$FS $POOL/clone
86-
log_must verify_keylocation $POOL/$FS "none"
87-
log_must verify_origin $POOL/$FS "$POOL/clone@snap"
107+
log_must verify_encryption_root $POOL/fs1/$FS $POOL/clone
108+
log_must verify_keylocation $POOL/fs1/$FS "none"
109+
log_must verify_origin $POOL/fs1/$FS "$POOL/clone@snap"
110+
log_must verify_encryption_root $POOL/fs1/a $POOL/clonea
111+
log_must verify_keylocation $POOL/fs1/a "none"
112+
log_must verify_origin $POOL/fs1/a "$POOL/clonea@snapa"
88113

89114
log_must verify_encryption_root $POOL/clone $POOL/clone
90115
log_must verify_keylocation $POOL/clone "prompt"
91116
log_must verify_origin $POOL/clone "-"
92-
93-
log_must verify_encryption_root $POOL/$FS/child $POOL/$FS/child
94-
log_must verify_keylocation $POOL/$FS/child "prompt"
117+
log_must verify_encryption_root $POOL/clonea $POOL/clonea
118+
log_must verify_keylocation $POOL/clonea "prompt"
119+
log_must verify_origin $POOL/clonea "-"
120+
121+
log_must verify_encryption_root $POOL/fs1/$FS/child $POOL/fs1/$FS/child
122+
log_must verify_keylocation $POOL/fs1/$FS/child "prompt"
123+
log_must verify_encryption_root $POOL/fs1/a/childa $POOL/fs1/a/childa
124+
log_must verify_keylocation $POOL/fs1/a/childa "prompt"
125+
126+
log_must verify_encryption_root $POOL2/fs2 "-"
127+
log_must verify_encryption_root $POOL2/fs2/clone $POOL2/fs2/clone
128+
log_must verify_encryption_root $POOL2/fs2/clonea $POOL2/fs2/clonea
129+
log_must verify_encryption_root $POOL2/fs2/fs1 "-"
130+
log_must verify_encryption_root $POOL2/fs2/fs1/a $POOL2/fs2/clonea
131+
log_must verify_encryption_root $POOL2/fs2/fs1/a/childa $POOL2/fs2/fs1/a/childa
132+
log_must verify_encryption_root $POOL2/fs2/fs1/$FS $POOL2/fs2/clone
133+
log_must verify_encryption_root $POOL2/fs2/fs1/$FS/child $POOL2/fs2/fs1/$FS/child
134+
135+
log_must verify_keylocation $POOL2/fs2 "none"
136+
log_must verify_keylocation $POOL2/fs2/clone "prompt"
137+
log_must verify_keylocation $POOL2/fs2/clonea "prompt"
138+
log_must verify_keylocation $POOL2/fs2/fs1 "none"
139+
log_must verify_keylocation $POOL2/fs2/fs1/a "none"
140+
log_must verify_keylocation $POOL2/fs2/fs1/a/childa "prompt"
141+
log_must verify_keylocation $POOL2/fs2/fs1/$FS "none"
142+
log_must verify_keylocation $POOL2/fs2/fs1/$FS/child "prompt"
143+
144+
log_must verify_origin $POOL2/fs2 "-"
145+
log_must verify_origin $POOL2/fs2/clone "-"
146+
log_must verify_origin $POOL2/fs2/clonea "-"
147+
log_must verify_origin $POOL2/fs2/fs1 "-"
148+
log_must verify_origin $POOL2/fs2/fs1/a "$POOL2/fs2/clonea@snapa"
149+
log_must verify_origin $POOL2/fs2/fs1/a/childa "-"
150+
log_must verify_origin $POOL2/fs2/fs1/$FS "$POOL2/fs2/clone@snap"
151+
log_must verify_origin $POOL2/fs2/fs1/$FS/child "-"
152+
log_must zfs list
95153

96154
log_pass "Raw recursive sends preserve filesystem structure."

0 commit comments

Comments
 (0)