diff --git a/MAINTAINERS b/MAINTAINERS index 6720018bc674..94b823f71e94 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7382,6 +7382,7 @@ W: http://user-mode-linux.sourceforge.net S: Maintained F: Documentation/virtual/uml/ F: arch/um/ +F: arch/x86/um/ F: fs/hostfs/ F: fs/hppfs/ diff --git a/arch/um/defconfig b/arch/um/defconfig index fec0d5d27460..08107a795062 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -163,7 +163,7 @@ CONFIG_CGROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y # CONFIG_CFS_BANDWIDTH is not set # CONFIG_RT_GROUP_SCHED is not set -CONFIG_BLK_CGROUP=m +CONFIG_BLK_CGROUP=y # CONFIG_DEBUG_BLK_CGROUP is not set # CONFIG_CHECKPOINT_RESTORE is not set CONFIG_NAMESPACES=y diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 45e248c2f43c..87eebfe03c61 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -150,9 +150,11 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty) static void line_timer_cb(struct work_struct *work) { struct line *line = container_of(work, struct line, task.work); + struct tty_struct *tty = tty_port_tty_get(&line->port); if (!line->throttled) - chan_interrupt(line, line->tty, line->driver->read_irq); + chan_interrupt(line, tty, line->driver->read_irq); + tty_kref_put(tty); } int enable_chan(struct line *line) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index ac9d25c8dc01..bbaf2c59830a 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -19,9 +19,11 @@ static irqreturn_t line_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; + struct tty_struct *tty = tty_port_tty_get(&line->port); if (line) - chan_interrupt(line, line->tty, irq); + chan_interrupt(line, tty, irq); + tty_kref_put(tty); return IRQ_HANDLED; } @@ -219,92 +221,6 @@ void line_set_termios(struct tty_struct *tty, struct ktermios * old) /* nothing */ } -static const struct { - int cmd; - char *level; - char *name; -} tty_ioctls[] = { - /* don't print these, they flood the log ... */ - { TCGETS, NULL, "TCGETS" }, - { TCSETS, NULL, "TCSETS" }, - { TCSETSW, NULL, "TCSETSW" }, - { TCFLSH, NULL, "TCFLSH" }, - { TCSBRK, NULL, "TCSBRK" }, - - /* general tty stuff */ - { TCSETSF, KERN_DEBUG, "TCSETSF" }, - { TCGETA, KERN_DEBUG, "TCGETA" }, - { TIOCMGET, KERN_DEBUG, "TIOCMGET" }, - { TCSBRKP, KERN_DEBUG, "TCSBRKP" }, - { TIOCMSET, KERN_DEBUG, "TIOCMSET" }, - - /* linux-specific ones */ - { TIOCLINUX, KERN_INFO, "TIOCLINUX" }, - { KDGKBMODE, KERN_INFO, "KDGKBMODE" }, - { KDGKBTYPE, KERN_INFO, "KDGKBTYPE" }, - { KDSIGACCEPT, KERN_INFO, "KDSIGACCEPT" }, -}; - -int line_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - int ret; - int i; - - ret = 0; - switch(cmd) { -#ifdef TIOCGETP - case TIOCGETP: - case TIOCSETP: - case TIOCSETN: -#endif -#ifdef TIOCGETC - case TIOCGETC: - case TIOCSETC: -#endif -#ifdef TIOCGLTC - case TIOCGLTC: - case TIOCSLTC: -#endif - /* Note: these are out of date as we now have TCGETS2 etc but this - whole lot should probably go away */ - case TCGETS: - case TCSETSF: - case TCSETSW: - case TCSETS: - case TCGETA: - case TCSETAF: - case TCSETAW: - case TCSETA: - case TCXONC: - case TCFLSH: - case TIOCOUTQ: - case TIOCINQ: - case TIOCGLCKTRMIOS: - case TIOCSLCKTRMIOS: - case TIOCPKT: - case TIOCGSOFTCAR: - case TIOCSSOFTCAR: - return -ENOIOCTLCMD; -#if 0 - case TCwhatever: - /* do something */ - break; -#endif - default: - for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++) - if (cmd == tty_ioctls[i].cmd) - break; - if (i == ARRAY_SIZE(tty_ioctls)) { - printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n", - __func__, tty->name, cmd); - } - ret = -ENOIOCTLCMD; - break; - } - return ret; -} - void line_throttle(struct tty_struct *tty) { struct line *line = tty->driver_data; @@ -333,7 +249,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; - struct tty_struct *tty = line->tty; + struct tty_struct *tty; int err; /* @@ -352,10 +268,13 @@ static irqreturn_t line_write_interrupt(int irq, void *data) } spin_unlock(&line->lock); + tty = tty_port_tty_get(&line->port); if (tty == NULL) return IRQ_NONE; tty_wakeup(tty); + tty_kref_put(tty); + return IRQ_HANDLED; } @@ -377,43 +296,14 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) return err; } -/* - * Normally, a driver like this can rely mostly on the tty layer - * locking, particularly when it comes to the driver structure. - * However, in this case, mconsole requests can come in "from the - * side", and race with opens and closes. - * - * mconsole config requests will want to be sure the device isn't in - * use, and get_config, open, and close will want a stable - * configuration. The checking and modification of the configuration - * is done under a spinlock. Checking whether the device is in use is - * line->tty->count > 1, also under the spinlock. - * - * line->count serves to decide whether the device should be enabled or - * disabled on the host. If it's equal to 0, then we are doing the - * first open or last close. Otherwise, open and close just return. - */ - -int line_open(struct line *lines, struct tty_struct *tty) +static int line_activate(struct tty_port *port, struct tty_struct *tty) { - struct line *line = &lines[tty->index]; - int err = -ENODEV; + int ret; + struct line *line = tty->driver_data; - mutex_lock(&line->count_lock); - if (!line->valid) - goto out_unlock; - - err = 0; - if (line->count++) - goto out_unlock; - - BUG_ON(tty->driver_data); - tty->driver_data = line; - line->tty = tty; - - err = enable_chan(line); - if (err) /* line_close() will be called by our caller */ - goto out_unlock; + ret = enable_chan(line); + if (ret) + return ret; if (!line->sigio) { chan_enable_winch(line->chan_out, tty); @@ -421,44 +311,60 @@ int line_open(struct line *lines, struct tty_struct *tty) } chan_window_size(line, &tty->winsize.ws_row, - &tty->winsize.ws_col); -out_unlock: - mutex_unlock(&line->count_lock); - return err; + &tty->winsize.ws_col); + + return 0; +} + +static const struct tty_port_operations line_port_ops = { + .activate = line_activate, +}; + +int line_open(struct tty_struct *tty, struct file *filp) +{ + struct line *line = tty->driver_data; + + return tty_port_open(&line->port, tty, filp); +} + +int line_install(struct tty_driver *driver, struct tty_struct *tty, + struct line *line) +{ + int ret; + + ret = tty_standard_install(driver, tty); + if (ret) + return ret; + + tty->driver_data = line; + + return 0; } static void unregister_winch(struct tty_struct *tty); -void line_close(struct tty_struct *tty, struct file * filp) +void line_cleanup(struct tty_struct *tty) { struct line *line = tty->driver_data; - /* - * If line_open fails (and tty->driver_data is never set), - * tty_open will call line_close. So just return in this case. - */ - if (line == NULL) - return; - - /* We ignore the error anyway! */ - flush_buffer(line); - - mutex_lock(&line->count_lock); - BUG_ON(!line->valid); - - if (--line->count) - goto out_unlock; - - line->tty = NULL; - tty->driver_data = NULL; - if (line->sigio) { unregister_winch(tty); line->sigio = 0; } +} -out_unlock: - mutex_unlock(&line->count_lock); +void line_close(struct tty_struct *tty, struct file * filp) +{ + struct line *line = tty->driver_data; + + tty_port_close(&line->port, tty, filp); +} + +void line_hangup(struct tty_struct *tty) +{ + struct line *line = tty->driver_data; + + tty_port_hangup(&line->port); } void close_lines(struct line *lines, int nlines) @@ -476,9 +382,7 @@ int setup_one_line(struct line *lines, int n, char *init, struct tty_driver *driver = line->driver->driver; int err = -EINVAL; - mutex_lock(&line->count_lock); - - if (line->count) { + if (line->port.count) { *error_out = "Device is already open"; goto out; } @@ -519,7 +423,6 @@ int setup_one_line(struct line *lines, int n, char *init, } } out: - mutex_unlock(&line->count_lock); return err; } @@ -607,13 +510,17 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, line = &lines[dev]; - mutex_lock(&line->count_lock); if (!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); - else if (line->tty == NULL) - CONFIG_CHUNK(str, size, n, line->init_str, 1); - else n = chan_config_string(line, str, size, error_out); - mutex_unlock(&line->count_lock); + else { + struct tty_struct *tty = tty_port_tty_get(&line->port); + if (tty == NULL) { + CONFIG_CHUNK(str, size, n, line->init_str, 1); + } else { + n = chan_config_string(line, str, size, error_out); + tty_kref_put(tty); + } + } return n; } @@ -663,8 +570,9 @@ int register_lines(struct line_driver *line_driver, driver->init_termios = tty_std_termios; for (i = 0; i < nlines; i++) { + tty_port_init(&lines[i].port); + lines[i].port.ops = &line_port_ops; spin_lock_init(&lines[i].lock); - mutex_init(&lines[i].count_lock); lines[i].driver = line_driver; INIT_LIST_HEAD(&lines[i].chan_list); } diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 0a1834719dba..bae95611e7ab 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -32,9 +32,7 @@ struct line_driver { }; struct line { - struct tty_struct *tty; - struct mutex count_lock; - unsigned long count; + struct tty_port port; int valid; char *init_str; @@ -59,7 +57,11 @@ struct line { }; extern void line_close(struct tty_struct *tty, struct file * filp); -extern int line_open(struct line *lines, struct tty_struct *tty); +extern int line_open(struct tty_struct *tty, struct file *filp); +extern int line_install(struct tty_driver *driver, struct tty_struct *tty, + struct line *line); +extern void line_cleanup(struct tty_struct *tty); +extern void line_hangup(struct tty_struct *tty); extern int line_setup(char **conf, unsigned nlines, char **def, char *init, char *name); extern int line_write(struct tty_struct *tty, const unsigned char *buf, @@ -70,8 +72,6 @@ extern int line_chars_in_buffer(struct tty_struct *tty); extern void line_flush_buffer(struct tty_struct *tty); extern void line_flush_chars(struct tty_struct *tty); extern int line_write_room(struct tty_struct *tty); -extern int line_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg); extern void line_throttle(struct tty_struct *tty); extern void line_unthrottle(struct tty_struct *tty); diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index e09801a1327b..7e86f0070123 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -87,40 +87,13 @@ static int ssl_remove(int n, char **error_out) error_out); } -static int ssl_open(struct tty_struct *tty, struct file *filp) +static int ssl_install(struct tty_driver *driver, struct tty_struct *tty) { - int err = line_open(serial_lines, tty); - - if (err) - printk(KERN_ERR "Failed to open serial line %d, err = %d\n", - tty->index, err); - - return err; + return line_install(driver, tty, &serial_lines[tty->index]); } -#if 0 -static void ssl_flush_buffer(struct tty_struct *tty) -{ - return; -} - -static void ssl_stop(struct tty_struct *tty) -{ - printk(KERN_ERR "Someone should implement ssl_stop\n"); -} - -static void ssl_start(struct tty_struct *tty) -{ - printk(KERN_ERR "Someone should implement ssl_start\n"); -} - -void ssl_hangup(struct tty_struct *tty) -{ -} -#endif - static const struct tty_operations ssl_ops = { - .open = ssl_open, + .open = line_open, .close = line_close, .write = line_write, .put_char = line_put_char, @@ -129,14 +102,11 @@ static const struct tty_operations ssl_ops = { .flush_buffer = line_flush_buffer, .flush_chars = line_flush_chars, .set_termios = line_set_termios, - .ioctl = line_ioctl, .throttle = line_throttle, .unthrottle = line_unthrottle, -#if 0 - .stop = ssl_stop, - .start = ssl_start, - .hangup = ssl_hangup, -#endif + .install = ssl_install, + .cleanup = line_cleanup, + .hangup = line_hangup, }; /* Changed by ssl_init and referenced by ssl_exit, which are both serialized diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 7663541c372e..929b99a261f3 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -89,21 +89,17 @@ static int con_remove(int n, char **error_out) return line_remove(vts, ARRAY_SIZE(vts), n, error_out); } -static int con_open(struct tty_struct *tty, struct file *filp) -{ - int err = line_open(vts, tty); - if (err) - printk(KERN_ERR "Failed to open console %d, err = %d\n", - tty->index, err); - - return err; -} - /* Set in an initcall, checked in an exitcall */ static int con_init_done = 0; +static int con_install(struct tty_driver *driver, struct tty_struct *tty) +{ + return line_install(driver, tty, &vts[tty->index]); +} + static const struct tty_operations console_ops = { - .open = con_open, + .open = line_open, + .install = con_install, .close = line_close, .write = line_write, .put_char = line_put_char, @@ -112,9 +108,10 @@ static const struct tty_operations console_ops = { .flush_buffer = line_flush_buffer, .flush_chars = line_flush_chars, .set_termios = line_set_termios, - .ioctl = line_ioctl, .throttle = line_throttle, .unthrottle = line_unthrottle, + .cleanup = line_cleanup, + .hangup = line_hangup, }; static void uml_console_write(struct console *console, const char *string, diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 20505cafa299..0643e5bc9f41 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -514,7 +514,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) goto out; } - fd = os_open_file(ubd_dev->file, global_openflags, 0); + fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0); if (fd < 0) return fd; diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h index e786a6a3ec5e..442f1d025dc2 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h @@ -37,6 +37,8 @@ extern int putreg(struct task_struct *child, int regno, unsigned long value); extern int arch_copy_tls(struct task_struct *new); extern void clear_flushed_tls(struct task_struct *task); +extern void syscall_trace_enter(struct pt_regs *regs); +extern void syscall_trace_leave(struct pt_regs *regs); #endif diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h index 896e16602176..86daa5461815 100644 --- a/arch/um/include/shared/as-layout.h +++ b/arch/um/include/shared/as-layout.h @@ -60,7 +60,8 @@ extern unsigned long host_task_size; extern int linux_main(int argc, char **argv); -extern void (*sig_info[])(int, struct uml_pt_regs *); +struct siginfo; +extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *); #endif diff --git a/arch/um/include/shared/irq_user.h b/arch/um/include/shared/irq_user.h index c6c784df2673..2b6d703925b5 100644 --- a/arch/um/include/shared/irq_user.h +++ b/arch/um/include/shared/irq_user.h @@ -20,7 +20,8 @@ struct irq_fd { enum { IRQ_READ, IRQ_WRITE }; -extern void sigio_handler(int sig, struct uml_pt_regs *regs); +struct siginfo; +extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern void free_irq_by_fd(int fd); extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index 00965d06d2ca..af6b6dc868ba 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -9,6 +9,8 @@ #include "sysdep/ptrace.h" #include "sysdep/faultinfo.h" +struct siginfo; + extern int uml_exitcode; extern int ncpus; @@ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order); extern int do_signal(void); extern void interrupt_end(void); -extern void relay_signal(int sig, struct uml_pt_regs *regs); +extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs); extern unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, struct uml_pt_regs *regs); @@ -33,9 +35,8 @@ extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); extern int smp_sigio_handler(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int is_syscall(unsigned long addr); -extern void timer_handler(int sig, struct uml_pt_regs *regs); -extern void timer_handler(int sig, struct uml_pt_regs *regs); +extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern int start_uml(void); extern void paging_init(void); @@ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested); extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); extern int singlestepping(void *t); -extern void segv_handler(int sig, struct uml_pt_regs *regs); -extern void bus_handler(int sig, struct uml_pt_regs *regs); -extern void winch(int sig, struct uml_pt_regs *regs); +extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); +extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern void fatal_sigsegv(void) __attribute__ ((noreturn)); diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 00506c3d5d6e..9883026f0730 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds; extern void free_irqs(void); -void sigio_handler(int sig, struct uml_pt_regs *regs) +void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { struct irq_fd *irq_fd; int n; diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index ccb9a9d283f1..57fc7028714a 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -151,12 +151,10 @@ void new_thread_handler(void) * 0 if it just exits */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); - if (n == 1) { - /* Handle any immediate reschedules or signals */ - interrupt_end(); + if (n == 1) userspace(¤t->thread.regs.regs); - } - else do_exit(0); + else + do_exit(0); } /* Called magically, see new_thread_handler above */ @@ -175,9 +173,6 @@ void fork_handler(void) current->thread.prev_sched = NULL; - /* Handle any immediate reschedules or signals */ - interrupt_end(); - userspace(¤t->thread.regs.regs); } @@ -193,7 +188,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)); - UPT_SET_SYSCALL_RETURN(&p->thread.regs.regs, 0); + PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0); if (sp != 0) REGS_SP(p->thread.regs.regs.gp) = sp; diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 06b190390505..694d551c8899 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -3,11 +3,12 @@ * Licensed under the GPL */ -#include "linux/audit.h" -#include "linux/ptrace.h" -#include "linux/sched.h" -#include "asm/uaccess.h" -#include "skas_ptrace.h" +#include +#include +#include +#include +#include +#include @@ -162,48 +163,36 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check */ -void syscall_trace(struct uml_pt_regs *regs, int entryexit) +void syscall_trace_enter(struct pt_regs *regs) { - int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; - int tracesysgood; - - if (!entryexit) - audit_syscall_entry(HOST_AUDIT_ARCH, - UPT_SYSCALL_NR(regs), - UPT_SYSCALL_ARG1(regs), - UPT_SYSCALL_ARG2(regs), - UPT_SYSCALL_ARG3(regs), - UPT_SYSCALL_ARG4(regs)); - else - audit_syscall_exit(regs); - - /* Fake a debug trap */ - if (is_singlestep) - send_sigtrap(current, regs, 0); + audit_syscall_entry(HOST_AUDIT_ARCH, + UPT_SYSCALL_NR(®s->regs), + UPT_SYSCALL_ARG1(®s->regs), + UPT_SYSCALL_ARG2(®s->regs), + UPT_SYSCALL_ARG3(®s->regs), + UPT_SYSCALL_ARG4(®s->regs)); if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; - if (!(current->ptrace & PT_PTRACED)) + tracehook_report_syscall_entry(regs); +} + +void syscall_trace_leave(struct pt_regs *regs) +{ + int ptraced = current->ptrace; + + audit_syscall_exit(regs); + + /* Fake a debug trap */ + if (ptraced & PT_DTRACE) + send_sigtrap(current, ®s->regs, 0); + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; - /* - * the 0x80 provides a way for the tracing parent to distinguish - * between a syscall stop and SIGTRAP delivery - */ - tracesysgood = (current->ptrace & PT_TRACESYSGOOD); - ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); - - if (entryexit) /* force do_signal() --> is_syscall() */ + tracehook_report_syscall_exit(regs, 0); + /* force do_signal() --> is_syscall() */ + if (ptraced & PT_PTRACED) set_thread_flag(TIF_SIGPENDING); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } } diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 05fbeb480e0b..86368a025a96 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -18,7 +18,7 @@ void handle_syscall(struct uml_pt_regs *r) long result; int syscall; - syscall_trace(r, 0); + syscall_trace_enter(regs); /* * This should go in the declaration of syscall, but when I do that, @@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r) result = -ENOSYS; else result = EXECUTE_SYSCALL(syscall, regs); - UPT_SET_SYSCALL_RETURN(r, result); + PT_REGS_SET_SYSCALL_RETURN(regs, result); - syscall_trace(r, 1); + syscall_trace_leave(regs); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index d1a23fb3190d..5f76d4ba151c 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -13,7 +13,7 @@ #include "kern_util.h" #include "os.h" -void timer_handler(int sig, struct uml_pt_regs *regs) +void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { unsigned long flags; diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 3be60765c0e2..0353b98ae35a 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -172,7 +172,7 @@ void fatal_sigsegv(void) os_dump_core(); } -void segv_handler(int sig, struct uml_pt_regs *regs) +void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { struct faultinfo * fi = UPT_FAULTINFO(regs); @@ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, return 0; } -void relay_signal(int sig, struct uml_pt_regs *regs) +void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) { + struct faultinfo *fi; + struct siginfo clean_si; + if (!UPT_IS_USER(regs)) { if (sig == SIGBUS) printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " @@ -269,18 +272,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs) arch_examine_signal(sig, regs); - current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); - force_sig(sig, current); + memset(&clean_si, 0, sizeof(clean_si)); + clean_si.si_signo = si->si_signo; + clean_si.si_errno = si->si_errno; + clean_si.si_code = si->si_code; + switch (sig) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + fi = UPT_FAULTINFO(regs); + clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi); + current->thread.arch.faultinfo = *fi; +#ifdef __ARCH_SI_TRAPNO + clean_si.si_trapno = si->si_trapno; +#endif + break; + default: + printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", + sig, si->si_code); + } + + force_sig_info(sig, &clean_si, current); } -void bus_handler(int sig, struct uml_pt_regs *regs) +void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) { if (current->thread.fault_catcher != NULL) UML_LONGJMP(current->thread.fault_catcher, 1); - else relay_signal(sig, regs); + else + relay_signal(sig, si, regs); } -void winch(int sig, struct uml_pt_regs *regs) +void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { do_IRQ(WINCH_IRQ, regs); } diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h index 2c3c3ecd8c01..0dc2c9f135f6 100644 --- a/arch/um/os-Linux/internal.h +++ b/arch/um/os-Linux/internal.h @@ -1 +1 @@ -void alarm_handler(int, mcontext_t *); +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc); diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 2d22f1fcd8e2..6366ce904b9b 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -13,8 +13,9 @@ #include "kern_util.h" #include "os.h" #include "sysdep/mcontext.h" +#include "internal.h" -void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { +void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, [SIGFPE] = relay_signal, [SIGILL] = relay_signal, @@ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { [SIGIO] = sigio_handler, [SIGVTALRM] = timer_handler }; -static void sig_handler_common(int sig, mcontext_t *mc) +static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc) { struct uml_pt_regs r; int save_errno = errno; @@ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) unblock_signals(); - (*sig_info[sig])(sig, &r); + (*sig_info[sig])(sig, si, &r); errno = save_errno; } @@ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) static int signals_enabled; static unsigned int signals_pending; -void sig_handler(int sig, mcontext_t *mc) +void sig_handler(int sig, siginfo_t *si, mcontext_t *mc) { int enabled; @@ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc) block_signals(); - sig_handler_common(sig, mc); + sig_handler_common(sig, si, mc); set_signals(enabled); } @@ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc) get_regs_from_mc(®s, mc); regs.is_user = 0; unblock_signals(); - timer_handler(SIGVTALRM, ®s); + timer_handler(SIGVTALRM, NULL, ®s); } -void alarm_handler(int sig, mcontext_t *mc) +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; @@ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size) panic("enabling signal stack failed, errno = %d\n", errno); } -static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { +static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = { [SIGSEGV] = sig_handler, [SIGBUS] = sig_handler, [SIGILL] = sig_handler, @@ -132,7 +133,7 @@ static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { }; -static void hard_handler(int sig, siginfo_t *info, void *p) +static void hard_handler(int sig, siginfo_t *si, void *p) { struct ucontext *uc = p; mcontext_t *mc = &uc->uc_mcontext; @@ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p) while ((sig = ffs(pending)) != 0){ sig--; pending &= ~(1 << sig); - (*handlers[sig])(sig, mc); + (*handlers[sig])(sig, si, mc); } /* @@ -273,9 +274,12 @@ void unblock_signals(void) * Deal with SIGIO first because the alarm handler might * schedule, leaving the pending SIGIO stranded until we come * back here. + * + * SIGIO's handler doesn't use siginfo or mcontext, + * so they can be NULL. */ if (save_pending & SIGIO_MASK) - sig_handler_common(SIGIO, NULL); + sig_handler_common(SIGIO, NULL, NULL); if (save_pending & SIGVTALRM_MASK) real_alarm_handler(NULL); diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index cd65727854eb..d93bb40499f7 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -346,6 +346,10 @@ void userspace(struct uml_pt_regs *regs) int err, status, op, pid = userspace_pid[0]; /* To prevent races if using_sysemu changes under us.*/ int local_using_sysemu; + siginfo_t si; + + /* Handle any immediate reschedules or signals */ + interrupt_end(); if (getitimer(ITIMER_VIRTUAL, &timer)) printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno); @@ -404,13 +408,17 @@ void userspace(struct uml_pt_regs *regs) if (WIFSTOPPED(status)) { int sig = WSTOPSIG(status); + + ptrace(PTRACE_GETSIGINFO, pid, 0, &si); + switch (sig) { case SIGSEGV: if (PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) { get_skas_faultinfo(pid, ®s->faultinfo); - (*sig_info[SIGSEGV])(SIGSEGV, regs); + (*sig_info[SIGSEGV])(SIGSEGV, &si, + regs); } else handle_segv(pid, regs); break; @@ -418,14 +426,14 @@ void userspace(struct uml_pt_regs *regs) handle_trap(pid, regs, local_using_sysemu); break; case SIGTRAP: - relay_signal(SIGTRAP, regs); + relay_signal(SIGTRAP, &si, regs); break; case SIGVTALRM: now = os_nsecs(); if (now < nsecs) break; block_signals(); - (*sig_info[sig])(sig, regs); + (*sig_info[sig])(sig, &si, regs); unblock_signals(); nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + @@ -439,7 +447,7 @@ void userspace(struct uml_pt_regs *regs) case SIGFPE: case SIGWINCH: block_signals(); - (*sig_info[sig])(sig, regs); + (*sig_info[sig])(sig, &si, regs); unblock_signals(); break; default: diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 910499d76a67..f60238559af3 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts) static void deliver_alarm(void) { - alarm_handler(SIGVTALRM, NULL); + alarm_handler(SIGVTALRM, NULL, NULL); } static unsigned long long sleep_time(unsigned long long nsecs) diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h index 950dfb7b8417..e72cd0df5ba3 100644 --- a/arch/x86/um/asm/ptrace.h +++ b/arch/x86/um/asm/ptrace.h @@ -30,10 +30,10 @@ #define profile_pc(regs) PT_REGS_IP(regs) #define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2) -#define UPT_SET_SYSCALL_RETURN(r, res) (UPT_AX(r) = (res)) +#define PT_REGS_SET_SYSCALL_RETURN(r, res) (PT_REGS_AX(r) = (res)) -static inline long regs_return_value(struct uml_pt_regs *regs) +static inline long regs_return_value(struct pt_regs *regs) { - return UPT_AX(regs); + return PT_REGS_AX(regs); } #endif /* __UM_X86_PTRACE_H */