aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Melikov <[email protected]>2017-01-23 21:53:46 +0300
committerBrian Behlendorf <[email protected]>2017-01-23 10:53:46 -0800
commitec923db25c823dd460fdb5db44a5a202a0975f27 (patch)
tree16fde8482af6d62f45c97586aab2b9ed42b5dbc3
parentcffd6e116711640d070d9690480b95c5a6de7154 (diff)
OpenZFS 7180 - potential race between zfs_suspend_fs+zfs_resume_fs and zfs_ioc_rename
Authored by: Andriy Gapon <[email protected]> Reviewed by: Matt Ahrens <[email protected]> Reviewed by: Pavel Zakharov <[email protected]> Approved by: Richard Lowe <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Ported-by: George Melikov <[email protected]> OpenZFS-issue: https://www.illumos.org/issues/7180 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/690041b Closes #5627
-rw-r--r--include/sys/zfs_vfsops.h2
-rw-r--r--module/zfs/zfs_ioctl.c14
-rw-r--r--module/zfs/zfs_vfsops.c13
3 files changed, 18 insertions, 11 deletions
diff --git a/include/sys/zfs_vfsops.h b/include/sys/zfs_vfsops.h
index b59ace5b1..870eb9727 100644
--- a/include/sys/zfs_vfsops.h
+++ b/include/sys/zfs_vfsops.h
@@ -181,7 +181,7 @@ typedef struct zfid_long {
extern uint_t zfs_fsyncer_key;
extern int zfs_suspend_fs(zfs_sb_t *zsb);
-extern int zfs_resume_fs(zfs_sb_t *zsb, const char *osname);
+extern int zfs_resume_fs(zfs_sb_t *zsb, struct dsl_dataset *ds);
extern int zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
const char *domain, uint64_t rid, uint64_t *valuep);
extern int zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index 659345917..8ae4300f5 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -3645,12 +3645,15 @@ zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl)
int error;
if (get_zfs_sb(fsname, &zsb) == 0) {
+ dsl_dataset_t *ds;
+
+ ds = dmu_objset_ds(zsb->z_os);
error = zfs_suspend_fs(zsb);
if (error == 0) {
int resume_err;
error = dsl_dataset_rollback(fsname, zsb, outnvl);
- resume_err = zfs_resume_fs(zsb, fsname);
+ resume_err = zfs_resume_fs(zsb, ds);
error = error ? error : resume_err;
}
deactivate_super(zsb->z_sb);
@@ -4248,8 +4251,10 @@ zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin,
if (get_zfs_sb(tofs, &zsb) == 0) {
/* online recv */
+ dsl_dataset_t *ds;
int end_err;
+ ds = dmu_objset_ds(zsb->z_os);
error = zfs_suspend_fs(zsb);
/*
* If the suspend fails, then the recv_end will
@@ -4257,7 +4262,7 @@ zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin,
*/
end_err = dmu_recv_end(&drc, zsb);
if (error == 0)
- error = zfs_resume_fs(zsb, tofs);
+ error = zfs_resume_fs(zsb, ds);
error = error ? error : end_err;
deactivate_super(zsb->z_sb);
} else if ((zv = zvol_suspend(tofs)) != NULL) {
@@ -4944,11 +4949,14 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
* objset needs to be closed & reopened (to grow the
* objset_phys_t). Suspend/resume the fs will do that.
*/
+ dsl_dataset_t *ds;
+
+ ds = dmu_objset_ds(zsb->z_os);
error = zfs_suspend_fs(zsb);
if (error == 0) {
dmu_objset_refresh_ownership(zsb->z_os,
zsb);
- error = zfs_resume_fs(zsb, zc->zc_name);
+ error = zfs_resume_fs(zsb, ds);
}
}
if (error == 0)
diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c
index 65efcdce5..20ff165d9 100644
--- a/module/zfs/zfs_vfsops.c
+++ b/module/zfs/zfs_vfsops.c
@@ -1710,7 +1710,7 @@ EXPORT_SYMBOL(zfs_suspend_fs);
* Reopen zfs_sb_t and release VFS ops.
*/
int
-zfs_resume_fs(zfs_sb_t *zsb, const char *osname)
+zfs_resume_fs(zfs_sb_t *zsb, dsl_dataset_t *ds)
{
int err, err2;
znode_t *zp;
@@ -1720,13 +1720,12 @@ zfs_resume_fs(zfs_sb_t *zsb, const char *osname)
ASSERT(RW_WRITE_HELD(&zsb->z_teardown_inactive_lock));
/*
- * We already own this, so just hold and rele it to update the
- * objset_t, as the one we had before may have been evicted.
+ * We already own this, so just update the objset_t, as the one we
+ * had before may have been evicted.
*/
- VERIFY0(dmu_objset_hold(osname, zsb, &zsb->z_os));
- VERIFY3P(zsb->z_os->os_dsl_dataset->ds_owner, ==, zsb);
- VERIFY(dsl_dataset_long_held(zsb->z_os->os_dsl_dataset));
- dmu_objset_rele(zsb->z_os, zsb);
+ VERIFY3P(ds->ds_owner, ==, zsb);
+ VERIFY(dsl_dataset_long_held(ds));
+ VERIFY0(dmu_objset_from_ds(ds, &zsb->z_os));
/*
* Make sure version hasn't changed