Skip to content

Commit a0bd735

Browse files
bprotopopovbehlendorf
authored andcommitted
Add support for asynchronous zvol minor operations
zfsonlinux issue #2217 - zvol minor operations: check snapdev property before traversing snapshots of a dataset zfsonlinux issue #3681 - lock order inversion between zvol_open() and dsl_pool_sync()...zvol_rename_minors() Create a per-pool zvol taskq for asynchronous zvol tasks. There are a few key design decisions to be aware of. * Each taskq must be single threaded to ensure tasks are always processed in the order in which they were dispatched. * There is a taskq per-pool in order to keep the pools independent. This way if one pool is suspended it will not impact another. * The preferred location to dispatch a zvol minor task is a sync task. In this context there is easy access to the spa_t and minimal error handling is required because the sync task must succeed. Support for asynchronous zvol minor operations address issue #3681. Signed-off-by: Boris Protopopov <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #2217 Closes #3678 Closes #3681
1 parent eb08567 commit a0bd735

File tree

12 files changed

+482
-214
lines changed

12 files changed

+482
-214
lines changed

include/sys/spa_impl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
2424
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
2525
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
26+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2627
*/
2728

2829
#ifndef _SYS_SPA_IMPL_H
@@ -253,6 +254,7 @@ struct spa {
253254
uint64_t spa_errata; /* errata issues detected */
254255
spa_stats_t spa_stats; /* assorted spa statistics */
255256
hrtime_t spa_ccw_fail_time; /* Conf cache write fail time */
257+
taskq_t *spa_zvol_taskq; /* Taskq for minor managment */
256258

257259
/*
258260
* spa_refcount & spa_config_lock must be the last elements

include/sys/zvol.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
/*
2323
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2425
*/
2526

2627
#ifndef _SYS_ZVOL_H
@@ -31,24 +32,22 @@
3132
#define ZVOL_OBJ 1ULL
3233
#define ZVOL_ZAP_OBJ 2ULL
3334

34-
#ifdef _KERNEL
35+
extern void zvol_create_minors(spa_t *spa, const char *name, boolean_t async);
36+
extern void zvol_remove_minors(spa_t *spa, const char *name, boolean_t async);
37+
extern void zvol_rename_minors(spa_t *spa, const char *oldname,
38+
const char *newname, boolean_t async);
3539

40+
#ifdef _KERNEL
3641
extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize);
3742
extern int zvol_check_volblocksize(const char *name, uint64_t volblocksize);
3843
extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
3944
extern boolean_t zvol_is_zvol(const char *);
4045
extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
41-
extern int zvol_create_minor(const char *name);
42-
extern int zvol_create_minors(const char *name);
43-
extern int zvol_remove_minor(const char *name);
44-
extern void zvol_remove_minors(const char *name);
45-
extern void zvol_rename_minors(const char *oldname, const char *newname);
4646
extern int zvol_set_volsize(const char *, uint64_t);
4747
extern int zvol_set_volblocksize(const char *, uint64_t);
48-
extern int zvol_set_snapdev(const char *, uint64_t);
48+
extern int zvol_set_snapdev(const char *, zprop_source_t, uint64_t);
4949

5050
extern int zvol_init(void);
5151
extern void zvol_fini(void);
52-
5352
#endif /* _KERNEL */
5453
#endif /* _SYS_ZVOL_H */

lib/libzpool/kernel.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
/*
2222
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2324
*/
2425

2526
#include <assert.h>
@@ -1354,3 +1355,24 @@ spl_fstrans_check(void)
13541355
{
13551356
return (0);
13561357
}
1358+
1359+
void
1360+
zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
1361+
{
1362+
}
1363+
1364+
void
1365+
zvol_remove_minor(spa_t *spa, const char *name, boolean_t async)
1366+
{
1367+
}
1368+
1369+
void
1370+
zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
1371+
{
1372+
}
1373+
1374+
void
1375+
zvol_rename_minors(spa_t *spa, const char *oldname, const char *newname,
1376+
boolean_t async)
1377+
{
1378+
}

module/zfs/dmu_objset.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
2727
* Copyright (c) 2015 Nexenta Systems, Inc. All rights reserved.
2828
* Copyright (c) 2015, STRATO AG, Inc. All rights reserved.
29+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2930
*/
3031

3132
/* Portions Copyright 2010 Robert Milkowski */
@@ -868,6 +869,8 @@ dmu_objset_create_sync(void *arg, dmu_tx_t *tx)
868869
}
869870

870871
spa_history_log_internal_ds(ds, "create", tx, "");
872+
zvol_create_minors(dp->dp_spa, doca->doca_name, B_TRUE);
873+
871874
dsl_dataset_rele(ds, FTAG);
872875
dsl_dir_rele(pdd, FTAG);
873876
}
@@ -961,6 +964,7 @@ dmu_objset_clone_sync(void *arg, dmu_tx_t *tx)
961964
dsl_dataset_name(origin, namebuf);
962965
spa_history_log_internal_ds(ds, "clone", tx,
963966
"origin=%s (%llu)", namebuf, origin->ds_object);
967+
zvol_create_minors(dp->dp_spa, doca->doca_clone, B_TRUE);
964968
dsl_dataset_rele(ds, FTAG);
965969
dsl_dataset_rele(origin, FTAG);
966970
dsl_dir_rele(pdd, FTAG);

module/zfs/dmu_send.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
2525
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
2626
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
27+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2728
*/
2829

2930
#include <sys/dmu.h>
@@ -54,6 +55,7 @@
5455
#include <sys/dsl_bookmark.h>
5556
#include <sys/zfeature.h>
5657
#include <sys/bqueue.h>
58+
#include <sys/zvol.h>
5759

5860
/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
5961
int zfs_send_corrupt_data = B_FALSE;
@@ -2646,6 +2648,7 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
26462648
dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
26472649
}
26482650
drc->drc_newsnapobj = dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
2651+
zvol_create_minors(dp->dp_spa, drc->drc_tofs, B_TRUE);
26492652
/*
26502653
* Release the hold from dmu_recv_begin. This must be done before
26512654
* we return to open context, so that when we free the dataset's dnode,

module/zfs/dsl_dataset.c

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
2525
* Copyright (c) 2014 RackTop Systems.
2626
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
27+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2728
*/
2829

2930
#include <sys/dmu_objset.h>
@@ -1424,6 +1425,7 @@ dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
14241425
dsl_props_set_sync_impl(ds->ds_prev,
14251426
ZPROP_SRC_LOCAL, ddsa->ddsa_props, tx);
14261427
}
1428+
zvol_create_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
14271429
dsl_dataset_rele(ds, FTAG);
14281430
}
14291431
}
@@ -1498,16 +1500,6 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
14981500
fnvlist_free(suspended);
14991501
}
15001502

1501-
#ifdef _KERNEL
1502-
if (error == 0) {
1503-
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
1504-
pair = nvlist_next_nvpair(snaps, pair)) {
1505-
char *snapname = nvpair_name(pair);
1506-
zvol_create_minors(snapname);
1507-
}
1508-
}
1509-
#endif
1510-
15111503
return (error);
15121504
}
15131505

@@ -1930,6 +1922,8 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
19301922
VERIFY0(zap_add(dp->dp_meta_objset,
19311923
dsl_dataset_phys(hds)->ds_snapnames_zapobj,
19321924
ds->ds_snapname, 8, 1, &ds->ds_object, tx));
1925+
zvol_rename_minors(dp->dp_spa, ddrsa->ddrsa_oldsnapname,
1926+
ddrsa->ddrsa_newsnapname, B_TRUE);
19331927

