// SPDX-License-Identifier: GPL-2.0 /* * mm/zswapd_control.c * * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. */ #include #include #include #include #include #include #include "zswapd_internal.h" #define ANON_REFAULT_SNAPSHOT_MIN_INTERVAL 200 #define AREA_ANON_REFAULT_THRESHOLD 22000 #define EMPTY_ROUND_CHECK_THRESHOLD 10 #define EMPTY_ROUND_SKIP_INTERVAL 20 #define ZSWAPD_MAX_LEVEL_NUM 10 #define MAX_SKIP_INTERVAL 1000 #define MAX_RECLAIM_SIZE 100 #define INACTIVE_FILE_RATIO 90 #define ACTIVE_FILE_RATIO 70 #define COMPRESS_RATIO 30 #define ZRAM_WM_RATIO 0 #define MAX_RATIO 100 #define CHECK_BUFFER_VALID(var1, var2) (((var2) != 0) && ((var1) > (var2))) struct zswapd_param { unsigned int min_score; unsigned int max_score; unsigned int ub_mem2zram_ratio; unsigned int ub_zram2ufs_ratio; unsigned int refault_threshold; }; static struct zswapd_param zswap_param[ZSWAPD_MAX_LEVEL_NUM]; struct eventfd_ctx *zswapd_press_efd[LEVEL_COUNT]; static DEFINE_MUTEX(pressure_event_lock); static DEFINE_MUTEX(reclaim_para_lock); atomic_t avail_buffers = ATOMIC_INIT(0); atomic_t min_avail_buffers = ATOMIC_INIT(0); atomic_t high_avail_buffers = ATOMIC_INIT(0); atomic_t max_reclaim_size = ATOMIC_INIT(MAX_RECLAIM_SIZE); atomic_t inactive_file_ratio = ATOMIC_INIT(INACTIVE_FILE_RATIO); atomic_t active_file_ratio = ATOMIC_INIT(ACTIVE_FILE_RATIO); atomic_t zram_wm_ratio = ATOMIC_INIT(ZRAM_WM_RATIO); atomic_t compress_ratio = ATOMIC_INIT(COMPRESS_RATIO); atomic64_t zram_critical_threshold = ATOMIC_LONG_INIT(0); atomic64_t free_swap_threshold = ATOMIC_LONG_INIT(0); atomic64_t area_anon_refault_threshold = ATOMIC_LONG_INIT(AREA_ANON_REFAULT_THRESHOLD); atomic64_t anon_refault_snapshot_min_interval = ATOMIC_LONG_INIT(ANON_REFAULT_SNAPSHOT_MIN_INTERVAL); atomic64_t empty_round_skip_interval = ATOMIC_LONG_INIT(EMPTY_ROUND_SKIP_INTERVAL); atomic64_t max_skip_interval = ATOMIC_LONG_INIT(MAX_SKIP_INTERVAL); atomic64_t empty_round_check_threshold = ATOMIC_LONG_INIT(EMPTY_ROUND_CHECK_THRESHOLD); inline unsigned int get_zram_wm_ratio(void) { return atomic_read(&zram_wm_ratio); } inline unsigned int get_compress_ratio(void) { return atomic_read(&compress_ratio); } inline unsigned int get_inactive_file_ratio(void) { return atomic_read(&inactive_file_ratio); } inline unsigned int get_active_file_ratio(void) { return atomic_read(&active_file_ratio); } inline unsigned int get_avail_buffers(void) { return atomic_read(&avail_buffers); } inline unsigned int get_min_avail_buffers(void) { return atomic_read(&min_avail_buffers); } inline unsigned int get_high_avail_buffers(void) { return atomic_read(&high_avail_buffers); } inline unsigned int get_zswapd_max_reclaim_size(void) { return atomic_read(&max_reclaim_size); } inline unsigned long long get_free_swap_threshold(void) { return atomic64_read(&free_swap_threshold); } inline unsigned long long get_area_anon_refault_threshold(void) { return atomic64_read(&area_anon_refault_threshold); } inline unsigned long long get_anon_refault_snapshot_min_interval(void) { return atomic64_read(&anon_refault_snapshot_min_interval); } inline unsigned long long get_empty_round_skip_interval(void) { return atomic64_read(&empty_round_skip_interval); } inline unsigned long long get_max_skip_interval(void) { return atomic64_read(&max_skip_interval); } inline unsigned long long get_empty_round_check_threshold(void) { return atomic64_read(&empty_round_check_threshold); } inline unsigned long long get_zram_critical_threshold(void) { return atomic64_read(&zram_critical_threshold); } static ssize_t avail_buffers_params_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { unsigned long long threshold; unsigned int high_buffers; unsigned int min_buffers; unsigned int buffers; buf = strstrip(buf); if (sscanf(buf, "%u %u %u %llu", &buffers, &min_buffers, &high_buffers, &threshold) != 4) return -EINVAL; if (CHECK_BUFFER_VALID(min_buffers, buffers) || CHECK_BUFFER_VALID(min_buffers, high_buffers) || CHECK_BUFFER_VALID(buffers, high_buffers)) return -EINVAL; atomic_set(&avail_buffers, buffers); atomic_set(&min_avail_buffers, min_buffers); atomic_set(&high_avail_buffers, high_buffers); atomic64_set(&free_swap_threshold, (threshold * (SZ_1M / PAGE_SIZE))); if (atomic_read(&min_avail_buffers) == 0) set_snapshotd_init_flag(0); else set_snapshotd_init_flag(1); wake_all_zswapd(); return nbytes; } static ssize_t zswapd_max_reclaim_size_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { u32 max; int ret; buf = strstrip(buf); ret = kstrtouint(buf, 10, &max); if (ret) return -EINVAL; atomic_set(&max_reclaim_size, max); return nbytes; } static ssize_t buffers_ratio_params_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { unsigned int inactive; unsigned int active; buf = strstrip(buf); if (sscanf(buf, "%u %u", &inactive, &active) != 2) return -EINVAL; if (inactive > MAX_RATIO || active > MAX_RATIO) return -EINVAL; atomic_set(&inactive_file_ratio, inactive); atomic_set(&active_file_ratio, active); return nbytes; } static int area_anon_refault_threshold_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) { atomic64_set(&area_anon_refault_threshold, val); return 0; } static int empty_round_skip_interval_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) { atomic64_set(&empty_round_skip_interval, val); return 0; } static int max_skip_interval_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) { atomic64_set(&max_skip_interval, val); return 0; } static int empty_round_check_threshold_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) { atomic64_set(&empty_round_check_threshold, val); return 0; } static int anon_refault_snapshot_min_interval_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) { atomic64_set(&anon_refault_snapshot_min_interval, val); return 0; } static int zram_critical_thres_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 val) { atomic64_set(&zram_critical_threshold, val); return 0; } static ssize_t zswapd_pressure_event_control(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { unsigned int level; unsigned int efd; struct fd efile; int ret; buf = strstrip(buf); if (sscanf(buf, "%u %u", &efd, &level) != 2) return -EINVAL; if (level >= LEVEL_COUNT) return -EINVAL; mutex_lock(&pressure_event_lock); efile = fdget(efd); if (!efile.file) { ret = -EBADF; goto out; } zswapd_press_efd[level] = eventfd_ctx_fileget(efile.file); if (IS_ERR(zswapd_press_efd[level])) { ret = PTR_ERR(zswapd_press_efd[level]); goto out_put_efile; } fdput(efile); mutex_unlock(&pressure_event_lock); return nbytes; out_put_efile: fdput(efile); out: mutex_unlock(&pressure_event_lock); return ret; } void zswapd_pressure_report(enum zswapd_pressure_level level) { int ret; if (zswapd_press_efd[level] == NULL) return; ret = eventfd_signal(zswapd_press_efd[level], 1); if (ret < 0) pr_err("SWAP-MM: %s : level:%u, ret:%d ", __func__, level, ret); } static u64 zswapd_pid_read(struct cgroup_subsys_state *css, struct cftype *cft) { return get_zswapd_pid(); } static void zswapd_memcgs_param_parse(int level_num) { struct mem_cgroup *memcg = NULL; u64 score; int i; while ((memcg = get_next_memcg(memcg))) { score = atomic64_read(&memcg->memcg_reclaimed.app_score); for (i = 0; i < level_num; ++i) if (score >= zswap_param[i].min_score && score <= zswap_param[i].max_score) break; atomic_set(&memcg->memcg_reclaimed.ub_mem2zram_ratio, zswap_param[i].ub_mem2zram_ratio); atomic_set(&memcg->memcg_reclaimed.ub_zram2ufs_ratio, zswap_param[i].ub_zram2ufs_ratio); atomic_set(&memcg->memcg_reclaimed.refault_threshold, zswap_param[i].refault_threshold); } } static ssize_t zswapd_memcgs_param_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { char *token = NULL; int level_num; int i; buf = strstrip(buf); token = strsep(&buf, " "); if (!token) return -EINVAL; if (kstrtoint(token, 0, &level_num)) return -EINVAL; if (level_num > ZSWAPD_MAX_LEVEL_NUM) return -EINVAL; mutex_lock(&reclaim_para_lock); for (i = 0; i < level_num; ++i) { token = strsep(&buf, " "); if (!token) goto out; if (kstrtoint(token, 0, &zswap_param[i].min_score) || zswap_param[i].min_score > MAX_APP_SCORE) goto out; token = strsep(&buf, " "); if (!token) goto out; if (kstrtoint(token, 0, &zswap_param[i].max_score) || zswap_param[i].max_score > MAX_APP_SCORE) goto out; token = strsep(&buf, " "); if (!token) goto out; if (kstrtoint(token, 0, &zswap_param[i].ub_mem2zram_ratio) || zswap_param[i].ub_mem2zram_ratio > MAX_RATIO) goto out; token = strsep(&buf, " "); if (!token) goto out; if (kstrtoint(token, 0, &zswap_param[i].ub_zram2ufs_ratio) || zswap_param[i].ub_zram2ufs_ratio > MAX_RATIO) goto out; token = strsep(&buf, " "); if (!token) goto out; if (kstrtoint(token, 0, &zswap_param[i].refault_threshold)) goto out; } zswapd_memcgs_param_parse(level_num); mutex_unlock(&reclaim_para_lock); return nbytes; out: mutex_unlock(&reclaim_para_lock); return -EINVAL; } static ssize_t zswapd_single_memcg_param_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); unsigned int ub_mem2zram_ratio; unsigned int ub_zram2ufs_ratio; unsigned int refault_threshold; buf = strstrip(buf); if (sscanf(buf, "%u %u %u", &ub_mem2zram_ratio, &ub_zram2ufs_ratio, &refault_threshold) != 3) return -EINVAL; if (ub_mem2zram_ratio > MAX_RATIO || ub_zram2ufs_ratio > MAX_RATIO || refault_threshold > MAX_RATIO) return -EINVAL; atomic_set(&memcg->memcg_reclaimed.ub_mem2zram_ratio, ub_mem2zram_ratio); atomic_set(&memcg->memcg_reclaimed.ub_zram2ufs_ratio, ub_zram2ufs_ratio); atomic_set(&memcg->memcg_reclaimed.refault_threshold, refault_threshold); return nbytes; } static ssize_t mem_cgroup_zram_wm_ratio_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { unsigned int ratio; int ret; buf = strstrip(buf); ret = kstrtouint(buf, 10, &ratio); if (ret) return -EINVAL; if (ratio > MAX_RATIO) return -EINVAL; atomic_set(&zram_wm_ratio, ratio); return nbytes; } static ssize_t mem_cgroup_compress_ratio_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { unsigned int ratio; int ret; buf = strstrip(buf); ret = kstrtouint(buf, 10, &ratio); if (ret) return -EINVAL; if (ratio > MAX_RATIO) return -EINVAL; atomic_set(&compress_ratio, ratio); return nbytes; } static int zswapd_pressure_show(struct seq_file *m, void *v) { zswapd_status_show(m); return 0; } static int memcg_active_app_info_list_show(struct seq_file *m, void *v) { struct mem_cgroup_per_node *mz = NULL; struct mem_cgroup *memcg = NULL; struct lruvec *lruvec = NULL; unsigned long eswap_size; unsigned long anon_size; unsigned long zram_size; while ((memcg = get_next_memcg(memcg))) { u64 score = atomic64_read(&memcg->memcg_reclaimed.app_score); mz = mem_cgroup_nodeinfo(memcg, 0); if (!mz) { get_next_memcg_break(memcg); return 0; } lruvec = &mz->lruvec; if (!lruvec) { get_next_memcg_break(memcg); return 0; } anon_size = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) + lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, MAX_NR_ZONES); eswap_size = memcg_data_size(memcg, SWAP_SIZE); zram_size = memcg_data_size(memcg, CACHE_SIZE); if (anon_size + zram_size + eswap_size == 0) continue; if (!strlen(memcg->name)) continue; anon_size *= PAGE_SIZE / SZ_1K; zram_size *= PAGE_SIZE / SZ_1K; eswap_size *= PAGE_SIZE / SZ_1K; seq_printf(m, "%s %llu %lu %lu %lu %llu\n", memcg->name, score, anon_size, zram_size, eswap_size, memcg->memcg_reclaimed.reclaimed_pagefault); } return 0; } #ifdef CONFIG_HYPERHOLD_DEBUG static int avail_buffers_params_show(struct seq_file *m, void *v) { seq_printf(m, "avail_buffers: %u\n", atomic_read(&avail_buffers)); seq_printf(m, "min_avail_buffers: %u\n", atomic_read(&min_avail_buffers)); seq_printf(m, "high_avail_buffers: %u\n", atomic_read(&high_avail_buffers)); seq_printf(m, "free_swap_threshold: %llu\n", atomic64_read(&free_swap_threshold) * PAGE_SIZE / SZ_1M); return 0; } static int zswapd_max_reclaim_size_show(struct seq_file *m, void *v) { seq_printf(m, "zswapd_max_reclaim_size: %u\n", atomic_read(&max_reclaim_size)); return 0; } static int buffers_ratio_params_show(struct seq_file *m, void *v) { seq_printf(m, "inactive_file_ratio: %u\n", atomic_read(&inactive_file_ratio)); seq_printf(m, "active_file_ratio: %u\n", atomic_read(&active_file_ratio)); return 0; } static u64 area_anon_refault_threshold_read(struct cgroup_subsys_state *css, struct cftype *cft) { return atomic64_read(&area_anon_refault_threshold); } static u64 empty_round_skip_interval_read(struct cgroup_subsys_state *css, struct cftype *cft) { return atomic64_read(&empty_round_skip_interval); } static u64 max_skip_interval_read(struct cgroup_subsys_state *css, struct cftype *cft) { return atomic64_read(&max_skip_interval); } static u64 empty_round_check_threshold_read(struct cgroup_subsys_state *css, struct cftype *cft) { return atomic64_read(&empty_round_check_threshold); } static u64 anon_refault_snapshot_min_interval_read( struct cgroup_subsys_state *css, struct cftype *cft) { return atomic64_read(&anon_refault_snapshot_min_interval); } static u64 zram_critical_threshold_read(struct cgroup_subsys_state *css, struct cftype *cft) { return atomic64_read(&zram_critical_threshold); } static int zswapd_memcgs_param_show(struct seq_file *m, void *v) { int i; for (i = 0; i < ZSWAPD_MAX_LEVEL_NUM; ++i) { seq_printf(m, "level %d min score: %u\n", i, zswap_param[i].min_score); seq_printf(m, "level %d max score: %u\n", i, zswap_param[i].max_score); seq_printf(m, "level %d ub_mem2zram_ratio: %u\n", i, zswap_param[i].ub_mem2zram_ratio); seq_printf(m, "level %d ub_zram2ufs_ratio: %u\n", i, zswap_param[i].ub_zram2ufs_ratio); seq_printf(m, "level %d refault_threshold: %u\n", i, zswap_param[i].refault_threshold); } return 0; } static int zswapd_single_memcg_param_show(struct seq_file *m, void *v) { struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); seq_printf(m, "memcg score: %llu\n", atomic64_read(&memcg->memcg_reclaimed.app_score)); seq_printf(m, "memcg ub_mem2zram_ratio: %u\n", atomic_read(&memcg->memcg_reclaimed.ub_mem2zram_ratio)); seq_printf(m, "memcg ub_zram2ufs_ratio: %u\n", atomic_read(&memcg->memcg_reclaimed.ub_zram2ufs_ratio)); seq_printf(m, "memcg refault_threshold: %u\n", atomic_read(&memcg->memcg_reclaimed.refault_threshold)); return 0; } static int zram_wm_ratio_show(struct seq_file *m, void *v) { seq_printf(m, "zram_wm_ratio: %u\n", atomic_read(&zram_wm_ratio)); return 0; } static int compress_ratio_show(struct seq_file *m, void *v) { seq_printf(m, "compress_ratio: %u\n", atomic_read(&compress_ratio)); return 0; } static int zswapd_vmstat_show(struct seq_file *m, void *v) { #ifdef CONFIG_VM_EVENT_COUNTERS unsigned long *vm_buf = NULL; vm_buf = kzalloc(sizeof(struct vm_event_state), GFP_KERNEL); if (!vm_buf) return -ENOMEM; all_vm_events(vm_buf); seq_printf(m, "zswapd_wake_up:%lu\n", vm_buf[ZSWAPD_WAKEUP]); seq_printf(m, "zswapd_area_refault:%lu\n", vm_buf[ZSWAPD_REFAULT]); seq_printf(m, "zswapd_medium_press:%lu\n", vm_buf[ZSWAPD_MEDIUM_PRESS]); seq_printf(m, "zswapd_critical_press:%lu\n", vm_buf[ZSWAPD_CRITICAL_PRESS]); seq_printf(m, "zswapd_memcg_ratio_skip:%lu\n", vm_buf[ZSWAPD_MEMCG_RATIO_SKIP]); seq_printf(m, "zswapd_memcg_refault_skip:%lu\n", vm_buf[ZSWAPD_MEMCG_REFAULT_SKIP]); seq_printf(m, "zswapd_swapout:%lu\n", vm_buf[ZSWAPD_SWAPOUT]); seq_printf(m, "zswapd_snapshot_times:%lu\n", vm_buf[ZSWAPD_SNAPSHOT_TIMES]); seq_printf(m, "zswapd_reclaimed:%lu\n", vm_buf[ZSWAPD_RECLAIMED]); seq_printf(m, "zswapd_scanned:%lu\n", vm_buf[ZSWAPD_SCANNED]); kfree(vm_buf); #endif return 0; } static int eswap_info_show(struct seq_file *m, void *v) { struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); unsigned long long eswap_size; eswap_size = memcg_data_size(memcg, WRITE_SIZE) / SZ_1K; seq_printf(m, "Total Swapout Size: %llu kB\n", eswap_size); return 0; } void memcg_eswap_info_show(struct seq_file *m) { struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); struct mem_cgroup_per_node *mz = NULL; struct lruvec *lruvec = NULL; unsigned long anon; unsigned long file; unsigned long zram; unsigned long eswap; mz = mem_cgroup_nodeinfo(memcg, 0); if (!mz) return; lruvec = &mz->lruvec; if (!lruvec) return; anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) + lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, MAX_NR_ZONES); file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES) + lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, MAX_NR_ZONES); zram = memcg_data_size(memcg, CACHE_SIZE) / SZ_1K; eswap = memcg_data_size(memcg, SWAP_SIZE) / SZ_1K; anon *= PAGE_SIZE / SZ_1K; file *= PAGE_SIZE / SZ_1K; seq_printf(m, "Anon:\t%12lu kB\nFile:\t%12lu kB\nzram:\t%12lu kB\nEswap:\t%12lu kB\n", anon, file, zram, eswap); } #endif static struct cftype zswapd_policy_files[] = { { .name = "active_app_info_list", .flags = CFTYPE_ONLY_ON_ROOT, .seq_show = memcg_active_app_info_list_show, }, { .name = "zram_wm_ratio", .flags = CFTYPE_ONLY_ON_ROOT, .write = mem_cgroup_zram_wm_ratio_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = zram_wm_ratio_show, #endif }, { .name = "compress_ratio", .flags = CFTYPE_ONLY_ON_ROOT, .write = mem_cgroup_compress_ratio_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = compress_ratio_show, #endif }, { .name = "zswapd_pressure", .flags = CFTYPE_ONLY_ON_ROOT, .write = zswapd_pressure_event_control, }, { .name = "zswapd_pid", .flags = CFTYPE_ONLY_ON_ROOT, .read_u64 = zswapd_pid_read, }, { .name = "avail_buffers", .flags = CFTYPE_ONLY_ON_ROOT, .write = avail_buffers_params_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = avail_buffers_params_show, #endif }, { .name = "zswapd_max_reclaim_size", .flags = CFTYPE_ONLY_ON_ROOT, .write = zswapd_max_reclaim_size_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = zswapd_max_reclaim_size_show, #endif }, { .name = "area_anon_refault_threshold", .flags = CFTYPE_ONLY_ON_ROOT, .write_u64 = area_anon_refault_threshold_write, #ifdef CONFIG_HYPERHOLD_DEBUG .read_u64 = area_anon_refault_threshold_read, #endif }, { .name = "empty_round_skip_interval", .flags = CFTYPE_ONLY_ON_ROOT, .write_u64 = empty_round_skip_interval_write, #ifdef CONFIG_HYPERHOLD_DEBUG .read_u64 = empty_round_skip_interval_read, #endif }, { .name = "max_skip_interval", .flags = CFTYPE_ONLY_ON_ROOT, .write_u64 = max_skip_interval_write, #ifdef CONFIG_HYPERHOLD_DEBUG .read_u64 = max_skip_interval_read, #endif }, { .name = "empty_round_check_threshold", .flags = CFTYPE_ONLY_ON_ROOT, .write_u64 = empty_round_check_threshold_write, #ifdef CONFIG_HYPERHOLD_DEBUG .read_u64 = empty_round_check_threshold_read, #endif }, { .name = "anon_refault_snapshot_min_interval", .flags = CFTYPE_ONLY_ON_ROOT, .write_u64 = anon_refault_snapshot_min_interval_write, #ifdef CONFIG_HYPERHOLD_DEBUG .read_u64 = anon_refault_snapshot_min_interval_read, #endif }, { .name = "zswapd_memcgs_param", .flags = CFTYPE_ONLY_ON_ROOT, .write = zswapd_memcgs_param_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = zswapd_memcgs_param_show, #endif }, { .name = "zswapd_single_memcg_param", .write = zswapd_single_memcg_param_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = zswapd_single_memcg_param_show, #endif }, { .name = "buffer_ratio_params", .flags = CFTYPE_ONLY_ON_ROOT, .write = buffers_ratio_params_write, #ifdef CONFIG_HYPERHOLD_DEBUG .seq_show = buffers_ratio_params_show, #endif }, { .name = "zswapd_pressure_show", .flags = CFTYPE_ONLY_ON_ROOT, .seq_show = zswapd_pressure_show, }, { .name = "zram_critical_threshold", .flags = CFTYPE_ONLY_ON_ROOT, .write_u64 = zram_critical_thres_write, #ifdef CONFIG_HYPERHOLD_DEBUG .read_u64 = zram_critical_threshold_read, #endif }, #ifdef CONFIG_HYPERHOLD_DEBUG { .name = "zswapd_vmstat_show", .flags = CFTYPE_ONLY_ON_ROOT, .seq_show = zswapd_vmstat_show, }, #endif { .name = "eswap_info", .flags = CFTYPE_ONLY_ON_ROOT, .seq_show = eswap_info_show, }, { }, /* terminate */ }; static int __init zswapd_policy_init(void) { if (!mem_cgroup_disabled()) WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys, zswapd_policy_files)); return 0; } subsys_initcall(zswapd_policy_init);