Skip to content

Commit b09697c

Browse files
cwillahrens
authored andcommitted
7247 zfs receive of deduplicated stream fails
Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> This resolves two 'zfs recv' issues. First, when receiving into an existing filesystem, a snapshot created during the receive process is not added to the guid->dataset map for the stream, resulting in failed lookups for deduped streams when a WRITE_BYREF record refers to a snapshot received earlier in the stream. Second, the newly created snapshot was also not set properly, referencing the snapshot before the new receiving dataset rather than the existing filesystem. Closes #159
1 parent 0780b3e commit b09697c

File tree

5 files changed

+101
-25
lines changed

5 files changed

+101
-25
lines changed

usr/src/pkg/manifests/system-test-zfstest.mf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,9 @@ file \
710710
file \
711711
path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_012_pos \
712712
mode=0555
713+
file \
714+
path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_013_pos \
715+
mode=0555
713716
file path=opt/zfs-tests/tests/functional/cli_root/zfs_rename/cleanup mode=0555
714717
file path=opt/zfs-tests/tests/functional/cli_root/zfs_rename/setup mode=0555
715718
file path=opt/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.cfg \

usr/src/test/zfs-tests/runfiles/delphix.run

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ tests = ['zfs_written_property_001_pos']
150150
tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
151151
'zfs_receive_005_neg', 'zfs_receive_006_pos',
152152
'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_009_neg',
153-
'zfs_receive_010_pos', 'zfs_receive_011_pos', 'zfs_receive_012_pos']
153+
'zfs_receive_010_pos', 'zfs_receive_011_pos', 'zfs_receive_012_pos',
154+
'zfs_receive_013_pos']
154155

155156
[/opt/zfs-tests/tests/functional/cli_root/zfs_rename]
156157
tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos',

usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ PROGS = cleanup \
3232
zfs_receive_009_neg \
3333
zfs_receive_010_pos \
3434
zfs_receive_011_pos \
35-
zfs_receive_012_pos
35+
zfs_receive_012_pos \
36+
zfs_receive_013_pos
3637

3738
CMDS = $(PROGS:%=$(TESTDIR)/%)
3839
$(CMDS) := FILEMODE = 0555
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/ksh -p
2+
#
3+
# CDDL HEADER START
4+
#
5+
# This file and its contents are supplied under the terms of the
6+
# Common Development and Distribution License ("CDDL"), version 1.0.
7+
# You may only use this file in accordance with the terms of version
8+
# 1.0 of the CDDL.
9+
#
10+
# A full copy of the text of the CDDL should have accompanied this
11+
# source. A copy of the CDDL is also available via the Internet at
12+
# http://www.illumos.org/license/CDDL.
13+
#
14+
# CDDL HEADER END
15+
#
16+
17+
#
18+
# Copyright (c) 2015 by Delphix. All rights reserved.
19+
#
20+
21+
. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
22+
23+
#
24+
# DESCRIPTION:
25+
# Verifying 'zfs receive' works correctly on deduplicated streams
26+
#
27+
# STRATEGY:
28+
# 1. Create some snapshots with duplicated data
29+
# 2. Send a deduplicated stream of the last snapshot
30+
# 3. Attempt to receive the deduplicated stream
31+
#
32+
33+
src_fs=$TESTPOOL/drecvsrc
34+
temppool=recvtank
35+
dst_fs=$temppool/drecvdest
36+
streamfile=/var/tmp/drecvstream.$$
37+
tpoolfile=/temptank.$$
38+
39+
function cleanup
40+
{
41+
for fs in $src_fs $dst_fs; do
42+
datasetexists $fs && log_must $ZFS destroy -rf $fs
43+
done
44+
zpool destroy $temppool
45+
[[ -f $streamfile ]] && log_must $RM -f $streamfile
46+
[[ -f $tpoolfile ]] && log_must $RM -f $tpoolfile
47+
}
48+
49+
log_assert "Verifying 'zfs receive' works correctly on deduplicated streams"
50+
log_onexit cleanup
51+
52+
truncate -s 100M $tpoolfile
53+
log_must zpool create $temppool $tpoolfile
54+
log_must $ZFS create $src_fs
55+
src_mnt=$(get_prop mountpoint $src_fs) || log_fail "get_prop mountpoint $src_fs"
56+
57+
echo blah > $src_mnt/blah
58+
$ZFS snapshot $src_fs@base
59+
60+
echo grumble > $src_mnt/grumble
61+
echo blah > $src_mnt/blah2
62+
$ZFS snapshot $src_fs@snap2
63+
64+
echo grumble > $src_mnt/mumble
65+
echo blah > $src_mnt/blah3
66+
$ZFS snapshot $src_fs@snap3
67+
68+
log_must eval "$ZFS send -D -R $src_fs@snap3 > $streamfile"
69+
log_must eval "$ZFS receive -v $dst_fs < $streamfile"
70+
71+
cleanup
72+
73+
log_pass "Verifying 'zfs receive' works correctly on deduplicated streams"

