mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
OpenZFS 7180 - potential race between zfs_suspend_fs+zfs_resume_fs and zfs_ioc_rename
Authored by: Andriy Gapon <andriy.gapon@clusterhq.com> Reviewed by: Matt Ahrens <mahrens@delphix.com> Reviewed by: Pavel Zakharov <pavel.zakharov@delphix.com> Approved by: Richard Lowe <richlowe@richlowe.net> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Ported-by: George Melikov <mail@gmelikov.ru> OpenZFS-issue: https://www.illumos.org/issues/7180 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/690041b Closes #5627
This commit is contained in:
parent
cffd6e1167
commit
ec923db25c
@ -181,7 +181,7 @@ typedef struct zfid_long {
|
|||||||
extern uint_t zfs_fsyncer_key;
|
extern uint_t zfs_fsyncer_key;
|
||||||
|
|
||||||
extern int zfs_suspend_fs(zfs_sb_t *zsb);
|
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,
|
extern int zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||||
const char *domain, uint64_t rid, uint64_t *valuep);
|
const char *domain, uint64_t rid, uint64_t *valuep);
|
||||||
extern int zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
extern int zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||||
|
@ -3645,12 +3645,15 @@ zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl)
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (get_zfs_sb(fsname, &zsb) == 0) {
|
if (get_zfs_sb(fsname, &zsb) == 0) {
|
||||||
|
dsl_dataset_t *ds;
|
||||||
|
|
||||||
|
ds = dmu_objset_ds(zsb->z_os);
|
||||||
error = zfs_suspend_fs(zsb);
|
error = zfs_suspend_fs(zsb);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
int resume_err;
|
int resume_err;
|
||||||
|
|
||||||
error = dsl_dataset_rollback(fsname, zsb, outnvl);
|
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;
|
error = error ? error : resume_err;
|
||||||
}
|
}
|
||||||
deactivate_super(zsb->z_sb);
|
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) {
|
if (get_zfs_sb(tofs, &zsb) == 0) {
|
||||||
/* online recv */
|
/* online recv */
|
||||||
|
dsl_dataset_t *ds;
|
||||||
int end_err;
|
int end_err;
|
||||||
|
|
||||||
|
ds = dmu_objset_ds(zsb->z_os);
|
||||||
error = zfs_suspend_fs(zsb);
|
error = zfs_suspend_fs(zsb);
|
||||||
/*
|
/*
|
||||||
* If the suspend fails, then the recv_end will
|
* 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);
|
end_err = dmu_recv_end(&drc, zsb);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
error = zfs_resume_fs(zsb, tofs);
|
error = zfs_resume_fs(zsb, ds);
|
||||||
error = error ? error : end_err;
|
error = error ? error : end_err;
|
||||||
deactivate_super(zsb->z_sb);
|
deactivate_super(zsb->z_sb);
|
||||||
} else if ((zv = zvol_suspend(tofs)) != NULL) {
|
} 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 needs to be closed & reopened (to grow the
|
||||||
* objset_phys_t). Suspend/resume the fs will do that.
|
* 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);
|
error = zfs_suspend_fs(zsb);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
dmu_objset_refresh_ownership(zsb->z_os,
|
dmu_objset_refresh_ownership(zsb->z_os,
|
||||||
zsb);
|
zsb);
|
||||||
error = zfs_resume_fs(zsb, zc->zc_name);
|
error = zfs_resume_fs(zsb, ds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
|
@ -1710,7 +1710,7 @@ EXPORT_SYMBOL(zfs_suspend_fs);
|
|||||||
* Reopen zfs_sb_t and release VFS ops.
|
* Reopen zfs_sb_t and release VFS ops.
|
||||||
*/
|
*/
|
||||||
int
|
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;
|
int err, err2;
|
||||||
znode_t *zp;
|
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));
|
ASSERT(RW_WRITE_HELD(&zsb->z_teardown_inactive_lock));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We already own this, so just hold and rele it to update the
|
* We already own this, so just update the objset_t, as the one we
|
||||||
* objset_t, as the one we had before may have been evicted.
|
* had before may have been evicted.
|
||||||
*/
|
*/
|
||||||
VERIFY0(dmu_objset_hold(osname, zsb, &zsb->z_os));
|
VERIFY3P(ds->ds_owner, ==, zsb);
|
||||||
VERIFY3P(zsb->z_os->os_dsl_dataset->ds_owner, ==, zsb);
|
VERIFY(dsl_dataset_long_held(ds));
|
||||||
VERIFY(dsl_dataset_long_held(zsb->z_os->os_dsl_dataset));
|
VERIFY0(dmu_objset_from_ds(ds, &zsb->z_os));
|
||||||
dmu_objset_rele(zsb->z_os, zsb);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure version hasn't changed
|
* Make sure version hasn't changed
|
||||||
|
Loading…
Reference in New Issue
Block a user