libbpf: Update a bpf_link with another struct_ops.

Introduce bpf_link__update_map(), which allows to atomically update
underlying struct_ops implementation for given struct_ops BPF link.

Also add old_map_fd to struct bpf_link_update_opts to handle
BPF_F_REPLACE feature.

Signed-off-by: Kui-Feng Lee <kuifeng@meta.com>
Link: https://lore.kernel.org/r/20230323032405.3735486-7-kuifeng@meta.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
Kui-Feng Lee
2023-03-22 20:24:03 -07:00
committed by Andrii Nakryiko
parent 055cbdcc9f
commit e51cdaaca0
5 changed files with 46 additions and 2 deletions

View File

@@ -11677,6 +11677,41 @@ struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
return &link->link;
}
/*
* Swap the back struct_ops of a link with a new struct_ops map.
*/
int bpf_link__update_map(struct bpf_link *link, const struct bpf_map *map)
{
struct bpf_link_struct_ops *st_ops_link;
__u32 zero = 0;
int err;
if (!bpf_map__is_struct_ops(map) || map->fd < 0)
return -EINVAL;
st_ops_link = container_of(link, struct bpf_link_struct_ops, link);
/* Ensure the type of a link is correct */
if (st_ops_link->map_fd < 0)
return -EINVAL;
err = bpf_map_update_elem(map->fd, &zero, map->st_ops->kern_vdata, 0);
/* It can be EBUSY if the map has been used to create or
* update a link before. We don't allow updating the value of
* a struct_ops once it is set. That ensures that the value
* never changed. So, it is safe to skip EBUSY.
*/
if (err && err != -EBUSY)
return err;
err = bpf_link_update(link->fd, map->fd, NULL);
if (err < 0)
return err;
st_ops_link->map_fd = map->fd;
return 0;
}
typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(struct perf_event_header *hdr,
void *private_data);