Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 May 2015 01:40:33 +0000 (UTC)
From:      Xin LI <delphij@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r283551 - head/sys/kern
Message-ID:  <201505260140.t4Q1eXlj001379@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: delphij
Date: Tue May 26 01:40:33 2015
New Revision: 283551
URL: https://svnweb.freebsd.org/changeset/base/283551

Log:
  MFuser/delphij/zfs-arc-rebase@r281754:
  
  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:
  head/sys/kern/subr_taskqueue.c
Directory Properties:
  head/   (props changed)
  head/sys/   (props changed)

Modified: head/sys/kern/subr_taskqueue.c
==============================================================================
--- head/sys/kern/subr_taskqueue.c	Tue May 26 01:30:09 2015	(r283550)
+++ head/sys/kern/subr_taskqueue.c	Tue May 26 01:40:33 2015	(r283551)
@@ -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?201505260140.t4Q1eXlj001379>