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.zanu...@linux.intel.com> --- 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/