// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Memory Controller-related BPF kfuncs and auxiliary code3*4* Author: Roman Gushchin <[email protected]>5*/67#include <linux/memcontrol.h>8#include <linux/bpf.h>910__bpf_kfunc_start_defs();1112/**13* bpf_get_root_mem_cgroup - Returns a pointer to the root memory cgroup14*15* The function has KF_ACQUIRE semantics, even though the root memory16* cgroup is never destroyed after being created and doesn't require17* reference counting. And it's perfectly safe to pass it to18* bpf_put_mem_cgroup()19*20* Return: A pointer to the root memory cgroup.21*/22__bpf_kfunc struct mem_cgroup *bpf_get_root_mem_cgroup(void)23{24if (mem_cgroup_disabled())25return NULL;2627/* css_get() is not needed */28return root_mem_cgroup;29}3031/**32* bpf_get_mem_cgroup - Get a reference to a memory cgroup33* @css: pointer to the css structure34*35* It's fine to pass a css which belongs to any cgroup controller,36* e.g. unified hierarchy's main css.37*38* Implements KF_ACQUIRE semantics.39*40* Return: A pointer to a mem_cgroup structure after bumping41* the corresponding css's reference counter.42*/43__bpf_kfunc struct mem_cgroup *44bpf_get_mem_cgroup(struct cgroup_subsys_state *css)45{46struct mem_cgroup *memcg = NULL;47bool rcu_unlock = false;4849if (mem_cgroup_disabled() || !root_mem_cgroup)50return NULL;5152if (root_mem_cgroup->css.ss != css->ss) {53struct cgroup *cgroup = css->cgroup;54int ssid = root_mem_cgroup->css.ss->id;5556rcu_read_lock();57rcu_unlock = true;58css = rcu_dereference_raw(cgroup->subsys[ssid]);59}6061if (css && css_tryget(css))62memcg = container_of(css, struct mem_cgroup, css);6364if (rcu_unlock)65rcu_read_unlock();6667return memcg;68}6970/**71* bpf_put_mem_cgroup - Put a reference to a memory cgroup72* @memcg: memory cgroup to release73*74* Releases a previously acquired memcg reference.75* Implements KF_RELEASE semantics.76*/77__bpf_kfunc void bpf_put_mem_cgroup(struct mem_cgroup *memcg)78{79css_put(&memcg->css);80}8182/**83* bpf_mem_cgroup_vm_events - Read memory cgroup's vm event counter84* @memcg: memory cgroup85* @event: event id86*87* Allows to read memory cgroup event counters.88*89* Return: The current value of the corresponding events counter.90*/91__bpf_kfunc unsigned long bpf_mem_cgroup_vm_events(struct mem_cgroup *memcg,92enum vm_event_item event)93{94if (unlikely(!memcg_vm_event_item_valid(event)))95return (unsigned long)-1;9697return memcg_events(memcg, event);98}99100/**101* bpf_mem_cgroup_usage - Read memory cgroup's usage102* @memcg: memory cgroup103*104* Please, note that the root memory cgroup it special and is exempt105* from the memory accounting. The returned value is a sum of sub-cgroup's106* usages and it not reflecting the size of the root memory cgroup itself.107* If you need to get an approximation, you can use root level statistics:108* e.g. NR_FILE_PAGES + NR_ANON_MAPPED.109*110* Return: The current memory cgroup size in bytes.111*/112__bpf_kfunc unsigned long bpf_mem_cgroup_usage(struct mem_cgroup *memcg)113{114return page_counter_read(&memcg->memory) * PAGE_SIZE;115}116117/**118* bpf_mem_cgroup_memory_events - Read memory cgroup's memory event value119* @memcg: memory cgroup120* @event: memory event id121*122* Return: The current value of the memory event counter.123*/124__bpf_kfunc unsigned long bpf_mem_cgroup_memory_events(struct mem_cgroup *memcg,125enum memcg_memory_event event)126{127if (unlikely(event >= MEMCG_NR_MEMORY_EVENTS))128return (unsigned long)-1;129130return atomic_long_read(&memcg->memory_events[event]);131}132133/**134* bpf_mem_cgroup_page_state - Read memory cgroup's page state counter135* @memcg: memory cgroup136* @idx: counter idx137*138* Allows to read memory cgroup statistics. The output is in bytes.139*140* Return: The value of the page state counter in bytes.141*/142__bpf_kfunc unsigned long bpf_mem_cgroup_page_state(struct mem_cgroup *memcg, int idx)143{144if (unlikely(!memcg_stat_item_valid(idx)))145return (unsigned long)-1;146147return memcg_page_state_output(memcg, idx);148}149150/**151* bpf_mem_cgroup_flush_stats - Flush memory cgroup's statistics152* @memcg: memory cgroup153*154* Propagate memory cgroup's statistics up the cgroup tree.155*/156__bpf_kfunc void bpf_mem_cgroup_flush_stats(struct mem_cgroup *memcg)157{158mem_cgroup_flush_stats(memcg);159}160161__bpf_kfunc_end_defs();162163BTF_KFUNCS_START(bpf_memcontrol_kfuncs)164BTF_ID_FLAGS(func, bpf_get_root_mem_cgroup, KF_ACQUIRE | KF_RET_NULL)165BTF_ID_FLAGS(func, bpf_get_mem_cgroup, KF_ACQUIRE | KF_RET_NULL | KF_RCU)166BTF_ID_FLAGS(func, bpf_put_mem_cgroup, KF_RELEASE)167168BTF_ID_FLAGS(func, bpf_mem_cgroup_vm_events)169BTF_ID_FLAGS(func, bpf_mem_cgroup_memory_events)170BTF_ID_FLAGS(func, bpf_mem_cgroup_usage)171BTF_ID_FLAGS(func, bpf_mem_cgroup_page_state)172BTF_ID_FLAGS(func, bpf_mem_cgroup_flush_stats, KF_SLEEPABLE)173174BTF_KFUNCS_END(bpf_memcontrol_kfuncs)175176static const struct btf_kfunc_id_set bpf_memcontrol_kfunc_set = {177.owner = THIS_MODULE,178.set = &bpf_memcontrol_kfuncs,179};180181static int __init bpf_memcontrol_init(void)182{183int err;184185err = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC,186&bpf_memcontrol_kfunc_set);187if (err)188pr_warn("error while registering bpf memcontrol kfuncs: %d", err);189190return err;191}192late_initcall(bpf_memcontrol_init);193194195