Skip to content

Commit

Permalink
free objects when receiving full stream as clone
Browse files Browse the repository at this point in the history
all objects after the last written or freed object are not supposed to
exist after receiving the stream. free them accordingly, as if a
freeobjects record for them had been included in the stream.

Signed-off-by: Fabian Grünbichler <[email protected]>
  • Loading branch information
Fabian-Gruenbichler committed Oct 3, 2017
1 parent 4adab0c commit bf7a8de
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/sys/dmu_send.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ typedef struct dmu_recv_cookie {
boolean_t drc_force;
boolean_t drc_resumable;
boolean_t drc_raw;
boolean_t drc_clone;
struct avl_tree *drc_guid_to_ds_map;
zio_cksum_t drc_cksum;
uint64_t drc_newsnapobj;
Expand Down
58 changes: 58 additions & 0 deletions module/zfs/dmu_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -2088,6 +2088,7 @@ dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
drc->drc_force = force;
drc->drc_resumable = resumable;
drc->drc_cred = CRED();
drc->drc_clone = (origin != NULL);

if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
drc->drc_byteswap = B_TRUE;
Expand Down Expand Up @@ -2150,6 +2151,7 @@ struct receive_writer_arg {
boolean_t resumable;
boolean_t raw;
uint64_t last_object, last_offset;
uint64_t last_touched_object;
uint64_t bytes_read; /* bytes read when current record created */
};

Expand Down Expand Up @@ -2451,6 +2453,9 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
return (SET_ERROR(EINVAL));
object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT;

if (drro->drr_object > rwa->last_touched_object)
rwa->last_touched_object = drro->drr_object;

/*
* If we are losing blkptrs or changing the block size this must
* be a new file instance. We must clear out the previous file
Expand Down Expand Up @@ -2587,6 +2592,9 @@ receive_freeobjects(struct receive_writer_arg *rwa,
err = dmu_free_long_object(rwa->os, obj);
if (err != 0)
return (err);

if (obj > rwa->last_touched_object)
rwa->last_touched_object = obj;
}
if (next_err != ESRCH)
return (next_err);
Expand Down Expand Up @@ -2617,6 +2625,9 @@ receive_write(struct receive_writer_arg *rwa, struct drr_write *drrw,
rwa->last_object = drrw->drr_object;
rwa->last_offset = drrw->drr_offset;

if (rwa->last_object > rwa->last_touched_object)
rwa->last_touched_object = rwa->last_object;

if (dmu_object_info(rwa->os, drrw->drr_object, NULL) != 0)
return (SET_ERROR(EINVAL));

Expand Down Expand Up @@ -2698,6 +2709,9 @@ receive_write_byref(struct receive_writer_arg *rwa,
ref_os = rwa->os;
}

if (drrwbr->drr_object > rwa->last_touched_object)
rwa->last_touched_object = drrwbr->drr_object;

if (rwa->raw)
flags |= DMU_READ_NO_DECRYPT;

Expand Down Expand Up @@ -2751,6 +2765,9 @@ receive_write_embedded(struct receive_writer_arg *rwa,
if (drrwe->drr_compression >= ZIO_COMPRESS_FUNCTIONS)
return (SET_ERROR(EINVAL));

if (drrwe->drr_object > rwa->last_touched_object)
rwa->last_touched_object = drrwe->drr_object;

tx = dmu_tx_create(rwa->os);

dmu_tx_hold_write(tx, drrwe->drr_object,
Expand Down Expand Up @@ -2794,6 +2811,9 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
if (dmu_object_info(rwa->os, drrs->drr_object, NULL) != 0)
return (SET_ERROR(EINVAL));

if (drrs->drr_object > rwa->last_touched_object)
rwa->last_touched_object = drrs->drr_object;

VERIFY0(dmu_bonus_hold(rwa->os, drrs->drr_object, FTAG, &db));
if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) {
dmu_buf_rele(db, FTAG);
Expand Down Expand Up @@ -2840,6 +2860,9 @@ receive_free(struct receive_writer_arg *rwa, struct drr_free *drrf)
if (dmu_object_info(rwa->os, drrf->drr_object, NULL) != 0)
return (SET_ERROR(EINVAL));

if (drrf->drr_object > rwa->last_touched_object)
rwa->last_touched_object = drrf->drr_object;

err = dmu_free_long_range(rwa->os, drrf->drr_object,
drrf->drr_offset, drrf->drr_length);

Expand Down Expand Up @@ -2882,6 +2905,9 @@ receive_object_range(struct receive_writer_arg *rwa,
!rwa->raw)
return (SET_ERROR(EINVAL));

if (drror->drr_firstobj > rwa->last_touched_object)
rwa->last_touched_object = drror->drr_firstobj;

offset = drror->drr_firstobj * sizeof (dnode_phys_t);
mdn = DMU_META_DNODE(rwa->os);

Expand Down Expand Up @@ -3720,6 +3746,38 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
}
mutex_exit(&rwa->mutex);

/*
* if we are receiving a full stream as clone, we need to free leftover
* objects after the last one referenced in the stream.
*/
if (drc->drc_clone && drc->drc_drrb->drr_fromguid == 0) {
uint64_t obj;
int free_err = 0, next_err = 0;

for (obj = rwa->last_touched_object + 1;
next_err == 0;
next_err = dmu_object_next(rwa->os, &obj, FALSE, 0)) {
dmu_object_info_t doi;

free_err = dmu_object_info(rwa->os, obj, &doi);
if (free_err == ENOENT)
continue;
else if (free_err != 0)
break;

free_err = dmu_free_long_object(rwa->os, obj);
if (free_err != 0)
break;
}

if (err == 0) {
if (free_err != 0 && free_err != ENOENT)
err = free_err;
else if (next_err != ESRCH)
err = next_err;
}
}

cv_destroy(&rwa->cv);
mutex_destroy(&rwa->mutex);
bqueue_destroy(&rwa->q);
Expand Down

0 comments on commit bf7a8de

Please sign in to comment.