Commit 0cc0f9fc authored by Dean Nelson's avatar Dean Nelson Committed by Linus Torvalds

[PATCH] export sched_setscheduler() for kernel module use

This patch exports sched_setscheduler() so that it can be used by a kernel
module to set a kthread's scheduling policy and associated parameters.
Signed-off-by: default avatarDean Nelson <dcn@sgi.com>
Acked-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 38ff2da8
...@@ -761,6 +761,7 @@ extern int task_prio(const task_t *p); ...@@ -761,6 +761,7 @@ extern int task_prio(const task_t *p);
extern int task_nice(const task_t *p); extern int task_nice(const task_t *p);
extern int task_curr(const task_t *p); extern int task_curr(const task_t *p);
extern int idle_cpu(int cpu); extern int idle_cpu(int cpu);
extern int sched_setscheduler(struct task_struct *, int, struct sched_param *);
void yield(void); void yield(void);
......
...@@ -2940,7 +2940,7 @@ void set_user_nice(task_t *p, long nice) ...@@ -2940,7 +2940,7 @@ void set_user_nice(task_t *p, long nice)
*/ */
rq = task_rq_lock(p, &flags); rq = task_rq_lock(p, &flags);
/* /*
* The RT priorities are set via setscheduler(), but we still * The RT priorities are set via sched_setscheduler(), but we still
* allow the 'normal' nice value to be set - but as expected * allow the 'normal' nice value to be set - but as expected
* it wont have any effect on scheduling until the task is * it wont have any effect on scheduling until the task is
* not SCHED_NORMAL: * not SCHED_NORMAL:
...@@ -3072,67 +3072,48 @@ static void __setscheduler(struct task_struct *p, int policy, int prio) ...@@ -3072,67 +3072,48 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
p->prio = p->static_prio; p->prio = p->static_prio;
} }
/* /**
* setscheduler - change the scheduling policy and/or RT priority of a thread. * sched_setscheduler - change the scheduling policy and/or RT priority of
* a thread.
* @p: the task in question.
* @policy: new policy.
* @param: structure containing the new RT priority.
*/ */
static int setscheduler(pid_t pid, int policy, struct sched_param __user *param) int sched_setscheduler(struct task_struct *p, int policy, struct sched_param *param)
{ {
struct sched_param lp; int retval;
int retval = -EINVAL;
int oldprio, oldpolicy = -1; int oldprio, oldpolicy = -1;
prio_array_t *array; prio_array_t *array;
unsigned long flags; unsigned long flags;
runqueue_t *rq; runqueue_t *rq;
task_t *p;
if (!param || pid < 0)
goto out_nounlock;
retval = -EFAULT;
if (copy_from_user(&lp, param, sizeof(struct sched_param)))
goto out_nounlock;
/*
* We play safe to avoid deadlocks.
*/
read_lock_irq(&tasklist_lock);
p = find_process_by_pid(pid);
retval = -ESRCH;
if (!p)
goto out_unlock;
recheck: recheck:
/* double check policy once rq lock held */ /* double check policy once rq lock held */
if (policy < 0) if (policy < 0)
policy = oldpolicy = p->policy; policy = oldpolicy = p->policy;
else { else if (policy != SCHED_FIFO && policy != SCHED_RR &&
retval = -EINVAL;
if (policy != SCHED_FIFO && policy != SCHED_RR &&
policy != SCHED_NORMAL) policy != SCHED_NORMAL)
goto out_unlock; return -EINVAL;
}
/* /*
* Valid priorities for SCHED_FIFO and SCHED_RR are * Valid priorities for SCHED_FIFO and SCHED_RR are
* 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL is 0. * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL is 0.
*/ */
retval = -EINVAL; if (param->sched_priority < 0 ||
if (lp.sched_priority < 0 || lp.sched_priority > MAX_USER_RT_PRIO-1) param->sched_priority > MAX_USER_RT_PRIO-1)
goto out_unlock; return -EINVAL;
if ((policy == SCHED_NORMAL) != (lp.sched_priority == 0)) if ((policy == SCHED_NORMAL) != (param->sched_priority == 0))
goto out_unlock; return -EINVAL;
retval = -EPERM;
if ((policy == SCHED_FIFO || policy == SCHED_RR) && if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
!capable(CAP_SYS_NICE)) !capable(CAP_SYS_NICE))
goto out_unlock; return -EPERM;
if ((current->euid != p->euid) && (current->euid != p->uid) && if ((current->euid != p->euid) && (current->euid != p->uid) &&
!capable(CAP_SYS_NICE)) !capable(CAP_SYS_NICE))
goto out_unlock; return -EPERM;
retval = security_task_setscheduler(p, policy, &lp); retval = security_task_setscheduler(p, policy, param);
if (retval) if (retval)
goto out_unlock; return retval;
/* /*
* To be able to change p->policy safely, the apropriate * To be able to change p->policy safely, the apropriate
* runqueue lock must be held. * runqueue lock must be held.
...@@ -3147,9 +3128,8 @@ static int setscheduler(pid_t pid, int policy, struct sched_param __user *param) ...@@ -3147,9 +3128,8 @@ static int setscheduler(pid_t pid, int policy, struct sched_param __user *param)
array = p->array; array = p->array;
if (array) if (array)
deactivate_task(p, rq); deactivate_task(p, rq);
retval = 0;
oldprio = p->prio; oldprio = p->prio;
__setscheduler(p, policy, lp.sched_priority); __setscheduler(p, policy, param->sched_priority);
if (array) { if (array) {
__activate_task(p, rq); __activate_task(p, rq);
/* /*
...@@ -3164,22 +3144,41 @@ static int setscheduler(pid_t pid, int policy, struct sched_param __user *param) ...@@ -3164,22 +3144,41 @@ static int setscheduler(pid_t pid, int policy, struct sched_param __user *param)
resched_task(rq->curr); resched_task(rq->curr);
} }
task_rq_unlock(rq, &flags); task_rq_unlock(rq, &flags);
out_unlock: return 0;
}
EXPORT_SYMBOL_GPL(sched_setscheduler);
static int do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
{
int retval;
struct sched_param lparam;
struct task_struct *p;
if (!param || pid < 0)
return -EINVAL;
if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
return -EFAULT;
read_lock_irq(&tasklist_lock);
p = find_process_by_pid(pid);
if (!p) {
read_unlock_irq(&tasklist_lock);
return -ESRCH;
}
retval = sched_setscheduler(p, policy, &lparam);
read_unlock_irq(&tasklist_lock); read_unlock_irq(&tasklist_lock);
out_nounlock:
return retval; return retval;
} }
/** /**
* sys_sched_setscheduler - set/change the scheduler policy and RT priority * sys_sched_setscheduler - set/change the scheduler policy and RT priority
* @pid: the pid in question. * @pid: the pid in question.
* @policy: new policy * @policy: new policy.
* @param: structure containing the new RT priority. * @param: structure containing the new RT priority.
*/ */
asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
struct sched_param __user *param) struct sched_param __user *param)
{ {
return setscheduler(pid, policy, param); return do_sched_setscheduler(pid, policy, param);
} }
/** /**
...@@ -3189,7 +3188,7 @@ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, ...@@ -3189,7 +3188,7 @@ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
*/ */
asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param) asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param)
{ {
return setscheduler(pid, -1, param); return do_sched_setscheduler(pid, -1, param);
} }
/** /**
......
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