]> Git Repo - linux.git/blame - kernel/bpf/bpf_cgrp_storage.c
Merge tag 'tomoyo-pr-20250211' of git://git.code.sf.net/p/tomoyo/tomoyo
[linux.git] / kernel / bpf / bpf_cgrp_storage.c
CommitLineData
c4bcfb38
YS
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 */
5
6#include <linux/types.h>
7#include <linux/bpf.h>
8#include <linux/bpf_local_storage.h>
9#include <uapi/linux/btf.h>
10#include <linux/btf_ids.h>
11
12DEFINE_BPF_STORAGE_CACHE(cgroup_cache);
13
14static DEFINE_PER_CPU(int, bpf_cgrp_storage_busy);
15
16static void bpf_cgrp_storage_lock(void)
17{
25dc65f7 18 cant_migrate();
c4bcfb38
YS
19 this_cpu_inc(bpf_cgrp_storage_busy);
20}
21
22static void bpf_cgrp_storage_unlock(void)
23{
24 this_cpu_dec(bpf_cgrp_storage_busy);
c4bcfb38
YS
25}
26
27static bool bpf_cgrp_storage_trylock(void)
28{
25dc65f7 29 cant_migrate();
c4bcfb38
YS
30 if (unlikely(this_cpu_inc_return(bpf_cgrp_storage_busy) != 1)) {
31 this_cpu_dec(bpf_cgrp_storage_busy);
c4bcfb38
YS
32 return false;
33 }
34 return true;
35}
36
37static struct bpf_local_storage __rcu **cgroup_storage_ptr(void *owner)
38{
39 struct cgroup *cg = owner;
40
41 return &cg->bpf_cgrp_storage;
42}
43
44void bpf_cgrp_storage_free(struct cgroup *cgroup)
45{
46 struct bpf_local_storage *local_storage;
c4bcfb38 47
25dc65f7 48 migrate_disable();
c4bcfb38
YS
49 rcu_read_lock();
50 local_storage = rcu_dereference(cgroup->bpf_cgrp_storage);
25dc65f7
HT
51 if (!local_storage)
52 goto out;
c4bcfb38
YS
53
54 bpf_cgrp_storage_lock();
2ffcb6fc 55 bpf_local_storage_destroy(local_storage);
c4bcfb38 56 bpf_cgrp_storage_unlock();
25dc65f7 57out:
c4bcfb38 58 rcu_read_unlock();
25dc65f7 59 migrate_enable();
c4bcfb38
YS
60}
61
62static struct bpf_local_storage_data *
63cgroup_storage_lookup(struct cgroup *cgroup, struct bpf_map *map, bool cacheit_lockit)
64{
65 struct bpf_local_storage *cgroup_storage;
66 struct bpf_local_storage_map *smap;
67
68 cgroup_storage = rcu_dereference_check(cgroup->bpf_cgrp_storage,
69 bpf_rcu_lock_held());
70 if (!cgroup_storage)
71 return NULL;
72
73 smap = (struct bpf_local_storage_map *)map;
74 return bpf_local_storage_lookup(cgroup_storage, smap, cacheit_lockit);
75}
76
77static void *bpf_cgrp_storage_lookup_elem(struct bpf_map *map, void *key)
78{
79 struct bpf_local_storage_data *sdata;
80 struct cgroup *cgroup;
81 int fd;
82
83 fd = *(int *)key;
73d9eb34 84 cgroup = cgroup_v1v2_get_from_fd(fd);
c4bcfb38
YS
85 if (IS_ERR(cgroup))
86 return ERR_CAST(cgroup);
87
88 bpf_cgrp_storage_lock();
89 sdata = cgroup_storage_lookup(cgroup, map, true);
90 bpf_cgrp_storage_unlock();
91 cgroup_put(cgroup);
92 return sdata ? sdata->data : NULL;
93}
94
d7ba4cc9
JK
95static long bpf_cgrp_storage_update_elem(struct bpf_map *map, void *key,
96 void *value, u64 map_flags)
c4bcfb38
YS
97{
98 struct bpf_local_storage_data *sdata;
99 struct cgroup *cgroup;
100 int fd;
101
102 fd = *(int *)key;
73d9eb34 103 cgroup = cgroup_v1v2_get_from_fd(fd);
c4bcfb38
YS
104 if (IS_ERR(cgroup))
105 return PTR_ERR(cgroup);
106
107 bpf_cgrp_storage_lock();
108 sdata = bpf_local_storage_update(cgroup, (struct bpf_local_storage_map *)map,
b9a5a07a 109 value, map_flags, false, GFP_ATOMIC);
c4bcfb38
YS
110 bpf_cgrp_storage_unlock();
111 cgroup_put(cgroup);
112 return PTR_ERR_OR_ZERO(sdata);
113}
114
115static int cgroup_storage_delete(struct cgroup *cgroup, struct bpf_map *map)
116{
117 struct bpf_local_storage_data *sdata;
118
119 sdata = cgroup_storage_lookup(cgroup, map, false);
120 if (!sdata)
121 return -ENOENT;
122
a47eabf2 123 bpf_selem_unlink(SELEM(sdata), false);
c4bcfb38
YS
124 return 0;
125}
126
d7ba4cc9 127static long bpf_cgrp_storage_delete_elem(struct bpf_map *map, void *key)
c4bcfb38
YS
128{
129 struct cgroup *cgroup;
130 int err, fd;
131
132 fd = *(int *)key;
73d9eb34 133 cgroup = cgroup_v1v2_get_from_fd(fd);
c4bcfb38
YS
134 if (IS_ERR(cgroup))
135 return PTR_ERR(cgroup);
136
137 bpf_cgrp_storage_lock();
138 err = cgroup_storage_delete(cgroup, map);
139 bpf_cgrp_storage_unlock();
140 cgroup_put(cgroup);
141 return err;
142}
143
144static int notsupp_get_next_key(struct bpf_map *map, void *key, void *next_key)
145{
146 return -ENOTSUPP;
147}
148
149static struct bpf_map *cgroup_storage_map_alloc(union bpf_attr *attr)
150{
08a7ce38 151 return bpf_local_storage_map_alloc(attr, &cgroup_cache, true);
c4bcfb38
YS
152}
153
154static void cgroup_storage_map_free(struct bpf_map *map)
155{
156 bpf_local_storage_map_free(map, &cgroup_cache, NULL);
157}
158
159/* *gfp_flags* is a hidden argument provided by the verifier */
160BPF_CALL_5(bpf_cgrp_storage_get, struct bpf_map *, map, struct cgroup *, cgroup,
161 void *, value, u64, flags, gfp_t, gfp_flags)
162{
163 struct bpf_local_storage_data *sdata;
164
165 WARN_ON_ONCE(!bpf_rcu_lock_held());
166 if (flags & ~(BPF_LOCAL_STORAGE_GET_F_CREATE))
167 return (unsigned long)NULL;
168
169 if (!cgroup)
170 return (unsigned long)NULL;
171
172 if (!bpf_cgrp_storage_trylock())
173 return (unsigned long)NULL;
174
175 sdata = cgroup_storage_lookup(cgroup, map, true);
176 if (sdata)
177 goto unlock;
178
179 /* only allocate new storage, when the cgroup is refcounted */
180 if (!percpu_ref_is_dying(&cgroup->self.refcnt) &&
181 (flags & BPF_LOCAL_STORAGE_GET_F_CREATE))
182 sdata = bpf_local_storage_update(cgroup, (struct bpf_local_storage_map *)map,
b9a5a07a 183 value, BPF_NOEXIST, false, gfp_flags);
c4bcfb38
YS
184
185unlock:
186 bpf_cgrp_storage_unlock();
187 return IS_ERR_OR_NULL(sdata) ? (unsigned long)NULL : (unsigned long)sdata->data;
188}
189
190BPF_CALL_2(bpf_cgrp_storage_delete, struct bpf_map *, map, struct cgroup *, cgroup)
191{
192 int ret;
193
194 WARN_ON_ONCE(!bpf_rcu_lock_held());
195 if (!cgroup)
196 return -EINVAL;
197
198 if (!bpf_cgrp_storage_trylock())
199 return -EBUSY;
200
201 ret = cgroup_storage_delete(cgroup, map);
202 bpf_cgrp_storage_unlock();
203 return ret;
204}
205
c4bcfb38
YS
206const struct bpf_map_ops cgrp_storage_map_ops = {
207 .map_meta_equal = bpf_map_meta_equal,
208 .map_alloc_check = bpf_local_storage_map_alloc_check,
209 .map_alloc = cgroup_storage_map_alloc,
210 .map_free = cgroup_storage_map_free,
211 .map_get_next_key = notsupp_get_next_key,
212 .map_lookup_elem = bpf_cgrp_storage_lookup_elem,
213 .map_update_elem = bpf_cgrp_storage_update_elem,
214 .map_delete_elem = bpf_cgrp_storage_delete_elem,
215 .map_check_btf = bpf_local_storage_map_check_btf,
7490b7f1 216 .map_mem_usage = bpf_local_storage_map_mem_usage,
3144bfa5 217 .map_btf_id = &bpf_local_storage_map_btf_id[0],
c4bcfb38
YS
218 .map_owner_storage_ptr = cgroup_storage_ptr,
219};
220
221const struct bpf_func_proto bpf_cgrp_storage_get_proto = {
222 .func = bpf_cgrp_storage_get,
223 .gpl_only = false,
224 .ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL,
225 .arg1_type = ARG_CONST_MAP_PTR,
91571a51 226 .arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
c4bcfb38
YS
227 .arg2_btf_id = &bpf_cgroup_btf_id[0],
228 .arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
229 .arg4_type = ARG_ANYTHING,
230};
231
232const struct bpf_func_proto bpf_cgrp_storage_delete_proto = {
233 .func = bpf_cgrp_storage_delete,
234 .gpl_only = false,
235 .ret_type = RET_INTEGER,
236 .arg1_type = ARG_CONST_MAP_PTR,
91571a51 237 .arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
c4bcfb38
YS
238 .arg2_btf_id = &bpf_cgroup_btf_id[0],
239};
This page took 0.303724 seconds and 5 git commands to generate.