aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-10-27 17:58:47 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-11-21 17:14:48 -0500
commit420eb554d5ee6daad743d8190383219f757dd66c (patch)
tree0c8b69dbc2de5aea96be93a24a8b39dbb9256b88 /drivers/xen
parent0cc678f850f2cba0cedbd133fcbbf175554cd6c6 (diff)
xen/event: Add reference counting to event channels
Event channels exposed to userspace by the evtchn module may be used by other modules in an asynchronous manner, which requires that reference counting be used to prevent the event channel from being closed before the signals are delivered. The reference count on new event channels defaults to -1 which indicates the event channel is not referenced outside the kernel; evtchn_get fails if called on such an event channel. The event channels made visible to userspace by evtchn have a normal reference count. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/events.c74
-rw-r--r--drivers/xen/evtchn.c2
2 files changed, 74 insertions, 2 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 6e075cdd0c6..a3bcd6175f4 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -87,6 +87,7 @@ enum xen_irq_type {
87 */ 87 */
88struct irq_info { 88struct irq_info {
89 struct list_head list; 89 struct list_head list;
90 int refcnt;
90 enum xen_irq_type type; /* type */ 91 enum xen_irq_type type; /* type */
91 unsigned irq; 92 unsigned irq;
92 unsigned short evtchn; /* event channel */ 93 unsigned short evtchn; /* event channel */
@@ -406,6 +407,7 @@ static void xen_irq_init(unsigned irq)
406 panic("Unable to allocate metadata for IRQ%d\n", irq); 407 panic("Unable to allocate metadata for IRQ%d\n", irq);
407 408
408 info->type = IRQT_UNBOUND; 409 info->type = IRQT_UNBOUND;
410 info->refcnt = -1;
409 411
410 irq_set_handler_data(irq, info); 412 irq_set_handler_data(irq, info);
411 413
@@ -469,6 +471,8 @@ static void xen_free_irq(unsigned irq)
469 471
470 irq_set_handler_data(irq, NULL); 472 irq_set_handler_data(irq, NULL);
471 473
474 WARN_ON(info->refcnt > 0);
475
472 kfree(info); 476 kfree(info);
473 477
474 /* Legacy IRQ descriptors are managed by the arch. */ 478 /* Legacy IRQ descriptors are managed by the arch. */
@@ -637,7 +641,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
637 if (irq != -1) { 641 if (irq != -1) {
638 printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", 642 printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n",
639 irq, gsi); 643 irq, gsi);
640 goto out; /* XXX need refcount? */ 644 goto out;
641 } 645 }
642 646
643 irq = xen_allocate_irq_gsi(gsi); 647 irq = xen_allocate_irq_gsi(gsi);
@@ -939,9 +943,16 @@ static void unbind_from_irq(unsigned int irq)
939{ 943{
940 struct evtchn_close close; 944 struct evtchn_close close;
941 int evtchn = evtchn_from_irq(irq); 945 int evtchn = evtchn_from_irq(irq);
946 struct irq_info *info = irq_get_handler_data(irq);
942 947
943 mutex_lock(&irq_mapping_update_lock); 948 mutex_lock(&irq_mapping_update_lock);
944 949
950 if (info->refcnt > 0) {
951 info->refcnt--;
952 if (info->refcnt != 0)
953 goto done;
954 }
955
945 if (VALID_EVTCHN(evtchn)) { 956 if (VALID_EVTCHN(evtchn)) {
946 close.port = evtchn; 957 close.port = evtchn;
947 if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) 958 if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
@@ -970,6 +981,7 @@ static void unbind_from_irq(unsigned int irq)
970 981
971 xen_free_irq(irq); 982 xen_free_irq(irq);
972 983
984 done:
973 mutex_unlock(&irq_mapping_update_lock); 985 mutex_unlock(&irq_mapping_update_lock);
974} 986}
975 987
@@ -1065,6 +1077,66 @@ void unbind_from_irqhandler(unsigned int irq, void *dev_id)
1065} 1077}
1066EXPORT_SYMBOL_GPL(unbind_from_irqhandler); 1078EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
1067 1079
1080int evtchn_make_refcounted(unsigned int evtchn)
1081{
1082 int irq = evtchn_to_irq[evtchn];
1083 struct irq_info *info;
1084
1085 if (irq == -1)
1086 return -ENOENT;
1087
1088 info = irq_get_handler_data(irq);
1089
1090 if (!info)
1091 return -ENOENT;
1092
1093 WARN_ON(info->refcnt != -1);
1094
1095 info->refcnt = 1;
1096
1097 return 0;
1098}
1099EXPORT_SYMBOL_GPL(evtchn_make_refcounted);
1100
1101int evtchn_get(unsigned int evtchn)
1102{
1103 int irq;
1104 struct irq_info *info;
1105 int err = -ENOENT;
1106
1107 mutex_lock(&irq_mapping_update_lock);
1108
1109 irq = evtchn_to_irq[evtchn];
1110 if (irq == -1)
1111 goto done;
1112
1113 info = irq_get_handler_data(irq);
1114
1115 if (!info)
1116 goto done;
1117
1118 err = -EINVAL;
1119 if (info->refcnt <= 0)
1120 goto done;
1121
1122 info->refcnt++;
1123 err = 0;
1124 done:
1125 mutex_unlock(&irq_mapping_update_lock);
1126
1127 return err;
1128}
1129EXPORT_SYMBOL_GPL(evtchn_get);
1130
1131void evtchn_put(unsigned int evtchn)
1132{
1133 int irq = evtchn_to_irq[evtchn];
1134 if (WARN_ON(irq == -1))
1135 return;
1136 unbind_from_irq(irq);
1137}
1138EXPORT_SYMBOL_GPL(evtchn_put);
1139
1068void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) 1140void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
1069{ 1141{
1070 int irq = per_cpu(ipi_to_irq, cpu)[vector]; 1142 int irq = per_cpu(ipi_to_irq, cpu)[vector];
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index dbc13e94b61..b1f60a0c0be 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -268,7 +268,7 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
269 u->name, (void *)(unsigned long)port); 269 u->name, (void *)(unsigned long)port);
270 if (rc >= 0) 270 if (rc >= 0)
271 rc = 0; 271 rc = evtchn_make_refcounted(port);
272 272
273 return rc; 273 return rc;
274} 274}