Uncharged pages are tricky to track by their essential "uncharged" nature. To maintain good accounting, introduce a vmstat counter tracking all uncharged pages. Since this is only meaningful when cgroups are configured, only expose the counter when CONFIG_MEMCG is set. Confirmed that these work as expected at a high level by mounting a btrfs using AS_UNCHARGED for metadata pages, and seeing the counter rise with fs usage then go back to a minimal level after drop_caches and finally down to 0 after unmounting the fs. Suggested-by: Shakeel Butt Acked-by: Shakeel Butt Tested-by: syzbot@syzkaller.appspotmail.com Signed-off-by: Boris Burkov --- include/linux/mmzone.h | 3 +++ mm/filemap.c | 17 +++++++++++++++++ mm/vmstat.c | 3 +++ 3 files changed, 23 insertions(+) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index fe13ad175fed..8166dadb6a33 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -259,6 +259,9 @@ enum node_stat_item { NR_HUGETLB, #endif NR_BALLOON_PAGES, +#ifdef CONFIG_MEMCG + NR_UNCHARGED_FILE_PAGES, +#endif NR_VM_NODE_STAT_ITEMS }; diff --git a/mm/filemap.c b/mm/filemap.c index 5004a2cfa0cc..514ccf7c8aa3 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -146,6 +146,19 @@ static void page_cache_delete(struct address_space *mapping, mapping->nrpages -= nr; } +#ifdef CONFIG_MEMCG +static void filemap_mod_uncharged_vmstat(struct folio *folio, int sign) +{ + long nr = folio_nr_pages(folio) * sign; + + mod_node_page_state(folio_pgdat(folio), NR_UNCHARGED_FILE_PAGES, nr); +} +#else +static void filemap_mod_uncharged_vmstat(struct folio *folio, int sign) +{ +} +#endif + static void filemap_unaccount_folio(struct address_space *mapping, struct folio *folio) { @@ -190,6 +203,8 @@ static void filemap_unaccount_folio(struct address_space *mapping, __lruvec_stat_mod_folio(folio, NR_FILE_THPS, -nr); filemap_nr_thps_dec(mapping); } + if (test_bit(AS_UNCHARGED, &folio->mapping->flags)) + filemap_mod_uncharged_vmstat(folio, -1); /* * At this point folio must be either written or cleaned by @@ -987,6 +1002,8 @@ int filemap_add_folio(struct address_space *mapping, struct folio *folio, if (!(gfp & __GFP_WRITE) && shadow) workingset_refault(folio, shadow); folio_add_lru(folio); + if (!charge_mem_cgroup) + filemap_mod_uncharged_vmstat(folio, 1); } return ret; } diff --git a/mm/vmstat.c b/mm/vmstat.c index e74f0b2a1021..135f7bab4de6 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1290,6 +1290,9 @@ const char * const vmstat_text[] = { [I(NR_HUGETLB)] = "nr_hugetlb", #endif [I(NR_BALLOON_PAGES)] = "nr_balloon_pages", +#ifdef CONFIG_MEMCG + [I(NR_UNCHARGED_FILE_PAGES)] = "nr_uncharged_file_pages", +#endif #undef I /* system-wide enum vm_stat_item counters */ -- 2.50.1