From a430c11f0b1ef16ca5edf3059e4082709277376c Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 3 Dec 2015 14:15:16 -0500 Subject: [PATCH] Make taskq_member() use ->journal_info The ->journal_info pointer in the task_struct is reserved for use by filesystems and because the kernel can have multiple file systems on the same stack due to direct reclaim, each filesystem that touches ->journal_info in a callback function will save the value at the start of its frame and restore it at the end of its frame. This allows us to safely use ->journal_info to store a pointer to the taskq's struct in taskq threads so that ZFS code paths can detect the presence of a taskq. This could break if the ZFS code were to use taskq_member from the context of direct reclaim. However, there are no such uses of it in that manner, so this is safe. This eliminates an O(N) list traversal under a spinlock with an O(1) unlocked pointer comparison. Signed-off-by: Richard Yao Signed-off-by: Brian Behlendorf Signed-off-by: tuxoko Signed-off-by: Tim Chase Closes #500 --- include/sys/taskq.h | 2 +- module/spl/spl-taskq.c | 37 +++---------------------------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/include/sys/taskq.h b/include/sys/taskq.h index a43a86da6..65f911245 100644 --- a/include/sys/taskq.h +++ b/include/sys/taskq.h @@ -124,7 +124,7 @@ extern void taskq_wait_id(taskq_t *, taskqid_t); extern void taskq_wait_outstanding(taskq_t *, taskqid_t); extern void taskq_wait(taskq_t *); extern int taskq_cancel_id(taskq_t *, taskqid_t); -extern int taskq_member(taskq_t *, void *); +#define taskq_member(taskq, thread) ((taskq) == ((thread)->journal_info)) #define taskq_create_proc(name, nthreads, pri, min, max, proc, flags) \ taskq_create(name, nthreads, pri, min, max, flags) diff --git a/module/spl/spl-taskq.c b/module/spl/spl-taskq.c index 2c2e3ad46..0c5b230aa 100644 --- a/module/spl/spl-taskq.c +++ b/module/spl/spl-taskq.c @@ -448,40 +448,6 @@ taskq_wait(taskq_t *tq) } EXPORT_SYMBOL(taskq_wait); -static int -taskq_member_impl(taskq_t *tq, void *t) -{ - struct list_head *l; - taskq_thread_t *tqt; - int found = 0; - - ASSERT(tq); - ASSERT(t); - ASSERT(spin_is_locked(&tq->tq_lock)); - - list_for_each(l, &tq->tq_thread_list) { - tqt = list_entry(l, taskq_thread_t, tqt_thread_list); - if (tqt->tqt_thread == (struct task_struct *)t) { - found = 1; - break; - } - } - return (found); -} - -int -taskq_member(taskq_t *tq, void *t) -{ - int found; - - spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags); - found = taskq_member_impl(tq, t); - spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags); - - return (found); -} -EXPORT_SYMBOL(taskq_member); - /* * Cancel an already dispatched task given the task id. Still pending tasks * will be immediately canceled, and if the task is active the function will @@ -812,6 +778,7 @@ taskq_thread(void *args) ASSERT(tqt); tq = tqt->tqt_tq; current->flags |= PF_NOFREEZE; + current->journal_info = tq; #if defined(PF_MEMALLOC_NOIO) (void) memalloc_noio_save(); @@ -877,6 +844,8 @@ taskq_thread(void *args) /* Perform the requested task */ t->tqent_func(t->tqent_arg); + ASSERT3P(tq, ==, current->journal_info); + spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags); tq->tq_nactive--; list_del_init(&tqt->tqt_active_list); -- 2.40.0