Commit 0dafcbe1 authored by Johannes Berg's avatar Johannes Berg Committed by Richard Weinberger

um: Implement TRACE_IRQFLAGS_SUPPORT

UML enables TRACE_IRQFLAGS_SUPPORT but doesn't actually implement
it. It seems to have been added for lockdep support, but that can't
actually really work well without IRQ flags tracing, as is also
very noisily reported when enabling CONFIG_DEBUG_LOCKDEP.

Implement it now.

Fixes: 711553ef ("[PATCH] uml: declare in Kconfig our partial LOCKDEP support")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 276d75c4
...@@ -18,7 +18,7 @@ extern void longjmp(jmp_buf, int); ...@@ -18,7 +18,7 @@ extern void longjmp(jmp_buf, int);
enable = get_signals(); \ enable = get_signals(); \
n = setjmp(*buf); \ n = setjmp(*buf); \
if(n != 0) \ if(n != 0) \
set_signals(enable); \ set_signals_trace(enable); \
n; }) n; })
#endif #endif
...@@ -232,6 +232,7 @@ extern void block_signals(void); ...@@ -232,6 +232,7 @@ extern void block_signals(void);
extern void unblock_signals(void); extern void unblock_signals(void);
extern int get_signals(void); extern int get_signals(void);
extern int set_signals(int enable); extern int set_signals(int enable);
extern int set_signals_trace(int enable);
extern int os_is_signal_stack(void); extern int os_is_signal_stack(void);
extern void deliver_alarm(void); extern void deliver_alarm(void);
...@@ -317,4 +318,10 @@ extern unsigned long os_get_top_address(void); ...@@ -317,4 +318,10 @@ extern unsigned long os_get_top_address(void);
long syscall(long number, ...); long syscall(long number, ...);
/* irqflags tracing */
extern void block_signals_trace(void);
extern void unblock_signals_trace(void);
extern void um_trace_signals_on(void);
extern void um_trace_signals_off(void);
#endif #endif
...@@ -6,15 +6,43 @@ ...@@ -6,15 +6,43 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/ftrace.h>
#include <asm/siginfo.h> #include <asm/siginfo.h>
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <frame_kern.h> #include <frame_kern.h>
#include <kern_util.h> #include <kern_util.h>
#include <os.h>
EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(block_signals);
EXPORT_SYMBOL(unblock_signals); EXPORT_SYMBOL(unblock_signals);
void block_signals_trace(void)
{
block_signals();
if (current_thread_info())
trace_hardirqs_off();
}
void unblock_signals_trace(void)
{
if (current_thread_info())
trace_hardirqs_on();
unblock_signals();
}
void um_trace_signals_on(void)
{
if (current_thread_info())
trace_hardirqs_on();
}
void um_trace_signals_off(void)
{
if (current_thread_info())
trace_hardirqs_off();
}
/* /*
* OK, we're invoking a handler * OK, we're invoking a handler
*/ */
......
...@@ -63,12 +63,12 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) ...@@ -63,12 +63,12 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
if (current->mm != NULL && current->mm != &init_mm) if (current->mm != NULL && current->mm != &init_mm)
from_mm = &current->mm->context; from_mm = &current->mm->context;
block_signals(); block_signals_trace();
if (from_mm) if (from_mm)
to_mm->id.u.pid = copy_context_skas0(stack, to_mm->id.u.pid = copy_context_skas0(stack,
from_mm->id.u.pid); from_mm->id.u.pid);
else to_mm->id.u.pid = start_userspace(stack); else to_mm->id.u.pid = start_userspace(stack);
unblock_signals(); unblock_signals_trace();
if (to_mm->id.u.pid < 0) { if (to_mm->id.u.pid < 0) {
ret = to_mm->id.u.pid; ret = to_mm->id.u.pid;
......
...@@ -19,7 +19,7 @@ static int __init start_kernel_proc(void *unused) ...@@ -19,7 +19,7 @@ static int __init start_kernel_proc(void *unused)
{ {
int pid; int pid;
block_signals(); block_signals_trace();
pid = os_getpid(); pid = os_getpid();
cpu_tasks[0].pid = pid; cpu_tasks[0].pid = pid;
......
...@@ -170,7 +170,7 @@ int __init main(int argc, char **argv, char **envp) ...@@ -170,7 +170,7 @@ int __init main(int argc, char **argv, char **envp)
* that they won't be delivered after the exec, when * that they won't be delivered after the exec, when
* they are definitely not expected. * they are definitely not expected.
*/ */
unblock_signals(); unblock_signals_trace();
os_info("\n"); os_info("\n");
/* Reboot */ /* Reboot */
......
...@@ -132,7 +132,7 @@ static void update_thread(void) ...@@ -132,7 +132,7 @@ static void update_thread(void)
int n; int n;
char c; char c;
flags = set_signals(0); flags = set_signals_trace(0);
CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c)));
if (n != sizeof(c)) { if (n != sizeof(c)) {
printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", printk(UM_KERN_ERR "update_thread : write failed, err = %d\n",
...@@ -147,7 +147,7 @@ static void update_thread(void) ...@@ -147,7 +147,7 @@ static void update_thread(void)
goto fail; goto fail;
} }
set_signals(flags); set_signals_trace(flags);
return; return;
fail: fail:
/* Critical section start */ /* Critical section start */
...@@ -161,7 +161,7 @@ static void update_thread(void) ...@@ -161,7 +161,7 @@ static void update_thread(void)
close(write_sigio_fds[0]); close(write_sigio_fds[0]);
close(write_sigio_fds[1]); close(write_sigio_fds[1]);
/* Critical section end */ /* Critical section end */
set_signals(flags); set_signals_trace(flags);
} }
int add_sigio_fd(int fd) int add_sigio_fd(int fd)
......
...@@ -43,7 +43,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) ...@@ -43,7 +43,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
/* enable signals if sig isn't IRQ signal */ /* enable signals if sig isn't IRQ signal */
if ((sig != SIGIO) && (sig != SIGWINCH)) if ((sig != SIGIO) && (sig != SIGWINCH))
unblock_signals(); unblock_signals_trace();
(*sig_info[sig])(sig, si, &r); (*sig_info[sig])(sig, si, &r);
...@@ -76,11 +76,11 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) ...@@ -76,11 +76,11 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
return; return;
} }
block_signals(); block_signals_trace();
sig_handler_common(sig, si, mc); sig_handler_common(sig, si, mc);
set_signals(enabled); set_signals_trace(enabled);
} }
static void timer_real_alarm_handler(mcontext_t *mc) static void timer_real_alarm_handler(mcontext_t *mc)
...@@ -104,7 +104,7 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) ...@@ -104,7 +104,7 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
return; return;
} }
block_signals(); block_signals_trace();
signals_active |= SIGALRM_MASK; signals_active |= SIGALRM_MASK;
...@@ -112,7 +112,7 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) ...@@ -112,7 +112,7 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
signals_active &= ~SIGALRM_MASK; signals_active &= ~SIGALRM_MASK;
set_signals(enabled); set_signals_trace(enabled);
} }
void deliver_alarm(void) { void deliver_alarm(void) {
...@@ -253,6 +253,8 @@ void unblock_signals(void) ...@@ -253,6 +253,8 @@ void unblock_signals(void)
if (signals_enabled == 1) if (signals_enabled == 1)
return; return;
signals_enabled = 1;
/* /*
* We loop because the IRQ handler returns with interrupts off. So, * We loop because the IRQ handler returns with interrupts off. So,
* interrupts may have arrived and we need to re-enable them and * interrupts may have arrived and we need to re-enable them and
...@@ -262,12 +264,9 @@ void unblock_signals(void) ...@@ -262,12 +264,9 @@ void unblock_signals(void)
/* /*
* Save and reset save_pending after enabling signals. This * Save and reset save_pending after enabling signals. This
* way, signals_pending won't be changed while we're reading it. * way, signals_pending won't be changed while we're reading it.
*/ *
signals_enabled = 1;
/*
* Setting signals_enabled and reading signals_pending must * Setting signals_enabled and reading signals_pending must
* happen in this order. * happen in this order, so have the barrier here.
*/ */
barrier(); barrier();
...@@ -280,10 +279,13 @@ void unblock_signals(void) ...@@ -280,10 +279,13 @@ void unblock_signals(void)
/* /*
* We have pending interrupts, so disable signals, as the * We have pending interrupts, so disable signals, as the
* handlers expect them off when they are called. They will * handlers expect them off when they are called. They will
* be enabled again above. * be enabled again above. We need to trace this, as we're
* expected to be enabling interrupts already, but any more
* tracing that happens inside the handlers we call for the
* pending signals will mess up the tracing state.
*/ */
signals_enabled = 0; signals_enabled = 0;
um_trace_signals_off();
/* /*
* Deal with SIGIO first because the alarm handler might * Deal with SIGIO first because the alarm handler might
...@@ -306,6 +308,9 @@ void unblock_signals(void) ...@@ -306,6 +308,9 @@ void unblock_signals(void)
if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK)) if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK))
return; return;
/* Re-enable signals and trace that we're doing so. */
um_trace_signals_on();
signals_enabled = 1;
} }
} }
...@@ -328,6 +333,21 @@ int set_signals(int enable) ...@@ -328,6 +333,21 @@ int set_signals(int enable)
return ret; return ret;
} }
int set_signals_trace(int enable)
{
int ret;
if (signals_enabled == enable)
return enable;
ret = signals_enabled;
if (enable)
unblock_signals_trace();
else
block_signals_trace();
return ret;
}
int os_is_signal_stack(void) int os_is_signal_stack(void)
{ {
stack_t ss; stack_t ss;
......
...@@ -425,9 +425,9 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) ...@@ -425,9 +425,9 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
case SIGBUS: case SIGBUS:
case SIGFPE: case SIGFPE:
case SIGWINCH: case SIGWINCH:
block_signals(); block_signals_trace();
(*sig_info[sig])(sig, (struct siginfo *)&si, regs); (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
unblock_signals(); unblock_signals_trace();
break; break;
default: default:
printk(UM_KERN_ERR "userspace - child stopped " printk(UM_KERN_ERR "userspace - child stopped "
...@@ -625,10 +625,10 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) ...@@ -625,10 +625,10 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
cb_arg = arg; cb_arg = arg;
cb_back = &here; cb_back = &here;
block_signals(); block_signals_trace();
if (UML_SETJMP(&here) == 0) if (UML_SETJMP(&here) == 0)
UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
unblock_signals(); unblock_signals_trace();
cb_proc = NULL; cb_proc = NULL;
cb_arg = NULL; cb_arg = NULL;
...@@ -637,13 +637,13 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) ...@@ -637,13 +637,13 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
void halt_skas(void) void halt_skas(void)
{ {
block_signals(); block_signals_trace();
UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT); UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
} }
void reboot_skas(void) void reboot_skas(void)
{ {
block_signals(); block_signals_trace();
UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT); UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment