Changeset View
Changeset View
Standalone View
Standalone View
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
Show First 20 Lines • Show All 1,431 Lines • ▼ Show 20 Lines | if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) && | ||||
return (SET_ERROR(ENOTSUP)); | return (SET_ERROR(ENOTSUP)); | ||||
if ((featureflags & DMU_BACKUP_FEATURE_LZ4) && | if ((featureflags & DMU_BACKUP_FEATURE_LZ4) && | ||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) | !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) | ||||
return (SET_ERROR(ENOTSUP)); | return (SET_ERROR(ENOTSUP)); | ||||
/* | /* | ||||
* The receiving code doesn't know how to translate large blocks | * The receiving code doesn't know how to translate large blocks | ||||
* to smaller ones, so the pool must have the LARGE_BLOCKS | * to smaller ones, so the pool must have the LARGE_BLOCKS | ||||
* feature enabled if the stream has LARGE_BLOCKS. | * feature enabled if the stream has LARGE_BLOCKS. Same with | ||||
* large dnodes. | |||||
*/ | */ | ||||
if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) && | if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) && | ||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS)) | !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS)) | ||||
return (SET_ERROR(ENOTSUP)); | return (SET_ERROR(ENOTSUP)); | ||||
/* | |||||
* The receiving code doesn't know how to translate large dnodes | |||||
* to smaller ones, so the pool must have the LARGE_DNODE | |||||
* feature enabled if the stream has LARGE_DNODE. | |||||
*/ | |||||
if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) && | if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) && | ||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE)) | !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE)) | ||||
return (SET_ERROR(ENOTSUP)); | return (SET_ERROR(ENOTSUP)); | ||||
error = dsl_dataset_hold(dp, tofs, FTAG, &ds); | error = dsl_dataset_hold(dp, tofs, FTAG, &ds); | ||||
if (error == 0) { | if (error == 0) { | ||||
/* target fs already exists; recv into temp clone */ | /* target fs already exists; recv into temp clone */ | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx) | ||||
dmu_recv_begin_arg_t *drba = arg; | dmu_recv_begin_arg_t *drba = arg; | ||||
dsl_pool_t *dp = dmu_tx_pool(tx); | dsl_pool_t *dp = dmu_tx_pool(tx); | ||||
struct drr_begin *drrb = drba->drba_cookie->drc_drrb; | struct drr_begin *drrb = drba->drba_cookie->drc_drrb; | ||||
int error; | int error; | ||||
uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo); | uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo); | ||||
dsl_dataset_t *ds; | dsl_dataset_t *ds; | ||||
const char *tofs = drba->drba_cookie->drc_tofs; | const char *tofs = drba->drba_cookie->drc_tofs; | ||||
/* 6 extra bytes for /%recv */ | |||||
char recvname[ZFS_MAX_DATASET_NAME_LEN + 6]; | |||||
/* already checked */ | /* already checked */ | ||||
ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); | ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); | ||||
ASSERT(featureflags & DMU_BACKUP_FEATURE_RESUMING); | ASSERT(featureflags & DMU_BACKUP_FEATURE_RESUMING); | ||||
if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == | if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == | ||||
DMU_COMPOUNDSTREAM || | DMU_COMPOUNDSTREAM || | ||||
drrb->drr_type >= DMU_OST_NUMTYPES) | drrb->drr_type >= DMU_OST_NUMTYPES) | ||||
return (SET_ERROR(EINVAL)); | return (SET_ERROR(EINVAL)); | ||||
Show All 11 Lines | dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx) | ||||
*/ | */ | ||||
if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) && | if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) && | ||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) | !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) | ||||
return (SET_ERROR(ENOTSUP)); | return (SET_ERROR(ENOTSUP)); | ||||
if ((featureflags & DMU_BACKUP_FEATURE_LZ4) && | if ((featureflags & DMU_BACKUP_FEATURE_LZ4) && | ||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) | !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) | ||||
return (SET_ERROR(ENOTSUP)); | return (SET_ERROR(ENOTSUP)); | ||||
/* 6 extra bytes for /%recv */ | /* | ||||
char recvname[ZFS_MAX_DATASET_NAME_LEN + 6]; | * The receiving code doesn't know how to translate large blocks | ||||
* to smaller ones, so the pool must have the LARGE_BLOCKS | |||||
* feature enabled if the stream has LARGE_BLOCKS. Same with | |||||
* large dnodes. | |||||
*/ | |||||
if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) && | |||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS)) | |||||
return (SET_ERROR(ENOTSUP)); | |||||
if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) && | |||||
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE)) | |||||
return (SET_ERROR(ENOTSUP)); | |||||
(void) snprintf(recvname, sizeof (recvname), "%s/%s", | (void) snprintf(recvname, sizeof (recvname), "%s/%s", | ||||
tofs, recv_clone_name); | tofs, recv_clone_name); | ||||
if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) { | if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) { | ||||
/* %recv does not exist; continue in tofs */ | /* %recv does not exist; continue in tofs */ | ||||
error = dsl_dataset_hold(dp, tofs, FTAG, &ds); | error = dsl_dataset_hold(dp, tofs, FTAG, &ds); | ||||
if (error != 0) | if (error != 0) | ||||
▲ Show 20 Lines • Show All 455 Lines • ▼ Show 20 Lines | if (drro->drr_type == DMU_OT_NONE || | ||||
!DMU_OT_IS_VALID(drro->drr_type) || | !DMU_OT_IS_VALID(drro->drr_type) || | ||||
!DMU_OT_IS_VALID(drro->drr_bonustype) || | !DMU_OT_IS_VALID(drro->drr_bonustype) || | ||||
drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || | drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || | ||||
drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || | drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || | ||||
P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || | P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || | ||||
drro->drr_blksz < SPA_MINBLOCKSIZE || | drro->drr_blksz < SPA_MINBLOCKSIZE || | ||||
drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) || | drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) || | ||||
drro->drr_bonuslen > | drro->drr_bonuslen > | ||||
DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os)))) { | DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os))) || | ||||
drro->drr_dn_slots > | |||||
(spa_maxdnodesize(dmu_objset_spa(rwa->os)) >> DNODE_SHIFT)) { | |||||
return (SET_ERROR(EINVAL)); | return (SET_ERROR(EINVAL)); | ||||
} | } | ||||
err = dmu_object_info(rwa->os, drro->drr_object, &doi); | err = dmu_object_info(rwa->os, drro->drr_object, &doi); | ||||
if (err != 0 && err != ENOENT) | if (err != 0 && err != ENOENT && err != EEXIST) | ||||
return (SET_ERROR(EINVAL)); | return (SET_ERROR(EINVAL)); | ||||
object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT; | |||||
if (drro->drr_object > rwa->max_object) | if (drro->drr_object > rwa->max_object) | ||||
rwa->max_object = drro->drr_object; | rwa->max_object = drro->drr_object; | ||||
/* | /* | ||||
* If we are losing blkptrs or changing the block size this must | * If we are losing blkptrs or changing the block size this must | ||||
* be a new file instance. We must clear out the previous file | * be a new file instance. We must clear out the previous file | ||||
* contents before we can change this type of metadata in the dnode. | * contents before we can change this type of metadata in the dnode. | ||||
*/ | */ | ||||
if (err == 0) { | if (err == 0) { | ||||
int nblkptr; | int nblkptr; | ||||
object = drro->drr_object; | |||||
nblkptr = deduce_nblkptr(drro->drr_bonustype, | nblkptr = deduce_nblkptr(drro->drr_bonustype, | ||||
drro->drr_bonuslen); | drro->drr_bonuslen); | ||||
if (drro->drr_blksz != doi.doi_data_block_size || | if (drro->drr_blksz != doi.doi_data_block_size || | ||||
nblkptr < doi.doi_nblkptr) { | nblkptr < doi.doi_nblkptr || | ||||
drro->drr_dn_slots != doi.doi_dnodesize >> DNODE_SHIFT) { | |||||
err = dmu_free_long_range(rwa->os, drro->drr_object, | err = dmu_free_long_range(rwa->os, drro->drr_object, | ||||
0, DMU_OBJECT_END); | 0, DMU_OBJECT_END); | ||||
if (err != 0) | if (err != 0) | ||||
return (SET_ERROR(EINVAL)); | return (SET_ERROR(EINVAL)); | ||||
} | } | ||||
} else if (err == EEXIST) { | |||||
/* | |||||
* The object requested is currently an interior slot of a | |||||
* multi-slot dnode. This will be resolved when the next txg | |||||
* is synced out, since the send stream will have told us | |||||
* to free this slot when we freed the associated dnode | |||||
* earlier in the stream. | |||||
*/ | |||||
txg_wait_synced(dmu_objset_pool(rwa->os), 0); | |||||
object = drro->drr_object; | |||||
} else { | |||||
/* object is free and we are about to allocate a new one */ | |||||
object = DMU_NEW_OBJECT; | |||||
} | } | ||||
/* | |||||
* If this is a multi-slot dnode there is a chance that this | |||||
* object will expand into a slot that is already used by | |||||
* another object from the previous snapshot. We must free | |||||
* these objects before we attempt to allocate the new dnode. | |||||
*/ | |||||
if (drro->drr_dn_slots > 1) { | |||||
boolean_t need_sync = B_FALSE; | |||||
for (uint64_t slot = drro->drr_object + 1; | |||||
slot < drro->drr_object + drro->drr_dn_slots; | |||||
slot++) { | |||||
dmu_object_info_t slot_doi; | |||||
err = dmu_object_info(rwa->os, slot, &slot_doi); | |||||
if (err == ENOENT || err == EEXIST) | |||||
continue; | |||||
else if (err != 0) | |||||
return (err); | |||||
err = dmu_free_long_object(rwa->os, slot); | |||||
if (err != 0) | |||||
return (err); | |||||
need_sync = B_TRUE; | |||||
} | |||||
if (need_sync) | |||||
txg_wait_synced(dmu_objset_pool(rwa->os), 0); | |||||
} | |||||
tx = dmu_tx_create(rwa->os); | tx = dmu_tx_create(rwa->os); | ||||
dmu_tx_hold_bonus(tx, object); | dmu_tx_hold_bonus(tx, object); | ||||
err = dmu_tx_assign(tx, TXG_WAIT); | err = dmu_tx_assign(tx, TXG_WAIT); | ||||
if (err != 0) { | if (err != 0) { | ||||
dmu_tx_abort(tx); | dmu_tx_abort(tx); | ||||
return (err); | return (err); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) | ||||
return (SET_ERROR(EINVAL)); | return (SET_ERROR(EINVAL)); | ||||
for (obj = drrfo->drr_firstobj == 0 ? 1 : drrfo->drr_firstobj; | for (obj = drrfo->drr_firstobj == 0 ? 1 : drrfo->drr_firstobj; | ||||
obj < drrfo->drr_firstobj + drrfo->drr_numobjs && next_err == 0; | obj < drrfo->drr_firstobj + drrfo->drr_numobjs && next_err == 0; | ||||
next_err = dmu_object_next(rwa->os, &obj, FALSE, 0)) { | next_err = dmu_object_next(rwa->os, &obj, FALSE, 0)) { | ||||
dmu_object_info_t doi; | dmu_object_info_t doi; | ||||
int err; | int err; | ||||
err = dmu_object_info(rwa->os, obj, &doi); | err = dmu_object_info(rwa->os, obj, NULL); | ||||
if (err == ENOENT) { | if (err == ENOENT) { | ||||
obj++; | obj++; | ||||
continue; | continue; | ||||
} else if (err != 0) { | } else if (err != 0) { | ||||
return (err); | return (err); | ||||
} | } | ||||
err = dmu_free_long_object(rwa->os, obj); | err = dmu_free_long_object(rwa->os, obj); | ||||
if (err != 0) | if (err != 0) | ||||
return (err); | return (err); | ||||
▲ Show 20 Lines • Show All 1,182 Lines • Show Last 20 Lines |