diff options
| author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2010-07-23 14:35:47 -0400 |
|---|---|---|
| committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-07-19 20:58:32 -0400 |
| commit | 494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48 (patch) | |
| tree | 1ec8749b08e5042a57d08014ea9e0fea832e4ee8 | |
| parent | 0513fe9e5b54e47e37217ea078dd870e3825e02d (diff) | |
xen/pciback: Fine-grain the spinlocks and fix BUG: scheduling while atomic cases.
We were using coarse spinlocks that could end up with a deadlock.
This patch fixes that and makes the spinlocks much more fine-grained.
We also drop be->watchding state spinlocks as they are already
guarded by the xenwatch_thread against multiple customers. Without
that we would trigger the BUG: scheduling while atomic.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
| -rw-r--r-- | drivers/xen/xen-pciback/passthrough.c | 9 | ||||
| -rw-r--r-- | drivers/xen/xen-pciback/xenbus.c | 26 |
2 files changed, 21 insertions, 14 deletions
diff --git a/drivers/xen/xen-pciback/passthrough.c b/drivers/xen/xen-pciback/passthrough.c index 5386bebf7f9a..6e3999b997d4 100644 --- a/drivers/xen/xen-pciback/passthrough.c +++ b/drivers/xen/xen-pciback/passthrough.c | |||
| @@ -113,14 +113,14 @@ int pciback_publish_pci_roots(struct pciback_device *pdev, | |||
| 113 | { | 113 | { |
| 114 | int err = 0; | 114 | int err = 0; |
| 115 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 115 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
| 116 | struct pci_dev_entry *dev_entry, *e; | 116 | struct pci_dev_entry *dev_entry, *e, *tmp; |
| 117 | struct pci_dev *dev; | 117 | struct pci_dev *dev; |
| 118 | int found; | 118 | int found; |
| 119 | unsigned int domain, bus; | 119 | unsigned int domain, bus; |
| 120 | 120 | ||
| 121 | spin_lock(&dev_data->lock); | 121 | spin_lock(&dev_data->lock); |
| 122 | 122 | ||
| 123 | list_for_each_entry(dev_entry, &dev_data->dev_list, list) { | 123 | list_for_each_entry_safe(dev_entry, tmp, &dev_data->dev_list, list) { |
| 124 | /* Only publish this device as a root if none of its | 124 | /* Only publish this device as a root if none of its |
| 125 | * parent bridges are exported | 125 | * parent bridges are exported |
| 126 | */ | 126 | */ |
| @@ -139,13 +139,16 @@ int pciback_publish_pci_roots(struct pciback_device *pdev, | |||
| 139 | bus = (unsigned int)dev_entry->dev->bus->number; | 139 | bus = (unsigned int)dev_entry->dev->bus->number; |
| 140 | 140 | ||
| 141 | if (!found) { | 141 | if (!found) { |
| 142 | spin_unlock(&dev_data->lock); | ||
| 142 | err = publish_root_cb(pdev, domain, bus); | 143 | err = publish_root_cb(pdev, domain, bus); |
| 143 | if (err) | 144 | if (err) |
| 144 | break; | 145 | break; |
| 146 | spin_lock(&dev_data->lock); | ||
| 145 | } | 147 | } |
| 146 | } | 148 | } |
| 147 | 149 | ||
| 148 | spin_unlock(&dev_data->lock); | 150 | if (!err) |
| 151 | spin_unlock(&dev_data->lock); | ||
| 149 | 152 | ||
| 150 | return err; | 153 | return err; |
| 151 | } | 154 | } |
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index a0cf7285d320..70030c409212 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c | |||
| @@ -54,23 +54,29 @@ static void pciback_disconnect(struct pciback_device *pdev) | |||
| 54 | unbind_from_irqhandler(pdev->evtchn_irq, pdev); | 54 | unbind_from_irqhandler(pdev->evtchn_irq, pdev); |
| 55 | pdev->evtchn_irq = INVALID_EVTCHN_IRQ; | 55 | pdev->evtchn_irq = INVALID_EVTCHN_IRQ; |
| 56 | } | 56 | } |
| 57 | spin_unlock(&pdev->dev_lock); | ||
| 57 | 58 | ||
| 58 | /* If the driver domain started an op, make sure we complete it | 59 | /* If the driver domain started an op, make sure we complete it |
| 59 | * before releasing the shared memory */ | 60 | * before releasing the shared memory */ |
| 61 | |||
| 62 | /* Note, the workqueue does not use spinlocks at all.*/ | ||
| 60 | flush_workqueue(pciback_wq); | 63 | flush_workqueue(pciback_wq); |
| 61 | 64 | ||
| 65 | spin_lock(&pdev->dev_lock); | ||
| 62 | if (pdev->sh_info != NULL) { | 66 | if (pdev->sh_info != NULL) { |
| 63 | xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); | 67 | xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); |
| 64 | pdev->sh_info = NULL; | 68 | pdev->sh_info = NULL; |
| 65 | } | 69 | } |
| 66 | |||
| 67 | spin_unlock(&pdev->dev_lock); | 70 | spin_unlock(&pdev->dev_lock); |
| 71 | |||
| 68 | } | 72 | } |
| 69 | 73 | ||
| 70 | static void free_pdev(struct pciback_device *pdev) | 74 | static void free_pdev(struct pciback_device *pdev) |
| 71 | { | 75 | { |
| 72 | if (pdev->be_watching) | 76 | if (pdev->be_watching) { |
| 73 | unregister_xenbus_watch(&pdev->be_watch); | 77 | unregister_xenbus_watch(&pdev->be_watch); |
| 78 | pdev->be_watching = 0; | ||
| 79 | } | ||
| 74 | 80 | ||
| 75 | pciback_disconnect(pdev); | 81 | pciback_disconnect(pdev); |
| 76 | 82 | ||
| @@ -98,7 +104,10 @@ static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref, | |||
| 98 | "Error mapping other domain page in ours."); | 104 | "Error mapping other domain page in ours."); |
| 99 | goto out; | 105 | goto out; |
| 100 | } | 106 | } |
| 107 | |||
| 108 | spin_lock(&pdev->dev_lock); | ||
| 101 | pdev->sh_info = vaddr; | 109 | pdev->sh_info = vaddr; |
| 110 | spin_unlock(&pdev->dev_lock); | ||
| 102 | 111 | ||
| 103 | err = bind_interdomain_evtchn_to_irqhandler( | 112 | err = bind_interdomain_evtchn_to_irqhandler( |
| 104 | pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event, | 113 | pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event, |
| @@ -108,7 +117,10 @@ static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref, | |||
| 108 | "Error binding event channel to IRQ"); | 117 | "Error binding event channel to IRQ"); |
| 109 | goto out; | 118 | goto out; |
| 110 | } | 119 | } |
| 120 | |||
| 121 | spin_lock(&pdev->dev_lock); | ||
| 111 | pdev->evtchn_irq = err; | 122 | pdev->evtchn_irq = err; |
| 123 | spin_unlock(&pdev->dev_lock); | ||
| 112 | err = 0; | 124 | err = 0; |
| 113 | 125 | ||
| 114 | dev_dbg(&pdev->xdev->dev, "Attached!\n"); | 126 | dev_dbg(&pdev->xdev->dev, "Attached!\n"); |
| @@ -122,7 +134,6 @@ static int pciback_attach(struct pciback_device *pdev) | |||
| 122 | int gnt_ref, remote_evtchn; | 134 | int gnt_ref, remote_evtchn; |
| 123 | char *magic = NULL; | 135 | char *magic = NULL; |
| 124 | 136 | ||
| 125 | spin_lock(&pdev->dev_lock); | ||
| 126 | 137 | ||
| 127 | /* Make sure we only do this setup once */ | 138 | /* Make sure we only do this setup once */ |
| 128 | if (xenbus_read_driver_state(pdev->xdev->nodename) != | 139 | if (xenbus_read_driver_state(pdev->xdev->nodename) != |
| @@ -168,7 +179,6 @@ static int pciback_attach(struct pciback_device *pdev) | |||
| 168 | 179 | ||
| 169 | dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); | 180 | dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); |
| 170 | out: | 181 | out: |
| 171 | spin_unlock(&pdev->dev_lock); | ||
| 172 | 182 | ||
| 173 | kfree(magic); | 183 | kfree(magic); |
| 174 | 184 | ||
| @@ -340,7 +350,6 @@ static int pciback_reconfigure(struct pciback_device *pdev) | |||
| 340 | char state_str[64]; | 350 | char state_str[64]; |
| 341 | char dev_str[64]; | 351 | char dev_str[64]; |
| 342 | 352 | ||
| 343 | spin_lock(&pdev->dev_lock); | ||
| 344 | 353 | ||
| 345 | dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); | 354 | dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); |
| 346 | 355 | ||
| @@ -481,8 +490,6 @@ static int pciback_reconfigure(struct pciback_device *pdev) | |||
| 481 | } | 490 | } |
| 482 | 491 | ||
| 483 | out: | 492 | out: |
| 484 | spin_unlock(&pdev->dev_lock); | ||
| 485 | |||
| 486 | return 0; | 493 | return 0; |
| 487 | } | 494 | } |
| 488 | 495 | ||
| @@ -539,8 +546,6 @@ static int pciback_setup_backend(struct pciback_device *pdev) | |||
| 539 | char dev_str[64]; | 546 | char dev_str[64]; |
| 540 | char state_str[64]; | 547 | char state_str[64]; |
| 541 | 548 | ||
| 542 | spin_lock(&pdev->dev_lock); | ||
| 543 | |||
| 544 | /* It's possible we could get the call to setup twice, so make sure | 549 | /* It's possible we could get the call to setup twice, so make sure |
| 545 | * we're not already connected. | 550 | * we're not already connected. |
| 546 | */ | 551 | */ |
| @@ -621,8 +626,6 @@ static int pciback_setup_backend(struct pciback_device *pdev) | |||
| 621 | "Error switching to initialised state!"); | 626 | "Error switching to initialised state!"); |
| 622 | 627 | ||
| 623 | out: | 628 | out: |
| 624 | spin_unlock(&pdev->dev_lock); | ||
| 625 | |||
| 626 | if (!err) | 629 | if (!err) |
| 627 | /* see if pcifront is already configured (if not, we'll wait) */ | 630 | /* see if pcifront is already configured (if not, we'll wait) */ |
| 628 | pciback_attach(pdev); | 631 | pciback_attach(pdev); |
| @@ -669,6 +672,7 @@ static int pciback_xenbus_probe(struct xenbus_device *dev, | |||
| 669 | pciback_be_watch); | 672 | pciback_be_watch); |
| 670 | if (err) | 673 | if (err) |
| 671 | goto out; | 674 | goto out; |
| 675 | |||
| 672 | pdev->be_watching = 1; | 676 | pdev->be_watching = 1; |
| 673 | 677 | ||
| 674 | /* We need to force a call to our callback here in case | 678 | /* We need to force a call to our callback here in case |
