mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 07:23:14 +00:00
bpf: enable detaching links of struct_ops objects.
Implement the detach callback in bpf_link_ops for struct_ops so that user programs can detach a struct_ops link. The subsystems that struct_ops objects are registered to can also use this callback to detach the links being passed to them. Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com> Link: https://lore.kernel.org/r/20240530065946.979330-3-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
parent
73287fe228
commit
6fb2544ea1
@ -1057,9 +1057,6 @@ static void bpf_struct_ops_map_link_dealloc(struct bpf_link *link)
|
||||
st_map = (struct bpf_struct_ops_map *)
|
||||
rcu_dereference_protected(st_link->map, true);
|
||||
if (st_map) {
|
||||
/* st_link->map can be NULL if
|
||||
* bpf_struct_ops_link_create() fails to register.
|
||||
*/
|
||||
st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data, link);
|
||||
bpf_map_put(&st_map->map);
|
||||
}
|
||||
@ -1075,7 +1072,8 @@ static void bpf_struct_ops_map_link_show_fdinfo(const struct bpf_link *link,
|
||||
st_link = container_of(link, struct bpf_struct_ops_link, link);
|
||||
rcu_read_lock();
|
||||
map = rcu_dereference(st_link->map);
|
||||
seq_printf(seq, "map_id:\t%d\n", map->id);
|
||||
if (map)
|
||||
seq_printf(seq, "map_id:\t%d\n", map->id);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -1088,7 +1086,8 @@ static int bpf_struct_ops_map_link_fill_link_info(const struct bpf_link *link,
|
||||
st_link = container_of(link, struct bpf_struct_ops_link, link);
|
||||
rcu_read_lock();
|
||||
map = rcu_dereference(st_link->map);
|
||||
info->struct_ops.map_id = map->id;
|
||||
if (map)
|
||||
info->struct_ops.map_id = map->id;
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
@ -1113,6 +1112,10 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
|
||||
mutex_lock(&update_mutex);
|
||||
|
||||
old_map = rcu_dereference_protected(st_link->map, lockdep_is_held(&update_mutex));
|
||||
if (!old_map) {
|
||||
err = -ENOLINK;
|
||||
goto err_out;
|
||||
}
|
||||
if (expected_old_map && old_map != expected_old_map) {
|
||||
err = -EPERM;
|
||||
goto err_out;
|
||||
@ -1139,8 +1142,37 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bpf_struct_ops_map_link_detach(struct bpf_link *link)
|
||||
{
|
||||
struct bpf_struct_ops_link *st_link = container_of(link, struct bpf_struct_ops_link, link);
|
||||
struct bpf_struct_ops_map *st_map;
|
||||
struct bpf_map *map;
|
||||
|
||||
mutex_lock(&update_mutex);
|
||||
|
||||
map = rcu_dereference_protected(st_link->map, lockdep_is_held(&update_mutex));
|
||||
if (!map) {
|
||||
mutex_unlock(&update_mutex);
|
||||
return 0;
|
||||
}
|
||||
st_map = container_of(map, struct bpf_struct_ops_map, map);
|
||||
|
||||
st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data, link);
|
||||
|
||||
RCU_INIT_POINTER(st_link->map, NULL);
|
||||
/* Pair with bpf_map_get() in bpf_struct_ops_link_create() or
|
||||
* bpf_map_inc() in bpf_struct_ops_map_link_update().
|
||||
*/
|
||||
bpf_map_put(&st_map->map);
|
||||
|
||||
mutex_unlock(&update_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bpf_link_ops bpf_struct_ops_map_lops = {
|
||||
.dealloc = bpf_struct_ops_map_link_dealloc,
|
||||
.detach = bpf_struct_ops_map_link_detach,
|
||||
.show_fdinfo = bpf_struct_ops_map_link_show_fdinfo,
|
||||
.fill_link_info = bpf_struct_ops_map_link_fill_link_info,
|
||||
.update_map = bpf_struct_ops_map_link_update,
|
||||
@ -1176,13 +1208,19 @@ int bpf_struct_ops_link_create(union bpf_attr *attr)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
/* Hold the update_mutex such that the subsystem cannot
|
||||
* do link->ops->detach() before the link is fully initialized.
|
||||
*/
|
||||
mutex_lock(&update_mutex);
|
||||
err = st_map->st_ops_desc->st_ops->reg(st_map->kvalue.data, &link->link);
|
||||
if (err) {
|
||||
mutex_unlock(&update_mutex);
|
||||
bpf_link_cleanup(&link_primer);
|
||||
link = NULL;
|
||||
goto err_out;
|
||||
}
|
||||
RCU_INIT_POINTER(link->map, map);
|
||||
mutex_unlock(&update_mutex);
|
||||
|
||||
return bpf_link_settle(&link_primer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user