mm: convert totalram_pages, totalhigh_pages and managed pages to atomic
Subsystems (54)
v2 cover mm: convert totalram_pages, totalhigh_pages and managed pages to atomic
This series convert totalram_pages, totalhigh_pages and zone->managed_pages to atomic variables.
The patch was comiple tested on x86(x86_64_defconfig & i386_defconfig) on 4.20-rc1. And memory hotplug tested on arm64, but on an older version of kernel.
Arun KS (4):
mm: Fix multiple evaluvations of totalram_pages and managed_pages
mm: Convert zone->managed_pages to atomic variable
mm: convert totalram_pages and totalhigh_pages variables to atomic
mm: Remove managed_page_count spinlock
arch/csky/mm/init.c | 4 +- arch/powerpc/platforms/pseries/cmm.c | 10 ++-- arch/s390/mm/init.c | 2 +- arch/um/kernel/mem.c | 3 +- arch/x86/kernel/cpu/microcode/core.c | 5 +- drivers/char/agp/backend.c | 4 +- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 2 +- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 4 +- drivers/hv/hv_balloon.c | 19 +++---- drivers/md/dm-bufio.c | 2 +- drivers/md/dm-crypt.c | 2 +- drivers/md/dm-integrity.c | 2 +- drivers/md/dm-stats.c | 2 +- drivers/media/platform/mtk-vpu/mtk_vpu.c | 2 +- drivers/misc/vmw_balloon.c | 2 +- drivers/parisc/ccio-dma.c | 4 +- drivers/parisc/sba_iommu.c | 4 +- drivers/staging/android/ion/ion_system_heap.c | 2 +- drivers/xen/xen-selfballoon.c | 6 +-- fs/ceph/super.h | 2 +- fs/file_table.c | 7 +-- fs/fuse/inode.c | 2 +- fs/nfs/write.c | 2 +- fs/nfsd/nfscache.c | 2 +- fs/ntfs/malloc.h | 2 +- fs/proc/base.c | 2 +- include/linux/highmem.h | 28 ++++++++++- include/linux/mm.h | 27 +++++++++- include/linux/mmzone.h | 15 +++--- include/linux/swap.h | 1 - kernel/fork.c | 5 +- kernel/kexec_core.c | 5 +- kernel/power/snapshot.c | 2 +- lib/show_mem.c | 2 +- mm/highmem.c | 4 +- mm/huge_memory.c | 2 +- mm/kasan/quarantine.c | 2 +- mm/memblock.c | 6 +-- mm/mm_init.c | 2 +- mm/oom_kill.c | 2 +- mm/page_alloc.c | 71 +++++++++++++-------------- mm/shmem.c | 7 +-- mm/slab.c | 2 +- mm/swap.c | 2 +- mm/util.c | 2 +- mm/vmalloc.c | 4 +- mm/vmstat.c | 4 +- mm/workingset.c | 2 +- mm/zswap.c | 4 +- net/dccp/proto.c | 7 +-- net/decnet/dn_route.c | 2 +- net/ipv4/tcp_metrics.c | 2 +- net/netfilter/nf_conntrack_core.c | 7 +-- net/netfilter/xt_hashlimit.c | 5 +- net/sctp/protocol.c | 7 +-- security/integrity/ima/ima_kexec.c | 2 +- 57 files changed, 193 insertions(+), 142 deletions(-)
Signature · 1 line
1.9.1
PATCH v2 1/4 mm: Fix multiple evaluvations of totalram_pages and managed_pages
This patch is in preparation to a later patch which converts totalram_pages and zone->managed_pages to atomic variables. This patch does not introduce any functional changes.
--- arch/um/kernel/mem.c | 3 +-- arch/x86/kernel/cpu/microcode/core.c | 5 +++-- drivers/hv/hv_balloon.c | 19 ++++++++++--------- fs/file_table.c | 7 ++++--- kernel/fork.c | 5 +++-- kernel/kexec_core.c | 5 +++-- mm/page_alloc.c | 5 +++-- mm/shmem.c | 3 ++- net/dccp/proto.c | 7 ++++--- net/netfilter/nf_conntrack_core.c | 7 ++++--- net/netfilter/xt_hashlimit.c | 5 +++-- net/sctp/protocol.c | 7 ++++--- 12 files changed, 44 insertions(+), 34 deletions(-)
arch/um/kernel/mem.c +1 -2
@@ -51,8 +51,7 @@ void __init mem_init(void)/* this will put all low memory onto the freelists */ memblock_free_all (); - max_low_pfn = totalram_pages; - max_pfn = totalram_pages; + max_pfn = max_low_pfn = totalram_pages;mem_init_print_info (NULL ); kmalloc_ok =1 ; }
arch/x86/kernel/cpu/microcode/core.c +3 -2
@@ -434,9 +434,10 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { ssize_t ret = -EINVAL; +unsigned long totalram_pgs = totalram_pages; -if ((len >>PAGE_SHIFT ) > totalram_pages) { -pr_err ("too much data (max %ld pages)\n" , totalram_pages); +if ((len >>PAGE_SHIFT ) > totalram_pgs) { +pr_err ("too much data (max %ld pages)\n" , totalram_pgs);return ret; }
drivers/hv/hv_balloon.c +10 -9
@@ -1090,6 +1090,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)static unsigned long compute_balloon_floor (void ) {unsigned long min_pages; +unsigned long totalram_pgs = totalram_pages;#define MB2PAGES (mb) ((mb) << (20 - PAGE_SHIFT))/* Simple continuous piecewiese linear function: * max MiB -> min MiB gradient
@@ -1102,16 +1103,16 @@ static unsigned long compute_balloon_floor(void)* 8192 744 (1/16) * 32768 1512 (1/32) */ -if (totalram_pages <MB2PAGES (128 )) - min_pages =MB2PAGES (8 ) + (totalram_pages >>1 ); -else if (totalram_pages <MB2PAGES (512 )) - min_pages =MB2PAGES (40 ) + (totalram_pages >>2 ); -else if (totalram_pages <MB2PAGES (2048 )) - min_pages =MB2PAGES (104 ) + (totalram_pages >>3 ); -else if (totalram_pages <MB2PAGES (8192 )) - min_pages =MB2PAGES (232 ) + (totalram_pages >>4 ); +if (totalram_pgs <MB2PAGES (128 )) + min_pages =MB2PAGES (8 ) + (totalram_pgs >>1 ); +else if (totalram_pgs <MB2PAGES (512 )) + min_pages =MB2PAGES (40 ) + (totalram_pgs >>2 ); +else if (totalram_pgs <MB2PAGES (2048 )) + min_pages =MB2PAGES (104 ) + (totalram_pgs >>3 ); +else if (totalram_pgs <MB2PAGES (8192 )) + min_pages =MB2PAGES (232 ) + (totalram_pgs >>4 );else - min_pages =MB2PAGES (488 ) + (totalram_pages >>5 ); + min_pages =MB2PAGES (488 ) + (totalram_pgs >>5 );#undef MB2PAGESreturn min_pages; }
fs/file_table.c +4 -3
@@ -380,10 +380,11 @@ void __init files_init(void)void __init files_maxfiles_init (void ) {unsigned long n; -unsigned long memreserve = (totalram_pages -nr_free_pages ()) *3 /2 ; +unsigned long totalram_pgs = totalram_pages; +unsigned long memreserve = (totalram_pgs -nr_free_pages ()) *3 /2 ; - memreserve =min (memreserve, totalram_pages -1 ); - n = ((totalram_pages - memreserve) * (PAGE_SIZE /1024 )) /10 ; + memreserve =min (memreserve, totalram_pgs -1 ); + n = ((totalram_pgs - memreserve) * (PAGE_SIZE /1024 )) /10 ; files_stat.max_files = max_t(unsigned long, n, NR_FILE); }
kernel/fork.c +3 -2
@@ -739,15 +739,16 @@ void __init __weak arch_task_cache_init(void) { }static void set_max_threads (unsigned int max_threads_suggested) {u64 threads; +unsigned long totalram_pgs = totalram_pages;/* * The number of threads shall be limited such that the thread * structures may only consume a small part of the available memory. */ -if (fls64 (totalram_pages) +fls64 (PAGE_SIZE ) >64 ) +if (fls64 (totalram_pgs) +fls64 (PAGE_SIZE ) >64 ) threads =MAX_THREADS ;else - threads =div64_u64 ((u64 ) totalram_pages * (u64 )PAGE_SIZE , + threads =div64_u64 ((u64 ) totalram_pgs * (u64 )PAGE_SIZE , (u64 )THREAD_SIZE *8UL );if (threads > max_threads_suggested)
kernel/kexec_core.c +3 -2
@@ -152,6 +152,7 @@ int sanity_check_segment_list(struct kimage *image)int i;unsigned long nr_segments = image->nr_segments;unsigned long total_pages =0 ; +unsigned long totalram_pgs = totalram_pages;/* * Verify we have good destination addresses. The caller is
@@ -217,13 +218,13 @@ int sanity_check_segment_list(struct kimage *image)* wasted allocating pages, which can cause a soft lockup. */ for (i =0 ; i < nr_segments; i++) { -if (PAGE_COUNT (image->segment[i].memsz) > totalram_pages /2 ) +if (PAGE_COUNT (image->segment[i].memsz) > totalram_pgs /2 )return -EINVAL ; total_pages +=PAGE_COUNT (image->segment[i].memsz); } -if (total_pages > totalram_pages /2 ) +if (total_pages > totalram_pgs /2 )return -EINVAL ;/*
mm/page_alloc.c +3 -2
@@ -7245,6 +7245,7 @@ static void calculate_totalreserve_pages(void)for (i =0 ; i <MAX_NR_ZONES ; i++) {struct zone *zone = pgdat->node_zones + i;long max =0 ; +unsigned long managed_pages = zone->managed_pages;/* Find valid and maximum lowmem_reserve in the zone */ for (j = i; j <MAX_NR_ZONES ; j++) {
@@ -7255,8 +7256,8 @@ static void calculate_totalreserve_pages(void)/* we treat the high watermark as reserved pages. */ max +=high_wmark_pages (zone); -if (max > zone->managed_pages) - max = zone->managed_pages; +if (max > managed_pages) + max = managed_pages; pgdat->totalreserve_pages += max;
mm/shmem.c +2 -1
@@ -114,7 +114,8 @@ static unsigned long shmem_default_max_blocks(void)static unsigned long shmem_default_max_inodes (void ) { -return min (totalram_pages - totalhigh_pages, totalram_pages /2 ); +unsigned long totalram_pgs = totalram_pages; +return min (totalram_pgs - totalhigh_pages, totalram_pgs /2 ); }#endif
net/dccp/proto.c +4 -3
@@ -1131,6 +1131,7 @@ static inline void dccp_mib_exit(void)static int __init dccp_init (void ) {unsigned long goal; +unsigned long totalram_pgs = totalram_pages;int ehash_order, bhash_order, i;int rc;
@@ -1154,10 +1155,10 @@ static int __init dccp_init(void)* * The methodology is similar to that of the buffer cache. */ -if (totalram_pages >= (128 *1024 )) - goal = totalram_pages >> (21 -PAGE_SHIFT ); +if (totalram_pgs >= (128 *1024 )) + goal = totalram_pgs >> (21 -PAGE_SHIFT );else - goal = totalram_pages >> (23 -PAGE_SHIFT ); + goal = totalram_pgs >> (23 -PAGE_SHIFT );if (thash_entries) goal = (thash_entries *
net/netfilter/nf_conntrack_core.c +4 -3
@@ -2248,6 +2248,7 @@ static __always_inline unsigned int total_extension_size(void)int nf_conntrack_init_start (void ) { +unsigned long totalram_pgs = totalram_pages;int max_factor =8 ;int ret = -ENOMEM ;int i;
@@ -2267,11 +2268,11 @@ int nf_conntrack_init_start(void)* >= 4GB machines have 65536 buckets. */ nf_conntrack_htable_size - = (((totalram_pages <<PAGE_SHIFT ) /16384 ) + = (((totalram_pgs <<PAGE_SHIFT ) /16384 ) /sizeof (struct hlist_head )); -if (totalram_pages > (4 * (1024 *1024 *1024 /PAGE_SIZE ))) +if (totalram_pgs > (4 * (1024 *1024 *1024 /PAGE_SIZE ))) nf_conntrack_htable_size =65536 ; -else if (totalram_pages > (1024 *1024 *1024 /PAGE_SIZE )) +else if (totalram_pgs > (1024 *1024 *1024 /PAGE_SIZE )) nf_conntrack_htable_size =16384 ;if (nf_conntrack_htable_size <32 ) nf_conntrack_htable_size =32 ;
net/netfilter/xt_hashlimit.c +3 -2
@@ -274,14 +274,15 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,struct xt_hashlimit_htable *hinfo;const struct seq_operations *ops;unsigned int size, i; +unsigned long totalram_pgs = totalram_pages;int ret;if (cfg->size) { size = cfg->size; }else { - size = (totalram_pages <<PAGE_SHIFT ) /16384 / + size = (totalram_pgs <<PAGE_SHIFT ) /16384 /sizeof (struct hlist_head ); -if (totalram_pages >1024 *1024 *1024 /PAGE_SIZE ) +if (totalram_pgs >1024 *1024 *1024 /PAGE_SIZE ) size =8192 ;if (size <16 ) size =16 ;
net/sctp/protocol.c +4 -3
@@ -1368,6 +1368,7 @@ static __init int sctp_init(void)int status = -EINVAL ;unsigned long goal;unsigned long limit; +unsigned long totalram_pages;int max_share;int order;int num_entries;
@@ -1426,10 +1427,10 @@ static __init int sctp_init(void)* The methodology is similar to that of the tcp hash tables. * Though not identical. Start by getting a goal size */ -if (totalram_pages >= (128 *1024 )) - goal = totalram_pages >> (22 -PAGE_SHIFT ); +if (totalram_pgs >= (128 *1024 )) + goal = totalram_pgs >> (22 -PAGE_SHIFT );else - goal = totalram_pages >> (24 -PAGE_SHIFT ); + goal = totalram_pgs >> (24 -PAGE_SHIFT );/* Then compute the page order for said goal */ order =get_order (goal);
Signature · 1 line
1.9.1
Re: [PATCH v2 1/4] mm: Fix multiple evaluvations of totalram_pages and managed_pages
Quoted 3 lines · Arun KS
This patch is in preparation to a later patch which converts
totalram_pagesandzone->managed_pagesto atomic variables. This patch does not introduce any functional changes.
I forgot to comment on this one. The patch makes a lot of sense. But I would be little bit more conservative and won't claim "no functional changes". As things stand now multiple reads in the same function are racy (without holding the lock). I do not see any example of an obviously harmful case but claiming the above is too strong of a statement. I would simply go with something like "Please note that re-reading the value might lead to a different value and as such it could lead to unexpected behavior. There are no known bugs as a result of the current code but it is better to prevent from them in principle."
Quoted 2 lines
Signed-off-by Arun KS <[email protected]>Reviewed-by Konstantin Khlebnikov <[email protected]>
Other than that
Quoted 294 lines
--- arch/um/kernel/mem.c | 3 +-- arch/x86/kernel/cpu/microcode/core.c | 5 +++-- drivers/hv/hv_balloon.c | 19 ++++++++++--------- fs/file_table.c | 7 ++++--- kernel/fork.c | 5 +++-- kernel/kexec_core.c | 5 +++-- mm/page_alloc.c | 5 +++-- mm/shmem.c | 3 ++- net/dccp/proto.c | 7 ++++--- net/netfilter/nf_conntrack_core.c | 7 ++++--- net/netfilter/xt_hashlimit.c | 5 +++-- net/sctp/protocol.c | 7 ++++--- 12 files changed, 44 insertions(+), 34 deletions(-)arch/um/kernel/mem.c +1
-2@@ -51,8 +51,7 @@ void __init mem_init(void)/* this will put all low memory onto the freelists */ memblock_free_all (); - max_low_pfn = totalram_pages; - max_pfn = totalram_pages; + max_pfn = max_low_pfn = totalram_pages;mem_init_print_info (NULL ); kmalloc_ok =1 ; }arch/x86/kernel/cpu/microcode/core.c +3
-2@@ -434,9 +434,10 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { ssize_t ret = -EINVAL; +unsigned long totalram_pgs = totalram_pages; -if ((len >>PAGE_SHIFT ) > totalram_pages) { -pr_err ("too much data (max %ld pages)\n" , totalram_pages); +if ((len >>PAGE_SHIFT ) > totalram_pgs) { +pr_err ("too much data (max %ld pages)\n" , totalram_pgs);return ret; }drivers/hv/hv_balloon.c +10
-9@@ -1090,6 +1090,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)static unsigned long compute_balloon_floor (void ) {unsigned long min_pages; +unsigned long totalram_pgs = totalram_pages;#define MB2PAGES (mb) ((mb) << (20 - PAGE_SHIFT))/* Simple continuous piecewiese linear function: * max MiB -> min MiB gradient @@ -1102,16 +1103,16 @@ static unsigned long compute_balloon_floor(void)* 8192 744 (1/16) * 32768 1512 (1/32) */ -if (totalram_pages <MB2PAGES (128 )) - min_pages =MB2PAGES (8 ) + (totalram_pages >>1 ); -else if (totalram_pages <MB2PAGES (512 )) - min_pages =MB2PAGES (40 ) + (totalram_pages >>2 ); -else if (totalram_pages <MB2PAGES (2048 )) - min_pages =MB2PAGES (104 ) + (totalram_pages >>3 ); -else if (totalram_pages <MB2PAGES (8192 )) - min_pages =MB2PAGES (232 ) + (totalram_pages >>4 ); +if (totalram_pgs <MB2PAGES (128 )) + min_pages =MB2PAGES (8 ) + (totalram_pgs >>1 ); +else if (totalram_pgs <MB2PAGES (512 )) + min_pages =MB2PAGES (40 ) + (totalram_pgs >>2 ); +else if (totalram_pgs <MB2PAGES (2048 )) + min_pages =MB2PAGES (104 ) + (totalram_pgs >>3 ); +else if (totalram_pgs <MB2PAGES (8192 )) + min_pages =MB2PAGES (232 ) + (totalram_pgs >>4 );else - min_pages =MB2PAGES (488 ) + (totalram_pages >>5 ); + min_pages =MB2PAGES (488 ) + (totalram_pgs >>5 );#undef MB2PAGESreturn min_pages; }fs/file_table.c +4
-3@@ -380,10 +380,11 @@ void __init files_init(void)void __init files_maxfiles_init (void ) {unsigned long n; -unsigned long memreserve = (totalram_pages -nr_free_pages ()) *3 /2 ; +unsigned long totalram_pgs = totalram_pages; +unsigned long memreserve = (totalram_pgs -nr_free_pages ()) *3 /2 ; - memreserve =min (memreserve, totalram_pages -1 ); - n = ((totalram_pages - memreserve) * (PAGE_SIZE /1024 )) /10 ; + memreserve =min (memreserve, totalram_pgs -1 ); + n = ((totalram_pgs - memreserve) * (PAGE_SIZE /1024 )) /10 ; files_stat.max_files = max_t(unsigned long, n, NR_FILE); }kernel/fork.c +3
-2@@ -739,15 +739,16 @@ void __init __weak arch_task_cache_init(void) { }static void set_max_threads (unsigned int max_threads_suggested) {u64 threads; +unsigned long totalram_pgs = totalram_pages;/* * The number of threads shall be limited such that the thread * structures may only consume a small part of the available memory. */ -if (fls64 (totalram_pages) +fls64 (PAGE_SIZE ) >64 ) +if (fls64 (totalram_pgs) +fls64 (PAGE_SIZE ) >64 ) threads =MAX_THREADS ;else - threads =div64_u64 ((u64 ) totalram_pages * (u64 )PAGE_SIZE , + threads =div64_u64 ((u64 ) totalram_pgs * (u64 )PAGE_SIZE , (u64 )THREAD_SIZE *8UL );if (threads > max_threads_suggested)kernel/kexec_core.c +3
-2@@ -152,6 +152,7 @@ int sanity_check_segment_list(struct kimage *image)int i;unsigned long nr_segments = image->nr_segments;unsigned long total_pages =0 ; +unsigned long totalram_pgs = totalram_pages;/* * Verify we have good destination addresses. The caller is @@ -217,13 +218,13 @@ int sanity_check_segment_list(struct kimage *image)* wasted allocating pages, which can cause a soft lockup. */ for (i =0 ; i < nr_segments; i++) { -if (PAGE_COUNT (image->segment[i].memsz) > totalram_pages /2 ) +if (PAGE_COUNT (image->segment[i].memsz) > totalram_pgs /2 )return -EINVAL ; total_pages +=PAGE_COUNT (image->segment[i].memsz); } -if (total_pages > totalram_pages /2 ) +if (total_pages > totalram_pgs /2 )return -EINVAL ;/* mm/page_alloc.c +3
-2@@ -7245,6 +7245,7 @@ static void calculate_totalreserve_pages(void)for (i =0 ; i <MAX_NR_ZONES ; i++) {struct zone *zone = pgdat->node_zones + i;long max =0 ; +unsigned long managed_pages = zone->managed_pages;/* Find valid and maximum lowmem_reserve in the zone */ for (j = i; j <MAX_NR_ZONES ; j++) {@@ -7255,8 +7256,8 @@ static void calculate_totalreserve_pages(void)/* we treat the high watermark as reserved pages. */ max +=high_wmark_pages (zone); -if (max > zone->managed_pages) - max = zone->managed_pages; +if (max > managed_pages) + max = managed_pages; pgdat->totalreserve_pages += max;mm/shmem.c +2
-1@@ -114,7 +114,8 @@ static unsigned long shmem_default_max_blocks(void)static unsigned long shmem_default_max_inodes (void ) { -return min (totalram_pages - totalhigh_pages, totalram_pages /2 ); +unsigned long totalram_pgs = totalram_pages; +return min (totalram_pgs - totalhigh_pages, totalram_pgs /2 ); }#endif net/dccp/proto.c +4
-3@@ -1131,6 +1131,7 @@ static inline void dccp_mib_exit(void)static int __init dccp_init (void ) {unsigned long goal; +unsigned long totalram_pgs = totalram_pages;int ehash_order, bhash_order, i;int rc;@@ -1154,10 +1155,10 @@ static int __init dccp_init(void)* * The methodology is similar to that of the buffer cache. */ -if (totalram_pages >= (128 *1024 )) - goal = totalram_pages >> (21 -PAGE_SHIFT ); +if (totalram_pgs >= (128 *1024 )) + goal = totalram_pgs >> (21 -PAGE_SHIFT );else - goal = totalram_pages >> (23 -PAGE_SHIFT ); + goal = totalram_pgs >> (23 -PAGE_SHIFT );if (thash_entries) goal = (thash_entries *net/netfilter/nf_conntrack_core.c +4
-3@@ -2248,6 +2248,7 @@ static __always_inline unsigned int total_extension_size(void)int nf_conntrack_init_start (void ) { +unsigned long totalram_pgs = totalram_pages;int max_factor =8 ;int ret = -ENOMEM ;int i;@@ -2267,11 +2268,11 @@ int nf_conntrack_init_start(void)* >= 4GB machines have 65536 buckets. */ nf_conntrack_htable_size - = (((totalram_pages <<PAGE_SHIFT ) /16384 ) + = (((totalram_pgs <<PAGE_SHIFT ) /16384 ) /sizeof (struct hlist_head )); -if (totalram_pages > (4 * (1024 *1024 *1024 /PAGE_SIZE ))) +if (totalram_pgs > (4 * (1024 *1024 *1024 /PAGE_SIZE ))) nf_conntrack_htable_size =65536 ; -else if (totalram_pages > (1024 *1024 *1024 /PAGE_SIZE )) +else if (totalram_pgs > (1024 *1024 *1024 /PAGE_SIZE )) nf_conntrack_htable_size =16384 ;if (nf_conntrack_htable_size <32 ) nf_conntrack_htable_size =32 ;net/netfilter/xt_hashlimit.c +3
-2@@ -274,14 +274,15 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,struct xt_hashlimit_htable *hinfo;const struct seq_operations *ops;unsigned int size, i; +unsigned long totalram_pgs = totalram_pages;int ret;if (cfg->size) { size = cfg->size; }else { - size = (totalram_pages <<PAGE_SHIFT ) /16384 / + size = (totalram_pgs <<PAGE_SHIFT ) /16384 /sizeof (struct hlist_head ); -if (totalram_pages >1024 *1024 *1024 /PAGE_SIZE ) +if (totalram_pgs >1024 *1024 *1024 /PAGE_SIZE ) size =8192 ;if (size <16 ) size =16 ;net/sctp/protocol.c +4
-3@@ -1368,6 +1368,7 @@ static __init int sctp_init(void)int status = -EINVAL ;unsigned long goal;unsigned long limit; +unsigned long totalram_pages;int max_share;int order;int num_entries;@@ -1426,10 +1427,10 @@ static __init int sctp_init(void)* The methodology is similar to that of the tcp hash tables. * Though not identical. Start by getting a goal size */ -if (totalram_pages >= (128 *1024 )) - goal = totalram_pages >> (22 -PAGE_SHIFT ); +if (totalram_pgs >= (128 *1024 )) + goal = totalram_pgs >> (22 -PAGE_SHIFT );else - goal = totalram_pages >> (24 -PAGE_SHIFT ); + goal = totalram_pgs >> (24 -PAGE_SHIFT );/* Then compute the page order for said goal */ order =get_order (goal);Signature · 1 line
1.9.1
Signature · 2 lines
Michal Hocko SUSE Labs
Re: [PATCH v2 1/4] mm: Fix multiple evaluvations of totalram_pages and managed_pages
Quoted 1 line · Michal Hocko
On Tue 06-11-18 21:51:47, Arun KS wrote:
Hi,
there's typo in subject: evaluvations -> evaluations.
However, "fix" is also misleading (more below), so I'd suggest something like:
mm: reference totalram_pages and managed_pages once per function
Quoted 4 lines
Quoted 3 lines
This patch is in preparation to a later patch which converts
totalram_pagesandzone->managed_pagesto atomic variables. This patch does not introduce any functional changes.
Quoted 9 lines
I forgot to comment on this one. The patch makes a lot of sense. But I would be little bit more conservative and won't claim "no functional changes". As things stand now multiple reads in the same function are racy (without holding the lock). I do not see any example of an obviously harmful case but claiming the above is too strong of a statement. I would simply go with something like "Please note that re-reading the value might lead to a different value and as such it could lead to unexpected behavior. There are no known bugs as a result of the current code but it is better to prevent from them in principle."
However, the new code doesn't use READ_ONCE(), so the compiler is free to read the value multiple times, and before the patch it was free to read it just once, as the variables are not volatile. So strictly speaking this is indeed not a functional change (if compiler decides differently based on the patch, it's an implementation detail).
So even in my suggested subject above, 'reference' is meant as a source code reference, not really a memory read reference. Couldn't think of a better word though.
Michal Hocko
reviewerRe: [PATCH v2 1/4] mm: Fix multiple evaluvations of totalram_pages and managed_pages
Quoted 26 lines · Vlastimil Babka
Quoted 1 line · Michal Hocko
On Tue 06-11-18 21:51:47, Arun KS wrote:
Hi,
there's typo in subject: evaluvations -> evaluations.
However, "fix" is also misleading (more below), so I'd suggest something like:
mm: reference
totalram_pagesandmanaged_pagesonce per functionQuoted 4 lines
Quoted 3 lines
This patch is in preparation to a later patch which converts
totalram_pagesandzone->managed_pagesto atomic variables. This patch does not introduce any functional changes.Quoted 9 lines
I forgot to comment on this one. The patch makes a lot of sense. But I would be little bit more conservative and won't claim "no functional changes". As things stand now multiple reads in the same function are racy (without holding the lock). I do not see any example of an obviously harmful case but claiming the above is too strong of a statement. I would simply go with something like "Please note that re-reading the value might lead to a different value and as such it could lead to unexpected behavior. There are no known bugs as a result of the current code but it is better to prevent from them in principle."
Quoted 5 lines
However, the new code doesn't use
READ_ONCE(), so the compiler is free to read the value multiple times, and before the patch it was free to read it just once, as the variables are not volatile. So strictly speaking this is indeed not a functional change (if compiler decides differently based on the patch, it's an implementation detail).
Yes, compiler is allowed to optimize this either way without READ_ONCE but it is allowed to do two reads so claiming no functional change is a bit problematic. Not that this would be a reason to discuss this in length...
Signature · 2 lines
Michal Hocko SUSE Labs
kbuild test robot
build botRe: [PATCH v2 1/4] mm: Fix multiple evaluvations of totalram_pages and managed_pages
In reply to Arun KSThank you for the patch! Perhaps something to improve:
Hi Arun,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v4.20-rc1 next-20181107]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Arun-KS/mm-Fix-multiple-evaluvations-of-totalram_pages-and-managed_pages/20181108-025657
config: i386-randconfig-x014-201844 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0 reproduce:
# save the attached .config to linux build tree
make ARCH=i386 All warnings (new ones prefixed by >>):
In file included from include/linux/export.h:45:0,
from include/linux/linkage.h:7,
from include/linux/kernel.h:7,
from include/linux/list.h:9,
from include/linux/module.h:9,
from net/sctp/protocol.c:44:
net/sctp/protocol.c: In function 'sctp_init':
net/sctp/protocol.c:1430:6: error: 'totalram_pgs' undeclared (first use in this function); did you mean 'totalram_pages'?
if (totalram_pgs >= (128 * 1024))
^
include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^~~~
>> net/sctp/protocol.c:1430:2: note: in expansion of macro 'if'
if (totalram_pgs >= (128 * 1024))
^~
net/sctp/protocol.c:1430:6: note: each undeclared identifier is reported only once for each function it appears in
if (totalram_pgs >= (128 * 1024))
^
include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^~~~
>> net/sctp/protocol.c:1430:2: note: in expansion of macro 'if'
if (totalram_pgs >= (128 * 1024))
^~
net/sctp/protocol.c:1371:16: warning: unused variable 'totalram_pages' [-Wunused-variable]
unsigned long totalram_pages;
^~~~~~~~~~~~~~vim +/if +1430 net/sctp/protocol.c
1363
1364 /* Initialize the universe into something sensible. */
1365 static __init int sctp_init(void)
1366 {
1367 int i;
1368 int status = -EINVAL;
1369 unsigned long goal;
1370 unsigned long limit;
1371 unsigned long totalram_pages;
1372 int max_share;
1373 int order;
1374 int num_entries;
1375 int max_entry_order;
1376
1377 sock_skb_cb_check_size(sizeof(struct sctp_ulpevent));
1378
1379 /* Allocate bind_bucket and chunk caches. */
1380 status = -ENOBUFS;
1381 sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
1382 sizeof(struct sctp_bind_bucket),
1383 0, SLAB_HWCACHE_ALIGN,
1384 NULL);
1385 if (!sctp_bucket_cachep)
1386 goto out;
1387
1388 sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
1389 sizeof(struct sctp_chunk),
1390 0, SLAB_HWCACHE_ALIGN,
1391 NULL);
1392 if (!sctp_chunk_cachep)
1393 goto err_chunk_cachep;
1394
1395 status = percpu_counter_init(&sctp_sockets_allocated, 0, GFP_KERNEL);
1396 if (status)
1397 goto err_percpu_counter_init;
1398
1399 /* Implementation specific variables. */
1400
1401 /* Initialize default stream count setup information. */
1402 sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
1403 sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
1404
1405 /* Initialize handle used for association ids. */
1406 idr_init(&sctp_assocs_id);
1407
1408 limit = nr_free_buffer_pages() / 8;
1409 limit = max(limit, 128UL);
1410 sysctl_sctp_mem[0] = limit / 4 * 3;
1411 sysctl_sctp_mem[1] = limit;
1412 sysctl_sctp_mem[2] = sysctl_sctp_mem[0] * 2;
1413
1414 /* Set per-socket limits to no more than 1/128 the pressure threshold*/
1415 limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7);
1416 max_share = min(4UL*1024*1024, limit);
1417
1418 sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */
1419 sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1);
1420 sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share);
1421
1422 sysctl_sctp_wmem[0] = SK_MEM_QUANTUM;
1423 sysctl_sctp_wmem[1] = 16*1024;
1424 sysctl_sctp_wmem[2] = max(64*1024, max_share);
1425
1426 /* Size and allocate the association hash table.
1427 * The methodology is similar to that of the tcp hash tables.
1428 * Though not identical. Start by getting a goal size
1429 */
> 1430 if (totalram_pgs >= (128 * 1024)) 1431 goal = totalram_pgs >> (22 - PAGE_SHIFT);
1432 else
1433 goal = totalram_pgs >> (24 - PAGE_SHIFT);
1434
1435 /* Then compute the page order for said goal */
1436 order = get_order(goal);
1437
1438 /* Now compute the required page order for the maximum sized table we
1439 * want to create
1440 */
1441 max_entry_order = get_order(MAX_SCTP_PORT_HASH_ENTRIES *
1442 sizeof(struct sctp_bind_hashbucket));
1443
1444 /* Limit the page order by that maximum hash table size */
1445 order = min(order, max_entry_order);
1446
1447 /* Allocate and initialize the endpoint hash table. */
1448 sctp_ep_hashsize = 64;
1449 sctp_ep_hashtable =
1450 kmalloc_array(64, sizeof(struct sctp_hashbucket), GFP_KERNEL);
1451 if (!sctp_ep_hashtable) {
1452 pr_err("Failed endpoint_hash alloc\n");
1453 status = -ENOMEM;
1454 goto err_ehash_alloc;
1455 }
1456 for (i = 0; i < sctp_ep_hashsize; i++) {
1457 rwlock_init(&sctp_ep_hashtable[i].lock);
1458 INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain);
1459 }
1460
1461 /* Allocate and initialize the SCTP port hash table.
1462 * Note that order is initalized to start at the max sized
1463 * table we want to support. If we can't get that many pages
1464 * reduce the order and try again
1465 */
1466 do {
1467 sctp_port_hashtable = (struct sctp_bind_hashbucket *)
1468 __get_free_pages(GFP_KERNEL | __GFP_NOWARN, order);
1469 } while (!sctp_port_hashtable && --order > 0);
1470
1471 if (!sctp_port_hashtable) {
1472 pr_err("Failed bind hash alloc\n");
1473 status = -ENOMEM;
1474 goto err_bhash_alloc;
1475 }
1476
1477 /* Now compute the number of entries that will fit in the
1478 * port hash space we allocated
1479 */
1480 num_entries = (1UL << order) * PAGE_SIZE /
1481 sizeof(struct sctp_bind_hashbucket);
1482
1483 /* And finish by rounding it down to the nearest power of two
1484 * this wastes some memory of course, but its needed because
1485 * the hash function operates based on the assumption that
1486 * that the number of entries is a power of two
1487 */
1488 sctp_port_hashsize = rounddown_pow_of_two(num_entries);
1489
1490 for (i = 0; i < sctp_port_hashsize; i++) {
1491 spin_lock_init(&sctp_port_hashtable[i].lock);
1492 INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
1493 }
1494
1495 status = sctp_transport_hashtable_init();
1496 if (status)
1497 goto err_thash_alloc;
1498
1499 pr_info("Hash tables configured (bind %d/%d)\n", sctp_port_hashsize,
1500 num_entries);
1501
1502 sctp_sysctl_register();
1503
1504 INIT_LIST_HEAD(&sctp_address_families);
1505 sctp_v4_pf_init();
1506 sctp_v6_pf_init();
1507 sctp_sched_ops_init();
1508
1509 status = register_pernet_subsys(&sctp_defaults_ops);
1510 if (status)
1511 goto err_register_defaults;
1512
1513 status = sctp_v4_protosw_init();
1514 if (status)
1515 goto err_protosw_init;
1516
1517 status = sctp_v6_protosw_init();
1518 if (status)
1519 goto err_v6_protosw_init;
1520
1521 status = register_pernet_subsys(&sctp_ctrlsock_ops);
1522 if (status)
1523 goto err_register_ctrlsock;
1524
1525 status = sctp_v4_add_protocol();
1526 if (status)
1527 goto err_add_protocol;
1528
1529 /* Register SCTP with inet6 layer. */
1530 status = sctp_v6_add_protocol();
1531 if (status)
1532 goto err_v6_add_protocol;
1533
1534 if (sctp_offload_init() < 0)
1535 pr_crit("%s: Cannot add SCTP protocol offload\n", __func__);
1536
1537 out:
1538 return status;
1539 err_v6_add_protocol:
1540 sctp_v4_del_protocol();
1541 err_add_protocol:
1542 unregister_pernet_subsys(&sctp_ctrlsock_ops);
1543 err_register_ctrlsock:
1544 sctp_v6_protosw_exit();
1545 err_v6_protosw_init:
1546 sctp_v4_protosw_exit();
1547 err_protosw_init:
1548 unregister_pernet_subsys(&sctp_defaults_ops);
1549 err_register_defaults:
1550 sctp_v4_pf_exit();
1551 sctp_v6_pf_exit();
1552 sctp_sysctl_unregister();
1553 free_pages((unsigned long)sctp_port_hashtable,
1554 get_order(sctp_port_hashsize *
1555 sizeof(struct sctp_bind_hashbucket)));
1556 err_bhash_alloc:
1557 sctp_transport_hashtable_destroy();
1558 err_thash_alloc:
1559 kfree(sctp_ep_hashtable);
1560 err_ehash_alloc:
1561 percpu_counter_destroy(&sctp_sockets_allocated);
1562 err_percpu_counter_init:
1563 kmem_cache_destroy(sctp_chunk_cachep);
1564 err_chunk_cachep:
1565 kmem_cache_destroy(sctp_bucket_cachep);
1566 goto out;
1567 }
1568
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kbuild test robot
build botRe: [PATCH v2 1/4] mm: Fix multiple evaluvations of totalram_pages and managed_pages
In reply to Arun KSThank you for the patch! Yet something to improve:
Hi Arun,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v4.20-rc1 next-20181107]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Arun-KS/mm-Fix-multiple-evaluvations-of-totalram_pages-and-managed_pages/20181108-025657
config: i386-randconfig-x004-201844 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0 reproduce:
# save the attached .config to linux build tree
make ARCH=i386 All errors (new ones prefixed by >>):
net//sctp/protocol.c: In function 'sctp_init':
>> net//sctp/protocol.c:1430:6: error: 'totalram_pgs' undeclared (first use in this function); did you mean 'totalram_pages'?
if (totalram_pgs >= (128 * 1024))
^~~~~~~~~~~~
totalram_pages
net//sctp/protocol.c:1430:6: note: each undeclared identifier is reported only once for each function it appears in
net//sctp/protocol.c:1371:16: warning: unused variable 'totalram_pages' [-Wunused-variable]
unsigned long totalram_pages;
^~~~~~~~~~~~~~vim +1430 net//sctp/protocol.c
1363
1364 /* Initialize the universe into something sensible. */
1365 static __init int sctp_init(void)
1366 {
1367 int i;
1368 int status = -EINVAL;
1369 unsigned long goal;
1370 unsigned long limit;
1371 unsigned long totalram_pages;
1372 int max_share;
1373 int order;
1374 int num_entries;
1375 int max_entry_order;
1376
1377 sock_skb_cb_check_size(sizeof(struct sctp_ulpevent));
1378
1379 /* Allocate bind_bucket and chunk caches. */
1380 status = -ENOBUFS;
1381 sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
1382 sizeof(struct sctp_bind_bucket),
1383 0, SLAB_HWCACHE_ALIGN,
1384 NULL);
1385 if (!sctp_bucket_cachep)
1386 goto out;
1387
1388 sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
1389 sizeof(struct sctp_chunk),
1390 0, SLAB_HWCACHE_ALIGN,
1391 NULL);
1392 if (!sctp_chunk_cachep)
1393 goto err_chunk_cachep;
1394
1395 status = percpu_counter_init(&sctp_sockets_allocated, 0, GFP_KERNEL);
1396 if (status)
1397 goto err_percpu_counter_init;
1398
1399 /* Implementation specific variables. */
1400
1401 /* Initialize default stream count setup information. */
1402 sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
1403 sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
1404
1405 /* Initialize handle used for association ids. */
1406 idr_init(&sctp_assocs_id);
1407
1408 limit = nr_free_buffer_pages() / 8;
1409 limit = max(limit, 128UL);
1410 sysctl_sctp_mem[0] = limit / 4 * 3;
1411 sysctl_sctp_mem[1] = limit;
1412 sysctl_sctp_mem[2] = sysctl_sctp_mem[0] * 2;
1413
1414 /* Set per-socket limits to no more than 1/128 the pressure threshold*/
1415 limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7);
1416 max_share = min(4UL*1024*1024, limit);
1417
1418 sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */
1419 sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1);
1420 sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share);
1421
1422 sysctl_sctp_wmem[0] = SK_MEM_QUANTUM;
1423 sysctl_sctp_wmem[1] = 16*1024;
1424 sysctl_sctp_wmem[2] = max(64*1024, max_share);
1425
1426 /* Size and allocate the association hash table.
1427 * The methodology is similar to that of the tcp hash tables.
1428 * Though not identical. Start by getting a goal size
1429 */
> 1430 if (totalram_pgs >= (128 * 1024)) 1431 goal = totalram_pgs >> (22 - PAGE_SHIFT);
1432 else
1433 goal = totalram_pgs >> (24 - PAGE_SHIFT);
1434
1435 /* Then compute the page order for said goal */
1436 order = get_order(goal);
1437
1438 /* Now compute the required page order for the maximum sized table we
1439 * want to create
1440 */
1441 max_entry_order = get_order(MAX_SCTP_PORT_HASH_ENTRIES *
1442 sizeof(struct sctp_bind_hashbucket));
1443
1444 /* Limit the page order by that maximum hash table size */
1445 order = min(order, max_entry_order);
1446
1447 /* Allocate and initialize the endpoint hash table. */
1448 sctp_ep_hashsize = 64;
1449 sctp_ep_hashtable =
1450 kmalloc_array(64, sizeof(struct sctp_hashbucket), GFP_KERNEL);
1451 if (!sctp_ep_hashtable) {
1452 pr_err("Failed endpoint_hash alloc\n");
1453 status = -ENOMEM;
1454 goto err_ehash_alloc;
1455 }
1456 for (i = 0; i < sctp_ep_hashsize; i++) {
1457 rwlock_init(&sctp_ep_hashtable[i].lock);
1458 INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain);
1459 }
1460
1461 /* Allocate and initialize the SCTP port hash table.
1462 * Note that order is initalized to start at the max sized
1463 * table we want to support. If we can't get that many pages
1464 * reduce the order and try again
1465 */
1466 do {
1467 sctp_port_hashtable = (struct sctp_bind_hashbucket *)
1468 __get_free_pages(GFP_KERNEL | __GFP_NOWARN, order);
1469 } while (!sctp_port_hashtable && --order > 0);
1470
1471 if (!sctp_port_hashtable) {
1472 pr_err("Failed bind hash alloc\n");
1473 status = -ENOMEM;
1474 goto err_bhash_alloc;
1475 }
1476
1477 /* Now compute the number of entries that will fit in the
1478 * port hash space we allocated
1479 */
1480 num_entries = (1UL << order) * PAGE_SIZE /
1481 sizeof(struct sctp_bind_hashbucket);
1482
1483 /* And finish by rounding it down to the nearest power of two
1484 * this wastes some memory of course, but its needed because
1485 * the hash function operates based on the assumption that
1486 * that the number of entries is a power of two
1487 */
1488 sctp_port_hashsize = rounddown_pow_of_two(num_entries);
1489
1490 for (i = 0; i < sctp_port_hashsize; i++) {
1491 spin_lock_init(&sctp_port_hashtable[i].lock);
1492 INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
1493 }
1494
1495 status = sctp_transport_hashtable_init();
1496 if (status)
1497 goto err_thash_alloc;
1498
1499 pr_info("Hash tables configured (bind %d/%d)\n", sctp_port_hashsize,
1500 num_entries);
1501
1502 sctp_sysctl_register();
1503
1504 INIT_LIST_HEAD(&sctp_address_families);
1505 sctp_v4_pf_init();
1506 sctp_v6_pf_init();
1507 sctp_sched_ops_init();
1508
1509 status = register_pernet_subsys(&sctp_defaults_ops);
1510 if (status)
1511 goto err_register_defaults;
1512
1513 status = sctp_v4_protosw_init();
1514 if (status)
1515 goto err_protosw_init;
1516
1517 status = sctp_v6_protosw_init();
1518 if (status)
1519 goto err_v6_protosw_init;
1520
1521 status = register_pernet_subsys(&sctp_ctrlsock_ops);
1522 if (status)
1523 goto err_register_ctrlsock;
1524
1525 status = sctp_v4_add_protocol();
1526 if (status)
1527 goto err_add_protocol;
1528
1529 /* Register SCTP with inet6 layer. */
1530 status = sctp_v6_add_protocol();
1531 if (status)
1532 goto err_v6_add_protocol;
1533
1534 if (sctp_offload_init() < 0)
1535 pr_crit("%s: Cannot add SCTP protocol offload\n", __func__);
1536
1537 out:
1538 return status;
1539 err_v6_add_protocol:
1540 sctp_v4_del_protocol();
1541 err_add_protocol:
1542 unregister_pernet_subsys(&sctp_ctrlsock_ops);
1543 err_register_ctrlsock:
1544 sctp_v6_protosw_exit();
1545 err_v6_protosw_init:
1546 sctp_v4_protosw_exit();
1547 err_protosw_init:
1548 unregister_pernet_subsys(&sctp_defaults_ops);
1549 err_register_defaults:
1550 sctp_v4_pf_exit();
1551 sctp_v6_pf_exit();
1552 sctp_sysctl_unregister();
1553 free_pages((unsigned long)sctp_port_hashtable,
1554 get_order(sctp_port_hashsize *
1555 sizeof(struct sctp_bind_hashbucket)));
1556 err_bhash_alloc:
1557 sctp_transport_hashtable_destroy();
1558 err_thash_alloc:
1559 kfree(sctp_ep_hashtable);
1560 err_ehash_alloc:
1561 percpu_counter_destroy(&sctp_sockets_allocated);
1562 err_percpu_counter_init:
1563 kmem_cache_destroy(sctp_chunk_cachep);
1564 err_chunk_cachep:
1565 kmem_cache_destroy(sctp_bucket_cachep);
1566 goto out;
1567 }
1568
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
PATCH v2 2/4 mm: Convert zone->managed_pages to atomic variable
In reply to Arun KStotalram_pages, zone->managed_pages and totalhigh_pages updates are protected by managed_page_count_lock, but readers never care about it. Convert these variables to atomic to avoid readers potentially seeing a store tear.
This patch converts zone->managed_pages. Subsequent patches will convert totalram_panges, totalhigh_pages and eventually managed_page_count_lock will be removed.
---
Most of the changes are done by below coccinelle script,
@@
struct zone *z;
expression e1;
@@
(
- z->managed_pages = e1
+ atomic_long_set(&z->managed_pages, e1)
|
- e1->managed_pages++
+ atomic_long_inc(&e1->managed_pages)
|
- z->managed_pages
+ zone_managed_pages(z)
)
@@
expression e,e1;
@@
- e->managed_pages += e1
+ atomic_long_add(e1, &e->managed_pages)
@@
expression z;
@@
- z.managed_pages
+ zone_managed_pages(&z)
Then, manually apply following change,include/linux/mmzone.h
- unsigned long managed_pages;
+ atomic_long_t managed_pages;
+static inline unsigned long zone_managed_pages(struct zone *zone) +{
+ return (unsigned long)atomic_long_read(&zone->managed_pages);
+}
---
--- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 2 +- include/linux/mmzone.h | 9 +++++-- lib/show_mem.c | 2 +- mm/memblock.c | 2 +- mm/page_alloc.c | 44 +++++++++++++++++------------------ mm/vmstat.c | 4 ++-- 6 files changed, 34 insertions(+), 29 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_crat.c +1 -1
@@ -848,7 +848,7 @@ static int kfd_fill_mem_info_for_cpu(int numa_node_id, int *avail_size,*/ pgdat =NODE_DATA (numa_node_id);for (zone_type =0 ; zone_type <MAX_NR_ZONES ; zone_type++) - mem_in_bytes += pgdat->node_zones[zone_type].managed_pages; + mem_in_bytes +=zone_managed_pages (&pgdat->node_zones[zone_type]); mem_in_bytes <<=PAGE_SHIFT ; sub_type_hdr->length_low =lower_32_bits (mem_in_bytes);
include/linux/mmzone.h +7 -2
@@ -435,7 +435,7 @@ struct zone {* adjust_managed_page_count() should be used instead of directly * touching zone->managed_pages and totalram_pages. */ -unsigned long managed_pages; +atomic_long_t managed_pages;unsigned long spanned_pages;unsigned long present_pages;
@@ -524,6 +524,11 @@ enum pgdat_flags { PGDAT_RECLAIM_LOCKED, /* prevents concurrent reclaim */ }; +static inline unsigned long zone_managed_pages (struct zone *zone) +{ +return (unsigned long )atomic_long_read (&zone->managed_pages); +} +static inline unsigned long zone_end_pfn (const struct zone *zone) {return zone->zone_start_pfn + zone->spanned_pages;
@@ -814,7 +819,7 @@ static inline bool is_dev_zone(const struct zone *zone)*/ static inline bool managed_zone (struct zone *zone) { -return zone->managed_pages; +return zone_managed_pages (zone); }/* Returns true if a zone has memory */
lib/show_mem.c +1 -1
@@ -28,7 +28,7 @@ void show_mem(unsigned int filter, nodemask_t *nodemask)continue ; total += zone->present_pages; - reserved += zone->present_pages - zone->managed_pages; + reserved += zone->present_pages -zone_managed_pages (zone);if (is_highmem_idx (zoneid)) highmem += zone->present_pages;
mm/memblock.c +1 -1
@@ -1950,7 +1950,7 @@ void reset_node_managed_pages(pg_data_t *pgdat)struct zone *z;for (z = pgdat->node_zones; z < pgdat->node_zones +MAX_NR_ZONES ; z++) - z->managed_pages =0 ; +atomic_long_set (&z->managed_pages,0 ); }void __init reset_all_zones_managed_pages (void )
mm/page_alloc.c +22 -22
164 lines not on this page · raw message
mm/vmstat.c +2 -2
@@ -227,7 +227,7 @@ int calculate_normal_threshold(struct zone *zone)* 125 1024 10 16-32 GB 9 */ - mem = zone->managed_pages >> (27 -PAGE_SHIFT ); + mem =zone_managed_pages (zone) >> (27 -PAGE_SHIFT ); threshold =2 *fls (num_online_cpus ()) * (1 +fls (mem));
@@ -1569,7 +1569,7 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,high_wmark_pages (zone), zone->spanned_pages, zone->present_pages, - zone->managed_pages); + zone_managed_pages(zone)); seq_printf(m, "\n protection: (%ld",
Signature · 1 line
1.9.1
Re: [PATCH v2 2/4] mm: Convert zone->managed_pages to atomic variable
Quoted 9 lines · Arun KS
totalram_pages,zone->managed_pagesandtotalhigh_pagesupdates are protected bymanaged_page_count_lock, but readers never care about it. Convert these variables to atomic to avoid readers potentially seeing a store tear.This patch converts
zone->managed_pages. Subsequent patches will converttotalram_panges,totalhigh_pagesand eventuallymanaged_page_count_lockwill be removed.
Quoted 5 lines
Suggested-by Michal Hocko <[email protected]>Suggested-by Vlastimil Babka <[email protected]>Signed-off-by Arun KS <[email protected]>Reviewed-by Konstantin Khlebnikov <[email protected]>Acked-by Michal Hocko <[email protected]>
PATCH v2 3/4 mm: convert totalram_pages and totalhigh_pages variables to atomic
In reply to Arun KStotalram_pages and totalhigh_pages are made static inline function.
---
coccinelle script to make most of the changes,
@@
declarer name EXPORT_SYMBOL;
symbol totalram_pages;
expression e;
@@
(EXPORT_SYMBOL(totalram_pages);
|
- totalram_pages = e
+ totalram_pages_set(e)
|
- totalram_pages += e
+ totalram_pages_add(e)
|
- totalram_pages++
+ totalram_pages_inc()
|
- totalram_pages--
+ totalram_pages_dec()
|
- totalram_pages
+ totalram_pages()
)
@@
symbol totalhigh_pages;
expression e;
@@
(EXPORT_SYMBOL(totalhigh_pages);
|
- totalhigh_pages = e
+ totalhigh_pages_set(e)
|
- totalhigh_pages += e
+ totalhigh_pages_add(e)
|
- totalhigh_pages++
+ totalhigh_pages_inc()
|
- totalhigh_pages--
+ totalhigh_pages_dec()
|
- totalhigh_pages
+ totalhigh_pages()
)
Manaually apply all changes of following files,
include/linux/highmem.hinclude/linux/mm.hinclude/linux/swap.hmm/highmem.c
and for mm/page_alloc.c mannualy apply only below changes,
#include <linux/stddef.h>
#include <linux/mm.h>
+#include <linux/highmem.h>
#include <linux/swap.h>
#include <linux/interrupt.h>
#include <linux/pagemap.h>
/* Protect totalram_pages and zone->managed_pages */ static DEFINE_SPINLOCK(managed_page_count_lock);
-unsigned long totalram_pages __read_mostly;
+atomic_long_t _totalram_pages __read_mostly;
unsigned long totalreserve_pages __read_mostly;
unsigned long totalcma_pages __read_mostly;
---
--- arch/csky/mm/init.c | 4 ++-- arch/powerpc/platforms/pseries/cmm.c | 10 +++++----- arch/s390/mm/init.c | 2 +- arch/um/kernel/mem.c | 2 +- arch/x86/kernel/cpu/microcode/core.c | 2 +- drivers/char/agp/backend.c | 4 ++-- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 4 ++-- drivers/hv/hv_balloon.c | 2 +- drivers/md/dm-bufio.c | 2 +- drivers/md/dm-crypt.c | 2 +- drivers/md/dm-integrity.c | 2 +- drivers/md/dm-stats.c | 2 +- drivers/media/platform/mtk-vpu/mtk_vpu.c | 2 +- drivers/misc/vmw_balloon.c | 2 +- drivers/parisc/ccio-dma.c | 4 ++-- drivers/parisc/sba_iommu.c | 4 ++-- drivers/staging/android/ion/ion_system_heap.c | 2 +- drivers/xen/xen-selfballoon.c | 6 +++--- fs/ceph/super.h | 2 +- fs/file_table.c | 2 +- fs/fuse/inode.c | 2 +- fs/nfs/write.c | 2 +- fs/nfsd/nfscache.c | 2 +- fs/ntfs/malloc.h | 2 +- fs/proc/base.c | 2 +- include/linux/highmem.h | 28 +++++++++++++++++++++++++-- include/linux/mm.h | 27 +++++++++++++++++++++++++- include/linux/swap.h | 1 - kernel/fork.c | 2 +- kernel/kexec_core.c | 2 +- kernel/power/snapshot.c | 2 +- mm/highmem.c | 4 +--- mm/huge_memory.c | 2 +- mm/kasan/quarantine.c | 2 +- mm/memblock.c | 4 ++-- mm/mm_init.c | 2 +- mm/oom_kill.c | 2 +- mm/page_alloc.c | 19 +++++++++--------- mm/shmem.c | 8 ++++---- mm/slab.c | 2 +- mm/swap.c | 2 +- mm/util.c | 2 +- mm/vmalloc.c | 4 ++-- mm/workingset.c | 2 +- mm/zswap.c | 4 ++-- net/dccp/proto.c | 2 +- net/decnet/dn_route.c | 2 +- net/ipv4/tcp_metrics.c | 2 +- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/xt_hashlimit.c | 2 +- security/integrity/ima/ima_kexec.c | 2 +- 52 files changed, 127 insertions(+), 80 deletions(-)
arch/csky/mm/init.c +2 -2
@@ -71,7 +71,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)ClearPageReserved (virt_to_page (start));init_page_count (virt_to_page (start));free_page (start); - totalram_pages++; + totalram_pages_inc(); } }#endif
@@ -88,7 +88,7 @@ void free_initmem(void)ClearPageReserved (virt_to_page (addr));init_page_count (virt_to_page (addr));free_page (addr); - totalram_pages++; +totalram_pages_inc (); addr +=PAGE_SIZE ; }
arch/powerpc/platforms/pseries/cmm.c +5 -5
@@ -208,7 +208,7 @@ static long cmm_alloc_pages(long nr) pa->page[pa->index++] = addr; loaned_pages++; - totalram_pages--; +totalram_pages_dec ();spin_unlock (&cmm_lock); nr--; }
@@ -247,7 +247,7 @@ static long cmm_free_pages(long nr)free_page (addr); loaned_pages--; nr--; - totalram_pages++; +totalram_pages_inc (); }spin_unlock (&cmm_lock);cmm_dbg ("End request with %ld pages unfulfilled\n" , nr);
@@ -291,7 +291,7 @@ static void cmm_get_mpp(void)int rc;struct hvcall_mpp_data mpp_data;signed long active_pages_target, page_loan_request, target; -signed long total_pages = totalram_pages + loaned_pages; +signed long total_pages =totalram_pages () + loaned_pages;signed long min_mem_pages = (min_mem_mb *1024 *1024 ) /PAGE_SIZE ; rc =h_get_mpp (&mpp_data);
@@ -322,7 +322,7 @@ static void cmm_get_mpp(void)cmm_dbg ("delta = %ld, loaned = %lu, target = %lu, oom = %lu, totalram = %lu\n" , page_loan_request, loaned_pages, loaned_pages_target, - oom_freed_pages, totalram_pages); + oom_freed_pages,totalram_pages ()); }static struct notifier_block cmm_oom_nb = {
@@ -581,7 +581,7 @@ static int cmm_mem_going_offline(void *arg)free_page (pa_curr->page[idx]); freed++; loaned_pages--; - totalram_pages++; +totalram_pages_inc (); pa_curr->page[idx] = pa_last->page[--pa_last->index];if (pa_last->index ==0 ) {if (pa_curr == pa_last)
arch/s390/mm/init.c +1 -1
@@ -59,7 +59,7 @@ static void __init setup_zero_pages(void) order =7 ;/* Limit number of empty zero pages for small memory sizes */ -while (order >2 && (totalram_pages >>10 ) < (1UL << order)) +while (order >2 && (totalram_pages () >>10 ) < (1UL << order)) order--; empty_zero_page =__get_free_pages (GFP_KERNEL | __GFP_ZERO, order);
arch/um/kernel/mem.c +1 -1
@@ -51,7 +51,7 @@ void __init mem_init(void)/* this will put all low memory onto the freelists */ memblock_free_all (); - max_pfn = max_low_pfn = totalram_pages; + max_pfn = max_low_pfn =totalram_pages ();mem_init_print_info (NULL ); kmalloc_ok =1 ; }
arch/x86/kernel/cpu/microcode/core.c +1 -1
@@ -434,7 +434,7 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { ssize_t ret = -EINVAL; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();if ((len >>PAGE_SHIFT ) > totalram_pgs) {pr_err ("too much data (max %ld pages)\n" , totalram_pgs);
drivers/char/agp/backend.c +2 -2
@@ -115,9 +115,9 @@ static int agp_find_max(void)long memory, index, result;#if PAGE_SHIFT <20 - memory = totalram_pages >> (20 -PAGE_SHIFT ); + memory =totalram_pages () >> (20 -PAGE_SHIFT );#else - memory = totalram_pages << (PAGE_SHIFT -20 ); + memory =totalram_pages () << (PAGE_SHIFT -20 );#endif index =1 ;
drivers/gpu/drm/i915/i915_gem.c +1 -1
@@ -2539,7 +2539,7 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)* If there's no chance of allocating enough pages for the whole * object, bail early. */ -if (page_count > totalram_pages) +if (page_count >totalram_pages ())return -ENOMEM ; st =kmalloc (sizeof (*st),GFP_KERNEL );
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +2 -2
@@ -170,7 +170,7 @@ static int igt_ppgtt_alloc(void *arg)* This should ensure that we do not run into the oomkiller during * the test and take down the machine wilfully. */ - limit = totalram_pages <<PAGE_SHIFT ; + limit =totalram_pages () <<PAGE_SHIFT ; limit =min (ppgtt->vm.total, limit);/* Check we can allocate the entire range */
@@ -1244,7 +1244,7 @@ static int exercise_mock(struct drm_i915_private *i915, u64 hole_start, u64 hole_end, unsigned long end_time)) { - const u64 limit = totalram_pages << PAGE_SHIFT; + const u64 limit = totalram_pages() << PAGE_SHIFT;struct i915_gem_context *ctx;struct i915_hw_ppgtt *ppgtt;IGT_TIMEOUT (end_time);
drivers/hv/hv_balloon.c +1 -1
@@ -1090,7 +1090,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)static unsigned long compute_balloon_floor (void ) {unsigned long min_pages; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();#define MB2PAGES (mb) ((mb) << (20 - PAGE_SHIFT))/* Simple continuous piecewiese linear function: * max MiB -> min MiB gradient
drivers/md/dm-bufio.c +1 -1
@@ -1887,7 +1887,7 @@ static int __init dm_bufio_init(void) dm_bufio_allocated_vmalloc =0 ; dm_bufio_current_allocated =0 ; - mem = (__u64 )mult_frac (totalram_pages - totalhigh_pages, + mem = (__u64 )mult_frac (totalram_pages () -totalhigh_pages (),DM_BUFIO_MEMORY_PERCENT ,100 ) <<PAGE_SHIFT ;if (mem >ULONG_MAX )
drivers/md/dm-crypt.c +1 -1
@@ -2158,7 +2158,7 @@ static int crypt_wipe_key(struct crypt_config *cc)static void crypt_calculate_pages_per_client (void ) { -unsigned long pages = (totalram_pages - totalhigh_pages) *DM_CRYPT_MEMORY_PERCENT /100 ; +unsigned long pages = (totalram_pages () -totalhigh_pages ()) *DM_CRYPT_MEMORY_PERCENT /100 ;if (!dm_crypt_clients_n)return ;
drivers/md/dm-integrity.c +1 -1
@@ -2843,7 +2843,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error) journal_pages =roundup ((__u64 )ic->journal_sections * ic->journal_section_sectors,PAGE_SIZE >>SECTOR_SHIFT ) >> (PAGE_SHIFT -SECTOR_SHIFT ); journal_desc_size = journal_pages *sizeof (struct page_list ); -if (journal_pages >= totalram_pages - totalhigh_pages || journal_desc_size >ULONG_MAX ) { +if (journal_pages >=totalram_pages () -totalhigh_pages () || journal_desc_size >ULONG_MAX ) { *error ="Journal doesn't fit into memory" ; r = -ENOMEM ; goto bad;
drivers/md/dm-stats.c +1 -1
@@ -85,7 +85,7 @@ static bool __check_shared_memory(size_t alloc_size) a = shared_memory_amount + alloc_size;if (a < shared_memory_amount)return false; -if (a >>PAGE_SHIFT > totalram_pages /DM_STATS_MEMORY_FACTOR ) +if (a >>PAGE_SHIFT >totalram_pages () /DM_STATS_MEMORY_FACTOR )return false;#ifdef CONFIG_MMU if (a > (VMALLOC_END -VMALLOC_START ) /DM_STATS_VMALLOC_FACTOR )
drivers/media/platform/mtk-vpu/mtk_vpu.c +1 -1
@@ -855,7 +855,7 @@ static int mtk_vpu_probe(struct platform_device *pdev)/* Set PTCM to 96K and DTCM to 32K */ vpu_cfg_writel (vpu,0x2 ,VPU_TCM_CFG ); - vpu->enable_4GB = !!(totalram_pages > (SZ_2G >>PAGE_SHIFT )); + vpu->enable_4GB = !!(totalram_pages () > (SZ_2G >>PAGE_SHIFT ));dev_info (dev,"4GB mode %u\n" , vpu->enable_4GB);if (vpu->enable_4GB) {
drivers/misc/vmw_balloon.c +1 -1
@@ -570,7 +570,7 @@ static int vmballoon_send_get_target(struct vmballoon *b)unsigned long status;unsigned long limit; - limit = totalram_pages; + limit =totalram_pages ();/* Ensure limit fits in 32-bits */ if (limit != (u32 )limit)
drivers/parisc/ccio-dma.c +2 -2
@@ -1251,7 +1251,7 @@ void __init ccio_cujo20_fixup(struct parisc_device *cujo, u32 iovp)** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). */ - iova_space_size = (u32) (totalram_pages /count_parisc_driver (&ccio_driver)); + iova_space_size = (u32) (totalram_pages () /count_parisc_driver (&ccio_driver));/* limit IOVA space size to 1MB-1GB */
@@ -1290,7 +1290,7 @@ void __init ccio_cujo20_fixup(struct parisc_device *cujo, u32 iovp)DBG_INIT ("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n" , __func__, ioc->ioc_regs, - (unsigned long ) totalram_pages >> (20 -PAGE_SHIFT ), + (unsigned long )totalram_pages () >> (20 -PAGE_SHIFT ), iova_space_size>>20 , iov_order +PAGE_SHIFT );
drivers/parisc/sba_iommu.c +2 -2
@@ -1414,7 +1414,7 @@ static int setup_ibase_imask_callback(struct device *dev, void *data)** for DMA hints - ergo only 30 bits max. */ - iova_space_size = (u32) (totalram_pages/global_ioc_cnt); + iova_space_size = (u32) (totalram_pages ()/global_ioc_cnt);/* limit IOVA space size to 1MB-1GB */ if (iova_space_size < (1 << (20 -PAGE_SHIFT ))) {
@@ -1439,7 +1439,7 @@ static int setup_ibase_imask_callback(struct device *dev, void *data)DBG_INIT ("%s() hpa 0x%lx mem %ldMB IOV %dMB (%d bits)\n" , __func__, ioc->ioc_hpa, - (unsigned long ) totalram_pages >> (20 -PAGE_SHIFT ), + (unsigned long )totalram_pages () >> (20 -PAGE_SHIFT ), iova_space_size>>20 , iov_order +PAGE_SHIFT );
drivers/staging/android/ion/ion_system_heap.c +1 -1
@@ -110,7 +110,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,unsigned long size_remaining =PAGE_ALIGN (size);unsigned int max_order = orders[0 ]; -if (size /PAGE_SIZE > totalram_pages /2 ) +if (size /PAGE_SIZE >totalram_pages () /2 )return -ENOMEM ;INIT_LIST_HEAD (&pages);
drivers/xen/xen-selfballoon.c +3 -3
@@ -189,7 +189,7 @@ static void selfballoon_process(struct work_struct *work)bool reset_timer = false;if (xen_selfballooning_enabled) { - cur_pages = totalram_pages; + cur_pages =totalram_pages (); tgt_pages = cur_pages;/* default is no change */ goal_pages =vm_memory_committed () + totalreserve_pages +
@@ -227,7 +227,7 @@ static void selfballoon_process(struct work_struct *work)if (tgt_pages < floor_pages) tgt_pages = floor_pages;balloon_set_new_target (tgt_pages + - balloon_stats.current_pages - totalram_pages); + balloon_stats.current_pages -totalram_pages ()); reset_timer = true; }#ifdef CONFIG_FRONTSWAP
@@ -569,7 +569,7 @@ int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)* much more reliably and response faster in some cases. */ if (!selfballoon_reserved_mb) { - reserve_pages = totalram_pages /10 ; + reserve_pages =totalram_pages () /10 ; selfballoon_reserved_mb =PAGES2MB (reserve_pages); }schedule_delayed_work (&selfballoon_worker, selfballoon_interval *HZ );
fs/ceph/super.h +1 -1
@@ -808,7 +808,7 @@ static inline int default_congestion_kb(void)* This allows larger machines to have larger/more transfers. * Limit the default to 256M */ - congestion_kb = (16 *int_sqrt (totalram_pages)) << (PAGE_SHIFT -10 ); + congestion_kb = (16 *int_sqrt (totalram_pages ())) << (PAGE_SHIFT -10 );if (congestion_kb >256 *1024 ) congestion_kb =256 *1024 ;
fs/file_table.c +1 -1
@@ -380,7 +380,7 @@ void __init files_init(void)void __init files_maxfiles_init (void ) {unsigned long n; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();unsigned long memreserve = (totalram_pgs -nr_free_pages ()) *3 /2 ; memreserve =min (memreserve, totalram_pgs -1 );
fs/fuse/inode.c +1 -1
@@ -824,7 +824,7 @@ static struct dentry *fuse_get_parent(struct dentry *child)static void sanitize_global_limit (unsigned *limit) {if (*limit ==0 ) - *limit = ((totalram_pages <<PAGE_SHIFT ) >>13 ) / + *limit = ((totalram_pages () <<PAGE_SHIFT ) >>13 ) /sizeof (struct fuse_req );if (*limit >=1 <<16 )
fs/nfs/write.c +1 -1
@@ -2121,7 +2121,7 @@ int __init nfs_init_writepagecache(void)* This allows larger machines to have larger/more transfers. * Limit the default to 256M */ - nfs_congestion_kb = (16 *int_sqrt (totalram_pages)) << (PAGE_SHIFT -10 ); + nfs_congestion_kb = (16 *int_sqrt (totalram_pages ())) << (PAGE_SHIFT -10 );if (nfs_congestion_kb >256 *1024 ) nfs_congestion_kb =256 *1024 ;
fs/nfsd/nfscache.c +1 -1
@@ -99,7 +99,7 @@ static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink,nfsd_cache_size_limit (void) {unsigned int limit; -unsigned long low_pages = totalram_pages - totalhigh_pages; +unsigned long low_pages =totalram_pages () -totalhigh_pages (); limit = (16 *int_sqrt (low_pages)) << (PAGE_SHIFT -10 ); return min_t(unsigned int, limit, 256*1024);
fs/ntfs/malloc.h +1 -1
@@ -47,7 +47,7 @@ static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask)return kmalloc (PAGE_SIZE , gfp_mask & ~__GFP_HIGHMEM);/* return (void *)__get_free_page(gfp_mask); */ } -if (likely ((size >>PAGE_SHIFT ) < totalram_pages)) +if (likely ((size >>PAGE_SHIFT ) <totalram_pages ()))return __vmalloc (size, gfp_mask,PAGE_KERNEL );return NULL ; }
fs/proc/base.c +1 -1
@@ -530,7 +530,7 @@ static ssize_t lstats_write(struct file *file, const char __user *buf,static int proc_oom_score (struct seq_file *m,struct pid_namespace *ns,struct pid *pid,struct task_struct *task) { -unsigned long totalpages = totalram_pages + total_swap_pages; +unsigned long totalpages =totalram_pages () + total_swap_pages;unsigned long points =0 ; points = oom_badness(task, NULL, NULL, totalpages) *
include/linux/highmem.h +26 -2
@@ -36,7 +36,31 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size)/* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages (void ); -extern unsigned long totalhigh_pages; +extern atomic_long_t _totalhigh_pages; +static inline unsigned long totalhigh_pages (void ) +{ +return (unsigned long )atomic_long_read (&_totalhigh_pages); +} + +static inline void totalhigh_pages_inc (void ) +{ +atomic_long_inc (&_totalhigh_pages); +} + +static inline void totalhigh_pages_dec (void ) +{ +atomic_long_dec (&_totalhigh_pages); +} + +static inline void totalhigh_pages_add (long count) +{ +atomic_long_add (count, &_totalhigh_pages); +} + +static inline void totalhigh_pages_set (long val) +{ +atomic_long_set (&_totalhigh_pages, val); +}void kmap_flush_unused (void );
@@ -51,7 +75,7 @@ static inline struct page *kmap_to_page(void *addr)return virt_to_page (addr); } -#define totalhigh_pages 0UL +static inline unsigned long totalhigh_pages (void ) {return 0UL ; }#ifndef ARCH_HAS_KMAP static inline void *kmap (struct page *page)
include/linux/mm.h +26 -1
@@ -48,7 +48,32 @@ static inline void set_max_mapnr(unsigned long limit)static inline void set_max_mapnr (unsigned long limit) { }#endif -extern unsigned long totalram_pages; +extern atomic_long_t _totalram_pages; +static inline unsigned long totalram_pages (void ) +{ +return (unsigned long )atomic_long_read (&_totalram_pages); +} + +static inline void totalram_pages_inc (void ) +{ +atomic_long_inc (&_totalram_pages); +} + +static inline void totalram_pages_dec (void ) +{ +atomic_long_dec (&_totalram_pages); +} + +static inline void totalram_pages_add (long count) +{ +atomic_long_add (count, &_totalram_pages); +} + +static inline void totalram_pages_set (long val) +{ +atomic_long_set (&_totalram_pages, val); +} +extern void * high_memory;extern int page_cluster;
include/linux/swap.h +0 -1
@@ -308,7 +308,6 @@ struct vma_swap_readahead { }while (0 )/* linux/mm/page_alloc.c */ -extern unsigned long totalram_pages; extern unsigned long totalreserve_pages;extern unsigned long nr_free_buffer_pages (void );extern unsigned long nr_free_pagecache_pages (void );
kernel/fork.c +1 -1
@@ -739,7 +739,7 @@ void __init __weak arch_task_cache_init(void) { }static void set_max_threads (unsigned int max_threads_suggested) {u64 threads; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();/* * The number of threads shall be limited such that the thread
kernel/kexec_core.c +1 -1
@@ -152,7 +152,7 @@ int sanity_check_segment_list(struct kimage *image)int i;unsigned long nr_segments = image->nr_segments;unsigned long total_pages =0 ; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();/* * Verify we have good destination addresses. The caller is
kernel/power/snapshot.c +1 -1
@@ -105,7 +105,7 @@ void __init hibernate_reserved_size_init(void)void __init hibernate_image_size_init (void ) { - image_size = ((totalram_pages *2 ) /5 ) *PAGE_SIZE ; + image_size = ((totalram_pages () *2 ) /5 ) *PAGE_SIZE ; }/*
mm/highmem.c +1 -3
@@ -105,9 +105,7 @@ static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) }#endif -unsigned long totalhigh_pages__read_mostly ; -EXPORT_SYMBOL (totalhigh_pages); - +atomic_long_t _totalhigh_pages__read_mostly ;EXPORT_PER_CPU_SYMBOL (__kmap_atomic_idx);
mm/huge_memory.c +1 -1
@@ -420,7 +420,7 @@ static int __init hugepage_init(void)* where the extra memory used could hurt more than TLB overhead * is likely to save. The admin can still enable it through /sys. */ -if (totalram_pages < (512 << (20 -PAGE_SHIFT ))) { +if (totalram_pages () < (512 << (20 -PAGE_SHIFT ))) { transparent_hugepage_flags =0 ;return 0 ; }
mm/kasan/quarantine.c +1 -1
@@ -236,7 +236,7 @@ void quarantine_reduce(void)* Update quarantine size in case of hotplug. Allocate a fraction of * the installed memory to quarantine minus per-cpu queue limits. */ - total_size = (READ_ONCE (totalram_pages) <<PAGE_SHIFT ) / + total_size = (READ_ONCE (totalram_pages ()) <<PAGE_SHIFT ) /QUARANTINE_FRACTION ; percpu_quarantines =QUARANTINE_PERCPU_SIZE *num_online_cpus (); new_quarantine_size = (total_size < percpu_quarantines) ?
mm/memblock.c +2 -2
@@ -1576,7 +1576,7 @@ void __init __memblock_free_late(phys_addr_t base, phys_addr_t size)for (; cursor < end; cursor++) {memblock_free_pages (pfn_to_page (cursor), cursor,0 ); - totalram_pages++; +totalram_pages_inc (); } }
@@ -1978,7 +1978,7 @@ unsigned long __init memblock_free_all(void)reset_all_zones_managed_pages (); pages =free_low_memory_core_early (); - totalram_pages += pages; +totalram_pages_add (pages);return pages; }
mm/mm_init.c +1 -1
@@ -146,7 +146,7 @@ static void __meminit mm_compute_batch(void)s32 batch =max_t (s32, nr*2 ,32 );/* batch size set to 0.4% of (total memory/#cpus), or max int32 */ - memsized_batch =min_t (u64, (totalram_pages/nr)/256 ,0x7fffffff ); + memsized_batch =min_t (u64, (totalram_pages ()/nr)/256 ,0x7fffffff ); vm_committed_as_batch =max_t (s32, memsized_batch, batch); }
mm/oom_kill.c +1 -1
@@ -269,7 +269,7 @@ static enum oom_constraint constrained_alloc(struct oom_control *oc) }/* Default to all available memory */ - oc->totalpages = totalram_pages + total_swap_pages; + oc->totalpages =totalram_pages () + total_swap_pages;if (!IS_ENABLED (CONFIG_NUMA ))return CONSTRAINT_NONE ;
mm/page_alloc.c +10 -9
@@ -16,6 +16,7 @@#include <linux/stddef.h> #include <linux/mm.h> +#include <linux/highmem.h> #include <linux/swap.h> #include <linux/interrupt.h> #include <linux/pagemap.h>
@@ -124,7 +125,7 @@/* Protect totalram_pages and zone->managed_pages */ static DEFINE_SPINLOCK (managed_page_count_lock); -unsigned long totalram_pages__read_mostly ; +atomic_long_t _totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;unsigned long totalcma_pages__read_mostly ;
@@ -4748,11 +4749,11 @@ long si_mem_available(void)void si_meminfo (struct sysinfo *val) { - val->totalram = totalram_pages; + val->totalram =totalram_pages (); val->sharedram =global_node_page_state (NR_SHMEM ); val->freeram =global_zone_page_state (NR_FREE_PAGES ); val->bufferram =nr_blockdev_pages (); - val->totalhigh = totalhigh_pages; + val->totalhigh =totalhigh_pages (); val->freehigh =nr_free_highpages (); val->mem_unit =PAGE_SIZE ; }
@@ -7065,10 +7066,10 @@ void adjust_managed_page_count(struct page *page, long count) {spin_lock (&managed_page_count_lock);atomic_long_add (count, &page_zone (page)->managed_pages); - totalram_pages += count; +totalram_pages_add (count);#ifdef CONFIG_HIGHMEM if (PageHighMem (page)) - totalhigh_pages += count; +totalhigh_pages_add (count);#endif spin_unlock (&managed_page_count_lock); }
@@ -7111,9 +7112,9 @@ unsigned long free_reserved_area(void *start, void *end, int poison, char *s)void free_highmem_page (struct page *page) {__free_reserved_page (page); - totalram_pages++; +totalram_pages_inc ();atomic_long_inc (&page_zone (page)->managed_pages); - totalhigh_pages++; +totalhigh_pages_inc (); }#endif
@@ -7162,10 +7163,10 @@ void __init mem_init_print_info(const char *str) physpages << (PAGE_SHIFT -10 ), codesize >>10 , datasize >>10 , rosize >>10 , (init_data_size + init_code_size) >>10 , bss_size >>10 , - (physpages - totalram_pages - totalcma_pages) << (PAGE_SHIFT -10 ), + (physpages -totalram_pages () - totalcma_pages) << (PAGE_SHIFT -10 ), totalcma_pages << (PAGE_SHIFT -10 ), #ifdef CONFIG_HIGHMEM - totalhigh_pages << (PAGE_SHIFT -10 ), +totalhigh_pages () << (PAGE_SHIFT -10 ), #endif str ? ", " : "", str ? str : ""); }
mm/shmem.c +4 -4
@@ -109,13 +109,13 @@ struct shmem_falloc {#ifdef CONFIG_TMPFS static unsigned long shmem_default_max_blocks (void ) { -return totalram_pages /2 ; +return totalram_pages () /2 ; }static unsigned long shmem_default_max_inodes (void ) { -unsigned long totalram_pgs = totalram_pages; -return min (totalram_pgs - totalhigh_pages, totalram_pgs /2 ); +unsigned long totalram_pgs =totalram_pages (); +return min (totalram_pgs -totalhigh_pages (), totalram_pgs /2 ); }#endif
@@ -3275,7 +3275,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, size =memparse (value,&rest);if (*rest =='%' ) { size <<=PAGE_SHIFT ; - size *= totalram_pages; + size *=totalram_pages ();do_div (size,100 ); rest++; }
mm/slab.c +1 -1
@@ -1248,7 +1248,7 @@ void __init kmem_cache_init(void)* page orders on machines with more than 32MB of memory if * not overridden on the command line. */ -if (!slab_max_order_set && totalram_pages > (32 <<20 ) >>PAGE_SHIFT ) +if (!slab_max_order_set &&totalram_pages () > (32 <<20 ) >>PAGE_SHIFT ) slab_max_order =SLAB_MAX_ORDER_HI ;/* Bootstrap is tricky, because several objects are allocated
mm/swap.c +1 -1
@@ -1023,7 +1023,7 @@ unsigned pagevec_lookup_range_nr_tag(struct pagevec *pvec,*/ void __init swap_setup (void ) { -unsigned long megs = totalram_pages >> (20 -PAGE_SHIFT ); +unsigned long megs =totalram_pages () >> (20 -PAGE_SHIFT );/* Use a smaller cluster for small-memory machines */ if (megs <16 )
mm/util.c +1 -1
@@ -593,7 +593,7 @@ unsigned long vm_commit_limit(void)if (sysctl_overcommit_kbytes) allowed = sysctl_overcommit_kbytes >> (PAGE_SHIFT -10 );else - allowed = ((totalram_pages -hugetlb_total_pages ()) + allowed = ((totalram_pages () -hugetlb_total_pages ()) * sysctl_overcommit_ratio /100 ); allowed += total_swap_pages;
mm/vmalloc.c +2 -2
@@ -1634,7 +1634,7 @@ void *vmap(struct page **pages, unsigned int count,might_sleep (); -if (count > totalram_pages) +if (count >totalram_pages ())return NULL ; size = (unsigned long )count <<PAGE_SHIFT ;
@@ -1739,7 +1739,7 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,unsigned long real_size = size; size =PAGE_ALIGN (size); -if (!size || (size >>PAGE_SHIFT ) > totalram_pages) +if (!size || (size >>PAGE_SHIFT ) >totalram_pages ()) goto fail; area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNINITIALIZED |
mm/workingset.c +1 -1
@@ -549,7 +549,7 @@ static int __init workingset_init(void)* double the initial memory by using totalram_pages as-is. */ timestamp_bits =BITS_PER_LONG -EVICTION_SHIFT ; - max_order =fls_long (totalram_pages -1 ); + max_order =fls_long (totalram_pages () -1 );if (max_order > timestamp_bits) bucket_order = max_order - timestamp_bits; pr_info("workingset: timestamp_bits=%d max_order=%d bucket_order=%u\n",
mm/zswap.c +2 -2
@@ -219,8 +219,8 @@ struct zswap_tree {static bool zswap_is_full (void ) { -return totalram_pages * zswap_max_pool_percent /100 < -DIV_ROUND_UP (zswap_pool_total_size,PAGE_SIZE ); +return totalram_pages () * zswap_max_pool_percent /100 < +DIV_ROUND_UP (zswap_pool_total_size,PAGE_SIZE ); }static void zswap_update_total_size (void )
net/dccp/proto.c +1 -1
@@ -1131,7 +1131,7 @@ static inline void dccp_mib_exit(void)static int __init dccp_init (void ) {unsigned long goal; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();int ehash_order, bhash_order, i;int rc;
net/decnet/dn_route.c +1 -1
@@ -1866,7 +1866,7 @@ void __init dn_route_init(void) dn_route_timer.expires = jiffies + decnet_dst_gc_interval *HZ ;add_timer (&dn_route_timer); - goal = totalram_pages >> (26 -PAGE_SHIFT ); + goal =totalram_pages () >> (26 -PAGE_SHIFT );for (order =0 ; (1UL << order) < goal; order++)/* NOTHING */ ;
net/ipv4/tcp_metrics.c +1 -1
@@ -1000,7 +1000,7 @@ static int __net_init tcp_net_metrics_init(struct net *net) slots = tcpmhash_entries;if (!slots) { -if (totalram_pages >=128 *1024 ) +if (totalram_pages () >=128 *1024 ) slots =16 *1024 ;else slots =8 *1024 ;
net/netfilter/nf_conntrack_core.c +1 -1
@@ -2248,7 +2248,7 @@ static __always_inline unsigned int total_extension_size(void)int nf_conntrack_init_start (void ) { -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();int max_factor =8 ;int ret = -ENOMEM ;int i;
net/netfilter/xt_hashlimit.c +1 -1
@@ -274,7 +274,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,struct xt_hashlimit_htable *hinfo;const struct seq_operations *ops;unsigned int size, i; -unsigned long totalram_pgs = totalram_pages; +unsigned long totalram_pgs =totalram_pages ();int ret;if (cfg->size) {
security/integrity/ima/ima_kexec.c +1 -1
@@ -106,7 +106,7 @@ void ima_add_kexec_buffer(struct kimage *image) kexec_segment_size =ALIGN (ima_get_binary_runtime_size () +PAGE_SIZE /2 ,PAGE_SIZE );if ((kexec_segment_size ==ULONG_MAX ) || - ((kexec_segment_size >>PAGE_SHIFT ) > totalram_pages /2 )) { + ((kexec_segment_size >>PAGE_SHIFT ) >totalram_pages () /2 )) {pr_err ("Binary measurement list too large.\n" );return ; }
Signature · 1 line
1.9.1
Re: [PATCH v2 3/4] mm: convert totalram_pages and totalhigh_pages variables to atomic
Quoted 7 lines · Arun KS
totalram_pagesandtotalhigh_pagesare made static inline function.Suggested-by Michal Hocko <[email protected]>Suggested-by Vlastimil Babka <[email protected]>Signed-off-by Arun KS <[email protected]>Reviewed-by Konstantin Khlebnikov <[email protected]>Acked-by Michal Hocko <[email protected]>
One bug (probably) below:
mm/highmem.c static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) · line 109
Quoted 10 lines
mm/highmem.c +0
-2@@ -105,9 +105,7 @@ static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) }#endif -unsigned long totalhigh_pages__read_mostly ; -EXPORT_SYMBOL (totalhigh_pages);
I think you still need to export _totalhigh_pages so that modules can use the inline accessors.
Quoted 5 lines
mm/highmem.c +1
-1- +atomic_long_t _totalhigh_pages__read_mostly ;EXPORT_PER_CPU_SYMBOL (__kmap_atomic_idx);
Re: [PATCH v2 3/4] mm: convert totalram_pages and totalhigh_pages variables to atomic
Quoted 22 lines · Vlastimil Babka
Quoted 7 lines · Arun KS
totalram_pagesandtotalhigh_pagesare made static inline function.Suggested-by Michal Hocko <[email protected]>Suggested-by Vlastimil Babka <[email protected]>Signed-off-by Arun KS <[email protected]>Reviewed-by Konstantin Khlebnikov <[email protected]>Acked-by Michal Hocko <[email protected]>Acked-by Vlastimil Babka <[email protected]>One bug (probably) below:
Quoted 9 lines
mm/highmem.c +0
-0@@ -105,9 +105,7 @@ static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) }#endif
Quoted 5 lines
mm/highmem.c static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) · line 109
Quoted 2 lines
mm/highmem.c +0
-2-unsigned long totalhigh_pages__read_mostly ; -EXPORT_SYMBOL (totalhigh_pages);I think you still need to export
_totalhigh_pagesso that modules can use the inline accessors.
Thanks for pointing this. I missed that. Will do the same for _totalram_pages.
Regards,
Arun
Quoted 6 lines
Quoted 6 lines
mm/highmem.c +1
-1- +atomic_long_t _totalhigh_pages__read_mostly ;EXPORT_PER_CPU_SYMBOL (__kmap_atomic_idx);
kbuild test robot
build botRe: [PATCH v2 3/4] mm: convert totalram_pages and totalhigh_pages variables to atomic
In reply to Arun KSThank you for the patch! Yet something to improve:
Hi Arun,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v4.20-rc1 next-20181107]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Arun-KS/mm-Fix-multiple-evaluvations-of-totalram_pages-and-managed_pages/20181108-025657
config: x86_64-randconfig-x018-201844 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 All error/warnings (new ones prefixed by >>):
In file included from include/asm-generic/bug.h:5:0,
from arch/x86/include/asm/bug.h:47,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/gfp.h:5,
from mm/kasan/quarantine.c:20:
mm/kasan/quarantine.c: In function 'quarantine_reduce':
>> include/linux/compiler.h:246:20: error: lvalue required as unary '&' operand
__read_once_size(&(x), __u.__c, sizeof(x)); \
^
>> include/linux/compiler.h:252:22: note: in expansion of macro '__READ_ONCE'
#define READ_ONCE(x) __READ_ONCE(x, 1)
^~~~~~~~~~~
>> mm/kasan/quarantine.c:239:16: note: in expansion of macro 'READ_ONCE'
total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
^~~~~~~~~
include/linux/compiler.h:248:28: error: lvalue required as unary '&' operand
__read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
^
>> include/linux/compiler.h:252:22: note: in expansion of macro '__READ_ONCE'
#define READ_ONCE(x) __READ_ONCE(x, 1)
^~~~~~~~~~~
>> mm/kasan/quarantine.c:239:16: note: in expansion of macro 'READ_ONCE' total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
^~~~~~~~~
--
In file included from include/asm-generic/bug.h:5:0,
from arch/x86/include/asm/bug.h:47,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/gfp.h:5,
from mm//kasan/quarantine.c:20:
mm//kasan/quarantine.c: In function 'quarantine_reduce':
>> include/linux/compiler.h:246:20: error: lvalue required as unary '&' operand
__read_once_size(&(x), __u.__c, sizeof(x)); \
^
>> include/linux/compiler.h:252:22: note: in expansion of macro '__READ_ONCE'
#define READ_ONCE(x) __READ_ONCE(x, 1)
^~~~~~~~~~~
mm//kasan/quarantine.c:239:16: note: in expansion of macro 'READ_ONCE'
total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
^~~~~~~~~
include/linux/compiler.h:248:28: error: lvalue required as unary '&' operand
__read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
^
>> include/linux/compiler.h:252:22: note: in expansion of macro '__READ_ONCE'
#define READ_ONCE(x) __READ_ONCE(x, 1)
^~~~~~~~~~~ mm//kasan/quarantine.c:239:16: note: in expansion of macro 'READ_ONCE'
total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
^~~~~~~~~
vim +/READ_ONCE +239 mm/kasan/quarantine.c
211
212 void quarantine_reduce(void)
213 {
214 size_t total_size, new_quarantine_size, percpu_quarantines;
215 unsigned long flags;
216 int srcu_idx;
217 struct qlist_head to_free = QLIST_INIT;
218
219 if (likely(READ_ONCE(quarantine_size) <=
220 READ_ONCE(quarantine_max_size)))
221 return;
222
223 /*
224 * srcu critical section ensures that quarantine_remove_cache()
225 * will not miss objects belonging to the cache while they are in our
226 * local to_free list. srcu is chosen because (1) it gives us private
227 * grace period domain that does not interfere with anything else,
228 * and (2) it allows synchronize_srcu() to return without waiting
229 * if there are no pending read critical sections (which is the
230 * expected case).
231 */
232 srcu_idx = srcu_read_lock(&remove_cache_srcu);
233 raw_spin_lock_irqsave(&quarantine_lock, flags);
234
235 /*
236 * Update quarantine size in case of hotplug. Allocate a fraction of
237 * the installed memory to quarantine minus per-cpu queue limits.
238 */
> 239 total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
240 QUARANTINE_FRACTION;
241 percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
242 new_quarantine_size = (total_size < percpu_quarantines) ?
243 0 : total_size - percpu_quarantines;
244 WRITE_ONCE(quarantine_max_size, new_quarantine_size);
245 /* Aim at consuming at most 1/2 of slots in quarantine. */
246 WRITE_ONCE(quarantine_batch_size, max((size_t)QUARANTINE_PERCPU_SIZE,
247 2 * total_size / QUARANTINE_BATCHES));
248
249 if (likely(quarantine_size > quarantine_max_size)) {
250 qlist_move_all(&global_quarantine[quarantine_head], &to_free);
251 WRITE_ONCE(quarantine_size, quarantine_size - to_free.bytes);
252 quarantine_head++;
253 if (quarantine_head == QUARANTINE_BATCHES)
254 quarantine_head = 0;
255 }
256
257 raw_spin_unlock_irqrestore(&quarantine_lock, flags);
258
259 qlist_free_all(&to_free, NULL);
260 srcu_read_unlock(&remove_cache_srcu, srcu_idx);
261 }
262
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kbuild test robot
build botRe: [PATCH v2 3/4] mm: convert totalram_pages and totalhigh_pages variables to atomic
In reply to Arun KSThank you for the patch! Yet something to improve:
Hi Arun,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v4.20-rc1 next-20181107]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Arun-KS/mm-Fix-multiple-evaluvations-of-totalram_pages-and-managed_pages/20181108-025657
config: i386-randconfig-s2-201844 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026 reproduce:
# save the attached .config to linux build tree
make ARCH=i386 All errors (new ones prefixed by >>):
>> ERROR: "_totalram_pages" [drivers/gpu/drm/i915/i915.ko] undefined!
ERROR: "_totalram_pages" [drivers/char/agp/agpgart.ko] undefined!
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
PATCH v2 4/4 mm: Remove managed_page_count spinlock
In reply to Arun KSNow totalram_pages and managed_pages are atomic varibles. No need of managed_page_count spinlock.
--- include/linux/mmzone.h | 6 ------ mm/page_alloc.c | 5 ----- 2 files changed, 11 deletions(-)
include/linux/mmzone.h +0 -6
@@ -428,12 +428,6 @@ struct zone {* Write access to present_pages at runtime should be protected by * mem_hotplug_begin/end(). Any reader who can't tolerant drift of * present_pages should get_online_mems() to get a stable value. -* -* Read access to managed_pages should be safe because it's unsigned -* long. Write access to zone->managed_pages and totalram_pages are -* protected by managed_page_count_lock at runtime. Idealy only -* adjust_managed_page_count() should be used instead of directly -* touching zone->managed_pages and totalram_pages. */ atomic_long_t managed_pages;unsigned long spanned_pages;
mm/page_alloc.c +0 -5
@@ -122,9 +122,6 @@ };EXPORT_SYMBOL (node_states); -/* Protect totalram_pages and zone->managed_pages */ -static DEFINE_SPINLOCK (managed_page_count_lock); -atomic_long_t _totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;unsigned long totalcma_pages__read_mostly ;
@@ -7064,14 +7061,12 @@ static int __init cmdline_parse_movablecore(char *p)void adjust_managed_page_count (struct page *page,long count) { -spin_lock (&managed_page_count_lock);atomic_long_add (count, &page_zone (page)->managed_pages);totalram_pages_add (count);#ifdef CONFIG_HIGHMEM if (PageHighMem (page))totalhigh_pages_add (count);#endif -spin_unlock (&managed_page_count_lock); }EXPORT_SYMBOL (adjust_managed_page_count);
Signature · 1 line
1.9.1
kbuild test robot
build botRe: [PATCH v2 4/4] mm: Remove managed_page_count spinlock
Thank you for the patch! Yet something to improve:
Hi Arun,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v4.20-rc1 next-20181107]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Arun-KS/mm-Fix-multiple-evaluvations-of-totalram_pages-and-managed_pages/20181108-025657
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 All errors (new ones prefixed by >>):
>> mm/kasan/quarantine.c:239:23: error: not addressable
>> mm/kasan/quarantine.c:239:23: error: not addressable
In file included from include/asm-generic/bug.h:5:0,
from arch/x86/include/asm/bug.h:47,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/gfp.h:5,
from mm/kasan/quarantine.c:20:
mm/kasan/quarantine.c: In function 'quarantine_reduce':
include/linux/compiler.h:246:20: error: lvalue required as unary '&' operand
__read_once_size(&(x), __u.__c, sizeof(x)); \
^
include/linux/compiler.h:252:22: note: in expansion of macro '__READ_ONCE'
#define READ_ONCE(x) __READ_ONCE(x, 1)
^~~~~~~~~~~
mm/kasan/quarantine.c:239:16: note: in expansion of macro 'READ_ONCE'
total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
^~~~~~~~~
include/linux/compiler.h:248:28: error: lvalue required as unary '&' operand
__read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
^
include/linux/compiler.h:252:22: note: in expansion of macro '__READ_ONCE'
#define READ_ONCE(x) __READ_ONCE(x, 1)
^~~~~~~~~~~ mm/kasan/quarantine.c:239:16: note: in expansion of macro 'READ_ONCE'
total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
^~~~~~~~~
--
include/linux/slab.h:332:43: warning: dubious: x & !y include/linux/slab.h:332:43: warning: dubious: x & !y
>> net/sctp/protocol.c:1430:13: error: undefined identifier 'totalram_pgs' net/sctp/protocol.c:1431:24: error: undefined identifier 'totalram_pgs' net/sctp/protocol.c:1433:24: error: undefined identifier 'totalram_pgs' >> /bin/bash: line 1: 74457 Segmentation fault sparse -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise -Wno-return-void -Wno-unknown-attribute -D__CHECK_ENDIAN__ -D__x86_64__ -mlittle-endian -m64 -Wp,-MD,net/sctp/.protocol.o.d -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/7/include -Iarch/x86/include -I./arch/x86/include/generated -Iinclude -I./include -Iarch/x86/include/uapi -I./arch/x86/include/generated/uapi -Iinclude/uapi -I./include/generated/uapi -include include/linux/kconfig.h -include include/linux/compiler_types.h -Inet/sctp -Inet/sctp -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -DCC_HAVE_ASM_GOTO -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_AVX512=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -DRETPOLINE -Wa,arch/x86/kernel/macros.s -Wa,- -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-int-in-bool-context -O2 --param=allow-store-data-races=0 -fplugin=./scripts/gcc-plugins/latent_entropy_plugin.so -fplugin=./scripts/gcc-plugins/structleak_plugin.so -fplugin=./scripts/gcc-plugins/randomize_layout_plugin.so -fplugin=./scripts/gcc-plugins/stackleak_plugin.so -DLATENT_ENTROPY_PLUGIN -DSTRUCTLEAK_PLUGIN -DRANDSTRUCT_PLUGIN -DSTACKLEAK_PLUGIN -fplugin-arg-stackleak_plugin-track-min-size=100 -fno-reorder-blocks -fno-ipa-cp-clone -fno-partial-inlining -Wframe-larger-than=8192 -fstack-protector-strong -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-var-tracking-assignments -pg -mrecord-mcount -mfentry -DCC_USING_FENTRY -fno-inline-functions-called-once -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -fsanitize=kernel-address -fasan-shadow-offset=0xdffffc0000000000 --param asan-globals=1 --param asan-instrumentation-with-call-threshold=0 --param asan-stack=1 -fsanitize-coverage=trace-pc -DMODULE -DKBUILD_BASENAME='"protocol"' -DKBUILD_MODNAME='"sctp"' net/sctp/protocol.c
vim +239 mm/kasan/quarantine.c
55834c59 Alexander Potapenko 2016-05-20 211
55834c59 Alexander Potapenko 2016-05-20 212 void quarantine_reduce(void)
55834c59 Alexander Potapenko 2016-05-20 213 {
64abdcb2 Dmitry Vyukov 2016-12-12 214 size_t total_size, new_quarantine_size, percpu_quarantines;
55834c59 Alexander Potapenko 2016-05-20 215 unsigned long flags;
ce5bec54 Dmitry Vyukov 2017-03-09 216 int srcu_idx;
55834c59 Alexander Potapenko 2016-05-20 217 struct qlist_head to_free = QLIST_INIT;
55834c59 Alexander Potapenko 2016-05-20 218
64abdcb2 Dmitry Vyukov 2016-12-12 219 if (likely(READ_ONCE(quarantine_size) <=
64abdcb2 Dmitry Vyukov 2016-12-12 220 READ_ONCE(quarantine_max_size)))
55834c59 Alexander Potapenko 2016-05-20 221 return;
55834c59 Alexander Potapenko 2016-05-20 222
ce5bec54 Dmitry Vyukov 2017-03-09 223 /*
ce5bec54 Dmitry Vyukov 2017-03-09 224 * srcu critical section ensures that quarantine_remove_cache()
ce5bec54 Dmitry Vyukov 2017-03-09 225 * will not miss objects belonging to the cache while they are in our
ce5bec54 Dmitry Vyukov 2017-03-09 226 * local to_free list. srcu is chosen because (1) it gives us private
ce5bec54 Dmitry Vyukov 2017-03-09 227 * grace period domain that does not interfere with anything else,
ce5bec54 Dmitry Vyukov 2017-03-09 228 * and (2) it allows synchronize_srcu() to return without waiting
ce5bec54 Dmitry Vyukov 2017-03-09 229 * if there are no pending read critical sections (which is the
ce5bec54 Dmitry Vyukov 2017-03-09 230 * expected case).
ce5bec54 Dmitry Vyukov 2017-03-09 231 */
ce5bec54 Dmitry Vyukov 2017-03-09 232 srcu_idx = srcu_read_lock(&remove_cache_srcu);
026d1eaf Clark Williams 2018-10-26 233 raw_spin_lock_irqsave(&quarantine_lock, flags);
55834c59 Alexander Potapenko 2016-05-20 234
55834c59 Alexander Potapenko 2016-05-20 235 /*
55834c59 Alexander Potapenko 2016-05-20 236 * Update quarantine size in case of hotplug. Allocate a fraction of
55834c59 Alexander Potapenko 2016-05-20 237 * the installed memory to quarantine minus per-cpu queue limits.
55834c59 Alexander Potapenko 2016-05-20 238 */
a399c534 Arun KS 2018-11-06 @239 total_size = (READ_ONCE(totalram_pages()) << PAGE_SHIFT) /
55834c59 Alexander Potapenko 2016-05-20 240 QUARANTINE_FRACTION;
c3cee372 Alexander Potapenko 2016-08-02 241 percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
64abdcb2 Dmitry Vyukov 2016-12-12 242 new_quarantine_size = (total_size < percpu_quarantines) ?
64abdcb2 Dmitry Vyukov 2016-12-12 243 0 : total_size - percpu_quarantines;
64abdcb2 Dmitry Vyukov 2016-12-12 244 WRITE_ONCE(quarantine_max_size, new_quarantine_size);
64abdcb2 Dmitry Vyukov 2016-12-12 245 /* Aim at consuming at most 1/2 of slots in quarantine. */
64abdcb2 Dmitry Vyukov 2016-12-12 246 WRITE_ONCE(quarantine_batch_size, max((size_t)QUARANTINE_PERCPU_SIZE,
64abdcb2 Dmitry Vyukov 2016-12-12 247 2 * total_size / QUARANTINE_BATCHES));
64abdcb2 Dmitry Vyukov 2016-12-12 248
64abdcb2 Dmitry Vyukov 2016-12-12 249 if (likely(quarantine_size > quarantine_max_size)) {
64abdcb2 Dmitry Vyukov 2016-12-12 250 qlist_move_all(&global_quarantine[quarantine_head], &to_free);
64abdcb2 Dmitry Vyukov 2016-12-12 251 WRITE_ONCE(quarantine_size, quarantine_size - to_free.bytes);
64abdcb2 Dmitry Vyukov 2016-12-12 252 quarantine_head++;
64abdcb2 Dmitry Vyukov 2016-12-12 253 if (quarantine_head == QUARANTINE_BATCHES)
64abdcb2 Dmitry Vyukov 2016-12-12 254 quarantine_head = 0;
55834c59 Alexander Potapenko 2016-05-20 255 }
55834c59 Alexander Potapenko 2016-05-20 256
026d1eaf Clark Williams 2018-10-26 257 raw_spin_unlock_irqrestore(&quarantine_lock, flags);
55834c59 Alexander Potapenko 2016-05-20 258
55834c59 Alexander Potapenko 2016-05-20 259 qlist_free_all(&to_free, NULL);
ce5bec54 Dmitry Vyukov 2017-03-09 260 srcu_read_unlock(&remove_cache_srcu, srcu_idx);
55834c59 Alexander Potapenko 2016-05-20 261 }
55834c59 Alexander Potapenko 2016-05-20 262 :::::: The code at line 239 was first introduced by commit
:::::: a399c534492723c9d2f175bc2b66aa930abd895f mm: convert totalram_pages and totalhigh_pages variables to atomic
:::::: TO: Arun KS <[email protected]>
:::::: CC: 0day robot <[email protected]>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation