aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/search.c
diff options
context:
space:
mode:
authorZhang Yanmin <yanmin.zhang@intel.com>2006-06-02 00:35:43 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 15:00:01 -0400
commitd71374dafbba7ec3f67371d3b7e9f6310a588808 (patch)
tree116dcd65fde3701d10fea954cdbd5bb063182b2c /drivers/pci/search.c
parent733a7fe12248072e1bca729c88a26298666f1956 (diff)
[PATCH] PCI: fix race with pci_walk_bus and pci_destroy_dev
pci_walk_bus has a race with pci_destroy_dev. When cb is called in pci_walk_bus, pci_destroy_dev might unlink the dev pointed by next. Later on in the next loop, pointer next becomes NULL and cause kernel panic. Below patch against 2.6.17-rc4 fixes it by changing pci_bus_lock (spin_lock) to pci_bus_sem (rw_semaphore). Signed-off-by: Zhang Yanmin <yanmin.zhang@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/search.c')
-rw-r--r--drivers/pci/search.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index ce7dd6e7be60..622b3f8ba820 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -13,7 +13,7 @@
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include "pci.h" 14#include "pci.h"
15 15
16DEFINE_SPINLOCK(pci_bus_lock); 16DECLARE_RWSEM(pci_bus_sem);
17 17
18static struct pci_bus * __devinit 18static struct pci_bus * __devinit
19pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) 19pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
@@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from)
72 struct pci_bus *b = NULL; 72 struct pci_bus *b = NULL;
73 73
74 WARN_ON(in_interrupt()); 74 WARN_ON(in_interrupt());
75 spin_lock(&pci_bus_lock); 75 down_read(&pci_bus_sem);
76 n = from ? from->node.next : pci_root_buses.next; 76 n = from ? from->node.next : pci_root_buses.next;
77 if (n != &pci_root_buses) 77 if (n != &pci_root_buses)
78 b = pci_bus_b(n); 78 b = pci_bus_b(n);
79 spin_unlock(&pci_bus_lock); 79 up_read(&pci_bus_sem);
80 return b; 80 return b;
81} 81}
82 82
@@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
124 struct pci_dev *dev; 124 struct pci_dev *dev;
125 125
126 WARN_ON(in_interrupt()); 126 WARN_ON(in_interrupt());
127 spin_lock(&pci_bus_lock); 127 down_read(&pci_bus_sem);
128 128
129 list_for_each(tmp, &bus->devices) { 129 list_for_each(tmp, &bus->devices) {
130 dev = pci_dev_b(tmp); 130 dev = pci_dev_b(tmp);
@@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
135 dev = NULL; 135 dev = NULL;
136 out: 136 out:
137 pci_dev_get(dev); 137 pci_dev_get(dev);
138 spin_unlock(&pci_bus_lock); 138 up_read(&pci_bus_sem);
139 return dev; 139 return dev;
140} 140}
141 141
@@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
167 struct pci_dev *dev; 167 struct pci_dev *dev;
168 168
169 WARN_ON(in_interrupt()); 169 WARN_ON(in_interrupt());
170 spin_lock(&pci_bus_lock); 170 down_read(&pci_bus_sem);
171 n = from ? from->global_list.next : pci_devices.next; 171 n = from ? from->global_list.next : pci_devices.next;
172 172
173 while (n && (n != &pci_devices)) { 173 while (n && (n != &pci_devices)) {
@@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
181 } 181 }
182 dev = NULL; 182 dev = NULL;
183exit: 183exit:
184 spin_unlock(&pci_bus_lock); 184 up_read(&pci_bus_sem);
185 return dev; 185 return dev;
186} 186}
187 187
@@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
232 struct pci_dev *dev; 232 struct pci_dev *dev;
233 233
234 WARN_ON(in_interrupt()); 234 WARN_ON(in_interrupt());
235 spin_lock(&pci_bus_lock); 235 down_read(&pci_bus_sem);
236 n = from ? from->global_list.next : pci_devices.next; 236 n = from ? from->global_list.next : pci_devices.next;
237 237
238 while (n && (n != &pci_devices)) { 238 while (n && (n != &pci_devices)) {
@@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
247 dev = NULL; 247 dev = NULL;
248exit: 248exit:
249 dev = pci_dev_get(dev); 249 dev = pci_dev_get(dev);
250 spin_unlock(&pci_bus_lock); 250 up_read(&pci_bus_sem);
251 pci_dev_put(from); 251 pci_dev_put(from);
252 return dev; 252 return dev;
253} 253}
@@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p
292 struct pci_dev *dev; 292 struct pci_dev *dev;
293 293
294 WARN_ON(in_interrupt()); 294 WARN_ON(in_interrupt());
295 spin_lock(&pci_bus_lock); 295 down_read(&pci_bus_sem);
296 n = from ? from->global_list.prev : pci_devices.prev; 296 n = from ? from->global_list.prev : pci_devices.prev;
297 297
298 while (n && (n != &pci_devices)) { 298 while (n && (n != &pci_devices)) {
@@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p
304 } 304 }
305 dev = NULL; 305 dev = NULL;
306exit: 306exit:
307 spin_unlock(&pci_bus_lock); 307 up_read(&pci_bus_sem);
308 return dev; 308 return dev;
309} 309}
310 310
@@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
328 struct pci_dev *dev; 328 struct pci_dev *dev;
329 329
330 WARN_ON(in_interrupt()); 330 WARN_ON(in_interrupt());
331 spin_lock(&pci_bus_lock); 331 down_read(&pci_bus_sem);
332 n = from ? from->global_list.next : pci_devices.next; 332 n = from ? from->global_list.next : pci_devices.next;
333 333
334 while (n && (n != &pci_devices)) { 334 while (n && (n != &pci_devices)) {
@@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
340 dev = NULL; 340 dev = NULL;
341exit: 341exit:
342 dev = pci_dev_get(dev); 342 dev = pci_dev_get(dev);
343 spin_unlock(&pci_bus_lock); 343 up_read(&pci_bus_sem);
344 pci_dev_put(from); 344 pci_dev_put(from);
345 return dev; 345 return dev;
346} 346}
@@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids)
362 int found = 0; 362 int found = 0;
363 363
364 WARN_ON(in_interrupt()); 364 WARN_ON(in_interrupt());
365 spin_lock(&pci_bus_lock); 365 down_read(&pci_bus_sem);
366 while (ids->vendor || ids->subvendor || ids->class_mask) { 366 while (ids->vendor || ids->subvendor || ids->class_mask) {
367 list_for_each_entry(dev, &pci_devices, global_list) { 367 list_for_each_entry(dev, &pci_devices, global_list) {
368 if (pci_match_one_device(ids, dev)) { 368 if (pci_match_one_device(ids, dev)) {
@@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids)
372 } 372 }
373 ids++; 373 ids++;
374 } 374 }
375exit: 375exit:
376 spin_unlock(&pci_bus_lock); 376 up_read(&pci_bus_sem);
377 return found; 377 return found;
378} 378}
379EXPORT_SYMBOL(pci_dev_present); 379EXPORT_SYMBOL(pci_dev_present);