Skip to content

Commit

Permalink
Make taskq_member() use ->journal_info
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Signed-off-by: tuxoko <[email protected]>
Signed-off-by: Tim Chase <[email protected]>
Closes openzfs#500
  • Loading branch information
ryao authored and behlendorf committed Dec 8, 2015
1 parent 1683e75 commit a430c11
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 35 deletions.
2 changes: 1 addition & 1 deletion include/sys/taskq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
37 changes: 3 additions & 34 deletions module/spl/spl-taskq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a430c11

Please sign in to comment.