Skip to contentSkip to conversation

x86: split e820 reserved entries record to late v4 - fix v6

PATCH In review Yinghai Lu 1 participant 2 messages Aug 30, 2008 – Aug 31, 2008 x86

lore
Share & tools
lore

Yinghai Lu

author
#0 lore raw

PATCH 1/1 x86: split e820 reserved entries record to late v4 - fix v6

try to insert_resource second time, by expand the resource...

for case: e820 reserved entry is partially overlapped with bar res...

hope it will never happen

v2: according to Linus, add insert_resource_expand_to_fit, and change
__insert_resource to static without lock

v3: use reserve_region_with_split() instead to hand overlapping

	with test case by extend 0xe0000000 - 0xeffffff to 0xdd800000 -
	get
		e0000000-efffffff : PCI MMCONFIG 0
			 e0000000-efffffff : reserved
	in /proc/iomem
	get
		found conflict for reserved [dd800000, efffffff], try to reserve with split
		    __reserve_region_with_split: (PCI Bus #80) [dd000000, ddffffff], res: (reserved) [dd800000, efffffff]
		    __reserve_region_with_split: (PCI Bus #00) [de000000, dfffffff], res: (reserved) [de000000, efffffff]
		initcall pci_subsys_init+0x0/0x121 returned 0 after 381 msecs
	in dmesg

v4: take out __insert_resource and insert_resource_expand_to_fit : Linus already check in.
use reserve_region_with_split at the first point
use const char *name

v5: fix checking on overlapping

v6: only reserve common area in conflict

	so got sth in /proc/iomem
		d8000000-dfffffff : PCI Bus #00
		  dc000000-dfffffff : GART
		    dc000000-dfffffff : reserved
		e0000000-efffffff : PCI MMCONFIG 0
		  e0000000-efffffff : reserved
	when we have big range in e820
		00000000dc000000-00000000f0000000 (reserved)
---
 arch/x86/kernel/e820.c |    2 -
 include/linux/ioport.h |    3 ++
 kernel/resource.c      |   69 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 72 insertions(+), 2 deletions(-)
arch/x86/kernel/e820.c +1 -1
Index: linux-2.6/arch/x86/kernel/e820.c
===================================================================
@@ -1320,7 +1320,7 @@ void __init e820_reserve_resources_late(
 	res = e820_res;
 	for (i = 0; i < e820.nr_map; i++) {
 		if (!res->parent && res->end)
-			insert_resource(&iomem_resource, res);
+			reserve_region_with_split(&iomem_resource, res->start, res->end, res->name);
 		res++;
 	}
 }
include/linux/ioport.h +3 -0
Index: linux-2.6/include/linux/ioport.h
===================================================================
@@ -108,6 +108,9 @@ extern struct resource iomem_resource;
 
 extern int request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
+extern void reserve_region_with_split(struct resource *root,
+			     resource_size_t start, resource_size_t end,
+			     const char *name);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
kernel/resource.c +68 -1

78 lines not on this page · raw message

author
#1 lore raw

Adding to : Ivan..

Quoted 157 lines · Yinghai Lu

try to insert_resource second time, by expand the resource...

for case: e820 reserved entry is partially overlapped with bar res...

hope it will never happen

v2: according to Linus, add insert_resource_expand_to_fit, and change
__insert_resource to static without lock

v3: use reserve_region_with_split() instead to hand overlapping

       with test case by extend 0xe0000000 - 0xeffffff to 0xdd800000 -
       get
               e0000000-efffffff : PCI MMCONFIG 0
                        e0000000-efffffff : reserved
       in /proc/iomem
       get
               found conflict for reserved [dd800000, efffffff], try to reserve with split
                   __reserve_region_with_split: (PCI Bus #80) [dd000000, ddffffff], res: (reserved) [dd800000, efffffff]
                   __reserve_region_with_split: (PCI Bus #00) [de000000, dfffffff], res: (reserved) [de000000, efffffff]
               initcall pci_subsys_init+0x0/0x121 returned 0 after 381 msecs
       in dmesg

v4: take out __insert_resource and insert_resource_expand_to_fit : Linus already check in.
use reserve_region_with_split at the first point
use const char *name

v5: fix checking on overlapping

v6: only reserve common area in conflict

       so got sth in /proc/iomem
               d8000000-dfffffff : PCI Bus #00
                 dc000000-dfffffff : GART
                   dc000000-dfffffff : reserved
               e0000000-efffffff : PCI MMCONFIG 0
                 e0000000-efffffff : reserved
       when we have big range in e820
               00000000dc000000-00000000f0000000 (reserved)
---
 arch/x86/kernel/e820.c |    2 -
 include/linux/ioport.h |    3 ++
 kernel/resource.c      |   69 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 72 insertions(+), 2 deletions(-)

Index: linux-2.6/arch/x86/kernel/e820.c
===================================================================

arch/x86/kernel/e820.c +1 -1
@@ -1320,7 +1320,7 @@ void __init e820_reserve_resources_late(
       res = e820_res;
       for (i = 0; i < e820.nr_map; i++) {
               if (!res->parent && res->end)
-                       insert_resource(&iomem_resource, res);
+                       reserve_region_with_split(&iomem_resource, res->start, res->end, res->name);
               res++;
       }
 }

Index: linux-2.6/include/linux/ioport.h
===================================================================

include/linux/ioport.h +3 -0
@@ -108,6 +108,9 @@ extern struct resource iomem_resource;
 
 extern int request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
+extern void reserve_region_with_split(struct resource *root,
+                            resource_size_t start, resource_size_t end,
+                            const char *name);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,

Index: linux-2.6/kernel/resource.c
===================================================================

kernel/resource.c +68 -1
@@ -512,10 +512,77 @@ int adjust_resource(struct resource *res
       result = 0;
 
 out:
-       write_unlock(&resource_lock);
       return result;
 }
 
+static void __init __reserve_region_with_split(struct resource *root,
+               resource_size_t start, resource_size_t end,
+               const char *name)
+{
+       struct resource *parent = root;
+       struct resource *conflict;
+       struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
+
+       if (!res)
+               return;
+
+       res->name = name;
+       res->start = start;
+       res->end = end;
+       res->flags = IORESOURCE_BUSY;
+
+       for (;;) {
+               conflict = __request_resource(parent, res);
+               if (!conflict)
+                       break;
+               if (conflict != parent) {
+                       parent = conflict;
+                       if (!(conflict->flags & IORESOURCE_BUSY))
+                               continue;
+               }
+
+               /* Uhhuh, that didn't work out.. */
+               kfree(res);
+               res = NULL;
+               break;
+       }
+
+       if (!res) {
+               printk(KERN_DEBUG "    __reserve_region_with_split: (%s) [%llx, %llx], res: (%s) [%llx, %llx]\n",
+                        conflict->name, conflict->start, conflict->end,
+                        name, start, end);
+
+               /* failed, split and try again */
+
+               /* conflict coverred whole area */
+               if (conflict->start <= start && conflict->end >= end)
+                       return;
+
+               if (conflict->start > start)
+                       __reserve_region_with_split(root, start, conflict->start-1, name);
+               if (!(conflict->flags & IORESOURCE_BUSY)) {
+                       resource_size_t common_start, common_end;
+
+                       common_start = max(conflict->start, start);
+                       common_end = min(conflict->end, end);
+                       if (common_start < common_end)
+                               __reserve_region_with_split(root, common_start, common_end, name);
+               }
+               if (conflict->end < end)
+                       __reserve_region_with_split(root, conflict->end+1, end, name);
+       }
+
+}
+
+void reserve_region_with_split(struct resource *root,
+               resource_size_t start, resource_size_t end,
+               const char *name)
+{
+       write_lock(&resource_lock);
+       __reserve_region_with_split(root, start, end, name);
+       write_unlock(&resource_lock);
+}
+
 EXPORT_SYMBOL(adjust_resource);
 
 /**