iproute2/lib/cg_map.c
<<
>>
Prefs
   1/*
   2 * cg_map.c     cgroup v2 cache
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Dmitry Yakunin <zeil@yandex-team.ru>
  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                /* root cgroup */
  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