usr/src/uts/common/fs/zfs/dmu_send.c

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3047,6 +3047,9 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
30473047
dsl_dataset_phys(origin_head)->ds_flags &=
30483048
~DS_FLAG_INCONSISTENT;
30493049

3050+
drc->drc_newsnapobj =
3051+
dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
3052+
30503053
dsl_dataset_rele(origin_head, FTAG);
30513054
dsl_destroy_head_sync_impl(drc->drc_ds, tx);
30523055

@@ -3082,8 +3085,9 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
30823085
(void) zap_remove(dp->dp_meta_objset, ds->ds_object,
30833086
DS_FIELD_RESUME_TONAME, tx);
30843087
}
3088+
drc->drc_newsnapobj =
3089+
dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
30853090
}
3086-
drc->drc_newsnapobj = dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
30873091
/*
30883092
* Release the hold from dmu_recv_begin. This must be done before
30893093
* we return to open context, so that when we free the dataset's dnode,
@@ -3126,8 +3130,6 @@ static int dmu_recv_end_modified_blocks = 3;
31263130
static int
31273131
dmu_recv_existing_end(dmu_recv_cookie_t *drc)
31283132
{
3129-
int error;
3130-
31313133
#ifdef _KERNEL
31323134
/*
31333135
* We will be destroying the ds; make sure its origin is unmounted if
@@ -3138,23 +3140,30 @@ dmu_recv_existing_end(dmu_recv_cookie_t *drc)
31383140
zfs_destroy_unmount_origin(name);
31393141
#endif
31403142

3141-
error = dsl_sync_task(drc->drc_tofs,
3143+
return (dsl_sync_task(drc->drc_tofs,
31423144
dmu_recv_end_check, dmu_recv_end_sync, drc,
3143-
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
3144-
3145-
if (error != 0)
3146-
dmu_recv_cleanup_ds(drc);
3147-
return (error);
3145+
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
31483146
}
31493147

31503148
static int
31513149
dmu_recv_new_end(dmu_recv_cookie_t *drc)
3150+
{
3151+
return (dsl_sync_task(drc->drc_tofs,
3152+
dmu_recv_end_check, dmu_recv_end_sync, drc,
3153+
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
3154+
}
3155+
3156+
int
3157+
dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
31523158
{
31533159
int error;
31543160

3155-
error = dsl_sync_task(drc->drc_tofs,
3156-
dmu_recv_end_check, dmu_recv_end_sync, drc,
3157-
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
3161+
drc->drc_owner = owner;
3162+
3163+
if (drc->drc_newfs)
3164+
error = dmu_recv_new_end(drc);
3165+
else
3166+
error = dmu_recv_existing_end(drc);
31583167

31593168
if (error != 0) {
31603169
dmu_recv_cleanup_ds(drc);
@@ -3166,17 +3175,6 @@ dmu_recv_new_end(dmu_recv_cookie_t *drc)
31663175
return (error);
31673176
}
31683177

3169-
int
3170-
dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
3171-
{
3172-
drc->drc_owner = owner;
3173-
3174-
if (drc->drc_newfs)
3175-
return (dmu_recv_new_end(drc));
3176-
else
3177-
return (dmu_recv_existing_end(drc));
3178-
}
3179-
31803178
/*
31813179
* Return TRUE if this objset is currently being received into.
31823180
*/

0 commit comments

Comments
 (0)