diff --git a/include/sys/dmu_send.h b/include/sys/dmu_send.h index 061b81532f..75d8568eb5 100644 --- a/include/sys/dmu_send.h +++ b/include/sys/dmu_send.h @@ -54,7 +54,7 @@ dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok, const char *redactbook, int outfd, offset_t *off, struct dmu_send_outparams *dsop); int dmu_send_estimate_fast(struct dsl_dataset *ds, struct dsl_dataset *fromds, - zfs_bookmark_phys_t *frombook, boolean_t stream_compressed, + zfs_bookmark_phys_t *frombook, boolean_t compressok, boolean_t rawok, boolean_t saved, uint64_t *sizep); int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, boolean_t embedok, boolean_t large_block_ok, boolean_t compressok, diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index cb2b62fed3..5197a89f3e 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -3009,16 +3009,21 @@ dmu_adjust_send_estimate_for_indirects(dsl_dataset_t *ds, uint64_t uncompressed, int dmu_send_estimate_fast(dsl_dataset_t *origds, dsl_dataset_t *fromds, - zfs_bookmark_phys_t *frombook, boolean_t stream_compressed, + zfs_bookmark_phys_t *frombook, boolean_t compressok, boolean_t rawok, boolean_t saved, uint64_t *sizep) { int err; dsl_dataset_t *ds = origds; + ds_hold_flags_t dsflags; uint64_t uncomp, comp; + boolean_t owned = B_FALSE; + boolean_t stream_compressed = compressok || rawok; ASSERT(dsl_pool_config_held(origds->ds_dir->dd_pool)); ASSERT(fromds == NULL || frombook == NULL); + dsflags = (rawok) ? DS_HOLD_FLAG_NONE : DS_HOLD_FLAG_DECRYPT; + /* * If this is a saved send we may actually be sending * from the %recv clone used for resuming. @@ -3056,10 +3061,22 @@ dmu_send_estimate_fast(dsl_dataset_t *origds, dsl_dataset_t *fromds, } } - /* tosnap must be a snapshot or the target of a saved send */ - if (!ds->ds_is_snapshot && ds == origds) - return (SET_ERROR(EINVAL)); + /* + * If we are sending a filesystem or volume, ensure + * that it doesn't change by owning the dataset. + */ + if (!ds->ds_is_snapshot && ds == origds) { + char dsname[ZFS_MAX_DATASET_NAME_LEN]; + dsl_dataset_name(ds, dsname); + err = dsl_dataset_own(ds->ds_dir->dd_pool, dsname, dsflags, + FTAG, &ds); + + if (err != 0) + return (err); + + owned = B_TRUE; + } if (fromds != NULL) { uint64_t used; if (!fromds->ds_is_snapshot) { @@ -3097,6 +3114,10 @@ dmu_send_estimate_fast(dsl_dataset_t *origds, dsl_dataset_t *fromds, out: if (ds != origds) dsl_dataset_rele(ds, FTAG); + + if (owned == B_TRUE) + dsl_dataset_disown(ds, dsflags, FTAG); + return (err); } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 7b527eb75e..9241abc8b9 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5678,7 +5678,7 @@ zfs_ioc_send(zfs_cmd_t *zc) } error = dmu_send_estimate_fast(tosnap, fromsnap, NULL, - compressok || rawok, savedok, &zc->zc_objset_type); + compressok, rawok, savedok, &zc->zc_objset_type); if (fromsnap != NULL) dsl_dataset_rele(fromsnap, FTAG); @@ -6849,7 +6849,7 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) } else { error = dmu_send_estimate_fast(tosnap, fromsnap, (from && strchr(fromname, '#') != NULL ? &zbm : NULL), - compressok || rawok, savedok, &space); + compressok, rawok, savedok, &space); space -= resume_bytes; if (fromsnap != NULL) dsl_dataset_rele(fromsnap, FTAG);