aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorRyan Moeller <[email protected]>2020-09-30 16:19:49 -0400
committerGitHub <[email protected]>2020-09-30 13:19:49 -0700
commitc0bd2e0fe206791242d467b6f84789bf08c3a118 (patch)
tree7da4b6764fde98a8b300c0a4c298eb7a2d7e6a96 /module
parent68cdafdbb8c3515328cedd351b471e1bb918bd27 (diff)
Drop references when skipping dmu_send due to EXDEV
When an invalid incremental send is requested where the "to" ds is before the "from" ds, make sure to drop the reference to the pool and the dataset before returning the error. Add an assert on FreeBSD to make sure we don't hold any locks after returning from an ioctl. Add some test coverage. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Ryan Moeller <[email protected]> Closes #10919
Diffstat (limited to 'module')
-rw-r--r--module/os/freebsd/zfs/kmod_core.c4
-rw-r--r--module/zfs/dmu_send.c11
2 files changed, 10 insertions, 5 deletions
diff --git a/module/os/freebsd/zfs/kmod_core.c b/module/os/freebsd/zfs/kmod_core.c
index 4c6961298..3a13271aa 100644
--- a/module/os/freebsd/zfs/kmod_core.c
+++ b/module/os/freebsd/zfs/kmod_core.c
@@ -86,6 +86,7 @@ __FBSDID("$FreeBSD$");
#include <sys/zio_checksum.h>
#include <sys/vdev_removal.h>
#include <sys/dsl_crypt.h>
+#include <sys/zfs_context.h>
#include <sys/zfs_ioctl_compat.h>
#include <sys/zfs_ioctl_impl.h>
@@ -98,7 +99,7 @@ __FBSDID("$FreeBSD$");
SYSCTL_DECL(_vfs_zfs);
SYSCTL_DECL(_vfs_zfs_vdev);
-
+extern uint_t rrw_tsd_key;
static int zfs_version_ioctl = ZFS_IOCVER_OZFS;
SYSCTL_DECL(_vfs_zfs_version);
SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl,
@@ -180,6 +181,7 @@ out:
if (zcl)
kmem_free(zcl, sizeof (zfs_cmd_legacy_t));
kmem_free(zc, sizeof (zfs_cmd_t));
+ MPASS(tsd_get(rrw_tsd_key) == NULL);
return (error);
}
diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c
index 07c2d6ef2..9480c8b75 100644
--- a/module/zfs/dmu_send.c
+++ b/module/zfs/dmu_send.c
@@ -2684,12 +2684,15 @@ dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
bcopy(fromredact, dspp.fromredactsnaps, size);
}
- if (!dsl_dataset_is_before(dspp.to_ds, fromds, 0)) {
+ boolean_t is_before =
+ dsl_dataset_is_before(dspp.to_ds, fromds, 0);
+ dspp.is_clone = (dspp.to_ds->ds_dir !=
+ fromds->ds_dir);
+ dsl_dataset_rele(fromds, FTAG);
+ if (!is_before) {
+ dsl_pool_rele(dspp.dp, FTAG);
err = SET_ERROR(EXDEV);
} else {
- dspp.is_clone = (dspp.to_ds->ds_dir !=
- fromds->ds_dir);
- dsl_dataset_rele(fromds, FTAG);
err = dmu_send_impl(&dspp);
}
} else {