summaryrefslogtreecommitdiff
path: root/kernel/resource.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-02-18 04:56:48 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-02-18 04:56:48 -0800
commit43630c2cf39121fef7c8e49dff028b320870c80b (patch)
treef0ee201ca67e9a1a14241eda0f33015ee52864b4 /kernel/resource.c
parentb75add94ae319a72f0eb31ac8482ac12057dce30 (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.c6
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);
}