spa_taskq_dispatch_ent: look for an unlocked taskq before waiting

Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
This commit is contained in:
Rob Norris 2023-10-23 12:42:28 +11:00
parent c85d31a88b
commit 7d74fc7a68
1 changed files with 14 additions and 7 deletions

View File

@ -1390,15 +1390,14 @@ spa_taskq_write_param(ZFS_MODULE_PARAM_ARGS)
/* /*
* Dispatch a task to the appropriate taskq for the ZFS I/O type and priority. * Dispatch a task to the appropriate taskq for the ZFS I/O type and priority.
* Note that a type may have multiple discrete taskqs to avoid lock contention * Note that a type may have multiple discrete taskqs to avoid lock contention
* on the taskq itself. In that case we choose which taskq at random by using * on the taskq itself. In that case we try each one until it goes in, before
* the low bits of gethrtime(). * falling back to waiting on a lock.
*/ */
void void
spa_taskq_dispatch_ent(spa_t *spa, zio_type_t t, zio_taskq_type_t q, spa_taskq_dispatch_ent(spa_t *spa, zio_type_t t, zio_taskq_type_t q,
task_func_t *func, void *arg, uint_t flags, taskq_ent_t *ent) task_func_t *func, void *arg, uint_t flags, taskq_ent_t *ent)
{ {
spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q]; spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
taskq_t *tq;
ASSERT3P(tqs->stqs_taskq, !=, NULL); ASSERT3P(tqs->stqs_taskq, !=, NULL);
ASSERT3U(tqs->stqs_count, !=, 0); ASSERT3U(tqs->stqs_count, !=, 0);
@ -1407,13 +1406,21 @@ spa_taskq_dispatch_ent(spa_t *spa, zio_type_t t, zio_taskq_type_t q,
spa_taskqs_t *, tqs, taskq_ent_t *, ent); spa_taskqs_t *, tqs, taskq_ent_t *, ent);
if (tqs->stqs_count == 1) { if (tqs->stqs_count == 1) {
tq = tqs->stqs_taskq[0]; taskq_dispatch_ent(tqs->stqs_taskq[0], func, arg, flags, ent);
} else { goto out;
tq = tqs->stqs_taskq[((uint64_t)gethrtime()) % tqs->stqs_count];
} }
taskq_dispatch_ent(tq, func, arg, flags, ent); int select = ((uint64_t)gethrtime()) % tqs->stqs_count;
for (int i = 0; i < tqs->stqs_count; i++) {
if (taskq_try_dispatch_ent(
tqs->stqs_taskq[select], func, arg, flags, ent))
goto out;
select = (select+1) % tqs->stqs_count;
}
taskq_dispatch_ent(tqs->stqs_taskq[select], func, arg, flags, ent);
out:
DTRACE_PROBE2(spa_taskqs_ent__dispatched, DTRACE_PROBE2(spa_taskqs_ent__dispatched,
spa_taskqs_t *, tqs, taskq_ent_t *, ent); spa_taskqs_t *, tqs, taskq_ent_t *, ent);
} }