Skip to content

Commit

Permalink
rewise implementation of zvol_set_snapdev_sync() to skip everything b…
Browse files Browse the repository at this point in the history
…ut snapshots instead of using zvol_create/destroy_minors()
  • Loading branch information
bprotopopov committed Feb 23, 2016
1 parent ad7395c commit 418852a
Showing 1 changed file with 139 additions and 68 deletions.
207 changes: 139 additions & 68 deletions module/zfs/zvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ typedef enum {
ZVOL_ASYNC_CREATE_MINORS,
ZVOL_ASYNC_REMOVE_MINORS,
ZVOL_ASYNC_RENAME_MINORS,
ZVOL_ASYNC_SET_SNAPDEV,
ZVOL_ASYNC_MAX
} zvol_async_op_t;

Expand All @@ -95,6 +96,8 @@ typedef struct {
char pool[MAXNAMELEN];
char name1[MAXNAMELEN];
char name2[MAXNAMELEN];
zprop_source_t source;
uint64_t snapdev;
} zvol_task_t;

#define ZVOL_RDONLY 0x1
Expand Down Expand Up @@ -1641,6 +1644,36 @@ zvol_remove_minors_impl(const char *name)
mutex_exit(&zvol_state_lock);
}

/* Remove minor for this specific snapshot only */
static void
zvol_remove_minor_impl(const char *name)
{
zvol_state_t *zv, *zv_next;

if (zvol_inhibit_dev)
return;

if (strchr(name, '@') == NULL)
return;

mutex_enter(&zvol_state_lock);

for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
zv_next = list_next(&zvol_state_list, zv);

if (strcmp(zv->zv_name, name) == 0) {
/* If in use, leave alone */
if (zv->zv_open_count > 0)
continue;
zvol_remove(zv);
zvol_free(zv);
break;
}
}

mutex_exit(&zvol_state_lock);
}

/*
* Rename minors for specified dataset including children and snapshots.
*/
Expand Down Expand Up @@ -1684,6 +1717,102 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
kmem_free(name, MAXNAMELEN);
}

typedef struct zvol_snapdev_cb_arg {
uint64_t snapdev;
} zvol_snapdev_cb_arg_t;


static int
zvol_set_snapdev_cb(const char *dsname, void *param) {
zvol_snapdev_cb_arg_t *arg = param;

if (strchr(dsname, '@') == NULL)
return (0);

switch (arg->snapdev) {
case ZFS_SNAPDEV_VISIBLE:
(void) zvol_create_minor_impl(dsname);
break;
case ZFS_SNAPDEV_HIDDEN:
(void) zvol_remove_minor_impl(dsname);
break;
}

return (0);
}

static void
zvol_set_snapdev_impl(char *name, uint64_t snapdev)
{
zvol_snapdev_cb_arg_t arg = {snapdev};
fstrans_cookie_t cookie = spl_fstrans_mark();
/*
* The zvol_set_snapdev_sync() sets snapdev appropriately
* in the dataset hierarchy. Here, we only scan snapshots.
*/
dmu_objset_find(name, zvol_set_snapdev_cb, &arg, DS_FIND_SNAPSHOTS);
spl_fstrans_unmark(cookie);
}

static zvol_task_t *
zvol_task_alloc(zvol_async_op_t op, const char *name1, const char *name2,
uint64_t snapdev)
{
zvol_task_t *task;
char *delim;

/* Never allow tasks on hidden names. */
if (name1[0] == '$')
return (NULL);

task = kmem_zalloc(sizeof (zvol_task_t), KM_SLEEP);
task->op = op;
task->snapdev = snapdev;
delim = strchr(name1, '/');
strlcpy(task->pool, name1, delim ? (delim - name1 + 1) : MAXNAMELEN);

strlcpy(task->name1, name1, MAXNAMELEN);
if (name2 != NULL)
strlcpy(task->name2, name2, MAXNAMELEN);

return (task);
}

static void
zvol_task_free(zvol_task_t *task)
{
kmem_free(task, sizeof (zvol_task_t));
}

