VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / s390 / kernel / process.c
index 252e652..73cb6ba 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 #include <linux/config.h>
+#include <linux/compiler.h>
+#include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -33,6 +35,8 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -40,9 +44,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
-#if defined(CONFIG_VIRT_TIMER) || defined (CONFIG_NO_IDLE_HZ)
 #include <asm/timer.h>
-#endif
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
@@ -67,13 +69,39 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 }
 
 /*
- * The idle loop on a S390...
+ * Need to know about CPUs going idle?
  */
+static struct notifier_block *idle_chain;
+
+int register_idle_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_register(&idle_chain, nb);
+}
+EXPORT_SYMBOL(register_idle_notifier);
 
+int unregister_idle_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_unregister(&idle_chain, nb);
+}
+EXPORT_SYMBOL(unregister_idle_notifier);
+
+void do_monitor_call(struct pt_regs *regs, long interruption_code)
+{
+       /* disable monitor call class 0 */
+       __ctl_clear_bit(8, 15);
+
+       notifier_call_chain(&idle_chain, CPU_NOT_IDLE,
+                           (void *)(long) smp_processor_id());
+}
+
+/*
+ * The idle loop on a S390...
+ */
 void default_idle(void)
 {
        psw_t wait_psw;
        unsigned long reg;
+       int cpu, rc;
 
        local_irq_disable();
         if (need_resched()) {
@@ -82,14 +110,22 @@ void default_idle(void)
                 return;
         }
 
-#if defined(CONFIG_VIRT_TIMER) || defined (CONFIG_NO_IDLE_HZ)
-       /*
-        * hook to stop timers that should not tick while CPU is idle
-        */
-       if (stop_timers()) {
+       /* CPU is going idle. */
+       cpu = smp_processor_id();
+       rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
+       if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
+               BUG();
+       if (rc != NOTIFY_OK) {
                local_irq_enable();
                return;
        }
+
+       /* enable monitor call class 0 */
+       __ctl_set_bit(8, 15);
+
+#ifdef CONFIG_HOTPLUG_CPU
+       if (cpu_is_offline(smp_processor_id()))
+               cpu_die();
 #endif
 
        /* 
@@ -292,12 +328,12 @@ asmlinkage long sys_clone(struct pt_regs regs)
 {
         unsigned long clone_flags;
         unsigned long newsp;
-       int *parent_tidptr, *child_tidptr;
+       int __user *parent_tidptr, *child_tidptr;
 
         clone_flags = regs.gprs[3];
         newsp = regs.orig_gpr2;
-       parent_tidptr = (int *) regs.gprs[4];
-       child_tidptr = (int *) regs.gprs[5];
+       parent_tidptr = (int __user *) regs.gprs[4];
+       child_tidptr = (int __user *) regs.gprs[5];
         if (!newsp)
                 newsp = regs.gprs[15];
         return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
@@ -328,12 +364,12 @@ asmlinkage long sys_execve(struct pt_regs regs)
         int error;
         char * filename;
 
-        filename = getname((char *) regs.orig_gpr2);
+        filename = getname((char __user *) regs.orig_gpr2);
         error = PTR_ERR(filename);
         if (IS_ERR(filename))
                 goto out;
-        error = do_execve(filename, (char **) regs.gprs[3],
-                         (char **) regs.gprs[4], &regs);
+        error = do_execve(filename, (char __user * __user *) regs.gprs[3],
+                         (char __user * __user *) regs.gprs[4], &regs);
        if (error == 0) {
                current->ptrace &= ~PT_DTRACE;
                current->thread.fp_regs.fpc = 0;
@@ -385,12 +421,6 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
        dump->regs.per_info = current->thread.per_info;
 }
 
-/*
- * These bracket the sleeping functions..
- */
-#define first_sched    ((unsigned long) scheduling_functions_start_here)
-#define last_sched     ((unsigned long) scheduling_functions_end_here)
-
 unsigned long get_wchan(struct task_struct *p)
 {
        unsigned long r14, r15, bc;
@@ -413,12 +443,10 @@ unsigned long get_wchan(struct task_struct *p)
 #else
                r14 = *(unsigned long *) (bc+112);
 #endif
-               if (r14 < first_sched || r14 >= last_sched)
+               if (!in_sched_functions(r14))
                        return r14;
                bc = (*(unsigned long *) bc) & PSW_ADDR_INSN;
        } while (count++ < 16);
        return 0;
 }
-#undef last_sched
-#undef first_sched