lkml.org 
[lkml]   [2010]   [Mar]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectInfinite loop on boot in free_early_partial due to start==end on tip/master
From
Date
Adding some debug, including a WARN_ON(start >= end) I get:

(early) [ 0.000000] pcpu_embed_first_chunk CPU0 copy and return the unused part ffff880001f1f000 0x0. unit_size 122880 size sum 122880
(early) [ 0.000000] free_early_partial 0x1f1f000-0x1f1f000
(early) [ 0.000000] ------------[ cut here ]------------
(early) [ 0.000000] WARNING: at /local/scratch/ianc/devel/kernels/linux-2.6/kernel/early_res.c:359 free_early_partial+0x46/0x15c()
(early) [ 0.000000] Modules linked in:(early)
(early) [ 0.000000] Pid: 0, comm: swapper Not tainted 2.6.33-x86_64-xenU-tip+ #119
(early) [ 0.000000] Call Trace:
(early) [ 0.000000] [<ffffffff81b3938e>] ? free_early_partial+0x46/0x15c
(early) [ 0.000000] [<ffffffff81047317>] warn_slowpath_common+0x77/0xa4
(early) [ 0.000000] [<ffffffff81047353>] warn_slowpath_null+0xf/0x11
(early) [ 0.000000] [<ffffffff81b3938e>] free_early_partial+0x46/0x15c
(early) [ 0.000000] [<ffffffff81b29a05>] pcpu_fc_free+0x1f/0x23
(early) [ 0.000000] [<ffffffff81b3fcf1>] pcpu_embed_first_chunk+0x22f/0x363
(early) [ 0.000000] [<ffffffff81b299e6>] ? pcpu_fc_free+0x0/0x23
(early) [ 0.000000] [<ffffffff81b29a09>] ? pcpu_fc_alloc+0x0/0xa9
(early) [ 0.000000] [<ffffffff81b29825>] setup_per_cpu_areas+0x82/0x238
(early) [ 0.000000] [<ffffffff81b1eabc>] start_kernel+0x14b/0x3ab
(early) [ 0.000000] [<ffffffff81b1e2ba>] x86_64_start_reservations+0xa5/0xa9
(early) [ 0.000000] [<ffffffff81b21d61>] xen_start_kernel+0x52e/0x535
(early) [ 0.000000] ---[ end trace 4eaa2a86a8e2da22 ]---
I'm seeing this in a Xen guest but I don't think it relates to Xen
specifically. The problem occurs when ai->unit_size == size_sum in
pcpu_embed_first_chunk(). It looks like I just got unlucky with the
various sizes of stuff coming out of pcpu_build_alloc_info().

It's also possible that the presence or absence of PSE is responsible,
since it impacts atom_size which feeds into alloc_size and has an impact
on all these calculations.

I was able to reproduce on native 32 bit by disabling PSE and
artificially increasing dyn_size.

(early) [ 0.000000] pcpu_build_alloc_info initial max_upa/upa is 1
(early) [ 0.000000] pcpu_build_alloc_info after expansion best_upa/upa is 1
(early) [ 0.000000] reserve_early_without_check: 0x1ce3000-0x1ce4000 "BOOTMEM"
(early) [ 0.000000] pcpu_build_alloc_info unit_size 122880 == alloc_size 122880 / upa 1
(early) [ 0.000000] pcpu_embed_first_chunk size_sum = 122880
(early) [ 0.000000] pcpu_embed_first_chunk static_size = 91304
(early) [ 0.000000] pcpu_embed_first_chunk reserved_size = 8192
(early) [ 0.000000] pcpu_embed_first_chunk dyn_size = 23384
(early) [ 0.000000] pcpu_embed_first_chunk unit_size 122880
I guess the arises from fb90ef93 "early_res: Add free_early_partial"
since I don't see any other changes in this area recently.

Following patch fixes this specific issue and adds a warning to catch
future potential errors of this type.

---
Subject: x86: do not free zero sized per cpu areas
This avoids an infinite loop in free_early_partial().

Add a warning to free_early_partial to catch future problems.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>

diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index ef6370b..89a3205 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -140,7 +140,8 @@ static void __init pcpu_fc_free(void *ptr, size_t size)
#ifdef CONFIG_NO_BOOTMEM
u64 start = __pa(ptr);
u64 end = start + size;
- free_early_partial(start, end);
+ if (start < end)
+ free_early_partial(start, end);
#else
free_bootmem(__pa(ptr), size);
#endif
diff --git a/kernel/early_res.c b/kernel/early_res.c
index 3cb2c66..fbde443 100644
--- a/kernel/early_res.c
+++ b/kernel/early_res.c
@@ -333,6 +333,8 @@ void __init free_early_partial(u64 start, u64 end)
struct early_res *r;
int i;

+ WARN_ON(start>=end);
+
try_next:
i = find_overlapped_early(start, end);
if (i >= max_early_res)



\
 
 \ /
  Last update: 2010-03-05 16:05    [from the cache]
©2003-2011 Jasper Spaans