On Sun, Sep 11, 2011 at 12:49:59PM +1200, Michal Ludvig wrote: > On 09/09/2011 11:34 PM, Ram Pai wrote: > >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. > > Hi Ram, > > applied your patch on top of 3.1.0-rc5 and unfortunately it's not > much better than it was. Log attached. > > BTW Kernel bugzilla seems to be down, will update it later. > > Michal Hi Michal, Attaching yet another patch. Please revert the earlier patch and apply this. I dont know if this will solve your problem. if it does not, then I will have to send you a patch with lots of printk to understand the root cause. I suppose we can continue our discussion on bugzilla. Thanks for your help. diff --git a/kernel/resource.c b/kernel/resource.c index 3ff4017..4fcba8f 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,70 @@ 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; + } +} + +static inline int check_overlap(struct resource *tmp, + resource_size_t start, resource_size_t end) +{ + return (tmp->start <= end && tmp->end >= start); +} + +/* + * 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 = NULL, *prev, **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; + prev = tmp; + tmp = *p; + + /* check for overlaps */ + if (tmp && check_overlap(tmp, start, end)) { + if (tmp != old) + return -EBUSY; + if (tmp->sibling && check_overlap(tmp->sibling, start, end)) + return -EBUSY; + old->start = start; + old->end = end; + return 0; + } + + if (!tmp || tmp->start > end ) { + if (prev == old || 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 */ + old->start = start; + old->end = end; + *p_old = old->sibling; + old->sibling = tmp; + *p = old; + return 0; + } + p = &tmp->sibling; } } @@ -471,7 +528,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 +549,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