| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Memory Controller-related BPF kfuncs and auxiliary code
- *
- * Author: Roman Gushchin <roman.gushchin@linux.dev>
- */
- #include <linux/memcontrol.h>
- #include <linux/bpf.h>
- __bpf_kfunc_start_defs();
- /**
- * bpf_get_root_mem_cgroup - Returns a pointer to the root memory cgroup
- *
- * The function has KF_ACQUIRE semantics, even though the root memory
- * cgroup is never destroyed after being created and doesn't require
- * reference counting. And it's perfectly safe to pass it to
- * bpf_put_mem_cgroup()
- *
- * Return: A pointer to the root memory cgroup.
- */
- __bpf_kfunc struct mem_cgroup *bpf_get_root_mem_cgroup(void)
- {
- if (mem_cgroup_disabled())
- return NULL;
- /* css_get() is not needed */
- return root_mem_cgroup;
- }
- /**
- * bpf_get_mem_cgroup - Get a reference to a memory cgroup
- * @css: pointer to the css structure
- *
- * It's fine to pass a css which belongs to any cgroup controller,
- * e.g. unified hierarchy's main css.
- *
- * Implements KF_ACQUIRE semantics.
- *
- * Return: A pointer to a mem_cgroup structure after bumping
- * the corresponding css's reference counter.
- */
- __bpf_kfunc struct mem_cgroup *
- bpf_get_mem_cgroup(struct cgroup_subsys_state *css)
- {
- struct mem_cgroup *memcg = NULL;
- bool rcu_unlock = false;
- if (mem_cgroup_disabled() || !root_mem_cgroup)
- return NULL;
- if (root_mem_cgroup->css.ss != css->ss) {
- struct cgroup *cgroup = css->cgroup;
- int ssid = root_mem_cgroup->css.ss->id;
- rcu_read_lock();
- rcu_unlock = true;
- css = rcu_dereference_raw(cgroup->subsys[ssid]);
- }
- if (css && css_tryget(css))
- memcg = container_of(css, struct mem_cgroup, css);
- if (rcu_unlock)
- rcu_read_unlock();
- return memcg;
- }
- /**
- * bpf_put_mem_cgroup - Put a reference to a memory cgroup
- * @memcg: memory cgroup to release
- *
- * Releases a previously acquired memcg reference.
- * Implements KF_RELEASE semantics.
- */
- __bpf_kfunc void bpf_put_mem_cgroup(struct mem_cgroup *memcg)
- {
- css_put(&memcg->css);
- }
- /**
- * bpf_mem_cgroup_vm_events - Read memory cgroup's vm event counter
- * @memcg: memory cgroup
- * @event: event id
- *
- * Allows to read memory cgroup event counters.
- *
- * Return: The current value of the corresponding events counter.
- */
- __bpf_kfunc unsigned long bpf_mem_cgroup_vm_events(struct mem_cgroup *memcg,
- enum vm_event_item event)
- {
- if (unlikely(!memcg_vm_event_item_valid(event)))
- return (unsigned long)-1;
- return memcg_events(memcg, event);
- }
- /**
- * bpf_mem_cgroup_usage - Read memory cgroup's usage
- * @memcg: memory cgroup
- *
- * Please, note that the root memory cgroup it special and is exempt
- * from the memory accounting. The returned value is a sum of sub-cgroup's
- * usages and it not reflecting the size of the root memory cgroup itself.
- * If you need to get an approximation, you can use root level statistics:
- * e.g. NR_FILE_PAGES + NR_ANON_MAPPED.
- *
- * Return: The current memory cgroup size in bytes.
- */
- __bpf_kfunc unsigned long bpf_mem_cgroup_usage(struct mem_cgroup *memcg)
- {
- return page_counter_read(&memcg->memory) * PAGE_SIZE;
- }
- /**
- * bpf_mem_cgroup_memory_events - Read memory cgroup's memory event value
- * @memcg: memory cgroup
- * @event: memory event id
- *
- * Return: The current value of the memory event counter.
- */
- __bpf_kfunc unsigned long bpf_mem_cgroup_memory_events(struct mem_cgroup *memcg,
- enum memcg_memory_event event)
- {
- if (unlikely(event >= MEMCG_NR_MEMORY_EVENTS))
- return (unsigned long)-1;
- return atomic_long_read(&memcg->memory_events[event]);
- }
- /**
- * bpf_mem_cgroup_page_state - Read memory cgroup's page state counter
- * @memcg: memory cgroup
- * @idx: counter idx
- *
- * Allows to read memory cgroup statistics. The output is in bytes.
- *
- * Return: The value of the page state counter in bytes.
- */
- __bpf_kfunc unsigned long bpf_mem_cgroup_page_state(struct mem_cgroup *memcg, int idx)
- {
- if (unlikely(!memcg_stat_item_valid(idx)))
- return (unsigned long)-1;
- return memcg_page_state_output(memcg, idx);
- }
- /**
- * bpf_mem_cgroup_flush_stats - Flush memory cgroup's statistics
- * @memcg: memory cgroup
- *
- * Propagate memory cgroup's statistics up the cgroup tree.
- */
- __bpf_kfunc void bpf_mem_cgroup_flush_stats(struct mem_cgroup *memcg)
- {
- mem_cgroup_flush_stats(memcg);
- }
- __bpf_kfunc_end_defs();
- BTF_KFUNCS_START(bpf_memcontrol_kfuncs)
- BTF_ID_FLAGS(func, bpf_get_root_mem_cgroup, KF_ACQUIRE | KF_RET_NULL)
- BTF_ID_FLAGS(func, bpf_get_mem_cgroup, KF_ACQUIRE | KF_RET_NULL | KF_RCU)
- BTF_ID_FLAGS(func, bpf_put_mem_cgroup, KF_RELEASE)
- BTF_ID_FLAGS(func, bpf_mem_cgroup_vm_events)
- BTF_ID_FLAGS(func, bpf_mem_cgroup_memory_events)
- BTF_ID_FLAGS(func, bpf_mem_cgroup_usage)
- BTF_ID_FLAGS(func, bpf_mem_cgroup_page_state)
- BTF_ID_FLAGS(func, bpf_mem_cgroup_flush_stats, KF_SLEEPABLE)
- BTF_KFUNCS_END(bpf_memcontrol_kfuncs)
- static const struct btf_kfunc_id_set bpf_memcontrol_kfunc_set = {
- .owner = THIS_MODULE,
- .set = &bpf_memcontrol_kfuncs,
- };
- static int __init bpf_memcontrol_init(void)
- {
- int err;
- err = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC,
- &bpf_memcontrol_kfunc_set);
- if (err)
- pr_warn("error while registering bpf memcontrol kfuncs: %d", err);
- return err;
- }
- late_initcall(bpf_memcontrol_init);
|