Commit 6fb2544e authored by Kui-Feng Lee's avatar Kui-Feng Lee Committed by Martin KaFai Lau

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: default avatarKui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240530065946.979330-3-thinker.li@gmail.comSigned-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parent 73287fe2
...@@ -1057,9 +1057,6 @@ static void bpf_struct_ops_map_link_dealloc(struct bpf_link *link) ...@@ -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,7 +1072,8 @@ static void bpf_struct_ops_map_link_show_fdinfo(const struct bpf_link *link, ...@@ -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); 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);
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(); rcu_read_unlock();
} }
...@@ -1088,7 +1086,8 @@ static int bpf_struct_ops_map_link_fill_link_info(const struct bpf_link *link, ...@@ -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); 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);
info->struct_ops.map_id = map->id; if (map)
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 ...@@ -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 ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment