aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJorgen Lundman <lundman@lundman.net>2021-09-13 20:27:07 +0000
committerGitHub <noreply@github.com>2021-09-13 20:27:07 +0000
commit7443299fe0b8caaadbfc18f778732bb26c899e41 (patch)
tree6a2d1eb6c92d5a40b19fbc90cd1e8c6f55da0a5b
parentf82f0279ed588505c16a9026786ba966dbc5f0ee (diff)
downloadsrc-7443299fe0b8caaadbfc18f778732bb26c899e41.tar.gz
src-7443299fe0b8caaadbfc18f778732bb26c899e41.zip
Iterate encrypted clones at zvol_create_minor
Userland figures out which encryption-root keys are required to load, and issues ZFS_IOC_LOAD_KEY. The tail section of spa_keystore_load_wkey() will call zvol_create_minors() on the encryption-root object. Any clones of the encrypted zvol will not be plumbed. This commits adds additional logic to detect if zvol has clones, and is encrypted, then adds these to the list of zvols to call zvol_create_minors() on. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Signed-off-by: Jorgen Lundman <lundman@lundman.net> Closes #12471
-rw-r--r--module/zfs/zvol.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index b7bc587cf624..5438e8f928d1 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -1041,6 +1041,68 @@ zvol_create_snap_minor_cb(const char *dsname, void *arg)
}
/*
+ * If spa_keystore_load_wkey() is called for an encrypted zvol,
+ * we need to look for any clones also using the key. This function
+ * is "best effort" - so we just skip over it if there are failures.
+ */
+static void
+zvol_add_clones(const char *dsname, list_t *minors_list)
+{
+ /* Also check if it has clones */
+ dsl_dir_t *dd = NULL;
+ dsl_pool_t *dp = NULL;
+
+ if (dsl_pool_hold(dsname, FTAG, &dp) != 0)
+ return;
+
+ if (!spa_feature_is_enabled(dp->dp_spa,
+ SPA_FEATURE_ENCRYPTION))
+ goto out;
+
+ if (dsl_dir_hold(dp, dsname, FTAG, &dd, NULL) != 0)
+ goto out;
+
+ if (dsl_dir_phys(dd)->dd_clones == 0)
+ goto out;
+
+ zap_cursor_t *zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
+ zap_attribute_t *za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+ objset_t *mos = dd->dd_pool->dp_meta_objset;
+
+ for (zap_cursor_init(zc, mos, dsl_dir_phys(dd)->dd_clones);
+ zap_cursor_retrieve(zc, za) == 0;
+ zap_cursor_advance(zc)) {
+ dsl_dataset_t *clone;
+ minors_job_t *job;
+
+ if (dsl_dataset_hold_obj(dd->dd_pool,
+ za->za_first_integer, FTAG, &clone) == 0) {
+
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ dsl_dataset_name(clone, name);
+
+ char *n = kmem_strdup(name);
+ job = kmem_alloc(sizeof (minors_job_t), KM_SLEEP);
+ job->name = n;
+ job->list = minors_list;
+ job->error = 0;
+ list_insert_tail(minors_list, job);
+
+ dsl_dataset_rele(clone, FTAG);
+ }
+ }
+ zap_cursor_fini(zc);
+ kmem_free(za, sizeof (zap_attribute_t));
+ kmem_free(zc, sizeof (zap_cursor_t));
+
+out:
+ if (dd != NULL)
+ dsl_dir_rele(dd, FTAG);
+ if (dp != NULL)
+ dsl_pool_rele(dp, FTAG);
+}
+
+/*
* Mask errors to continue dmu_objset_find() traversal
*/
static int
@@ -1078,6 +1140,8 @@ zvol_create_minors_cb(const char *dsname, void *arg)
taskq_dispatch(system_taskq, zvol_prefetch_minors_impl, job,
TQ_SLEEP);
+ zvol_add_clones(dsname, minors_list);
+
if (snapdev == ZFS_SNAPDEV_VISIBLE) {
/*
* traverse snapshots only, do not traverse children,