diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2008-08-11 03:30:22 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-11 03:30:22 -0400 |
commit | 1b12bbc747560ea68bcc132c3d05699e52271da0 (patch) | |
tree | 0e0fe5b7fe07d411251eebdd053e9e7793820248 /kernel/sched_rt.c | |
parent | 64aa348edc617dea17bbd01ddee4e47886d5ec8c (diff) |
lockdep: re-annotate scheduler runqueues
Instead of using a per-rq lock class, use the regular nesting operations.
However, take extra care with double_lock_balance() as it can release the
already held rq->lock (and therefore change its nesting class).
So what can happen is:
spin_lock(rq->lock); // this rq subclass 0
double_lock_balance(rq, other_rq);
// release rq
// acquire other_rq->lock subclass 0
// acquire rq->lock subclass 1
spin_unlock(other_rq->lock);
leaving you with rq->lock in subclass 1
So a subsequent double_lock_balance() call can try to nest a subclass 1
lock while already holding a subclass 1 lock.
Fix this by introducing double_unlock_balance() which releases the other
rq's lock, but also re-sets the subclass for this rq's lock to 0.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched_rt.c')
-rw-r--r-- | kernel/sched_rt.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 908c04f9dad0..6163e4cf885b 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c | |||
@@ -861,6 +861,8 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) | |||
861 | #define RT_MAX_TRIES 3 | 861 | #define RT_MAX_TRIES 3 |
862 | 862 | ||
863 | static int double_lock_balance(struct rq *this_rq, struct rq *busiest); | 863 | static int double_lock_balance(struct rq *this_rq, struct rq *busiest); |
864 | static void double_unlock_balance(struct rq *this_rq, struct rq *busiest); | ||
865 | |||
864 | static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep); | 866 | static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep); |
865 | 867 | ||
866 | static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) | 868 | static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) |
@@ -1022,7 +1024,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) | |||
1022 | break; | 1024 | break; |
1023 | 1025 | ||
1024 | /* try again */ | 1026 | /* try again */ |
1025 | spin_unlock(&lowest_rq->lock); | 1027 | double_unlock_balance(rq, lowest_rq); |
1026 | lowest_rq = NULL; | 1028 | lowest_rq = NULL; |
1027 | } | 1029 | } |
1028 | 1030 | ||
@@ -1091,7 +1093,7 @@ static int push_rt_task(struct rq *rq) | |||
1091 | 1093 | ||
1092 | resched_task(lowest_rq->curr); | 1094 | resched_task(lowest_rq->curr); |
1093 | 1095 | ||
1094 | spin_unlock(&lowest_rq->lock); | 1096 | double_unlock_balance(rq, lowest_rq); |
1095 | 1097 | ||
1096 | ret = 1; | 1098 | ret = 1; |
1097 | out: | 1099 | out: |
@@ -1197,7 +1199,7 @@ static int pull_rt_task(struct rq *this_rq) | |||
1197 | 1199 | ||
1198 | } | 1200 | } |
1199 | skip: | 1201 | skip: |
1200 | spin_unlock(&src_rq->lock); | 1202 | double_unlock_balance(this_rq, src_rq); |
1201 | } | 1203 | } |
1202 | 1204 | ||
1203 | return ret; | 1205 | return ret; |