Print this page
zpool import speedup
@@ -45,10 +45,11 @@
#include <sys/dmu_impl.h>
#include <sys/zfs_ioctl.h>
#include <sys/sa.h>
#include <sys/zfs_onexit.h>
#include <sys/dsl_destroy.h>
+#include <sys/vdev.h>
/*
* Needed to close a window in dnode_move() that allows the objset to be freed
* before it can be safely accessed.
*/
@@ -464,18 +465,18 @@
/*
* Holds the pool while the objset is held. Therefore only one objset
* can be held at a time.
*/
-int
-dmu_objset_hold(const char *name, void *tag, objset_t **osp)
+static int
+dmu_objset_hold_impl(const char *name, void *tag, objset_t **osp, int lock)
{
dsl_pool_t *dp;
dsl_dataset_t *ds;
int err;
- err = dsl_pool_hold(name, tag, &dp);
+ err = dsl_pool_hold_lock(name, tag, &dp, lock);
if (err != 0)
return (err);
err = dsl_dataset_hold(dp, name, tag, &ds);
if (err != 0) {
dsl_pool_rele(dp, tag);
@@ -489,24 +490,36 @@
}
return (err);
}
+int
+dmu_objset_hold(const char *name, void *tag, objset_t **osp)
+{
+ return (dmu_objset_hold_impl(name, tag, osp, 1));
+}
+
+int
+dmu_objset_hold_nolock(const char *name, void *tag, objset_t **osp)
+{
+ return (dmu_objset_hold_impl(name, tag, osp, 0));
+}
+
/*
* dsl_pool must not be held when this is called.
* Upon successful return, there will be a longhold on the dataset,
* and the dsl_pool will not be held.
*/
-int
-dmu_objset_own(const char *name, dmu_objset_type_t type,
- boolean_t readonly, void *tag, objset_t **osp)
+static int
+dmu_objset_own_impl(const char *name, dmu_objset_type_t type,
+ boolean_t readonly, void *tag, objset_t **osp, int lock)
{
dsl_pool_t *dp;
dsl_dataset_t *ds;
int err;
- err = dsl_pool_hold(name, FTAG, &dp);
+ err = dsl_pool_hold_lock(name, FTAG, &dp, lock);
if (err != 0)
return (err);
err = dsl_dataset_own(dp, name, tag, &ds);
if (err != 0) {
dsl_pool_rele(dp, FTAG);
@@ -525,10 +538,24 @@
return (SET_ERROR(EROFS));
}
return (err);
}
+int
+dmu_objset_own(const char *name, dmu_objset_type_t type,
+ boolean_t readonly, void *tag, objset_t **osp)
+{
+ return (dmu_objset_own_impl(name, type, readonly, tag, osp, 1));
+}
+
+int
+dmu_objset_own_nolock(const char *name, dmu_objset_type_t type,
+ boolean_t readonly, void *tag, objset_t **osp)
+{
+ return (dmu_objset_own_impl(name, type, readonly, tag, osp, 0));
+}
+
void
dmu_objset_rele(objset_t *os, void *tag)
{
dsl_pool_t *dp = dmu_objset_pool(os);
dsl_dataset_rele(os->os_dsl_dataset, tag);
@@ -1771,10 +1798,148 @@
error = spa_open(name, &spa, FTAG);
if (error != 0)
return (error);
error = dmu_objset_find_impl(spa, name, func, arg, flags);
spa_close(spa, FTAG);
+
+ return (error);
+}
+
+typedef struct dmu_objset_find_ctx {
+ taskq_t *dc_tq;
+ spa_t *dc_spa;
+ char *dc_name;
+ int (*dc_func)(const char *, void *);
+ void *dc_arg;
+ int dc_flags;
+ kmutex_t *dc_error_lock;
+ int *dc_error;
+} dmu_objset_find_ctx_t;
+
+static void
+dmu_objset_find_parallel_impl(void *arg)
+{
+ dmu_objset_find_ctx_t *dcp = arg;
+ dsl_dir_t *dd;
+ dsl_pool_t *dp = spa_get_dsl(dcp->dc_spa);
+ dsl_dataset_t *ds;
+ zap_cursor_t zc;
+ zap_attribute_t *attr;
+ char *child;
+ dmu_objset_find_ctx_t *child_dcp;
+ uint64_t thisobj;
+ int err;
+
+ /* don't process if there already was an error */
+ if (*dcp->dc_error)
+ goto out;
+
+ dsl_pool_config_enter(dp, FTAG);
+
+ err = dsl_dir_hold(dp, dcp->dc_name, FTAG, &dd, NULL);
+ if (err != 0) {
+ dsl_pool_config_exit(dp, FTAG);
+ goto fail;
+ }
+
+ /* Don't visit hidden ($MOS & $ORIGIN) objsets. */
+ if (dd->dd_myname[0] == '$') {
+ dsl_dir_rele(dd, FTAG);
+ dsl_pool_config_exit(dp, FTAG);
+ goto out;
+ }
+
+ thisobj = dd->dd_phys->dd_head_dataset_obj;
+ attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+
+ /*
+ * Iterate over all children.
+ */
+ if (dcp->dc_flags & DS_FIND_CHILDREN) {
+ for (zap_cursor_init(&zc, dp->dp_meta_objset,
+ dd->dd_phys->dd_child_dir_zapobj);
+ zap_cursor_retrieve(&zc, attr) == 0;
+ (void) zap_cursor_advance(&zc)) {
+ ASSERT3U(attr->za_integer_length, ==,
+ sizeof (uint64_t));
+ ASSERT3U(attr->za_num_integers, ==, 1);
+
+ child = kmem_asprintf("%s/%s", dcp->dc_name,
+ attr->za_name);
+ dsl_pool_config_exit(dp, FTAG);
+ child_dcp = kmem_alloc(sizeof(*child_dcp), KM_SLEEP);
+ *child_dcp = *dcp;
+ child_dcp->dc_name = child;
+ taskq_dispatch(dcp->dc_tq,
+ dmu_objset_find_parallel_impl, child_dcp, TQ_SLEEP);
+ dsl_pool_config_enter(dp, FTAG);
+ }
+ zap_cursor_fini(&zc);
+ }
+
+ dsl_dir_rele(dd, FTAG);
+ kmem_free(attr, sizeof (zap_attribute_t));
+ dsl_pool_config_exit(dp, FTAG);
+
+ err = dcp->dc_func(dcp->dc_name, dcp->dc_arg);
+
+fail:
+ if (err) {
+ mutex_enter(dcp->dc_error_lock);
+ /* only keep first error */
+ if (*dcp->dc_error == 0)
+ *dcp->dc_error = err;
+ mutex_exit(dcp->dc_error_lock);
+ }
+
+out:
+ strfree(dcp->dc_name);
+ kmem_free(dcp, sizeof(*dcp));
+}
+
+int
+dmu_objset_find_parallel(char *name, int func(const char *, void *), void *arg,
+ int flags)
+{
+ spa_t *spa;
+ int error;
+ taskq_t *tq = NULL;
+ int ntasks;
+ dmu_objset_find_ctx_t *dcp;
+ kmutex_t err_lock;
+
+ error = spa_open(name, &spa, FTAG);
+ if (error != 0)
+ return (error);
+
+ ntasks = vdev_count_leaves(spa) * 4;
+ tq = taskq_create("dmu_objset_find", ntasks, minclsyspri, ntasks,
+ INT_MAX, 0);
+ if (!tq) {
+ spa_close(spa, FTAG);
+ return (dmu_objset_find(name, func, arg, flags));
+ }
+
+ mutex_init(&err_lock, NULL, MUTEX_DEFAULT, NULL);
+ dcp = kmem_alloc(sizeof(*dcp), KM_SLEEP);
+ dcp->dc_tq = tq;
+ dcp->dc_spa = spa;
+ dcp->dc_name = strdup(name);
+ dcp->dc_func = func;
+ dcp->dc_arg = arg;
+ dcp->dc_flags = flags;
+ dcp->dc_error_lock = &err_lock;
+ dcp->dc_error = &error;
+ /* dcp and dc_name will be freed by task */
+ taskq_dispatch(tq, dmu_objset_find_parallel_impl, dcp, TQ_SLEEP);
+
+ taskq_wait(tq);
+ taskq_destroy(tq);
+ mutex_destroy(&err_lock);
+
+ spa_close(spa, FTAG);
+
return (error);
}
void
dmu_objset_set_user(objset_t *os, void *user_ptr)