[PATCH 06/15] bpf: Add tracing_map client ops

From: Tom Zanussi
Date: Mon Mar 02 2015 - 11:01:50 EST


External users of the tracing_map API may customize their map usage
and need to be notified of certain events occuring during the lifetime
of a map.

One example would be element deletion - if private data has been
associated with an element's value, the client should be notified when
that element is being deleted in order to give it a chance to delete
the private data.

struct bpf_map_client_ops defines a set of client callbacks, a pointer
to an instance of which can be passed by the client to tracing_map_create().

Initially, the only callback defined is free_elem(), which is called
when a map element is freed and gives clients the opportunity to free
app-specific elements. Other callbacks such as a client-defined
sort() function are anticipated, however, which is why it's not a
standalone op.

Signed-off-by: Tom Zanussi <tom.zanussi@xxxxxxxxxxxxxxx>
---
include/linux/bpf.h | 8 +++++++-
kernel/bpf/arraymap.c | 16 ++++++++++++++++
kernel/bpf/hashtab.c | 12 ++++++++++++
kernel/bpf/syscall.c | 7 +++++--
4 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index f7f95d7..09095ec 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -27,6 +27,10 @@ struct bpf_map_ops {
int (*map_delete_elem)(struct bpf_map *map, void *key);
};

+struct bpf_map_client_ops {
+ void (*free_elem)(void *value);
+};
+
struct bpf_map {
atomic_t refcnt;
enum bpf_map_type map_type;
@@ -35,6 +39,7 @@ struct bpf_map {
u32 max_entries;
struct bpf_map_ops *ops;
struct work_struct work;
+ struct bpf_map_client_ops *client_ops;
};

struct bpf_map_type_list {
@@ -143,7 +148,8 @@ extern struct bpf_func_proto bpf_map_lookup_elem_proto;
extern struct bpf_func_proto bpf_map_update_elem_proto;
extern struct bpf_func_proto bpf_map_delete_elem_proto;

-struct bpf_map *tracing_map_create(union bpf_attr *attr);
+struct bpf_map *tracing_map_create(union bpf_attr *attr,
+ struct bpf_map_client_ops *client_ops);
void tracing_map_destroy(struct bpf_map *map);
void tracing_map_clear(struct bpf_map *map);
int tracing_map_update_elem(struct bpf_map *map, void *key, void *value,
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 9eb4d8a..333c959 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -119,6 +119,20 @@ static int array_map_delete_elem(struct bpf_map *map, void *key)
return -EINVAL;
}

+static void free_client_elems(struct bpf_array *array)
+{
+ void *val;
+ u32 index;
+
+ if (!array->map.client_ops || !array->map.client_ops->free_elem)
+ return;
+
+ for (index = 0; index < array->map.max_entries; index++) {
+ val = array->value + array->elem_size * index;
+ array->map.client_ops->free_elem(val);
+ }
+}
+
/* Called when map->refcnt goes to zero, either from workqueue or from syscall */
static void array_map_free(struct bpf_map *map)
{
@@ -131,6 +145,8 @@ static void array_map_free(struct bpf_map *map)
*/
synchronize_rcu();

+ free_client_elems(array);
+
kvfree(array);
}

diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index addf3a8..6f349ad 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -275,6 +275,16 @@ err:
return ret;
}

+static void free_client_elem(struct bpf_htab *htab, struct htab_elem *l)
+{
+ void *val;
+
+ if (htab->map.client_ops && htab->map.client_ops->free_elem) {
+ val = l->key + round_up(htab->map.key_size, 8);
+ htab->map.client_ops->free_elem(val);
+ }
+}
+
/* Called from syscall or from eBPF program */
static int htab_map_delete_elem(struct bpf_map *map, void *key)
{
@@ -298,6 +308,7 @@ static int htab_map_delete_elem(struct bpf_map *map, void *key)
l = lookup_elem_raw(head, hash, key, key_size);

if (l) {
+ free_client_elem(htab, l);
hlist_del_rcu(&l->hash_node);
htab->count--;
kfree_rcu(l, rcu);
@@ -318,6 +329,7 @@ static void delete_all_elements(struct bpf_htab *htab)
struct htab_elem *l;

hlist_for_each_entry_safe(l, n, head, hash_node) {
+ free_client_elem(htab, l);
hlist_del_rcu(&l->hash_node);
htab->count--;
kfree(l);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0f28904..85735e6 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -110,7 +110,8 @@ static const struct file_operations bpf_map_fops = {
*
* Return: the map created on success, ERR_PTR otherwise
*/
-struct bpf_map *tracing_map_create(union bpf_attr *attr)
+struct bpf_map *tracing_map_create(union bpf_attr *attr,
+ struct bpf_map_client_ops *client_ops)
{
struct bpf_map *map;

@@ -119,6 +120,8 @@ struct bpf_map *tracing_map_create(union bpf_attr *attr)
if (!IS_ERR(map))
atomic_set(&map->refcnt, 1);

+ map->client_ops = client_ops;
+
return map;
}
EXPORT_SYMBOL_GPL(tracing_map_create);
@@ -133,7 +136,7 @@ static int map_create(union bpf_attr *attr)
if (err)
return -EINVAL;

- map = tracing_map_create(attr);
+ map = tracing_map_create(attr, NULL);
if (IS_ERR(map))
return PTR_ERR(map);

--
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/