]>
Commit | Line | Data |
---|---|---|
9dd11ed0 MT |
1 | /*############################################################################# |
2 | # # | |
3 | # Pakfire - The IPFire package management system # | |
e3ddb498 | 4 | # Copyright (C) 2022 Pakfire development team # |
9dd11ed0 MT |
5 | # # |
6 | # This program is free software: you can redistribute it and/or modify # | |
7 | # it under the terms of the GNU General Public License as published by # | |
8 | # the Free Software Foundation, either version 3 of the License, or # | |
9 | # (at your option) any later version. # | |
10 | # # | |
11 | # This program is distributed in the hope that it will be useful, # | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
14 | # GNU General Public License for more details. # | |
15 | # # | |
16 | # You should have received a copy of the GNU General Public License # | |
17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
18 | # # | |
19 | #############################################################################*/ | |
20 | ||
21 | #include <errno.h> | |
e3ddb498 | 22 | #include <fcntl.h> |
9dd11ed0 | 23 | #include <stdlib.h> |
9dd11ed0 | 24 | #include <sys/types.h> |
9dd11ed0 MT |
25 | |
26 | #include <pakfire/cgroup.h> | |
27 | #include <pakfire/logging.h> | |
e3ddb498 | 28 | #include <pakfire/pakfire.h> |
9dd11ed0 MT |
29 | #include <pakfire/util.h> |
30 | ||
e3ddb498 MT |
31 | #define ROOT "/sys/fs/cgroup" |
32 | #define BUFFER_SIZE 64 * 1024 | |
9dd11ed0 | 33 | |
2901c3a7 MT |
34 | enum pakfire_cgroup_controllers { |
35 | PAKFIRE_CGROUP_CONTROLLER_CPU = (1 << 0), | |
36 | PAKFIRE_CGROUP_CONTROLLER_MEMORY = (1 << 1), | |
37 | PAKFIRE_CGROUP_CONTROLLER_PIDS = (1 << 2), | |
38 | PAKFIRE_CGROUP_CONTROLLER_IO = (1 << 3), | |
39 | }; | |
40 | ||
41 | static const enum pakfire_cgroup_controllers pakfire_cgroup_accounting_controllers = | |
42 | PAKFIRE_CGROUP_CONTROLLER_CPU | | |
43 | PAKFIRE_CGROUP_CONTROLLER_MEMORY | | |
44 | PAKFIRE_CGROUP_CONTROLLER_PIDS | | |
45 | PAKFIRE_CGROUP_CONTROLLER_IO; | |
46 | ||
e3ddb498 MT |
47 | struct pakfire_cgroup { |
48 | struct pakfire* pakfire; | |
49 | int nrefs; | |
9dd11ed0 | 50 | |
2901c3a7 MT |
51 | // Flags |
52 | int flags; | |
53 | ||
e3ddb498 MT |
54 | // Store the path |
55 | char path[PATH_MAX]; | |
9dd11ed0 | 56 | |
e3ddb498 MT |
57 | // File descriptor to cgroup |
58 | int fd; | |
59 | }; | |
9e1e7985 | 60 | |
e3ddb498 MT |
61 | // Returns true if this is the root cgroup |
62 | static int pakfire_cgroup_is_root(struct pakfire_cgroup* cgroup) { | |
63 | return !*cgroup->path; | |
64 | } | |
9e1e7985 | 65 | |
2901c3a7 MT |
66 | static int pakfire_cgroup_has_flag(struct pakfire_cgroup* cgroup, int flag) { |
67 | return cgroup->flags & flag; | |
68 | } | |
69 | ||
e3ddb498 MT |
70 | static const char* pakfire_cgroup_name(struct pakfire_cgroup* cgroup) { |
71 | if (pakfire_cgroup_is_root(cgroup)) | |
72 | return "(root)"; | |
9e1e7985 | 73 | |
e3ddb498 | 74 | return cgroup->path; |
9e1e7985 MT |
75 | } |
76 | ||
2901c3a7 MT |
77 | static const char* pakfire_cgroup_controller_name( |
78 | enum pakfire_cgroup_controllers controller) { | |
79 | switch (controller) { | |
80 | case PAKFIRE_CGROUP_CONTROLLER_CPU: | |
81 | return "cpu"; | |
82 | ||
83 | case PAKFIRE_CGROUP_CONTROLLER_MEMORY: | |
84 | return "memory"; | |
85 | ||
86 | case PAKFIRE_CGROUP_CONTROLLER_PIDS: | |
87 | return "pids"; | |
88 | ||
89 | case PAKFIRE_CGROUP_CONTROLLER_IO: | |
90 | return "io"; | |
91 | } | |
92 | ||
93 | return NULL; | |
94 | } | |
95 | ||
96 | static enum pakfire_cgroup_controllers pakfire_cgroup_find_controller_by_name( | |
97 | const char* name) { | |
98 | const char* n = NULL; | |
99 | ||
100 | // Walk through the bitmap | |
101 | for (unsigned int i = 1; i; i <<= 1) { | |
102 | n = pakfire_cgroup_controller_name(i); | |
103 | if (!n) | |
104 | break; | |
105 | ||
106 | // Match | |
107 | if (strcmp(name, n) == 0) | |
108 | return i; | |
109 | } | |
110 | ||
111 | // Nothing found | |
112 | return 0; | |
113 | } | |
114 | ||
115 | static struct pakfire_cgroup* pakfire_cgroup_parent(struct pakfire_cgroup* cgroup) { | |
116 | struct pakfire_cgroup* parent = NULL; | |
117 | int r; | |
118 | ||
119 | // Cannot return parent for root group | |
120 | if (pakfire_cgroup_is_root(cgroup)) | |
121 | return NULL; | |
122 | ||
123 | // Determine the path of the parent | |
124 | char* path = pakfire_dirname(cgroup->path); | |
125 | if (!path) { | |
126 | ERROR(cgroup->pakfire, "Could not determine path for parent cgroup: %m\n"); | |
127 | return NULL; | |
128 | } | |
129 | ||
130 | // dirname() returns . if no directory component could be found | |
131 | if (strcmp(path, ".") == 0) | |
132 | *path = '\0'; | |
133 | ||
134 | // Open the cgroup | |
135 | r = pakfire_cgroup_open(&parent, cgroup->pakfire, path, 0); | |
136 | if (r) { | |
137 | ERROR(cgroup->pakfire, "Could not open parent cgroup: %m\n"); | |
138 | parent = NULL; | |
139 | } | |
140 | ||
141 | // Cleanup | |
142 | free(path); | |
143 | ||
144 | return parent; | |
145 | } | |
146 | ||
e3ddb498 MT |
147 | static void pakfire_cgroup_free(struct pakfire_cgroup* cgroup) { |
148 | DEBUG(cgroup->pakfire, "Releasing cgroup %s at %p\n", | |
149 | pakfire_cgroup_name(cgroup), cgroup); | |
9e1e7985 | 150 | |
e3ddb498 MT |
151 | // Close the file descriptor |
152 | if (cgroup->fd) | |
153 | close(cgroup->fd); | |
9e1e7985 | 154 | |
e3ddb498 MT |
155 | pakfire_unref(cgroup->pakfire); |
156 | free(cgroup); | |
9e1e7985 MT |
157 | } |
158 | ||
01cf6134 MT |
159 | static int pakfire_cgroup_open_root(struct pakfire_cgroup* cgroup) { |
160 | int fd = open(ROOT, O_DIRECTORY|O_PATH|O_CLOEXEC); | |
161 | if (fd < 0) { | |
162 | ERROR(cgroup->pakfire, "Could not open %s: %m\n", ROOT); | |
163 | return -1; | |
164 | } | |
165 | ||
166 | return fd; | |
167 | } | |
168 | ||
e3ddb498 MT |
169 | static int __pakfire_cgroup_create(struct pakfire_cgroup* cgroup) { |
170 | char path[PATH_MAX]; | |
171 | int r; | |
9dd11ed0 | 172 | |
e3ddb498 | 173 | DEBUG(cgroup->pakfire, "Trying to create cgroup %s\n", pakfire_cgroup_name(cgroup)); |
9dd11ed0 | 174 | |
e3ddb498 MT |
175 | // Compose the absolute path |
176 | r = pakfire_path_join(path, ROOT, cgroup->path); | |
177 | if (r < 0) | |
178 | return 1; | |
9dd11ed0 | 179 | |
e3ddb498 MT |
180 | // Try creating the directory |
181 | return pakfire_mkdir(path, 0755); | |
182 | } | |
9dd11ed0 | 183 | |
e3ddb498 MT |
184 | /* |
185 | Opens the cgroup and returns a file descriptor. | |
9dd11ed0 | 186 | |
e3ddb498 | 187 | If the cgroup does not exist, it will try to create it. |
9dd11ed0 | 188 | |
e3ddb498 MT |
189 | This function returns a negative value on error. |
190 | */ | |
191 | static int __pakfire_cgroup_open(struct pakfire_cgroup* cgroup) { | |
e3ddb498 MT |
192 | int fd = -1; |
193 | int r; | |
9dd11ed0 | 194 | |
e3ddb498 | 195 | // Open file descriptor of the cgroup root |
01cf6134 MT |
196 | int rootfd = pakfire_cgroup_open_root(cgroup); |
197 | if (rootfd < 0) | |
e3ddb498 | 198 | return -1; |
9dd11ed0 | 199 | |
e3ddb498 MT |
200 | // Return the rootfd for the root group |
201 | if (pakfire_cgroup_is_root(cgroup)) | |
202 | return rootfd; | |
9dd11ed0 | 203 | |
e3ddb498 MT |
204 | RETRY: |
205 | fd = openat(rootfd, cgroup->path, O_DIRECTORY|O_PATH|O_CLOEXEC); | |
206 | if (fd < 0) { | |
207 | switch (errno) { | |
208 | // If the cgroup doesn't exist yet, try to create it | |
209 | case ENOENT: | |
210 | r = __pakfire_cgroup_create(cgroup); | |
211 | if (r) | |
212 | goto ERROR; | |
9dd11ed0 | 213 | |
e3ddb498 MT |
214 | // Retry open after successful creation |
215 | goto RETRY; | |
9dd11ed0 | 216 | |
e3ddb498 MT |
217 | // Exit on all other errors |
218 | default: | |
219 | ERROR(cgroup->pakfire, "Could not open cgroup %s: %m\n", | |
220 | pakfire_cgroup_name(cgroup)); | |
221 | goto ERROR; | |
222 | } | |
223 | } | |
9dd11ed0 | 224 | |
e3ddb498 MT |
225 | ERROR: |
226 | if (rootfd > 0) | |
227 | close(rootfd); | |
9dd11ed0 | 228 | |
e3ddb498 MT |
229 | return fd; |
230 | } | |
9dd11ed0 | 231 | |
2901c3a7 | 232 | static ssize_t pakfire_cgroup_read(struct pakfire_cgroup* cgroup, const char* path, |
e3ddb498 | 233 | char* buffer, size_t length) { |
2901c3a7 | 234 | ssize_t bytes_read = -1; |
9dd11ed0 | 235 | |
e3ddb498 MT |
236 | // Check if this cgroup has been destroyed already |
237 | if (!cgroup->fd) { | |
238 | ERROR(cgroup->pakfire, "Trying to read from destroyed cgroup\n"); | |
2901c3a7 | 239 | return -1; |
9dd11ed0 MT |
240 | } |
241 | ||
e3ddb498 MT |
242 | // Open the file |
243 | int fd = openat(cgroup->fd, path, O_CLOEXEC); | |
244 | if (fd < 0) { | |
245 | DEBUG(cgroup->pakfire, "Could not open %s/%s: %m\n", | |
246 | pakfire_cgroup_name(cgroup), path); | |
247 | goto ERROR; | |
248 | } | |
9dd11ed0 | 249 | |
e3ddb498 | 250 | // Read file content into buffer |
2901c3a7 MT |
251 | bytes_read = read(fd, buffer, length); |
252 | if (bytes_read < 0) { | |
e3ddb498 MT |
253 | DEBUG(cgroup->pakfire, "Could not read from %s/%s: %m\n", |
254 | pakfire_cgroup_name(cgroup), path); | |
255 | goto ERROR; | |
256 | } | |
9dd11ed0 | 257 | |
2901c3a7 MT |
258 | // Terminate the buffer |
259 | if (bytes_read < length) | |
260 | buffer[bytes_read] = '\0'; | |
9dd11ed0 | 261 | |
e3ddb498 MT |
262 | ERROR: |
263 | if (fd > 0) | |
264 | close(fd); | |
9dd11ed0 | 265 | |
2901c3a7 | 266 | return bytes_read; |
9dd11ed0 MT |
267 | } |
268 | ||
e3ddb498 MT |
269 | static int pakfire_cgroup_write(struct pakfire_cgroup* cgroup, |
270 | const char* path, const char* format, ...) { | |
305de320 | 271 | va_list args; |
e3ddb498 MT |
272 | int r = 0; |
273 | ||
274 | // Check if this cgroup has been destroyed already | |
275 | if (!cgroup->fd) { | |
276 | ERROR(cgroup->pakfire, "Trying to write to destroyed cgroup\n"); | |
277 | errno = EPERM; | |
278 | return 1; | |
279 | } | |
9dd11ed0 | 280 | |
e3ddb498 MT |
281 | // Open the file |
282 | int fd = openat(cgroup->fd, path, O_WRONLY|O_CLOEXEC); | |
283 | if (fd < 0) { | |
284 | DEBUG(cgroup->pakfire, "Could not open %s/%s for writing: %m\n", | |
285 | pakfire_cgroup_name(cgroup), path); | |
9dd11ed0 | 286 | return 1; |
e3ddb498 | 287 | } |
9dd11ed0 | 288 | |
e3ddb498 | 289 | // Write buffer |
305de320 | 290 | va_start(args, format); |
e3ddb498 | 291 | ssize_t bytes_written = vdprintf(fd, format, args); |
305de320 MT |
292 | va_end(args); |
293 | ||
e3ddb498 MT |
294 | // Check if content was written okay |
295 | if (bytes_written < 0) { | |
296 | DEBUG(cgroup->pakfire, "Could not write to %s/%s: %m\n", | |
297 | pakfire_cgroup_name(cgroup), path); | |
298 | r = 1; | |
299 | } | |
820c32c7 | 300 | |
e3ddb498 MT |
301 | // Close fd |
302 | close(fd); | |
305de320 MT |
303 | |
304 | return r; | |
305 | } | |
306 | ||
2901c3a7 MT |
307 | static int pakfire_cgroup_read_controllers( |
308 | struct pakfire_cgroup* cgroup, const char* name) { | |
309 | char buffer[BUFFER_SIZE]; | |
310 | char* p = NULL; | |
9dd11ed0 MT |
311 | int r; |
312 | ||
2901c3a7 MT |
313 | // Discovered controllers |
314 | int controllers = 0; | |
69cfa22d | 315 | |
2901c3a7 MT |
316 | // Read cgroup.controllers file |
317 | ssize_t bytes_read = pakfire_cgroup_read(cgroup, name, buffer, sizeof(buffer)); | |
318 | if (bytes_read < 0) | |
319 | return -1; | |
320 | ||
321 | // If the file was empty, there is nothing more to do | |
322 | if (bytes_read == 0) | |
323 | return 0; | |
324 | ||
325 | char* token = strtok_r(buffer, " \n", &p); | |
326 | ||
327 | while (token) { | |
328 | DEBUG(cgroup->pakfire, "Found controller '%s'\n", token); | |
329 | ||
330 | // Try finding this controller | |
331 | int controller = pakfire_cgroup_find_controller_by_name(token); | |
332 | if (controller) | |
333 | controllers |= controller; | |
334 | ||
335 | // Move on to next token | |
336 | token = strtok_r(NULL, " \n", &p); | |
9dd11ed0 MT |
337 | } |
338 | ||
2901c3a7 MT |
339 | // Return discovered controllers |
340 | return controllers; | |
341 | } | |
9dd11ed0 | 342 | |
2901c3a7 MT |
343 | /* |
344 | Returns a bitmap of all available controllers | |
345 | */ | |
346 | static int pakfire_cgroup_available_controllers(struct pakfire_cgroup* cgroup) { | |
347 | return pakfire_cgroup_read_controllers(cgroup, "cgroup.controllers"); | |
348 | } | |
349 | ||
350 | /* | |
351 | Returns a bitmap of all enabled controllers | |
352 | */ | |
353 | static int pakfire_cgroup_enabled_controllers(struct pakfire_cgroup* cgroup) { | |
354 | return pakfire_cgroup_read_controllers(cgroup, "cgroup.subtree_control"); | |
355 | } | |
356 | ||
357 | /* | |
358 | This function takes a bitmap of controllers that should be enabled. | |
359 | */ | |
360 | static int pakfire_cgroup_enable_controllers(struct pakfire_cgroup* cgroup, | |
361 | enum pakfire_cgroup_controllers controllers) { | |
362 | struct pakfire_cgroup* parent = NULL; | |
363 | int r = 1; | |
364 | ||
365 | // Find all enabled controllers | |
366 | const int enabled_controllers = pakfire_cgroup_enabled_controllers(cgroup); | |
367 | if (enabled_controllers < 0) { | |
368 | ERROR(cgroup->pakfire, "Could not fetch enabled controllers: %m\n"); | |
369 | goto ERROR; | |
9dd11ed0 MT |
370 | } |
371 | ||
2901c3a7 MT |
372 | // Filter out anything that is already enabled |
373 | controllers = (controllers & ~enabled_controllers); | |
9dd11ed0 | 374 | |
2901c3a7 MT |
375 | // Exit if everything is already enabled |
376 | if (!controllers) { | |
377 | DEBUG(cgroup->pakfire, "All controllers are already enabled\n"); | |
378 | return 0; | |
379 | } | |
380 | ||
381 | // Find all available controllers | |
382 | const int available_controllers = pakfire_cgroup_available_controllers(cgroup); | |
383 | if (available_controllers < 0) { | |
384 | ERROR(cgroup->pakfire, "Could not fetch available controllers: %m\n"); | |
385 | goto ERROR; | |
386 | } | |
387 | ||
388 | // Are all controllers we need available, yet? | |
389 | if (controllers & ~available_controllers) { | |
390 | DEBUG(cgroup->pakfire, "Not all controllers are available, yet\n"); | |
391 | ||
392 | parent = pakfire_cgroup_parent(cgroup); | |
393 | ||
394 | // Enable everything we need on the parent group | |
395 | if (parent) { | |
396 | r = pakfire_cgroup_enable_controllers(parent, controllers); | |
397 | if (r) | |
398 | goto ERROR; | |
399 | } | |
400 | } | |
401 | ||
402 | // Determine how many iterations we will need | |
403 | const int iterations = 1 << (sizeof(controllers) * 8 - __builtin_clz(controllers)); | |
404 | ||
405 | // Iterate over all known controllers | |
406 | for (int controller = 1; controller < iterations; controller <<= 1) { | |
407 | // Skip enabling this controller if not requested | |
408 | if (!(controller & controllers)) | |
409 | continue; | |
410 | ||
411 | // Fetch name | |
412 | const char* name = pakfire_cgroup_controller_name(controller); | |
413 | ||
414 | DEBUG(cgroup->pakfire, "Enabling controller %s in cgroup %s\n", | |
415 | name, pakfire_cgroup_name(cgroup)); | |
416 | ||
417 | // Try enabling the controller (this will succeed if it already is enabled) | |
418 | r = pakfire_cgroup_write(cgroup, "cgroup.subtree_control", "+%s\n", name); | |
419 | if (r) { | |
420 | ERROR(cgroup->pakfire, "Could not enable controller %s in cgroup %s\n", | |
421 | name, pakfire_cgroup_name(cgroup)); | |
422 | goto ERROR; | |
423 | } | |
424 | } | |
425 | ||
426 | ERROR: | |
427 | if (parent) | |
428 | pakfire_cgroup_unref(parent); | |
429 | ||
430 | return r; | |
431 | } | |
432 | ||
433 | static int pakfire_cgroup_enable_accounting(struct pakfire_cgroup* cgroup) { | |
434 | // Enable all accounting controllers | |
435 | return pakfire_cgroup_enable_controllers(cgroup, | |
436 | pakfire_cgroup_accounting_controllers); | |
9dd11ed0 MT |
437 | } |
438 | ||
e3ddb498 MT |
439 | /* |
440 | Entry function to open a new cgroup. | |
9dd11ed0 | 441 | |
e3ddb498 MT |
442 | If the cgroup doesn't exist, it will be created including any parent cgroups. |
443 | */ | |
444 | int pakfire_cgroup_open(struct pakfire_cgroup** cgroup, | |
2901c3a7 | 445 | struct pakfire* pakfire, const char* path, int flags) { |
e3ddb498 | 446 | int r = 1; |
9dd11ed0 | 447 | |
e3ddb498 MT |
448 | // Allocate the cgroup struct |
449 | struct pakfire_cgroup* c = calloc(1, sizeof(*c)); | |
450 | if (!c) | |
451 | return 1; | |
9dd11ed0 | 452 | |
e3ddb498 | 453 | DEBUG(pakfire, "Allocated cgroup %s at %p\n", path, c); |
9dd11ed0 | 454 | |
e3ddb498 MT |
455 | // Keep a reference to pakfire |
456 | c->pakfire = pakfire_ref(pakfire); | |
4630031c | 457 | |
e3ddb498 MT |
458 | // Initialize reference counter |
459 | c->nrefs = 1; | |
5ae21aa1 | 460 | |
e3ddb498 MT |
461 | // Copy path |
462 | pakfire_string_set(c->path, path); | |
5ae21aa1 | 463 | |
2901c3a7 MT |
464 | // Copy flags |
465 | c->flags = flags; | |
466 | ||
e3ddb498 MT |
467 | // Open a file descriptor |
468 | c->fd = __pakfire_cgroup_open(c); | |
469 | if (c->fd < 0) | |
470 | goto ERROR; | |
4630031c | 471 | |
2901c3a7 MT |
472 | // Enable accounting if requested |
473 | if (pakfire_cgroup_has_flag(c, PAKFIRE_CGROUP_ENABLE_ACCOUNTING)) { | |
474 | r = pakfire_cgroup_enable_accounting(c); | |
475 | if (r) | |
476 | goto ERROR; | |
477 | } | |
478 | ||
e3ddb498 | 479 | *cgroup = c; |
4630031c | 480 | return 0; |
4630031c | 481 | |
e3ddb498 MT |
482 | ERROR: |
483 | pakfire_cgroup_free(c); | |
484 | return r; | |
4630031c MT |
485 | } |
486 | ||
e3ddb498 MT |
487 | struct pakfire_cgroup* pakfire_cgroup_ref(struct pakfire_cgroup* cgroup) { |
488 | ++cgroup->nrefs; | |
4630031c | 489 | |
e3ddb498 | 490 | return cgroup; |
1b41d3b1 MT |
491 | } |
492 | ||
e3ddb498 MT |
493 | struct pakfire_cgroup* pakfire_cgroup_unref(struct pakfire_cgroup* cgroup) { |
494 | if (--cgroup->nrefs > 0) | |
495 | return cgroup; | |
1b41d3b1 | 496 | |
e3ddb498 MT |
497 | pakfire_cgroup_free(cgroup); |
498 | return NULL; | |
1b41d3b1 MT |
499 | } |
500 | ||
e3ddb498 MT |
501 | /* |
502 | Immediately kills all processes in this cgroup | |
503 | */ | |
504 | int pakfire_cgroup_killall(struct pakfire_cgroup* cgroup) { | |
505 | int r = pakfire_cgroup_write(cgroup, "cgroup.kill", "1"); | |
506 | if (r) | |
507 | ERROR(cgroup->pakfire, "Could not kill processes: %m\n"); | |
1b41d3b1 | 508 | |
e3ddb498 MT |
509 | return r; |
510 | } | |
1b41d3b1 | 511 | |
e3ddb498 MT |
512 | /* |
513 | Immediately destroys this cgroup | |
514 | */ | |
515 | int pakfire_cgroup_destroy(struct pakfire_cgroup* cgroup) { | |
516 | int r; | |
1b41d3b1 | 517 | |
01cf6134 MT |
518 | // Cannot call this for the root group |
519 | if (pakfire_cgroup_is_root(cgroup)) { | |
520 | errno = EPERM; | |
521 | return 1; | |
522 | } | |
523 | ||
524 | DEBUG(cgroup->pakfire, "Destroying cgroup %s\n", pakfire_cgroup_name(cgroup)); | |
525 | ||
e3ddb498 MT |
526 | // Kill everything in this group |
527 | r = pakfire_cgroup_killall(cgroup); | |
528 | if (r) | |
529 | return r; | |
1b41d3b1 | 530 | |
e3ddb498 MT |
531 | // Close the file descriptor |
532 | if (cgroup->fd) { | |
533 | close(cgroup->fd); | |
534 | cgroup->fd = 0; | |
d5256224 | 535 | } |
d5256224 | 536 | |
01cf6134 MT |
537 | // Open the root directory |
538 | int fd = pakfire_cgroup_open_root(cgroup); | |
539 | if (fd < 0) | |
540 | return 1; | |
541 | ||
542 | // Delete the directory | |
543 | r = unlinkat(fd, cgroup->path, AT_REMOVEDIR); | |
544 | if (r) | |
545 | ERROR(cgroup->pakfire, "Could not destroy cgroup: %m\n"); | |
546 | ||
547 | // Close fd | |
548 | close(fd); | |
549 | ||
550 | return r; | |
d5256224 | 551 | } |
820c32c7 | 552 | |
e3ddb498 MT |
553 | int pakfire_cgroup_fd(struct pakfire_cgroup* cgroup) { |
554 | return cgroup->fd; | |
820c32c7 | 555 | } |
46dd01c6 MT |
556 | |
557 | // Memory | |
558 | ||
559 | int pakfire_cgroup_set_guaranteed_memory(struct pakfire_cgroup* cgroup, size_t mem) { | |
560 | int r; | |
561 | ||
562 | // Enable memory controller | |
563 | r = pakfire_cgroup_enable_controllers(cgroup, PAKFIRE_CGROUP_CONTROLLER_MEMORY); | |
564 | if (r) | |
565 | return r; | |
566 | ||
567 | DEBUG(cgroup->pakfire, "%s: Setting guaranteed memory to %zu byte(s)\n", | |
568 | pakfire_cgroup_name(cgroup), mem); | |
569 | ||
570 | // Set value | |
571 | r = pakfire_cgroup_write(cgroup, "memory.min", "%zu\n", mem); | |
572 | if (r) | |
573 | ERROR(cgroup->pakfire, "%s: Could not set guaranteed memory: %m\n", | |
574 | pakfire_cgroup_name(cgroup)); | |
575 | ||
576 | return r; | |
577 | } | |
578 | ||
579 | int pakfire_cgroup_set_memory_limit(struct pakfire_cgroup* cgroup, size_t mem) { | |
580 | int r; | |
581 | ||
582 | // Enable memory controller | |
583 | r = pakfire_cgroup_enable_controllers(cgroup, PAKFIRE_CGROUP_CONTROLLER_MEMORY); | |
584 | if (r) | |
585 | return r; | |
586 | ||
587 | DEBUG(cgroup->pakfire, "%s: Setting memory limit to %zu byte(s)\n", | |
588 | pakfire_cgroup_name(cgroup), mem); | |
589 | ||
590 | // Set value | |
591 | r = pakfire_cgroup_write(cgroup, "memory.max", "%zu\n", mem); | |
592 | if (r) | |
593 | ERROR(cgroup->pakfire, "%s: Could not set memory limit: %m\n", | |
594 | pakfire_cgroup_name(cgroup)); | |
595 | ||
596 | return r; | |
597 | } |