On Sun, Sep 04, 2011 at 09:42:44PM +1200, Michal Ludvig wrote: > Hi Bjorn, > > On 09/02/2011 11:08 AM, Bjorn Helgaas wrote: > >Thanks! Can you reassign this to "Drivers/PCI" and set "Regression = > >yes"? I can't seem to do it myself. Also, the logs look like console > >logs, which don't include everything in the dmesg log unless you boot > >with "ignore_loglevel". Can you boot the failing one with > >"ignore_loglevel"? And maybe attach the "lspci -vv" output? > > Attached in bugzilla as requested. Let me know if you need something more. > https://bugzilla.kernel.org/show_bug.cgi?id=42002 > > Michal Michal, My patch assumed that the resource-range returned by __find_resource() will always return a range that when allocated through request_resource() will not lead to conflicts. However your platform somehow breaks that assumption. I have rearranged the code to ensure that request_resource() returns without conflicting overlaps; before returning success. Please test the following new patch. I have touch-tested on my machine and found it not to cause any problems. diff --git a/kernel/resource.c b/kernel/resource.c index 3ff4017..492d6f3 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -156,11 +156,7 @@ static struct resource * __request_resource(struct resource *root, struct resour resource_size_t end = new->end; struct resource *tmp, **p; - if (end < start) - return root; - if (start < root->start) - return root; - if (end > root->end) + if (end < start || start < root->start || end > root->end) return root; p = &root->child; for (;;) { @@ -172,9 +168,54 @@ static struct resource * __request_resource(struct resource *root, struct resour return NULL; } p = &tmp->sibling; - if (tmp->end < start) - continue; - return tmp; + if (tmp->end >= start) + return tmp; + } +} + +/* + * relocate the old resource, to the new position. Return error and do nothing + * if the new location conflicts with any other resource. + */ +static int re_request_resource(struct resource *root, + struct resource *new, struct resource *old) +{ + resource_size_t start = new->start; + resource_size_t end = new->end; + struct resource *tmp, **p, **p_old = NULL; + + if (end < start || start < root->start || end > root->end) + return -EBUSY; + p = &root->child; + for (;;) { + if ( *p == old ) p_old = p; + tmp = *p; + if (!tmp || tmp->start > end) { + + if (tmp == old) { + old->start = start; + old->end = end; + return 0; + } + + if (!p_old) { + p_old = p; + while ( *p_old && old != (*p_old)->sibling ) + p_old = &(*p_old)->sibling; + BUG_ON(!*p_old); + } + + /* relocate old */ + *p_old = old->sibling; + old->start = start; + old->end = end; + old->sibling = tmp; + *p = old; + return 0; + } + p = &tmp->sibling; + if (tmp->end >= start) + return -EBUSY; } } @@ -471,7 +512,6 @@ int reallocate_resource(struct resource *root, struct resource *old, { int err=0; struct resource new = *old; - struct resource *conflict; write_lock(&resource_lock); @@ -493,10 +533,7 @@ int reallocate_resource(struct resource *root, struct resource *old, old->start = new.start; old->end = new.end; } else { - __release_resource(old); - *old = new; - conflict = __request_resource(root, old); - BUG_ON(conflict); + err = re_request_resource(root, &new, old); } out: write_unlock(&resource_lock); -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html