]> granicus.if.org Git - zfs/commitdiff
OpenZFS 7180 - potential race between zfs_suspend_fs+zfs_resume_fs and zfs_ioc_rename
authorGeorge Melikov <mail@gmelikov.ru>
Mon, 23 Jan 2017 18:53:46 +0000 (21:53 +0300)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 23 Jan 2017 18:53:46 +0000 (10:53 -0800)
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

include/sys/zfs_vfsops.h
module/zfs/zfs_ioctl.c
module/zfs/zfs_vfsops.c

index b59ace5b1996b151ee06ea0e4ad7b0384d8e1ee9..870eb97270b90e537180cc7a45e4ac860ba38f2c 100644 (file)
@@ -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,
index 659345917f8cf3c5c9c381e98ba0f9c9d35d725f..8ae4300f5d8884a00737cdca38c99082d4afd45b 100644 (file)
@@ -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)
index 65efcdce5c59583ca60d948d7edddadca0e07b36..20ff165d94f95eaf1624de59a2c8b068b9039664 100644 (file)
@@ -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