Author: jpaetzel
Date: Thu Apr 27 15:10:45 2017
New Revision: 317507
URL: https://svnweb.freebsd.org/changeset/base/317507

Log:
  MFV 316895
  
  7606 dmu_objset_find_dp() takes a long time while importing pool
  
  illumos/illumos-gate@7588687e6ba67c47bf7c9805086dec4a97fcac7b
  
https://github.com/illumos/illumos-gate/commit/7588687e6ba67c47bf7c9805086dec4a97fcac7b
  
  https://www.illumos.org/issues/7606
    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.
  
  Reviewed by: Steve Gonczi <steve.gon...@delphix.com>
  Reviewed by: George Wilson <george.wil...@delphix.com>
  Reviewed by: Prashanth Sreenivasa <prash...@gmail.com>
  Approved by: Gordon Ross <gordon.w.r...@gmail.com>
  Author: Matthew Ahrens <mahr...@delphix.com>

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
Directory Properties:
  head/sys/cddl/contrib/opensolaris/   (props changed)

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c    Thu Apr 
27 15:03:24 2017        (r317506)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c    Thu Apr 
27 15:10:45 2017        (r317507)
@@ -1705,6 +1705,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;
@@ -1716,7 +1717,6 @@ static void
 dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp)
 {
        dsl_pool_t *dp = dcp->dc_dp;
-       dmu_objset_find_ctx_t *child_dcp;
        dsl_dir_t *dd;
        dsl_dataset_t *ds;
        zap_cursor_t zc;
@@ -1728,7 +1728,12 @@ dmu_objset_find_dp_impl(dmu_objset_find_
        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;
 
@@ -1753,9 +1758,11 @@ dmu_objset_find_dp_impl(dmu_objset_find_
                            sizeof (uint64_t));
                        ASSERT3U(attr->za_num_integers, ==, 1);
 
-                       child_dcp = kmem_alloc(sizeof (*child_dcp), KM_SLEEP);
+                       dmu_objset_find_ctx_t *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);
@@ -1798,16 +1805,25 @@ dmu_objset_find_dp_impl(dmu_objset_find_
                }
        }
 
-       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);
@@ -1822,6 +1838,8 @@ out:
                mutex_exit(dcp->dc_error_lock);
        }
 
+       if (dcp->dc_ddname != NULL)
+               spa_strfree(dcp->dc_ddname);
        kmem_free(dcp, sizeof (*dcp));
 }
 
@@ -1866,6 +1884,7 @@ dmu_objset_find_dp(dsl_pool_t *dp, uint6
        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;
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to