Date: Sun, 19 Apr 2015 23:31:01 +0000 (UTC) From: Xin LI <delphij@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r281754 - user/delphij/zfs-arc-rebase/sys/kern Message-ID: <201504192331.t3JNV1pw062589@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: delphij Date: Sun Apr 19 23:31:00 2015 New Revision: 281754 URL: https://svnweb.freebsd.org/changeset/base/281754 Log: In r256613, taskqueue_enqueue_locked() have been modified to release the task queue lock before returning. In r276665, taskqueue_drain_all() will call taskqueue_enqueue_locked() to insert the barrier task into the queue, but did not reacquire the lock after it but later code expects the lock still being held (e.g. TQ_SLEEP()). The barrier task is special and if we release then reacquire the lock, there would be a small race window where a high priority task could sneak into the queue. Looking more closely, the race seems to be tolerable but is undesirable from semantics standpoint. To solve this, in taskqueue_drain_tq_queue(), instead of directly calling taskqueue_enqueue_locked(), insert the barrier task directly without releasing the lock. Modified: user/delphij/zfs-arc-rebase/sys/kern/subr_taskqueue.c Modified: user/delphij/zfs-arc-rebase/sys/kern/subr_taskqueue.c ============================================================================== --- user/delphij/zfs-arc-rebase/sys/kern/subr_taskqueue.c Sun Apr 19 22:33:24 2015 (r281753) +++ user/delphij/zfs-arc-rebase/sys/kern/subr_taskqueue.c Sun Apr 19 23:31:00 2015 (r281754) @@ -323,17 +323,16 @@ taskqueue_drain_tq_queue(struct taskqueu return; /* - * Enqueue our barrier with the lowest possible priority - * so we are inserted after all current tasks. + * Enqueue our barrier after all current tasks, but with + * the highest priority so that newly queued tasks cannot + * pass it. Because of the high priority, we can not use + * taskqueue_enqueue_locked directly (which drops the lock + * anyway) so just insert it at tail while we have the + * queue lock. */ - TASK_INIT(&t_barrier, 0, taskqueue_task_nop_fn, &t_barrier); - taskqueue_enqueue_locked(queue, &t_barrier); - - /* - * Raise the barrier's priority so newly queued tasks cannot - * pass it. - */ - t_barrier.ta_priority = USHRT_MAX; + TASK_INIT(&t_barrier, USHRT_MAX, taskqueue_task_nop_fn, &t_barrier); + STAILQ_INSERT_TAIL(&queue->tq_queue, &t_barrier, ta_link); + t_barrier.ta_pending = 1; /* * Once the barrier has executed, all previously queued tasks
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201504192331.t3JNV1pw062589>