diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-03-24 06:15:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-24 10:33:21 -0500 |
commit | a4a6198b80cf82eb8160603c98da218d1bd5e104 (patch) | |
tree | 8c59e9088840b6b95e46c00ddda4fd7a134154c2 /kernel | |
parent | c98d8cfbc600af88e9e6cffc84dd342280445760 (diff) |
[PATCH] tvec_bases too large for per-cpu data
With internal Xen-enabled kernels we see the kernel's static per-cpu data
area exceed the limit of 32k on x86-64, and even native x86-64 kernels get
fairly close to that limit. I generally question whether it is reasonable
to have data structures several kb in size allocated as per-cpu data when
the space there is rather limited.
The biggest arch-independent consumer is tvec_bases (over 4k on 32-bit
archs, over 8k on 64-bit ones), which now gets converted to use dynamically
allocated memory instead.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/timer.c | 45 |
1 files changed, 34 insertions, 11 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index 2410c18dbeb1..4427e725ccdd 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -86,7 +86,8 @@ struct tvec_t_base_s { | |||
86 | } ____cacheline_aligned_in_smp; | 86 | } ____cacheline_aligned_in_smp; |
87 | 87 | ||
88 | typedef struct tvec_t_base_s tvec_base_t; | 88 | typedef struct tvec_t_base_s tvec_base_t; |
89 | static DEFINE_PER_CPU(tvec_base_t, tvec_bases); | 89 | static DEFINE_PER_CPU(tvec_base_t *, tvec_bases); |
90 | static tvec_base_t boot_tvec_bases; | ||
90 | 91 | ||
91 | static inline void set_running_timer(tvec_base_t *base, | 92 | static inline void set_running_timer(tvec_base_t *base, |
92 | struct timer_list *timer) | 93 | struct timer_list *timer) |
@@ -157,7 +158,7 @@ EXPORT_SYMBOL(__init_timer_base); | |||
157 | void fastcall init_timer(struct timer_list *timer) | 158 | void fastcall init_timer(struct timer_list *timer) |
158 | { | 159 | { |
159 | timer->entry.next = NULL; | 160 | timer->entry.next = NULL; |
160 | timer->base = &per_cpu(tvec_bases, raw_smp_processor_id()).t_base; | 161 | timer->base = &per_cpu(tvec_bases, raw_smp_processor_id())->t_base; |
161 | } | 162 | } |
162 | EXPORT_SYMBOL(init_timer); | 163 | EXPORT_SYMBOL(init_timer); |
163 | 164 | ||
@@ -218,7 +219,7 @@ int __mod_timer(struct timer_list *timer, unsigned long expires) | |||
218 | ret = 1; | 219 | ret = 1; |
219 | } | 220 | } |
220 | 221 | ||
221 | new_base = &__get_cpu_var(tvec_bases); | 222 | new_base = __get_cpu_var(tvec_bases); |
222 | 223 | ||
223 | if (base != &new_base->t_base) { | 224 | if (base != &new_base->t_base) { |
224 | /* | 225 | /* |
@@ -258,7 +259,7 @@ EXPORT_SYMBOL(__mod_timer); | |||
258 | */ | 259 | */ |
259 | void add_timer_on(struct timer_list *timer, int cpu) | 260 | void add_timer_on(struct timer_list *timer, int cpu) |
260 | { | 261 | { |
261 | tvec_base_t *base = &per_cpu(tvec_bases, cpu); | 262 | tvec_base_t *base = per_cpu(tvec_bases, cpu); |
262 | unsigned long flags; | 263 | unsigned long flags; |
263 | 264 | ||
264 | BUG_ON(timer_pending(timer) || !timer->function); | 265 | BUG_ON(timer_pending(timer) || !timer->function); |
@@ -504,7 +505,7 @@ unsigned long next_timer_interrupt(void) | |||
504 | } | 505 | } |
505 | hr_expires += jiffies; | 506 | hr_expires += jiffies; |
506 | 507 | ||
507 | base = &__get_cpu_var(tvec_bases); | 508 | base = __get_cpu_var(tvec_bases); |
508 | spin_lock(&base->t_base.lock); | 509 | spin_lock(&base->t_base.lock); |
509 | expires = base->timer_jiffies + (LONG_MAX >> 1); | 510 | expires = base->timer_jiffies + (LONG_MAX >> 1); |
510 | list = NULL; | 511 | list = NULL; |
@@ -901,7 +902,7 @@ EXPORT_SYMBOL(xtime_lock); | |||
901 | */ | 902 | */ |
902 | static void run_timer_softirq(struct softirq_action *h) | 903 | static void run_timer_softirq(struct softirq_action *h) |
903 | { | 904 | { |
904 | tvec_base_t *base = &__get_cpu_var(tvec_bases); | 905 | tvec_base_t *base = __get_cpu_var(tvec_bases); |
905 | 906 | ||
906 | hrtimer_run_queues(); | 907 | hrtimer_run_queues(); |
907 | if (time_after_eq(jiffies, base->timer_jiffies)) | 908 | if (time_after_eq(jiffies, base->timer_jiffies)) |
@@ -1256,12 +1257,32 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info) | |||
1256 | return 0; | 1257 | return 0; |
1257 | } | 1258 | } |
1258 | 1259 | ||
1259 | static void __devinit init_timers_cpu(int cpu) | 1260 | static int __devinit init_timers_cpu(int cpu) |
1260 | { | 1261 | { |
1261 | int j; | 1262 | int j; |
1262 | tvec_base_t *base; | 1263 | tvec_base_t *base; |
1263 | 1264 | ||
1264 | base = &per_cpu(tvec_bases, cpu); | 1265 | base = per_cpu(tvec_bases, cpu); |
1266 | if (!base) { | ||
1267 | static char boot_done; | ||
1268 | |||
1269 | /* | ||
1270 | * Cannot do allocation in init_timers as that runs before the | ||
1271 | * allocator initializes (and would waste memory if there are | ||
1272 | * more possible CPUs than will ever be installed/brought up). | ||
1273 | */ | ||
1274 | if (boot_done) { | ||
1275 | base = kmalloc_node(sizeof(*base), GFP_KERNEL, | ||
1276 | cpu_to_node(cpu)); | ||
1277 | if (!base) | ||
1278 | return -ENOMEM; | ||
1279 | memset(base, 0, sizeof(*base)); | ||
1280 | } else { | ||
1281 | base = &boot_tvec_bases; | ||
1282 | boot_done = 1; | ||
1283 | } | ||
1284 | per_cpu(tvec_bases, cpu) = base; | ||
1285 | } | ||
1265 | spin_lock_init(&base->t_base.lock); | 1286 | spin_lock_init(&base->t_base.lock); |
1266 | for (j = 0; j < TVN_SIZE; j++) { | 1287 | for (j = 0; j < TVN_SIZE; j++) { |
1267 | INIT_LIST_HEAD(base->tv5.vec + j); | 1288 | INIT_LIST_HEAD(base->tv5.vec + j); |
@@ -1273,6 +1294,7 @@ static void __devinit init_timers_cpu(int cpu) | |||
1273 | INIT_LIST_HEAD(base->tv1.vec + j); | 1294 | INIT_LIST_HEAD(base->tv1.vec + j); |
1274 | 1295 | ||
1275 | base->timer_jiffies = jiffies; | 1296 | base->timer_jiffies = jiffies; |
1297 | return 0; | ||
1276 | } | 1298 | } |
1277 | 1299 | ||
1278 | #ifdef CONFIG_HOTPLUG_CPU | 1300 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -1295,8 +1317,8 @@ static void __devinit migrate_timers(int cpu) | |||
1295 | int i; | 1317 | int i; |
1296 | 1318 | ||
1297 | BUG_ON(cpu_online(cpu)); | 1319 | BUG_ON(cpu_online(cpu)); |
1298 | old_base = &per_cpu(tvec_bases, cpu); | 1320 | old_base = per_cpu(tvec_bases, cpu); |
1299 | new_base = &get_cpu_var(tvec_bases); | 1321 | new_base = get_cpu_var(tvec_bases); |
1300 | 1322 | ||
1301 | local_irq_disable(); | 1323 | local_irq_disable(); |
1302 | spin_lock(&new_base->t_base.lock); | 1324 | spin_lock(&new_base->t_base.lock); |
@@ -1326,7 +1348,8 @@ static int __devinit timer_cpu_notify(struct notifier_block *self, | |||
1326 | long cpu = (long)hcpu; | 1348 | long cpu = (long)hcpu; |
1327 | switch(action) { | 1349 | switch(action) { |
1328 | case CPU_UP_PREPARE: | 1350 | case CPU_UP_PREPARE: |
1329 | init_timers_cpu(cpu); | 1351 | if (init_timers_cpu(cpu) < 0) |
1352 | return NOTIFY_BAD; | ||
1330 | break; | 1353 | break; |
1331 | #ifdef CONFIG_HOTPLUG_CPU | 1354 | #ifdef CONFIG_HOTPLUG_CPU |
1332 | case CPU_DEAD: | 1355 | case CPU_DEAD: |