[S390] stacktrace bug.
[safe/jmp/linux-2.6] / arch / s390 / kernel / process.c
index 7dd58f8..6603fbb 100644 (file)
@@ -15,7 +15,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <linux/config.h>
 #include <linux/compiler.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
@@ -46,7 +45,7 @@
 #include <asm/irq.h>
 #include <asm/timer.h>
 
-asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
 
 /*
  * Return saved PC of a blocked thread. used in kernel/sched.
@@ -58,27 +57,35 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
  */
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-       struct stack_frame *sf;
+       struct stack_frame *sf, *low, *high;
 
-       sf = (struct stack_frame *) tsk->thread.ksp;
-       sf = (struct stack_frame *) sf->back_chain;
+       if (!tsk || !task_stack_page(tsk))
+               return 0;
+       low = task_stack_page(tsk);
+       high = (struct stack_frame *) task_pt_regs(tsk);
+       sf = (struct stack_frame *) (tsk->thread.ksp & PSW_ADDR_INSN);
+       if (sf <= low || sf > high)
+               return 0;
+       sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
+       if (sf <= low || sf > high)
+               return 0;
        return sf->gprs[8];
 }
 
 /*
  * Need to know about CPUs going idle?
  */
-static struct notifier_block *idle_chain;
+static ATOMIC_NOTIFIER_HEAD(idle_chain);
 
 int register_idle_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_register(&idle_chain, nb);
+       return atomic_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);
+       return atomic_notifier_chain_unregister(&idle_chain, nb);
 }
 EXPORT_SYMBOL(unregister_idle_notifier);
 
@@ -87,7 +94,7 @@ 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,
+       atomic_notifier_call_chain(&idle_chain, CPU_NOT_IDLE,
                            (void *)(long) smp_processor_id());
 }
 
@@ -95,7 +102,7 @@ extern void s390_handle_mcck(void);
 /*
  * The idle loop on a S390...
  */
-void default_idle(void)
+static void default_idle(void)
 {
        int cpu, rc;
 
@@ -108,7 +115,8 @@ void default_idle(void)
                return;
        }
 
-       rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
+       rc = atomic_notifier_call_chain(&idle_chain,
+                       CPU_IDLE, (void *)(long) cpu);
        if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
                BUG();
        if (rc != NOTIFY_OK) {
@@ -120,8 +128,10 @@ void default_idle(void)
        __ctl_set_bit(8, 15);
 
 #ifdef CONFIG_HOTPLUG_CPU
-       if (cpu_is_offline(cpu))
+       if (cpu_is_offline(cpu)) {
+               preempt_enable_no_resched();
                cpu_die();
+       }
 #endif
 
        local_mcck_disable();
@@ -132,6 +142,7 @@ void default_idle(void)
                return;
        }
 
+       trace_hardirqs_on();
        /* Wait for external, I/O or machine check interrupt. */
        __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
                        PSW_MASK_IO | PSW_MASK_EXT);
@@ -153,7 +164,7 @@ void show_regs(struct pt_regs *regs)
 {
        struct task_struct *tsk = current;
 
-        printk("CPU:    %d    %s\n", tsk->thread_info->cpu, print_tainted());
+        printk("CPU:    %d    %s\n", task_thread_info(tsk)->cpu, print_tainted());
         printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
               current->comm, current->pid, (void *) tsk,
               (void *) tsk->thread.ksp);
@@ -161,12 +172,13 @@ void show_regs(struct pt_regs *regs)
        show_registers(regs);
        /* Show stack backtrace if pt_regs is from kernel mode */
        if (!(regs->psw.mask & PSW_MASK_PSTATE))
-               show_trace(0,(unsigned long *) regs->gprs[15]);
+               show_trace(NULL, (unsigned long *) regs->gprs[15]);
 }
 
 extern void kernel_thread_starter(void);
 
-__asm__(".align 4\n"
+asm(
+       ".align 4\n"
        "kernel_thread_starter:\n"
        "    la    2,0(10)\n"
        "    basr  14,9\n"
@@ -217,8 +229,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
             struct pt_regs childregs;
           } *frame;
 
-        frame = ((struct fake_frame *)
-                (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
+        frame = container_of(task_pt_regs(p), struct fake_frame, childregs);
         p->thread.ksp = (unsigned long) frame;
        /* Store access registers to kernel stack of new process. */
         frame->childregs = *regs;
@@ -358,11 +369,10 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long return_address;
        int count;
 
-       if (!p || p == current || p->state == TASK_RUNNING || !p->thread_info)
+       if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p))
                return 0;
-       low = (struct stack_frame *) p->thread_info;
-       high = (struct stack_frame *)
-               ((unsigned long) p->thread_info + THREAD_SIZE) - 1;
+       low = task_stack_page(p);
+       high = (struct stack_frame *) task_pt_regs(p);
        sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN);
        if (sf <= low || sf > high)
                return 0;