summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2016-10-10 04:57:33 +0000
committerjulian <julian@FreeBSD.org>2016-10-10 04:57:33 +0000
commitf3eddd4e73c64e4b2b7b2ca5b968e6d742f3669a (patch)
treee36e4229fc95b4975e9d7e94c65f27264cb1fd5f /sys/kern
parentd8fc7ba5ea5f7d4b1f87a24e4b01ecc65d5836d9 (diff)
downloadFreeBSD-src-f3eddd4e73c64e4b2b7b2ca5b968e6d742f3669a.zip
FreeBSD-src-f3eddd4e73c64e4b2b7b2ca5b968e6d742f3669a.tar.gz
While the thread is sleeping in taskqueue_drain_all() it is
posible that the queue entry it is looking at is removed from the queue, but we make no effort to account for this. when we wake up we need to check it's still there. PR: 209580 Sponsored by: Panzura inc Differential Revision: D8160
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/subr_taskqueue.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c
index bfc941e..c9addb1 100644
--- a/sys/kern/subr_taskqueue.c
+++ b/sys/kern/subr_taskqueue.c
@@ -454,9 +454,26 @@ taskqueue_drain_all(struct taskqueue *queue)
TQ_LOCK(queue);
task = STAILQ_LAST(&queue->tq_queue, task, ta_link);
- if (task != NULL)
- while (task->ta_pending != 0)
- TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0);
+ while (task != NULL && task->ta_pending != 0) {
+ struct task *oldtask;
+ TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0);
+ /*
+ * While we were asleeep the last entry may have been freed.
+ * We need to check if it's still even in the queue.
+ * Not perfect, but it's better than referencing bad memory.
+ * first guess is the current 'end of queue' but if a new
+ * item has been added we need to take the expensive path
+ * Better fix in 11.
+ */
+ oldtask = task;
+ if (oldtask !=
+ (task = STAILQ_LAST(&queue->tq_queue, task, ta_link))) {
+ STAILQ_FOREACH(task, &queue->tq_queue, ta_link) {
+ if (task == oldtask)
+ break;
+ }
+ }
+ }
taskqueue_drain_running(queue);
KASSERT(STAILQ_EMPTY(&queue->tq_queue),
("taskqueue queue is not empty after draining"));
OpenPOWER on IntegriCloud