| From 47ea91b4052d9e94b9dca5d7a3d947fbebd07ba9 Mon Sep 17 00:00:00 2001 |
| From: Ram Pai <linuxram@us.ibm.com> |
| Date: Thu, 22 Sep 2011 15:48:58 +0800 |
| Subject: Resource: fix wrong resource window calculation |
| |
| From: Ram Pai <linuxram@us.ibm.com> |
| |
| commit 47ea91b4052d9e94b9dca5d7a3d947fbebd07ba9 upstream. |
| |
| __find_resource() incorrectly returns a resource window which overlaps |
| an existing allocated window. This happens when the parent's |
| resource-window spans 0x00000000 to 0xffffffff and is entirely allocated |
| to all its children resource-windows. |
| |
| __find_resource() looks for gaps in resource allocation among the |
| children resource windows. When it encounters the last child window it |
| blindly tries the range next to one allocated to the last child. Since |
| the last child's window ends at 0xffffffff the calculation overflows, |
| leading the algorithm to believe that any window in the range 0x0000000 |
| to 0xfffffff is available for allocation. This leads to a conflicting |
| window allocation. |
| |
| Michal Ludvig reported this issue seen on his platform. The following |
| patch fixes the problem and has been verified by Michal. I believe this |
| bug has been there for ages. It got exposed by git commit 2bbc6942273b |
| ("PCI : ability to relocate assigned pci-resources") |
| |
| Signed-off-by: Ram Pai <linuxram@us.ibm.com> |
| Tested-by: Michal Ludvig <mludvig@logix.net.nz> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Herton Ronaldo Krzesinski <herton.krzesinski@canonical.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/resource.c | 7 ++++++- |
| 1 file changed, 6 insertions(+), 1 deletion(-) |
| |
| --- a/kernel/resource.c |
| +++ b/kernel/resource.c |
| @@ -419,6 +419,9 @@ static int __find_resource(struct resour |
| else |
| tmp.end = root->end; |
| |
| + if (tmp.end < tmp.start) |
| + goto next; |
| + |
| resource_clip(&tmp, constraint->min, constraint->max); |
| arch_remove_reservations(&tmp); |
| |
| @@ -436,8 +439,10 @@ static int __find_resource(struct resour |
| return 0; |
| } |
| } |
| - if (!this) |
| + |
| +next: if (!this || this->end == root->end) |
| break; |
| + |
| if (this != old) |
| tmp.start = this->end + 1; |
| this = this->sibling; |