Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e59c6fa

Browse files
winnscodeMingcongBai
authored andcommittedMar 5, 2025·
mm/memcg: add wmark-step support
Signed-off-by: Winston Wen <wentao@uniontech.com> Change-Id: I07fcfcced59279861e27440426000f6d6b42f36f
1 parent 2bbfb8f commit e59c6fa

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed
 

‎include/linux/memcontrol.h

+4
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ struct mem_cgroup {
256256
/* OOM-Killer disable */
257257
int oom_kill_disable;
258258

259+
#ifdef CONFIG_WMARK_STEP
260+
int wmark_step;
261+
#endif
262+
259263
/* memory.events and memory.events.local */
260264
struct cgroup_file events_file;
261265
struct cgroup_file events_local_file;

‎mm/Kconfig

+7
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,13 @@ config LOCK_MM_AND_FIND_VMA
12821282
bool
12831283
depends on !STACK_GROWSUP
12841284

1285+
config WMARK_STEP
1286+
bool "WaterMark step"
1287+
depends on MEMCG
1288+
default y
1289+
help
1290+
Watermark step.
1291+
12851292
source "mm/damon/Kconfig"
12861293

12871294
endmenu

‎mm/internal.h

+16
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,24 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,
913913
#define ALLOC_HIGHATOMIC 0x200 /* Allows access to MIGRATE_HIGHATOMIC */
914914
#define ALLOC_KSWAPD 0x800 /* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */
915915

916+
#ifdef CONFIG_WMARK_STEP
917+
#define ALLOC_WMARK_STEP 0x1000 /* Allow use user-reserve */
918+
#endif
919+
920+
#ifndef CONFIG_WMARK_STEP
916921
/* Flags that allow allocations below the min watermark. */
917922
#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)
923+
#else
924+
#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM|ALLOC_WMARK_STEP)
925+
#endif
926+
927+
#ifdef CONFIG_WMARK_STEP
928+
extern unsigned int wmark_step_enable;
929+
extern unsigned int wmark_step_max;
930+
extern unsigned int wmark_step_kthread;
931+
extern unsigned int wmark_step_size;
932+
int should_use_wmark_step(void);
933+
#endif
918934

919935
enum ttu_flags;
920936
struct tlbflush_unmap_batch;

‎mm/memcontrol.c

+141
Original file line numberDiff line numberDiff line change
@@ -5388,6 +5388,9 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
53885388
if (parent) {
53895389
WRITE_ONCE(memcg->swappiness, mem_cgroup_swappiness(parent));
53905390
WRITE_ONCE(memcg->oom_kill_disable, READ_ONCE(parent->oom_kill_disable));
5391+
#ifdef CONFIG_WMARK_STEP
5392+
WRITE_ONCE(memcg->wmark_step, READ_ONCE(parent->wmark_step));
5393+
#endif
53915394

53925395
page_counter_init(&memcg->memory, &parent->memory);
53935396
page_counter_init(&memcg->swap, &parent->swap);
@@ -6735,6 +6738,71 @@ static ssize_t memory_oom_group_write(struct kernfs_open_file *of,
67356738
return nbytes;
67366739
}
67376740

6741+
#ifdef CONFIG_WMARK_STEP
6742+
int should_use_wmark_step(void)
6743+
{
6744+
struct mem_cgroup *memcg;
6745+
6746+
if (!wmark_step_enable)
6747+
return 0;
6748+
6749+
if (!in_task())
6750+
return 0;
6751+
6752+
if (mem_cgroup_disabled())
6753+
return 0;
6754+
6755+
if (current->flags & PF_KTHREAD)
6756+
return wmark_step_kthread;
6757+
6758+
memcg = get_mem_cgroup_from_mm(current->mm);
6759+
return memcg->wmark_step;
6760+
}
6761+
6762+
static int memory_wmark_step_show(struct seq_file *m, void *v)
6763+
{
6764+
struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
6765+
6766+
seq_printf(m, "%d\n", READ_ONCE(memcg->wmark_step));
6767+
6768+
return 0;
6769+
}
6770+
6771+
static ssize_t memory_wmark_step_write(struct kernfs_open_file *of,
6772+
char *buf, size_t nbytes, loff_t off)
6773+
{
6774+
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
6775+
struct mem_cgroup *iter;
6776+
int ret, wmark_step;
6777+
// kuid_t root_uid;
6778+
// const struct cred *cred;
6779+
6780+
BUG_ON(mem_cgroup_is_root(memcg));
6781+
6782+
/* Temporarily keep the code for future use */
6783+
//root_uid = make_kuid(&init_user_ns, 0);
6784+
//cred = current_cred();
6785+
//if (!uid_eq(cred->uid, root_uid))
6786+
// return -EPERM;
6787+
6788+
buf = strstrip(buf);
6789+
if (!buf)
6790+
return -EINVAL;
6791+
6792+
ret = kstrtoint(buf, 0, &wmark_step);
6793+
if (ret)
6794+
return ret;
6795+
6796+
if (wmark_step < 0 || wmark_step > wmark_step_max)
6797+
return -EINVAL;
6798+
6799+
for_each_mem_cgroup_tree(iter, memcg)
6800+
WRITE_ONCE(iter->wmark_step, wmark_step);
6801+
6802+
return nbytes;
6803+
}
6804+
#endif
6805+
67386806
static ssize_t memory_reclaim(struct kernfs_open_file *of, char *buf,
67396807
size_t nbytes, loff_t off)
67406808
{
@@ -6840,6 +6908,14 @@ static struct cftype memory_files[] = {
68406908
.seq_show = memory_oom_group_show,
68416909
.write = memory_oom_group_write,
68426910
},
6911+
#ifdef CONFIG_WMARK_STEP
6912+
{
6913+
.name = "wmark_step",
6914+
.flags = CFTYPE_NOT_ON_ROOT,
6915+
.seq_show = memory_wmark_step_show,
6916+
.write = memory_wmark_step_write,
6917+
},
6918+
#endif
68436919
{
68446920
.name = "reclaim",
68456921
.flags = CFTYPE_NS_DELEGATABLE,
@@ -7416,6 +7492,66 @@ static int __init cgroup_memory(char *s)
74167492
}
74177493
__setup("cgroup.memory=", cgroup_memory);
74187494

7495+
#ifdef CONFIG_WMARK_STEP
7496+
static ssize_t wmark_step_kthread_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
7497+
{
7498+
return sysfs_emit(buf, "%u\n", wmark_step_kthread);
7499+
}
7500+
7501+
static ssize_t wmark_step_kthread_store(struct kobject *kobj, struct kobj_attribute *attr,
7502+
const char *buf, size_t len)
7503+
{
7504+
unsigned int kthread;
7505+
7506+
if (kstrtouint(buf, 0, &kthread))
7507+
return -EINVAL;
7508+
7509+
if (kthread > 5)
7510+
return -EINVAL;
7511+
7512+
wmark_step_kthread = kthread;
7513+
7514+
return len;
7515+
}
7516+
7517+
static struct kobj_attribute wmark_step_kthread_attr = __ATTR_RW(wmark_step_kthread);
7518+
7519+
static ssize_t wmark_step_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
7520+
{
7521+
return sysfs_emit(buf, "%u\n", wmark_step_enable);
7522+
}
7523+
7524+
static ssize_t wmark_step_enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
7525+
const char *buf, size_t len)
7526+
{
7527+
unsigned int enable;
7528+
7529+
if (kstrtouint(buf, 0, &enable))
7530+
return -EINVAL;
7531+
7532+
if (enable > 1)
7533+
return -EINVAL;
7534+
7535+
wmark_step_enable = enable;
7536+
7537+
return len;
7538+
}
7539+
7540+
static struct kobj_attribute wmark_step_enabled_attr = __ATTR(enabled, 0644,
7541+
wmark_step_enabled_show, wmark_step_enabled_store);
7542+
7543+
static struct attribute *wmark_step_attrs[] = {
7544+
&wmark_step_enabled_attr.attr,
7545+
&wmark_step_kthread_attr.attr,
7546+
NULL
7547+
};
7548+
7549+
static const struct attribute_group wmark_step_attr_group = {
7550+
.name = "wmark_step",
7551+
.attrs = wmark_step_attrs,
7552+
};
7553+
#endif
7554+
74197555
/*
74207556
* subsys_initcall() for memory controller.
74217557
*
@@ -7454,6 +7590,11 @@ static int __init mem_cgroup_init(void)
74547590
soft_limit_tree.rb_tree_per_node[node] = rtpn;
74557591
}
74567592

7593+
#ifdef CONFIG_WMARK_STEP
7594+
if (sysfs_create_group(mm_kobj, &wmark_step_attr_group))
7595+
pr_warn("wmark-step: failed to create sysfs group\n");
7596+
#endif
7597+
74577598
return 0;
74587599
}
74597600
subsys_initcall(mem_cgroup_init);

‎mm/page_alloc.c

+46
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ EXPORT_SYMBOL(node_states);
204204

205205
gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
206206

207+
#ifdef CONFIG_WMARK_STEP
208+
unsigned int wmark_step_enable = 0;
209+
unsigned int wmark_step_max = 5;
210+
unsigned int wmark_step_kthread = 3;
211+
unsigned int wmark_step_size = 16 * 1024 * 1024;
212+
#endif
213+
207214
/*
208215
* A cached value of the page's pageblock's migratetype, used when the page is
209216
* put on a pcplist. Used to avoid the pageblock migratetype lookup when
@@ -2860,11 +2867,35 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
28602867
{
28612868
long min = mark;
28622869
int o;
2870+
#ifdef CONFIG_WMARK_STEP
2871+
long pages_wmark_step = (wmark_step_max * wmark_step_size) >> PAGE_SHIFT;
2872+
int wmark_step;
2873+
#endif
28632874

28642875
/* free_pages may go negative - that's OK */
28652876
free_pages -= __zone_watermark_unusable_free(z, order, alloc_flags);
28662877

2878+
28672879
if (unlikely(alloc_flags & ALLOC_RESERVES)) {
2880+
#ifdef CONFIG_WMARK_STEP
2881+
if (zone_idx(z) == ZONE_NORMAL) {
2882+
wmark_step = should_use_wmark_step();
2883+
if (wmark_step < 0 || wmark_step > wmark_step_max) {
2884+
pr_err("uosste: wmark_step error: %d\n", wmark_step);
2885+
goto skip;
2886+
}
2887+
2888+
if (min <= pages_wmark_step) {
2889+
pr_err("uosste: min[%ld] < pages_wmark_step[%ld]\n",
2890+
min, pages_wmark_step);
2891+
goto skip;
2892+
}
2893+
2894+
min -= (wmark_step * wmark_step_size) >> PAGE_SHIFT;
2895+
}
2896+
skip:
2897+
#endif
2898+
28682899
/*
28692900
* __GFP_HIGH allows access to 50% of the min reserve as well
28702901
* as OOM.
@@ -3713,6 +3744,11 @@ static inline unsigned int
37133744
gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)
37143745
{
37153746
unsigned int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;
3747+
#ifdef CONFIG_WMARK_STEP
3748+
/* Only enabled when ALLOC_WMARK_MIN */
3749+
if (should_use_wmark_step())
3750+
alloc_flags |= ALLOC_WMARK_STEP;
3751+
#endif
37163752

37173753
/*
37183754
* __GFP_HIGH is assumed to be the same as ALLOC_MIN_RESERVE
@@ -3731,6 +3767,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)
37313767
alloc_flags |= (__force int)
37323768
(gfp_mask & (__GFP_HIGH | __GFP_KSWAPD_RECLAIM));
37333769

3770+
37343771
if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {
37353772
/*
37363773
* Not worth trying to allocate harder for __GFP_NOMEMALLOC even
@@ -5656,6 +5693,9 @@ static void setup_per_zone_lowmem_reserve(void)
56565693
static void __setup_per_zone_wmarks(void)
56575694
{
56585695
unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
5696+
#ifdef CONFIG_WMARK_STEP
5697+
unsigned long pages_wmark_step = (wmark_step_max * wmark_step_size) >> PAGE_SHIFT;
5698+
#endif
56595699
unsigned long lowmem_pages = 0;
56605700
struct zone *zone;
56615701
unsigned long flags;
@@ -5693,6 +5733,12 @@ static void __setup_per_zone_wmarks(void)
56935733
* proportionate to the zone's size.
56945734
*/
56955735
zone->_watermark[WMARK_MIN] = tmp;
5736+
5737+
#ifdef CONFIG_WMARK_STEP
5738+
/* Put all wmark step in zone normal */
5739+
if (zone_idx(zone) == ZONE_NORMAL)
5740+
zone->_watermark[WMARK_MIN] += pages_wmark_step;
5741+
#endif
56965742
}
56975743

56985744
/*

0 commit comments

Comments
 (0)
Please sign in to comment.