[PATCH] sched_setscheduler: fix? policy checks
authorOleg Nesterov <oleg@tv-sign.ru>
Fri, 29 Sep 2006 09:00:50 +0000 (02:00 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 29 Sep 2006 16:18:17 +0000 (09:18 -0700)
I am not sure this patch is correct: I can't understand what the current
code does, and I don't know what it was supposed to do.

The comment says:

 * can't change policy, except between SCHED_NORMAL
 * and SCHED_BATCH:

The code:

if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
(policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&

But this is equivalent to:

if ( (is_rt_policy(policy) && has_rt_policy(p)) &&

which means something different.  We can't _decrease_ the current
->rt_priority with such a check (if rlim[RLIMIT_RTPRIO] == 0).

Probably, it was supposed to be:

if ( !(policy == SCHED_NORMAL && p->policy == SCHED_BATCH)  &&
!(policy == SCHED_BATCH  && p->policy == SCHED_NORMAL)

this matches the comment, but strange: it doesn't allow to _drop_ the
realtime priority when rlim[RLIMIT_RTPRIO] == 0.

I think the right check would be:

/* can't set/change rt policy */
if (is_rt_policy(policy) &&
policy != p->policy &&
!rlim_rtprio)
return -EPERM;

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>
kernel/sched.c

index c3c718aea618c505247631ccde8ccd1c0c31d3b0..155a33da7aa76ca733977c9b934042551ca2e7f0 100644 (file)
@@ -4116,27 +4116,25 @@ recheck:
         * Allow unprivileged RT tasks to decrease priority:
         */
        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);
+               if (is_rt_policy(policy)) {
+                       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 set/change the rt policy */
+                       if (policy != p->policy && !rlim_rtprio)
+                               return -EPERM;
+
+                       /* can't increase priority */
+                       if (param->sched_priority > p->rt_priority &&
+                           param->sched_priority > rlim_rtprio)
+                               return -EPERM;
+               }
 
-               /*
-                * can't change policy, except between SCHED_NORMAL
-                * and SCHED_BATCH:
-                */
-               if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
-                       (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&
-                               !rlim_rtprio)
-                       return -EPERM;
-               /* can't increase priority */
-               if (is_rt_policy(policy) &&
-                   param->sched_priority > p->rt_priority &&
-                   param->sched_priority > rlim_rtprio)
-                       return -EPERM;
                /* can't change other user's priorities */
                if ((current->euid != p->euid) &&
                    (current->euid != p->uid))