diff options
author | Roger Pau Monné <royger@FreeBSD.org> | 2016-10-31 13:00:53 +0000 |
---|---|---|
committer | Roger Pau Monné <royger@FreeBSD.org> | 2016-10-31 13:00:53 +0000 |
commit | 0f4d7d9fd78bd396c1c768bdcc2a298991115433 (patch) | |
tree | 86a828b16db62ab74d764c995d51a6eeb531b5e7 /sys/x86/xen/xen_intr.c | |
parent | b2fd6999db269fd54228068dd0a719f86c4e002d (diff) | |
download | src-0f4d7d9fd78bd396c1c768bdcc2a298991115433.tar.gz src-0f4d7d9fd78bd396c1c768bdcc2a298991115433.zip |
xen/intr: add reference counts to event channels
Add a reference count to xenisrc. This is required for implementation of
unmap-notifications in the grant table userspace device (gntdev). We need to
hold a reference to the event channel port, in case the user deallocates the
port before we send the notification.
Submitted by: jaggi
Reviewed by: royger
Differential review: https://reviews.freebsd.org/D7429
Notes
Notes:
svn path=/head/; revision=308127
Diffstat (limited to 'sys/x86/xen/xen_intr.c')
-rw-r--r-- | sys/x86/xen/xen_intr.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c index 13ada84a2b34..66870b4c37f2 100644 --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/interrupt.h> #include <sys/pcpu.h> #include <sys/smp.h> +#include <sys/refcount.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -128,6 +129,7 @@ struct xenisrc { u_int xi_activehi:1; u_int xi_edgetrigger:1; u_int xi_masked:1; + volatile u_int xi_refcount; }; static void xen_intr_suspend(struct pic *); @@ -343,10 +345,8 @@ xen_intr_release_isrc(struct xenisrc *isrc) { mtx_lock(&xen_intr_isrc_lock); - if (isrc->xi_intsrc.is_handlers != 0) { - mtx_unlock(&xen_intr_isrc_lock); - return (EBUSY); - } + KASSERT(isrc->xi_intsrc.is_handlers == 0, + ("Release called, but xenisrc still in use")); evtchn_mask_port(isrc->xi_port); evtchn_clear_port(isrc->xi_port); @@ -417,6 +417,7 @@ xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port, } isrc->xi_port = local_port; xen_intr_port_to_isrc[local_port] = isrc; + refcount_init(&isrc->xi_refcount, 1); mtx_unlock(&xen_intr_isrc_lock); /* Assign the opaque handler (the event channel port) */ @@ -1508,6 +1509,13 @@ xen_intr_unbind(xen_intr_handle_t *port_handlep) if (isrc == NULL) return; + mtx_lock(&xen_intr_isrc_lock); + if (refcount_release(&isrc->xi_refcount) == 0) { + mtx_unlock(&xen_intr_isrc_lock); + return; + } + mtx_unlock(&xen_intr_isrc_lock); + if (isrc->xi_cookie != NULL) intr_remove_handler(isrc->xi_cookie); xen_intr_release_isrc(isrc); @@ -1563,6 +1571,31 @@ xen_intr_add_handler(device_t dev, driver_filter_t filter, return (error); } +int +xen_intr_get_evtchn_from_port(evtchn_port_t port, xen_intr_handle_t *handlep) +{ + + if (!is_valid_evtchn(port) || port >= NR_EVENT_CHANNELS) + return (EINVAL); + + if (handlep == NULL) { + return (EINVAL); + } + + mtx_lock(&xen_intr_isrc_lock); + if (xen_intr_port_to_isrc[port] == NULL) { + mtx_unlock(&xen_intr_isrc_lock); + return (EINVAL); + } + refcount_acquire(&xen_intr_port_to_isrc[port]->xi_refcount); + mtx_unlock(&xen_intr_isrc_lock); + + /* Assign the opaque handler (the event channel port) */ + *handlep = &xen_intr_port_to_isrc[port]->xi_vector; + + return (0); +} + #ifdef DDB static const char * xen_intr_print_type(enum evtchn_type type) |