ia64/xen-unstable
changeset 18681:de6af72f7b5c
x86, irq: No synamic memory allocation with IRQs disabled.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Tue Oct 21 14:13:54 2008 +0100 (2008-10-21) |
parents | 3b99705155c1 |
children | e7f876c94955 |
files | xen/arch/x86/irq.c |
line diff
1.1 --- a/xen/arch/x86/irq.c Tue Oct 21 11:44:39 2008 +0100 1.2 +++ b/xen/arch/x86/irq.c Tue Oct 21 14:13:54 2008 +0100 1.3 @@ -510,7 +510,7 @@ int pirq_guest_bind(struct vcpu *v, int 1.4 { 1.5 unsigned int vector; 1.6 irq_desc_t *desc; 1.7 - irq_guest_action_t *action; 1.8 + irq_guest_action_t *action, *newaction = NULL; 1.9 int rc = 0; 1.10 cpumask_t cpumask = CPU_MASK_NONE; 1.11 1.12 @@ -520,7 +520,10 @@ int pirq_guest_bind(struct vcpu *v, int 1.13 retry: 1.14 desc = domain_spin_lock_irq_desc(v->domain, irq, NULL); 1.15 if ( desc == NULL ) 1.16 - return -EINVAL; 1.17 + { 1.18 + rc = -EINVAL; 1.19 + goto out; 1.20 + } 1.21 1.22 action = (irq_guest_action_t *)desc->action; 1.23 vector = desc - irq_desc; 1.24 @@ -533,18 +536,24 @@ int pirq_guest_bind(struct vcpu *v, int 1.25 "Cannot bind IRQ %d to guest. In use by '%s'.\n", 1.26 irq, desc->action->name); 1.27 rc = -EBUSY; 1.28 + goto unlock_out; 1.29 + } 1.30 + 1.31 + if ( newaction == NULL ) 1.32 + { 1.33 + spin_unlock_irq(&desc->lock); 1.34 + if ( (newaction = xmalloc(irq_guest_action_t)) != NULL ) 1.35 + goto retry; 1.36 + gdprintk(XENLOG_INFO, 1.37 + "Cannot bind IRQ %d to guest. Out of memory.\n", 1.38 + irq); 1.39 + rc = -ENOMEM; 1.40 goto out; 1.41 } 1.42 1.43 - action = xmalloc(irq_guest_action_t); 1.44 - if ( (desc->action = (struct irqaction *)action) == NULL ) 1.45 - { 1.46 - gdprintk(XENLOG_INFO, 1.47 - "Cannot bind IRQ %d to guest. Out of memory.\n", 1.48 - irq); 1.49 - rc = -ENOMEM; 1.50 - goto out; 1.51 - } 1.52 + action = newaction; 1.53 + desc->action = (struct irqaction *)action; 1.54 + newaction = NULL; 1.55 1.56 action->nr_guests = 0; 1.57 action->in_flight = 0; 1.58 @@ -568,7 +577,7 @@ int pirq_guest_bind(struct vcpu *v, int 1.59 "Will not share with others.\n", 1.60 irq); 1.61 rc = -EBUSY; 1.62 - goto out; 1.63 + goto unlock_out; 1.64 } 1.65 else if ( action->nr_guests == 0 ) 1.66 { 1.67 @@ -588,17 +597,21 @@ int pirq_guest_bind(struct vcpu *v, int 1.68 gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. " 1.69 "Already at max share.\n", irq); 1.70 rc = -EBUSY; 1.71 - goto out; 1.72 + goto unlock_out; 1.73 } 1.74 1.75 action->guest[action->nr_guests++] = v->domain; 1.76 1.77 + unlock_out: 1.78 + spin_unlock_irq(&desc->lock); 1.79 out: 1.80 - spin_unlock_irq(&desc->lock); 1.81 + if ( newaction != NULL ) 1.82 + xfree(newaction); 1.83 return rc; 1.84 } 1.85 1.86 -static void __pirq_guest_unbind(struct domain *d, int irq, irq_desc_t *desc) 1.87 +static irq_guest_action_t *__pirq_guest_unbind( 1.88 + struct domain *d, int irq, irq_desc_t *desc) 1.89 { 1.90 unsigned int vector; 1.91 irq_guest_action_t *action; 1.92 @@ -644,7 +657,7 @@ static void __pirq_guest_unbind(struct d 1.93 BUG_ON(test_bit(irq, d->pirq_mask)); 1.94 1.95 if ( action->nr_guests != 0 ) 1.96 - return; 1.97 + return NULL; 1.98 1.99 BUG_ON(action->in_flight != 0); 1.100 1.101 @@ -672,15 +685,18 @@ static void __pirq_guest_unbind(struct d 1.102 BUG_ON(!cpus_empty(action->cpu_eoi_map)); 1.103 1.104 desc->action = NULL; 1.105 - xfree(action); 1.106 desc->status &= ~IRQ_GUEST; 1.107 desc->status &= ~IRQ_INPROGRESS; 1.108 kill_timer(&irq_guest_eoi_timer[vector]); 1.109 desc->handler->shutdown(vector); 1.110 + 1.111 + /* Caller frees the old guest descriptor block. */ 1.112 + return action; 1.113 } 1.114 1.115 void pirq_guest_unbind(struct domain *d, int irq) 1.116 { 1.117 + irq_guest_action_t *oldaction = NULL; 1.118 irq_desc_t *desc; 1.119 int vector; 1.120 1.121 @@ -699,16 +715,19 @@ void pirq_guest_unbind(struct domain *d, 1.122 } 1.123 else 1.124 { 1.125 - __pirq_guest_unbind(d, irq, desc); 1.126 + oldaction = __pirq_guest_unbind(d, irq, desc); 1.127 } 1.128 1.129 spin_unlock_irq(&desc->lock); 1.130 + 1.131 + if ( oldaction != NULL ) 1.132 + xfree(oldaction); 1.133 } 1.134 1.135 int pirq_guest_force_unbind(struct domain *d, int irq) 1.136 { 1.137 irq_desc_t *desc; 1.138 - irq_guest_action_t *action; 1.139 + irq_guest_action_t *action, *oldaction = NULL; 1.140 int i, bound = 0; 1.141 1.142 WARN_ON(!spin_is_locked(&d->event_lock)); 1.143 @@ -727,10 +746,14 @@ int pirq_guest_force_unbind(struct domai 1.144 goto out; 1.145 1.146 bound = 1; 1.147 - __pirq_guest_unbind(d, irq, desc); 1.148 + oldaction = __pirq_guest_unbind(d, irq, desc); 1.149 1.150 out: 1.151 spin_unlock_irq(&desc->lock); 1.152 + 1.153 + if ( oldaction != NULL ) 1.154 + xfree(oldaction); 1.155 + 1.156 return bound; 1.157 } 1.158