diff options
author | Juergen Gross <jgross@suse.com> | 2020-09-07 16:47:30 +0300 |
---|---|---|
committer | Juergen Gross <jgross@suse.com> | 2020-10-20 11:22:16 +0300 |
commit | e99502f76271d6bc4e374fe368c50c67a1fd3070 (patch) | |
tree | aadec8f665acbf22be002d42269ea26a9f01bea6 /drivers/xen/events/events_internal.h | |
parent | 7beb290caa2adb0a399e735a1e175db9aae0523a (diff) | |
download | linux-e99502f76271d6bc4e374fe368c50c67a1fd3070.tar.xz |
xen/events: defer eoi in case of excessive number of events
In case rogue guests are sending events at high frequency it might
happen that xen_evtchn_do_upcall() won't stop processing events in
dom0. As this is done in irq handling a crash might be the result.
In order to avoid that, delay further inter-domain events after some
time in xen_evtchn_do_upcall() by forcing eoi processing into a
worker on the same cpu, thus inhibiting new events coming in.
The time after which eoi processing is to be delayed is configurable
via a new module parameter "event_loop_timeout" which specifies the
maximum event loop time in jiffies (default: 2, the value was chosen
after some tests showing that a value of 2 was the lowest with an
only slight drop of dom0 network throughput while multiple guests
performed an event storm).
How long eoi processing will be delayed can be specified via another
parameter "event_eoi_delay" (again in jiffies, default 10, again the
value was chosen after testing with different delay values).
This is part of XSA-332.
Cc: stable@vger.kernel.org
Reported-by: Julien Grall <julien@xen.org>
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Reviewed-by: Wei Liu <wl@xen.org>
Diffstat (limited to 'drivers/xen/events/events_internal.h')
-rw-r--r-- | drivers/xen/events/events_internal.h | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h index 558abea19d0d..aac05cf52ced 100644 --- a/drivers/xen/events/events_internal.h +++ b/drivers/xen/events/events_internal.h @@ -30,11 +30,15 @@ enum xen_irq_type { */ struct irq_info { struct list_head list; + struct list_head eoi_list; int refcnt; enum xen_irq_type type; /* type */ unsigned irq; evtchn_port_t evtchn; /* event channel */ unsigned short cpu; /* cpu bound */ + unsigned short eoi_cpu; /* EOI must happen on this cpu */ + unsigned int irq_epoch; /* If eoi_cpu valid: irq_epoch of event */ + u64 eoi_time; /* Time in jiffies when to EOI. */ union { unsigned short virq; @@ -53,6 +57,8 @@ struct irq_info { #define PIRQ_SHAREABLE (1 << 1) #define PIRQ_MSI_GROUP (1 << 2) +struct evtchn_loop_ctrl; + struct evtchn_ops { unsigned (*max_channels)(void); unsigned (*nr_channels)(void); @@ -67,7 +73,7 @@ struct evtchn_ops { void (*mask)(evtchn_port_t port); void (*unmask)(evtchn_port_t port); - void (*handle_events)(unsigned cpu); + void (*handle_events)(unsigned cpu, struct evtchn_loop_ctrl *ctrl); void (*resume)(void); int (*percpu_init)(unsigned int cpu); @@ -78,6 +84,7 @@ extern const struct evtchn_ops *evtchn_ops; extern int **evtchn_to_irq; int get_evtchn_to_irq(evtchn_port_t evtchn); +void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl); struct irq_info *info_for_irq(unsigned irq); unsigned cpu_from_irq(unsigned irq); @@ -135,9 +142,10 @@ static inline void unmask_evtchn(evtchn_port_t port) return evtchn_ops->unmask(port); } -static inline void xen_evtchn_handle_events(unsigned cpu) +static inline void xen_evtchn_handle_events(unsigned cpu, + struct evtchn_loop_ctrl *ctrl) { - return evtchn_ops->handle_events(cpu); + return evtchn_ops->handle_events(cpu, ctrl); } static inline void xen_evtchn_resume(void) |