ANDROID: vendor_hooks: account page-mapcount

Support five hooks as follows to account
the amount of multi-mapped pages in kernel:

- android_vh_show_mapcount_pages
- android_vh_do_traversal_lruvec
- android_vh_update_page_mapcount
- android_vh_add_page_to_lrulist
- android_vh_del_page_from_lrulist

Bug: 236578020
Signed-off-by: Peifeng Li <lipeifeng@oppo.com>
Change-Id: Ia2c7015aab442be7dbb496b8b630b9dff59ab935
This commit is contained in:
Peifeng Li 2022-06-23 14:15:35 +08:00 committed by Suren Baghdasaryan
parent 1d2287f56e
commit 3f775b9367
8 changed files with 129 additions and 23 deletions

View File

@ -274,6 +274,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_include_reserved_zone);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_begin); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_begin);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_end); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_end);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mem); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mem);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mapcount_pages);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_traversal_lruvec);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpci_override_toggling); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpci_override_toggling);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_chk_contaminant); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_chk_contaminant);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_get_vbus); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_get_vbus);
@ -393,6 +395,9 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_tcp_recvmsg_stat);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_kmalloc_slab); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_kmalloc_slab);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmap_region); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmap_region);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_update_page_mapcount);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_add_page_to_lrulist);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_del_page_from_lrulist);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_to_unmap_one); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_to_unmap_one);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_id_remove); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_id_remove);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_css_offline); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_css_offline);

View File

