[PATCH] sched/wake_q: Restore task_struct::wake_q type safety

From: Ingo Molnar
Date: Wed Feb 08 2017 - 16:32:31 EST


Linus correctly observed that task_struct::wake_q is an opaque pointer
in a rather ugly way, through which we lose not just readability but
also type safety, for only marginal savings in sched.h.

Just restore the 'struct wake_q_node' type in sched.h and include
sched.h in sched/wake_q.h.

Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Mike Galbraith <efault@xxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx>
---
include/linux/sched.h | 6 +++++-
include/linux/sched/wake_q.h | 6 +-----
ipc/msg.c | 1 -
kernel/fork.c | 2 +-
kernel/sched/core.c | 6 +++---
5 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2cc4d7902418..d67eee84fd43 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -476,6 +476,10 @@ enum perf_event_task_context {
perf_nr_task_contexts,
};

+struct wake_q_node {
+ struct wake_q_node *next;
+};
+
struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
@@ -765,7 +769,7 @@ struct task_struct {
/* Protection of the PI data structures: */
raw_spinlock_t pi_lock;

- void *wake_q;
+ struct wake_q_node wake_q;

#ifdef CONFIG_RT_MUTEXES
/* PI waiters blocked on a rt_mutex held by this task: */
diff --git a/include/linux/sched/wake_q.h b/include/linux/sched/wake_q.h
index e6774a0385fb..d03d8a9047dc 100644
--- a/include/linux/sched/wake_q.h
+++ b/include/linux/sched/wake_q.h
@@ -28,11 +28,7 @@
* wakeup condition has in fact occurred.
*/

-struct task_struct;
-
-struct wake_q_node {
- struct wake_q_node *next;
-};
+#include <linux/sched.h>

struct wake_q_head {
struct wake_q_node *first;
diff --git a/ipc/msg.c b/ipc/msg.c
index ecc387e573f6..104926dc72be 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -30,7 +30,6 @@
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <linux/security.h>
-#include <linux/sched.h>
#include <linux/sched/wake_q.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
diff --git a/kernel/fork.c b/kernel/fork.c
index 4a033bb7d660..68b1706c75d0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -548,7 +548,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
#endif
tsk->splice_pipe = NULL;
tsk->task_frag.page = NULL;
- tsk->wake_q = NULL;
+ tsk->wake_q.next = NULL;

account_kernel_stack(tsk, 1);

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0abcf7307428..a4fdb6b03577 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -431,7 +431,7 @@ static bool set_nr_if_polling(struct task_struct *p)

void wake_q_add(struct wake_q_head *head, struct task_struct *task)
{
- struct wake_q_node *node = (void *)&task->wake_q;
+ struct wake_q_node *node = &task->wake_q;

/*
* Atomically grab the task, if ->wake_q is !nil already it means
@@ -460,11 +460,11 @@ void wake_up_q(struct wake_q_head *head)
while (node != WAKE_Q_TAIL) {
struct task_struct *task;

- task = container_of((void *)node, struct task_struct, wake_q);
+ task = container_of(node, struct task_struct, wake_q);
BUG_ON(!task);
/* Task can safely be re-inserted now: */
node = node->next;
- task->wake_q = NULL;
+ task->wake_q.next = NULL;

/*
* wake_up_process() implies a wmb() to pair with the queueing