ia64/xen-unstable

changeset 18681:de6af72f7b5c

x86, irq: No synamic memory allocation with IRQs disabled.
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