Commit 1871e845 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

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
parents a6dc7725 b070989a
...@@ -7382,6 +7382,7 @@ W: http://user-mode-linux.sourceforge.net ...@@ -7382,6 +7382,7 @@ W: http://user-mode-linux.sourceforge.net
S: Maintained S: Maintained
F: Documentation/virtual/uml/ F: Documentation/virtual/uml/
F: arch/um/ F: arch/um/
F: arch/x86/um/
F: fs/hostfs/ F: fs/hostfs/
F: fs/hppfs/ F: fs/hppfs/
......
...@@ -163,7 +163,7 @@ CONFIG_CGROUP_SCHED=y ...@@ -163,7 +163,7 @@ CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y
# CONFIG_CFS_BANDWIDTH is not set # CONFIG_CFS_BANDWIDTH is not set
# CONFIG_RT_GROUP_SCHED 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_DEBUG_BLK_CGROUP is not set
# CONFIG_CHECKPOINT_RESTORE is not set # CONFIG_CHECKPOINT_RESTORE is not set
CONFIG_NAMESPACES=y CONFIG_NAMESPACES=y
......
...@@ -150,9 +150,11 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty) ...@@ -150,9 +150,11 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
static void line_timer_cb(struct work_struct *work) static void line_timer_cb(struct work_struct *work)
{ {
struct line *line = container_of(work, struct line, task.work); struct line *line = container_of(work, struct line, task.work);
struct tty_struct *tty = tty_port_tty_get(&line->port);
if (!line->throttled) 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) int enable_chan(struct line *line)
......
...@@ -19,9 +19,11 @@ static irqreturn_t line_interrupt(int irq, void *data) ...@@ -19,9 +19,11 @@ static irqreturn_t line_interrupt(int irq, void *data)
{ {
struct chan *chan = data; struct chan *chan = data;
struct line *line = chan->line; struct line *line = chan->line;
struct tty_struct *tty = tty_port_tty_get(&line->port);
if (line) if (line)
chan_interrupt(line, line->tty, irq); chan_interrupt(line, tty, irq);
tty_kref_put(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -219,92 +221,6 @@ void line_set_termios(struct tty_struct *tty, struct ktermios * old) ...@@ -219,92 +221,6 @@ void line_set_termios(struct tty_struct *tty, struct ktermios * old)
/* nothing */ /* 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) void line_throttle(struct tty_struct *tty)
{ {
struct line *line = tty->driver_data; struct line *line = tty->driver_data;
...@@ -333,7 +249,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data) ...@@ -333,7 +249,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
{ {
struct chan *chan = data; struct chan *chan = data;
struct line *line = chan->line; struct line *line = chan->line;
struct tty_struct *tty = line->tty; struct tty_struct *tty;
int err; int err;
/* /*
...@@ -352,10 +268,13 @@ static irqreturn_t line_write_interrupt(int irq, void *data) ...@@ -352,10 +268,13 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
} }
spin_unlock(&line->lock); spin_unlock(&line->lock);
tty = tty_port_tty_get(&line->port);
if (tty == NULL) if (tty == NULL)
return IRQ_NONE; return IRQ_NONE;
tty_wakeup(tty); tty_wakeup(tty);
tty_kref_put(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -377,43 +296,14 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) ...@@ -377,43 +296,14 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
return err; return err;
} }
/* static int line_activate(struct tty_port *port, struct tty_struct *tty)
* 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)
{ {
struct line *line = &lines[tty->index]; int ret;
int err = -ENODEV; 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); ret = enable_chan(line);
if (err) /* line_close() will be called by our caller */ if (ret)
goto out_unlock; return ret;
if (!line->sigio) { if (!line->sigio) {
chan_enable_winch(line->chan_out, tty); chan_enable_winch(line->chan_out, tty);
...@@ -421,44 +311,60 @@ int line_open(struct line *lines, struct tty_struct *tty) ...@@ -421,44 +311,60 @@ int line_open(struct line *lines, struct tty_struct *tty)
} }
chan_window_size(line, &tty->winsize.ws_row, chan_window_size(line, &tty->winsize.ws_row,
&tty->winsize.ws_col); &tty->winsize.ws_col);
out_unlock:
mutex_unlock(&line->count_lock); return 0;
return err;
} }
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; struct line *line = tty->driver_data;
/* return tty_port_open(&line->port, tty, filp);
* 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! */ int line_install(struct tty_driver *driver, struct tty_struct *tty,
flush_buffer(line); struct line *line)
{
int ret;
mutex_lock(&line->count_lock); ret = tty_standard_install(driver, tty);
BUG_ON(!line->valid); if (ret)
return ret;
if (--line->count) tty->driver_data = line;
goto out_unlock;
line->tty = NULL; return 0;
tty->driver_data = NULL; }
static void unregister_winch(struct tty_struct *tty);
void line_cleanup(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
if (line->sigio) { if (line->sigio) {
unregister_winch(tty); unregister_winch(tty);
line->sigio = 0; line->sigio = 0;
} }
}
void line_close(struct tty_struct *tty, struct file * filp)
{
struct line *line = tty->driver_data;
out_unlock: tty_port_close(&line->port, tty, filp);
mutex_unlock(&line->count_lock); }
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) void close_lines(struct line *lines, int nlines)
...@@ -476,9 +382,7 @@ int setup_one_line(struct line *lines, int n, char *init, ...@@ -476,9 +382,7 @@ int setup_one_line(struct line *lines, int n, char *init,
struct tty_driver *driver = line->driver->driver; struct tty_driver *driver = line->driver->driver;
int err = -EINVAL; int err = -EINVAL;
mutex_lock(&line->count_lock); if (line->port.count) {
if (line->count) {
*error_out = "Device is already open"; *error_out = "Device is already open";
goto out; goto out;
} }
...@@ -519,7 +423,6 @@ int setup_one_line(struct line *lines, int n, char *init, ...@@ -519,7 +423,6 @@ int setup_one_line(struct line *lines, int n, char *init,
} }
} }
out: out:
mutex_unlock(&line->count_lock);
return err; return err;
} }
...@@ -607,13 +510,17 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, ...@@ -607,13 +510,17 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
line = &lines[dev]; line = &lines[dev];
mutex_lock(&line->count_lock);
if (!line->valid) if (!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1); CONFIG_CHUNK(str, size, n, "none", 1);
else if (line->tty == NULL) else {
CONFIG_CHUNK(str, size, n, line->init_str, 1); struct tty_struct *tty = tty_port_tty_get(&line->port);
else n = chan_config_string(line, str, size, error_out); if (tty == NULL) {
mutex_unlock(&line->count_lock); 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; return n;
} }
...@@ -663,8 +570,9 @@ int register_lines(struct line_driver *line_driver, ...@@ -663,8 +570,9 @@ int register_lines(struct line_driver *line_driver,
driver->init_termios = tty_std_termios; driver->init_termios = tty_std_termios;
for (i = 0; i < nlines; i++) { 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); spin_lock_init(&lines[i].lock);
mutex_init(&lines[i].count_lock);
lines[i].driver = line_driver; lines[i].driver = line_driver;
INIT_LIST_HEAD(&lines[i].chan_list); INIT_LIST_HEAD(&lines[i].chan_list);
} }
......
...@@ -32,9 +32,7 @@ struct line_driver { ...@@ -32,9 +32,7 @@ struct line_driver {
}; };
struct line { struct line {
struct tty_struct *tty; struct tty_port port;
struct mutex count_lock;
unsigned long count;
int valid; int valid;
char *init_str; char *init_str;
...@@ -59,7 +57,11 @@ struct line { ...@@ -59,7 +57,11 @@ struct line {
}; };
extern void line_close(struct tty_struct *tty, struct file * filp); 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, extern int line_setup(char **conf, unsigned nlines, char **def,
char *init, char *name); char *init, char *name);
extern int line_write(struct tty_struct *tty, const unsigned char *buf, 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); ...@@ -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_buffer(struct tty_struct *tty);
extern void line_flush_chars(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_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_throttle(struct tty_struct *tty);
extern void line_unthrottle(struct tty_struct *tty); extern void line_unthrottle(struct tty_struct *tty);
......
...@@ -87,40 +87,13 @@ static int ssl_remove(int n, char **error_out) ...@@ -87,40 +87,13 @@ static int ssl_remove(int n, char **error_out)
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;
}
#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)
{ {
return line_install(driver, tty, &serial_lines[tty->index]);
} }
#endif
static const struct tty_operations ssl_ops = { static const struct tty_operations ssl_ops = {
.open = ssl_open, .open = line_open,
.close = line_close, .close = line_close,
.write = line_write, .write = line_write,
.put_char = line_put_char, .put_char = line_put_char,
...@@ -129,14 +102,11 @@ static const struct tty_operations ssl_ops = { ...@@ -129,14 +102,11 @@ static const struct tty_operations ssl_ops = {
.flush_buffer = line_flush_buffer, .flush_buffer = line_flush_buffer,
.flush_chars = line_flush_chars, .flush_chars = line_flush_chars,
.set_termios = line_set_termios, .set_termios = line_set_termios,
.ioctl = line_ioctl,
.throttle = line_throttle, .throttle = line_throttle,
.unthrottle = line_unthrottle, .unthrottle = line_unthrottle,
#if 0 .install = ssl_install,
.stop = ssl_stop, .cleanup = line_cleanup,
.start = ssl_start, .hangup = line_hangup,
.hangup = ssl_hangup,
#endif
}; };
/* Changed by ssl_init and referenced by ssl_exit, which are both serialized /* Changed by ssl_init and referenced by ssl_exit, which are both serialized
......
...@@ -89,21 +89,17 @@ static int con_remove(int n, char **error_out) ...@@ -89,21 +89,17 @@ static int con_remove(int n, char **error_out)
return line_remove(vts, ARRAY_SIZE(vts), n, 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 */ /* Set in an initcall, checked in an exitcall */
static int con_init_done = 0; 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 = { static const struct tty_operations console_ops = {
.open = con_open, .open = line_open,
.install = con_install,
.close = line_close, .close = line_close,
.write = line_write, .write = line_write,
.put_char = line_put_char, .put_char = line_put_char,
...@@ -112,9 +108,10 @@ static const struct tty_operations console_ops = { ...@@ -112,9 +108,10 @@ static const struct tty_operations console_ops = {
.flush_buffer = line_flush_buffer, .flush_buffer = line_flush_buffer,
.flush_chars = line_flush_chars, .flush_chars = line_flush_chars,
.set_termios = line_set_termios, .set_termios = line_set_termios,
.ioctl = line_ioctl,
.throttle = line_throttle, .throttle = line_throttle,
.unthrottle = line_unthrottle, .unthrottle = line_unthrottle,
.cleanup = line_cleanup,
.hangup = line_hangup,
}; };
static void uml_console_write(struct console *console, const char *string, static void uml_console_write(struct console *console, const char *string,
......
...@@ -514,7 +514,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) ...@@ -514,7 +514,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
goto 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) if (fd < 0)
return fd; return fd;
......
...@@ -37,6 +37,8 @@ extern int putreg(struct task_struct *child, int regno, unsigned long value); ...@@ -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 int arch_copy_tls(struct task_struct *new);
extern void clear_flushed_tls(struct task_struct *task); 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 #endif
......
...@@ -60,7 +60,8 @@ extern unsigned long host_task_size; ...@@ -60,7 +60,8 @@ extern unsigned long host_task_size;
extern int linux_main(int argc, char **argv); 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 #endif
......
...@@ -20,7 +20,8 @@ struct irq_fd { ...@@ -20,7 +20,8 @@ struct irq_fd {
enum { IRQ_READ, IRQ_WRITE }; 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 free_irq_by_fd(int fd);
extern void reactivate_fd(int fd, int irqnum); extern void reactivate_fd(int fd, int irqnum);
extern void deactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum);
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "sysdep/ptrace.h" #include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h" #include "sysdep/faultinfo.h"
struct siginfo;
extern int uml_exitcode; extern int uml_exitcode;
extern int ncpus; extern int ncpus;
...@@ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order); ...@@ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order);
extern int do_signal(void); extern int do_signal(void);
extern void interrupt_end(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, extern unsigned long segv(struct faultinfo fi, unsigned long ip,
int is_user, struct uml_pt_regs *regs); int is_user, struct uml_pt_regs *regs);
...@@ -33,9 +35,8 @@ extern unsigned int do_IRQ(int irq, 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 int smp_sigio_handler(void);
extern void initial_thread_cb(void (*proc)(void *), void *arg); extern void initial_thread_cb(void (*proc)(void *), void *arg);
extern int is_syscall(unsigned long addr); 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 int start_uml(void);
extern void paging_init(void); extern void paging_init(void);
...@@ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested); ...@@ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested);
extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
extern int singlestepping(void *t); extern int singlestepping(void *t);
extern void segv_handler(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 uml_pt_regs *regs); extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
extern void winch(int sig, 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)); extern void fatal_sigsegv(void) __attribute__ ((noreturn));
......
...@@ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds; ...@@ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds;
extern void free_irqs(void); 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; struct irq_fd *irq_fd;
int n; int n;
......
...@@ -151,12 +151,10 @@ void new_thread_handler(void) ...@@ -151,12 +151,10 @@ void new_thread_handler(void)
* 0 if it just exits * 0 if it just exits
*/ */
n = run_kernel_thread(fn, arg, &current->thread.exec_buf); n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
if (n == 1) { if (n == 1)
/* Handle any immediate reschedules or signals */
interrupt_end();
userspace(&current->thread.regs.regs); userspace(&current->thread.regs.regs);
} else
else do_exit(0); do_exit(0);
} }
/* Called magically, see new_thread_handler above */ /* Called magically, see new_thread_handler above */
...@@ -175,9 +173,6 @@ void fork_handler(void) ...@@ -175,9 +173,6 @@ void fork_handler(void)
current->thread.prev_sched = NULL; current->thread.prev_sched = NULL;
/* Handle any immediate reschedules or signals */
interrupt_end();
userspace(&current->thread.regs.regs); userspace(&current->thread.regs.regs);
} }
...@@ -193,7 +188,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -193,7 +188,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
if (current->thread.forking) { if (current->thread.forking) {
memcpy(&p->thread.regs.regs, &regs->regs, memcpy(&p->thread.regs.regs, &regs->regs,
sizeof(p->thread.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) if (sp != 0)
REGS_SP(p->thread.regs.regs.gp) = sp; REGS_SP(p->thread.regs.regs.gp) = sp;
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include "linux/audit.h" #include <linux/audit.h>
#include "linux/ptrace.h" #include <linux/ptrace.h>
#include "linux/sched.h" #include <linux/sched.h>
#include "asm/uaccess.h" #include <linux/tracehook.h>
#include "skas_ptrace.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, ...@@ -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 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check * 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; audit_syscall_entry(HOST_AUDIT_ARCH,
int tracesysgood; UPT_SYSCALL_NR(&regs->regs),
UPT_SYSCALL_ARG1(&regs->regs),
if (!entryexit) UPT_SYSCALL_ARG2(&regs->regs),
audit_syscall_entry(HOST_AUDIT_ARCH, UPT_SYSCALL_ARG3(&regs->regs),
UPT_SYSCALL_NR(regs), UPT_SYSCALL_ARG4(&regs->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);
if (!test_thread_flag(TIF_SYSCALL_TRACE)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
return; return;
if (!(current->ptrace & PT_PTRACED)) tracehook_report_syscall_entry(regs);
return; }
/* void syscall_trace_leave(struct pt_regs *regs)
* the 0x80 provides a way for the tracing parent to distinguish {
* between a syscall stop and SIGTRAP delivery int ptraced = current->ptrace;
*/
tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
if (entryexit) /* force do_signal() --> is_syscall() */ audit_syscall_exit(regs);
set_thread_flag(TIF_SIGPENDING);
/* /* Fake a debug trap */
* this isn't the same as continuing with a signal, but it will do if (ptraced & PT_DTRACE)
* for normal use. strace only continues with a signal if the send_sigtrap(current, &regs->regs, 0);
* stopping signal is not SIGTRAP. -brl
*/ if (!test_thread_flag(TIF_SYSCALL_TRACE))
if (current->exit_code) { return;
send_sig(current->exit_code, current, 1);
current->exit_code = 0; tracehook_report_syscall_exit(regs, 0);
} /* force do_signal() --> is_syscall() */
if (ptraced & PT_PTRACED)
set_thread_flag(TIF_SIGPENDING);
} }
...@@ -18,7 +18,7 @@ void handle_syscall(struct uml_pt_regs *r) ...@@ -18,7 +18,7 @@ void handle_syscall(struct uml_pt_regs *r)
long result; long result;
int syscall; int syscall;
syscall_trace(r, 0); syscall_trace_enter(regs);
/* /*
* This should go in the declaration of syscall, but when I do that, * 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) ...@@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r)
result = -ENOSYS; result = -ENOSYS;
else result = EXECUTE_SYSCALL(syscall, regs); 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);
} }
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "kern_util.h" #include "kern_util.h"
#include "os.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; unsigned long flags;
......
...@@ -172,7 +172,7 @@ void fatal_sigsegv(void) ...@@ -172,7 +172,7 @@ void fatal_sigsegv(void)
os_dump_core(); 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); struct faultinfo * fi = UPT_FAULTINFO(regs);
...@@ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, ...@@ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
return 0; 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 (!UPT_IS_USER(regs)) {
if (sig == SIGBUS) if (sig == SIGBUS)
printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " 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) ...@@ -269,18 +272,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs)
arch_examine_signal(sig, regs); arch_examine_signal(sig, regs);
current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); memset(&clean_si, 0, sizeof(clean_si));
force_sig(sig, current); 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) if (current->thread.fault_catcher != NULL)
UML_LONGJMP(current->thread.fault_catcher, 1); 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); do_IRQ(WINCH_IRQ, regs);
} }
......
void alarm_handler(int, mcontext_t *); void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
...@@ -13,8 +13,9 @@ ...@@ -13,8 +13,9 @@
#include "kern_util.h" #include "kern_util.h"
#include "os.h" #include "os.h"
#include "sysdep/mcontext.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, [SIGTRAP] = relay_signal,
[SIGFPE] = relay_signal, [SIGFPE] = relay_signal,
[SIGILL] = relay_signal, [SIGILL] = relay_signal,
...@@ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { ...@@ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
[SIGIO] = sigio_handler, [SIGIO] = sigio_handler,
[SIGVTALRM] = timer_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; struct uml_pt_regs r;
int save_errno = errno; int save_errno = errno;
...@@ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) ...@@ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc)
if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
unblock_signals(); unblock_signals();
(*sig_info[sig])(sig, &r); (*sig_info[sig])(sig, si, &r);
errno = save_errno; errno = save_errno;
} }
...@@ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) ...@@ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc)
static int signals_enabled; static int signals_enabled;
static unsigned int signals_pending; 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; int enabled;
...@@ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc) ...@@ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc)
block_signals(); block_signals();
sig_handler_common(sig, mc); sig_handler_common(sig, si, mc);
set_signals(enabled); set_signals(enabled);
} }
...@@ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc) ...@@ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc)
get_regs_from_mc(&regs, mc); get_regs_from_mc(&regs, mc);
regs.is_user = 0; regs.is_user = 0;
unblock_signals(); 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; int enabled;
...@@ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size) ...@@ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size)
panic("enabling signal stack failed, errno = %d\n", errno); 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, [SIGSEGV] = sig_handler,
[SIGBUS] = sig_handler, [SIGBUS] = sig_handler,
[SIGILL] = sig_handler, [SIGILL] = sig_handler,
...@@ -132,7 +133,7 @@ static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { ...@@ -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; struct ucontext *uc = p;
mcontext_t *mc = &uc->uc_mcontext; mcontext_t *mc = &uc->uc_mcontext;
...@@ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p) ...@@ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p)
while ((sig = ffs(pending)) != 0){ while ((sig = ffs(pending)) != 0){
sig--; sig--;
pending &= ~(1 << sig); pending &= ~(1 << sig);
(*handlers[sig])(sig, mc); (*handlers[sig])(sig, si, mc);
} }
/* /*
...@@ -273,9 +274,12 @@ void unblock_signals(void) ...@@ -273,9 +274,12 @@ void unblock_signals(void)
* Deal with SIGIO first because the alarm handler might * Deal with SIGIO first because the alarm handler might
* schedule, leaving the pending SIGIO stranded until we come * schedule, leaving the pending SIGIO stranded until we come
* back here. * back here.
*
* SIGIO's handler doesn't use siginfo or mcontext,
* so they can be NULL.
*/ */
if (save_pending & SIGIO_MASK) if (save_pending & SIGIO_MASK)
sig_handler_common(SIGIO, NULL); sig_handler_common(SIGIO, NULL, NULL);
if (save_pending & SIGVTALRM_MASK) if (save_pending & SIGVTALRM_MASK)
real_alarm_handler(NULL); real_alarm_handler(NULL);
......
...@@ -346,6 +346,10 @@ void userspace(struct uml_pt_regs *regs) ...@@ -346,6 +346,10 @@ void userspace(struct uml_pt_regs *regs)
int err, status, op, pid = userspace_pid[0]; int err, status, op, pid = userspace_pid[0];
/* To prevent races if using_sysemu changes under us.*/ /* To prevent races if using_sysemu changes under us.*/
int local_using_sysemu; int local_using_sysemu;
siginfo_t si;
/* Handle any immediate reschedules or signals */
interrupt_end();
if (getitimer(ITIMER_VIRTUAL, &timer)) if (getitimer(ITIMER_VIRTUAL, &timer))
printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno); printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno);
...@@ -404,13 +408,17 @@ void userspace(struct uml_pt_regs *regs) ...@@ -404,13 +408,17 @@ void userspace(struct uml_pt_regs *regs)
if (WIFSTOPPED(status)) { if (WIFSTOPPED(status)) {
int sig = WSTOPSIG(status); int sig = WSTOPSIG(status);
ptrace(PTRACE_GETSIGINFO, pid, 0, &si);
switch (sig) { switch (sig) {
case SIGSEGV: case SIGSEGV:
if (PTRACE_FULL_FAULTINFO || if (PTRACE_FULL_FAULTINFO ||
!ptrace_faultinfo) { !ptrace_faultinfo) {
get_skas_faultinfo(pid, get_skas_faultinfo(pid,
&regs->faultinfo); &regs->faultinfo);
(*sig_info[SIGSEGV])(SIGSEGV, regs); (*sig_info[SIGSEGV])(SIGSEGV, &si,
regs);
} }
else handle_segv(pid, regs); else handle_segv(pid, regs);
break; break;
...@@ -418,14 +426,14 @@ void userspace(struct uml_pt_regs *regs) ...@@ -418,14 +426,14 @@ void userspace(struct uml_pt_regs *regs)
handle_trap(pid, regs, local_using_sysemu); handle_trap(pid, regs, local_using_sysemu);
break; break;
case SIGTRAP: case SIGTRAP:
relay_signal(SIGTRAP, regs); relay_signal(SIGTRAP, &si, regs);
break; break;
case SIGVTALRM: case SIGVTALRM:
now = os_nsecs(); now = os_nsecs();
if (now < nsecs) if (now < nsecs)
break; break;
block_signals(); block_signals();
(*sig_info[sig])(sig, regs); (*sig_info[sig])(sig, &si, regs);
unblock_signals(); unblock_signals();
nsecs = timer.it_value.tv_sec * nsecs = timer.it_value.tv_sec *
UM_NSEC_PER_SEC + UM_NSEC_PER_SEC +
...@@ -439,7 +447,7 @@ void userspace(struct uml_pt_regs *regs) ...@@ -439,7 +447,7 @@ void userspace(struct uml_pt_regs *regs)
case SIGFPE: case SIGFPE:
case SIGWINCH: case SIGWINCH:
block_signals(); block_signals();
(*sig_info[sig])(sig, regs); (*sig_info[sig])(sig, &si, regs);
unblock_signals(); unblock_signals();
break; break;
default: default:
......
...@@ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts) ...@@ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts)
static void deliver_alarm(void) static void deliver_alarm(void)
{ {
alarm_handler(SIGVTALRM, NULL); alarm_handler(SIGVTALRM, NULL, NULL);
} }
static unsigned long long sleep_time(unsigned long long nsecs) static unsigned long long sleep_time(unsigned long long nsecs)
......
...@@ -30,10 +30,10 @@ ...@@ -30,10 +30,10 @@
#define profile_pc(regs) PT_REGS_IP(regs) #define profile_pc(regs) PT_REGS_IP(regs)
#define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2) #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 */ #endif /* __UM_X86_PTRACE_H */
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