Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9956c112 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  sparc64: Prevent stack backtrace false positives on trap frames.
  sparc64: Fix stack tracing through trap frames.
  sparc64: Fix kernel thread stack termination.
  sunhv: Fix locking in non-paged I/O case.
parents 78b58e54 ada44a04
Loading
Loading
Loading
Loading
+25 −11
Original line number Diff line number Diff line
@@ -657,20 +657,39 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
		struct task_struct *p, struct pt_regs *regs)
{
	struct thread_info *t = task_thread_info(p);
	struct sparc_stackf *parent_sf;
	unsigned long child_stack_sz;
	char *child_trap_frame;
	int kernel_thread;

	/* Calculate offset to stack_frame & pt_regs */
	child_trap_frame = task_stack_page(p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ));
	memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ));
	kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
	parent_sf = ((struct sparc_stackf *) regs) - 1;

	t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
	/* Calculate offset to stack_frame & pt_regs */
	child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) +
			  (kernel_thread ? STACKFRAME_SZ : 0));
	child_trap_frame = (task_stack_page(p) +
			    (THREAD_SIZE - child_stack_sz));
	memcpy(child_trap_frame, parent_sf, child_stack_sz);

	t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
				 (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
		(((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
	t->new_child = 1;
	t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf));
	t->kregs = (struct pt_regs *) (child_trap_frame +
				       sizeof(struct sparc_stackf));
	t->fpsaved[0] = 0;

	if (regs->tstate & TSTATE_PRIV) {
	if (kernel_thread) {
		struct sparc_stackf *child_sf = (struct sparc_stackf *)
			(child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ));

		/* Zero terminate the stack backtrace.  */
		child_sf->fp = NULL;
		t->kregs->u_regs[UREG_FP] =
		  ((unsigned long) child_sf) - STACK_BIAS;

		/* Special case, if we are spawning a kernel thread from
		 * a userspace task (via KMOD, NFS, or similar) we must
		 * disable performance counters in the child because the
@@ -681,12 +700,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
			t->pcr_reg = 0;
			t->flags &= ~_TIF_PERFCTR;
		}
		t->kregs->u_regs[UREG_FP] = t->ksp;
		t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT);
		flush_register_windows();
		memcpy((void *)(t->ksp + STACK_BIAS),
		       (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
		       sizeof(struct sparc_stackf));
		t->kregs->u_regs[UREG_G6] = (unsigned long) t;
		t->kregs->u_regs[UREG_G4] = (unsigned long) t->task;
	} else {
+1 −0
Original line number Diff line number Diff line
@@ -363,6 +363,7 @@ kern_rtt: rdpr %canrestore, %g1
		brz,pn			%g1, kern_rtt_fill
		 nop
kern_rtt_restore:
		stw			%g0, [%sp + PTREGS_OFF + PT_V9_MAGIC]
		restore
		retry

+7 −5
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ void save_stack_trace(struct stack_trace *trace)
	fp = ksp + STACK_BIAS;
	thread_base = (unsigned long) tp;
	do {
		struct reg_window *rw;
		struct sparc_stackf *sf;
		struct pt_regs *regs;
		unsigned long pc;

@@ -28,15 +28,17 @@ void save_stack_trace(struct stack_trace *trace)
		    fp >= (thread_base + THREAD_SIZE))
			break;

		rw = (struct reg_window *) fp;
		regs = (struct pt_regs *) (rw + 1);
		sf = (struct sparc_stackf *) fp;
		regs = (struct pt_regs *) (sf + 1);

		if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
			if (!(regs->tstate & TSTATE_PRIV))
				break;
			pc = regs->tpc;
			fp = regs->u_regs[UREG_I6] + STACK_BIAS;
		} else {
			pc = rw->ins[7];
			fp = rw->ins[6] + STACK_BIAS;
			pc = sf->callers_pc;
			fp = (unsigned long)sf->fp + STACK_BIAS;
		}

		if (trace->skip > 0)
+7 −5
Original line number Diff line number Diff line
@@ -2116,7 +2116,7 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
	printk("\n");
#endif
	do {
		struct reg_window *rw;
		struct sparc_stackf *sf;
		struct pt_regs *regs;
		unsigned long pc;

@@ -2124,15 +2124,17 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
		if (fp < (thread_base + sizeof(struct thread_info)) ||
		    fp >= (thread_base + THREAD_SIZE))
			break;
		rw = (struct reg_window *)fp;
		regs = (struct pt_regs *) (rw + 1);
		sf = (struct sparc_stackf *) fp;
		regs = (struct pt_regs *) (sf + 1);

		if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
			if (!(regs->tstate & TSTATE_PRIV))
				break;
			pc = regs->tpc;
			fp = regs->u_regs[UREG_I6] + STACK_BIAS;
		} else {
			pc = rw->ins[7];
			fp = rw->ins[6] + STACK_BIAS;
			pc = sf->callers_pc;
			fp = (unsigned long)sf->fp + STACK_BIAS;
		}

		printk(" [%016lx] ", pc);
+0 −1
Original line number Diff line number Diff line
@@ -499,7 +499,6 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
	} else
		spin_lock(&port->lock);

	spin_lock_irqsave(&port->lock, flags);
	for (i = 0; i < n; i++) {
		if (*s == '\n')
			sunhv_console_putchar(port, '\r');