/*
* The worker thread function performed asynchronously.
*/
static void
zvol_task_cb(void *param)
{
zvol_task_t *task = (zvol_task_t *)param;

switch (task->op) {
case ZVOL_ASYNC_CREATE_MINORS:
(void) zvol_create_minors_impl(task->name1);
break;
case ZVOL_ASYNC_REMOVE_MINORS:
zvol_remove_minors_impl(task->name1);
break;
case ZVOL_ASYNC_RENAME_MINORS:
zvol_rename_minors_impl(task->name1, task->name2);
break;
case ZVOL_ASYNC_SET_SNAPDEV:
zvol_set_snapdev_impl(task->name1, task->snapdev);
break;
default:
VERIFY(0);
break;
}

zvol_task_free(task);
}

typedef struct zvol_set_snapdev_arg {
const char *zsda_name;
uint64_t zsda_value;
Expand Down Expand Up @@ -1717,24 +1846,20 @@ zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
zvol_set_snapdev_arg_t *zsda = arg;
char dsname[MAXNAMELEN];
zvol_task_t *task;

dsl_dataset_name(ds, dsname);
dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_SNAPDEV),
zsda->zsda_source, sizeof (zsda->zsda_value), 1,
&zsda->zsda_value, zsda->zsda_tx);

switch (zsda->zsda_value) {
case ZFS_SNAPDEV_VISIBLE:
zvol_create_minors(dp->dp_spa, dsname, B_TRUE);
break;
case ZFS_SNAPDEV_HIDDEN:
zvol_remove_minors(dp->dp_spa, dsname, B_TRUE);
zvol_create_minors(dp->dp_spa, dsname, B_TRUE);
break;
default:
break;
}
task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname,
NULL, zsda->zsda_value);
if (task == NULL)
return (0);

(void) taskq_dispatch(dp->dp_spa->spa_zvol_taskq, zvol_task_cb,
task, TQ_SLEEP);
return (0);
}

Expand Down Expand Up @@ -1770,67 +1895,13 @@ zvol_set_snapdev(const char *ddname, zprop_source_t source, uint64_t snapdev)
zvol_set_snapdev_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE));
}

static zvol_task_t *
zvol_task_alloc(zvol_async_op_t op, const char *name1, const char *name2)
{
zvol_task_t *task;
char *delim;

/* Never allow tasks on hidden names. */
if (name1[0] == '$')
return (NULL);

task = kmem_zalloc(sizeof (zvol_task_t), KM_SLEEP);
task->op = op;
delim = strchr(name1, '/');
strlcpy(task->pool, name1, delim ? (delim - name1 + 1) : MAXNAMELEN);

strlcpy(task->name1, name1, MAXNAMELEN);
if (name2 != NULL)
strlcpy(task->name2, name2, MAXNAMELEN);

return (task);
}

static void
zvol_task_free(zvol_task_t *task)
{
kmem_free(task, sizeof (zvol_task_t));
}

/*
* The worker thread function performed asynchronously.
*/
static void
zvol_task_cb(void *param)
{
zvol_task_t *task = (zvol_task_t *)param;

switch (task->op) {
case ZVOL_ASYNC_CREATE_MINORS:
(void) zvol_create_minors_impl(task->name1);
break;
case ZVOL_ASYNC_REMOVE_MINORS:
zvol_remove_minors_impl(task->name1);
break;
case ZVOL_ASYNC_RENAME_MINORS:
zvol_rename_minors_impl(task->name1, task->name2);
break;
default:
VERIFY(0);
break;
}

zvol_task_free(task);
}

void
zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
{
zvol_task_t *task;
taskqid_t id;

task = zvol_task_alloc(ZVOL_ASYNC_CREATE_MINORS, name, NULL);
task = zvol_task_alloc(ZVOL_ASYNC_CREATE_MINORS, name, NULL, ~0ULL);
if (task == NULL)
return;

Expand All @@ -1845,7 +1916,7 @@ zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
zvol_task_t *task;
taskqid_t id;

task = zvol_task_alloc(ZVOL_ASYNC_REMOVE_MINORS, name, NULL);
task = zvol_task_alloc(ZVOL_ASYNC_REMOVE_MINORS, name, NULL, ~0ULL);
if (task == NULL)
return;

Expand All @@ -1861,7 +1932,7 @@ zvol_rename_minors(spa_t *spa, const char *name1, const char *name2,
zvol_task_t *task;
taskqid_t id;

task = zvol_task_alloc(ZVOL_ASYNC_RENAME_MINORS, name1, name2);
task = zvol_task_alloc(ZVOL_ASYNC_RENAME_MINORS, name1, name2, ~0ULL);
if (task == NULL)
return;

Expand Down

0 comments on commit 418852a

Please sign in to comment.