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 /drivers/xen | |
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>
Diffstat (limited to 'drivers/xen')
-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 5386bebf7f9..6e3999b997d 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 a0cf7285d32..70030c40921 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 |