Free objects when receiving full stream as clone
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. Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> Closes #5699 Closes #6507 Closes #6616
This commit is contained in:
parent
aee1dd4d98
commit
48fbb9ddbf
|
@ -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;
|
||||
|
|
|
@ -2072,6 +2072,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;
|
||||
|
@ -2133,7 +2134,9 @@ struct receive_writer_arg {
|
|||
avl_tree_t *guid_to_ds_map;
|
||||
boolean_t resumable;
|
||||
boolean_t raw;
|
||||
uint64_t last_object, last_offset;
|
||||
uint64_t last_object;
|
||||
uint64_t last_offset;
|
||||
uint64_t max_object; /* highest object ID referenced in stream */
|
||||
uint64_t bytes_read; /* bytes read when current record created */
|
||||
};
|
||||
|
||||
|
@ -2435,6 +2438,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->max_object)
|
||||
rwa->max_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
|
||||
|
@ -2571,6 +2577,9 @@ receive_freeobjects(struct receive_writer_arg *rwa,
|
|||
err = dmu_free_long_object(rwa->os, obj);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
if (obj > rwa->max_object)
|
||||
rwa->max_object = obj;
|
||||
}
|
||||
if (next_err != ESRCH)
|
||||
return (next_err);
|
||||
|
@ -2601,6 +2610,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->max_object)
|
||||
rwa->max_object = rwa->last_object;
|
||||
|
||||
if (dmu_object_info(rwa->os, drrw->drr_object, NULL) != 0)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
|
@ -2682,6 +2694,9 @@ receive_write_byref(struct receive_writer_arg *rwa,
|
|||
ref_os = rwa->os;
|
||||
}
|
||||
|
||||
if (drrwbr->drr_object > rwa->max_object)
|
||||
rwa->max_object = drrwbr->drr_object;
|
||||
|
||||
if (rwa->raw)
|
||||
flags |= DMU_READ_NO_DECRYPT;
|
||||
|
||||
|
@ -2735,6 +2750,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->max_object)
|
||||
rwa->max_object = drrwe->drr_object;
|
||||
|
||||
tx = dmu_tx_create(rwa->os);
|
||||
|
||||
dmu_tx_hold_write(tx, drrwe->drr_object,
|
||||
|
@ -2778,6 +2796,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->max_object)
|
||||
rwa->max_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);
|
||||
|
@ -2824,6 +2845,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->max_object)
|
||||
rwa->max_object = drrf->drr_object;
|
||||
|
||||
err = dmu_free_long_range(rwa->os, drrf->drr_object,
|
||||
drrf->drr_offset, drrf->drr_length);
|
||||
|
||||
|
@ -2866,6 +2890,9 @@ receive_object_range(struct receive_writer_arg *rwa,
|
|||
!rwa->raw)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
if (drror->drr_firstobj > rwa->max_object)
|
||||
rwa->max_object = drror->drr_firstobj;
|
||||
|
||||
offset = drror->drr_firstobj * sizeof (dnode_phys_t);
|
||||
mdn = DMU_META_DNODE(rwa->os);
|
||||
|
||||
|
@ -3704,6 +3731,32 @@ 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 a clone, all object IDs which
|
||||
* are greater than the maximum ID referenced in the stream are
|
||||
* by definition unused and must be freed.
|
||||
*/
|
||||
if (drc->drc_clone && drc->drc_drrb->drr_fromguid == 0) {
|
||||
uint64_t obj = rwa->max_object + 1;
|
||||
int free_err = 0;
|
||||
int next_err = 0;
|
||||
|
||||
while (next_err == 0) {
|
||||
free_err = dmu_free_long_object(rwa->os, obj);
|
||||
if (free_err != 0 && free_err != ENOENT)
|
||||
break;
|
||||
|
||||
next_err = dmu_object_next(rwa->os, &obj, FALSE, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue