Commit 5fe1d75f authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

[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: default avatarOleg 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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c9472e0f
...@@ -4080,6 +4080,8 @@ static void __setscheduler(struct task_struct *p, int policy, int prio) ...@@ -4080,6 +4080,8 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
* @p: the task in question. * @p: the task in question.
* @policy: new policy. * @policy: new policy.
* @param: structure containing the new RT priority. * @param: structure containing the new RT priority.
*
* NOTE: the task may be already dead
*/ */
int sched_setscheduler(struct task_struct *p, int policy, int sched_setscheduler(struct task_struct *p, int policy,
struct sched_param *param) struct sched_param *param)
...@@ -4115,19 +4117,26 @@ recheck: ...@@ -4115,19 +4117,26 @@ recheck:
* Allow unprivileged RT tasks to decrease priority: * Allow unprivileged RT tasks to decrease priority:
*/ */
if (!capable(CAP_SYS_NICE)) { if (!capable(CAP_SYS_NICE)) {
unsigned long rlim_rtprio;
unsigned long flags;
if (!lock_task_sighand(p, &flags))
return -ESRCH;
rlim_rtprio = p->signal->rlim[RLIMIT_RTPRIO].rlim_cur;
unlock_task_sighand(p, &flags);
/* /*
* can't change policy, except between SCHED_NORMAL * can't change policy, except between SCHED_NORMAL
* and SCHED_BATCH: * and SCHED_BATCH:
*/ */
if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) && if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
(policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) && (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&
!p->signal->rlim[RLIMIT_RTPRIO].rlim_cur) !rlim_rtprio)
return -EPERM; return -EPERM;
/* can't increase priority */ /* can't increase priority */
if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) && if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) &&
param->sched_priority > p->rt_priority && param->sched_priority > p->rt_priority &&
param->sched_priority > param->sched_priority > rlim_rtprio)
p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
return -EPERM; return -EPERM;
/* can't change other user's priorities */ /* can't change other user's priorities */
if ((current->euid != p->euid) && if ((current->euid != p->euid) &&
...@@ -4193,14 +4202,13 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) ...@@ -4193,14 +4202,13 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
return -EINVAL; return -EINVAL;
if (copy_from_user(&lparam, param, sizeof(struct sched_param))) if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
return -EFAULT; return -EFAULT;
read_lock_irq(&tasklist_lock);
rcu_read_lock();
retval = -ESRCH;
p = find_process_by_pid(pid); p = find_process_by_pid(pid);
if (!p) { if (p != NULL)
read_unlock_irq(&tasklist_lock); retval = sched_setscheduler(p, policy, &lparam);
return -ESRCH; rcu_read_unlock();
}
retval = sched_setscheduler(p, policy, &lparam);
read_unlock_irq(&tasklist_lock);
return retval; return retval;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment