Skip to content

Commit

Permalink
zfsonlinux issue openzfs#3681 - lock order inversion between zvol_ope…
Browse files Browse the repository at this point in the history
…n() and

dsl_pool_sync()...zvol_rename_minors()

Execute zvol_*_minor(s) functions asynchronously in taskqs (one
taskq per pool) in order to avoid having to deal with the locking
state of the caller.
  • Loading branch information
bprotopopov committed Sep 23, 2015
1 parent c3d285f commit e390e94
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 28 deletions.
31 changes: 26 additions & 5 deletions include/sys/zvol.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,41 @@
#define ZVOL_OBJ 1ULL
#define ZVOL_ZAP_OBJ 2ULL

typedef enum {
ZVOL_ASYNC_CREATE_TASKQ,
ZVOL_ASYNC_REMOVE_TASKQ,
ZVOL_ASYNC_CREATE_MINORS,
ZVOL_ASYNC_REMOVE_MINORS,
ZVOL_ASYNC_REMOVE_MINOR,
ZVOL_ASYNC_RENAME_MINORS,
ZVOL_ASYNC_SET_SNAPDEV,
ZVOL_ASYNC_MAX
} zvol_async_op_t;

typedef struct {
zvol_async_op_t op;
char pool[MAXNAMELEN];
char name1[MAXNAMELEN];
char name2[MAXNAMELEN];
uint64_t value;
} zvol_async_arg_t;

#ifdef _KERNEL

extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize);
extern int zvol_check_volblocksize(const char *name, uint64_t volblocksize);
extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
extern boolean_t zvol_is_zvol(const char *);
extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
extern int zvol_create_minors(const char *name);
extern int zvol_remove_minor(const char *name);
extern void zvol_remove_minors(const char *name);
extern void zvol_rename_minors(const char *oldname, const char *newname);
extern void zvol_async_create_taskq(const char *pool);
extern void zvol_async_remove_taskq(const char *pool);
extern void zvol_async_create_minors(const char *name);
extern void zvol_async_remove_minor(const char *name);
extern void zvol_async_remove_minors(const char *name);
extern void zvol_async_rename_minors(const char *oldname, const char *newname);
extern int zvol_async_set_snapdev(const char *, uint64_t);
extern int zvol_set_volsize(const char *, uint64_t);
extern int zvol_set_volblocksize(const char *, uint64_t);
extern int zvol_set_snapdev(const char *, uint64_t);

extern int zvol_init(void);
extern void zvol_fini(void);
Expand Down
4 changes: 2 additions & 2 deletions module/zfs/dsl_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1455,7 +1455,7 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) {
char *snapname = nvpair_name(pair);
zvol_create_minors(snapname);
zvol_async_create_minors(snapname);
}
}
#endif
Expand Down Expand Up @@ -1920,7 +1920,7 @@ dsl_dataset_rename_snapshot(const char *fsname,
#ifdef _KERNEL
oldname = kmem_asprintf("%s@%s", fsname, oldsnapname);
newname = kmem_asprintf("%s@%s", fsname, newsnapname);
zvol_rename_minors(oldname, newname);
zvol_async_rename_minors(oldname, newname);
strfree(newname);
strfree(oldname);
#endif
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/dsl_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1914,7 +1914,7 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
dd->dd_myname, 8, 1, &dd->dd_object, tx));

#ifdef _KERNEL
zvol_rename_minors(ddra->ddra_oldname, ddra->ddra_newname);
zvol_async_rename_minors(ddra->ddra_oldname, ddra->ddra_newname);
#endif

dsl_prop_notify_all(dd);
Expand Down
10 changes: 7 additions & 3 deletions module/zfs/spa.c
Original file line number Diff line number Diff line change
Expand Up @@ -3084,8 +3084,11 @@ spa_open_common(const char *pool, spa_t **spapp, void *tag, nvlist_t *nvpolicy,
}

#ifdef _KERNEL
if (firstopen)
zvol_create_minors(spa->spa_name);
if (firstopen) {
char *name = spa_name(spa);
zvol_async_create_taskq(name);
zvol_async_create_minors(name);
}
#endif

*spapp = spa;
Expand Down Expand Up @@ -4208,7 +4211,8 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
spa_history_log_version(spa, "import");

#ifdef _KERNEL
zvol_create_minors(pool);
zvol_async_create_taskq(pool);
zvol_async_create_minors(pool);
#endif

return (0);
Expand Down
31 changes: 21 additions & 10 deletions module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,12 @@ zfs_ioc_pool_create(zfs_cmd_t *zc)
ZPROP_SRC_LOCAL, rootprops, NULL)) != 0)
(void) spa_destroy(zc->zc_name);

/*
* Create a taskq for asynchronous zvol-related work in this pool
*/
if (!error)
zvol_async_create_taskq(zc->zc_name);

pool_props_bad:
nvlist_free(rootprops);
nvlist_free(zplprops);
Expand All @@ -1500,8 +1506,10 @@ zfs_ioc_pool_destroy(zfs_cmd_t *zc)
int error;
zfs_log_history(zc);
error = spa_destroy(zc->zc_name);
if (error == 0)
zvol_remove_minors(zc->zc_name);
if (error == 0) {
zvol_async_remove_minors(zc->zc_name);
zvol_async_remove_taskq(zc->zc_name);
}
return (error);
}

Expand Down Expand Up @@ -1553,8 +1561,10 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)

zfs_log_history(zc);
error = spa_export(zc->zc_name, NULL, force, hardforce);
if (error == 0)
zvol_remove_minors(zc->zc_name);
if (error == 0) {
zvol_async_remove_minors(zc->zc_name);
zvol_async_remove_taskq(zc->zc_name);
}
return (error);
}

Expand Down Expand Up @@ -2395,7 +2405,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
err = zvol_set_volsize(dsname, intval);
break;
case ZFS_PROP_SNAPDEV:
err = zvol_set_snapdev(dsname, intval);
err = zvol_async_set_snapdev(dsname, intval);
break;
case ZFS_PROP_VERSION:
{
Expand Down Expand Up @@ -3192,7 +3202,7 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)

#ifdef _KERNEL
if (error == 0 && type == DMU_OST_ZVOL)
zvol_create_minors(fsname);
zvol_async_create_minors(fsname);
#endif

return (error);
Expand Down Expand Up @@ -3240,7 +3250,7 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)

#ifdef _KERNEL
if (error == 0)
zvol_create_minors(fsname);
zvol_async_create_minors(fsname);
#endif

return (error);
Expand Down Expand Up @@ -3430,7 +3440,7 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) {
(void) zfs_unmount_snap(nvpair_name(pair));
(void) zvol_remove_minor(nvpair_name(pair));
(void) zvol_async_remove_minor(nvpair_name(pair));
}

return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
Expand Down Expand Up @@ -3557,7 +3567,8 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
else
err = dsl_destroy_head(zc->zc_name);
if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0)
(void) zvol_remove_minor(zc->zc_name);
(void) zvol_async_remove_minor(zc->zc_name);

return (err);
}

Expand Down Expand Up @@ -4125,7 +4136,7 @@ zfs_ioc_recv(zfs_cmd_t *zc)

#ifdef _KERNEL
if (error == 0)
zvol_create_minors(tofs);
(void) zvol_async_create_minors(tofs);
#endif

/*
Expand Down
Loading

0 comments on commit e390e94

Please sign in to comment.