diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/include/shared/os.h | 8 | ||||
-rw-r--r-- | arch/um/kernel/irq.c | 17 | ||||
-rw-r--r-- | arch/um/os-Linux/sigio.c | 47 |
3 files changed, 56 insertions, 16 deletions
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index cd750d4edfb5..bc25c960f7e0 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -316,6 +316,14 @@ extern int add_sigio_fd(int fd); extern int ignore_sigio_fd(int fd); extern void maybe_sigio_broken(int fd); extern void sigio_broken(int fd); +/* + * unlocked versions for IRQ controller code. + * + * This is safe because it's used at suspend/resume and nothing + * else is running. + */ +extern int __add_sigio_fd(int fd); +extern int __ignore_sigio_fd(int fd); /* prctl.c */ extern int os_arch_prctl(int pid, int option, unsigned long *arg2); diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index ea43312cbfd3..3741d2380060 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -45,6 +45,7 @@ struct irq_entry { int fd; struct irq_reg reg[NUM_IRQ_TYPES]; bool suspended; + bool sigio_workaround; }; static DEFINE_SPINLOCK(irq_lock); @@ -392,7 +393,14 @@ void um_irqs_suspend(void) if (!entry->reg[t].events) continue; - if (entry->reg[t].wakeup) { + /* + * For the SIGIO_WRITE_IRQ, which is used to handle the + * SIGIO workaround thread, we need special handling: + * enable wake for it itself, but below we tell it about + * any FDs that should be suspended. + */ + if (entry->reg[t].wakeup || + entry->reg[t].irq == SIGIO_WRITE_IRQ) { wake = true; break; } @@ -401,6 +409,8 @@ void um_irqs_suspend(void) if (!wake) { entry->suspended = true; os_clear_fd_async(entry->fd); + entry->sigio_workaround = + !__ignore_sigio_fd(entry->fd); } } spin_unlock_irqrestore(&irq_lock, flags); @@ -418,6 +428,11 @@ void um_irqs_resume(void) WARN(err < 0, "os_set_fd_async returned %d\n", err); entry->suspended = false; + + if (entry->sigio_workaround) { + err = __add_sigio_fd(entry->fd); + WARN(err < 0, "add_sigio_returned %d\n", err); + } } } spin_unlock_irqrestore(&irq_lock, flags); diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 79cd6d6d6211..6597ea1986ff 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -164,47 +164,55 @@ static void update_thread(void) set_signals_trace(flags); } -int add_sigio_fd(int fd) +int __add_sigio_fd(int fd) { struct pollfd *p; int err, i, n; - sigio_lock(); for (i = 0; i < all_sigio_fds.used; i++) { if (all_sigio_fds.poll[i].fd == fd) break; } - if (i == all_sigio_fds.used) { - err = -ENOSPC; - goto out; - } + if (i == all_sigio_fds.used) + return -ENOSPC; p = &all_sigio_fds.poll[i]; for (i = 0; i < current_poll.used; i++) { if (current_poll.poll[i].fd == fd) - goto out; + return 0; } n = current_poll.used; err = need_poll(&next_poll, n + 1); if (err) - goto out; + return err; memcpy(next_poll.poll, current_poll.poll, current_poll.used * sizeof(struct pollfd)); next_poll.poll[n] = *p; next_poll.used = n + 1; update_thread(); - out: + + return 0; +} + + +int add_sigio_fd(int fd) +{ + int err; + + sigio_lock(); + err = __add_sigio_fd(fd); sigio_unlock(); + return err; } -int ignore_sigio_fd(int fd) +int __ignore_sigio_fd(int fd) { struct pollfd *p; - int err = 0, i, n = 0; + int err, i, n = 0; /* * This is called from exitcalls elsewhere in UML - if @@ -214,17 +222,16 @@ int ignore_sigio_fd(int fd) if (write_sigio_pid == -1) return -EIO; - sigio_lock(); for (i = 0; i < current_poll.used; i++) { if (current_poll.poll[i].fd == fd) break; } if (i == current_poll.used) - goto out; + return -ENOENT; err = need_poll(&next_poll, current_poll.used - 1); if (err) - goto out; + return err; for (i = 0; i < current_poll.used; i++) { p = ¤t_poll.poll[i]; @@ -234,8 +241,18 @@ int ignore_sigio_fd(int fd) next_poll.used = current_poll.used - 1; update_thread(); - out: + + return 0; +} + +int ignore_sigio_fd(int fd) +{ + int err; + + sigio_lock(); + err = __ignore_sigio_fd(fd); sigio_unlock(); + return err; } |