@ -4,6 +4,10 @@
#include <linux/huge_mm.h> #include <linux/huge_mm.h>
#include <linux/swap.h> #include <linux/swap.h>
#ifndef __GENKSYMS__
#define PROTECT_TRACE_INCLUDE_PATH
#include <trace/hooks/mm.h>
#endif
/** /**
* page_is_file_lru - should the page be on a file LRU or anon LRU? * page_is_file_lru - should the page be on a file LRU or anon LRU?
@ -48,6 +52,7 @@ static __always_inline void update_lru_size(struct lruvec *lruvec,
static __always_inline void add_page_to_lru_list(struct page *page, static __always_inline void add_page_to_lru_list(struct page *page,
struct lruvec *lruvec, enum lru_list lru) struct lruvec *lruvec, enum lru_list lru)
{ {
trace_android_vh_add_page_to_lrulist(page, false, lru);
update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
list_add(&page->lru, &lruvec->lists[lru]); list_add(&page->lru, &lruvec->lists[lru]);
} }
@ -55,6 +60,7 @@ static __always_inline void add_page_to_lru_list(struct page *page,
static __always_inline void add_page_to_lru_list_tail(struct page *page, static __always_inline void add_page_to_lru_list_tail(struct page *page,
struct lruvec *lruvec, enum lru_list lru) struct lruvec *lruvec, enum lru_list lru)
{ {
trace_android_vh_add_page_to_lrulist(page, false, lru);
update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
list_add_tail(&page->lru, &lruvec->lists[lru]); list_add_tail(&page->lru, &lruvec->lists[lru]);
} }
@ -62,6 +68,7 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page,
static __always_inline void del_page_from_lru_list(struct page *page, static __always_inline void del_page_from_lru_list(struct page *page,
struct lruvec *lruvec, enum lru_list lru) struct lruvec *lruvec, enum lru_list lru)
{ {
trace_android_vh_del_page_from_lrulist(page, false, lru);
list_del(&page->lru); list_del(&page->lru);
update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page)); update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page));
} }

View File

@ -11,6 +11,10 @@
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#ifndef __GENKSYMS__
#define PROTECT_TRACE_INCLUDE_PATH
#include <trace/hooks/mm.h>
#endif
/* /*
* The anon_vma heads a list of private "related" vmas, to scan if * The anon_vma heads a list of private "related" vmas, to scan if
@ -194,7 +198,12 @@ void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *,
static inline void page_dup_rmap(struct page *page, bool compound) static inline void page_dup_rmap(struct page *page, bool compound)
{ {
atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount); bool success = false;
if (!compound)
trace_android_vh_update_page_mapcount(page, true, compound, NULL, &success);
if (!success)
atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount);
} }
/* /*

View File

@ -153,6 +153,22 @@ DECLARE_HOOK(android_vh_drain_all_pages_bypass,
int migratetype, unsigned long did_some_progress, int migratetype, unsigned long did_some_progress,
bool *bypass), bool *bypass),
TP_ARGS(gfp_mask, order, alloc_flags, migratetype, did_some_progress, bypass)); TP_ARGS(gfp_mask, order, alloc_flags, migratetype, did_some_progress, bypass));
DECLARE_HOOK(android_vh_update_page_mapcount,
TP_PROTO(struct page *page, bool inc_size, bool compound,
bool *first_mapping, bool *success),
TP_ARGS(page, inc_size, compound, first_mapping, success));
DECLARE_HOOK(android_vh_add_page_to_lrulist,
TP_PROTO(struct page *page, bool compound, enum lru_list lru),
TP_ARGS(page, compound, lru));
DECLARE_HOOK(android_vh_del_page_from_lrulist,
TP_PROTO(struct page *page, bool compound, enum lru_list lru),
TP_ARGS(page, compound, lru));
DECLARE_HOOK(android_vh_show_mapcount_pages,
TP_PROTO(void *unused),
TP_ARGS(unused));
DECLARE_HOOK(android_vh_do_traversal_lruvec,
TP_PROTO(struct lruvec *lruvec),
TP_ARGS(lruvec));
DECLARE_HOOK(android_vh_cma_drain_all_pages_bypass, DECLARE_HOOK(android_vh_cma_drain_all_pages_bypass,
TP_PROTO(unsigned int migratetype, bool *bypass), TP_PROTO(unsigned int migratetype, bool *bypass),
TP_ARGS(migratetype, bypass)); TP_ARGS(migratetype, bypass));

View File

@ -33,7 +33,7 @@
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/numa.h> #include <linux/numa.h>
#include <linux/page_owner.h> #include <linux/page_owner.h>
#include <trace/hooks/mm.h>
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include "internal.h" #include "internal.h"
@ -2033,6 +2033,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
bool young, write, soft_dirty, pmd_migration = false, uffd_wp = false; bool young, write, soft_dirty, pmd_migration = false, uffd_wp = false;
unsigned long addr; unsigned long addr;
int i; int i;
bool success = false;
VM_BUG_ON(haddr & ~HPAGE_PMD_MASK); VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
VM_BUG_ON_VMA(vma->vm_start > haddr, vma); VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
@ -2164,8 +2165,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
pte = pte_offset_map(&_pmd, addr); pte = pte_offset_map(&_pmd, addr);
BUG_ON(!pte_none(*pte)); BUG_ON(!pte_none(*pte));
set_pte_at(mm, addr, pte, entry); set_pte_at(mm, addr, pte, entry);
if (!pmd_migration) if (!pmd_migration) {
atomic_inc(&page[i]._mapcount); trace_android_vh_update_page_mapcount(&page[i], true,
false, NULL, &success);
if (!success)
atomic_inc(&page[i]._mapcount);
}
pte_unmap(pte); pte_unmap(pte);
} }
@ -2176,8 +2181,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
*/ */
if (compound_mapcount(page) > 1 && if (compound_mapcount(page) > 1 &&
!TestSetPageDoubleMap(page)) { !TestSetPageDoubleMap(page)) {
for (i = 0; i < HPAGE_PMD_NR; i++) for (i = 0; i < HPAGE_PMD_NR; i++) {
atomic_inc(&page[i]._mapcount); trace_android_vh_update_page_mapcount(&page[i], true,
false, NULL, &success);
if (!success)
atomic_inc(&page[i]._mapcount);
}
} }
lock_page_memcg(page); lock_page_memcg(page);
@ -2186,8 +2195,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
__dec_lruvec_page_state(page, NR_ANON_THPS); __dec_lruvec_page_state(page, NR_ANON_THPS);
if (TestClearPageDoubleMap(page)) { if (TestClearPageDoubleMap(page)) {
/* No need in mapcount reference anymore */ /* No need in mapcount reference anymore */
for (i = 0; i < HPAGE_PMD_NR; i++) for (i = 0; i < HPAGE_PMD_NR; i++) {
atomic_dec(&page[i]._mapcount); trace_android_vh_update_page_mapcount(&page[i],
false, false, NULL, &success);
if (!success)
atomic_dec(&page[i]._mapcount);
}
} }
} }
unlock_page_memcg(page); unlock_page_memcg(page);

