mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
xen/timers: Fix memory leak with cpu unplug/plug
timer_softirq_action() realloc's itself a larger timer heap whenever necessary, which includes bootstrapping from the empty dummy_heap. Nothing ever freed this allocation. CPU plug and unplug has the side effect of zeroing the percpu data area, which clears ts->heap. This in turn causes new timers to be put on the list rather than the heap, and for timer_softirq_action() to bootstrap itself again. This in practice leaks ts->heap every time a CPU is unplugged and replugged. Implement free_percpu_timers() which includes freeing ts->heap when appropriate, and update the notifier callback with the recent cpu parking logic and free-avoidance across suspend. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
1c65041635
commit
597fbb8be6
1 file changed
+26
-1
+26
-1
@@ -615,6 +615,22 @@ static void migrate_timers_from_cpu(unsigned int old_cpu)
|
||||
*/
|
||||
static struct timer *dummy_heap[1];
|
||||
|
||||
static void free_percpu_timers(unsigned int cpu)
|
||||
{
|
||||
struct timers *ts = &per_cpu(timers, cpu);
|
||||
|
||||
migrate_timers_from_cpu(cpu);
|
||||
|
||||
ASSERT(heap_metadata(ts->heap)->size == 0);
|
||||
if ( heap_metadata(ts->heap)->limit )
|
||||
{
|
||||
xfree(ts->heap);
|
||||
ts->heap = dummy_heap;
|
||||
}
|
||||
else
|
||||
ASSERT(ts->heap == dummy_heap);
|
||||
}
|
||||
|
||||
static int cpu_callback(
|
||||
struct notifier_block *nfb, unsigned long action, void *hcpu)
|
||||
{
|
||||
@@ -628,10 +644,19 @@ static int cpu_callback(
|
||||
spin_lock_init(&ts->lock);
|
||||
ts->heap = dummy_heap;
|
||||
break;
|
||||
|
||||
case CPU_UP_CANCELED:
|
||||
case CPU_DEAD:
|
||||
migrate_timers_from_cpu(cpu);
|
||||
case CPU_RESUME_FAILED:
|
||||
if ( !park_offline_cpus && system_state != SYS_STATE_suspend )
|
||||
free_percpu_timers(cpu);
|
||||
break;
|
||||
|
||||
case CPU_REMOVE:
|
||||
if ( park_offline_cpus )
|
||||
free_percpu_timers(cpu);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||