18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mm/memcg_control.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/memcontrol.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/cgroup-defs.h> 108c2ecf20Sopenharmony_ci#include <linux/cgroup.h> 118c2ecf20Sopenharmony_ci#include <linux/zswapd.h> 128c2ecf20Sopenharmony_ci#include "internal.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "zswapd_internal.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#ifdef CONFIG_HYPERHOLD_MEMCG 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct list_head score_head; 198c2ecf20Sopenharmony_cibool score_head_inited; 208c2ecf20Sopenharmony_ciDEFINE_RWLOCK(score_list_lock); 218c2ecf20Sopenharmony_ciDEFINE_MUTEX(reclaim_para_lock); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/** 248c2ecf20Sopenharmony_ci * get_next_memcg - iterate over memory cgroup score_list 258c2ecf20Sopenharmony_ci * @prev: previously returned memcg, NULL on first invocation 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Returns references to the next memg on score_list of @prev, 288c2ecf20Sopenharmony_ci * or %NULL after a full round-trip. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Caller must pass the return value in @prev on subsequent 318c2ecf20Sopenharmony_ci * invocations for reference counting, or use get_next_memcg_break() 328c2ecf20Sopenharmony_ci * to cancel a walk before the round-trip is complete. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistruct mem_cgroup *get_next_memcg(struct mem_cgroup *prev) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = NULL; 378c2ecf20Sopenharmony_ci struct list_head *pos = NULL; 388c2ecf20Sopenharmony_ci unsigned long flags; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (unlikely(!score_head_inited)) 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci read_lock_irqsave(&score_list_lock, flags); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (unlikely(!prev)) 468c2ecf20Sopenharmony_ci pos = &score_head; 478c2ecf20Sopenharmony_ci else 488c2ecf20Sopenharmony_ci pos = &(prev->score_node); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (list_empty(pos)) /* deleted node */ 518c2ecf20Sopenharmony_ci goto unlock; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (pos->next == &score_head) 548c2ecf20Sopenharmony_ci goto unlock; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci memcg = list_entry(pos->next, 578c2ecf20Sopenharmony_ci struct mem_cgroup, score_node); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!css_tryget(&memcg->css)) 608c2ecf20Sopenharmony_ci memcg = NULL; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciunlock: 638c2ecf20Sopenharmony_ci read_unlock_irqrestore(&score_list_lock, flags); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (prev) 668c2ecf20Sopenharmony_ci css_put(&prev->css); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return memcg; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid get_next_memcg_break(struct mem_cgroup *memcg) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci if (memcg) 748c2ecf20Sopenharmony_ci css_put(&memcg->css); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct mem_cgroup *get_prev_memcg(struct mem_cgroup *next) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = NULL; 808c2ecf20Sopenharmony_ci struct list_head *pos = NULL; 818c2ecf20Sopenharmony_ci unsigned long flags; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (unlikely(!score_head_inited)) 848c2ecf20Sopenharmony_ci return NULL; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci read_lock_irqsave(&score_list_lock, flags); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (unlikely(!next)) 898c2ecf20Sopenharmony_ci pos = &score_head; 908c2ecf20Sopenharmony_ci else 918c2ecf20Sopenharmony_ci pos = &next->score_node; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (list_empty(pos)) /* deleted node */ 948c2ecf20Sopenharmony_ci goto unlock; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (pos->prev == &score_head) 978c2ecf20Sopenharmony_ci goto unlock; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci memcg = list_entry(pos->prev, 1008c2ecf20Sopenharmony_ci struct mem_cgroup, score_node); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (unlikely(!memcg)) 1038c2ecf20Sopenharmony_ci goto unlock; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (!css_tryget(&memcg->css)) 1068c2ecf20Sopenharmony_ci memcg = NULL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciunlock: 1098c2ecf20Sopenharmony_ci read_unlock_irqrestore(&score_list_lock, flags); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (next) 1128c2ecf20Sopenharmony_ci css_put(&next->css); 1138c2ecf20Sopenharmony_ci return memcg; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid get_prev_memcg_break(struct mem_cgroup *memcg) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (memcg) 1198c2ecf20Sopenharmony_ci css_put(&memcg->css); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_civoid memcg_app_score_update(struct mem_cgroup *target) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct list_head *pos = NULL; 1258c2ecf20Sopenharmony_ci struct list_head *tmp; 1268c2ecf20Sopenharmony_ci unsigned long flags; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci write_lock_irqsave(&score_list_lock, flags); 1298c2ecf20Sopenharmony_ci list_for_each_prev_safe(pos, tmp, &score_head) { 1308c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = list_entry(pos, 1318c2ecf20Sopenharmony_ci struct mem_cgroup, score_node); 1328c2ecf20Sopenharmony_ci if (atomic64_read(&memcg->memcg_reclaimed.app_score) < 1338c2ecf20Sopenharmony_ci atomic64_read(&target->memcg_reclaimed.app_score)) 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci list_move_tail(&target->score_node, pos); 1378c2ecf20Sopenharmony_ci write_unlock_irqrestore(&score_list_lock, flags); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic u64 mem_cgroup_app_score_read(struct cgroup_subsys_state *css, 1418c2ecf20Sopenharmony_ci struct cftype *cft) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(css); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return atomic64_read(&memcg->memcg_reclaimed.app_score); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int mem_cgroup_app_score_write(struct cgroup_subsys_state *css, 1498c2ecf20Sopenharmony_ci struct cftype *cft, u64 val) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(css); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (val > MAX_APP_SCORE) 1548c2ecf20Sopenharmony_ci return -EINVAL; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (atomic64_read(&memcg->memcg_reclaimed.app_score) != val) { 1578c2ecf20Sopenharmony_ci atomic64_set(&memcg->memcg_reclaimed.app_score, val); 1588c2ecf20Sopenharmony_ci memcg_app_score_update(memcg); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic unsigned long move_pages_to_page_list(struct lruvec *lruvec, enum lru_list lru, 1658c2ecf20Sopenharmony_ci struct list_head *page_list) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct list_head *src = &lruvec->lists[lru]; 1688c2ecf20Sopenharmony_ci unsigned long nr_isolated = 0; 1698c2ecf20Sopenharmony_ci struct page *page; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci while (!list_empty(src)) { 1728c2ecf20Sopenharmony_ci page = lru_to_page(src); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (PageUnevictable(page)) 1758c2ecf20Sopenharmony_ci continue; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (likely(get_page_unless_zero(page))) { 1788c2ecf20Sopenharmony_ci if (isolate_lru_page(page)) { 1798c2ecf20Sopenharmony_ci put_page(page); 1808c2ecf20Sopenharmony_ci continue; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci put_page(page); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci } else { 1858c2ecf20Sopenharmony_ci continue; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (PageUnevictable(page)) { 1908c2ecf20Sopenharmony_ci putback_lru_page(page); 1918c2ecf20Sopenharmony_ci continue; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (PageAnon(page) && !PageSwapBacked(page)) { 1958c2ecf20Sopenharmony_ci putback_lru_page(page); 1968c2ecf20Sopenharmony_ci continue; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci list_add(&page->lru, page_list); 2008c2ecf20Sopenharmony_ci nr_isolated++; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return nr_isolated; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ciunsigned long reclaim_all_anon_memcg(struct pglist_data *pgdat, struct mem_cgroup *memcg) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); 2108c2ecf20Sopenharmony_ci unsigned long nr_reclaimed; 2118c2ecf20Sopenharmony_ci LIST_HEAD(page_list); 2128c2ecf20Sopenharmony_ci struct page *page; 2138c2ecf20Sopenharmony_ci struct reclaim_stat stat = {}; 2148c2ecf20Sopenharmony_ci struct scan_control sc = { 2158c2ecf20Sopenharmony_ci .gfp_mask = GFP_KERNEL, 2168c2ecf20Sopenharmony_ci .may_writepage = 1, 2178c2ecf20Sopenharmony_ci .may_unmap = 1, 2188c2ecf20Sopenharmony_ci .may_swap = 1, 2198c2ecf20Sopenharmony_ci }; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci#ifdef CONFIG_RECLAIM_ACCT 2228c2ecf20Sopenharmony_ci reclaimacct_substage_start(RA_SHRINKANON); 2238c2ecf20Sopenharmony_ci#endif 2248c2ecf20Sopenharmony_ci count_vm_event(FREEZE_RECLAIME_COUNT); 2258c2ecf20Sopenharmony_ci move_pages_to_page_list(lruvec, LRU_INACTIVE_ANON, &page_list); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci nr_reclaimed = shrink_page_list(&page_list, pgdat, &sc, &stat, true); 2288c2ecf20Sopenharmony_ci count_vm_event(FREEZE_RECLAIMED); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci while (!list_empty(&page_list)) { 2318c2ecf20Sopenharmony_ci page = lru_to_page(&page_list); 2328c2ecf20Sopenharmony_ci list_del(&page->lru); 2338c2ecf20Sopenharmony_ci putback_lru_page(page); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci#ifdef CONFIG_RECLAIM_ACCT 2378c2ecf20Sopenharmony_ci reclaimacct_substage_end(RA_SHRINKANON, nr_reclaimed, NULL); 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return nr_reclaimed; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic ssize_t memcg_force_shrink_anon(struct kernfs_open_file *of, 2448c2ecf20Sopenharmony_ci char *buf, size_t nbytes, 2458c2ecf20Sopenharmony_ci loff_t off) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); 2488c2ecf20Sopenharmony_ci struct pglist_data *pgdat; 2498c2ecf20Sopenharmony_ci int nid; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for_each_online_node(nid) { 2528c2ecf20Sopenharmony_ci pgdat = NODE_DATA(nid); 2538c2ecf20Sopenharmony_ci reclaim_all_anon_memcg(pgdat, memcg); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return nbytes; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int memcg_name_show(struct seq_file *m, void *v) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci seq_printf(m, "%s\n", memcg->name); 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic ssize_t memcg_name_write(struct kernfs_open_file *of, char *buf, 2688c2ecf20Sopenharmony_ci size_t nbytes, loff_t off) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci buf = strstrip(buf); 2738c2ecf20Sopenharmony_ci if (nbytes >= MEM_CGROUP_NAME_MAX_LEN) 2748c2ecf20Sopenharmony_ci return -EINVAL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci mutex_lock(&reclaim_para_lock); 2778c2ecf20Sopenharmony_ci if (memcg) 2788c2ecf20Sopenharmony_ci strcpy(memcg->name, buf); 2798c2ecf20Sopenharmony_ci mutex_unlock(&reclaim_para_lock); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return nbytes; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int memcg_total_info_per_app_show(struct seq_file *m, void *v) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = NULL; 2878c2ecf20Sopenharmony_ci struct mem_cgroup_per_node *mz = NULL; 2888c2ecf20Sopenharmony_ci struct lruvec *lruvec = NULL; 2898c2ecf20Sopenharmony_ci unsigned long anon_size; 2908c2ecf20Sopenharmony_ci unsigned long zram_compress_size; 2918c2ecf20Sopenharmony_ci unsigned long eswap_compress_size; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci while ((memcg = get_next_memcg(memcg))) { 2958c2ecf20Sopenharmony_ci mz = mem_cgroup_nodeinfo(memcg, 0); 2968c2ecf20Sopenharmony_ci if (!mz) { 2978c2ecf20Sopenharmony_ci get_next_memcg_break(memcg); 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci lruvec = &mz->lruvec; 3028c2ecf20Sopenharmony_ci if (!lruvec) { 3038c2ecf20Sopenharmony_ci get_next_memcg_break(memcg); 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci anon_size = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) + 3088c2ecf20Sopenharmony_ci lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, MAX_NR_ZONES); 3098c2ecf20Sopenharmony_ci zram_compress_size = memcg_data_size(memcg, CACHE_SIZE); 3108c2ecf20Sopenharmony_ci eswap_compress_size = memcg_data_size(memcg, SWAP_SIZE); 3118c2ecf20Sopenharmony_ci anon_size *= PAGE_SIZE / SZ_1K; 3128c2ecf20Sopenharmony_ci zram_compress_size /= SZ_1K; 3138c2ecf20Sopenharmony_ci eswap_compress_size /= SZ_1K; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!strlen(memcg->name)) 3168c2ecf20Sopenharmony_ci continue; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci seq_printf(m, "%s %lu %lu %lu\n", memcg->name, anon_size, 3198c2ecf20Sopenharmony_ci zram_compress_size, eswap_compress_size); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int memcg_ub_ufs2zram_ratio_write(struct cgroup_subsys_state *css, 3268c2ecf20Sopenharmony_ci struct cftype *cft, u64 val) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(css); 3298c2ecf20Sopenharmony_ci const unsigned int ratio = 100; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (val > ratio) 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci atomic64_set(&memcg->memcg_reclaimed.ub_ufs2zram_ratio, val); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic u64 memcg_ub_ufs2zram_ratio_read(struct cgroup_subsys_state *css, struct cftype *cft) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(css); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return atomic64_read(&memcg->memcg_reclaimed.ub_ufs2zram_ratio); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int memcg_force_swapin_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(css); 3498c2ecf20Sopenharmony_ci u64 size; 3508c2ecf20Sopenharmony_ci const unsigned int ratio = 100; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci size = memcg_data_size(memcg, SWAP_SIZE); 3538c2ecf20Sopenharmony_ci size = div_u64(atomic64_read(&memcg->memcg_reclaimed.ub_ufs2zram_ratio) * size, ratio); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci swapin_memcg(memcg, size); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci#ifdef CONFIG_MEM_PURGEABLE 3618c2ecf20Sopenharmony_cistatic unsigned long purgeable_memcg_node(pg_data_t *pgdata, 3628c2ecf20Sopenharmony_ci struct scan_control *sc, struct mem_cgroup *memcg) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci unsigned long nr = 0; 3658c2ecf20Sopenharmony_ci struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdata); 3668c2ecf20Sopenharmony_ci if (!lruvec) 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci shrink_list(LRU_ACTIVE_PURGEABLE, -1, lruvec, sc); 3708c2ecf20Sopenharmony_ci nr += shrink_list(LRU_INACTIVE_PURGEABLE, -1, lruvec, sc); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci pr_info("reclaim %lu purgeable pages \n", nr); 3738c2ecf20Sopenharmony_ci return nr; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int memcg_force_shrink_purgeable_bysize(struct cgroup_subsys_state *css, 3778c2ecf20Sopenharmony_ci struct cftype *cft, u64 reclaim_size) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct mem_cgroup *memcg = mem_cgroup_from_css(css); 3808c2ecf20Sopenharmony_ci if (!memcg) 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (reclaim_size == 0) { 3848c2ecf20Sopenharmony_ci pr_err("reclaim_size is zero, skip shrink\n"); 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci struct scan_control sc = { 3898c2ecf20Sopenharmony_ci .gfp_mask = GFP_KERNEL, 3908c2ecf20Sopenharmony_ci .order = 0, 3918c2ecf20Sopenharmony_ci .priority = DEF_PRIORITY, 3928c2ecf20Sopenharmony_ci .may_deactivate = DEACTIVATE_ANON, 3938c2ecf20Sopenharmony_ci .may_writepage = 1, 3948c2ecf20Sopenharmony_ci .may_unmap = 1, 3958c2ecf20Sopenharmony_ci .may_swap = 1, 3968c2ecf20Sopenharmony_ci .reclaim_idx = MAX_NR_ZONES -1, 3978c2ecf20Sopenharmony_ci }; 3988c2ecf20Sopenharmony_ci int nid = 0; 3998c2ecf20Sopenharmony_ci sc.nr_to_reclaim = div_u64(reclaim_size, PAGE_SIZE); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci for_each_node_state(nid, N_MEMORY) 4028c2ecf20Sopenharmony_ci purgeable_memcg_node(NODE_DATA(nid), &sc, memcg); 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci#endif 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic struct cftype memcg_policy_files[] = { 4088c2ecf20Sopenharmony_ci { 4098c2ecf20Sopenharmony_ci .name = "name", 4108c2ecf20Sopenharmony_ci .write = memcg_name_write, 4118c2ecf20Sopenharmony_ci .seq_show = memcg_name_show, 4128c2ecf20Sopenharmony_ci }, 4138c2ecf20Sopenharmony_ci { 4148c2ecf20Sopenharmony_ci .name = "ub_ufs2zram_ratio", 4158c2ecf20Sopenharmony_ci .write_u64 = memcg_ub_ufs2zram_ratio_write, 4168c2ecf20Sopenharmony_ci .read_u64 = memcg_ub_ufs2zram_ratio_read, 4178c2ecf20Sopenharmony_ci }, 4188c2ecf20Sopenharmony_ci { 4198c2ecf20Sopenharmony_ci .name = "total_info_per_app", 4208c2ecf20Sopenharmony_ci .seq_show = memcg_total_info_per_app_show, 4218c2ecf20Sopenharmony_ci }, 4228c2ecf20Sopenharmony_ci { 4238c2ecf20Sopenharmony_ci .name = "app_score", 4248c2ecf20Sopenharmony_ci .write_u64 = mem_cgroup_app_score_write, 4258c2ecf20Sopenharmony_ci .read_u64 = mem_cgroup_app_score_read, 4268c2ecf20Sopenharmony_ci }, 4278c2ecf20Sopenharmony_ci { 4288c2ecf20Sopenharmony_ci .name = "force_shrink_anon", 4298c2ecf20Sopenharmony_ci .write = memcg_force_shrink_anon 4308c2ecf20Sopenharmony_ci }, 4318c2ecf20Sopenharmony_ci { 4328c2ecf20Sopenharmony_ci .name = "force_swapin", 4338c2ecf20Sopenharmony_ci .write_u64 = memcg_force_swapin_write, 4348c2ecf20Sopenharmony_ci }, 4358c2ecf20Sopenharmony_ci#ifdef CONFIG_MEM_PURGEABLE 4368c2ecf20Sopenharmony_ci { 4378c2ecf20Sopenharmony_ci .name = "force_shrink_purgeable_bysize", 4388c2ecf20Sopenharmony_ci .write_u64 = memcg_force_shrink_purgeable_bysize, 4398c2ecf20Sopenharmony_ci }, 4408c2ecf20Sopenharmony_ci#endif 4418c2ecf20Sopenharmony_ci { }, /* terminate */ 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int __init memcg_policy_init(void) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci if (!mem_cgroup_disabled()) 4478c2ecf20Sopenharmony_ci WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys, 4488c2ecf20Sopenharmony_ci memcg_policy_files)); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_cisubsys_initcall(memcg_policy_init); 4538c2ecf20Sopenharmony_ci#else 4548c2ecf20Sopenharmony_cistruct mem_cgroup *get_next_memcg(struct mem_cgroup *prev) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci return NULL; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_civoid get_next_memcg_break(struct mem_cgroup *memcg) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistruct mem_cgroup *get_prev_memcg(struct mem_cgroup *next) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci return NULL; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_civoid get_prev_memcg_break(struct mem_cgroup *memcg) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic u64 mem_cgroup_app_score_read(struct cgroup_subsys_state *css, 4748c2ecf20Sopenharmony_ci struct cftype *cft) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int mem_cgroup_app_score_write(struct cgroup_subsys_state *css, 4808c2ecf20Sopenharmony_ci struct cftype *cft, u64 val) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_civoid memcg_app_score_update(struct mem_cgroup *target) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci#endif 489