Print this page
zpool import speedup

*** 45,54 **** --- 45,55 ---- #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,481 **** /* * 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) { dsl_pool_t *dp; dsl_dataset_t *ds; int err; ! err = dsl_pool_hold(name, tag, &dp); if (err != 0) return (err); err = dsl_dataset_hold(dp, name, tag, &ds); if (err != 0) { dsl_pool_rele(dp, tag); --- 465,482 ---- /* * Holds the pool while the objset is held. Therefore only one objset * can be held at a time. */ ! 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_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,512 **** } return (err); } /* * 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) { dsl_pool_t *dp; dsl_dataset_t *ds; int err; ! err = dsl_pool_hold(name, FTAG, &dp); if (err != 0) return (err); err = dsl_dataset_own(dp, name, tag, &ds); if (err != 0) { dsl_pool_rele(dp, FTAG); --- 490,525 ---- } 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. */ ! 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_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,534 **** --- 538,561 ---- 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,1780 **** --- 1798,1945 ---- 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)