diff options
author | Jan Beulich <jbeulich@novell.com> | 2011-05-01 13:17:44 +0100 |
---|---|---|
committer | Jan Beulich <jbeulich@novell.com> | 2011-05-01 13:17:44 +0100 |
commit | 76ce27755b87aa5a91ce0f5a02e560ab5c0515e4 (patch) | |
tree | f2a7fcbd31e863d8a0238782c12a716bbc0f21e9 /xen/common | |
parent | f22f2fe48d144141fffd42a380383f45efbea8e3 (diff) | |
download | xen-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.c | 28 | ||||
-rw-r--r-- | xen/common/event_channel.c | 42 | ||||
-rw-r--r-- | xen/common/radix-tree.c | 16 |
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(¤t->domain->event_lock); rc = evtchn_unmask(unmask.port); + spin_unlock(¤t->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; |