]> granicus.if.org Git - zfs/commitdiff
Fix invalid locking order in rename operation
authorStanislav Seletskiy <s.seletskiy@gmail.com>
Wed, 3 Sep 2014 09:41:10 +0000 (16:41 +0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 4 Sep 2014 16:50:46 +0000 (09:50 -0700)
This commit should prevent a deadlock on dp_config_rwlock when
running `zfs rename` by ensuring zvol_rename_minors() is not
called under this lock.

Signed-off-by: Stanislav Seletskiy <s.seletskiy@gmail.com>
Signed-off-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2652.
Closes #2525.

module/zfs/dsl_dataset.c

index a5594f15c985cbec3d3c015b3325eb6276c7ac07..91d9120a58cabdd3339b322ebe8afee4ce84c997 100644 (file)
@@ -1619,9 +1619,6 @@ static int
 dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
     dsl_dataset_t *hds, void *arg)
 {
-#ifdef _KERNEL
-       char *oldname, *newname;
-#endif
        dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
        dsl_dataset_t *ds;
        uint64_t val;
@@ -1648,18 +1645,6 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
        VERIFY0(zap_add(dp->dp_meta_objset, hds->ds_phys->ds_snapnames_zapobj,
            ds->ds_snapname, 8, 1, &ds->ds_object, tx));
 
-#ifdef _KERNEL
-       oldname = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE);
-       newname = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE);
-       snprintf(oldname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname,
-           ddrsa->ddrsa_oldsnapname);
-       snprintf(newname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname,
-           ddrsa->ddrsa_newsnapname);
-       zvol_rename_minors(oldname, newname);
-       kmem_free(newname, MAXPATHLEN);
-       kmem_free(oldname, MAXPATHLEN);
-#endif
-
        dsl_dataset_rele(ds, FTAG);
        return (0);
 }
@@ -1687,6 +1672,11 @@ int
 dsl_dataset_rename_snapshot(const char *fsname,
     const char *oldsnapname, const char *newsnapname, boolean_t recursive)
 {
+#ifdef _KERNEL
+       char *oldname, *newname;
+#endif
+       int error;
+
        dsl_dataset_rename_snapshot_arg_t ddrsa;
 
        ddrsa.ddrsa_fsname = fsname;
@@ -1694,8 +1684,21 @@ dsl_dataset_rename_snapshot(const char *fsname,
        ddrsa.ddrsa_newsnapname = newsnapname;
        ddrsa.ddrsa_recursive = recursive;
 
-       return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
-           dsl_dataset_rename_snapshot_sync, &ddrsa, 1));
+       error = dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
+           dsl_dataset_rename_snapshot_sync, &ddrsa, 1);
+
+       if (error)
+           return (SET_ERROR(error));
+
+#ifdef _KERNEL
+       oldname = kmem_asprintf("%s@%s", fsname, oldsnapname);
+       newname = kmem_asprintf("%s@%s", fsname, newsnapname);
+       zvol_rename_minors(oldname, newname);
+       strfree(newname);
+       strfree(oldname);
+#endif
+
+       return (0);
 }
 
 /*