summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorAlexander Motin <[email protected]>2019-06-25 15:03:38 -0400
committerBrian Behlendorf <[email protected]>2019-06-25 12:03:38 -0700
commitfc7546777ba15a7fff651cd803bf521f592d8379 (patch)
tree8c4b293b0def171817efca85346cb55e22209f5d /module/zfs
parent5279ae918befc707b3b2c5e9b97e2b6e8d033d99 (diff)
Avoid extra taskq_dispatch() calls by DMU
DMU sync code calls taskq_dispatch() for each sublist of os_dirty_dnodes and os_synced_dnodes. Since the number of sublists by default is equal to number of CPUs, it will dispatch equal, potentially large, number of tasks, waking up many CPUs to handle them, even if only one or few of sublists actually have any work to do. This change adds check for empty sublists to avoid this. Reviewed by: Sean Eric Fagan <[email protected]> Reviewed by: Matt Ahrens <[email protected]> Reviewed by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Closes #8909
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/dmu_objset.c19
-rw-r--r--module/zfs/multilist.c22
2 files changed, 36 insertions, 5 deletions
diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c
index 4091ac355..8b55469a5 100644
--- a/module/zfs/dmu_objset.c
+++ b/module/zfs/dmu_objset.c
@@ -1598,6 +1598,8 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
zio_t *zio;
list_t *list;
dbuf_dirty_record_t *dr;
+ int num_sublists;
+ multilist_t *ml;
blkptr_t *blkptr_copy = kmem_alloc(sizeof (*os->os_rootbp), KM_SLEEP);
*blkptr_copy = *os->os_rootbp;
@@ -1686,10 +1688,13 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
}
}
- for (int i = 0;
- i < multilist_get_num_sublists(os->os_dirty_dnodes[txgoff]); i++) {
+ ml = os->os_dirty_dnodes[txgoff];
+ num_sublists = multilist_get_num_sublists(ml);
+ for (int i = 0; i < num_sublists; i++) {
+ if (multilist_sublist_is_empty_idx(ml, i))
+ continue;
sync_dnodes_arg_t *sda = kmem_alloc(sizeof (*sda), KM_SLEEP);
- sda->sda_list = os->os_dirty_dnodes[txgoff];
+ sda->sda_list = ml;
sda->sda_sublist_idx = i;
sda->sda_tx = tx;
(void) taskq_dispatch(dmu_objset_pool(os)->dp_sync_taskq,
@@ -1992,6 +1997,8 @@ userquota_updates_task(void *arg)
void
dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
{
+ int num_sublists;
+
if (!dmu_objset_userused_enabled(os))
return;
@@ -2024,8 +2031,10 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx));
}
- for (int i = 0;
- i < multilist_get_num_sublists(os->os_synced_dnodes); i++) {
+ num_sublists = multilist_get_num_sublists(os->os_synced_dnodes);
+ for (int i = 0; i < num_sublists; i++) {
+ if (multilist_sublist_is_empty_idx(os->os_synced_dnodes, i))
+ continue;
userquota_updates_arg_t *uua =
kmem_alloc(sizeof (*uua), KM_SLEEP);
uua->uua_os = os;
diff --git a/module/zfs/multilist.c b/module/zfs/multilist.c
index 2a594c56c..b74ee0f06 100644
--- a/module/zfs/multilist.c
+++ b/module/zfs/multilist.c
@@ -363,6 +363,28 @@ multilist_sublist_remove(multilist_sublist_t *mls, void *obj)
list_remove(&mls->mls_list, obj);
}
+int
+multilist_sublist_is_empty(multilist_sublist_t *mls)
+{
+ ASSERT(MUTEX_HELD(&mls->mls_lock));
+ return (list_is_empty(&mls->mls_list));
+}
+
+int
+multilist_sublist_is_empty_idx(multilist_t *ml, unsigned int sublist_idx)
+{
+ multilist_sublist_t *mls;
+ int empty;
+
+ ASSERT3U(sublist_idx, <, ml->ml_num_sublists);
+ mls = &ml->ml_sublists[sublist_idx];
+ ASSERT(!MUTEX_HELD(&mls->mls_lock));
+ mutex_enter(&mls->mls_lock);
+ empty = list_is_empty(&mls->mls_list);
+ mutex_exit(&mls->mls_lock);
+ return (empty);
+}
+
void *
multilist_sublist_head(multilist_sublist_t *mls)
{