diff options
author | Zhang Yanmin <yanmin.zhang@intel.com> | 2006-06-02 00:35:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 15:00:01 -0400 |
commit | d71374dafbba7ec3f67371d3b7e9f6310a588808 (patch) | |
tree | 116dcd65fde3701d10fea954cdbd5bb063182b2c /drivers/pci/search.c | |
parent | 733a7fe12248072e1bca729c88a26298666f1956 (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.c | 32 |
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 | ||
16 | DEFINE_SPINLOCK(pci_bus_lock); | 16 | DECLARE_RWSEM(pci_bus_sem); |
17 | 17 | ||
18 | static struct pci_bus * __devinit | 18 | static struct pci_bus * __devinit |
19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) | 19 | pci_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; |
183 | exit: | 183 | exit: |
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; |
248 | exit: | 248 | exit: |
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; |
306 | exit: | 306 | exit: |
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; |
341 | exit: | 341 | exit: |
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 | } |
375 | exit: | 375 | exit: |
376 | spin_unlock(&pci_bus_lock); | 376 | up_read(&pci_bus_sem); |
377 | return found; | 377 | return found; |
378 | } | 378 | } |
379 | EXPORT_SYMBOL(pci_dev_present); | 379 | EXPORT_SYMBOL(pci_dev_present); |