Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.4-rc6 252 lines 5.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <subcmd/parse-options.h> 3#include "evsel.h" 4#include "cgroup.h" 5#include "evlist.h" 6#include <linux/stringify.h> 7#include <linux/zalloc.h> 8#include <sys/types.h> 9#include <sys/stat.h> 10#include <fcntl.h> 11#include <stdlib.h> 12#include <string.h> 13 14int nr_cgroups; 15 16static int 17cgroupfs_find_mountpoint(char *buf, size_t maxlen) 18{ 19 FILE *fp; 20 char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1]; 21 char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path; 22 char *token, *saved_ptr = NULL; 23 24 fp = fopen("/proc/mounts", "r"); 25 if (!fp) 26 return -1; 27 28 /* 29 * in order to handle split hierarchy, we need to scan /proc/mounts 30 * and inspect every cgroupfs mount point to find one that has 31 * perf_event subsystem 32 */ 33 path_v1[0] = '\0'; 34 path_v2[0] = '\0'; 35 36 while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %" 37 __stringify(PATH_MAX)"s %*d %*d\n", 38 mountpoint, type, tokens) == 3) { 39 40 if (!path_v1[0] && !strcmp(type, "cgroup")) { 41 42 token = strtok_r(tokens, ",", &saved_ptr); 43 44 while (token != NULL) { 45 if (!strcmp(token, "perf_event")) { 46 strcpy(path_v1, mountpoint); 47 break; 48 } 49 token = strtok_r(NULL, ",", &saved_ptr); 50 } 51 } 52 53 if (!path_v2[0] && !strcmp(type, "cgroup2")) 54 strcpy(path_v2, mountpoint); 55 56 if (path_v1[0] && path_v2[0]) 57 break; 58 } 59 fclose(fp); 60 61 if (path_v1[0]) 62 path = path_v1; 63 else if (path_v2[0]) 64 path = path_v2; 65 else 66 return -1; 67 68 if (strlen(path) < maxlen) { 69 strcpy(buf, path); 70 return 0; 71 } 72 return -1; 73} 74 75static int open_cgroup(const char *name) 76{ 77 char path[PATH_MAX + 1]; 78 char mnt[PATH_MAX + 1]; 79 int fd; 80 81 82 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1)) 83 return -1; 84 85 scnprintf(path, PATH_MAX, "%s/%s", mnt, name); 86 87 fd = open(path, O_RDONLY); 88 if (fd == -1) 89 fprintf(stderr, "no access to cgroup %s\n", path); 90 91 return fd; 92} 93 94static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str) 95{ 96 struct evsel *counter; 97 /* 98 * check if cgrp is already defined, if so we reuse it 99 */ 100 evlist__for_each_entry(evlist, counter) { 101 if (!counter->cgrp) 102 continue; 103 if (!strcmp(counter->cgrp->name, str)) 104 return cgroup__get(counter->cgrp); 105 } 106 107 return NULL; 108} 109 110static struct cgroup *cgroup__new(const char *name) 111{ 112 struct cgroup *cgroup = zalloc(sizeof(*cgroup)); 113 114 if (cgroup != NULL) { 115 refcount_set(&cgroup->refcnt, 1); 116 117 cgroup->name = strdup(name); 118 if (!cgroup->name) 119 goto out_err; 120 cgroup->fd = open_cgroup(name); 121 if (cgroup->fd == -1) 122 goto out_free_name; 123 } 124 125 return cgroup; 126 127out_free_name: 128 zfree(&cgroup->name); 129out_err: 130 free(cgroup); 131 return NULL; 132} 133 134struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name) 135{ 136 struct cgroup *cgroup = evlist__find_cgroup(evlist, name); 137 138 return cgroup ?: cgroup__new(name); 139} 140 141static int add_cgroup(struct evlist *evlist, const char *str) 142{ 143 struct evsel *counter; 144 struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str); 145 int n; 146 147 if (!cgrp) 148 return -1; 149 /* 150 * find corresponding event 151 * if add cgroup N, then need to find event N 152 */ 153 n = 0; 154 evlist__for_each_entry(evlist, counter) { 155 if (n == nr_cgroups) 156 goto found; 157 n++; 158 } 159 160 cgroup__put(cgrp); 161 return -1; 162found: 163 counter->cgrp = cgrp; 164 return 0; 165} 166 167static void cgroup__delete(struct cgroup *cgroup) 168{ 169 close(cgroup->fd); 170 zfree(&cgroup->name); 171 free(cgroup); 172} 173 174void cgroup__put(struct cgroup *cgrp) 175{ 176 if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) { 177 cgroup__delete(cgrp); 178 } 179} 180 181struct cgroup *cgroup__get(struct cgroup *cgroup) 182{ 183 if (cgroup) 184 refcount_inc(&cgroup->refcnt); 185 return cgroup; 186} 187 188static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup) 189{ 190 if (evsel->cgrp == NULL) 191 evsel->cgrp = cgroup__get(cgroup); 192} 193 194void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup) 195{ 196 struct evsel *evsel; 197 198 evlist__for_each_entry(evlist, evsel) 199 evsel__set_default_cgroup(evsel, cgroup); 200} 201 202int parse_cgroups(const struct option *opt, const char *str, 203 int unset __maybe_unused) 204{ 205 struct evlist *evlist = *(struct evlist **)opt->value; 206 struct evsel *counter; 207 struct cgroup *cgrp = NULL; 208 const char *p, *e, *eos = str + strlen(str); 209 char *s; 210 int ret, i; 211 212 if (list_empty(&evlist->core.entries)) { 213 fprintf(stderr, "must define events before cgroups\n"); 214 return -1; 215 } 216 217 for (;;) { 218 p = strchr(str, ','); 219 e = p ? p : eos; 220 221 /* allow empty cgroups, i.e., skip */ 222 if (e - str) { 223 /* termination added */ 224 s = strndup(str, e - str); 225 if (!s) 226 return -1; 227 ret = add_cgroup(evlist, s); 228 free(s); 229 if (ret) 230 return -1; 231 } 232 /* nr_cgroups is increased een for empty cgroups */ 233 nr_cgroups++; 234 if (!p) 235 break; 236 str = p+1; 237 } 238 /* for the case one cgroup combine to multiple events */ 239 i = 0; 240 if (nr_cgroups == 1) { 241 evlist__for_each_entry(evlist, counter) { 242 if (i == 0) 243 cgrp = counter->cgrp; 244 else { 245 counter->cgrp = cgrp; 246 refcount_inc(&cgrp->refcnt); 247 } 248 i++; 249 } 250 } 251 return 0; 252}