xref: /kernel/linux/linux-5.10/mm/memcg_control.c (revision 8c2ecf20)
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