diff options
author | George Melikov <[email protected]> | 2017-01-23 21:53:46 +0300 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-01-23 10:53:46 -0800 |
commit | ec923db25c823dd460fdb5db44a5a202a0975f27 (patch) | |
tree | 16fde8482af6d62f45c97586aab2b9ed42b5dbc3 | |
parent | cffd6e116711640d070d9690480b95c5a6de7154 (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.h | 2 | ||||
-rw-r--r-- | module/zfs/zfs_ioctl.c | 14 | ||||
-rw-r--r-- | module/zfs/zfs_vfsops.c | 13 |
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 |