svn commit: r317507 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs

Josh Paetzel jpaetzel at FreeBSD.org
Thu Apr 27 15:10:46 UTC 2017


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 at 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.gonczi at delphix.com>
  Reviewed by: George Wilson <george.wilson at delphix.com>
  Reviewed by: Prashanth Sreenivasa <prashksp at gmail.com>
  Approved by: Gordon Ross <gordon.w.ross at gmail.com>
  Author: Matthew Ahrens <mahrens at 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;


More information about the svn-src-all mailing list