Skip to content

Commit

Permalink
Epoll based IRQ controller
Browse files Browse the repository at this point in the history
1. Removes the need to walk the IRQ/Device list to determine
who triggered the IRQ.
2. Improves scalability (up to several times performance
improvement for cases with 10s of devices).
3. Improves UML baseline IO performance for one disk + one NIC
use case by up to 10%.
4. Introduces write poll triggered IRQs.
5. Prerequisite for introducing high performance mmesg family
of functions in network IO.
6. Fixes RNG shutdown which was leaking a file descriptor

Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
  • Loading branch information
Anton Ivanov authored and richardweinberger committed Feb 19, 2018
1 parent 4d1a535 commit ff6a179
Show file tree
Hide file tree
Showing 8 changed files with 444 additions and 317 deletions.
53 changes: 8 additions & 45 deletions arch/um/drivers/chan_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,56 +171,19 @@ int enable_chan(struct line *line)
return err;
}

/* Items are added in IRQ context, when free_irq can't be called, and
* removed in process context, when it can.
* This handles interrupt sources which disappear, and which need to
* be permanently disabled. This is discovered in IRQ context, but
* the freeing of the IRQ must be done later.
*/
static DEFINE_SPINLOCK(irqs_to_free_lock);
static LIST_HEAD(irqs_to_free);

void free_irqs(void)
{
struct chan *chan;
LIST_HEAD(list);
struct list_head *ele;
unsigned long flags;

spin_lock_irqsave(&irqs_to_free_lock, flags);
list_splice_init(&irqs_to_free, &list);
spin_unlock_irqrestore(&irqs_to_free_lock, flags);

list_for_each(ele, &list) {
chan = list_entry(ele, struct chan, free_list);

if (chan->input && chan->enabled)
um_free_irq(chan->line->driver->read_irq, chan);
if (chan->output && chan->enabled)
um_free_irq(chan->line->driver->write_irq, chan);
chan->enabled = 0;
}
}

static void close_one_chan(struct chan *chan, int delay_free_irq)
{
unsigned long flags;

if (!chan->opened)
return;

if (delay_free_irq) {
spin_lock_irqsave(&irqs_to_free_lock, flags);
list_add(&chan->free_list, &irqs_to_free);
spin_unlock_irqrestore(&irqs_to_free_lock, flags);
}
else {
if (chan->input && chan->enabled)
um_free_irq(chan->line->driver->read_irq, chan);
if (chan->output && chan->enabled)
um_free_irq(chan->line->driver->write_irq, chan);
chan->enabled = 0;
}
/* we can safely call free now - it will be marked
* as free and freed once the IRQ stopped processing
*/
if (chan->input && chan->enabled)
um_free_irq(chan->line->driver->read_irq, chan);
if (chan->output && chan->enabled)
um_free_irq(chan->line->driver->write_irq, chan);
chan->enabled = 0;
if (chan->ops->close != NULL)
(*chan->ops->close)(chan->fd, chan->data);

Expand Down
2 changes: 1 addition & 1 deletion arch/um/drivers/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
if (err)
return err;
if (output)
err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
err = um_request_irq(driver->write_irq, fd, IRQ_NONE,
line_write_interrupt, IRQF_SHARED,
driver->write_irq_name, data);
return err;
Expand Down
11 changes: 10 additions & 1 deletion arch/um/drivers/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <init.h>
#include <irq_kern.h>
#include <os.h>

Expand Down Expand Up @@ -154,14 +155,22 @@ static int __init rng_init (void)
/*
* rng_cleanup - shutdown RNG module
*/
static void __exit rng_cleanup (void)

static void cleanup(void)
{
free_irq_by_fd(random_fd);
os_close_file(random_fd);
}

static void __exit rng_cleanup(void)
{
os_close_file(random_fd);
misc_deregister (&rng_miscdev);
}

module_init (rng_init);
module_exit (rng_cleanup);
__uml_exitcall(cleanup);

MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
MODULE_LICENSE("GPL");
4 changes: 2 additions & 2 deletions arch/um/drivers/ubd_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -1587,11 +1587,11 @@ int io_thread(void *arg)

do {
res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
if (res > 0) {
if (res >= 0) {
written += res;
} else {
if (res != -EAGAIN) {
printk("io_thread - read failed, fd = %d, "
printk("io_thread - write failed, fd = %d, "
"err = %d\n", kernel_fd, -n);
}
}
Expand Down
12 changes: 10 additions & 2 deletions arch/um/include/shared/irq_user.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define __IRQ_USER_H__

#include <sysdep/ptrace.h>
#include <stdbool.h>

struct irq_fd {
struct irq_fd *next;
Expand All @@ -15,10 +16,17 @@ struct irq_fd {
int type;
int irq;
int events;
int current_events;
bool active;
bool pending;
bool purge;
};

enum { IRQ_READ, IRQ_WRITE };
#define IRQ_READ 0
#define IRQ_WRITE 1
#define IRQ_NONE 2
#define MAX_IRQ_TYPE (IRQ_NONE + 1)



struct siginfo;
extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
Expand Down
17 changes: 9 additions & 8 deletions arch/um/include/shared/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,15 +290,16 @@ extern void halt_skas(void);
extern void reboot_skas(void);

/* irq.c */
extern int os_waiting_for_events(struct irq_fd *active_fds);
extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds);
extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2);
extern void os_free_irq_later(struct irq_fd *active_fds,
int irq, void *dev_id);
extern int os_get_pollfd(int i);
extern void os_set_pollfd(int i, int fd);
extern int os_waiting_for_events_epoll(void);
extern void *os_epoll_get_data_pointer(int index);
extern int os_epoll_triggered(int index, int events);
extern int os_event_mask(int irq_type);
extern int os_setup_epoll(void);
extern int os_add_epoll_fd(int events, int fd, void *data);
extern int os_mod_epoll_fd(int events, int fd, void *data);
extern int os_del_epoll_fd(int fd);
extern void os_set_ioignore(void);
extern void os_close_epoll_fd(void);

/* sigio.c */
extern int add_sigio_fd(int fd);
Expand Down

0 comments on commit ff6a179

Please sign in to comment.