]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: tasks: Make sure we switch wait queues in task_set_affinity().
authorOlivier Houchard <cognet@ci0.org>
Thu, 5 Dec 2019 14:11:19 +0000 (15:11 +0100)
committerOlivier Houchard <cognet@ci0.org>
Thu, 5 Dec 2019 14:11:19 +0000 (15:11 +0100)
In task_set_affinity(), leave the wait_queue if any before changing the
affinity, and re-enter a wait queue once it is done. If we don't do that,
the task may stay in the wait queue of another thread, and we later may
end up modifying that wait queue while holding no lock, which could lead
to memory corruption.

THis should be backported to 2.1, 2.0 and 1.9.

include/proto/task.h

index b29d84a9144f60334d2e786322d2e2603905c18b..a828cd71f19a28ae90f4cb3810dc8686f23657e5 100644 (file)
@@ -105,6 +105,8 @@ extern struct task_per_thread task_per_thread[MAX_THREADS];
 __decl_hathreads(extern HA_SPINLOCK_T rq_lock);  /* spin lock related to run queue */
 __decl_hathreads(extern HA_RWLOCK_T wq_lock);    /* RW lock related to the wait queue */
 
+static inline struct task *task_unlink_wq(struct task *t);
+static inline void task_queue(struct task *task);
 
 /* return 0 if task is in run queue, otherwise non-zero */
 static inline int task_in_rq(struct task *t)
@@ -153,7 +155,11 @@ static inline void task_wakeup(struct task *t, unsigned int f)
 /* change the thread affinity of a task to <thread_mask> */
 static inline void task_set_affinity(struct task *t, unsigned long thread_mask)
 {
+       if (task_in_wq(t))
+               task_unlink_wq(t);
        t->thread_mask = thread_mask;
+       if (t->expire != TICK_ETERNITY)
+               task_queue(t);
 }
 
 /*