diff options
Diffstat (limited to 'arch/um/kernel')
-rw-r--r-- | arch/um/kernel/irq.c | 9 | ||||
-rw-r--r-- | arch/um/kernel/process.c | 7 | ||||
-rw-r--r-- | arch/um/kernel/reboot.c | 13 | ||||
-rw-r--r-- | arch/um/kernel/signal.c | 50 | ||||
-rw-r--r-- | arch/um/kernel/skas/syscall.c | 2 | ||||
-rw-r--r-- | arch/um/kernel/tlb.c | 1 | ||||
-rw-r--r-- | arch/um/kernel/trap.c | 24 |
7 files changed, 51 insertions, 55 deletions
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 71b8c94..00506c3 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -297,6 +297,13 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs) return 1; } +void um_free_irq(unsigned int irq, void *dev) +{ + free_irq_by_irq_and_dev(irq, dev); + free_irq(irq, dev); +} +EXPORT_SYMBOL(um_free_irq); + int um_request_irq(unsigned int irq, int fd, int type, irq_handler_t handler, unsigned long irqflags, const char * devname, @@ -327,7 +334,6 @@ static void dummy(struct irq_data *d) /* This is used for everything else than the timer. */ static struct irq_chip normal_irq_type = { .name = "SIGIO", - .release = free_irq_by_irq_and_dev, .irq_disable = dummy, .irq_enable = dummy, .irq_ack = dummy, @@ -335,7 +341,6 @@ static struct irq_chip normal_irq_type = { static struct irq_chip SIGVTALRM_irq_type = { .name = "SIGVTALRM", - .release = free_irq_by_irq_and_dev, .irq_disable = dummy, .irq_enable = dummy, .irq_ack = dummy, diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 2b73ded..ccb9a9d 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -18,6 +18,7 @@ #include <linux/seq_file.h> #include <linux/tick.h> #include <linux/threads.h> +#include <linux/tracehook.h> #include <asm/current.h> #include <asm/pgtable.h> #include <asm/mmu_context.h> @@ -114,8 +115,10 @@ void interrupt_end(void) { if (need_resched()) schedule(); - if (test_tsk_thread_flag(current, TIF_SIGPENDING)) + if (test_thread_flag(TIF_SIGPENDING)) do_signal(); + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + tracehook_notify_resume(¤t->thread.regs); } void exit_thread(void) @@ -190,7 +193,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, if (current->thread.forking) { memcpy(&p->thread.regs.regs, ®s->regs, sizeof(p->thread.regs.regs)); - REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0); + UPT_SET_SYSCALL_RETURN(&p->thread.regs.regs, 0); if (sp != 0) REGS_SP(p->thread.regs.regs.gp) = sp; diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 4d93dff..3d15243 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -4,7 +4,9 @@ */ #include "linux/sched.h" +#include "linux/spinlock.h" #include "linux/slab.h" +#include "linux/oom.h" #include "kern_util.h" #include "os.h" #include "skas.h" @@ -22,13 +24,18 @@ static void kill_off_processes(void) struct task_struct *p; int pid; + read_lock(&tasklist_lock); for_each_process(p) { - if (p->mm == NULL) - continue; + struct task_struct *t; - pid = p->mm->context.id.u.pid; + t = find_lock_task_mm(p); + if (!t) + continue; + pid = t->mm->context.id.u.pid; + task_unlock(t); os_kill_ptraced_process(pid, 1); } + read_unlock(&tasklist_lock); } } diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index fb12f4c..7362d58 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -15,23 +15,16 @@ EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) - /* * OK, we're invoking a handler */ -static int handle_signal(struct pt_regs *regs, unsigned long signr, - struct k_sigaction *ka, siginfo_t *info, - sigset_t *oldset) +static void handle_signal(struct pt_regs *regs, unsigned long signr, + struct k_sigaction *ka, siginfo_t *info) { + sigset_t *oldset = sigmask_to_save(); unsigned long sp; int err; - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - /* Did we come from a system call? */ if (PT_REGS_SYSCALL_NR(regs) >= 0) { /* If so, check system call restarting.. */ @@ -68,37 +61,19 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, if (err) force_sigsegv(signr, current); else - block_sigmask(ka, signr); - - return err; + signal_delivered(signr, info, ka, regs, 0); } static int kern_do_signal(struct pt_regs *regs) { struct k_sigaction ka_copy; siginfo_t info; - sigset_t *oldset; int sig, handled_sig = 0; - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else - oldset = ¤t->blocked; - while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { handled_sig = 1; /* Whee! Actually deliver the signal. */ - if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) { - /* - * a signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - break; - } + handle_signal(regs, sig, &ka_copy, &info); } /* Did we come from a system call? */ @@ -134,10 +109,8 @@ static int kern_do_signal(struct pt_regs *regs) * if there's no signal to deliver, we just put the saved sigmask * back */ - if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } + if (!handled_sig) + restore_saved_sigmask(); return handled_sig; } @@ -152,15 +125,8 @@ int do_signal(void) long sys_sigsuspend(int history0, int history1, old_sigset_t mask) { sigset_t blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index f5173e1..05fbeb4 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r) result = -ENOSYS; else result = EXECUTE_SYSCALL(syscall, regs); - REGS_SET_SYSCALL_RETURN(r->gp, result); + UPT_SET_SYSCALL_RETURN(r, result); syscall_trace(r, 1); } diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 7f3d4d8..f819af9 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -75,6 +75,7 @@ static int do_ops(struct host_vm_change *hvc, int end, default: printk(KERN_ERR "Unknown op type %d in do_ops\n", op->type); + BUG(); break; } } diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index dafc947..3be6076 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -30,6 +30,8 @@ int handle_page_fault(unsigned long address, unsigned long ip, pmd_t *pmd; pte_t *pte; int err = -EFAULT; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | + (is_write ? FAULT_FLAG_WRITE : 0); *code_out = SEGV_MAPERR; @@ -40,6 +42,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, if (in_atomic()) goto out_nosemaphore; +retry: down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -65,7 +68,11 @@ good_area: do { int fault; - fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + goto out_nosemaphore; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { goto out_of_memory; @@ -75,10 +82,17 @@ good_area: } BUG(); } - if (fault & VM_FAULT_MAJOR) - current->maj_flt++; - else - current->min_flt++; + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + goto retry; + } + } pgd = pgd_offset(mm, address); pud = pud_offset(pgd, address); |