Skip to content

Commit

Permalink
7247 zfs receive of deduplicated stream fails
Browse files Browse the repository at this point in the history
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

Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: Dan Kimmel <[email protected]>
Author: Chris Williamson <[email protected]>

openzfs/openzfs@b09697c
  • Loading branch information
amotin committed Sep 3, 2016
1 parent e172733 commit 4099119
Showing 1 changed file with 21 additions and 23 deletions.
44 changes: 21 additions & 23 deletions uts/common/fs/zfs/dmu_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -3047,6 +3047,9 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
dsl_dataset_phys(origin_head)->ds_flags &=
~DS_FLAG_INCONSISTENT;

drc->drc_newsnapobj =
dsl_dataset_phys(origin_head)->ds_prev_snap_obj;

dsl_dataset_rele(origin_head, FTAG);
dsl_destroy_head_sync_impl(drc->drc_ds, tx);

Expand Down Expand Up @@ -3082,8 +3085,9 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
(void) zap_remove(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_TONAME, tx);
}
drc->drc_newsnapobj =
dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
}
drc->drc_newsnapobj = dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
/*
* Release the hold from dmu_recv_begin. This must be done before
* we return to open context, so that when we free the dataset's dnode,
Expand Down Expand Up @@ -3126,8 +3130,6 @@ static int dmu_recv_end_modified_blocks = 3;
static int
dmu_recv_existing_end(dmu_recv_cookie_t *drc)
{
int error;

#ifdef _KERNEL
/*
* We will be destroying the ds; make sure its origin is unmounted if
Expand All @@ -3138,23 +3140,30 @@ dmu_recv_existing_end(dmu_recv_cookie_t *drc)
zfs_destroy_unmount_origin(name);
#endif

error = dsl_sync_task(drc->drc_tofs,
return (dsl_sync_task(drc->drc_tofs,
dmu_recv_end_check, dmu_recv_end_sync, drc,
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);

if (error != 0)
dmu_recv_cleanup_ds(drc);
return (error);
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
}

static int
dmu_recv_new_end(dmu_recv_cookie_t *drc)
{
return (dsl_sync_task(drc->drc_tofs,
dmu_recv_end_check, dmu_recv_end_sync, drc,
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
}

int
dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
{
int error;

error = dsl_sync_task(drc->drc_tofs,
dmu_recv_end_check, dmu_recv_end_sync, drc,
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
drc->drc_owner = owner;

if (drc->drc_newfs)
error = dmu_recv_new_end(drc);
else
error = dmu_recv_existing_end(drc);

if (error != 0) {
dmu_recv_cleanup_ds(drc);
Expand All @@ -3166,17 +3175,6 @@ dmu_recv_new_end(dmu_recv_cookie_t *drc)
return (error);
}

int
dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
{
drc->drc_owner = owner;

if (drc->drc_newfs)
return (dmu_recv_new_end(drc));
else
return (dmu_recv_existing_end(drc));
}

/*
* Return TRUE if this objset is currently being received into.
*/
Expand Down

0 comments on commit 4099119

Please sign in to comment.