[v2,bpf-next,2/3] libbpf: make global data internal arrays mmap()-able, if possible
diff mbox series

Message ID 20191109080633.2855561-3-andriin@fb.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series
  • Add support for memory-mapping BPF array maps
Related show

Commit Message

Andrii Nakryiko Nov. 9, 2019, 8:06 a.m. UTC
Add detection of BPF_F_MMAPABLE flag support for arrays and add it as an extra
flag to internal global data maps, if supported by kernel. This allows users
to memory-map global data and use it without BPF map operations, greatly
simplifying user experience.

Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
---
 tools/lib/bpf/libbpf.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

Comments

Jakub Kicinski Nov. 11, 2019, 6:40 p.m. UTC | #1
On Sat, 9 Nov 2019 00:06:31 -0800, Andrii Nakryiko wrote:
> +static int bpf_object__probe_array_mmap(struct bpf_object *obj)
> +{
> +	struct bpf_create_map_attr attr = {
> +		.map_type = BPF_MAP_TYPE_ARRAY,
> +		.map_flags = BPF_F_MMAPABLE,
> +		.key_size = sizeof(int),
> +		.value_size = sizeof(int),
> +		.max_entries = 1,
> +	};
> +	int fd = bpf_create_map_xattr(&attr);
> +
> +	if (fd >= 0) {

The point of the empty line between variable declarations and code in
the Linux coding style is to provide a visual separation between
variables and code.

If you call a complex function in variable init and then check for
errors in the code that really breaks that principle.

> +		obj->caps.array_mmap = 1;
> +		close(fd);
> +		return 1;
> +	}
> +
> +	return 0;
> +}
Andrii Nakryiko Nov. 12, 2019, 2:11 a.m. UTC | #2
On Mon, Nov 11, 2019 at 10:41 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Sat, 9 Nov 2019 00:06:31 -0800, Andrii Nakryiko wrote:
> > +static int bpf_object__probe_array_mmap(struct bpf_object *obj)
> > +{
> > +     struct bpf_create_map_attr attr = {
> > +             .map_type = BPF_MAP_TYPE_ARRAY,
> > +             .map_flags = BPF_F_MMAPABLE,
> > +             .key_size = sizeof(int),
> > +             .value_size = sizeof(int),
> > +             .max_entries = 1,
> > +     };
> > +     int fd = bpf_create_map_xattr(&attr);
> > +
> > +     if (fd >= 0) {
>
> The point of the empty line between variable declarations and code in
> the Linux coding style is to provide a visual separation between
> variables and code.
>
> If you call a complex function in variable init and then check for
> errors in the code that really breaks that principle.

I'll split declaration and initialization, no problem

>
> > +             obj->caps.array_mmap = 1;
> > +             close(fd);
> > +             return 1;
> > +     }
> > +
> > +     return 0;
> > +}
>

Patch
diff mbox series

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index fde6cb3e5d41..d32899e50f8a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -142,6 +142,8 @@  struct bpf_capabilities {
 	__u32 btf_func:1;
 	/* BTF_KIND_VAR and BTF_KIND_DATASEC support */
 	__u32 btf_datasec:1;
+	/* BPF_F_MMAPABLE is supported for arrays */
+	__u32 array_mmap:1;
 };
 
 /*
@@ -855,8 +857,6 @@  bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
 		pr_warn("failed to alloc map name\n");
 		return -ENOMEM;
 	}
-	pr_debug("map '%s' (global data): at sec_idx %d, offset %zu.\n",
-		 map_name, map->sec_idx, map->sec_offset);
 
 	def = &map->def;
 	def->type = BPF_MAP_TYPE_ARRAY;
@@ -864,6 +864,12 @@  bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
 	def->value_size = data->d_size;
 	def->max_entries = 1;
 	def->map_flags = type == LIBBPF_MAP_RODATA ? BPF_F_RDONLY_PROG : 0;
+	if (obj->caps.array_mmap)
+		def->map_flags |= BPF_F_MMAPABLE;
+
+	pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",
+		 map_name, map->sec_idx, map->sec_offset, def->map_flags);
+
 	if (data_buff) {
 		*data_buff = malloc(data->d_size);
 		if (!*data_buff) {
@@ -2158,6 +2164,26 @@  static int bpf_object__probe_btf_datasec(struct bpf_object *obj)
 	return 0;
 }
 
+static int bpf_object__probe_array_mmap(struct bpf_object *obj)
+{
+	struct bpf_create_map_attr attr = {
+		.map_type = BPF_MAP_TYPE_ARRAY,
+		.map_flags = BPF_F_MMAPABLE,
+		.key_size = sizeof(int),
+		.value_size = sizeof(int),
+		.max_entries = 1,
+	};
+	int fd = bpf_create_map_xattr(&attr);
+
+	if (fd >= 0) {
+		obj->caps.array_mmap = 1;
+		close(fd);
+		return 1;
+	}
+
+	return 0;
+}
+
 static int
 bpf_object__probe_caps(struct bpf_object *obj)
 {
@@ -2166,6 +2192,7 @@  bpf_object__probe_caps(struct bpf_object *obj)
 		bpf_object__probe_global_data,
 		bpf_object__probe_btf_func,
 		bpf_object__probe_btf_datasec,
+		bpf_object__probe_array_mmap,
 	};
 	int i, ret;