Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: reference totalram_pages and managed_pages once per function

Patch series "mm: convert totalram_pages, totalhigh_pages and managed
pages to atomic", v5.

This series converts totalram_pages, totalhigh_pages and
zone->managed_pages to atomic variables.

totalram_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.

Main motivation was that managed_page_count_lock handling was complicating
things. It was discussed in length here,
https://lore.kernel.org/patchwork/patch/995739/#1181785 It seemes better
to remove the lock and convert variables to atomic. With the change,
preventing poteintial store-to-read tearing comes as a bonus.

This patch (of 4):

This is in preparation to a later patch which converts totalram_pages and
zone->managed_pages to atomic variables. 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.

Link: http://lkml.kernel.org/r/1542090790-21750-2-git-send-email-arunks@codeaurora.org
Signed-off-by: Arun KS <arunks@codeaurora.org>
Reviewed-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Reviewed-by: David Hildenbrand <david@redhat.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: Pavel Tatashin <pasha.tatashin@soleen.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Arun KS and committed by
Linus Torvalds
3d6357de fecd4a50

+44 -33
+1 -1
arch/um/kernel/mem.c
··· 52 52 /* this will put all low memory onto the freelists */ 53 53 memblock_free_all(); 54 54 max_low_pfn = totalram_pages; 55 - max_pfn = totalram_pages; 55 + max_pfn = max_low_pfn; 56 56 mem_init_print_info(NULL); 57 57 kmalloc_ok = 1; 58 58 }
+3 -2
arch/x86/kernel/cpu/microcode/core.c
··· 434 434 size_t len, loff_t *ppos) 435 435 { 436 436 ssize_t ret = -EINVAL; 437 + unsigned long nr_pages = totalram_pages; 437 438 438 - if ((len >> PAGE_SHIFT) > totalram_pages) { 439 - pr_err("too much data (max %ld pages)\n", totalram_pages); 439 + if ((len >> PAGE_SHIFT) > nr_pages) { 440 + pr_err("too much data (max %ld pages)\n", nr_pages); 440 441 return ret; 441 442 } 442 443
+10 -9
drivers/hv/hv_balloon.c
··· 1090 1090 static unsigned long compute_balloon_floor(void) 1091 1091 { 1092 1092 unsigned long min_pages; 1093 + unsigned long nr_pages = totalram_pages; 1093 1094 #define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) 1094 1095 /* Simple continuous piecewiese linear function: 1095 1096 * max MiB -> min MiB gradient ··· 1103 1102 * 8192 744 (1/16) 1104 1103 * 32768 1512 (1/32) 1105 1104 */ 1106 - if (totalram_pages < MB2PAGES(128)) 1107 - min_pages = MB2PAGES(8) + (totalram_pages >> 1); 1108 - else if (totalram_pages < MB2PAGES(512)) 1109 - min_pages = MB2PAGES(40) + (totalram_pages >> 2); 1110 - else if (totalram_pages < MB2PAGES(2048)) 1111 - min_pages = MB2PAGES(104) + (totalram_pages >> 3); 1112 - else if (totalram_pages < MB2PAGES(8192)) 1113 - min_pages = MB2PAGES(232) + (totalram_pages >> 4); 1105 + if (nr_pages < MB2PAGES(128)) 1106 + min_pages = MB2PAGES(8) + (nr_pages >> 1); 1107 + else if (nr_pages < MB2PAGES(512)) 1108 + min_pages = MB2PAGES(40) + (nr_pages >> 2); 1109 + else if (nr_pages < MB2PAGES(2048)) 1110 + min_pages = MB2PAGES(104) + (nr_pages >> 3); 1111 + else if (nr_pages < MB2PAGES(8192)) 1112 + min_pages = MB2PAGES(232) + (nr_pages >> 4); 1114 1113 else 1115 - min_pages = MB2PAGES(488) + (totalram_pages >> 5); 1114 + min_pages = MB2PAGES(488) + (nr_pages >> 5); 1116 1115 #undef MB2PAGES 1117 1116 return min_pages; 1118 1117 }
+4 -3
fs/file_table.c
··· 380 380 void __init files_maxfiles_init(void) 381 381 { 382 382 unsigned long n; 383 - unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2; 383 + unsigned long nr_pages = totalram_pages; 384 + unsigned long memreserve = (nr_pages - nr_free_pages()) * 3/2; 384 385 385 - memreserve = min(memreserve, totalram_pages - 1); 386 - n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10; 386 + memreserve = min(memreserve, nr_pages - 1); 387 + n = ((nr_pages - memreserve) * (PAGE_SIZE / 1024)) / 10; 387 388 388 389 files_stat.max_files = max_t(unsigned long, n, NR_FILE); 389 390 }
+3 -2
kernel/fork.c
··· 744 744 static void set_max_threads(unsigned int max_threads_suggested) 745 745 { 746 746 u64 threads; 747 + unsigned long nr_pages = totalram_pages; 747 748 748 749 /* 749 750 * The number of threads shall be limited such that the thread 750 751 * structures may only consume a small part of the available memory. 751 752 */ 752 - if (fls64(totalram_pages) + fls64(PAGE_SIZE) > 64) 753 + if (fls64(nr_pages) + fls64(PAGE_SIZE) > 64) 753 754 threads = MAX_THREADS; 754 755 else 755 - threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE, 756 + threads = div64_u64((u64) nr_pages * (u64) PAGE_SIZE, 756 757 (u64) THREAD_SIZE * 8UL); 757 758 758 759 if (threads > max_threads_suggested)
+3 -2
kernel/kexec_core.c
··· 152 152 int i; 153 153 unsigned long nr_segments = image->nr_segments; 154 154 unsigned long total_pages = 0; 155 + unsigned long nr_pages = totalram_pages; 155 156 156 157 /* 157 158 * Verify we have good destination addresses. The caller is ··· 218 217 * wasted allocating pages, which can cause a soft lockup. 219 218 */ 220 219 for (i = 0; i < nr_segments; i++) { 221 - if (PAGE_COUNT(image->segment[i].memsz) > totalram_pages / 2) 220 + if (PAGE_COUNT(image->segment[i].memsz) > nr_pages / 2) 222 221 return -EINVAL; 223 222 224 223 total_pages += PAGE_COUNT(image->segment[i].memsz); 225 224 } 226 225 227 - if (total_pages > totalram_pages / 2) 226 + if (total_pages > nr_pages / 2) 228 227 return -EINVAL; 229 228 230 229 /*
+3 -2
mm/page_alloc.c
··· 7257 7257 for (i = 0; i < MAX_NR_ZONES; i++) { 7258 7258 struct zone *zone = pgdat->node_zones + i; 7259 7259 long max = 0; 7260 + unsigned long managed_pages = zone->managed_pages; 7260 7261 7261 7262 /* Find valid and maximum lowmem_reserve in the zone */ 7262 7263 for (j = i; j < MAX_NR_ZONES; j++) { ··· 7268 7267 /* we treat the high watermark as reserved pages. */ 7269 7268 max += high_wmark_pages(zone); 7270 7269 7271 - if (max > zone->managed_pages) 7272 - max = zone->managed_pages; 7270 + if (max > managed_pages) 7271 + max = managed_pages; 7273 7272 7274 7273 pgdat->totalreserve_pages += max; 7275 7274
+2 -1
mm/shmem.c
··· 114 114 115 115 static unsigned long shmem_default_max_inodes(void) 116 116 { 117 - return min(totalram_pages - totalhigh_pages, totalram_pages / 2); 117 + unsigned long nr_pages = totalram_pages; 118 + return min(nr_pages - totalhigh_pages, nr_pages / 2); 118 119 } 119 120 #endif 120 121
+4 -3
net/dccp/proto.c
··· 1131 1131 static int __init dccp_init(void) 1132 1132 { 1133 1133 unsigned long goal; 1134 + unsigned long nr_pages = totalram_pages; 1134 1135 int ehash_order, bhash_order, i; 1135 1136 int rc; 1136 1137 ··· 1158 1157 * 1159 1158 * The methodology is similar to that of the buffer cache. 1160 1159 */ 1161 - if (totalram_pages >= (128 * 1024)) 1162 - goal = totalram_pages >> (21 - PAGE_SHIFT); 1160 + if (nr_pages >= (128 * 1024)) 1161 + goal = nr_pages >> (21 - PAGE_SHIFT); 1163 1162 else 1164 - goal = totalram_pages >> (23 - PAGE_SHIFT); 1163 + goal = nr_pages >> (23 - PAGE_SHIFT); 1165 1164 1166 1165 if (thash_entries) 1167 1166 goal = (thash_entries *
+4 -3
net/netfilter/nf_conntrack_core.c
··· 2248 2248 2249 2249 int nf_conntrack_init_start(void) 2250 2250 { 2251 + unsigned long nr_pages = totalram_pages; 2251 2252 int max_factor = 8; 2252 2253 int ret = -ENOMEM; 2253 2254 int i; ··· 2268 2267 * >= 4GB machines have 65536 buckets. 2269 2268 */ 2270 2269 nf_conntrack_htable_size 2271 - = (((totalram_pages << PAGE_SHIFT) / 16384) 2270 + = (((nr_pages << PAGE_SHIFT) / 16384) 2272 2271 / sizeof(struct hlist_head)); 2273 - if (totalram_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) 2272 + if (nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) 2274 2273 nf_conntrack_htable_size = 65536; 2275 - else if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE)) 2274 + else if (nr_pages > (1024 * 1024 * 1024 / PAGE_SIZE)) 2276 2275 nf_conntrack_htable_size = 16384; 2277 2276 if (nf_conntrack_htable_size < 32) 2278 2277 nf_conntrack_htable_size = 32;
+3 -2
net/netfilter/xt_hashlimit.c
··· 274 274 struct xt_hashlimit_htable *hinfo; 275 275 const struct seq_operations *ops; 276 276 unsigned int size, i; 277 + unsigned long nr_pages = totalram_pages; 277 278 int ret; 278 279 279 280 if (cfg->size) { 280 281 size = cfg->size; 281 282 } else { 282 - size = (totalram_pages << PAGE_SHIFT) / 16384 / 283 + size = (nr_pages << PAGE_SHIFT) / 16384 / 283 284 sizeof(struct hlist_head); 284 - if (totalram_pages > 1024 * 1024 * 1024 / PAGE_SIZE) 285 + if (nr_pages > 1024 * 1024 * 1024 / PAGE_SIZE) 285 286 size = 8192; 286 287 if (size < 16) 287 288 size = 16;
+4 -3
net/sctp/protocol.c
··· 1368 1368 int status = -EINVAL; 1369 1369 unsigned long goal; 1370 1370 unsigned long limit; 1371 + unsigned long nr_pages = totalram_pages; 1371 1372 int max_share; 1372 1373 int order; 1373 1374 int num_entries; ··· 1427 1426 * The methodology is similar to that of the tcp hash tables. 1428 1427 * Though not identical. Start by getting a goal size 1429 1428 */ 1430 - if (totalram_pages >= (128 * 1024)) 1431 - goal = totalram_pages >> (22 - PAGE_SHIFT); 1429 + if (nr_pages >= (128 * 1024)) 1430 + goal = nr_pages >> (22 - PAGE_SHIFT); 1432 1431 else 1433 - goal = totalram_pages >> (24 - PAGE_SHIFT); 1432 + goal = nr_pages >> (24 - PAGE_SHIFT); 1434 1433 1435 1434 /* Then compute the page order for said goal */ 1436 1435 order = get_order(goal);