Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Aug 2012 23:45:02 +0000 (16:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Aug 2012 23:45:02 +0000 (16:45 -0700)
Pull UML fixes from Richard Weinberger:
 "This patch set contains mostly fixes and cleanups.  The UML tty driver
  uses now tty_port and is no longer broken like hell  :-)"

* 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: Add arch/x86/um to MAINTAINERS
  um: pass siginfo to guest process
  um: fix ubd_file_size for read-only files
  um: pull interrupt_end() into userspace()
  um: split syscall_trace(), pass pt_regs to it
  um: switch UPT_SET_RETURN_VALUE and regs_return_value to pt_regs
  um: set BLK_CGROUP=y in defconfig
  um: remove count_lock
  um: fully use tty_port
  um: Remove dead code
  um: remove line_ioctl()
  TTY: um/line, use tty from tty_port
  TTY: um/line, add tty_port

23 files changed:
MAINTAINERS
arch/um/defconfig
arch/um/drivers/chan_kern.c
arch/um/drivers/line.c
arch/um/drivers/line.h
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c
arch/um/drivers/ubd_kern.c
arch/um/include/asm/ptrace-generic.h
arch/um/include/shared/as-layout.h
arch/um/include/shared/irq_user.h
arch/um/include/shared/kern_util.h
arch/um/kernel/irq.c
arch/um/kernel/process.c
arch/um/kernel/ptrace.c
arch/um/kernel/skas/syscall.c
arch/um/kernel/time.c
arch/um/kernel/trap.c
arch/um/os-Linux/internal.h
arch/um/os-Linux/signal.c
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/time.c
arch/x86/um/asm/ptrace.h

index 6720018..94b823f 100644 (file)
@@ -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/
 
index fec0d5d..08107a7 100644 (file)
@@ -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
index 45e248c..87eebfe 100644 (file)
@@ -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)
index ac9d25c..bbaf2c5 100644 (file)
@@ -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;
-
-       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;
+       int ret;
+       struct line *line = tty->driver_data;
 
-       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 void unregister_winch(struct tty_struct *tty);
+static const struct tty_port_operations line_port_ops = {
+       .activate = line_activate,
+};
 
-void line_close(struct tty_struct *tty, struct file * filp)
+int line_open(struct tty_struct *tty, struct file *filp)
 {
        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;
+       return tty_port_open(&line->port, tty, filp);
+}
 
-       /* We ignore the error anyway! */
-       flush_buffer(line);
+int line_install(struct tty_driver *driver, struct tty_struct *tty,
+                struct line *line)
+{
+       int ret;
 
-       mutex_lock(&line->count_lock);
-       BUG_ON(!line->valid);
+       ret = tty_standard_install(driver, tty);
+       if (ret)
+               return ret;
 
-       if (--line->count)
-               goto out_unlock;
+       tty->driver_data = line;
 
-       line->tty = NULL;
-       tty->driver_data = NULL;
+       return 0;
+}
+
+static void unregister_winch(struct tty_struct *tty);
+
+void line_cleanup(struct tty_struct *tty)
+{
+       struct line *line = tty->driver_data;
 
        if (line->sigio) {
                unregister_winch(tty);
                line->sigio = 0;
        }
+}
+
+void line_close(struct tty_struct *tty, struct file * filp)
+{
+       struct line *line = tty->driver_data;
 
-out_unlock:
-       mutex_unlock(&line->count_lock);
+       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);
        }
index 0a18347..bae9561 100644 (file)
@@ -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);
 
index e09801a..7e86f00 100644 (file)
@@ -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)
-{
-       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;
-}
-
-#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)
+static int ssl_install(struct tty_driver *driver, struct tty_struct *tty)
 {
+       return line_install(driver, tty, &serial_lines[tty->index]);
 }
-#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
index 7663541..929b99a 100644 (file)
@@ -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,
index 20505ca..0643e5b 100644 (file)
@@ -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;
 
index e786a6a..442f1d0 100644 (file)
@@ -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
 
index 896e166..86daa54 100644 (file)
@@ -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
 
index c6c784d..2b6d703 100644 (file)
@@ -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);
index 00965d0..af6b6dc 100644 (file)
@@ -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));
 
 
index 00506c3..9883026 100644 (file)
@@ -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;
index ccb9a9d..57fc702 100644 (file)
@@ -151,12 +151,10 @@ void new_thread_handler(void)
         * 0 if it just exits
         */
        n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
-       if (n == 1) {
-               /* Handle any immediate reschedules or signals */
-               interrupt_end();
+       if (n == 1)
                userspace(&current->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(&current->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, &regs->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;
 
index 06b1903..694d551 100644 (file)
@@ -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 <linux/audit.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/tracehook.h>
+#include <asm/uaccess.h>
+#include <skas_ptrace.h>
 
 
 
@@ -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(&regs->regs),
+                           UPT_SYSCALL_ARG1(&regs->regs),
+                           UPT_SYSCALL_ARG2(&regs->regs),
+                           UPT_SYSCALL_ARG3(&regs->regs),
+                           UPT_SYSCALL_ARG4(&regs->regs));
 
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
                return;
 
-       if (!(current->ptrace & PT_PTRACED))
-               return;
+       tracehook_report_syscall_entry(regs);
+}
 
-       /*
-        * 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));
+void syscall_trace_leave(struct pt_regs *regs)
+{
+       int ptraced = current->ptrace;
 
-       if (entryexit) /* force do_signal() --> is_syscall() */
-               set_thread_flag(TIF_SIGPENDING);
+       audit_syscall_exit(regs);
 
-       /*
-        * 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;
-       }
+       /* Fake a debug trap */
+       if (ptraced & PT_DTRACE)
+               send_sigtrap(current, &regs->regs, 0);
+
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return;
+
+       tracehook_report_syscall_exit(regs, 0);
+       /* force do_signal() --> is_syscall() */
+       if (ptraced & PT_PTRACED)
+               set_thread_flag(TIF_SIGPENDING);
 }
index 05fbeb4..86368a0 100644 (file)
@@ -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);
 }
index d1a23fb..5f76d4b 100644 (file)
@@ -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;
 
index 3be6076..0353b98 100644 (file)
@@ -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);
 }
index 2c3c3ec..0dc2c9f 100644 (file)
@@ -1 +1 @@
-void alarm_handler(int, mcontext_t *);
+void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
index 2d22f1f..6366ce9 100644 (file)
@@ -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(&regs, mc);
        regs.is_user = 0;
        unblock_signals();
-       timer_handler(SIGVTALRM, &regs);
+       timer_handler(SIGVTALRM, NULL, &regs);
 }
 
-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);
index cd65727..d93bb40 100644 (file)
@@ -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,
                                                           &regs->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:
index 910499d..f602385 100644 (file)
@@ -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)
index 950dfb7..e72cd0d 100644 (file)
 #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 */