From c85d31a88b8880cac1701ce4d4f2f075583e82ea Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 23 Oct 2023 12:26:26 +1100 Subject: [PATCH] taskq: add taskq_try_dispatch_ent() Non-blocking form of taskq_dispatch_ent(), returns false if it can't acquire the taskq lock. Signed-off-by: Rob Norris --- include/os/freebsd/spl/sys/taskq.h | 2 ++ include/os/linux/spl/sys/taskq.h | 2 ++ include/sys/zfs_context.h | 2 ++ lib/libzpool/taskq.c | 24 ++++++++++++++-- module/os/freebsd/spl/spl_taskq.c | 9 ++++++ module/os/linux/spl/spl-taskq.c | 46 ++++++++++++++++++++++++------ 6 files changed, 74 insertions(+), 11 deletions(-) diff --git a/include/os/freebsd/spl/sys/taskq.h b/include/os/freebsd/spl/sys/taskq.h index 3040549e04..74243ba903 100644 --- a/include/os/freebsd/spl/sys/taskq.h +++ b/include/os/freebsd/spl/sys/taskq.h @@ -91,6 +91,8 @@ extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *, uint_t, clock_t); extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, taskq_ent_t *); +extern boolean_t taskq_try_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, + taskq_ent_t *); extern int taskq_empty_ent(taskq_ent_t *); taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); taskq_t *taskq_create_instance(const char *, int, int, pri_t, int, int, uint_t); diff --git a/include/os/linux/spl/sys/taskq.h b/include/os/linux/spl/sys/taskq.h index b50175a108..cdcaf8cbff 100644 --- a/include/os/linux/spl/sys/taskq.h +++ b/include/os/linux/spl/sys/taskq.h @@ -146,6 +146,8 @@ extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *, uint_t, clock_t); extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, taskq_ent_t *); +extern boolean_t taskq_try_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, + taskq_ent_t *); extern int taskq_empty_ent(taskq_ent_t *); extern void taskq_init_ent(taskq_ent_t *); extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 2c7ae3003f..2ec9636da2 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -503,6 +503,8 @@ extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *, uint_t, clock_t); extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, taskq_ent_t *); +extern boolean_t taskq_try_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, + taskq_ent_t *); extern int taskq_empty_ent(taskq_ent_t *); extern void taskq_init_ent(taskq_ent_t *); extern void taskq_destroy(taskq_t *); diff --git a/lib/libzpool/taskq.c b/lib/libzpool/taskq.c index 456080f7f2..28bead7930 100644 --- a/lib/libzpool/taskq.c +++ b/lib/libzpool/taskq.c @@ -156,8 +156,8 @@ taskq_init_ent(taskq_ent_t *t) t->tqent_flags = 0; } -void -taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, +static void +taskq_dispatch_ent_impl(taskq_t *tq, task_func_t func, void *arg, uint_t flags, taskq_ent_t *t) { ASSERT(func != NULL); @@ -170,7 +170,6 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, /* * Enqueue the task to the underlying queue. */ - mutex_enter(&tq->tq_lock); if (flags & TQ_FRONT) { t->tqent_next = tq->tq_task.tqent_next; @@ -184,9 +183,28 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, t->tqent_func = func; t->tqent_arg = arg; cv_signal(&tq->tq_dispatch_cv); +} + +void +taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, + taskq_ent_t *t) +{ + mutex_enter(&tq->tq_lock); + taskq_dispatch_ent_impl(tq, func, arg, flags, t); mutex_exit(&tq->tq_lock); } +boolean_t +taskq_try_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, + taskq_ent_t *t) +{ + if (!mutex_tryenter(&tq->tq_lock)) + return (B_FALSE); + taskq_dispatch_ent_impl(tq, func, arg, flags, t); + mutex_exit(&tq->tq_lock); + return (B_TRUE); +} + void taskq_wait(taskq_t *tq) { diff --git a/module/os/freebsd/spl/spl_taskq.c b/module/os/freebsd/spl/spl_taskq.c index 3fa7939bdb..ba9ab33227 100644 --- a/module/os/freebsd/spl/spl_taskq.c +++ b/module/os/freebsd/spl/spl_taskq.c @@ -411,6 +411,15 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint32_t flags, taskqueue_enqueue(tq->tq_queue, &task->tqent_task); } +boolean_t +taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint32_t flags, + taskq_ent_t *task) +{ + /* XXX: implement me -- robn, 2023-10-23 */ + taskq_dispatch_ent(tq, func, arg, flags, task); + return (B_TRUE); +} + void taskq_wait(taskq_t *tq) { diff --git a/module/os/linux/spl/spl-taskq.c b/module/os/linux/spl/spl-taskq.c index fb25a41544..d02ad6a445 100644 --- a/module/os/linux/spl/spl-taskq.c +++ b/module/os/linux/spl/spl-taskq.c @@ -673,17 +673,13 @@ out: } EXPORT_SYMBOL(taskq_dispatch_delay); -void -taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, +static void +taskq_dispatch_ent_impl(taskq_t *tq, task_func_t func, void *arg, uint_t flags, taskq_ent_t *t) { - unsigned long irqflags; ASSERT(tq); ASSERT(func); - spin_lock_irqsave_nested(&tq->tq_lock, irqflags, - tq->tq_lock_class); - /* Taskq being destroyed and all tasks drained */ if (!(tq->tq_flags & TASKQ_ACTIVE)) { t->tqent_id = TASKQID_INVALID; @@ -694,7 +690,7 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, /* Dynamic taskq may be able to spawn another thread */ if (!(tq->tq_flags & TASKQ_DYNAMIC) || taskq_thread_spawn(tq) == 0) - goto out2; + return; flags |= TQ_FRONT; } @@ -734,11 +730,45 @@ out: /* Spawn additional taskq threads if required. */ if (tq->tq_nactive == tq->tq_nthreads) (void) taskq_thread_spawn(tq); -out2: +} + +void +taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, + taskq_ent_t *t) +{ + unsigned long irqflags; + + spin_lock_irqsave_nested(&tq->tq_lock, irqflags, + tq->tq_lock_class); + + taskq_dispatch_ent_impl(tq, func, arg, flags, t); + spin_unlock_irqrestore(&tq->tq_lock, irqflags); } EXPORT_SYMBOL(taskq_dispatch_ent); +boolean_t +taskq_try_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, + taskq_ent_t *t) +{ + unsigned long irqflags; + + /* + * XXX I don't _think_ losing _nested matters, because I think its + * only related to lockdep, and we don't have access to that anyway + * -- robn, 2023-10-23 + */ + if (!spin_trylock_irqsave(&tq->tq_lock, irqflags)) + return (B_FALSE); + + taskq_dispatch_ent_impl(tq, func, arg, flags, t); + + spin_unlock_irqrestore(&tq->tq_lock, irqflags); + + return (B_TRUE); +} +EXPORT_SYMBOL(taskq_try_dispatch_ent); + int taskq_empty_ent(taskq_ent_t *t) {