Re: [PATCH] x86: split e820 reserved entries record to late v4 - fix v6

From: Yinghai Lu
Date: Sat Aug 30 2008 - 22:19:57 EST


Adding to : Ivan..

On Sat, Aug 30, 2008 at 1:34 PM, Yinghai Lu <yhlu.kernel@xxxxxxxxx> wrote:
> 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)
>
> Signed-off-by: Yinghai Lu <yhlu.kernel@xxxxxxxxx>
>
> ---
> 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
> ===================================================================
> --- linux-2.6.orig/arch/x86/kernel/e820.c
> +++ 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++;
> }
> }
> Index: linux-2.6/include/linux/ioport.h
> ===================================================================
> --- linux-2.6.orig/include/linux/ioport.h
> +++ 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,
> Index: linux-2.6/kernel/resource.c
> ===================================================================
> --- linux-2.6.orig/kernel/resource.c
> +++ linux-2.6/kernel/resource.c
> @@ -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);
>
> /**
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/