From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4643DC47097 for ; Thu, 3 Jun 2021 10:43:44 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id C9C30613D6 for ; Thu, 3 Jun 2021 10:43:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C9C30613D6 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 4C5A16B0080; Thu, 3 Jun 2021 06:43:43 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 4763C6B0081; Thu, 3 Jun 2021 06:43:43 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2F0476B0082; Thu, 3 Jun 2021 06:43:43 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0183.hostedemail.com [216.40.44.183]) by kanga.kvack.org (Postfix) with ESMTP id E14E36B0080 for ; Thu, 3 Jun 2021 06:43:42 -0400 (EDT) Received: from smtpin13.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 7D3F9999F for ; Thu, 3 Jun 2021 10:43:42 +0000 (UTC) X-FDA: 78212076684.13.748CFDB Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by imf28.hostedemail.com (Postfix) with ESMTP id DC79620010AF for ; Thu, 3 Jun 2021 10:43:28 +0000 (UTC) Received: by mail.kernel.org (Postfix) with ESMTPSA id 47813610A8; Thu, 3 Jun 2021 10:43:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1622717021; bh=3m7bk5laUslmhUj7H5XI0MlVfTlgaKfCqG5B/HUfQ1I=; h=From:To:Cc:Subject:Date:From; b=tkC6WYo2XGCaqV9QKIBvobBkvBXxH8MdRO66dHvrktlBSZBUE6S8pWTHX+cW6c2ZD P4uYAJVoKoDq1JGGYqvFsKX4x95EjoJfhF1C0UKlRJhLQD1iovvolif3oltcaZboUT rrEl/+3jOjIrP8dy3Mo8xFm+hFlWgUCZwkpBIJyr9NAVHJ9TfUGlUmOC6IqwQuKWMp whuPl6bmtqVf/Z94LECITZi2ueCrMqzisvIBZBjQyLO2Mer4eUK7TzMq4d45Zn15uI XmwI0fy93SQLw5wQbm6LqvdfWmFz0196olBGQyEPs2b0rXvuJsIH9apEM6LxzLsMIn aGv3LF8ujdHaw== From: legion@kernel.org To: LKML , Linux Containers , Linux Containers , Linux FS Devel , linux-mm@kvack.org Cc: Alexey Gladkov , Andrew Morton , Christian Brauner , "Eric W . Biederman" , Johannes Weiner , Michal Hocko Subject: [PATCH v1] proc: Implement /proc/self/meminfo Date: Thu, 3 Jun 2021 12:43:07 +0200 Message-Id: X-Mailer: git-send-email 2.29.3 MIME-Version: 1.0 X-Rspamd-Queue-Id: DC79620010AF Authentication-Results: imf28.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=tkC6WYo2; spf=pass (imf28.hostedemail.com: domain of legion@kernel.org designates 198.145.29.99 as permitted sender) smtp.mailfrom=legion@kernel.org; dmarc=pass (policy=none) header.from=kernel.org X-Rspamd-Server: rspam04 X-Stat-Signature: k9cbzg9pkssausu7p8zk5fzd1i4ymn43 X-HE-Tag: 1622717008-34245 Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: Alexey Gladkov The /proc/meminfo contains information regardless of the cgroups restrictions. This file is still widely used [1]. This means that all these programs will not work correctly inside container [2][3][4]. Some programs try to respect the cgroups limits, but not all of them implement support for all cgroup versions [5]. Correct information can be obtained from cgroups, but this requires the cgroups to be available inside container and the correct version of cgroups to be supported. There is lxcfs [6] that emulates /proc/meminfo using fuse to provide information regarding cgroups. This patch can help them. This patch adds /proc/self/meminfo that contains a subset of /proc/meminfo respecting cgroup restrictions. We cannot just create /proc/self/meminfo and make a symlink at the old location because this will break the existing apparmor rules [7]. Therefore, the patch adds a separate file with the same format. [1] https://codesearch.debian.net/search?q=3D%2Fproc%2Fmeminfo [2] https://sources.debian.org/src/erlang/1:23.2.6+dfsg-1/lib/os_mon/c_sr= c/memsup.c#L300 [3] https://sources.debian.org/src/p7zip/16.02+dfsg-8/CPP/Windows/System.= cpp/#L103 [4] https://sources.debian.org/src/systemd/247.3-5/src/oom/oomd.c/#L138 [5] https://sources.debian.org/src/nodejs/12.21.0%7Edfsg-4/deps/uv/src/un= ix/linux-core.c/#L1059 [6] https://linuxcontainers.org/lxcfs/ [7] https://gitlab.com/apparmor/apparmor/-/blob/master/profiles/apparmor.= d/abstractions/base#L98 Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 2 + fs/proc/internal.h | 6 ++ fs/proc/meminfo.c | 160 +++++++++++++++++++++++-------------- include/linux/memcontrol.h | 2 + include/linux/mm.h | 15 ++++ mm/memcontrol.c | 80 +++++++++++++++++++ mm/page_alloc.c | 28 ++++--- 7 files changed, 222 insertions(+), 71 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 58bbf334265b..e95837cf713f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3269,6 +3269,7 @@ static const struct pid_entry tgid_base_stuff[] =3D= { #ifdef CONFIG_SECCOMP_CACHE_DEBUG ONE("seccomp_cache", S_IRUSR, proc_pid_seccomp_cache), #endif + ONE("meminfo", S_IRUGO, proc_meminfo_show), }; =20 static int proc_tgid_base_readdir(struct file *file, struct dir_context = *ctx) @@ -3602,6 +3603,7 @@ static const struct pid_entry tid_base_stuff[] =3D = { #ifdef CONFIG_SECCOMP_CACHE_DEBUG ONE("seccomp_cache", S_IRUSR, proc_pid_seccomp_cache), #endif + ONE("meminfo", S_IRUGO, proc_meminfo_show), }; =20 static int proc_tid_base_readdir(struct file *file, struct dir_context *= ctx) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 03415f3fb3a8..a6e8540afbd3 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -241,6 +241,12 @@ extern int proc_net_init(void); static inline int proc_net_init(void) { return 0; } #endif =20 +/* + * meminfo.c + */ +extern int proc_meminfo_show(struct seq_file *m, struct pid_namespace *n= s, + struct pid *pid, struct task_struct *tsk); + /* * proc_self.c */ diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index 6fa761c9cc78..3587a79d4b96 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -16,6 +16,9 @@ #ifdef CONFIG_CMA #include #endif +#ifdef CONFIG_MEMCG +#include +#endif #include #include "internal.h" =20 @@ -23,91 +26,112 @@ void __attribute__((weak)) arch_report_meminfo(struc= t seq_file *m) { } =20 +static void proc_fill_meminfo(struct meminfo *mi) +{ + int lru; + long cached; + + si_meminfo(&mi->si); + si_swapinfo(&mi->si); + + for (lru =3D LRU_BASE; lru < NR_LRU_LISTS; lru++) + mi->pages[lru] =3D global_node_page_state(NR_LRU_BASE + lru); + + cached =3D global_node_page_state(NR_FILE_PAGES) - total_swapcache_page= s() - mi->si.bufferram; + if (cached < 0) + cached =3D 0; + + mi->cached =3D cached; + mi->swapcached =3D total_swapcache_pages(); + mi->slab_reclaimable =3D global_node_page_state_pages(NR_SLAB_RECLAIMAB= LE_B); + mi->slab_unreclaimable =3D global_node_page_state_pages(NR_SLAB_UNRECLA= IMABLE_B); + mi->anon_pages =3D global_node_page_state(NR_ANON_MAPPED); + mi->mapped =3D global_node_page_state(NR_FILE_MAPPED); + mi->nr_pagetable =3D global_node_page_state(NR_PAGETABLE); + mi->dirty_pages =3D global_node_page_state(NR_FILE_DIRTY); + mi->writeback_pages =3D global_node_page_state(NR_WRITEBACK); +} + +#ifdef CONFIG_MEMCG +static inline void fill_meminfo(struct meminfo *mi, struct task_struct *= task) +{ + mem_fill_meminfo(mi, task); +} +#else +static inline void fill_meminfo(struct meminfo *mi, struct task_struct *= task) +{ + proc_fill_meminfo(mi); +} +#endif + static void show_val_kb(struct seq_file *m, const char *s, unsigned long= num) { seq_put_decimal_ull_width(m, s, num << (PAGE_SHIFT - 10), 8); seq_write(m, " kB\n", 4); } =20 +static int meminfo_proc_show_mi(struct seq_file *m, struct meminfo *mi) +{ + show_val_kb(m, "MemTotal: ", mi->si.totalram); + show_val_kb(m, "MemFree: ", mi->si.freeram); + show_val_kb(m, "MemAvailable: ", si_mem_available_mi(mi)); + show_val_kb(m, "Buffers: ", mi->si.bufferram); + show_val_kb(m, "Cached: ", mi->cached); + show_val_kb(m, "SwapCached: ", mi->swapcached); + show_val_kb(m, "Active: ", mi->pages[LRU_ACTIVE_ANON] + mi->pag= es[LRU_ACTIVE_FILE]); + show_val_kb(m, "Inactive: ", mi->pages[LRU_INACTIVE_ANON] + mi->p= ages[LRU_INACTIVE_FILE]); + show_val_kb(m, "Active(anon): ", mi->pages[LRU_ACTIVE_ANON]); + show_val_kb(m, "Inactive(anon): ", mi->pages[LRU_INACTIVE_ANON]); + show_val_kb(m, "Active(file): ", mi->pages[LRU_ACTIVE_FILE]); + show_val_kb(m, "Inactive(file): ", mi->pages[LRU_INACTIVE_FILE]); + show_val_kb(m, "Unevictable: ", mi->pages[LRU_UNEVICTABLE]); + +#ifdef CONFIG_HIGHMEM + show_val_kb(m, "HighTotal: ", mi->si.totalhigh); + show_val_kb(m, "HighFree: ", mi->si.freehigh); + show_val_kb(m, "LowTotal: ", mi->si.totalram - mi->si.totalhigh); + show_val_kb(m, "LowFree: ", mi->si.freeram - mi->si.freehigh); +#endif + + show_val_kb(m, "SwapTotal: ", mi->si.totalswap); + show_val_kb(m, "SwapFree: ", mi->si.freeswap); + show_val_kb(m, "Dirty: ", mi->dirty_pages); + show_val_kb(m, "Writeback: ", mi->writeback_pages); + + show_val_kb(m, "AnonPages: ", mi->anon_pages); + show_val_kb(m, "Mapped: ", mi->mapped); + show_val_kb(m, "Shmem: ", mi->si.sharedram); + show_val_kb(m, "Slab: ", mi->slab_reclaimable + mi->slab_unre= claimable); + show_val_kb(m, "SReclaimable: ", mi->slab_reclaimable); + show_val_kb(m, "SUnreclaim: ", mi->slab_unreclaimable); + show_val_kb(m, "PageTables: ", mi->nr_pagetable); + + return 0; +} + static int meminfo_proc_show(struct seq_file *m, void *v) { - struct sysinfo i; - unsigned long committed; - long cached; - long available; - unsigned long pages[NR_LRU_LISTS]; - unsigned long sreclaimable, sunreclaim; - int lru; =20 - si_meminfo(&i); - si_swapinfo(&i); - committed =3D vm_memory_committed(); + struct meminfo mi; =20 - cached =3D global_node_page_state(NR_FILE_PAGES) - - total_swapcache_pages() - i.bufferram; - if (cached < 0) - cached =3D 0; + proc_fill_meminfo(&mi); + meminfo_proc_show_mi(m, &mi); =20 - for (lru =3D LRU_BASE; lru < NR_LRU_LISTS; lru++) - pages[lru] =3D global_node_page_state(NR_LRU_BASE + lru); - - available =3D si_mem_available(); - sreclaimable =3D global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim =3D global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); - show_val_kb(m, "Buffers: ", i.bufferram); - show_val_kb(m, "Cached: ", cached); - show_val_kb(m, "SwapCached: ", total_swapcache_pages()); - show_val_kb(m, "Active: ", pages[LRU_ACTIVE_ANON] + - pages[LRU_ACTIVE_FILE]); - show_val_kb(m, "Inactive: ", pages[LRU_INACTIVE_ANON] + - pages[LRU_INACTIVE_FILE]); - show_val_kb(m, "Active(anon): ", pages[LRU_ACTIVE_ANON]); - show_val_kb(m, "Inactive(anon): ", pages[LRU_INACTIVE_ANON]); - show_val_kb(m, "Active(file): ", pages[LRU_ACTIVE_FILE]); - show_val_kb(m, "Inactive(file): ", pages[LRU_INACTIVE_FILE]); - show_val_kb(m, "Unevictable: ", pages[LRU_UNEVICTABLE]); show_val_kb(m, "Mlocked: ", global_zone_page_state(NR_MLOCK)); =20 -#ifdef CONFIG_HIGHMEM - show_val_kb(m, "HighTotal: ", i.totalhigh); - show_val_kb(m, "HighFree: ", i.freehigh); - show_val_kb(m, "LowTotal: ", i.totalram - i.totalhigh); - show_val_kb(m, "LowFree: ", i.freeram - i.freehigh); -#endif - #ifndef CONFIG_MMU show_val_kb(m, "MmapCopy: ", (unsigned long)atomic_long_read(&mmap_pages_allocated)); #endif =20 - show_val_kb(m, "SwapTotal: ", i.totalswap); - show_val_kb(m, "SwapFree: ", i.freeswap); - show_val_kb(m, "Dirty: ", - global_node_page_state(NR_FILE_DIRTY)); - show_val_kb(m, "Writeback: ", - global_node_page_state(NR_WRITEBACK)); - show_val_kb(m, "AnonPages: ", - global_node_page_state(NR_ANON_MAPPED)); - show_val_kb(m, "Mapped: ", - global_node_page_state(NR_FILE_MAPPED)); - show_val_kb(m, "Shmem: ", i.sharedram); - show_val_kb(m, "KReclaimable: ", sreclaimable + + show_val_kb(m, "KReclaimable: ", mi.slab_reclaimable + global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE)); - show_val_kb(m, "Slab: ", sreclaimable + sunreclaim); - show_val_kb(m, "SReclaimable: ", sreclaimable); - show_val_kb(m, "SUnreclaim: ", sunreclaim); seq_printf(m, "KernelStack: %8lu kB\n", global_node_page_state(NR_KERNEL_STACK_KB)); #ifdef CONFIG_SHADOW_CALL_STACK seq_printf(m, "ShadowCallStack:%8lu kB\n", global_node_page_state(NR_KERNEL_SCS_KB)); #endif - show_val_kb(m, "PageTables: ", - global_node_page_state(NR_PAGETABLE)); =20 show_val_kb(m, "NFS_Unstable: ", 0); show_val_kb(m, "Bounce: ", @@ -115,7 +139,7 @@ static int meminfo_proc_show(struct seq_file *m, void= *v) show_val_kb(m, "WritebackTmp: ", global_node_page_state(NR_WRITEBACK_TEMP)); show_val_kb(m, "CommitLimit: ", vm_commit_limit()); - show_val_kb(m, "Committed_AS: ", committed); + show_val_kb(m, "Committed_AS: ", vm_memory_committed()); seq_printf(m, "VmallocTotal: %8lu kB\n", (unsigned long)VMALLOC_TOTAL >> 10); show_val_kb(m, "VmallocUsed: ", vmalloc_nr_pages()); @@ -153,6 +177,20 @@ static int meminfo_proc_show(struct seq_file *m, voi= d *v) return 0; } =20 +int proc_meminfo_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + struct meminfo mi; + + fill_meminfo(&mi, task); + + meminfo_proc_show_mi(m, &mi); + hugetlb_report_meminfo(m); + arch_report_meminfo(m); + + return 0; +} + static int __init proc_meminfo_init(void) { proc_create_single("meminfo", 0, NULL, meminfo_proc_show); diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index c193be760709..4a7e2894954f 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -1119,6 +1119,8 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data= _t *pgdat, int order, gfp_t gfp_mask, unsigned long *total_scanned); =20 +void mem_fill_meminfo(struct meminfo *mi, struct task_struct *task); + #else /* CONFIG_MEMCG */ =20 #define MEM_CGROUP_ID_SHIFT 0 diff --git a/include/linux/mm.h b/include/linux/mm.h index c274f75efcf9..7faeaddd5b88 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2467,6 +2467,20 @@ static inline int early_pfn_to_nid(unsigned long p= fn) extern int __meminit early_pfn_to_nid(unsigned long pfn); #endif =20 +struct meminfo { + struct sysinfo si; + unsigned long pages[NR_LRU_LISTS]; + unsigned long cached; + unsigned long swapcached; + unsigned long anon_pages; + unsigned long mapped; + unsigned long nr_pagetable; + unsigned long dirty_pages; + unsigned long writeback_pages; + unsigned long slab_reclaimable; + unsigned long slab_unreclaimable; +}; + extern void set_dma_reserve(unsigned long new_dma_reserve); extern void memmap_init_range(unsigned long, int, unsigned long, unsigned long, unsigned long, enum meminit_context, @@ -2477,6 +2491,7 @@ extern int __meminit init_per_zone_wmark_min(void); extern void mem_init(void); extern void __init mmap_init(void); extern void show_mem(unsigned int flags, nodemask_t *nodemask); +extern long si_mem_available_mi(struct meminfo *mi); extern long si_mem_available(void); extern void si_meminfo(struct sysinfo * val); extern void si_meminfo_node(struct sysinfo *val, int nid); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 64ada9e650a5..344b546f9e25 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3750,6 +3750,86 @@ static unsigned long mem_cgroup_nr_lru_pages(struc= t mem_cgroup *memcg, return nr; } =20 +static void mem_cgroup_nr_pages(struct mem_cgroup *memcg, int nid, unsig= ned long *pages) +{ + struct mem_cgroup *iter; + int i; + + for_each_mem_cgroup_tree(iter, memcg) { + for (i =3D 0; i < NR_LRU_LISTS; i++) + pages[i] +=3D mem_cgroup_node_nr_lru_pages(iter, nid, BIT(i), false); + } +} + +static void mem_cgroup_si_meminfo(struct sysinfo *si, struct task_struct= *task) +{ + unsigned long memtotal, memused, swapsize; + struct mem_cgroup *memcg; + struct cgroup_subsys_state *css; + + css =3D task_css(task, memory_cgrp_id); + memcg =3D mem_cgroup_from_css(css); + + memtotal =3D READ_ONCE(memcg->memory.max); + + if (memtotal !=3D PAGE_COUNTER_MAX) { + memused =3D page_counter_read(&memcg->memory); + + si->totalram =3D memtotal; + si->freeram =3D (memtotal > memused ? memtotal - memused : 0); + si->sharedram =3D memcg_page_state(memcg, NR_SHMEM); + + si->bufferram =3D nr_blockdev_pages(); + si->totalhigh =3D totalhigh_pages(); + si->freehigh =3D nr_free_highpages(); + si->mem_unit =3D PAGE_SIZE; + } else { + si_meminfo(si); + memused =3D si->totalram - si->freeram; + } + + swapsize =3D READ_ONCE(memcg->memsw.max); + + if (swapsize !=3D PAGE_COUNTER_MAX) { + unsigned long swaptotal, swapused; + + swaptotal =3D swapsize - memtotal; + swapused =3D page_counter_read(&memcg->memsw) - memused; + si->totalswap =3D swaptotal; + /* Due to global reclaim, memory.memsw.usage can be greater than + * (memory.memsw.max - memory.max). */ + si->freeswap =3D (swaptotal > swapused ? swaptotal - swapused : 0); + } else { + si_swapinfo(si); + } + + css_put(css); +} + +void mem_fill_meminfo(struct meminfo *mi, struct task_struct *task) +{ + struct cgroup_subsys_state *memcg_css =3D task_css(task, memory_cgrp_id= ); + struct mem_cgroup *memcg =3D mem_cgroup_from_css(memcg_css); + int nid; + + memset(&mi->pages, 0, sizeof(mi->pages)); + + mem_cgroup_si_meminfo(&mi->si, task); + + for_each_online_node(nid) + mem_cgroup_nr_pages(memcg, nid, mi->pages); + + mi->slab_reclaimable =3D memcg_page_state(memcg, NR_SLAB_RECLAIMABLE_B)= ; + mi->slab_unreclaimable =3D memcg_page_state(memcg, NR_SLAB_UNRECLAIMABL= E_B); + mi->cached =3D memcg_page_state(memcg, NR_FILE_PAGES); + mi->swapcached =3D memcg_page_state(memcg, NR_SWAPCACHE); + mi->anon_pages =3D memcg_page_state(memcg, NR_ANON_MAPPED); + mi->mapped =3D memcg_page_state(memcg, NR_FILE_MAPPED); + mi->nr_pagetable =3D memcg_page_state(memcg, NR_PAGETABLE); + mi->dirty_pages =3D memcg_page_state(memcg, NR_FILE_DIRTY); + mi->writeback_pages =3D memcg_page_state(memcg, NR_WRITEBACK); +} + static int memcg_numa_stat_show(struct seq_file *m, void *v) { struct numa_stat { diff --git a/mm/page_alloc.c b/mm/page_alloc.c index aaa1655cf682..0a3c9dcd2c13 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5551,18 +5551,13 @@ static inline void show_node(struct zone *zone) printk("Node %d ", zone_to_nid(zone)); } =20 -long si_mem_available(void) +long si_mem_available_mi(struct meminfo *mi) { long available; unsigned long pagecache; unsigned long wmark_low =3D 0; - unsigned long pages[NR_LRU_LISTS]; unsigned long reclaimable; struct zone *zone; - int lru; - - for (lru =3D LRU_BASE; lru < NR_LRU_LISTS; lru++) - pages[lru] =3D global_node_page_state(NR_LRU_BASE + lru); =20 for_each_zone(zone) wmark_low +=3D low_wmark_pages(zone); @@ -5571,14 +5566,14 @@ long si_mem_available(void) * Estimate the amount of memory available for userspace allocations, * without causing swapping. */ - available =3D global_zone_page_state(NR_FREE_PAGES) - totalreserve_page= s; + available =3D mi->si.freeram - totalreserve_pages; =20 /* * Not all the page cache can be freed, otherwise the system will * start swapping. Assume at least half of the page cache, or the * low watermark worth of cache, needs to stay. */ - pagecache =3D pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE]; + pagecache =3D mi->pages[LRU_ACTIVE_FILE] + mi->pages[LRU_INACTIVE_FILE]= ; pagecache -=3D min(pagecache / 2, wmark_low); available +=3D pagecache; =20 @@ -5587,14 +5582,27 @@ long si_mem_available(void) * items that are in use, and cannot be freed. Cap this estimate at the * low watermark. */ - reclaimable =3D global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B) + - global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE); + reclaimable =3D mi->slab_reclaimable + global_node_page_state(NR_KERNEL= _MISC_RECLAIMABLE); available +=3D reclaimable - min(reclaimable / 2, wmark_low); =20 if (available < 0) available =3D 0; return available; } + +long si_mem_available(void) +{ + struct meminfo mi; + int lru; + + for (lru =3D LRU_BASE; lru < NR_LRU_LISTS; lru++) + mi.pages[lru] =3D global_node_page_state(NR_LRU_BASE + lru); + + mi.si.freeram =3D global_zone_page_state(NR_FREE_PAGES); + mi.slab_reclaimable =3D global_node_page_state_pages(NR_SLAB_RECLAIMABL= E_B); + + return si_mem_available_mi(&mi); +} EXPORT_SYMBOL_GPL(si_mem_available); =20 void si_meminfo(struct sysinfo *val) --=20 2.29.3