]> Pileus Git - ~andy/linux/blobdiff - kernel/sched.c
Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6
[~andy/linux] / kernel / sched.c
index 90d22b72cf814ba2e9406a919d62fd6741489779..238a76957e86cc6c9ae982ba85db87159662fea5 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/percpu.h>
 #include <linux/kthread.h>
 #include <linux/seq_file.h>
+#include <linux/sysctl.h>
 #include <linux/syscalls.h>
 #include <linux/times.h>
 #include <linux/tsacct_kern.h>
@@ -263,8 +264,6 @@ struct rq {
        unsigned int clock_warps, clock_overflows;
        unsigned int clock_unstable_events;
 
-       struct sched_class *load_balance_class;
-
        atomic_t nr_iowait;
 
 #ifdef CONFIG_SMP
@@ -301,7 +300,7 @@ struct rq {
        struct lock_class_key rq_lock_key;
 };
 
-static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 static DEFINE_MUTEX(sched_hotcpu_mutex);
 
 static inline void check_preempt_curr(struct rq *rq, struct task_struct *p)
@@ -379,6 +378,22 @@ static inline unsigned long long rq_clock(struct rq *rq)
 #define task_rq(p)             cpu_rq(task_cpu(p))
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 
+/*
+ * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
+ * clock constructed from sched_clock():
+ */
+unsigned long long cpu_clock(int cpu)
+{
+       unsigned long long now;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       now = rq_clock(cpu_rq(cpu));
+       local_irq_restore(flags);
+
+       return now;
+}
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 /* Change a task's ->cfs_rq if it moves across CPUs */
 static inline void set_task_cfs_rq(struct task_struct *p)
@@ -756,14 +771,14 @@ static const int prio_to_weight[40] = {
  * into multiplications:
  */
 static const u32 prio_to_wmult[40] = {
-       48356,   60446,   75558,   94446,  118058,  147573,
-       184467,  230589,  288233,  360285,  450347,
-       562979,  703746,  879575, 1099582, 1374389,
-       1717986, 2147483, 2684354, 3355443, 4194304,
-       5244160, 6557201, 8196502, 10250518, 12782640,
-       16025997, 19976592, 24970740, 31350126, 39045157,
-       49367440, 61356675, 76695844, 95443717, 119304647,
-       148102320, 186737708, 238609294, 286331153,
+/* -20 */     48356,     60446,     75558,     94446,    118058,
+/* -15 */    147573,    184467,    230589,    288233,    360285,
+/* -10 */    450347,    562979,    703746,    879575,   1099582,
+/*  -5 */   1374389,   1717986,   2147483,   2684354,   3355443,
+/*   0 */   4194304,   5244160,   6557201,   8196502,  10250518,
+/*   5 */  12782640,  16025997,  19976592,  24970740,  31350126,
+/*  10 */  39045157,  49367440,  61356675,  76695844,  95443717,
+/*  15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
 };
 
 static inline void
@@ -1575,6 +1590,10 @@ static void __sched_fork(struct task_struct *p)
        INIT_LIST_HEAD(&p->run_list);
        p->se.on_rq = 0;
 
+#ifdef CONFIG_PREEMPT_NOTIFIERS
+       INIT_HLIST_HEAD(&p->preempt_notifiers);
+#endif
+
        /*
         * We mark the process as running here, but have not actually
         * inserted it onto the runqueue yet. This guarantees that
@@ -1656,9 +1675,68 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
        task_rq_unlock(rq, &flags);
 }
 
+#ifdef CONFIG_PREEMPT_NOTIFIERS
+
+/**
+ * preempt_notifier_register - tell me when current is being being preempted & rescheduled
+ * @notifier: notifier struct to register
+ */
+void preempt_notifier_register(struct preempt_notifier *notifier)
+{
+       hlist_add_head(&notifier->link, &current->preempt_notifiers);
+}
+EXPORT_SYMBOL_GPL(preempt_notifier_register);
+
+/**
+ * preempt_notifier_unregister - no longer interested in preemption notifications
+ * @notifier: notifier struct to unregister
+ *
+ * This is safe to call from within a preemption notifier.
+ */
+void preempt_notifier_unregister(struct preempt_notifier *notifier)
+{
+       hlist_del(&notifier->link);
+}
+EXPORT_SYMBOL_GPL(preempt_notifier_unregister);
+
+static void fire_sched_in_preempt_notifiers(struct task_struct *curr)
+{
+       struct preempt_notifier *notifier;
+       struct hlist_node *node;
+
+       hlist_for_each_entry(notifier, node, &curr->preempt_notifiers, link)
+               notifier->ops->sched_in(notifier, raw_smp_processor_id());
+}
+
+static void
+fire_sched_out_preempt_notifiers(struct task_struct *curr,
+                                struct task_struct *next)
+{
+       struct preempt_notifier *notifier;
+       struct hlist_node *node;
+
+       hlist_for_each_entry(notifier, node, &curr->preempt_notifiers, link)
+               notifier->ops->sched_out(notifier, next);
+}
+
+#else
+
+static void fire_sched_in_preempt_notifiers(struct task_struct *curr)
+{
+}
+
+static void
+fire_sched_out_preempt_notifiers(struct task_struct *curr,
+                                struct task_struct *next)
+{
+}
+
+#endif
+
 /**
  * prepare_task_switch - prepare to switch tasks
  * @rq: the runqueue preparing to switch
+ * @prev: the current task that is being switched out
  * @next: the task we are going to switch to.
  *
  * This is called with the rq lock held and interrupts off. It must
@@ -1668,8 +1746,11 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
  * prepare_task_switch sets up locking and calls architecture specific
  * hooks.
  */
-static inline void prepare_task_switch(struct rq *rq, struct task_struct *next)
+static inline void
+prepare_task_switch(struct rq *rq, struct task_struct *prev,
+                   struct task_struct *next)
 {
+       fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
 }
@@ -1711,6 +1792,7 @@ static inline void finish_task_switch(struct rq *rq, struct task_struct *prev)
        prev_state = prev->state;
        finish_arch_switch(prev);
        finish_lock_switch(rq, prev);
+       fire_sched_in_preempt_notifiers(current);
        if (mm)
                mmdrop(mm);
        if (unlikely(prev_state == TASK_DEAD)) {
@@ -1751,7 +1833,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
 {
        struct mm_struct *mm, *oldmm;
 
-       prepare_task_switch(rq, next);
+       prepare_task_switch(rq, prev, next);
        mm = next->mm;
        oldmm = prev->active_mm;
        /*
@@ -2235,7 +2317,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
 
                        rq = cpu_rq(i);
 
-                       if (*sd_idle && !idle_cpu(i))
+                       if (*sd_idle && rq->nr_running)
                                *sd_idle = 0;
 
                        /* Bias balancing toward cpus of our domain */
@@ -2257,9 +2339,11 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                /*
                 * First idle cpu or the first cpu(busiest) in this sched group
                 * is eligible for doing load balancing at this and above
-                * domains.
+                * domains. In the newly idle case, we will allow all the cpu's
+                * to do the newly idle load balance.
                 */
-               if (local_group && balance_cpu != this_cpu && balance) {
+               if (idle != CPU_NEWLY_IDLE && local_group &&
+                   balance_cpu != this_cpu && balance) {
                        *balance = 0;
                        goto ret;
                }
@@ -2677,6 +2761,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
        unsigned long imbalance;
        int nr_moved = 0;
        int sd_idle = 0;
+       int all_pinned = 0;
        cpumask_t cpus = CPU_MASK_ALL;
 
        /*
@@ -2715,10 +2800,11 @@ redo:
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
                                        minus_1_or_zero(busiest->nr_running),
-                                       imbalance, sd, CPU_NEWLY_IDLE, NULL);
+                                       imbalance, sd, CPU_NEWLY_IDLE,
+                                       &all_pinned);
                spin_unlock(&busiest->lock);
 
-               if (!nr_moved) {
+               if (unlikely(all_pinned)) {
                        cpu_clear(cpu_of(busiest), cpus);
                        if (!cpus_empty(cpus))
                                goto redo;
@@ -4912,8 +4998,6 @@ static int migration_thread(void *data)
                struct migration_req *req;
                struct list_head *head;
 
-               try_to_freeze();
-
                spin_lock_irq(&rq->lock);
 
                if (cpu_is_offline(cpu)) {
@@ -5121,10 +5205,129 @@ static void migrate_dead_tasks(unsigned int dead_cpu)
                if (!next)
                        break;
                migrate_dead(dead_cpu, next);
+
        }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
+#if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL)
+
+static struct ctl_table sd_ctl_dir[] = {
+       {CTL_UNNUMBERED, "sched_domain", NULL, 0, 0755, NULL, },
+       {0,},
+};
+
+static struct ctl_table sd_ctl_root[] = {
+       {CTL_UNNUMBERED, "kernel", NULL, 0, 0755, sd_ctl_dir, },
+       {0,},
+};
+
+static struct ctl_table *sd_alloc_ctl_entry(int n)
+{
+       struct ctl_table *entry =
+               kmalloc(n * sizeof(struct ctl_table), GFP_KERNEL);
+
+       BUG_ON(!entry);
+       memset(entry, 0, n * sizeof(struct ctl_table));
+
+       return entry;
+}
+
+static void
+set_table_entry(struct ctl_table *entry, int ctl_name,
+               const char *procname, void *data, int maxlen,
+               mode_t mode, proc_handler *proc_handler)
+{
+       entry->ctl_name = ctl_name;
+       entry->procname = procname;
+       entry->data = data;
+       entry->maxlen = maxlen;
+       entry->mode = mode;
+       entry->proc_handler = proc_handler;
+}
+
+static struct ctl_table *
+sd_alloc_ctl_domain_table(struct sched_domain *sd)
+{
+       struct ctl_table *table = sd_alloc_ctl_entry(14);
+
+       set_table_entry(&table[0], 1, "min_interval", &sd->min_interval,
+               sizeof(long), 0644, proc_doulongvec_minmax);
+       set_table_entry(&table[1], 2, "max_interval", &sd->max_interval,
+               sizeof(long), 0644, proc_doulongvec_minmax);
+       set_table_entry(&table[2], 3, "busy_idx", &sd->busy_idx,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[3], 4, "idle_idx", &sd->idle_idx,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[4], 5, "newidle_idx", &sd->newidle_idx,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[5], 6, "wake_idx", &sd->wake_idx,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[6], 7, "forkexec_idx", &sd->forkexec_idx,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[7], 8, "busy_factor", &sd->busy_factor,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[8], 9, "imbalance_pct", &sd->imbalance_pct,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[9], 10, "cache_hot_time", &sd->cache_hot_time,
+               sizeof(long long), 0644, proc_doulongvec_minmax);
+       set_table_entry(&table[10], 11, "cache_nice_tries",
+               &sd->cache_nice_tries,
+               sizeof(int), 0644, proc_dointvec_minmax);
+       set_table_entry(&table[12], 13, "flags", &sd->flags,
+               sizeof(int), 0644, proc_dointvec_minmax);
+
+       return table;
+}
+
+static ctl_table *sd_alloc_ctl_cpu_table(int cpu)
+{
+       struct ctl_table *entry, *table;
+       struct sched_domain *sd;
+       int domain_num = 0, i;
+       char buf[32];
+
+       for_each_domain(cpu, sd)
+               domain_num++;
+       entry = table = sd_alloc_ctl_entry(domain_num + 1);
+
+       i = 0;
+       for_each_domain(cpu, sd) {
+               snprintf(buf, 32, "domain%d", i);
+               entry->ctl_name = i + 1;
+               entry->procname = kstrdup(buf, GFP_KERNEL);
+               entry->mode = 0755;
+               entry->child = sd_alloc_ctl_domain_table(sd);
+               entry++;
+               i++;
+       }
+       return table;
+}
+
+static struct ctl_table_header *sd_sysctl_header;
+static void init_sched_domain_sysctl(void)
+{
+       int i, cpu_num = num_online_cpus();
+       struct ctl_table *entry = sd_alloc_ctl_entry(cpu_num + 1);
+       char buf[32];
+
+       sd_ctl_dir[0].child = entry;
+
+       for (i = 0; i < cpu_num; i++, entry++) {
+               snprintf(buf, 32, "cpu%d", i);
+               entry->ctl_name = i + 1;
+               entry->procname = kstrdup(buf, GFP_KERNEL);
+               entry->mode = 0755;
+               entry->child = sd_alloc_ctl_cpu_table(i);
+       }
+       sd_sysctl_header = register_sysctl_table(sd_ctl_root);
+}
+#else
+static void init_sched_domain_sysctl(void)
+{
+}
+#endif
+
 /*
  * migration_call - callback that gets triggered when a CPU is added.
  * Here we can start up the necessary migration thread for the new CPU.
@@ -5147,7 +5350,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                p = kthread_create(migration_thread, hcpu, "migration/%d", cpu);
                if (IS_ERR(p))
                        return NOTIFY_BAD;
-               p->flags |= PF_NOFREEZE;
                kthread_bind(p, cpu);
                /* Must be high prio: stop_machine expects to yield to it. */
                rq = task_rq_lock(p, &flags);
@@ -6231,6 +6433,8 @@ void __init sched_init_smp(void)
        /* XXX: Theoretical race here - CPU may be hotplugged now */
        hotcpu_notifier(update_sched_domains, 0);
 
+       init_sched_domain_sysctl();
+
        /* Move init over to a non-isolated CPU */
        if (set_cpus_allowed(current, non_isolated_cpus) < 0)
                BUG();
@@ -6317,6 +6521,10 @@ void __init sched_init(void)
 
        set_load_weight(&init_task);
 
+#ifdef CONFIG_PREEMPT_NOTIFIERS
+       INIT_HLIST_HEAD(&init_task.preempt_notifiers);
+#endif
+
 #ifdef CONFIG_SMP
        nr_cpu_ids = highest_cpu + 1;
        open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL);