diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-09-29 05:00:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-29 12:18:17 -0400 |
commit | 5fe1d75f34974046fffcca5e22fb8a7b42fded33 (patch) | |
tree | 831e360aa8d7d37c7c5202937a2f617ebea6e737 /kernel/sched.c | |
parent | c9472e0f28cd2f0695a0ac3a0b4bd33f21714a7e (diff) |
[PATCH] do_sched_setscheduler(): don't take tasklist_lock
Use rcu locks instead. sched_setscheduler() now takes ->siglock
before reading ->signal->rlim[].
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index b946209d9c15..f9b3c6a414f1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -4080,6 +4080,8 @@ static void __setscheduler(struct task_struct *p, int policy, int prio) | |||
4080 | * @p: the task in question. | 4080 | * @p: the task in question. |
4081 | * @policy: new policy. | 4081 | * @policy: new policy. |
4082 | * @param: structure containing the new RT priority. | 4082 | * @param: structure containing the new RT priority. |
4083 | * | ||
4084 | * NOTE: the task may be already dead | ||
4083 | */ | 4085 | */ |
4084 | int sched_setscheduler(struct task_struct *p, int policy, | 4086 | int sched_setscheduler(struct task_struct *p, int policy, |
4085 | struct sched_param *param) | 4087 | struct sched_param *param) |
@@ -4115,19 +4117,26 @@ recheck: | |||
4115 | * Allow unprivileged RT tasks to decrease priority: | 4117 | * Allow unprivileged RT tasks to decrease priority: |
4116 | */ | 4118 | */ |
4117 | if (!capable(CAP_SYS_NICE)) { | 4119 | if (!capable(CAP_SYS_NICE)) { |
4120 | unsigned long rlim_rtprio; | ||
4121 | unsigned long flags; | ||
4122 | |||
4123 | if (!lock_task_sighand(p, &flags)) | ||
4124 | return -ESRCH; | ||
4125 | rlim_rtprio = p->signal->rlim[RLIMIT_RTPRIO].rlim_cur; | ||
4126 | unlock_task_sighand(p, &flags); | ||
4127 | |||
4118 | /* | 4128 | /* |
4119 | * can't change policy, except between SCHED_NORMAL | 4129 | * can't change policy, except between SCHED_NORMAL |
4120 | * and SCHED_BATCH: | 4130 | * and SCHED_BATCH: |
4121 | */ | 4131 | */ |
4122 | if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) && | 4132 | if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) && |
4123 | (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) && | 4133 | (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) && |
4124 | !p->signal->rlim[RLIMIT_RTPRIO].rlim_cur) | 4134 | !rlim_rtprio) |
4125 | return -EPERM; | 4135 | return -EPERM; |
4126 | /* can't increase priority */ | 4136 | /* can't increase priority */ |
4127 | if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) && | 4137 | if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) && |
4128 | param->sched_priority > p->rt_priority && | 4138 | param->sched_priority > p->rt_priority && |
4129 | param->sched_priority > | 4139 | param->sched_priority > rlim_rtprio) |
4130 | p->signal->rlim[RLIMIT_RTPRIO].rlim_cur) | ||
4131 | return -EPERM; | 4140 | return -EPERM; |
4132 | /* can't change other user's priorities */ | 4141 | /* can't change other user's priorities */ |
4133 | if ((current->euid != p->euid) && | 4142 | if ((current->euid != p->euid) && |
@@ -4193,14 +4202,13 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) | |||
4193 | return -EINVAL; | 4202 | return -EINVAL; |
4194 | if (copy_from_user(&lparam, param, sizeof(struct sched_param))) | 4203 | if (copy_from_user(&lparam, param, sizeof(struct sched_param))) |
4195 | return -EFAULT; | 4204 | return -EFAULT; |
4196 | read_lock_irq(&tasklist_lock); | 4205 | |
4206 | rcu_read_lock(); | ||
4207 | retval = -ESRCH; | ||
4197 | p = find_process_by_pid(pid); | 4208 | p = find_process_by_pid(pid); |
4198 | if (!p) { | 4209 | if (p != NULL) |
4199 | read_unlock_irq(&tasklist_lock); | 4210 | retval = sched_setscheduler(p, policy, &lparam); |
4200 | return -ESRCH; | 4211 | rcu_read_unlock(); |
4201 | } | ||
4202 | retval = sched_setscheduler(p, policy, &lparam); | ||
4203 | read_unlock_irq(&tasklist_lock); | ||
4204 | 4212 | ||
4205 | return retval; | 4213 | return retval; |
4206 | } | 4214 | } |