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 <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.
This commit is contained in:
Stanislav Seletskiy 2014-09-03 16:41:10 +07:00 committed by Brian Behlendorf
parent 4f6a14798d
commit 2078f21015

View 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);
}
/*