1
2
3
4
5
6
7
8
9
10
11
12#include <stdlib.h>
13#include <string.h>
14#include <stdio.h>
15#include <stdbool.h>
16#include <linux/types.h>
17#include <linux/limits.h>
18#include <ftw.h>
19
20#include "cg_map.h"
21#include "list.h"
22#include "utils.h"
23
24struct cg_cache {
25 struct hlist_node id_hash;
26 __u64 id;
27 char path[];
28};
29
30#define IDMAP_SIZE 1024
31static struct hlist_head id_head[IDMAP_SIZE];
32
33static struct cg_cache *cg_get_by_id(__u64 id)
34{
35 unsigned int h = id & (IDMAP_SIZE - 1);
36 struct hlist_node *n;
37
38 hlist_for_each(n, &id_head[h]) {
39 struct cg_cache *cg;
40
41 cg = container_of(n, struct cg_cache, id_hash);
42 if (cg->id == id)
43 return cg;
44 }
45
46 return NULL;
47}
48
49static struct cg_cache *cg_entry_create(__u64 id, const char *path)
50{
51 unsigned int h = id & (IDMAP_SIZE - 1);
52 struct cg_cache *cg;
53
54 cg = malloc(sizeof(*cg) + strlen(path) + 1);
55 if (!cg) {
56 fprintf(stderr,
57 "Failed to allocate memory for cgroup2 cache entry");
58 return NULL;
59 }
60 cg->id = id;
61 strcpy(cg->path, path);
62
63 hlist_add_head(&cg->id_hash, &id_head[h]);
64
65 return cg;
66}
67
68static int mntlen;
69
70static int nftw_fn(const char *fpath, const struct stat *sb,
71 int typeflag, struct FTW *ftw)
72{
73 const char *path;
74 __u64 id;
75
76 if (typeflag != FTW_D)
77 return 0;
78
79 id = get_cgroup2_id(fpath);
80 if (!id)
81 return -1;
82
83 path = fpath + mntlen;
84 if (*path == '\0')
85
86 path = "/";
87 if (!cg_entry_create(id, path))
88 return -1;
89
90 return 0;
91}
92
93static void cg_init_map(void)
94{
95 char *mnt;
96
97 mnt = find_cgroup2_mount(false);
98 if (!mnt)
99 exit(1);
100
101 mntlen = strlen(mnt);
102 if (nftw(mnt, nftw_fn, 1024, FTW_MOUNT) < 0)
103 exit(1);
104
105 free(mnt);
106}
107
108const char *cg_id_to_path(__u64 id)
109{
110 static int initialized;
111 static char buf[64];
112
113 const struct cg_cache *cg;
114 char *path;
115
116 if (!initialized) {
117 cg_init_map();
118 initialized = 1;
119 }
120
121 cg = cg_get_by_id(id);
122 if (cg)
123 return cg->path;
124
125 path = get_cgroup2_path(id, false);
126 if (path) {
127 cg = cg_entry_create(id, path);
128 free(path);
129 if (cg)
130 return cg->path;
131 }
132
133 snprintf(buf, sizeof(buf), "unreachable:%llx", id);
134 return buf;
135}
136