From: Eric Dumazet percpu_data blindly allocates bootmem memory to store NR_CPUS instances of cpudata, instead of allocating memory only for possible cpus. This patch saves ram, allocating num_possible_cpus() (instead of NR_CPUS) instances. This patch also makes sure a reference to per_cpu(object, not_possible_cpu) does a reference to invalid memory (NULL+small_offset). As some architectures (x86_64) are now allocating cpudata only on possible cpus, we (kernel developers on x86 machines) should make sure that x86 does a similar thing to find bugs. This is important that this patch has some exposure in -mm for some time, some places must now use : for_each_cpu(i) { ... per_cpu(xxx,i) ... instead of the traditional for (i = 0 ; i < NR_CPUS ; i++) Signed-off-by: Eric Dumazet Cc: "David S. Miller" Cc: James Bottomley Cc: Jens Axboe Acked-by: Ingo Molnar Signed-off-by: Andrew Morton --- block/ll_rw_blk.c | 2 +- drivers/scsi/scsi.c | 2 +- init/main.c | 11 ++++++++--- net/core/utils.c | 2 +- net/ipv4/proc.c | 2 +- net/ipv6/proc.c | 2 +- net/socket.c | 2 +- core/dev.c | 0 8 files changed, 14 insertions(+), 9 deletions(-) diff -puN block/ll_rw_blk.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject block/ll_rw_blk.c --- devel/block/ll_rw_blk.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/block/ll_rw_blk.c 2006-01-28 13:17:23.000000000 -0800 @@ -3487,7 +3487,7 @@ int __init blk_dev_init(void) iocontext_cachep = kmem_cache_create("blkdev_ioc", sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL); - for (i = 0; i < NR_CPUS; i++) + for_each_cpu(i) INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL); diff -puN drivers/scsi/scsi.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject drivers/scsi/scsi.c --- devel/drivers/scsi/scsi.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/drivers/scsi/scsi.c 2006-01-28 13:17:23.000000000 -0800 @@ -1245,7 +1245,7 @@ static int __init init_scsi(void) if (error) goto cleanup_sysctl; - for (i = 0; i < NR_CPUS; i++) + for_each_cpu(i) INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); devfs_mk_dir("scsi"); diff -puN init/main.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject init/main.c --- devel/init/main.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/init/main.c 2006-01-28 13:17:23.000000000 -0800 @@ -333,6 +333,7 @@ static void __init setup_per_cpu_areas(v { unsigned long size, i; char *ptr; + unsigned long nr_possible_cpus = num_possible_cpus(); /* Copy section for each CPU (we discard the original) */ size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); @@ -340,12 +341,16 @@ static void __init setup_per_cpu_areas(v if (size < PERCPU_ENOUGH_ROOM) size = PERCPU_ENOUGH_ROOM; #endif + ptr = alloc_bootmem(size * nr_possible_cpus); - ptr = alloc_bootmem(size * NR_CPUS); - - for (i = 0; i < NR_CPUS; i++, ptr += size) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) { + __per_cpu_offset[i] = (char*)0 - __per_cpu_start; + continue; + } __per_cpu_offset[i] = ptr - __per_cpu_start; memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); + ptr += size; } } #endif /* !__GENERIC_PER_CPU */ diff -puN net/core/dev.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject net/core/dev.c diff -puN net/core/utils.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject net/core/utils.c --- devel/net/core/utils.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/net/core/utils.c 2006-01-28 13:17:23.000000000 -0800 @@ -121,7 +121,7 @@ void __init net_random_init(void) { int i; - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu(i) { struct nrnd_state *state = &per_cpu(net_rand_state,i); __net_srandom(state, i+jiffies); } diff -puN net/ipv4/proc.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject net/ipv4/proc.c --- devel/net/ipv4/proc.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/net/ipv4/proc.c 2006-01-28 13:17:23.000000000 -0800 @@ -49,7 +49,7 @@ static int fold_prot_inuse(struct proto int res = 0; int cpu; - for (cpu = 0; cpu < NR_CPUS; cpu++) + for_each_cpu(cpu) res += proto->stats[cpu].inuse; return res; diff -puN net/ipv6/proc.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject net/ipv6/proc.c --- devel/net/ipv6/proc.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/net/ipv6/proc.c 2006-01-28 13:17:23.000000000 -0800 @@ -38,7 +38,7 @@ static int fold_prot_inuse(struct proto int res = 0; int cpu; - for (cpu=0; cpustats[cpu].inuse; return res; diff -puN net/socket.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject net/socket.c --- devel/net/socket.c~reduce-size-of-percpudata-and-make-sure-per_cpuobject 2006-01-28 13:17:23.000000000 -0800 +++ devel-akpm/net/socket.c 2006-01-28 13:19:19.000000000 -0800 @@ -2108,7 +2108,7 @@ void socket_seq_show(struct seq_file *se int cpu; int counter = 0; - for_each_cpu (cpu) + for_each_cpu(cpu) counter += per_cpu(sockets_in_use, cpu); /* It can be negative, by the way. 8) */ _