Commit 4580b25f authored by Toke Høiland-Jørgensen's avatar Toke Høiland-Jørgensen Committed by Alexei Starovoitov
Browse files

libbpf: Store map pin path and status in struct bpf_map



Support storing and setting a pin path in struct bpf_map, which can be used
for automatic pinning. Also store the pin status so we can avoid attempts
to re-pin a map that has already been pinned (or reused from a previous
pinning).

The behaviour of bpf_object__{un,}pin_maps() is changed so that if it is
called with a NULL path argument (which was previously illegal), it will
(un)pin only those maps that have a pin_path set.

Signed-off-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/157269297876.394725.14782206533681896279.stgit@toke.dk
parent d1b4574a
Loading
Loading
Loading
Loading
+123 −41
Original line number Diff line number Diff line
@@ -227,6 +227,8 @@ struct bpf_map {
	void *priv;
	bpf_map_clear_priv_t clear_priv;
	enum libbpf_map_type libbpf_type;
	char *pin_path;
	bool pinned;
};

struct bpf_secdata {
@@ -4036,47 +4038,119 @@ int bpf_map__pin(struct bpf_map *map, const char *path)
	char *cp, errmsg[STRERR_BUFSIZE];
	int err;

	err = check_path(path);
	if (err)
		return err;

	if (map == NULL) {
		pr_warn("invalid map pointer\n");
		return -EINVAL;
	}

	if (bpf_obj_pin(map->fd, path)) {
		cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
		pr_warn("failed to pin map: %s\n", cp);
		return -errno;
	if (map->pin_path) {
		if (path && strcmp(path, map->pin_path)) {
			pr_warn("map '%s' already has pin path '%s' different from '%s'\n",
				bpf_map__name(map), map->pin_path, path);
			return -EINVAL;
		} else if (map->pinned) {
			pr_debug("map '%s' already pinned at '%s'; not re-pinning\n",
				 bpf_map__name(map), map->pin_path);
			return 0;
		}
	} else {
		if (!path) {
			pr_warn("missing a path to pin map '%s' at\n",
				bpf_map__name(map));
			return -EINVAL;
		} else if (map->pinned) {
			pr_warn("map '%s' already pinned\n", bpf_map__name(map));
			return -EEXIST;
		}

	pr_debug("pinned map '%s'\n", path);
		map->pin_path = strdup(path);
		if (!map->pin_path) {
			err = -errno;
			goto out_err;
		}
	}

	err = check_path(map->pin_path);
	if (err)
		return err;

	if (bpf_obj_pin(map->fd, map->pin_path)) {
		err = -errno;
		goto out_err;
	}

	map->pinned = true;
	pr_debug("pinned map '%s'\n", map->pin_path);

	return 0;

out_err:
	cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg));
	pr_warn("failed to pin map: %s\n", cp);
	return err;
}

int bpf_map__unpin(struct bpf_map *map, const char *path)
{
	int err;

	err = check_path(path);
	if (err)
		return err;

	if (map == NULL) {
		pr_warn("invalid map pointer\n");
		return -EINVAL;
	}

	if (map->pin_path) {
		if (path && strcmp(path, map->pin_path)) {
			pr_warn("map '%s' already has pin path '%s' different from '%s'\n",
				bpf_map__name(map), map->pin_path, path);
			return -EINVAL;
		}
		path = map->pin_path;
	} else if (!path) {
		pr_warn("no path to unpin map '%s' from\n",
			bpf_map__name(map));
		return -EINVAL;
	}

	err = check_path(path);
	if (err)
		return err;

	err = unlink(path);
	if (err != 0)
		return -errno;
	pr_debug("unpinned map '%s'\n", path);

	map->pinned = false;
	pr_debug("unpinned map '%s' from '%s'\n", bpf_map__name(map), path);

	return 0;
}

int bpf_map__set_pin_path(struct bpf_map *map, const char *path)
{
	char *new = NULL;

	if (path) {
		new = strdup(path);
		if (!new)
			return -errno;
	}

	free(map->pin_path);
	map->pin_path = new;
	return 0;
}

const char *bpf_map__get_pin_path(const struct bpf_map *map)
{
	return map->pin_path;
}

bool bpf_map__is_pinned(const struct bpf_map *map)
{
	return map->pinned;
}

int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
{
	struct bpf_map *map;
@@ -4095,7 +4169,10 @@ int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
		return err;

	bpf_object__for_each_map(map, obj) {
		char *pin_path = NULL;
		char buf[PATH_MAX];

		if (path) {
			int len;

			len = snprintf(buf, PATH_MAX, "%s/%s", path,
@@ -4107,8 +4184,12 @@ int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
				err = -ENAMETOOLONG;
				goto err_unpin_maps;
			}
			pin_path = buf;
		} else if (!map->pin_path) {
			continue;
		}

		err = bpf_map__pin(map, buf);
		err = bpf_map__pin(map, pin_path);
		if (err)
			goto err_unpin_maps;
	}
@@ -4117,17 +4198,10 @@ int bpf_object__pin_maps(struct bpf_object *obj, const char *path)

err_unpin_maps:
	while ((map = bpf_map__prev(map, obj))) {
		char buf[PATH_MAX];
		int len;

		len = snprintf(buf, PATH_MAX, "%s/%s", path,
			       bpf_map__name(map));
		if (len < 0)
			continue;
		else if (len >= PATH_MAX)
		if (!map->pin_path)
			continue;

		bpf_map__unpin(map, buf);
		bpf_map__unpin(map, NULL);
	}

	return err;
@@ -4142,7 +4216,10 @@ int bpf_object__unpin_maps(struct bpf_object *obj, const char *path)
		return -ENOENT;

	bpf_object__for_each_map(map, obj) {
		char *pin_path = NULL;
		char buf[PATH_MAX];

		if (path) {
			int len;

			len = snprintf(buf, PATH_MAX, "%s/%s", path,
@@ -4151,8 +4228,12 @@ int bpf_object__unpin_maps(struct bpf_object *obj, const char *path)
				return -EINVAL;
			else if (len >= PATH_MAX)
				return -ENAMETOOLONG;
			pin_path = buf;
		} else if (!map->pin_path) {
			continue;
		}

		err = bpf_map__unpin(map, buf);
		err = bpf_map__unpin(map, pin_path);
		if (err)
			return err;
	}
@@ -4277,6 +4358,7 @@ void bpf_object__close(struct bpf_object *obj)

	for (i = 0; i < obj->nr_maps; i++) {
		zfree(&obj->maps[i].name);
		zfree(&obj->maps[i].pin_path);
		if (obj->maps[i].clear_priv)
			obj->maps[i].clear_priv(&obj->maps[i],
						obj->maps[i].priv);
+8 −0
Original line number Diff line number Diff line
@@ -124,6 +124,11 @@ int bpf_object__section_size(const struct bpf_object *obj, const char *name,
			     __u32 *size);
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
				__u32 *off);

/* pin_maps and unpin_maps can both be called with a NULL path, in which case
 * they will use the pin_path attribute of each map (and ignore all maps that
 * don't have a pin_path set).
 */
LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
				      const char *path);
@@ -387,6 +392,9 @@ LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);

+3 −0
Original line number Diff line number Diff line
@@ -193,6 +193,9 @@ LIBBPF_0.0.5 {

LIBBPF_0.0.6 {
	global:
		bpf_map__get_pin_path;
		bpf_map__is_pinned;
		bpf_map__set_pin_path;
		bpf_object__open_file;
		bpf_object__open_mem;
		bpf_program__get_expected_attach_type;