| .. | .. |
|---|
| 37 | 37 | #include <asm/irq.h> |
|---|
| 38 | 38 | #include <asm/nmi.h> |
|---|
| 39 | 39 | #include <asm/smp.h> |
|---|
| 40 | +#include <asm/stacktrace.h> |
|---|
| 40 | 41 | #include <asm/switch_to.h> |
|---|
| 41 | 42 | #include <asm/runtime_instr.h> |
|---|
| 43 | +#include <asm/unwind.h> |
|---|
| 42 | 44 | #include "entry.h" |
|---|
| 43 | 45 | |
|---|
| 44 | 46 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); |
|---|
| .. | .. |
|---|
| 75 | 77 | |
|---|
| 76 | 78 | memcpy(dst, src, arch_task_struct_size); |
|---|
| 77 | 79 | dst->thread.fpu.regs = dst->thread.fpu.fprs; |
|---|
| 80 | + |
|---|
| 81 | + /* |
|---|
| 82 | + * Don't transfer over the runtime instrumentation or the guarded |
|---|
| 83 | + * storage control block pointers. These fields are cleared here instead |
|---|
| 84 | + * of in copy_thread() to avoid premature freeing of associated memory |
|---|
| 85 | + * on fork() failure. Wait to clear the RI flag because ->stack still |
|---|
| 86 | + * refers to the source thread. |
|---|
| 87 | + */ |
|---|
| 88 | + dst->thread.ri_cb = NULL; |
|---|
| 89 | + dst->thread.gs_cb = NULL; |
|---|
| 90 | + dst->thread.gs_bc_cb = NULL; |
|---|
| 91 | + |
|---|
| 78 | 92 | return 0; |
|---|
| 79 | 93 | } |
|---|
| 80 | 94 | |
|---|
| 81 | | -int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp, |
|---|
| 82 | | - unsigned long arg, struct task_struct *p, unsigned long tls) |
|---|
| 95 | +int copy_thread(unsigned long clone_flags, unsigned long new_stackp, |
|---|
| 96 | + unsigned long arg, struct task_struct *p, unsigned long tls) |
|---|
| 83 | 97 | { |
|---|
| 84 | 98 | struct fake_frame |
|---|
| 85 | 99 | { |
|---|
| .. | .. |
|---|
| 104 | 118 | p->thread.system_timer = 0; |
|---|
| 105 | 119 | p->thread.hardirq_timer = 0; |
|---|
| 106 | 120 | p->thread.softirq_timer = 0; |
|---|
| 121 | + p->thread.last_break = 1; |
|---|
| 107 | 122 | |
|---|
| 108 | 123 | frame->sf.back_chain = 0; |
|---|
| 109 | 124 | /* new return point is ret_from_fork */ |
|---|
| .. | .. |
|---|
| 112 | 127 | frame->sf.gprs[9] = (unsigned long) frame; |
|---|
| 113 | 128 | |
|---|
| 114 | 129 | /* Store access registers to kernel stack of new process. */ |
|---|
| 115 | | - if (unlikely(p->flags & PF_KTHREAD)) { |
|---|
| 130 | + if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { |
|---|
| 116 | 131 | /* kernel thread */ |
|---|
| 117 | 132 | memset(&frame->childregs, 0, sizeof(struct pt_regs)); |
|---|
| 118 | 133 | frame->childregs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT | |
|---|
| .. | .. |
|---|
| 131 | 146 | frame->childregs.flags = 0; |
|---|
| 132 | 147 | if (new_stackp) |
|---|
| 133 | 148 | frame->childregs.gprs[15] = new_stackp; |
|---|
| 134 | | - |
|---|
| 135 | | - /* Don't copy runtime instrumentation info */ |
|---|
| 136 | | - p->thread.ri_cb = NULL; |
|---|
| 149 | + /* |
|---|
| 150 | + * Clear the runtime instrumentation flag after the above childregs |
|---|
| 151 | + * copy. The CB pointer was already cleared in arch_dup_task_struct(). |
|---|
| 152 | + */ |
|---|
| 137 | 153 | frame->childregs.psw.mask &= ~PSW_MASK_RI; |
|---|
| 138 | | - /* Don't copy guarded storage control block */ |
|---|
| 139 | | - p->thread.gs_cb = NULL; |
|---|
| 140 | | - p->thread.gs_bc_cb = NULL; |
|---|
| 141 | 154 | |
|---|
| 142 | 155 | /* Set a new TLS ? */ |
|---|
| 143 | 156 | if (clone_flags & CLONE_SETTLS) { |
|---|
| .. | .. |
|---|
| 157 | 170 | asm volatile("sfpc %0" : : "d" (0)); |
|---|
| 158 | 171 | } |
|---|
| 159 | 172 | |
|---|
| 160 | | -/* |
|---|
| 161 | | - * fill in the FPU structure for a core dump. |
|---|
| 162 | | - */ |
|---|
| 163 | | -int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) |
|---|
| 164 | | -{ |
|---|
| 165 | | - save_fpu_regs(); |
|---|
| 166 | | - fpregs->fpc = current->thread.fpu.fpc; |
|---|
| 167 | | - fpregs->pad = 0; |
|---|
| 168 | | - if (MACHINE_HAS_VX) |
|---|
| 169 | | - convert_vx_to_fp((freg_t *)&fpregs->fprs, |
|---|
| 170 | | - current->thread.fpu.vxrs); |
|---|
| 171 | | - else |
|---|
| 172 | | - memcpy(&fpregs->fprs, current->thread.fpu.fprs, |
|---|
| 173 | | - sizeof(fpregs->fprs)); |
|---|
| 174 | | - return 1; |
|---|
| 175 | | -} |
|---|
| 176 | | -EXPORT_SYMBOL(dump_fpu); |
|---|
| 177 | | - |
|---|
| 178 | 173 | unsigned long get_wchan(struct task_struct *p) |
|---|
| 179 | 174 | { |
|---|
| 180 | | - struct stack_frame *sf, *low, *high; |
|---|
| 181 | | - unsigned long return_address; |
|---|
| 182 | | - int count; |
|---|
| 175 | + struct unwind_state state; |
|---|
| 176 | + unsigned long ip = 0; |
|---|
| 183 | 177 | |
|---|
| 184 | 178 | if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p)) |
|---|
| 185 | 179 | return 0; |
|---|
| .. | .. |
|---|
| 187 | 181 | if (!try_get_task_stack(p)) |
|---|
| 188 | 182 | return 0; |
|---|
| 189 | 183 | |
|---|
| 190 | | - low = task_stack_page(p); |
|---|
| 191 | | - high = (struct stack_frame *) task_pt_regs(p); |
|---|
| 192 | | - sf = (struct stack_frame *) p->thread.ksp; |
|---|
| 193 | | - if (sf <= low || sf > high) { |
|---|
| 194 | | - return_address = 0; |
|---|
| 195 | | - goto out; |
|---|
| 196 | | - } |
|---|
| 197 | | - for (count = 0; count < 16; count++) { |
|---|
| 198 | | - sf = (struct stack_frame *) sf->back_chain; |
|---|
| 199 | | - if (sf <= low || sf > high) { |
|---|
| 200 | | - return_address = 0; |
|---|
| 201 | | - goto out; |
|---|
| 184 | + unwind_for_each_frame(&state, p, NULL, 0) { |
|---|
| 185 | + if (state.stack_info.type != STACK_TYPE_TASK) { |
|---|
| 186 | + ip = 0; |
|---|
| 187 | + break; |
|---|
| 202 | 188 | } |
|---|
| 203 | | - return_address = sf->gprs[8]; |
|---|
| 204 | | - if (!in_sched_functions(return_address)) |
|---|
| 205 | | - goto out; |
|---|
| 189 | + |
|---|
| 190 | + ip = unwind_get_return_address(&state); |
|---|
| 191 | + if (!ip) |
|---|
| 192 | + break; |
|---|
| 193 | + |
|---|
| 194 | + if (!in_sched_functions(ip)) |
|---|
| 195 | + break; |
|---|
| 206 | 196 | } |
|---|
| 207 | | -out: |
|---|
| 197 | + |
|---|
| 208 | 198 | put_task_stack(p); |
|---|
| 209 | | - return return_address; |
|---|
| 199 | + return ip; |
|---|
| 210 | 200 | } |
|---|
| 211 | 201 | |
|---|
| 212 | 202 | unsigned long arch_align_stack(unsigned long sp) |
|---|