From 2078f21015b1f33329849997c9f918e5196806bd Mon Sep 17 00:00:00 2001 From: Stanislav Seletskiy Date: Wed, 3 Sep 2014 16:41:10 +0700 Subject: [PATCH] Fix invalid locking order in rename operation 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 Signed-off-by: Richard Yao Signed-off-by: Tim Chase Signed-off-by: Brian Behlendorf Closes #2652. Closes #2525. --- module/zfs/dsl_dataset.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index a5594f15c..91d9120a5 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -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); } /*