Skip to content

Commit ff6a179

Browse files
kot-begemot-ukrichardweinberger
authored andcommitted
Epoll based IRQ controller
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>
1 parent 4d1a535 commit ff6a179

File tree

8 files changed

+444
-317
lines changed

8 files changed

+444
-317
lines changed

arch/um/drivers/chan_kern.c

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -171,56 +171,19 @@ int enable_chan(struct line *line)
171171
return err;
172172
}
173173

174-
/* Items are added in IRQ context, when free_irq can't be called, and
175-
* removed in process context, when it can.
176-
* This handles interrupt sources which disappear, and which need to
177-
* be permanently disabled. This is discovered in IRQ context, but
178-
* the freeing of the IRQ must be done later.
179-
*/
180-
static DEFINE_SPINLOCK(irqs_to_free_lock);
181-
static LIST_HEAD(irqs_to_free);
182-
183-
void free_irqs(void)
184-
{
185-
struct chan *chan;
186-
LIST_HEAD(list);
187-
struct list_head *ele;
188-
unsigned long flags;
189-
190-
spin_lock_irqsave(&irqs_to_free_lock, flags);
191-
list_splice_init(&irqs_to_free, &list);
192-
spin_unlock_irqrestore(&irqs_to_free_lock, flags);
193-
194-
list_for_each(ele, &list) {
195-
chan = list_entry(ele, struct chan, free_list);
196-
197-
if (chan->input && chan->enabled)
198-
um_free_irq(chan->line->driver->read_irq, chan);
199-
if (chan->output && chan->enabled)
200-
um_free_irq(chan->line->driver->write_irq, chan);
201-
chan->enabled = 0;
202-
}
203-
}
204-
205174
static void close_one_chan(struct chan *chan, int delay_free_irq)
206175
{
207-
unsigned long flags;
208-
209176
if (!chan->opened)
210177
return;
211178

212-
if (delay_free_irq) {
213-
spin_lock_irqsave(&irqs_to_free_lock, flags);
214-
list_add(&chan->free_list, &irqs_to_free);
215-
spin_unlock_irqrestore(&irqs_to_free_lock, flags);
216-
}
217-
else {
218-
if (chan->input && chan->enabled)
219-
um_free_irq(chan->line->driver->read_irq, chan);
220-
if (chan->output && chan->enabled)
221-
um_free_irq(chan->line->driver->write_irq, chan);
222-
chan->enabled = 0;
223-
}
179+
/* we can safely call free now - it will be marked
180+
* as free and freed once the IRQ stopped processing
181+
*/
182+
if (chan->input && chan->enabled)
183+
um_free_irq(chan->line->driver->read_irq, chan);
184+
if (chan->output && chan->enabled)
185+
um_free_irq(chan->line->driver->write_irq, chan);
186+
chan->enabled = 0;
224187
if (chan->ops->close != NULL)
225188
(*chan->ops->close)(chan->fd, chan->data);
226189

arch/um/drivers/line.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
284284
if (err)
285285
return err;
286286
if (output)
287-
err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
287+
err = um_request_irq(driver->write_irq, fd, IRQ_NONE,
288288
line_write_interrupt, IRQF_SHARED,
289289
driver->write_irq_name, data);
290290
return err;

arch/um/drivers/random.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/miscdevice.h>
1414
#include <linux/delay.h>
1515
#include <linux/uaccess.h>
16+
#include <init.h>
1617
#include <irq_kern.h>
1718
#include <os.h>
1819

@@ -154,14 +155,22 @@ static int __init rng_init (void)
154155
/*
155156
* rng_cleanup - shutdown RNG module
156157
*/
157-
static void __exit rng_cleanup (void)
158+
159+
static void cleanup(void)
160+
{
161+
free_irq_by_fd(random_fd);
162+
os_close_file(random_fd);
163+
}
164+
165+
static void __exit rng_cleanup(void)
158166
{
159167
os_close_file(random_fd);
160168
misc_deregister (&rng_miscdev);
161169
}
162170

163171
module_init (rng_init);
164172
module_exit (rng_cleanup);
173+
__uml_exitcall(cleanup);
165174

166175
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
167176
MODULE_LICENSE("GPL");

arch/um/drivers/ubd_kern.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,11 +1587,11 @@ int io_thread(void *arg)
15871587

15881588
do {
15891589
res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
1590-
if (res > 0) {
1590+
if (res >= 0) {
15911591
written += res;
15921592
} else {
15931593
if (res != -EAGAIN) {
1594-
printk("io_thread - read failed, fd = %d, "
1594+
printk("io_thread - write failed, fd = %d, "
15951595
"err = %d\n", kernel_fd, -n);
15961596
}
15971597
}

arch/um/include/shared/irq_user.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define __IRQ_USER_H__
88

99
#include <sysdep/ptrace.h>
10+
#include <stdbool.h>
1011

1112
struct irq_fd {
1213
struct irq_fd *next;
@@ -15,10 +16,17 @@ struct irq_fd {
1516
int type;
1617
int irq;
1718
int events;
18-
int current_events;
19+
bool active;
20+
bool pending;
21+
bool purge;
1922
};
2023

21-
enum { IRQ_READ, IRQ_WRITE };
24+
#define IRQ_READ 0
25+
#define IRQ_WRITE 1
26+
#define IRQ_NONE 2
27+
#define MAX_IRQ_TYPE (IRQ_NONE + 1)
28+
29+
2230

2331
struct siginfo;
2432
extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);

arch/um/include/shared/os.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,16 @@ extern void halt_skas(void);
290290
extern void reboot_skas(void);
291291

292292
/* irq.c */
293-
extern int os_waiting_for_events(struct irq_fd *active_fds);
294-
extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds);
295-
extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
296-
struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2);
297-
extern void os_free_irq_later(struct irq_fd *active_fds,
298-
int irq, void *dev_id);
299-
extern int os_get_pollfd(int i);
300-
extern void os_set_pollfd(int i, int fd);
293+
extern int os_waiting_for_events_epoll(void);
294+
extern void *os_epoll_get_data_pointer(int index);
295+
extern int os_epoll_triggered(int index, int events);
296+
extern int os_event_mask(int irq_type);
297+
extern int os_setup_epoll(void);
298+
extern int os_add_epoll_fd(int events, int fd, void *data);
299+
extern int os_mod_epoll_fd(int events, int fd, void *data);
300+
extern int os_del_epoll_fd(int fd);
301301
extern void os_set_ioignore(void);
302+
extern void os_close_epoll_fd(void);
302303

303304
/* sigio.c */
304305
extern int add_sigio_fd(int fd);

0 commit comments

Comments
 (0)