Commit 58f6259b authored by Rahul Singh's avatar Rahul Singh Committed by Juergen Gross

xen/evtchn: Introduce new IOCTL to bind static evtchn

Xen 4.17 supports the creation of static evtchns. To allow user space
application to bind static evtchns introduce new ioctl
"IOCTL_EVTCHN_BIND_STATIC". Existing IOCTL doing more than binding
that’s why we need to introduce the new IOCTL to only bind the static
event channels.

Static evtchns to be available for use during the lifetime of the
guest. When the application exits, __unbind_from_irq() ends up being
called from release() file operations because of that static evtchns
are getting closed. To avoid closing the static event channel, add the
new bool variable "is_static" in "struct irq_info" to mark the event
channel static when creating the event channel to avoid closing the
static evtchn.

Also, take this opportunity to remove the open-coded version of the
evtchn close in drivers/xen/evtchn.c file and use xen_evtchn_close().
Signed-off-by: default avatarRahul Singh <rahul.singh@arm.com>
Reviewed-by: default avatarOleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Acked-by: default avatarStefano Stabellini <sstabellini@kernel.org>
Link: https://lore.kernel.org/r/ae7329bf1713f83e4aad4f3fa0f316258c40a3e9.1689677042.git.rahul.singh@arm.comSigned-off-by: default avatarJuergen Gross <jgross@suse.com>
parent 0d8f7cc8
...@@ -112,6 +112,7 @@ struct irq_info { ...@@ -112,6 +112,7 @@ struct irq_info {
unsigned int irq_epoch; /* If eoi_cpu valid: irq_epoch of event */ unsigned int irq_epoch; /* If eoi_cpu valid: irq_epoch of event */
u64 eoi_time; /* Time in jiffies when to EOI. */ u64 eoi_time; /* Time in jiffies when to EOI. */
raw_spinlock_t lock; raw_spinlock_t lock;
bool is_static; /* Is event channel static */
union { union {
unsigned short virq; unsigned short virq;
...@@ -815,15 +816,6 @@ static void xen_free_irq(unsigned irq) ...@@ -815,15 +816,6 @@ static void xen_free_irq(unsigned irq)
irq_free_desc(irq); irq_free_desc(irq);
} }
static void xen_evtchn_close(evtchn_port_t port)
{
struct evtchn_close close;
close.port = port;
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
BUG();
}
/* Not called for lateeoi events. */ /* Not called for lateeoi events. */
static void event_handler_exit(struct irq_info *info) static void event_handler_exit(struct irq_info *info)
{ {
...@@ -982,6 +974,7 @@ static void __unbind_from_irq(unsigned int irq) ...@@ -982,6 +974,7 @@ static void __unbind_from_irq(unsigned int irq)
unsigned int cpu = cpu_from_irq(irq); unsigned int cpu = cpu_from_irq(irq);
struct xenbus_device *dev; struct xenbus_device *dev;
if (!info->is_static)
xen_evtchn_close(evtchn); xen_evtchn_close(evtchn);
switch (type_from_irq(irq)) { switch (type_from_irq(irq)) {
...@@ -1574,7 +1567,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority) ...@@ -1574,7 +1567,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority)
} }
EXPORT_SYMBOL_GPL(xen_set_irq_priority); EXPORT_SYMBOL_GPL(xen_set_irq_priority);
int evtchn_make_refcounted(evtchn_port_t evtchn) int evtchn_make_refcounted(evtchn_port_t evtchn, bool is_static)
{ {
int irq = get_evtchn_to_irq(evtchn); int irq = get_evtchn_to_irq(evtchn);
struct irq_info *info; struct irq_info *info;
...@@ -1590,6 +1583,7 @@ int evtchn_make_refcounted(evtchn_port_t evtchn) ...@@ -1590,6 +1583,7 @@ int evtchn_make_refcounted(evtchn_port_t evtchn)
WARN_ON(info->refcnt != -1); WARN_ON(info->refcnt != -1);
info->refcnt = 1; info->refcnt = 1;
info->is_static = is_static;
return 0; return 0;
} }
......
...@@ -366,10 +366,10 @@ static int evtchn_resize_ring(struct per_user_data *u) ...@@ -366,10 +366,10 @@ static int evtchn_resize_ring(struct per_user_data *u)
return 0; return 0;
} }
static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port) static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port,
bool is_static)
{ {
struct user_evtchn *evtchn; struct user_evtchn *evtchn;
struct evtchn_close close;
int rc = 0; int rc = 0;
/* /*
...@@ -402,14 +402,14 @@ static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port) ...@@ -402,14 +402,14 @@ static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port)
if (rc < 0) if (rc < 0)
goto err; goto err;
rc = evtchn_make_refcounted(port); rc = evtchn_make_refcounted(port, is_static);
return rc; return rc;
err: err:
/* bind failed, should close the port now */ /* bind failed, should close the port now */
close.port = port; if (!is_static)
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) xen_evtchn_close(port);
BUG();
del_evtchn(u, evtchn); del_evtchn(u, evtchn);
return rc; return rc;
} }
...@@ -456,7 +456,7 @@ static long evtchn_ioctl(struct file *file, ...@@ -456,7 +456,7 @@ static long evtchn_ioctl(struct file *file,
if (rc != 0) if (rc != 0)
break; break;
rc = evtchn_bind_to_user(u, bind_virq.port); rc = evtchn_bind_to_user(u, bind_virq.port, false);
if (rc == 0) if (rc == 0)
rc = bind_virq.port; rc = bind_virq.port;
break; break;
...@@ -482,7 +482,7 @@ static long evtchn_ioctl(struct file *file, ...@@ -482,7 +482,7 @@ static long evtchn_ioctl(struct file *file,
if (rc != 0) if (rc != 0)
break; break;
rc = evtchn_bind_to_user(u, bind_interdomain.local_port); rc = evtchn_bind_to_user(u, bind_interdomain.local_port, false);
if (rc == 0) if (rc == 0)
rc = bind_interdomain.local_port; rc = bind_interdomain.local_port;
break; break;
...@@ -507,7 +507,7 @@ static long evtchn_ioctl(struct file *file, ...@@ -507,7 +507,7 @@ static long evtchn_ioctl(struct file *file,
if (rc != 0) if (rc != 0)
break; break;
rc = evtchn_bind_to_user(u, alloc_unbound.port); rc = evtchn_bind_to_user(u, alloc_unbound.port, false);
if (rc == 0) if (rc == 0)
rc = alloc_unbound.port; rc = alloc_unbound.port;
break; break;
...@@ -536,6 +536,23 @@ static long evtchn_ioctl(struct file *file, ...@@ -536,6 +536,23 @@ static long evtchn_ioctl(struct file *file,
break; break;
} }
case IOCTL_EVTCHN_BIND_STATIC: {
struct ioctl_evtchn_bind bind;
struct user_evtchn *evtchn;
rc = -EFAULT;
if (copy_from_user(&bind, uarg, sizeof(bind)))
break;
rc = -EISCONN;
evtchn = find_evtchn(u, bind.port);
if (evtchn)
break;
rc = evtchn_bind_to_user(u, bind.port, true);
break;
}
case IOCTL_EVTCHN_NOTIFY: { case IOCTL_EVTCHN_NOTIFY: {
struct ioctl_evtchn_notify notify; struct ioctl_evtchn_notify notify;
struct user_evtchn *evtchn; struct user_evtchn *evtchn;
......
...@@ -101,4 +101,13 @@ struct ioctl_evtchn_restrict_domid { ...@@ -101,4 +101,13 @@ struct ioctl_evtchn_restrict_domid {
domid_t domid; domid_t domid;
}; };
/*
* Bind statically allocated @port.
*/
#define IOCTL_EVTCHN_BIND_STATIC \
_IOC(_IOC_NONE, 'E', 7, sizeof(struct ioctl_evtchn_bind))
struct ioctl_evtchn_bind {
unsigned int port;
};
#endif /* __LINUX_PUBLIC_EVTCHN_H__ */ #endif /* __LINUX_PUBLIC_EVTCHN_H__ */
...@@ -69,7 +69,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority); ...@@ -69,7 +69,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority);
/* /*
* Allow extra references to event channels exposed to userspace by evtchn * Allow extra references to event channels exposed to userspace by evtchn
*/ */
int evtchn_make_refcounted(evtchn_port_t evtchn); int evtchn_make_refcounted(evtchn_port_t evtchn, bool is_static);
int evtchn_get(evtchn_port_t evtchn); int evtchn_get(evtchn_port_t evtchn);
void evtchn_put(evtchn_port_t evtchn); void evtchn_put(evtchn_port_t evtchn);
...@@ -141,4 +141,13 @@ void xen_init_IRQ(void); ...@@ -141,4 +141,13 @@ void xen_init_IRQ(void);
irqreturn_t xen_debug_interrupt(int irq, void *dev_id); irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
static inline void xen_evtchn_close(evtchn_port_t port)
{
struct evtchn_close close;
close.port = port;
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
BUG();
}
#endif /* _XEN_EVENTS_H */ #endif /* _XEN_EVENTS_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