diff options
author | Stanislav Seletskiy <[email protected]> | 2014-09-03 16:41:10 +0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2014-09-04 09:50:46 -0700 |
commit | 2078f21015b1f33329849997c9f918e5196806bd (patch) | |
tree | dc847b674adf42ae452e56744869f65b421805a9 | |
parent | 4f6a14798d43e20e50dac015e332328ec3eae36f (diff) |
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 <[email protected]>
Signed-off-by: Richard Yao <[email protected]>
Signed-off-by: Tim Chase <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #2652.
Closes #2525.
-rw-r--r-- | module/zfs/dsl_dataset.c | 37 |
1 files 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); } /* |