Skip to content

Commit 5d299ea

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
sched/fair: Add tmp_alone_branch assertion
The magic in list_add_leaf_cfs_rq() requires that at the end of enqueue_task_fair(): rq->tmp_alone_branch == &rq->lead_cfs_rq_list If this is violated, list integrity is compromised for list entries and the tmp_alone_branch pointer might dangle. Also, reflow list_add_leaf_cfs_rq() while there. This looses one indentation level and generates a form that's convenient for the next patch. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Signed-off-by: Ingo Molnar <[email protected]>
1 parent c546951 commit 5d299ea

File tree

1 file changed

+71
-55
lines changed

1 file changed

+71
-55
lines changed

kernel/sched/fair.c

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -277,64 +277,69 @@ static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
277277

278278
static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
279279
{
280-
if (!cfs_rq->on_list) {
281-
struct rq *rq = rq_of(cfs_rq);
282-
int cpu = cpu_of(rq);
280+
struct rq *rq = rq_of(cfs_rq);
281+
int cpu = cpu_of(rq);
282+
283+
if (cfs_rq->on_list)
284+
return;
285+
286+
cfs_rq->on_list = 1;
287+
288+
/*
289+
* Ensure we either appear before our parent (if already
290+
* enqueued) or force our parent to appear after us when it is
291+
* enqueued. The fact that we always enqueue bottom-up
292+
* reduces this to two cases and a special case for the root
293+
* cfs_rq. Furthermore, it also means that we will always reset
294+
* tmp_alone_branch either when the branch is connected
295+
* to a tree or when we reach the top of the tree
296+
*/
297+
if (cfs_rq->tg->parent &&
298+
cfs_rq->tg->parent->cfs_rq[cpu]->on_list) {
283299
/*
284-
* Ensure we either appear before our parent (if already
285-
* enqueued) or force our parent to appear after us when it is
286-
* enqueued. The fact that we always enqueue bottom-up
287-
* reduces this to two cases and a special case for the root
288-
* cfs_rq. Furthermore, it also means that we will always reset
289-
* tmp_alone_branch either when the branch is connected
290-
* to a tree or when we reach the beg of the tree
300+
* If parent is already on the list, we add the child
301+
* just before. Thanks to circular linked property of
302+
* the list, this means to put the child at the tail
303+
* of the list that starts by parent.
291304
*/
292-
if (cfs_rq->tg->parent &&
293-
cfs_rq->tg->parent->cfs_rq[cpu]->on_list) {
294-
/*
295-
* If parent is already on the list, we add the child
296-
* just before. Thanks to circular linked property of
297-
* the list, this means to put the child at the tail
298-
* of the list that starts by parent.
299-
*/
300-
list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
301-
&(cfs_rq->tg->parent->cfs_rq[cpu]->leaf_cfs_rq_list));
302-
/*
303-
* The branch is now connected to its tree so we can
304-
* reset tmp_alone_branch to the beginning of the
305-
* list.
306-
*/
307-
rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
308-
} else if (!cfs_rq->tg->parent) {
309-
/*
310-
* cfs rq without parent should be put
311-
* at the tail of the list.
312-
*/
313-
list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
314-
&rq->leaf_cfs_rq_list);
315-
/*
316-
* We have reach the beg of a tree so we can reset
317-
* tmp_alone_branch to the beginning of the list.
318-
*/
319-
rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
320-
} else {
321-
/*
322-
* The parent has not already been added so we want to
323-
* make sure that it will be put after us.
324-
* tmp_alone_branch points to the beg of the branch
325-
* where we will add parent.
326-
*/
327-
list_add_rcu(&cfs_rq->leaf_cfs_rq_list,
328-
rq->tmp_alone_branch);
329-
/*
330-
* update tmp_alone_branch to points to the new beg
331-
* of the branch
332-
*/
333-
rq->tmp_alone_branch = &cfs_rq->leaf_cfs_rq_list;
334-
}
305+
list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
306+
&(cfs_rq->tg->parent->cfs_rq[cpu]->leaf_cfs_rq_list));
307+
/*
308+
* The branch is now connected to its tree so we can
309+
* reset tmp_alone_branch to the beginning of the
310+
* list.
311+
*/
312+
rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
313+
return;
314+
}
335315

336-
cfs_rq->on_list = 1;
316+
if (!cfs_rq->tg->parent) {
317+
/*
318+
* cfs rq without parent should be put
319+
* at the tail of the list.
320+
*/
321+
list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
322+
&rq->leaf_cfs_rq_list);
323+
/*
324+
* We have reach the top of a tree so we can reset
325+
* tmp_alone_branch to the beginning of the list.
326+
*/
327+
rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
328+
return;
337329
}
330+
331+
/*
332+
* The parent has not already been added so we want to
333+
* make sure that it will be put after us.
334+
* tmp_alone_branch points to the begin of the branch
335+
* where we will add parent.
336+
*/
337+
list_add_rcu(&cfs_rq->leaf_cfs_rq_list, rq->tmp_alone_branch);
338+
/*
339+
* update tmp_alone_branch to points to the new begin
340+
* of the branch
341+
*/
342+
rq->tmp_alone_branch = &cfs_rq->leaf_cfs_rq_list;
338343
}
339344

340345
static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
@@ -345,7 +350,12 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
345350
}
346351
}
347352

348-
/* Iterate through all leaf cfs_rq's on a runqueue: */
353+
static inline void assert_list_leaf_cfs_rq(struct rq *rq)
354+
{
355+
SCHED_WARN_ON(rq->tmp_alone_branch != &rq->leaf_cfs_rq_list);
356+
}
357+
358+
/* Iterate through all cfs_rq's on a runqueue in bottom-up order */
349359
#define for_each_leaf_cfs_rq(rq, cfs_rq) \
350360
list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
351361

@@ -433,6 +443,10 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
433443
{
434444
}
435445

446+
static inline void assert_list_leaf_cfs_rq(struct rq *rq)
447+
{
448+
}
449+
436450
#define for_each_leaf_cfs_rq(rq, cfs_rq) \
437451
for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
438452

@@ -5172,6 +5186,8 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
51725186

51735187
}
51745188

5189+
assert_list_leaf_cfs_rq(rq);
5190+
51755191
hrtick_update(rq);
51765192
}
51775193

0 commit comments

Comments
 (0)