Skip to content

Commit e890106

Browse files
author
Peter Zijlstra
committed
sched: Split DEQUEUE_SLEEP from deactivate_task()
As a preparation for dequeue_task() failing, and a second code-path needing to take care of the 'success' path, split out the DEQEUE_SLEEP path from deactivate_task(). Much thanks to Libo for spotting and fixing a TASK_ON_RQ_MIGRATING ordering fail. Fixed-by: Libo Chen <libo.chen@oracle.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Valentin Schneider <vschneid@redhat.com> Tested-by: Valentin Schneider <vschneid@redhat.com> Link: https://lkml.kernel.org/r/20240727105029.086192709@infradead.org
1 parent fab4a80 commit e890106

2 files changed

Lines changed: 27 additions & 10 deletions

File tree

kernel/sched/core.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,12 +2036,23 @@ void activate_task(struct rq *rq, struct task_struct *p, int flags)
20362036

20372037
void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
20382038
{
2039-
WRITE_ONCE(p->on_rq, (flags & DEQUEUE_SLEEP) ? 0 : TASK_ON_RQ_MIGRATING);
2039+
WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
20402040
ASSERT_EXCLUSIVE_WRITER(p->on_rq);
20412041

2042+
/*
2043+
* Code explicitly relies on TASK_ON_RQ_MIGRATING begin set *before*
2044+
* dequeue_task() and cleared *after* enqueue_task().
2045+
*/
2046+
20422047
dequeue_task(rq, p, flags);
20432048
}
20442049

2050+
static void block_task(struct rq *rq, struct task_struct *p, int flags)
2051+
{
2052+
if (dequeue_task(rq, p, DEQUEUE_SLEEP | flags))
2053+
__block_task(rq, p);
2054+
}
2055+
20452056
/**
20462057
* task_curr - is this task currently executing on a CPU?
20472058
* @p: the task in question.
@@ -6498,9 +6509,6 @@ static void __sched notrace __schedule(unsigned int sched_mode)
64986509
!(prev_state & TASK_NOLOAD) &&
64996510
!(prev_state & TASK_FROZEN);
65006511

6501-
if (prev->sched_contributes_to_load)
6502-
rq->nr_uninterruptible++;
6503-
65046512
/*
65056513
* __schedule() ttwu()
65066514
* prev_state = prev->state; if (p->on_rq && ...)
@@ -6512,12 +6520,7 @@ static void __sched notrace __schedule(unsigned int sched_mode)
65126520
*
65136521
* After this, schedule() must not care about p->state any more.
65146522
*/
6515-
deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);
6516-
6517-
if (prev->in_iowait) {
6518-
atomic_inc(&rq->nr_iowait);
6519-
delayacct_blkio_start();
6520-
}
6523+
block_task(rq, prev, DEQUEUE_NOCLOCK);
65216524
}
65226525
switch_count = &prev->nvcsw;
65236526
}

kernel/sched/sched.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include <linux/wait_api.h>
6969
#include <linux/wait_bit.h>
7070
#include <linux/workqueue_api.h>
71+
#include <linux/delayacct.h>
7172

7273
#include <trace/events/power.h>
7374
#include <trace/events/sched.h>
@@ -2585,6 +2586,19 @@ static inline void sub_nr_running(struct rq *rq, unsigned count)
25852586
sched_update_tick_dependency(rq);
25862587
}
25872588

2589+
static inline void __block_task(struct rq *rq, struct task_struct *p)
2590+
{
2591+
WRITE_ONCE(p->on_rq, 0);
2592+
ASSERT_EXCLUSIVE_WRITER(p->on_rq);
2593+
if (p->sched_contributes_to_load)
2594+
rq->nr_uninterruptible++;
2595+
2596+
if (p->in_iowait) {
2597+
atomic_inc(&rq->nr_iowait);
2598+
delayacct_blkio_start();
2599+
}
2600+
}
2601+
25882602
extern void activate_task(struct rq *rq, struct task_struct *p, int flags);
25892603
extern void deactivate_task(struct rq *rq, struct task_struct *p, int flags);
25902604

0 commit comments

Comments
 (0)