aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2011-05-01 13:17:44 +0100
committerJan Beulich <jbeulich@novell.com>2011-05-01 13:17:44 +0100
commit76ce27755b87aa5a91ce0f5a02e560ab5c0515e4 (patch)
treef2a7fcbd31e863d8a0238782c12a716bbc0f21e9 /xen/common
parentf22f2fe48d144141fffd42a380383f45efbea8e3 (diff)
downloadxen-76ce27755b87aa5a91ce0f5a02e560ab5c0515e4.tar.gz
xen-76ce27755b87aa5a91ce0f5a02e560ab5c0515e4.tar.bz2
xen-76ce27755b87aa5a91ce0f5a02e560ab5c0515e4.zip
replace d->nr_pirqs sized arrays with radix tree
With this it is questionable whether retaining struct domain's nr_pirqs is actually necessary - the value now only serves for bounds checking, and this boundary could easily be nr_irqs. Another thing to consider is whether it's worth storing the pirq number in struct pirq, to avoid passing the number and a pointer to quite a number of functions. Note that ia64, the build of which is broken currently anyway, is only partially fixed up. Signed-off-by: Jan Beulich <jbeulich@novell.com>
Diffstat (limited to 'xen/common')
-rw-r--r--xen/common/domain.c28
-rw-r--r--xen/common/event_channel.c42
-rw-r--r--xen/common/radix-tree.c16
3 files changed, 54 insertions, 32 deletions
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 852c968bba..40a2833762 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -290,13 +290,7 @@ struct domain *domain_create(
if ( d->nr_pirqs > nr_irqs )
d->nr_pirqs = nr_irqs;
- d->pirq_to_evtchn = xmalloc_array(u16, d->nr_pirqs);
- d->pirq_mask = xmalloc_array(
- unsigned long, BITS_TO_LONGS(d->nr_pirqs));
- if ( (d->pirq_to_evtchn == NULL) || (d->pirq_mask == NULL) )
- goto fail;
- memset(d->pirq_to_evtchn, 0, d->nr_pirqs * sizeof(*d->pirq_to_evtchn));
- bitmap_zero(d->pirq_mask, d->nr_pirqs);
+ INIT_RADIX_TREE(&d->pirq_tree, 0);
if ( evtchn_init(d) != 0 )
goto fail;
@@ -346,6 +340,7 @@ struct domain *domain_create(
{
evtchn_destroy(d);
evtchn_destroy_final(d);
+ radix_tree_destroy(&d->pirq_tree, free_pirq_struct, NULL);
}
if ( init_status & INIT_rangeset )
rangeset_domain_destroy(d);
@@ -353,8 +348,6 @@ struct domain *domain_create(
watchdog_domain_destroy(d);
if ( init_status & INIT_xsm )
xsm_free_security_domain(d);
- xfree(d->pirq_mask);
- xfree(d->pirq_to_evtchn);
free_cpumask_var(d->domain_dirty_cpumask);
free_domain_struct(d);
return NULL;
@@ -680,8 +673,7 @@ static void complete_domain_destroy(struct rcu_head *head)
evtchn_destroy_final(d);
- xfree(d->pirq_mask);
- xfree(d->pirq_to_evtchn);
+ radix_tree_destroy(&d->pirq_tree, free_pirq_struct, NULL);
xsm_free_security_domain(d);
free_cpumask_var(d->domain_dirty_cpumask);
@@ -963,6 +955,20 @@ long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
return -ENOSYS;
}
+struct pirq *pirq_get_info(struct domain *d, int pirq)
+{
+ struct pirq *info = pirq_info(d, pirq);
+
+ if ( !info && (info = alloc_pirq_struct(d)) != NULL &&
+ radix_tree_insert(&d->pirq_tree, pirq, info, NULL, NULL) )
+ {
+ free_pirq_struct(info);
+ info = NULL;
+ }
+
+ return info;
+}
+
struct migrate_info {
long (*func)(void *data);
void *data;
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 558fbb1256..56d80b9bed 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -325,6 +325,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
struct evtchn *chn;
struct domain *d = current->domain;
struct vcpu *v = d->vcpu[0];
+ struct pirq *info;
int port, pirq = bind->pirq;
long rc;
@@ -336,7 +337,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
spin_lock(&d->event_lock);
- if ( d->pirq_to_evtchn[pirq] != 0 )
+ if ( pirq_to_evtchn(d, pirq) != 0 )
ERROR_EXIT(-EEXIST);
if ( (port = get_free_port(d)) < 0 )
@@ -344,14 +345,18 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
chn = evtchn_from_port(d, port);
- d->pirq_to_evtchn[pirq] = port;
+ info = pirq_get_info(d, pirq);
+ if ( !info )
+ ERROR_EXIT(-ENOMEM);
+ info->evtchn = port;
rc = (!is_hvm_domain(d)
- ? pirq_guest_bind(
- v, pirq, !!(bind->flags & BIND_PIRQ__WILL_SHARE))
+ ? pirq_guest_bind(v, pirq, info,
+ !!(bind->flags & BIND_PIRQ__WILL_SHARE))
: 0);
if ( rc != 0 )
{
- d->pirq_to_evtchn[pirq] = 0;
+ info->evtchn = 0;
+ pirq_cleanup_check(info, d, pirq);
goto out;
}
@@ -404,12 +409,18 @@ static long __evtchn_close(struct domain *d1, int port1)
case ECS_UNBOUND:
break;
- case ECS_PIRQ:
+ case ECS_PIRQ: {
+ struct pirq *pirq = pirq_info(d1, chn1->u.pirq.irq);
+
+ if ( !pirq )
+ break;
if ( !is_hvm_domain(d1) )
- pirq_guest_unbind(d1, chn1->u.pirq.irq);
- d1->pirq_to_evtchn[chn1->u.pirq.irq] = 0;
+ pirq_guest_unbind(d1, chn1->u.pirq.irq, pirq);
+ pirq->evtchn = 0;
+ pirq_cleanup_check(pirq, d1, chn1->u.pirq.irq);
unlink_pirq_port(chn1, d1->vcpu[chn1->notify_vcpu_id]);
break;
+ }
case ECS_VIRQ:
for_each_vcpu ( d1, v )
@@ -659,9 +670,9 @@ void send_guest_global_virq(struct domain *d, int virq)
spin_unlock_irqrestore(&v->virq_lock, flags);
}
-int send_guest_pirq(struct domain *d, int pirq)
+int send_guest_pirq(struct domain *d, const struct pirq *pirq)
{
- int port = d->pirq_to_evtchn[pirq];
+ int port;
struct evtchn *chn;
/*
@@ -670,7 +681,7 @@ int send_guest_pirq(struct domain *d, int pirq)
* HVM guests: Port is legitimately zero when the guest disables the
* emulated interrupt/evtchn.
*/
- if ( port == 0 )
+ if ( pirq == NULL || (port = pirq->evtchn) == 0 )
{
BUG_ON(!is_hvm_domain(d));
return 0;
@@ -812,13 +823,10 @@ int evtchn_unmask(unsigned int port)
struct domain *d = current->domain;
struct vcpu *v;
- spin_lock(&d->event_lock);
+ ASSERT(spin_is_locked(&d->event_lock));
if ( unlikely(!port_is_valid(d, port)) )
- {
- spin_unlock(&d->event_lock);
return -EINVAL;
- }
v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id];
@@ -834,8 +842,6 @@ int evtchn_unmask(unsigned int port)
vcpu_mark_events_pending(v);
}
- spin_unlock(&d->event_lock);
-
return 0;
}
@@ -960,7 +966,9 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE(void) arg)
struct evtchn_unmask unmask;
if ( copy_from_guest(&unmask, arg, 1) != 0 )
return -EFAULT;
+ spin_lock(&current->domain->event_lock);
rc = evtchn_unmask(unmask.port);
+ spin_unlock(&current->domain->event_lock);
break;
}
diff --git a/xen/common/radix-tree.c b/xen/common/radix-tree.c
index 1763fe7555..f2736d9a00 100644
--- a/xen/common/radix-tree.c
+++ b/xen/common/radix-tree.c
@@ -225,7 +225,8 @@ EXPORT_SYMBOL(radix_tree_lookup);
static unsigned int
__lookup(struct radix_tree_root *root, void **results, unsigned long index,
- unsigned int max_items, unsigned long *next_index)
+ unsigned int max_items, unsigned long *indexes,
+ unsigned long *next_index)
{
unsigned int nr_found = 0;
unsigned int shift, height;
@@ -235,8 +236,11 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
height = root->height;
if (index > radix_tree_maxindex(height))
if (height == 0) {
- if (root->rnode && index == 0)
+ if (root->rnode && index == 0) {
+ if (indexes)
+ indexes[nr_found] = index;
results[nr_found++] = root->rnode;
+ }
goto out;
}
@@ -265,6 +269,8 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
index++;
if (slot->slots[i]) {
+ if (indexes)
+ indexes[nr_found] = index - 1;
results[nr_found++] = slot->slots[i];
if (nr_found == max_items)
goto out;
@@ -281,6 +287,7 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
* @results: where the results of the lookup are placed
* @first_index: start the lookup from this key
* @max_items: place up to this many items at *results
+ * @indexes: (optional) array to store indexes of items.
*
* Performs an index-ascending scan of the tree for present items. Places
* them at *@results and returns the number of items which were placed at
@@ -290,7 +297,8 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
*/
unsigned int
radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
- unsigned long first_index, unsigned int max_items)
+ unsigned long first_index, unsigned int max_items,
+ unsigned long *indexes)
{
const unsigned long max_index = radix_tree_maxindex(root->height);
unsigned long cur_index = first_index;
@@ -303,7 +311,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
if (cur_index > max_index)
break;
nr_found = __lookup(root, results + ret, cur_index,
- max_items - ret, &next_index);
+ max_items - ret, indexes + ret, &next_index);
ret += nr_found;
if (next_index == 0)
break;