From 6356ed35b9e7f51b8c43af4277f5c7395cc7b864 Mon Sep 17 00:00:00 2001 From: Lincheng Yang Date: Thu, 7 Sep 2023 11:19:43 +0800 Subject: [PATCH] ANDROID: add vendor hook of add/delete/iterate node for swap_avail_heads Our Android phones occur Panic as follows: [77522.303024][ T9734] Call trace: [77522.303039][ T9734] dump_backtrace.cfi_jt+0x0/0x8 [77522.303052][ T9734] dump_stack_lvl+0xc4/0x140 [77522.303061][ T9734] dump_stack+0x1c/0x2c [77522.303123][ T9734] mrdump_common_die+0x3a8/0x544 [mrdump] [77522.303177][ T9734] ipanic_die+0x24/0x38 [mrdump] [77522.303189][ T9734] die+0x340/0x698 [77522.303199][ T9734] bug_handler+0x48/0x108 [77522.303210][ T9734] brk_handler+0xac/0x1a8 [77522.303221][ T9734] do_debug_exception+0xe0/0x1e0 [77522.303233][ T9734] el1_dbg+0x38/0x54 [77522.303242][ T9734] el1_sync_handler+0x40/0x88 [77522.303255][ T9734] el1_sync+0x8c/0x140 [77522.303264][ T9734] plist_requeue+0xd4/0x110 [77522.303297][ T9734] tran_get_swap_pages+0xc8/0x364 [memfusion] [77522.303329][ T9734] probe_android_vh_get_swap_page+0x1b4/0x220 [memfusion] [77522.303342][ T9734] get_swap_page+0x258/0x304 [77522.303352][ T9734] shrink_page_list+0xe00/0x1e0c [77522.303361][ T9734] shrink_inactive_list+0x2f4/0xac8 [77522.303373][ T9734] shrink_lruvec+0x1a4/0x34c [77522.303383][ T9734] shrink_node_memcgs+0x84/0x3b0 [77522.303391][ T9734] shrink_node+0x2c4/0x6e4 [77522.303400][ T9734] shrink_zones+0x16c/0x29c [77522.303410][ T9734] do_try_to_free_pages+0xe4/0x2bc [77522.303418][ T9734] try_to_free_pages+0x388/0x7b4 [77522.303429][ T9734] __alloc_pages_direct_reclaim+0x88/0x278 [77522.303438][ T9734] __alloc_pages_slowpath+0x464/0xb24 [77522.303447][ T9734] __alloc_pages_nodemask+0x1f4/0x3dc [77522.303458][ T9734] do_anonymous_page+0x164/0x914 [77522.303466][ T9734] handle_pte_fault+0x15c/0x9f8 [77522.303476][ T9734] ___handle_speculative_fault+0x234/0xe18 [77522.303485][ T9734] __handle_speculative_fault+0x78/0x21c [77522.303497][ T9734] do_page_fault+0x36c/0x754 [77522.303506][ T9734] do_translation_fault+0x48/0x64 [77522.303514][ T9734] do_mem_abort+0x6c/0x164 [77522.303522][ T9734] el0_da+0x24/0x34 [77522.303531][ T9734] el0_sync_handler+0xc8/0xf0 [77522.303539][ T9734] el0_sync+0x1b4/0x1c0 The analysis shows that when we iterate the swap_avail_heads list, we get node A, but before we access node A, node A is maybe deleted, and by the time we actually access node A, it no longer exists, as follows: CPU1 thread1 CPU2 thread2 plist_for_each_entry_safe() get si->avail_lists[node] from swap_avail_heads remove si->avail_lists[node] from swap_avail_heads plist_requeue(&si->avail_lists[node]) BUG_ON(plist_node_empty(node)); // trigger Due to when we use vendor hook of get_swap_page, the get_swap_pages() function is overridden, use our own spin_lock to protect when iterate swap_avail_heads list, but now use native swap_avail_lock spin_lock protect when the swap_avail_heads list to add and delete nodes, so there will be concurrent access. So add vendor hook of add/delete/iterate node for avail_list, in this way, we can use our own spin_lock to protect the swap_avail_heads list to add, delete and iterate node. Due to enable_swap_info function to call vendor hook of add_to_avail_list, need first init swap_avail_heads, so also add vendor hook of swap_avail_heads_init. Due to the vendor hook of __cgroup_throttle_swaprate need to call blkcg_schedule_throttle function, so export it also. Bug: 225795494 Change-Id: I03107cbda6310fa7ae85e41b8cf1fa8225cafe78 Signed-off-by: Lincheng Yang Suggested-by: Bing Han --- block/blk-cgroup.c | 1 + drivers/android/vendor_hooks.c | 4 ++++ include/trace/hooks/mm.h | 12 ++++++++++++ mm/swapfile.c | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index d7054c186845..10cc2e6fd6c6 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1794,6 +1794,7 @@ void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay) current->use_memdelay = use_memdelay; set_notify_resume(current); } +EXPORT_SYMBOL_GPL(blkcg_schedule_throttle); /** * blkcg_add_delay - add delay to this blkg diff --git a/drivers/android/vendor_hooks.c b/drivers/android/vendor_hooks.c index 815c5efb5c22..8b1929a3a486 100644 --- a/drivers/android/vendor_hooks.c +++ b/drivers/android/vendor_hooks.c @@ -468,12 +468,16 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_free_swap_slot); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_free_swap_slot); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_get_swap_page); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_swap_page); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_add_to_avail_list); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_del_from_avail_list); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh___cgroup_throttle_swaprate); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_madvise_cold_or_pageout); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_isolated_for_reclaim); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_inactive_is_low); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_snapshot_refaults); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_account_swap_pages); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_unuse_swap_page); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_swap_avail_heads_init); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_init_swap_info_struct); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_si_swapinfo); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_alloc_si); diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h index 480880a49d32..dd980641cb27 100644 --- a/include/trace/hooks/mm.h +++ b/include/trace/hooks/mm.h @@ -287,6 +287,15 @@ DECLARE_HOOK(android_vh_get_swap_page, TP_PROTO(struct page *page, swp_entry_t *entry, struct swap_slots_cache *cache, bool *found), TP_ARGS(page, entry, cache, found)); +DECLARE_HOOK(android_vh_add_to_avail_list, + TP_PROTO(struct swap_info_struct *p, bool *skip), + TP_ARGS(p, skip)); +DECLARE_HOOK(android_vh_del_from_avail_list, + TP_PROTO(struct swap_info_struct *p, bool *skip), + TP_ARGS(p, skip)); +DECLARE_HOOK(android_vh___cgroup_throttle_swaprate, + TP_PROTO(int nid, bool *skip), + TP_ARGS(nid, skip)); DECLARE_HOOK(android_vh_madvise_cold_or_pageout, TP_PROTO(struct vm_area_struct *vma, bool *allow_shared), TP_ARGS(vma, allow_shared)); @@ -299,6 +308,9 @@ DECLARE_HOOK(android_vh_account_swap_pages, DECLARE_HOOK(android_vh_unuse_swap_page, TP_PROTO(struct swap_info_struct *si, struct page *page), TP_ARGS(si, page)); +DECLARE_HOOK(android_vh_swap_avail_heads_init, + TP_PROTO(struct plist_head *swap_avail_heads), + TP_ARGS(swap_avail_heads)); DECLARE_HOOK(android_vh_init_swap_info_struct, TP_PROTO(struct swap_info_struct *p, struct plist_head *swap_avail_heads), TP_ARGS(p, swap_avail_heads)); diff --git a/mm/swapfile.c b/mm/swapfile.c index a31d90fdb19f..cc1ce66cb492 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -675,6 +675,12 @@ static void __del_from_avail_list(struct swap_info_struct *p) static void del_from_avail_list(struct swap_info_struct *p) { + bool skip = false; + + trace_android_vh_del_from_avail_list(p, &skip); + if (skip) + return; + spin_lock(&swap_avail_lock); __del_from_avail_list(p); spin_unlock(&swap_avail_lock); @@ -700,6 +706,11 @@ static void swap_range_alloc(struct swap_info_struct *si, unsigned long offset, static void add_to_avail_list(struct swap_info_struct *p) { int nid; + bool skip = false; + + trace_android_vh_add_to_avail_list(p, &skip); + if (skip) + return; spin_lock(&swap_avail_lock); for_each_node(nid) { @@ -3394,6 +3405,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (swap_flags & SWAP_FLAG_PREFER) prio = (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; + + trace_android_vh_swap_avail_heads_init(swap_avail_heads); enable_swap_info(p, prio, swap_map, cluster_info, frontswap_map); trace_android_vh_init_swap_info_struct(p, swap_avail_heads); @@ -3848,6 +3861,7 @@ void __cgroup_throttle_swaprate(struct page *page, gfp_t gfp_mask) { struct swap_info_struct *si, *next; int nid = page_to_nid(page); + bool skip = false; if (!(gfp_mask & __GFP_IO)) return; @@ -3862,6 +3876,10 @@ void __cgroup_throttle_swaprate(struct page *page, gfp_t gfp_mask) if (current->throttle_queue) return; + trace_android_vh___cgroup_throttle_swaprate(nid, &skip); + if (skip) + return; + spin_lock(&swap_avail_lock); plist_for_each_entry_safe(si, next, &swap_avail_heads[nid], avail_lists[nid]) {