1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
6 #include <linux/types.h>
8 #include <linux/bpf_local_storage.h>
9 #include <uapi/linux/btf.h>
10 #include <linux/btf_ids.h>
12 DEFINE_BPF_STORAGE_CACHE(cgroup_cache
);
14 static DEFINE_PER_CPU(int, bpf_cgrp_storage_busy
);
16 static void bpf_cgrp_storage_lock(void)
19 this_cpu_inc(bpf_cgrp_storage_busy
);
22 static void bpf_cgrp_storage_unlock(void)
24 this_cpu_dec(bpf_cgrp_storage_busy
);
28 static bool bpf_cgrp_storage_trylock(void)
31 if (unlikely(this_cpu_inc_return(bpf_cgrp_storage_busy
) != 1)) {
32 this_cpu_dec(bpf_cgrp_storage_busy
);
39 static struct bpf_local_storage __rcu
**cgroup_storage_ptr(void *owner
)
41 struct cgroup
*cg
= owner
;
43 return &cg
->bpf_cgrp_storage
;
46 void bpf_cgrp_storage_free(struct cgroup
*cgroup
)
48 struct bpf_local_storage
*local_storage
;
51 local_storage
= rcu_dereference(cgroup
->bpf_cgrp_storage
);
57 bpf_cgrp_storage_lock();
58 bpf_local_storage_destroy(local_storage
);
59 bpf_cgrp_storage_unlock();
63 static struct bpf_local_storage_data
*
64 cgroup_storage_lookup(struct cgroup
*cgroup
, struct bpf_map
*map
, bool cacheit_lockit
)
66 struct bpf_local_storage
*cgroup_storage
;
67 struct bpf_local_storage_map
*smap
;
69 cgroup_storage
= rcu_dereference_check(cgroup
->bpf_cgrp_storage
,
74 smap
= (struct bpf_local_storage_map
*)map
;
75 return bpf_local_storage_lookup(cgroup_storage
, smap
, cacheit_lockit
);
78 static void *bpf_cgrp_storage_lookup_elem(struct bpf_map
*map
, void *key
)
80 struct bpf_local_storage_data
*sdata
;
81 struct cgroup
*cgroup
;
85 cgroup
= cgroup_v1v2_get_from_fd(fd
);
87 return ERR_CAST(cgroup
);
89 bpf_cgrp_storage_lock();
90 sdata
= cgroup_storage_lookup(cgroup
, map
, true);
91 bpf_cgrp_storage_unlock();
93 return sdata
? sdata
->data
: NULL
;
96 static long bpf_cgrp_storage_update_elem(struct bpf_map
*map
, void *key
,
97 void *value
, u64 map_flags
)
99 struct bpf_local_storage_data
*sdata
;
100 struct cgroup
*cgroup
;
104 cgroup
= cgroup_v1v2_get_from_fd(fd
);
106 return PTR_ERR(cgroup
);
108 bpf_cgrp_storage_lock();
109 sdata
= bpf_local_storage_update(cgroup
, (struct bpf_local_storage_map
*)map
,
110 value
, map_flags
, false, GFP_ATOMIC
);
111 bpf_cgrp_storage_unlock();
113 return PTR_ERR_OR_ZERO(sdata
);
116 static int cgroup_storage_delete(struct cgroup
*cgroup
, struct bpf_map
*map
)
118 struct bpf_local_storage_data
*sdata
;
120 sdata
= cgroup_storage_lookup(cgroup
, map
, false);
124 bpf_selem_unlink(SELEM(sdata
), false);
128 static long bpf_cgrp_storage_delete_elem(struct bpf_map
*map
, void *key
)
130 struct cgroup
*cgroup
;
134 cgroup
= cgroup_v1v2_get_from_fd(fd
);
136 return PTR_ERR(cgroup
);
138 bpf_cgrp_storage_lock();
139 err
= cgroup_storage_delete(cgroup
, map
);
140 bpf_cgrp_storage_unlock();
145 static int notsupp_get_next_key(struct bpf_map
*map
, void *key
, void *next_key
)
150 static struct bpf_map
*cgroup_storage_map_alloc(union bpf_attr
*attr
)
152 return bpf_local_storage_map_alloc(attr
, &cgroup_cache
, true);
155 static void cgroup_storage_map_free(struct bpf_map
*map
)
157 bpf_local_storage_map_free(map
, &cgroup_cache
, NULL
);
160 /* *gfp_flags* is a hidden argument provided by the verifier */
161 BPF_CALL_5(bpf_cgrp_storage_get
, struct bpf_map
*, map
, struct cgroup
*, cgroup
,
162 void *, value
, u64
, flags
, gfp_t
, gfp_flags
)
164 struct bpf_local_storage_data
*sdata
;
166 WARN_ON_ONCE(!bpf_rcu_lock_held());
167 if (flags
& ~(BPF_LOCAL_STORAGE_GET_F_CREATE
))
168 return (unsigned long)NULL
;
171 return (unsigned long)NULL
;
173 if (!bpf_cgrp_storage_trylock())
174 return (unsigned long)NULL
;
176 sdata
= cgroup_storage_lookup(cgroup
, map
, true);
180 /* only allocate new storage, when the cgroup is refcounted */
181 if (!percpu_ref_is_dying(&cgroup
->self
.refcnt
) &&
182 (flags
& BPF_LOCAL_STORAGE_GET_F_CREATE
))
183 sdata
= bpf_local_storage_update(cgroup
, (struct bpf_local_storage_map
*)map
,
184 value
, BPF_NOEXIST
, false, gfp_flags
);
187 bpf_cgrp_storage_unlock();
188 return IS_ERR_OR_NULL(sdata
) ? (unsigned long)NULL
: (unsigned long)sdata
->data
;
191 BPF_CALL_2(bpf_cgrp_storage_delete
, struct bpf_map
*, map
, struct cgroup
*, cgroup
)
195 WARN_ON_ONCE(!bpf_rcu_lock_held());
199 if (!bpf_cgrp_storage_trylock())
202 ret
= cgroup_storage_delete(cgroup
, map
);
203 bpf_cgrp_storage_unlock();
207 const struct bpf_map_ops cgrp_storage_map_ops
= {
208 .map_meta_equal
= bpf_map_meta_equal
,
209 .map_alloc_check
= bpf_local_storage_map_alloc_check
,
210 .map_alloc
= cgroup_storage_map_alloc
,
211 .map_free
= cgroup_storage_map_free
,
212 .map_get_next_key
= notsupp_get_next_key
,
213 .map_lookup_elem
= bpf_cgrp_storage_lookup_elem
,
214 .map_update_elem
= bpf_cgrp_storage_update_elem
,
215 .map_delete_elem
= bpf_cgrp_storage_delete_elem
,
216 .map_check_btf
= bpf_local_storage_map_check_btf
,
217 .map_mem_usage
= bpf_local_storage_map_mem_usage
,
218 .map_btf_id
= &bpf_local_storage_map_btf_id
[0],
219 .map_owner_storage_ptr
= cgroup_storage_ptr
,
222 const struct bpf_func_proto bpf_cgrp_storage_get_proto
= {
223 .func
= bpf_cgrp_storage_get
,
225 .ret_type
= RET_PTR_TO_MAP_VALUE_OR_NULL
,
226 .arg1_type
= ARG_CONST_MAP_PTR
,
227 .arg2_type
= ARG_PTR_TO_BTF_ID_OR_NULL
,
228 .arg2_btf_id
= &bpf_cgroup_btf_id
[0],
229 .arg3_type
= ARG_PTR_TO_MAP_VALUE_OR_NULL
,
230 .arg4_type
= ARG_ANYTHING
,
233 const struct bpf_func_proto bpf_cgrp_storage_delete_proto
= {
234 .func
= bpf_cgrp_storage_delete
,
236 .ret_type
= RET_INTEGER
,
237 .arg1_type
= ARG_CONST_MAP_PTR
,
238 .arg2_type
= ARG_PTR_TO_BTF_ID_OR_NULL
,
239 .arg2_btf_id
= &bpf_cgroup_btf_id
[0],