]> xenbits.xensource.com Git - people/royger/linux-2.6.18-xen.git/commitdiff
linux/pcifront: fix freeing of device
authorKeir Fraser <keir@xen.org>
Mon, 4 Oct 2010 12:31:00 +0000 (13:31 +0100)
committerKeir Fraser <keir@xen.org>
Mon, 4 Oct 2010 12:31:00 +0000 (13:31 +0100)
unbind_from_irqhandler() takes irq, not evtchn, as its first argument.

Once at it, improve error handling.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Reported-by: Rafal Wojtczuk <rafal@invisiblethingslab.com>
drivers/xen/pcifront/pcifront.h
drivers/xen/pcifront/xenbus.c

index 06cb3e12fa78d513ed3193d1a8f586c318b9554e..1a27cc397c4f4dcfefb359b924ecbb358c448428 100644 (file)
@@ -30,6 +30,7 @@ struct pcifront_device {
 
        int evtchn;
        int gnt_ref;
+       int irq;
 
        /* Lock this when doing any operations in sh_info */
        spinlock_t sh_info_lock;
index ca40547c4274359f1bd5de8ee88513b6cb3b471a..93a73ff9b6cf0453459e8e5df9cdd0a5151c4e91 100644 (file)
@@ -48,6 +48,7 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
 
        pdev->evtchn = INVALID_EVTCHN;
        pdev->gnt_ref = INVALID_GRANT_REF;
+       pdev->irq = -1;
 
        INIT_WORK(&pdev->op_work, pcifront_do_aer, pdev);
 
@@ -65,7 +66,9 @@ static void free_pdev(struct pcifront_device *pdev)
 
        /*For PCIE_AER error handling job*/
        flush_scheduled_work();
-       unbind_from_irqhandler(pdev->evtchn, pdev);
+
+       if (pdev->irq > 0)
+               unbind_from_irqhandler(pdev->irq, pdev);
 
        if (pdev->evtchn != INVALID_EVTCHN)
                xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
@@ -73,6 +76,8 @@ static void free_pdev(struct pcifront_device *pdev)
        if (pdev->gnt_ref != INVALID_GRANT_REF)
                gnttab_end_foreign_access(pdev->gnt_ref,
                                          (unsigned long)pdev->sh_info);
+       else
+               free_page((unsigned long)pdev->sh_info);
 
        pdev->xdev->dev.driver_data = NULL;
 
@@ -94,8 +99,16 @@ static int pcifront_publish_info(struct pcifront_device *pdev)
        if (err)
                goto out;
 
-       bind_caller_port_to_irqhandler(pdev->evtchn, pcifront_handler_aer, 
-               SA_SAMPLE_RANDOM, "pcifront", pdev); 
+       err = bind_caller_port_to_irqhandler(pdev->evtchn,
+                                            pcifront_handler_aer,
+                                            SA_SAMPLE_RANDOM,
+                                            "pcifront", pdev);
+       if (err < 0) {
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Failed to bind event channel");
+               goto out;
+       }
+       pdev->irq = err;
 
       do_publish:
        err = xenbus_transaction_start(&trans);
@@ -428,6 +441,8 @@ static int pcifront_xenbus_probe(struct xenbus_device *xdev,
        }
 
        err = pcifront_publish_info(pdev);
+       if (err)
+               free_pdev(pdev);
 
       out:
        return err;