Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / kernel / sched / core.c
index 5a31a85bbd84e9b89298cf908991eeb002656733..3da7a2444a911131589ce616147efd517c7bd354 100644 (file)
@@ -2046,7 +2046,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
         * If the owning (remote) CPU is still in the middle of schedule() with
         * this task as prev, wait until its done referencing the task.
         *
-        * Pairs with the smp_store_release() in finish_lock_switch().
+        * Pairs with the smp_store_release() in finish_task().
         *
         * This ensures that tasks getting woken will be fully ordered against
         * their previous state and preserve Program Order.
@@ -2572,6 +2572,50 @@ fire_sched_out_preempt_notifiers(struct task_struct *curr,
 
 #endif /* CONFIG_PREEMPT_NOTIFIERS */
 
+static inline void prepare_task(struct task_struct *next)
+{
+#ifdef CONFIG_SMP
+       /*
+        * Claim the task as running, we do this before switching to it
+        * such that any running task will have this set.
+        */
+       next->on_cpu = 1;
+#endif
+}
+
+static inline void finish_task(struct task_struct *prev)
+{
+#ifdef CONFIG_SMP
+       /*
+        * After ->on_cpu is cleared, the task can be moved to a different CPU.
+        * We must ensure this doesn't happen until the switch is completely
+        * finished.
+        *
+        * In particular, the load of prev->state in finish_task_switch() must
+        * happen before this.
+        *
+        * Pairs with the smp_cond_load_acquire() in try_to_wake_up().
+        */
+       smp_store_release(&prev->on_cpu, 0);
+#endif
+}
+
+static inline void finish_lock_switch(struct rq *rq)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+       /* this is a valid case when another task releases the spinlock */
+       rq->lock.owner = current;
+#endif
+       /*
+        * If we are tracking spinlock dependencies then we have to
+        * fix up the runqueue lock - which gets 'carried over' from
+        * prev into current:
+        */
+       spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_);
+
+       raw_spin_unlock_irq(&rq->lock);
+}
+
 /**
  * prepare_task_switch - prepare to switch tasks
  * @rq: the runqueue preparing to switch
@@ -2592,7 +2636,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
        sched_info_switch(rq, prev, next);
        perf_event_task_sched_out(prev, next);
        fire_sched_out_preempt_notifiers(prev, next);
-       prepare_lock_switch(rq, next);
+       prepare_task(next);
        prepare_arch_switch(next);
 }
 
@@ -2647,7 +2691,7 @@ static struct rq *finish_task_switch(struct task_struct *prev)
         * the scheduled task must drop that reference.
         *
         * We must observe prev->state before clearing prev->on_cpu (in
-        * finish_lock_switch), otherwise a concurrent wakeup can get prev
+        * finish_task), otherwise a concurrent wakeup can get prev
         * running on another CPU and we could rave with its RUNNING -> DEAD
         * transition, resulting in a double drop.
         */
@@ -2664,7 +2708,8 @@ static struct rq *finish_task_switch(struct task_struct *prev)
         * to use.
         */
        smp_mb__after_unlock_lock();
-       finish_lock_switch(rq, prev);
+       finish_task(prev);
+       finish_lock_switch(rq);
        finish_arch_post_lock_switch();
 
        fire_sched_in_preempt_notifiers(current);
@@ -4041,8 +4086,7 @@ recheck:
                        return -EINVAL;
        }
 
-       if (attr->sched_flags &
-               ~(SCHED_FLAG_RESET_ON_FORK | SCHED_FLAG_RECLAIM))
+       if (attr->sched_flags & ~(SCHED_FLAG_ALL | SCHED_FLAG_SUGOV))
                return -EINVAL;
 
        /*
@@ -4109,6 +4153,9 @@ recheck:
        }
 
        if (user) {
+               if (attr->sched_flags & SCHED_FLAG_SUGOV)
+                       return -EINVAL;
+
                retval = security_task_setscheduler(p);
                if (retval)
                        return retval;
@@ -4164,7 +4211,8 @@ change:
                }
 #endif
 #ifdef CONFIG_SMP
-               if (dl_bandwidth_enabled() && dl_policy(policy)) {
+               if (dl_bandwidth_enabled() && dl_policy(policy) &&
+                               !(attr->sched_flags & SCHED_FLAG_SUGOV)) {
                        cpumask_t *span = rq->rd->span;
 
                        /*
@@ -4294,6 +4342,11 @@ int sched_setattr(struct task_struct *p, const struct sched_attr *attr)
 }
 EXPORT_SYMBOL_GPL(sched_setattr);
 
+int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr)
+{
+       return __sched_setscheduler(p, attr, false, true);
+}
+
 /**
  * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace.
  * @p: the task in question.