Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "cgen/cgen.h"
7 : :
8 : : #include <errno.h>
9 : : #include <stddef.h>
10 : : #include <stdint.h>
11 : : #include <stdio.h>
12 : : #include <stdlib.h>
13 : : #include <string.h>
14 : : #include <sys/types.h>
15 : : #include <unistd.h>
16 : :
17 : : #include <bpfilter/bpf.h>
18 : : #include <bpfilter/chain.h>
19 : : #include <bpfilter/core/list.h>
20 : : #include <bpfilter/counter.h>
21 : : #include <bpfilter/dump.h>
22 : : #include <bpfilter/helper.h>
23 : : #include <bpfilter/hook.h>
24 : : #include <bpfilter/logger.h>
25 : : #include <bpfilter/pack.h>
26 : : #include <bpfilter/rule.h>
27 : :
28 : : #include "cgen/dump.h"
29 : : #include "cgen/handle.h"
30 : : #include "cgen/prog/link.h"
31 : : #include "cgen/prog/map.h"
32 : : #include "cgen/program.h"
33 : : #include "core/lock.h"
34 : :
35 : : #define _BF_PROG_NAME "bf_prog"
36 : : #define _BF_CTX_PIN_NAME "bf_ctx"
37 : : #define _BF_CTX_TMP_PIN_NAME "bf_ctx_tmp"
38 : :
39 : : /**
40 : : * @brief Persist the codegen state to a BPF context map in bpffs.
41 : : *
42 : : * Serializes the cgen, creates a `BPF_MAP_TYPE_ARRAY` map with 1 entry
43 : : * containing the serialized data, pins it as `bf_ctx_tmp`, then atomically
44 : : * renames to `bf_ctx`. The map fd is closed after pinning - this is a
45 : : * one-shot operation.
46 : : *
47 : : * @param cgen Codegen to persist. Can't be NULL.
48 : : * @param dir_fd File descriptor of the chain's bpffs pin directory. Must be
49 : : * valid.
50 : : * @return 0 on success, or negative errno value on failure.
51 : : */
52 : 1329 : static int _bf_cgen_persist(const struct bf_cgen *cgen, int dir_fd)
53 : : {
54 : 1329 : _free_bf_wpack_ bf_wpack_t *pack = NULL;
55 : 1329 : _free_bf_map_ struct bf_map *map = NULL;
56 : : const void *data;
57 : : size_t data_len;
58 : 1329 : uint32_t key = 0;
59 : : int r;
60 : :
61 : : assert(cgen);
62 : :
63 : 1329 : r = bf_wpack_new(&pack);
64 [ - + ]: 1329 : if (r)
65 [ # # ]: 0 : return bf_err_r(r, "failed to create wpack for bf_cgen");
66 : :
67 : 1329 : r = bf_cgen_pack(cgen, pack);
68 [ - + ]: 1329 : if (r)
69 [ # # ]: 0 : return bf_err_r(r, "failed to pack bf_cgen");
70 : :
71 : 1329 : r = bf_wpack_get_data(pack, &data, &data_len);
72 [ - + ]: 1329 : if (r)
73 [ # # ]: 0 : return bf_err_r(r, "failed to get data from bf_cgen wpack");
74 : :
75 : 1329 : r = bf_map_new(&map, _BF_CTX_PIN_NAME, BF_MAP_TYPE_CTX, sizeof(uint32_t),
76 : : data_len, 1);
77 [ - + ]: 1329 : if (r)
78 [ # # ]: 0 : return bf_err_r(r, "failed to create context map");
79 : :
80 : 1329 : r = bf_map_set_elem(map, &key, (void *)data);
81 [ - + ]: 1329 : if (r)
82 [ # # ]: 0 : return bf_err_r(r, "failed to write context to map");
83 : :
84 : : // Remove stale temporary pin if present.
85 : 1329 : unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
86 : :
87 : 1329 : r = bf_bpf_obj_pin(_BF_CTX_TMP_PIN_NAME, map->fd, dir_fd);
88 [ - + ]: 1329 : if (r)
89 [ # # ]: 0 : return bf_err_r(r, "failed to pin context map");
90 : :
91 : 1329 : r = renameat(dir_fd, _BF_CTX_TMP_PIN_NAME, dir_fd, _BF_CTX_PIN_NAME);
92 [ - + ]: 1329 : if (r) {
93 : 0 : r = -errno;
94 : 0 : unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
95 [ # # ]: 0 : return bf_err_r(r, "failed to atomically replace context map pin");
96 : : }
97 : :
98 : : return 0;
99 : : }
100 : :
101 : 5327 : static int _bf_cgen_new_from_pack(struct bf_cgen **cgen, struct bf_lock *lock,
102 : : bf_rpack_node_t node)
103 : : {
104 : 5327 : _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
105 : : bf_rpack_node_t child;
106 : : int r;
107 : :
108 : : assert(cgen);
109 : : assert(lock);
110 : :
111 : 5327 : _cgen = calloc(1, sizeof(*_cgen));
112 [ + - ]: 5327 : if (!_cgen)
113 : : return -ENOMEM;
114 : :
115 : 5327 : r = bf_rpack_kv_obj(node, "chain", &child);
116 [ - + ]: 5327 : if (r)
117 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_cgen.chain");
118 : :
119 : 5327 : r = bf_chain_new_from_pack(&_cgen->chain, child);
120 [ - + ]: 5327 : if (r)
121 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_cgen.chain");
122 : :
123 : 5327 : r = bf_rpack_kv_node(node, "handle", &child);
124 [ - + ]: 5327 : if (r)
125 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_cgen.handle");
126 : :
127 : 5327 : r = bf_handle_new_from_pack(&_cgen->handle, lock, child);
128 [ + - ]: 5327 : if (r)
129 : : return r;
130 : :
131 : 5327 : *cgen = TAKE_PTR(_cgen);
132 : :
133 : 5327 : return 0;
134 : : }
135 : :
136 : 5330 : int bf_cgen_new_from_dir_fd(struct bf_cgen **cgen, struct bf_lock *lock)
137 : : {
138 : 5330 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
139 : 5330 : _cleanup_close_ int map_fd = -1;
140 : : _cleanup_free_ void *data = NULL;
141 : : struct bpf_map_info info;
142 : 5330 : uint32_t key = 0;
143 : : int r;
144 : :
145 : : assert(cgen);
146 : : assert(lock);
147 : :
148 : 5330 : r = bf_bpf_obj_get(_BF_CTX_PIN_NAME, lock->chain_fd, &map_fd);
149 [ + + ]: 5330 : if (r < 0)
150 [ + - ]: 3 : return bf_err_r(r, "failed to open pinned context map");
151 : :
152 : 5327 : r = bf_bpf_map_get_info(map_fd, &info);
153 [ - + ]: 5327 : if (r)
154 [ # # ]: 0 : return bf_err_r(r, "failed to get context map info");
155 : :
156 [ - + ]: 5327 : if (info.value_size == 0)
157 [ # # ]: 0 : return bf_err_r(-EINVAL, "invalid serialized context size");
158 : :
159 : 5327 : data = malloc(info.value_size);
160 [ + - ]: 5327 : if (!data)
161 : : return -ENOMEM;
162 : :
163 : 5327 : r = bf_bpf_map_lookup_elem(map_fd, &key, data);
164 [ - + ]: 5327 : if (r)
165 [ # # ]: 0 : return bf_err_r(r, "failed to read context from map");
166 : :
167 : 5327 : r = bf_rpack_new(&pack, data, info.value_size);
168 [ - + ]: 5327 : if (r)
169 [ # # ]: 0 : return bf_err_r(r, "failed to create rpack for bf_cgen");
170 : :
171 : 5327 : r = _bf_cgen_new_from_pack(cgen, lock, bf_rpack_root(pack));
172 [ - + ]: 5327 : if (r)
173 [ # # ]: 0 : return bf_err_r(r, "failed to deserialize cgen from context map");
174 : :
175 : : return 0;
176 : : }
177 : :
178 : 1296 : int bf_cgen_new(struct bf_cgen **cgen, struct bf_chain **chain)
179 : : {
180 : 1296 : _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
181 : : int r;
182 : :
183 : : assert(cgen);
184 : : assert(chain);
185 : :
186 : 1296 : _cgen = calloc(1, sizeof(*_cgen));
187 [ + - ]: 1296 : if (!_cgen)
188 : : return -ENOMEM;
189 : :
190 : 1296 : _cgen->chain = TAKE_PTR(*chain);
191 : :
192 : 1296 : r = bf_handle_new(&_cgen->handle, _BF_PROG_NAME);
193 [ + - ]: 1296 : if (r)
194 : : return r;
195 : :
196 : 1296 : *cgen = TAKE_PTR(_cgen);
197 : :
198 : 1296 : return 0;
199 : : }
200 : :
201 : 22676 : void bf_cgen_free(struct bf_cgen **cgen)
202 : : {
203 : : assert(cgen);
204 : :
205 [ + + ]: 22676 : if (!*cgen)
206 : : return;
207 : :
208 : 6623 : bf_handle_free(&(*cgen)->handle);
209 : 6623 : bf_chain_free(&(*cgen)->chain);
210 : :
211 : 6623 : free(*cgen);
212 : 6623 : *cgen = NULL;
213 : : }
214 : :
215 : 1329 : int bf_cgen_pack(const struct bf_cgen *cgen, bf_wpack_t *pack)
216 : : {
217 : : assert(cgen);
218 : : assert(pack);
219 : :
220 : 1329 : bf_wpack_open_object(pack, "chain");
221 : 1329 : bf_chain_pack(cgen->chain, pack);
222 : 1329 : bf_wpack_close_object(pack);
223 : :
224 : 1329 : bf_wpack_open_object(pack, "handle");
225 : 1329 : bf_handle_pack(cgen->handle, pack);
226 : 1329 : bf_wpack_close_object(pack);
227 : :
228 [ - + ]: 1329 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
229 : : }
230 : :
231 : 16 : void bf_cgen_dump(const struct bf_cgen *cgen, prefix_t *prefix)
232 : : {
233 : : assert(cgen);
234 : : assert(prefix);
235 : :
236 [ - + ]: 16 : DUMP(prefix, "struct bf_cgen at %p", cgen);
237 : :
238 : 16 : bf_dump_prefix_push(prefix);
239 : :
240 : : // Chain
241 [ - + ]: 16 : DUMP(prefix, "chain: struct bf_chain *");
242 : 16 : bf_dump_prefix_push(prefix);
243 : 16 : bf_chain_dump(cgen->chain, bf_dump_prefix_last(prefix));
244 : 16 : bf_dump_prefix_pop(prefix);
245 : :
246 [ - + ]: 16 : DUMP(bf_dump_prefix_last(prefix), "handle: struct bf_handle *");
247 : 16 : bf_dump_prefix_push(prefix);
248 : 16 : bf_handle_dump(cgen->handle, bf_dump_prefix_last(prefix));
249 : 16 : bf_dump_prefix_pop(prefix);
250 : :
251 : 16 : bf_dump_prefix_pop(prefix);
252 : 16 : }
253 : :
254 : 1155 : int bf_cgen_load_counters(struct bf_cgen *cgen)
255 : : {
256 : : int r;
257 : :
258 : : assert(cgen);
259 : :
260 [ + + + + : 4624 : bf_list_foreach (&cgen->chain->rules, rule_node) {
+ + ]
261 : : struct bf_rule *rule = bf_list_node_get_data(rule_node);
262 : :
263 [ + + ]: 1157 : if (!rule->has_counters)
264 : 14 : continue;
265 : :
266 : 1143 : r = bf_cgen_get_counter(cgen, rule->index, &rule->counters);
267 [ - + ]: 1143 : if (r) {
268 [ # # ]: 0 : return bf_err_r(r, "failed to load counter for rule %u",
269 : : rule->index);
270 : : }
271 : : }
272 : :
273 : 1155 : r = bf_cgen_get_counter(cgen, BF_COUNTER_POLICY,
274 : 1155 : &cgen->chain->policy_counters);
275 [ - + ]: 1155 : if (r) {
276 [ # # ]: 0 : return bf_err_r(r, "failed to load policy counters for '%s'",
277 : : cgen->chain->name);
278 : : }
279 : :
280 : 1155 : r = bf_cgen_get_counter(cgen, BF_COUNTER_ERRORS,
281 : 1155 : &cgen->chain->error_counters);
282 [ - + ]: 1155 : if (r) {
283 [ # # ]: 0 : return bf_err_r(r, "failed to load error counters for '%s'",
284 : : cgen->chain->name);
285 : : }
286 : :
287 : : return 0;
288 : : }
289 : :
290 : 3453 : int bf_cgen_get_counter(const struct bf_cgen *cgen,
291 : : enum bf_counter_type counter_idx,
292 : : struct bf_counter *counter)
293 : : {
294 : : assert(cgen);
295 : : assert(counter);
296 : :
297 : : /* There are two more counter than rules. The special counters must
298 : : * be accessed via the specific values, to avoid confusion. */
299 [ + + ]: 3453 : enum bf_counter_type rule_count = bf_list_size(&cgen->chain->rules);
300 [ + + ]: 3453 : if (counter_idx == BF_COUNTER_POLICY) {
301 : : counter_idx = rule_count;
302 [ + + ]: 2298 : } else if (counter_idx == BF_COUNTER_ERRORS) {
303 : 1155 : counter_idx = rule_count + 1;
304 [ + - ]: 1143 : } else if (counter_idx < 0 || counter_idx >= rule_count) {
305 : : return -EINVAL;
306 : : }
307 : :
308 : 3453 : return bf_handle_get_counter(cgen->handle, counter_idx, counter);
309 : : }
310 : :
311 : 1279 : int bf_cgen_set(struct bf_cgen *cgen, struct bf_hookopts **hookopts,
312 : : struct bf_lock *lock)
313 : : {
314 : 1279 : _free_bf_program_ struct bf_program *prog = NULL;
315 : : int r;
316 : :
317 : : assert(cgen);
318 : : assert(lock);
319 : :
320 : 1279 : r = bf_program_new(&prog, cgen->chain, cgen->handle);
321 [ + - ]: 1279 : if (r < 0)
322 : : return r;
323 : :
324 : 1279 : r = bf_program_generate(prog);
325 [ + + ]: 1279 : if (r < 0)
326 [ + - ]: 3 : return bf_err_r(r, "failed to generate bf_program");
327 : :
328 : 1276 : r = bf_program_load(prog);
329 [ - + ]: 1276 : if (r < 0)
330 [ # # ]: 0 : return bf_err_r(r, "failed to load the chain");
331 : :
332 [ + + ]: 1276 : if (hookopts) {
333 : 109 : r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
334 [ + + ]: 109 : if (r < 0)
335 [ + - ]: 2 : return bf_err_r(r, "failed to load and attach the chain");
336 : : }
337 : :
338 : 1274 : r = bf_handle_pin(cgen->handle, lock);
339 [ + + ]: 1274 : if (r)
340 : : return r;
341 : :
342 : 1273 : r = _bf_cgen_persist(cgen, lock->chain_fd);
343 [ - + ]: 1273 : if (r) {
344 : 0 : bf_handle_unpin(cgen->handle, lock);
345 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
346 : : cgen->chain->name);
347 : : }
348 : :
349 : : return 0;
350 : : }
351 : :
352 : 17 : int bf_cgen_load(struct bf_cgen *cgen, struct bf_lock *lock)
353 : : {
354 : 17 : _free_bf_program_ struct bf_program *prog = NULL;
355 : : int r;
356 : :
357 : : assert(cgen);
358 : : assert(lock);
359 : :
360 : 17 : r = bf_program_new(&prog, cgen->chain, cgen->handle);
361 [ + - ]: 17 : if (r < 0)
362 : : return r;
363 : :
364 : 17 : r = bf_program_generate(prog);
365 [ - + ]: 17 : if (r < 0)
366 [ # # ]: 0 : return bf_err_r(r, "failed to generate bf_program");
367 : :
368 : 17 : r = bf_program_load(prog);
369 [ - + ]: 17 : if (r < 0)
370 [ # # ]: 0 : return bf_err_r(r, "failed to load the chain");
371 : :
372 : 17 : r = bf_handle_pin(cgen->handle, lock);
373 [ + + ]: 17 : if (r)
374 : : return r;
375 : :
376 : 16 : r = _bf_cgen_persist(cgen, lock->chain_fd);
377 [ - + ]: 16 : if (r) {
378 : 0 : bf_handle_unpin(cgen->handle, lock);
379 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
380 : : cgen->chain->name);
381 : : }
382 : :
383 [ + - ]: 16 : bf_info("load %s", cgen->chain->name);
384 : 16 : bf_cgen_dump(cgen, EMPTY_PREFIX);
385 : :
386 : 16 : return 0;
387 : : }
388 : :
389 : 14 : int bf_cgen_attach(struct bf_cgen *cgen, struct bf_hookopts **hookopts,
390 : : struct bf_lock *lock)
391 : : {
392 : : int r;
393 : :
394 : : assert(cgen);
395 : : assert(hookopts);
396 : : assert(lock);
397 : :
398 [ + - ]: 14 : bf_info("attaching %s to %s", cgen->chain->name,
399 : : bf_hook_to_str(cgen->chain->hook));
400 : 14 : bf_hookopts_dump(*hookopts, EMPTY_PREFIX);
401 : :
402 : 14 : r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
403 [ + + ]: 14 : if (r < 0)
404 [ + - ]: 2 : return bf_err_r(r, "failed to attach chain '%s'", cgen->chain->name);
405 : :
406 : 12 : r = bf_link_pin(cgen->handle->link, lock);
407 [ - + ]: 12 : if (r) {
408 : 0 : bf_handle_detach(cgen->handle);
409 : 0 : return r;
410 : : }
411 : :
412 : 12 : r = _bf_cgen_persist(cgen, lock->chain_fd);
413 [ - + ]: 12 : if (r) {
414 : 0 : bf_link_unpin(cgen->handle->link, lock);
415 : 0 : bf_handle_detach(cgen->handle);
416 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
417 : : cgen->chain->name);
418 : : }
419 : :
420 : : return r;
421 : : }
422 : :
423 : : /**
424 : : * @brief Transfer all counters from old handle to new handle.
425 : : *
426 : : * Copies counter values 1:1 for all rule counters plus policy and error
427 : : * counters. The old and new chains must have the same number of rules.
428 : : * Both handles must be loaded.
429 : : *
430 : : * @param old_handle Handle with the source counter map. Can't be NULL.
431 : : * @param new_handle Handle with the destination counter map. Can't be NULL.
432 : : * @param n_rules Number of rules in the chain.
433 : : * @return 0 on success, or a negative errno value on failure.
434 : : */
435 : 8 : static int _bf_cgen_transfer_counters(const struct bf_handle *old_handle,
436 : : struct bf_handle *new_handle,
437 : : size_t n_rules)
438 : : {
439 : : int r;
440 : :
441 : : assert(old_handle);
442 : : assert(new_handle);
443 : :
444 [ + - - + ]: 8 : if (!old_handle->cmap || !new_handle->cmap)
445 [ # # ]: 0 : return bf_err_r(-ENOENT, "missing counter map for counter transfer");
446 : :
447 : : // n_rules entries for rules, +1 for policy, +1 for errors.
448 [ + + ]: 34 : for (uint32_t i = 0; i < n_rules + 2; ++i) {
449 : : struct bf_counter counter;
450 : :
451 : 26 : r = bf_handle_get_counter(old_handle, i, &counter);
452 [ - + ]: 26 : if (r)
453 [ # # ]: 0 : return bf_err_r(r, "failed to read counter %u", i);
454 : :
455 [ + + + - ]: 26 : if (!counter.count && !counter.size)
456 : 21 : continue;
457 : :
458 : 5 : r = bf_map_set_elem(new_handle->cmap, &i, &counter);
459 [ - + ]: 5 : if (r)
460 [ # # ]: 0 : return bf_err_r(r, "failed to write counter %u", i);
461 : : }
462 : :
463 : 8 : return 0;
464 : : }
465 : :
466 : 14 : int bf_cgen_update(struct bf_cgen *cgen, struct bf_chain **new_chain,
467 : : uint32_t flags, struct bf_lock *lock)
468 : : {
469 : 14 : _free_bf_program_ struct bf_program *new_prog = NULL;
470 : 14 : _free_bf_handle_ struct bf_handle *new_handle = NULL;
471 : : struct bf_handle *old_handle;
472 : : int r;
473 : :
474 : : assert(cgen);
475 : : assert(new_chain);
476 : : assert(lock);
477 : :
478 [ - + ]: 14 : if (flags & ~BF_FLAGS_MASK(_BF_CGEN_UPDATE_MAX))
479 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown update flags: 0x%x", flags);
480 : :
481 : 14 : old_handle = cgen->handle;
482 : :
483 : 14 : r = bf_handle_new(&new_handle, _BF_PROG_NAME);
484 [ + - ]: 14 : if (r)
485 : : return r;
486 : :
487 : 14 : r = bf_program_new(&new_prog, *new_chain, new_handle);
488 [ - + ]: 14 : if (r < 0)
489 [ # # ]: 0 : return bf_err_r(r, "failed to create a new bf_program");
490 : :
491 : 14 : r = bf_program_generate(new_prog);
492 [ - + ]: 14 : if (r < 0) {
493 [ # # ]: 0 : return bf_err_r(r,
494 : : "failed to generate the bytecode for a new bf_program");
495 : : }
496 : :
497 : 14 : r = bf_program_load(new_prog);
498 [ - + ]: 14 : if (r)
499 [ # # ]: 0 : return bf_err_r(r, "failed to load new program");
500 : :
501 [ + + ]: 14 : if (flags & BF_FLAG(BF_CGEN_UPDATE_PRESERVE_COUNTERS)) {
502 [ - + ]: 8 : if (bf_list_size(&cgen->chain->rules) !=
503 [ - + ]: 8 : bf_list_size(&(*new_chain)->rules)) {
504 [ # # ]: 0 : return bf_err_r(-EINVAL,
505 : : "rule count mismatch for counter transfer");
506 : : }
507 : :
508 : 8 : r = _bf_cgen_transfer_counters(old_handle, new_handle,
509 : : bf_list_size(&(*new_chain)->rules));
510 [ - + ]: 8 : if (r)
511 [ # # ]: 0 : return bf_err_r(r, "failed to transfer counters");
512 : : }
513 : :
514 : 14 : bf_handle_unpin(old_handle, lock);
515 : :
516 [ + + ]: 14 : if (old_handle->link) {
517 : 12 : r = bf_link_update(old_handle->link, new_handle->prog_fd);
518 [ - + ]: 12 : if (r) {
519 [ # # ]: 0 : bf_err_r(r, "failed to update bf_link object with new program");
520 [ # # ]: 0 : if (bf_handle_pin(old_handle, lock) < 0)
521 [ # # ]: 0 : bf_err("failed to repin old handle, ignoring");
522 : 0 : return r;
523 : : }
524 : :
525 : : // We updated the old link, we need to store it in the new handle
526 : 12 : bf_swap(new_handle->link, old_handle->link);
527 : : }
528 : :
529 : 14 : bf_swap(cgen->handle, new_handle);
530 : :
531 : 14 : r = bf_handle_pin(cgen->handle, lock);
532 [ - + ]: 14 : if (r)
533 [ # # ]: 0 : return bf_err_r(r, "failed to pin new handle");
534 : :
535 : 14 : r = _bf_cgen_persist(cgen, lock->chain_fd);
536 [ - + ]: 14 : if (r) {
537 : 0 : bf_handle_unpin(cgen->handle, lock);
538 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
539 : : cgen->chain->name);
540 : : }
541 : :
542 : 14 : bf_chain_free(&cgen->chain);
543 : 14 : cgen->chain = TAKE_PTR(*new_chain);
544 : :
545 : 14 : r = _bf_cgen_persist(cgen, lock->chain_fd);
546 [ - + ]: 14 : if (r) {
547 : 0 : bf_handle_unpin(cgen->handle, lock);
548 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
549 : : cgen->chain->name);
550 : : }
551 : :
552 : : return 0;
553 : : }
554 : :
555 : 0 : void bf_cgen_detach(struct bf_cgen *cgen)
556 : : {
557 : : assert(cgen);
558 : :
559 : 0 : bf_handle_detach(cgen->handle);
560 : 0 : }
561 : :
562 : 1263 : void bf_cgen_unload(struct bf_cgen *cgen, struct bf_lock *lock)
563 : : {
564 : : assert(cgen);
565 : : assert(lock);
566 : :
567 : : /* The chain's pin directory will be removed by bf_lock_release_chain()
568 : : * if a `BF_LOCK_WRITE` lock is held. */
569 : 1263 : unlinkat(lock->chain_fd, _BF_CTX_PIN_NAME, 0);
570 : 1263 : bf_handle_unpin(cgen->handle, lock);
571 : 1263 : bf_handle_unload(cgen->handle);
572 : 1263 : }
|