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
This commit is contained in:
parent
b2fd6999db
commit
0f4d7d9fd7
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/interrupt.h>
|
#include <sys/interrupt.h>
|
||||||
#include <sys/pcpu.h>
|
#include <sys/pcpu.h>
|
||||||
#include <sys/smp.h>
|
#include <sys/smp.h>
|
||||||
|
#include <sys/refcount.h>
|
||||||
|
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <vm/pmap.h>
|
#include <vm/pmap.h>
|
||||||
@ -128,6 +129,7 @@ struct xenisrc {
|
|||||||
u_int xi_activehi:1;
|
u_int xi_activehi:1;
|
||||||
u_int xi_edgetrigger:1;
|
u_int xi_edgetrigger:1;
|
||||||
u_int xi_masked:1;
|
u_int xi_masked:1;
|
||||||
|
volatile u_int xi_refcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void xen_intr_suspend(struct pic *);
|
static void xen_intr_suspend(struct pic *);
|
||||||
@ -343,10 +345,8 @@ xen_intr_release_isrc(struct xenisrc *isrc)
|
|||||||
{
|
{
|
||||||
|
|
||||||
mtx_lock(&xen_intr_isrc_lock);
|
mtx_lock(&xen_intr_isrc_lock);
|
||||||
if (isrc->xi_intsrc.is_handlers != 0) {
|
KASSERT(isrc->xi_intsrc.is_handlers == 0,
|
||||||
mtx_unlock(&xen_intr_isrc_lock);
|
("Release called, but xenisrc still in use"));
|
||||||
return (EBUSY);
|
|
||||||
}
|
|
||||||
evtchn_mask_port(isrc->xi_port);
|
evtchn_mask_port(isrc->xi_port);
|
||||||
evtchn_clear_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;
|
isrc->xi_port = local_port;
|
||||||
xen_intr_port_to_isrc[local_port] = isrc;
|
xen_intr_port_to_isrc[local_port] = isrc;
|
||||||
|
refcount_init(&isrc->xi_refcount, 1);
|
||||||
mtx_unlock(&xen_intr_isrc_lock);
|
mtx_unlock(&xen_intr_isrc_lock);
|
||||||
|
|
||||||
/* Assign the opaque handler (the event channel port) */
|
/* Assign the opaque handler (the event channel port) */
|
||||||
@ -1508,6 +1509,13 @@ xen_intr_unbind(xen_intr_handle_t *port_handlep)
|
|||||||
if (isrc == NULL)
|
if (isrc == NULL)
|
||||||
return;
|
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)
|
if (isrc->xi_cookie != NULL)
|
||||||
intr_remove_handler(isrc->xi_cookie);
|
intr_remove_handler(isrc->xi_cookie);
|
||||||
xen_intr_release_isrc(isrc);
|
xen_intr_release_isrc(isrc);
|
||||||
@ -1563,6 +1571,31 @@ xen_intr_add_handler(device_t dev, driver_filter_t filter,
|
|||||||
return (error);
|
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
|
#ifdef DDB
|
||||||
static const char *
|
static const char *
|
||||||
xen_intr_print_type(enum evtchn_type type)
|
xen_intr_print_type(enum evtchn_type type)
|
||||||
|
@ -263,4 +263,16 @@ int xen_intr_add_handler(device_t dev, driver_filter_t filter,
|
|||||||
driver_intr_t handler, void *arg, enum intr_type flags,
|
driver_intr_t handler, void *arg, enum intr_type flags,
|
||||||
xen_intr_handle_t handle);
|
xen_intr_handle_t handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a reference to an event channel port
|
||||||
|
*
|
||||||
|
* \param port Event channel port to which we get a reference.
|
||||||
|
* \param handlep Pointer to an opaque handle used to manage this
|
||||||
|
* registration.
|
||||||
|
*
|
||||||
|
* \returns 0 on success, otherwise an errno.
|
||||||
|
*/
|
||||||
|
int xen_intr_get_evtchn_from_port(evtchn_port_t port,
|
||||||
|
xen_intr_handle_t *handlep);
|
||||||
|
|
||||||
#endif /* _XEN_INTR_H_ */
|
#endif /* _XEN_INTR_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user