diff options
| author | Andrew Morton <akpm@osdl.org> | 2004-02-18 04:56:48 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-02-18 04:56:48 -0800 |
| commit | 43630c2cf39121fef7c8e49dff028b320870c80b (patch) | |
| tree | f0ee201ca67e9a1a14241eda0f33015ee52864b4 /kernel/resource.c | |
| parent | b75add94ae319a72f0eb31ac8482ac12057dce30 (diff) | |
[PATCH] Fix __release_region() race
From: MAEDA Naoaki <maeda.naoaki@jp.fujitsu.com>
I am testing PCI hot-plug in 2.6.2 kernel, but sometimes a struct resource
tree in kernel/resource.c was broken if multiple hot-plug requests are
issued at the same time.
The reason is lots of drivers call release_region() on hot removal, and
__release_region(), which is invoked by release_region() macro, changes the
tree without holding a writer lock for resource_lock.
I think __release_region() must hold a writer lock as well as
__request_region() does.
A following patch fixes the issue in my environment.
Diffstat (limited to 'kernel/resource.c')
| -rw-r--r-- | kernel/resource.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/kernel/resource.c b/kernel/resource.c index 558e5ed0abcc..fdab687f8a18 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -475,6 +475,8 @@ void __release_region(struct resource *parent, unsigned long start, unsigned lon p = &parent->child; end = start + n - 1; + write_lock(&resource_lock); + for (;;) { struct resource *res = *p; @@ -488,11 +490,15 @@ void __release_region(struct resource *parent, unsigned long start, unsigned lon if (res->start != start || res->end != end) break; *p = res->sibling; + write_unlock(&resource_lock); kfree(res); return; } p = &res->sibling; } + + write_unlock(&resource_lock); + printk(KERN_WARNING "Trying to free nonexistent resource <%08lx-%08lx>\n", start, end); } |
