Skip to content

Commit

Permalink
OpenZFS 7606 - dmu_objset_find_dp() takes a long time while importing…
Browse files Browse the repository at this point in the history
… 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 openzfs#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: openzfs/openzfs@cac6bab
Closes openzfs#5662
  • Loading branch information
gmelikov authored and wli5 committed Feb 27, 2017
1 parent 71e06a7 commit aac5771
Showing 1 changed file with 24 additions and 4 deletions.
28 changes: 24 additions & 4 deletions module/zfs/dmu_objset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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));
}

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit aac5771

Please sign in to comment.