OpenZFS 7606 - dmu_objset_find_dp() takes a long time while importing pool
When importing a pool with a large number of filesystems within the same parent filesystem, we see that dmu_objset_find_dp() takes a long time. It is called from 3 places: spa_check_logs(), spa_ld_claim_log_blocks(), and spa_load_verify(). There are several ways to improve performance here: 1. We don't really need to do spa_check_logs() or spa_ld_claim_log_blocks() if the pool was closed cleanly. 2. spa_load_verify() uses dmu_objset_find_dp() to check that no datasets have too long of names. 3. dmu_objset_find_dp() is slow because it's doing zap_value_search() (which is O(N sibling datasets)) to determine the name of each dsl_dir when it's opened. In this case we actually know the name when we are opening it, so we can provide it and avoid the lookup. This change implements fix #3 from the above list; i.e. make dmu_objset_find_dp() provide the name of the dataset so that we don't have to search for it. Authored by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Steve Gonczi <steve.gonczi@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Prashanth Sreenivasa <prashksp@gmail.com> Reviewed-by: David Quigley <david.quigley@intel.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Ported-by: George Melikov <mail@gmelikov.ru> OpenZFS-issue: https://www.illumos.org/issues/7606 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/cac6bab Closes #5662
This commit is contained in:
parent
89d43feb0b
commit
1149ba6478
@ -1927,6 +1927,7 @@ typedef struct dmu_objset_find_ctx {
|
||||
taskq_t *dc_tq;
|
||||
dsl_pool_t *dc_dp;
|
||||
uint64_t dc_ddobj;
|
||||
char *dc_ddname; /* last component of ddobj's name */
|
||||
int (*dc_func)(dsl_pool_t *, dsl_dataset_t *, void *);
|
||||
void *dc_arg;
|
||||
int dc_flags;
|
||||
@ -1950,7 +1951,12 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp)
|
||||
if (*dcp->dc_error != 0)
|
||||
goto out;
|
||||
|
||||
err = dsl_dir_hold_obj(dp, dcp->dc_ddobj, NULL, FTAG, &dd);
|
||||
/*
|
||||
* Note: passing the name (dc_ddname) here is optional, but it
|
||||
* improves performance because we don't need to call
|
||||
* zap_value_search() to determine the name.
|
||||
*/
|
||||
err = dsl_dir_hold_obj(dp, dcp->dc_ddobj, dcp->dc_ddname, FTAG, &dd);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
@ -1975,9 +1981,11 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp)
|
||||
sizeof (uint64_t));
|
||||
ASSERT3U(attr->za_num_integers, ==, 1);
|
||||
|
||||
child_dcp = kmem_alloc(sizeof (*child_dcp), KM_SLEEP);
|
||||
child_dcp =
|
||||
kmem_alloc(sizeof (*child_dcp), KM_SLEEP);
|
||||
*child_dcp = *dcp;
|
||||
child_dcp->dc_ddobj = attr->za_first_integer;
|
||||
child_dcp->dc_ddname = spa_strdup(attr->za_name);
|
||||
if (dcp->dc_tq != NULL)
|
||||
(void) taskq_dispatch(dcp->dc_tq,
|
||||
dmu_objset_find_dp_cb, child_dcp, TQ_SLEEP);
|
||||
@ -2020,16 +2028,25 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp)
|
||||
}
|
||||
}
|
||||
|
||||
dsl_dir_rele(dd, FTAG);
|
||||
kmem_free(attr, sizeof (zap_attribute_t));
|
||||
|
||||
if (err != 0)
|
||||
if (err != 0) {
|
||||
dsl_dir_rele(dd, FTAG);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply to self.
|
||||
*/
|
||||
err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds);
|
||||
|
||||
/*
|
||||
* Note: we hold the dir while calling dsl_dataset_hold_obj() so
|
||||
* that the dir will remain cached, and we won't have to re-instantiate
|
||||
* it (which could be expensive due to finding its name via
|
||||
* zap_value_search()).
|
||||
*/
|
||||
dsl_dir_rele(dd, FTAG);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
err = dcp->dc_func(dp, ds, dcp->dc_arg);
|
||||
@ -2044,6 +2061,8 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp)
|
||||
mutex_exit(dcp->dc_error_lock);
|
||||
}
|
||||
|
||||
if (dcp->dc_ddname != NULL)
|
||||
spa_strfree(dcp->dc_ddname);
|
||||
kmem_free(dcp, sizeof (*dcp));
|
||||
}
|
||||
|
||||
@ -2088,6 +2107,7 @@ dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj,
|
||||
dcp->dc_tq = NULL;
|
||||
dcp->dc_dp = dp;
|
||||
dcp->dc_ddobj = ddobj;
|
||||
dcp->dc_ddname = NULL;
|
||||
dcp->dc_func = func;
|
||||
dcp->dc_arg = arg;
|
||||
dcp->dc_flags = flags;
|
||||
|
Loading…
Reference in New Issue
Block a user