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 *)
|
st_map = (struct bpf_struct_ops_map *)
|
||||||
rcu_dereference_protected(st_link->map, true);
|
rcu_dereference_protected(st_link->map, true);
|
||||||
if (st_map) {
|
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);
|
st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data, link);
|
||||||
bpf_map_put(&st_map->map);
|
bpf_map_put(&st_map->map);
|
||||||
}
|
}
|
||||||
@ -1075,6 +1072,7 @@ 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);
|
st_link = container_of(link, struct bpf_struct_ops_link, link);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
map = rcu_dereference(st_link->map);
|
map = rcu_dereference(st_link->map);
|
||||||
|
if (map)
|
||||||
seq_printf(seq, "map_id:\t%d\n", map->id);
|
seq_printf(seq, "map_id:\t%d\n", map->id);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
@ -1088,6 +1086,7 @@ 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);
|
st_link = container_of(link, struct bpf_struct_ops_link, link);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
map = rcu_dereference(st_link->map);
|
map = rcu_dereference(st_link->map);
|
||||||
|
if (map)
|
||||||
info->struct_ops.map_id = map->id;
|
info->struct_ops.map_id = map->id;
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return 0;
|
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);
|
mutex_lock(&update_mutex);
|
||||||
|
|
||||||
old_map = rcu_dereference_protected(st_link->map, lockdep_is_held(&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) {
|
if (expected_old_map && old_map != expected_old_map) {
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -1139,8 +1142,37 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
|
|||||||
return err;
|
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 = {
|
static const struct bpf_link_ops bpf_struct_ops_map_lops = {
|
||||||
.dealloc = bpf_struct_ops_map_link_dealloc,
|
.dealloc = bpf_struct_ops_map_link_dealloc,
|
||||||
|
.detach = bpf_struct_ops_map_link_detach,
|
||||||
.show_fdinfo = bpf_struct_ops_map_link_show_fdinfo,
|
.show_fdinfo = bpf_struct_ops_map_link_show_fdinfo,
|
||||||
.fill_link_info = bpf_struct_ops_map_link_fill_link_info,
|
.fill_link_info = bpf_struct_ops_map_link_fill_link_info,
|
||||||
.update_map = bpf_struct_ops_map_link_update,
|
.update_map = bpf_struct_ops_map_link_update,
|
||||||
@ -1176,13 +1208,19 @@ int bpf_struct_ops_link_create(union bpf_attr *attr)
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
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);
|
err = st_map->st_ops_desc->st_ops->reg(st_map->kvalue.data, &link->link);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
mutex_unlock(&update_mutex);
|
||||||
bpf_link_cleanup(&link_primer);
|
bpf_link_cleanup(&link_primer);
|
||||||
link = NULL;
|
link = NULL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
RCU_INIT_POINTER(link->map, map);
|
RCU_INIT_POINTER(link->map, map);
|
||||||
|
mutex_unlock(&update_mutex);
|
||||||
|
|
||||||
return bpf_link_settle(&link_primer);
|
return bpf_link_settle(&link_primer);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user