19341928
dsl_dataset_rele(ds, FTAG);
19351929
return (0);
@@ -1958,34 +1952,16 @@ int
19581952
dsl_dataset_rename_snapshot(const char *fsname,
19591953
const char *oldsnapname, const char *newsnapname, boolean_t recursive)
19601954
{
1961-
#ifdef _KERNEL
1962-
char *oldname, *newname;
1963-
#endif
1964-
int error;
1965-
19661955
dsl_dataset_rename_snapshot_arg_t ddrsa;
19671956

19681957
ddrsa.ddrsa_fsname = fsname;
19691958
ddrsa.ddrsa_oldsnapname = oldsnapname;
19701959
ddrsa.ddrsa_newsnapname = newsnapname;
19711960
ddrsa.ddrsa_recursive = recursive;
19721961

1973-
error = dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
1962+
return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
19741963
dsl_dataset_rename_snapshot_sync, &ddrsa,
1975-
1, ZFS_SPACE_CHECK_RESERVED);
1976-
1977-
if (error)
1978-
return (SET_ERROR(error));
1979-
1980-
#ifdef _KERNEL
1981-
oldname = kmem_asprintf("%s@%s", fsname, oldsnapname);
1982-
newname = kmem_asprintf("%s@%s", fsname, newsnapname);
1983-
zvol_rename_minors(oldname, newname);
1984-
strfree(newname);
1985-
strfree(oldname);
1986-
#endif
1987-
1988-
return (0);
1964+
1, ZFS_SPACE_CHECK_RESERVED));
19891965
}
19901966

19911967
/*

module/zfs/dsl_destroy.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
2424
* Copyright (c) 2013 Steven Hartland. All rights reserved.
2525
* Copyright (c) 2013 by Joyent, Inc. All rights reserved.
26+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2627
*/
2728

2829
#include <sys/zfs_context.h>
@@ -40,6 +41,7 @@
4041
#include <sys/zfs_ioctl.h>
4142
#include <sys/dsl_deleg.h>
4243
#include <sys/dmu_impl.h>
44+
#include <sys/zvol.h>
4345

4446
typedef struct dmu_snapshots_destroy_arg {
4547
nvlist_t *dsda_snaps;
@@ -243,9 +245,6 @@ dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx)
243245
void
244246
dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
245247
{
246-
#ifdef ZFS_DEBUG
247-
int err;
248-
#endif
249248
spa_feature_t f;
250249
int after_branch_point = FALSE;
251250
dsl_pool_t *dp = ds->ds_dir->dd_pool;
@@ -441,6 +440,7 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
441440
#ifdef ZFS_DEBUG
442441
{
443442
uint64_t val;
443+
int err;
444444

445445
err = dsl_dataset_snap_lookup(ds_head,
446446
ds->ds_snapname, &val);
@@ -490,6 +490,7 @@ dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx)
490490
VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
491491

492492
dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx);
493+
zvol_remove_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
493494
dsl_dataset_rele(ds, FTAG);
494495
}
495496
}
@@ -889,6 +890,7 @@ dsl_destroy_head_sync(void *arg, dmu_tx_t *tx)
889890

890891
VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds));
891892
dsl_destroy_head_sync_impl(ds, tx);
893+
zvol_remove_minors(dp->dp_spa, ddha->ddha_name, B_TRUE);
892894
dsl_dataset_rele(ds, FTAG);
893895
}
894896

module/zfs/dsl_dir.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* Copyright (c) 2013 Martin Matuska. All rights reserved.
2525
* Copyright (c) 2014 Joyent, Inc. All rights reserved.
2626
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
27+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2728
*/
2829

2930
#include <sys/dmu.h>
@@ -1909,9 +1910,8 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
19091910
VERIFY0(zap_add(mos, dsl_dir_phys(newparent)->dd_child_dir_zapobj,
19101911
dd->dd_myname, 8, 1, &dd->dd_object, tx));
19111912

