Fix `zfs send -v` failing to send from filesystem or volume
Sends from filesystems or volumes (as opposed to snapshots) with the verbose flag set currently fail with an 'Invalid argument' error. This is caused by `dmu_send_estimate_fast()` failing to handle non-snapshot sends properly. Fix it by owning the dataset while we are estimating the send size. Signed-off-by: Attila Fülöp <attila@fueloep.org>
This commit is contained in:
parent
0b2428da20
commit
5b9afc16cf
|
@ -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,
|
||||
|
|
|
@ -3001,16 +3001,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.
|
||||
|
@ -3049,10 +3054,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) {
|
||||
|
@ -3090,6 +3107,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->ds_dir->dd_pool, dsflags, FTAG);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
|
|
|
@ -5573,7 +5573,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);
|
||||
|
@ -6751,7 +6751,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);
|
||||
|
|
Loading…
Reference in New Issue