View File

@ -5646,6 +5646,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
free_pcp, free_pcp,
global_zone_page_state(NR_FREE_CMA_PAGES)); global_zone_page_state(NR_FREE_CMA_PAGES));
trace_android_vh_show_mapcount_pages(NULL);
for_each_online_pgdat(pgdat) { for_each_online_pgdat(pgdat) {
if (show_mem_node_skip(filter, pgdat->node_id, nodemask)) if (show_mem_node_skip(filter, pgdat->node_id, nodemask))
continue; continue;

View File

@ -1113,6 +1113,7 @@ void do_page_add_anon_rmap(struct page *page,
{ {
bool compound = flags & RMAP_COMPOUND; bool compound = flags & RMAP_COMPOUND;
bool first; bool first;
bool success = false;
if (unlikely(PageKsm(page))) if (unlikely(PageKsm(page)))
lock_page_memcg(page); lock_page_memcg(page);
@ -1126,7 +1127,10 @@ void do_page_add_anon_rmap(struct page *page,
mapcount = compound_mapcount_ptr(page); mapcount = compound_mapcount_ptr(page);
first = atomic_inc_and_test(mapcount); first = atomic_inc_and_test(mapcount);
} else { } else {
first = atomic_inc_and_test(&page->_mapcount); trace_android_vh_update_page_mapcount(page, true, compound,
&first, &success);
if (!success)
first = atomic_inc_and_test(&page->_mapcount);
} }
if (first) { if (first) {
@ -1200,13 +1204,22 @@ void __page_add_new_anon_rmap(struct page *page,
void page_add_file_rmap(struct page *page, bool compound) void page_add_file_rmap(struct page *page, bool compound)
{ {
int i, nr = 1; int i, nr = 1;
bool first_mapping;
bool success = false;
VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page); VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page);
lock_page_memcg(page); lock_page_memcg(page);
if (compound && PageTransHuge(page)) { if (compound && PageTransHuge(page)) {
for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
if (atomic_inc_and_test(&page[i]._mapcount)) trace_android_vh_update_page_mapcount(&page[i], true,
nr++; compound, &first_mapping, &success);
if ((success)) {
if (first_mapping)
nr++;
} else {
if (atomic_inc_and_test(&page[i]._mapcount))
nr++;
}
} }
if (!atomic_inc_and_test(compound_mapcount_ptr(page))) if (!atomic_inc_and_test(compound_mapcount_ptr(page)))
goto out; goto out;
@ -1222,8 +1235,15 @@ void page_add_file_rmap(struct page *page, bool compound)
if (PageMlocked(page)) if (PageMlocked(page))
clear_page_mlock(compound_head(page)); clear_page_mlock(compound_head(page));
} }
if (!atomic_inc_and_test(&page->_mapcount)) trace_android_vh_update_page_mapcount(page, true,
goto out; compound, &first_mapping, &success);
if (success) {
if (!first_mapping)
goto out;
} else {
if (!atomic_inc_and_test(&page->_mapcount))
goto out;
}
} }
__mod_lruvec_page_state(page, NR_FILE_MAPPED, nr); __mod_lruvec_page_state(page, NR_FILE_MAPPED, nr);
out: out:
@ -1233,6 +1253,8 @@ void page_add_file_rmap(struct page *page, bool compound)
static void page_remove_file_rmap(struct page *page, bool compound) static void page_remove_file_rmap(struct page *page, bool compound)
{ {
int i, nr = 1; int i, nr = 1;
bool first_mapping;
bool success = false;
VM_BUG_ON_PAGE(compound && !PageHead(page), page); VM_BUG_ON_PAGE(compound && !PageHead(page), page);
@ -1246,8 +1268,15 @@ static void page_remove_file_rmap(struct page *page, bool compound)
/* page still mapped by someone else? */ /* page still mapped by someone else? */
if (compound && PageTransHuge(page)) { if (compound && PageTransHuge(page)) {
for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
if (atomic_add_negative(-1, &page[i]._mapcount)) trace_android_vh_update_page_mapcount(&page[i], false,
nr++; compound, &first_mapping, &success);
if (success) {
if (first_mapping)
nr++;
} else {
if (atomic_add_negative(-1, &page[i]._mapcount))
nr++;
}
} }
if (!atomic_add_negative(-1, compound_mapcount_ptr(page))) if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
return; return;
@ -1256,8 +1285,15 @@ static void page_remove_file_rmap(struct page *page, bool compound)
else else
__dec_node_page_state(page, NR_FILE_PMDMAPPED); __dec_node_page_state(page, NR_FILE_PMDMAPPED);
} else { } else {
if (!atomic_add_negative(-1, &page->_mapcount)) trace_android_vh_update_page_mapcount(page, false,
return; compound, &first_mapping, &success);
if (success) {
if (!first_mapping)
return;
} else {
if (!atomic_add_negative(-1, &page->_mapcount))
return;
}
} }
/* /*
@ -1274,6 +1310,8 @@ static void page_remove_file_rmap(struct page *page, bool compound)
static void page_remove_anon_compound_rmap(struct page *page) static void page_remove_anon_compound_rmap(struct page *page)
{ {
int i, nr; int i, nr;
bool first_mapping;
bool success = false;
if (!atomic_add_negative(-1, compound_mapcount_ptr(page))) if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
return; return;
@ -1293,8 +1331,15 @@ static void page_remove_anon_compound_rmap(struct page *page)
* them are still mapped. * them are still mapped.
*/ */
for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
if (atomic_add_negative(-1, &page[i]._mapcount)) trace_android_vh_update_page_mapcount(&page[i], false,
nr++; false, &first_mapping, &success);
if (success) {
if (first_mapping)
nr++;
} else {
if (atomic_add_negative(-1, &page[i]._mapcount))
nr++;
}
} }
/* /*
@ -1324,6 +1369,8 @@ static void page_remove_anon_compound_rmap(struct page *page)
*/ */
void page_remove_rmap(struct page *page, bool compound) void page_remove_rmap(struct page *page, bool compound)
{ {
bool first_mapping;
bool success = false;
lock_page_memcg(page); lock_page_memcg(page);
if (!PageAnon(page)) { if (!PageAnon(page)) {
@ -1336,10 +1383,16 @@ void page_remove_rmap(struct page *page, bool compound)
goto out; goto out;
} }
/* page still mapped by someone else? */ trace_android_vh_update_page_mapcount(page, false,
if (!atomic_add_negative(-1, &page->_mapcount)) compound, &first_mapping, &success);
goto out; if (success) {
if (!first_mapping)
goto out;
} else {
/* page still mapped by someone else? */
if (!atomic_add_negative(-1, &page->_mapcount))
goto out;
}
/* /*
* We use the irq-unsafe __{inc|mod}_zone_page_stat because * We use the irq-unsafe __{inc|mod}_zone_page_stat because
* these counters are not modified in interrupt context, and * these counters are not modified in interrupt context, and

View File

@ -1727,6 +1727,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
case 0: case 0:
nr_taken += nr_pages; nr_taken += nr_pages;
nr_zone_taken[page_zonenum(page)] += nr_pages; nr_zone_taken[page_zonenum(page)] += nr_pages;
trace_android_vh_del_page_from_lrulist(page, false, lru);
list_move(&page->lru, dst); list_move(&page->lru, dst);
break; break;
@ -1901,6 +1902,7 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec,
nr_pages = thp_nr_pages(page); nr_pages = thp_nr_pages(page);
update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); update_lru_size(lruvec, lru, page_zonenum(page), nr_pages);
list_move(&page->lru, &lruvec->lists[lru]); list_move(&page->lru, &lruvec->lists[lru]);
trace_android_vh_add_page_to_lrulist(page, false, lru);
if (put_page_testzero(page)) { if (put_page_testzero(page)) {
__ClearPageLRU(page); __ClearPageLRU(page);