1912-
#ifdef _KERNEL
1913-
zvol_rename_minors(ddra->ddra_oldname, ddra->ddra_newname);
1914-
#endif
1913+
zvol_rename_minors(dp->dp_spa, ddra->ddra_oldname,
1914+
ddra->ddra_newname, B_TRUE);
19151915

19161916
dsl_prop_notify_all(dd);
19171917

module/zfs/spa.c

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* Copyright (c) 2013 by Delphix. All rights reserved.
2525
* Copyright (c) 2013, 2014, Nexenta Systems, Inc. All rights reserved.
2626
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
27+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
2728
*/
2829

2930
/*
@@ -1136,6 +1137,24 @@ spa_activate(spa_t *spa, int mode)
11361137
avl_create(&spa->spa_errlist_last,
11371138
spa_error_entry_compare, sizeof (spa_error_entry_t),
11381139
offsetof(spa_error_entry_t, se_avl));
1140+
1141+
/*
1142+
* This taskq is used to perform zvol-minor-related tasks
1143+
* asynchronously. This has several advantages, including easy
1144+
* resolution of various deadlocks (zfsonlinux bug #3681).
1145+
*
1146+
* The taskq must be single threaded to ensure tasks are always
1147+
* processed in the order in which they were dispatched.
1148+
*
1149+
* A taskq per pool allows one to keep the pools independent.
1150+
* This way if one pool is suspended, it will not impact another.
1151+
*
1152+
* The preferred location to dispatch a zvol minor task is a sync
1153+
* task. In this context, there is easy access to the spa_t and minimal
1154+
* error handling is required because the sync task must succeed.
1155+
*/
1156+
spa->spa_zvol_taskq = taskq_create("z_zvol", 1, defclsyspri,
1157+
1, INT_MAX, 0);
11391158
}
11401159

11411160
/*
@@ -1154,6 +1173,11 @@ spa_deactivate(spa_t *spa)
11541173

11551174
spa_evicting_os_wait(spa);
11561175

1176+
if (spa->spa_zvol_taskq) {
1177+
taskq_destroy(spa->spa_zvol_taskq);
1178+
spa->spa_zvol_taskq = NULL;
1179+
}
1180+
11571181
txg_list_destroy(&spa->spa_vdev_txg_list);
11581182

11591183
list_destroy(&spa->spa_config_dirty_list);
@@ -3088,10 +3112,8 @@ spa_open_common(const char *pool, spa_t **spapp, void *tag, nvlist_t *nvpolicy,
30883112
mutex_exit(&spa_namespace_lock);
30893113
}
30903114

3091-
#ifdef _KERNEL
30923115
if (firstopen)
3093-
zvol_create_minors(spa->spa_name);
3094-
#endif
3116+
zvol_create_minors(spa, spa_name(spa), B_TRUE);
30953117

30963118
*spapp = spa;
30973119

@@ -4211,10 +4233,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
42114233

42124234
mutex_exit(&spa_namespace_lock);
42134235
spa_history_log_version(spa, "import");
4214-
4215-
#ifdef _KERNEL
4216-
zvol_create_minors(pool);
4217-
#endif
4236+
zvol_create_minors(spa, pool, B_TRUE);
42184237

42194238
return (0);
42204239
}
@@ -4349,6 +4368,10 @@ spa_export_common(char *pool, int new_state, nvlist_t **oldconfig,
43494368
spa_open_ref(spa, FTAG);
43504369
mutex_exit(&spa_namespace_lock);
43514370
spa_async_suspend(spa);
4371+
if (spa->spa_zvol_taskq) {
4372+
zvol_remove_minors(spa, spa_name(spa), B_TRUE);
4373+
taskq_wait(spa->spa_zvol_taskq);
4374+
}
43524375
mutex_enter(&spa_namespace_lock);
43534376
spa_close(spa, FTAG);
43544377

0 commit comments

Comments
 (0)