[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v8 03/27] ARM: GIC: Add checks for NULL pointer pending_irq's



Hi Andre,

On 12/04/17 01:44, Andre Przywara wrote:
For LPIs the struct pending_irq's are dynamically allocated and the
pointers will be stored in a radix tree. Since an LPI can be "unmapped"
at any time, teach the VGIC how to handle with irq_to_pending() returning
a NULL pointer.
We just do nothing in this case or clean up the LR if the virtual LPI
number was still in an LR.

Why not all the irq_to_pending call are not protected (such as vgic_irq_to_migrate)? This is a call to forget to check NULL if we decide to use the function in the future.

Also, I would like a comment on top of irq_to_pending stating this can return NULL as you change the semantic of the function.


Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
---
 xen/arch/arm/gic.c  | 37 ++++++++++++++++++++++++++++++++-----
 xen/arch/arm/vgic.c |  6 ++++++
 2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index dcb1783..62ae3b8 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -408,9 +408,15 @@ void gic_remove_from_queues(struct vcpu *v, unsigned int 
virtual_irq)
     spin_lock_irqsave(&v->arch.vgic.lock, flags);

     p = irq_to_pending(v, virtual_irq);
-
-    if ( !list_empty(&p->lr_queue) )
-        list_del_init(&p->lr_queue);
+    /*
+     * If an LPIs has been removed meanwhile, it has been cleaned up
+     * already, so nothing to remove here.
+     */
+    if ( p )
+    {
+        if ( !list_empty(&p->lr_queue) )
+            list_del_init(&p->lr_queue);
+    }

This could be simplified with:

if ( p && !list_empty(&p->lr_queue) )
  list_del_init(...);

Also, you probably want a likely(p).

     spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
 }

@@ -418,6 +424,10 @@ void gic_raise_inflight_irq(struct vcpu *v, unsigned int 
virtual_irq)
 {
     struct pending_irq *n = irq_to_pending(v, virtual_irq);

+    /* If an LPI has been removed meanwhile, there is nothing left to raise. */
+    if ( !n )

if ( unlikely(!n) )

+        return;
+
     ASSERT(spin_is_locked(&v->arch.vgic.lock));

     if ( list_empty(&n->lr_queue) )
@@ -437,6 +447,11 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int 
virtual_irq,
 {
     int i;
     unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
+    struct pending_irq *p = irq_to_pending(v, virtual_irq);
+
+    if ( !p )

if ( unlikely(!p) )

+        /* An unmapped LPI does not need to be raised. */
+        return;

Please move this check after the ASSERT to keep the check on all the paths.


     ASSERT(spin_is_locked(&v->arch.vgic.lock));

@@ -445,12 +460,12 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int 
virtual_irq,
         i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
         if (i < nr_lrs) {
             set_bit(i, &this_cpu(lr_mask));
-            gic_set_lr(i, irq_to_pending(v, virtual_irq), GICH_LR_PENDING);
+            gic_set_lr(i, p, GICH_LR_PENDING);
             return;
         }
     }

-    gic_add_to_lr_pending(v, irq_to_pending(v, virtual_irq));
+    gic_add_to_lr_pending(v, p);
 }

 static void gic_update_one_lr(struct vcpu *v, int i)
@@ -464,7 +479,19 @@ static void gic_update_one_lr(struct vcpu *v, int i)

     gic_hw_ops->read_lr(i, &lr_val);
     irq = lr_val.virq;
+

4th time I am saying this.... Spurious line.

     p = irq_to_pending(v, irq);
+    /* An LPI might have been unmapped, in which case we just clean up here. */
+    if ( !p )

unlikely(!p)

+    {
+        ASSERT(is_lpi(irq));
+
+        gic_hw_ops->clear_lr(i);
+        clear_bit(i, &this_cpu(lr_mask));
+
+        return;
+    }
+
     if ( lr_val.state & GICH_LR_ACTIVE )
     {
         set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index c953f13..b9fc837 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -473,6 +473,12 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int 
virq)
     spin_lock_irqsave(&v->arch.vgic.lock, flags);

     n = irq_to_pending(v, virq);
+    /* If an LPI has been removed, there is nothing to inject here. */
+    if ( !n )

unlikely(...)

+    {
+        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+        return;
+    }

     priority = vgic_get_virq_priority(v, virq);



Cheers,

--
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.