Blame lib/cg_map.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * cg_map.c	cgroup v2 cache
Packit Service 3880ab
 *
Packit Service 3880ab
 *		This program is free software; you can redistribute it and/or
Packit Service 3880ab
 *		modify it under the terms of the GNU General Public License
Packit Service 3880ab
 *		as published by the Free Software Foundation; either version
Packit Service 3880ab
 *		2 of the License, or (at your option) any later version.
Packit Service 3880ab
 *
Packit Service 3880ab
 * Authors:	Dmitry Yakunin <zeil@yandex-team.ru>
Packit Service 3880ab
 */
Packit Service 3880ab
Packit Service 3880ab
#include <stdlib.h>
Packit Service 3880ab
#include <string.h>
Packit Service 3880ab
#include <stdio.h>
Packit Service 3880ab
#include <stdbool.h>
Packit Service 3880ab
#include <linux/types.h>
Packit Service 3880ab
#include <linux/limits.h>
Packit Service 3880ab
#include <ftw.h>
Packit Service 3880ab
Packit Service 3880ab
#include "cg_map.h"
Packit Service 3880ab
#include "list.h"
Packit Service 3880ab
#include "utils.h"
Packit Service 3880ab
Packit Service 3880ab
struct cg_cache {
Packit Service 3880ab
	struct hlist_node id_hash;
Packit Service 3880ab
	__u64	id;
Packit Service 3880ab
	char	path[];
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
#define IDMAP_SIZE	1024
Packit Service 3880ab
static struct hlist_head id_head[IDMAP_SIZE];
Packit Service 3880ab
Packit Service 3880ab
static struct cg_cache *cg_get_by_id(__u64 id)
Packit Service 3880ab
{
Packit Service 3880ab
	unsigned int h = id & (IDMAP_SIZE - 1);
Packit Service 3880ab
	struct hlist_node *n;
Packit Service 3880ab
Packit Service 3880ab
	hlist_for_each(n, &id_head[h]) {
Packit Service 3880ab
		struct cg_cache *cg;
Packit Service 3880ab
Packit Service 3880ab
		cg = container_of(n, struct cg_cache, id_hash);
Packit Service 3880ab
		if (cg->id == id)
Packit Service 3880ab
			return cg;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return NULL;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static struct cg_cache *cg_entry_create(__u64 id, const char *path)
Packit Service 3880ab
{
Packit Service 3880ab
	unsigned int h = id & (IDMAP_SIZE - 1);
Packit Service 3880ab
	struct cg_cache *cg;
Packit Service 3880ab
Packit Service 3880ab
	cg = malloc(sizeof(*cg) + strlen(path) + 1);
Packit Service 3880ab
	if (!cg) {
Packit Service 3880ab
		fprintf(stderr,
Packit Service 3880ab
			"Failed to allocate memory for cgroup2 cache entry");
Packit Service 3880ab
		return NULL;
Packit Service 3880ab
	}
Packit Service 3880ab
	cg->id = id;
Packit Service 3880ab
	strcpy(cg->path, path);
Packit Service 3880ab
Packit Service 3880ab
	hlist_add_head(&cg->id_hash, &id_head[h]);
Packit Service 3880ab
Packit Service 3880ab
	return cg;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int mntlen;
Packit Service 3880ab
Packit Service 3880ab
static int nftw_fn(const char *fpath, const struct stat *sb,
Packit Service 3880ab
		   int typeflag, struct FTW *ftw)
Packit Service 3880ab
{
Packit Service 3880ab
	const char *path;
Packit Service 3880ab
	__u64 id;
Packit Service 3880ab
Packit Service 3880ab
	if (typeflag != FTW_D)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	id = get_cgroup2_id(fpath);
Packit Service 3880ab
	if (!id)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	path = fpath + mntlen;
Packit Service 3880ab
	if (*path == '\0')
Packit Service 3880ab
		/* root cgroup */
Packit Service 3880ab
		path = "/";
Packit Service 3880ab
	if (!cg_entry_create(id, path))
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void cg_init_map(void)
Packit Service 3880ab
{
Packit Service 3880ab
	char *mnt;
Packit Service 3880ab
Packit Service 3880ab
	mnt = find_cgroup2_mount(false);
Packit Service 3880ab
	if (!mnt)
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	mntlen = strlen(mnt);
Packit Service 3880ab
	(void) nftw(mnt, nftw_fn, 1024, FTW_MOUNT);
Packit Service 3880ab
Packit Service 3880ab
	free(mnt);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
const char *cg_id_to_path(__u64 id)
Packit Service 3880ab
{
Packit Service 3880ab
	static int initialized;
Packit Service 3880ab
	static char buf[64];
Packit Service 3880ab
Packit Service 3880ab
	const struct cg_cache *cg;
Packit Service 3880ab
	char *path;
Packit Service 3880ab
Packit Service 3880ab
	if (!initialized) {
Packit Service 3880ab
		cg_init_map();
Packit Service 3880ab
		initialized = 1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	cg = cg_get_by_id(id);
Packit Service 3880ab
	if (cg)
Packit Service 3880ab
		return cg->path;
Packit Service 3880ab
Packit Service 3880ab
	path = get_cgroup2_path(id, false);
Packit Service 3880ab
	if (path) {
Packit Service 3880ab
		cg = cg_entry_create(id, path);
Packit Service 3880ab
		free(path);
Packit Service 3880ab
		if (cg)
Packit Service 3880ab
			return cg->path;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	snprintf(buf, sizeof(buf), "unreachable:%llx", id);
Packit Service 3880ab
	return buf;
Packit Service 3880ab
}