From 5b9afc16cfacb5ec5aa851a8531bf65d9bd7318a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20F=C3=BCl=C3=B6p?= Date: Fri, 28 Oct 2022 19:12:01 +0200 Subject: [PATCH 1/2] Fix `zfs send -v` failing to send from filesystem or volume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- include/sys/dmu_send.h | 2 +- module/zfs/dmu_send.c | 29 +++++++++++++++++++++++++---- module/zfs/zfs_ioctl.c | 4 ++-- 3 files changed, 28 insertions(+), 7 deletions(-) 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 6e0057bb9e..dd55855dfd 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -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); } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index a5168b9375..b83a336594 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -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); From 9fd014d8b07e166a9c1449512bb9316c8a8068e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20F=C3=BCl=C3=B6p?= Date: Fri, 28 Oct 2022 20:12:13 +0200 Subject: [PATCH 2/2] fix arg; style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Fülöp --- module/zfs/dmu_send.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index dd55855dfd..215b0a26dd 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -3001,7 +3001,7 @@ 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 compressok, boolean_t rawok, + zfs_bookmark_phys_t *frombook, boolean_t compressok, boolean_t rawok, boolean_t saved, uint64_t *sizep) { int err; @@ -3109,7 +3109,7 @@ out: dsl_dataset_rele(ds, FTAG); if (owned == B_TRUE) - dsl_dataset_disown(ds->ds_dir->dd_pool, dsflags, FTAG); + dsl_dataset_disown(ds, dsflags, FTAG); return (err); }