]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/swap.c
importd: fix typos
[thirdparty/systemd.git] / src / core / swap.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
07b0b134
ML
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
07b0b134
ML
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
07b0b134 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
07b0b134
ML
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
07b0b134 23#include <unistd.h>
07b0b134
ML
24#include <sys/epoll.h>
25#include <sys/stat.h>
e04aad61 26#include <libudev.h>
07b0b134
ML
27
28#include "unit.h"
29#include "swap.h"
07b0b134
ML
30#include "unit-name.h"
31#include "dbus-swap.h"
514f4ef5 32#include "special.h"
9a57c629 33#include "exit-status.h"
9eb977db 34#include "path-util.h"
a5c3034f 35#include "virt.h"
5bcb0f2b 36#include "udev-util.h"
d15d0333 37#include "fstab-util.h"
6482f626 38#include "formats-util.h"
07b0b134
ML
39
40static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
41 [SWAP_DEAD] = UNIT_INACTIVE,
e04aad61 42 [SWAP_ACTIVATING] = UNIT_ACTIVATING,
5bcb0f2b 43 [SWAP_ACTIVATING_DONE] = UNIT_ACTIVE,
07b0b134 44 [SWAP_ACTIVE] = UNIT_ACTIVE,
e04aad61
LP
45 [SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
46 [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
47 [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
48 [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
49 [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
fdf20a31 50 [SWAP_FAILED] = UNIT_FAILED
07b0b134
ML
51};
52
718db961
LP
53static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
54static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
55
e04aad61 56static void swap_unset_proc_swaps(Swap *s) {
9670d583
LP
57 assert(s);
58
59 if (!s->from_proc_swaps)
60 return;
61
a1e58e8e 62 s->parameters_proc_swaps.what = mfree(s->parameters_proc_swaps.what);
9670d583
LP
63
64 s->from_proc_swaps = false;
65}
66
67static int swap_set_devnode(Swap *s, const char *devnode) {
df326b84 68 Hashmap *swaps;
5bcb0f2b 69 Swap *first;
9670d583 70 int r;
e04aad61
LP
71
72 assert(s);
73
d5099efc 74 r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, &string_hash_ops);
9670d583
LP
75 if (r < 0)
76 return r;
e04aad61 77
9670d583 78 swaps = UNIT(s)->manager->swaps_by_devnode;
e04aad61 79
9670d583
LP
80 if (s->devnode) {
81 first = hashmap_get(swaps, s->devnode);
e04aad61 82
9670d583
LP
83 LIST_REMOVE(same_devnode, first, s);
84 if (first)
85 hashmap_replace(swaps, first->devnode, first);
86 else
87 hashmap_remove(swaps, s->devnode);
5bcb0f2b 88
a1e58e8e 89 s->devnode = mfree(s->devnode);
9670d583
LP
90 }
91
92 if (devnode) {
93 s->devnode = strdup(devnode);
94 if (!s->devnode)
95 return -ENOMEM;
96
97 first = hashmap_get(swaps, s->devnode);
98 LIST_PREPEND(same_devnode, first, s);
99
100 return hashmap_replace(swaps, first->devnode, first);
101 }
102
103 return 0;
e04aad61
LP
104}
105
f6cebb3b 106static void swap_init(Unit *u) {
6e620bec
LP
107 Swap *s = SWAP(u);
108
109 assert(s);
1124fe6f 110 assert(UNIT(s)->load_state == UNIT_STUB);
6e620bec 111
1f19a534 112 s->timeout_usec = u->manager->default_timeout_start_usec;
e04aad61 113
ac155bb8
MS
114 s->exec_context.std_output = u->manager->default_std_output;
115 s->exec_context.std_error = u->manager->default_std_error;
085afe36 116
6b1dc2bd 117 s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
e04aad61 118
e1770af8 119 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
c8f4d764 120
5bcb0f2b 121 u->ignore_on_isolate = true;
e04aad61
LP
122}
123
124static void swap_unwatch_control_pid(Swap *s) {
125 assert(s);
126
127 if (s->control_pid <= 0)
128 return;
129
130 unit_unwatch_pid(UNIT(s), s->control_pid);
131 s->control_pid = 0;
6e620bec
LP
132}
133
4e85aff4
LP
134static void swap_done(Unit *u) {
135 Swap *s = SWAP(u);
07b0b134 136
4e85aff4 137 assert(s);
07b0b134 138
e04aad61 139 swap_unset_proc_swaps(s);
9670d583 140 swap_set_devnode(s, NULL);
e04aad61 141
a1e58e8e
LP
142 s->what = mfree(s->what);
143 s->parameters_fragment.what = mfree(s->parameters_fragment.what);
144 s->parameters_fragment.options = mfree(s->parameters_fragment.options);
86b23b07 145
613b411c 146 s->exec_runtime = exec_runtime_unref(s->exec_runtime);
e04aad61
LP
147 exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
148 s->control_command = NULL;
149
150 swap_unwatch_control_pid(s);
151
718db961
LP
152 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
153}
154
155static int swap_arm_timer(Swap *s) {
156 int r;
157
158 assert(s);
159
160 if (s->timeout_usec <= 0) {
161 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
162 return 0;
163 }
164
165 if (s->timer_event_source) {
166 r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
167 if (r < 0)
168 return r;
169
170 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
171 }
172
7dfbe2e3 173 r = sd_event_add_time(
6a0f1f6d
LP
174 UNIT(s)->manager->event,
175 &s->timer_event_source,
176 CLOCK_MONOTONIC,
177 now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
178 swap_dispatch_timer, s);
7dfbe2e3
TG
179 if (r < 0)
180 return r;
181
182 (void) sd_event_source_set_description(s->timer_event_source, "swap-timer");
183
184 return 0;
07b0b134
ML
185}
186
173a8d04 187static int swap_add_device_links(Swap *s) {
173a8d04
LP
188 assert(s);
189
190 if (!s->what)
191 return 0;
192
f10af76d
LP
193 if (!s->from_fragment)
194 return 0;
195
cfcfd4ae 196 if (is_device_path(s->what))
b2c23da8 197 return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM);
cfcfd4ae
LP
198 else
199 /* File based swap devices need to be ordered after
2b93b027 200 * systemd-remount-fs.service, since they might need a
cfcfd4ae 201 * writable file system. */
2b93b027 202 return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true);
173a8d04
LP
203}
204
2edd4434 205static int swap_add_default_dependencies(Swap *s) {
2edd4434
LP
206 assert(s);
207
b2c23da8 208 if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
6b1dc2bd 209 return 0;
2edd4434 210
75f86906 211 if (detect_container() > 0)
c0387ebf
LP
212 return 0;
213
5607d856 214 return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
2edd4434
LP
215}
216
4e85aff4 217static int swap_verify(Swap *s) {
7fd1b19b 218 _cleanup_free_ char *e = NULL;
7410616c 219 int r;
4e85aff4 220
1124fe6f 221 if (UNIT(s)->load_state != UNIT_LOADED)
5bcb0f2b 222 return 0;
4e85aff4 223
7410616c
LP
224 r = unit_name_from_path(s->what, ".swap", &e);
225 if (r < 0)
f2341e0a 226 return log_unit_error_errno(UNIT(s), r, "Failed to generate unit name from path: %m");
4e85aff4 227
7410616c 228 if (!unit_has_name(UNIT(s), e)) {
f2341e0a 229 log_unit_error(UNIT(s), "Value of What= and unit name do not match, not loading.");
4e85aff4
LP
230 return -EINVAL;
231 }
232
4819ff03 233 if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
f2341e0a 234 log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.");
e04aad61
LP
235 return -EINVAL;
236 }
237
4e85aff4
LP
238 return 0;
239}
240
9670d583
LP
241static int swap_load_devnode(Swap *s) {
242 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
243 struct stat st;
244 const char *p;
245
246 assert(s);
247
248 if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode))
249 return 0;
250
251 d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev);
252 if (!d)
253 return 0;
254
255 p = udev_device_get_devnode(d);
256 if (!p)
257 return 0;
258
259 return swap_set_devnode(s, p);
260}
261
07b0b134
ML
262static int swap_load(Unit *u) {
263 int r;
264 Swap *s = SWAP(u);
265
266 assert(s);
ac155bb8 267 assert(u->load_state == UNIT_STUB);
07b0b134
ML
268
269 /* Load a .swap file */
646134dc
ZJS
270 r = unit_load_fragment_and_dropin_optional(u);
271 if (r < 0)
07b0b134
ML
272 return r;
273
ac155bb8 274 if (u->load_state == UNIT_LOADED) {
4e85aff4 275
1124fe6f 276 if (UNIT(s)->fragment_path)
4e85aff4
LP
277 s->from_fragment = true;
278
279 if (!s->what) {
280 if (s->parameters_fragment.what)
281 s->what = strdup(s->parameters_fragment.what);
4e85aff4
LP
282 else if (s->parameters_proc_swaps.what)
283 s->what = strdup(s->parameters_proc_swaps.what);
7410616c
LP
284 else {
285 r = unit_name_to_path(u->id, &s->what);
286 if (r < 0)
287 return r;
288 }
4e85aff4
LP
289
290 if (!s->what)
07b0b134 291 return -ENOMEM;
4e85aff4 292 }
07b0b134
ML
293
294 path_kill_slashes(s->what);
295
5bcb0f2b
LP
296 if (!UNIT(s)->description) {
297 r = unit_set_description(u, s->what);
298 if (r < 0)
4e85aff4 299 return r;
5bcb0f2b 300 }
4e85aff4 301
a57f7e2c 302 r = unit_require_mounts_for(UNIT(s), s->what);
646134dc 303 if (r < 0)
07b0b134
ML
304 return r;
305
a57f7e2c 306 r = swap_add_device_links(s);
646134dc 307 if (r < 0)
6e2ef85b 308 return r;
07b0b134 309
9670d583
LP
310 r = swap_load_devnode(s);
311 if (r < 0)
312 return r;
313
598459ce
LP
314 r = unit_patch_contexts(u);
315 if (r < 0)
316 return r;
317
318 r = unit_add_exec_dependencies(u, &s->exec_context);
319 if (r < 0)
320 return r;
321
d79200e2 322 r = unit_set_default_slice(u);
a016b922
LP
323 if (r < 0)
324 return r;
325
646134dc
ZJS
326 if (UNIT(s)->default_dependencies) {
327 r = swap_add_default_dependencies(s);
328 if (r < 0)
2edd4434 329 return r;
646134dc 330 }
07b0b134
ML
331 }
332
333 return swap_verify(s);
334}
335
628c89cc 336static int swap_setup_unit(
4e85aff4
LP
337 Manager *m,
338 const char *what,
e04aad61 339 const char *what_proc_swaps,
4e85aff4 340 int priority,
e04aad61
LP
341 bool set_flags) {
342
7fd1b19b 343 _cleanup_free_ char *e = NULL;
2c7c6144 344 bool delete = false;
5bcb0f2b 345 Unit *u = NULL;
07b0b134 346 int r;
4e85aff4
LP
347 SwapParameters *p;
348
349 assert(m);
350 assert(what);
6b1dc2bd 351 assert(what_proc_swaps);
07b0b134 352
7410616c
LP
353 r = unit_name_from_path(what, ".swap", &e);
354 if (r < 0)
f2341e0a 355 return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
07b0b134 356
e04aad61
LP
357 u = manager_get_unit(m, e);
358
6b1dc2bd 359 if (u &&
e04aad61 360 SWAP(u)->from_proc_swaps &&
628c89cc
LP
361 !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) {
362 log_error("Swap %s appeared twice with different device paths %s and %s", e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
e04aad61 363 return -EEXIST;
628c89cc 364 }
4e85aff4
LP
365
366 if (!u) {
07b0b134
ML
367 delete = true;
368
7d17cfbc 369 u = unit_new(m, sizeof(Swap));
170ca19e
ZJS
370 if (!u)
371 return log_oom();
e04aad61 372
7d17cfbc
MS
373 r = unit_add_name(u, e);
374 if (r < 0)
e04aad61
LP
375 goto fail;
376
7d17cfbc
MS
377 SWAP(u)->what = strdup(what);
378 if (!SWAP(u)->what) {
628c89cc 379 r = -ENOMEM;
e04aad61
LP
380 goto fail;
381 }
382
383 unit_add_to_load_queue(u);
4e85aff4
LP
384 } else
385 delete = false;
07b0b134 386
6b1dc2bd 387 p = &SWAP(u)->parameters_proc_swaps;
07b0b134 388
6b1dc2bd 389 if (!p->what) {
5bcb0f2b
LP
390 p->what = strdup(what_proc_swaps);
391 if (!p->what) {
392 r = -ENOMEM;
6b1dc2bd
LP
393 goto fail;
394 }
6b1dc2bd 395 }
e04aad61 396
6b1dc2bd
LP
397 if (set_flags) {
398 SWAP(u)->is_active = true;
399 SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
4e85aff4 400 }
07b0b134 401
6b1dc2bd
LP
402 SWAP(u)->from_proc_swaps = true;
403
4e85aff4 404 p->priority = priority;
07b0b134 405
4e85aff4 406 unit_add_to_dbus_queue(u);
07b0b134
ML
407 return 0;
408
409fail:
f2341e0a 410 log_unit_warning_errno(u, r, "Failed to load swap unit: %m");
e04aad61 411
4e85aff4 412 if (delete && u)
07b0b134
ML
413 unit_free(u);
414
4e85aff4 415 return r;
07b0b134
ML
416}
417
628c89cc 418static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
5bcb0f2b
LP
419 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
420 struct udev_list_entry *item = NULL, *first = NULL;
421 const char *dn;
e04aad61 422 struct stat st;
5bcb0f2b 423 int r;
e04aad61
LP
424
425 assert(m);
426
628c89cc 427 r = swap_setup_unit(m, device, device, prio, set_flags);
5bcb0f2b
LP
428 if (r < 0)
429 return r;
e04aad61 430
5bcb0f2b
LP
431 /* If this is a block device, then let's add duplicates for
432 * all other names of this block device */
433 if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
434 return 0;
e04aad61 435
5bcb0f2b
LP
436 d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev);
437 if (!d)
438 return 0;
e04aad61 439
5bcb0f2b
LP
440 /* Add the main device node */
441 dn = udev_device_get_devnode(d);
442 if (dn && !streq(dn, device))
628c89cc 443 swap_setup_unit(m, dn, device, prio, set_flags);
e04aad61 444
5bcb0f2b
LP
445 /* Add additional units for all symlinks */
446 first = udev_device_get_devlinks_list_entry(d);
447 udev_list_entry_foreach(item, first) {
448 const char *p;
e04aad61 449
5bcb0f2b
LP
450 /* Don't bother with the /dev/block links */
451 p = udev_list_entry_get_name(item);
e04aad61 452
5bcb0f2b
LP
453 if (streq(p, device))
454 continue;
e04aad61 455
5bcb0f2b
LP
456 if (path_startswith(p, "/dev/block/"))
457 continue;
e04aad61 458
5bcb0f2b
LP
459 if (stat(p, &st) >= 0)
460 if (!S_ISBLK(st.st_mode) ||
461 st.st_rdev != udev_device_get_devnum(d))
462 continue;
e04aad61 463
628c89cc 464 swap_setup_unit(m, p, device, prio, set_flags);
e04aad61
LP
465 }
466
e04aad61
LP
467 return r;
468}
469
07b0b134
ML
470static void swap_set_state(Swap *s, SwapState state) {
471 SwapState old_state;
37cf8fee 472 Swap *other;
e04aad61 473
07b0b134
ML
474 assert(s);
475
476 old_state = s->state;
477 s->state = state;
478
e04aad61
LP
479 if (state != SWAP_ACTIVATING &&
480 state != SWAP_ACTIVATING_SIGTERM &&
481 state != SWAP_ACTIVATING_SIGKILL &&
5bcb0f2b 482 state != SWAP_ACTIVATING_DONE &&
e04aad61
LP
483 state != SWAP_DEACTIVATING &&
484 state != SWAP_DEACTIVATING_SIGTERM &&
485 state != SWAP_DEACTIVATING_SIGKILL) {
718db961 486 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
e04aad61
LP
487 swap_unwatch_control_pid(s);
488 s->control_command = NULL;
489 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
490 }
491
07b0b134 492 if (state != old_state)
f2341e0a 493 log_unit_debug(UNIT(s), "Changed %s -> %s", swap_state_to_string(old_state), swap_state_to_string(state));
07b0b134 494
5bcb0f2b 495 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
37cf8fee
LP
496
497 /* If there other units for the same device node have a job
498 queued it might be worth checking again if it is runnable
499 now. This is necessary, since swap_start() refuses
500 operation with EAGAIN if there's already another job for
501 the same device node queued. */
502 LIST_FOREACH_OTHERS(same_devnode, other, s)
503 if (UNIT(other)->job)
504 job_add_to_run_queue(UNIT(other)->job);
07b0b134
ML
505}
506
be847e82 507static int swap_coldplug(Unit *u) {
07b0b134
ML
508 Swap *s = SWAP(u);
509 SwapState new_state = SWAP_DEAD;
e04aad61 510 int r;
07b0b134
ML
511
512 assert(s);
513 assert(s->state == SWAP_DEAD);
514
515 if (s->deserialized_state != s->state)
516 new_state = s->deserialized_state;
4e85aff4 517 else if (s->from_proc_swaps)
07b0b134
ML
518 new_state = SWAP_ACTIVE;
519
5bcb0f2b
LP
520 if (new_state == s->state)
521 return 0;
e04aad61 522
5bcb0f2b
LP
523 if (new_state == SWAP_ACTIVATING ||
524 new_state == SWAP_ACTIVATING_SIGTERM ||
525 new_state == SWAP_ACTIVATING_SIGKILL ||
526 new_state == SWAP_ACTIVATING_DONE ||
527 new_state == SWAP_DEACTIVATING ||
528 new_state == SWAP_DEACTIVATING_SIGTERM ||
529 new_state == SWAP_DEACTIVATING_SIGKILL) {
e04aad61 530
5bcb0f2b
LP
531 if (s->control_pid <= 0)
532 return -EBADMSG;
e04aad61 533
5bcb0f2b
LP
534 r = unit_watch_pid(UNIT(s), s->control_pid);
535 if (r < 0)
536 return r;
e04aad61 537
5bcb0f2b
LP
538 r = swap_arm_timer(s);
539 if (r < 0)
540 return r;
e04aad61 541 }
07b0b134 542
5bcb0f2b 543 swap_set_state(s, new_state);
07b0b134
ML
544 return 0;
545}
546
547static void swap_dump(Unit *u, FILE *f, const char *prefix) {
548 Swap *s = SWAP(u);
4e85aff4 549 SwapParameters *p;
07b0b134
ML
550
551 assert(s);
4e85aff4
LP
552 assert(f);
553
554 if (s->from_proc_swaps)
555 p = &s->parameters_proc_swaps;
556 else if (s->from_fragment)
557 p = &s->parameters_fragment;
b6bfc7bb
LP
558 else
559 p = NULL;
07b0b134
ML
560
561 fprintf(f,
4e85aff4 562 "%sSwap State: %s\n"
e1770af8 563 "%sResult: %s\n"
07b0b134 564 "%sWhat: %s\n"
4e85aff4
LP
565 "%sFrom /proc/swaps: %s\n"
566 "%sFrom fragment: %s\n",
07b0b134 567 prefix, swap_state_to_string(s->state),
e1770af8 568 prefix, swap_result_to_string(s->result),
07b0b134 569 prefix, s->what,
4e85aff4
LP
570 prefix, yes_no(s->from_proc_swaps),
571 prefix, yes_no(s->from_fragment));
e04aad61 572
9670d583
LP
573 if (s->devnode)
574 fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
575
b6bfc7bb
LP
576 if (p)
577 fprintf(f,
578 "%sPriority: %i\n"
47cb901e 579 "%sOptions: %s\n",
b6bfc7bb 580 prefix, p->priority,
47cb901e 581 prefix, strempty(p->options));
b6bfc7bb 582
e04aad61
LP
583 if (s->control_pid > 0)
584 fprintf(f,
de0671ee
ZJS
585 "%sControl PID: "PID_FMT"\n",
586 prefix, s->control_pid);
e04aad61
LP
587
588 exec_context_dump(&s->exec_context, f, prefix);
4819ff03 589 kill_context_dump(&s->kill_context, f, prefix);
e04aad61
LP
590}
591
592static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
593 pid_t pid;
594 int r;
9fa95f85
DM
595 ExecParameters exec_params = {
596 .apply_permissions = true,
597 .apply_chroot = true,
598 .apply_tty_stdin = true,
6f856a09 599 .bus_endpoint_fd = -1,
9fa95f85 600 };
e04aad61
LP
601
602 assert(s);
603 assert(c);
604 assert(_pid);
605
5ad096b3
LP
606 (void) unit_realize_cgroup(UNIT(s));
607 if (s->reset_cpu_usage) {
608 (void) unit_reset_cpu_usage(UNIT(s));
609 s->reset_cpu_usage = false;
610 }
4ad49000 611
613b411c
LP
612 r = unit_setup_exec_runtime(UNIT(s));
613 if (r < 0)
614 goto fail;
615
718db961 616 r = swap_arm_timer(s);
646134dc 617 if (r < 0)
e04aad61
LP
618 goto fail;
619
9fa95f85
DM
620 exec_params.environment = UNIT(s)->manager->environment;
621 exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
622 exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
623 exec_params.cgroup_path = UNIT(s)->cgroup_path;
a931ad47 624 exec_params.cgroup_delegate = s->cgroup_context.delegate;
9fa95f85 625 exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
9fa95f85 626
f2341e0a
LP
627 r = exec_spawn(UNIT(s),
628 c,
646134dc 629 &s->exec_context,
9fa95f85 630 &exec_params,
613b411c 631 s->exec_runtime,
646134dc
ZJS
632 &pid);
633 if (r < 0)
e04aad61
LP
634 goto fail;
635
646134dc
ZJS
636 r = unit_watch_pid(UNIT(s), pid);
637 if (r < 0)
e04aad61
LP
638 /* FIXME: we need to do something here */
639 goto fail;
640
641 *_pid = pid;
642
643 return 0;
644
645fail:
718db961 646 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
e04aad61 647 return r;
07b0b134
ML
648}
649
e1770af8 650static void swap_enter_dead(Swap *s, SwapResult f) {
07b0b134
ML
651 assert(s);
652
e1770af8
LP
653 if (f != SWAP_SUCCESS)
654 s->result = f;
e04aad61 655
613b411c
LP
656 exec_runtime_destroy(s->exec_runtime);
657 s->exec_runtime = exec_runtime_unref(s->exec_runtime);
658
e66cf1a3
LP
659 exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
660
e1770af8 661 swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
07b0b134
ML
662}
663
e1770af8 664static void swap_enter_active(Swap *s, SwapResult f) {
e04aad61
LP
665 assert(s);
666
e1770af8
LP
667 if (f != SWAP_SUCCESS)
668 s->result = f;
e04aad61
LP
669
670 swap_set_state(s, SWAP_ACTIVE);
671}
672
e1770af8 673static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
07b0b134
ML
674 int r;
675
676 assert(s);
e04aad61 677
e1770af8
LP
678 if (f != SWAP_SUCCESS)
679 s->result = f;
e04aad61 680
cd2086fe
LP
681 r = unit_kill_context(
682 UNIT(s),
683 &s->kill_context,
db2cb23b
UTL
684 (state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM) ?
685 KILL_KILL : KILL_TERMINATE,
cd2086fe
LP
686 -1,
687 s->control_pid,
688 false);
689 if (r < 0)
690 goto fail;
e04aad61 691
cd2086fe 692 if (r > 0) {
718db961 693 r = swap_arm_timer(s);
646134dc 694 if (r < 0)
e04aad61
LP
695 goto fail;
696
697 swap_set_state(s, state);
ac84d1fb
LP
698 } else if (state == SWAP_ACTIVATING_SIGTERM)
699 swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_SUCCESS);
700 else if (state == SWAP_DEACTIVATING_SIGTERM)
701 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS);
702 else
e1770af8 703 swap_enter_dead(s, SWAP_SUCCESS);
e04aad61
LP
704
705 return;
706
707fail:
f2341e0a 708 log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
e1770af8 709 swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
710}
711
712static void swap_enter_activating(Swap *s) {
bf1d7ba7
KZ
713 _cleanup_free_ char *opts = NULL;
714 int r;
e04aad61
LP
715
716 assert(s);
717
718 s->control_command_id = SWAP_EXEC_ACTIVATE;
719 s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
07b0b134 720
86b23b07 721 if (s->from_fragment) {
bf1d7ba7 722 int priority = -1;
47cb901e 723
bf1d7ba7
KZ
724 r = fstab_find_pri(s->parameters_fragment.options, &priority);
725 if (r < 0)
726 log_warning_errno(r, "Failed to parse swap priority \"%s\", ignoring: %m", s->parameters_fragment.options);
727 else if (r == 1 && s->parameters_fragment.priority >= 0)
728 log_warning("Duplicate swap priority configuration by Priority and Options fields.");
729
730 if (r <= 0 && s->parameters_fragment.priority >= 0) {
731 if (s->parameters_fragment.options)
732 r = asprintf(&opts, "%s,pri=%i", s->parameters_fragment.options, s->parameters_fragment.priority);
733 else
734 r = asprintf(&opts, "pri=%i", s->parameters_fragment.priority);
e64d5235 735 if (r < 0)
bf1d7ba7 736 goto fail;
e64d5235 737 }
86b23b07
JS
738 }
739
740 r = exec_command_set(s->control_command, "/sbin/swapon", NULL);
741 if (r < 0)
742 goto fail;
4e85aff4 743
bf1d7ba7
KZ
744 if (s->parameters_fragment.options || opts) {
745 r = exec_command_append(s->control_command, "-o",
746 opts ? : s->parameters_fragment.options, NULL);
86b23b07
JS
747 if (r < 0)
748 goto fail;
749 }
e04aad61 750
86b23b07 751 r = exec_command_append(s->control_command, s->what, NULL);
e04aad61
LP
752 if (r < 0)
753 goto fail;
754
755 swap_unwatch_control_pid(s);
756
646134dc
ZJS
757 r = swap_spawn(s, s->control_command, &s->control_pid);
758 if (r < 0)
e04aad61
LP
759 goto fail;
760
761 swap_set_state(s, SWAP_ACTIVATING);
762
763 return;
764
765fail:
f2341e0a 766 log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapon' task: %m");
e1770af8 767 swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
768}
769
e1770af8 770static void swap_enter_deactivating(Swap *s) {
e04aad61
LP
771 int r;
772
773 assert(s);
774
e04aad61
LP
775 s->control_command_id = SWAP_EXEC_DEACTIVATE;
776 s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE;
777
646134dc 778 r = exec_command_set(s->control_command,
e04aad61
LP
779 "/sbin/swapoff",
780 s->what,
646134dc
ZJS
781 NULL);
782 if (r < 0)
e04aad61
LP
783 goto fail;
784
785 swap_unwatch_control_pid(s);
786
646134dc
ZJS
787 r = swap_spawn(s, s->control_command, &s->control_pid);
788 if (r < 0)
e04aad61
LP
789 goto fail;
790
791 swap_set_state(s, SWAP_DEACTIVATING);
792
793 return;
794
795fail:
f2341e0a 796 log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapoff' task: %m");
e1770af8 797 swap_enter_active(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
798}
799
800static int swap_start(Unit *u) {
37cf8fee 801 Swap *s = SWAP(u), *other;
e04aad61
LP
802
803 assert(s);
804
805 /* We cannot fulfill this request right now, try again later
806 * please! */
807
808 if (s->state == SWAP_DEACTIVATING ||
809 s->state == SWAP_DEACTIVATING_SIGTERM ||
810 s->state == SWAP_DEACTIVATING_SIGKILL ||
811 s->state == SWAP_ACTIVATING_SIGTERM ||
812 s->state == SWAP_ACTIVATING_SIGKILL)
813 return -EAGAIN;
814
815 if (s->state == SWAP_ACTIVATING)
816 return 0;
817
818 assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED);
819
75f86906 820 if (detect_container() > 0)
a5c3034f
LP
821 return -EPERM;
822
37cf8fee
LP
823 /* If there's a job for another swap unit for the same node
824 * running, then let's not dispatch this one for now, and wait
825 * until that other job has finished. */
826 LIST_FOREACH_OTHERS(same_devnode, other, s)
827 if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
828 return -EAGAIN;
829
e1770af8 830 s->result = SWAP_SUCCESS;
5ad096b3
LP
831 s->reset_cpu_usage = true;
832
e04aad61 833 swap_enter_activating(s);
82a2b6bb 834 return 1;
07b0b134
ML
835}
836
837static int swap_stop(Unit *u) {
838 Swap *s = SWAP(u);
07b0b134
ML
839
840 assert(s);
841
e04aad61
LP
842 if (s->state == SWAP_DEACTIVATING ||
843 s->state == SWAP_DEACTIVATING_SIGTERM ||
844 s->state == SWAP_DEACTIVATING_SIGKILL ||
845 s->state == SWAP_ACTIVATING_SIGTERM ||
846 s->state == SWAP_ACTIVATING_SIGKILL)
847 return 0;
07b0b134 848
e04aad61 849 assert(s->state == SWAP_ACTIVATING ||
5bcb0f2b 850 s->state == SWAP_ACTIVATING_DONE ||
e04aad61 851 s->state == SWAP_ACTIVE);
07b0b134 852
75f86906 853 if (detect_container() > 0)
a5c3034f
LP
854 return -EPERM;
855
e1770af8 856 swap_enter_deactivating(s);
82a2b6bb 857 return 1;
07b0b134
ML
858}
859
860static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
861 Swap *s = SWAP(u);
862
863 assert(s);
864 assert(f);
865 assert(fds);
866
867 unit_serialize_item(u, f, "state", swap_state_to_string(s->state));
e1770af8 868 unit_serialize_item(u, f, "result", swap_result_to_string(s->result));
e04aad61
LP
869
870 if (s->control_pid > 0)
de0671ee 871 unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
e04aad61
LP
872
873 if (s->control_command_id >= 0)
874 unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id));
07b0b134
ML
875
876 return 0;
877}
878
879static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
880 Swap *s = SWAP(u);
881
882 assert(s);
883 assert(fds);
884
885 if (streq(key, "state")) {
886 SwapState state;
887
646134dc
ZJS
888 state = swap_state_from_string(value);
889 if (state < 0)
f2341e0a 890 log_unit_debug(u, "Failed to parse state value: %s", value);
07b0b134
ML
891 else
892 s->deserialized_state = state;
e1770af8
LP
893 } else if (streq(key, "result")) {
894 SwapResult f;
895
896 f = swap_result_from_string(value);
897 if (f < 0)
f2341e0a 898 log_unit_debug(u, "Failed to parse result value: %s", value);
e1770af8
LP
899 else if (f != SWAP_SUCCESS)
900 s->result = f;
e04aad61
LP
901 } else if (streq(key, "control-pid")) {
902 pid_t pid;
903
904 if (parse_pid(value, &pid) < 0)
f2341e0a 905 log_unit_debug(u, "Failed to parse control-pid value: %s", value);
e04aad61
LP
906 else
907 s->control_pid = pid;
908
909 } else if (streq(key, "control-command")) {
910 SwapExecCommand id;
911
646134dc
ZJS
912 id = swap_exec_command_from_string(value);
913 if (id < 0)
f2341e0a 914 log_unit_debug(u, "Failed to parse exec-command value: %s", value);
e04aad61
LP
915 else {
916 s->control_command_id = id;
917 s->control_command = s->exec_command + id;
918 }
07b0b134 919 } else
f2341e0a 920 log_unit_debug(u, "Unknown serialization key: %s", key);
07b0b134
ML
921
922 return 0;
923}
924
44a6b1b6 925_pure_ static UnitActiveState swap_active_state(Unit *u) {
07b0b134
ML
926 assert(u);
927
928 return state_translation_table[SWAP(u)->state];
929}
930
44a6b1b6 931_pure_ static const char *swap_sub_state_to_string(Unit *u) {
07b0b134
ML
932 assert(u);
933
934 return swap_state_to_string(SWAP(u)->state);
935}
936
44a6b1b6 937_pure_ static bool swap_check_gc(Unit *u) {
07b0b134
ML
938 Swap *s = SWAP(u);
939
940 assert(s);
941
6b1dc2bd 942 return s->from_proc_swaps;
07b0b134
ML
943}
944
e04aad61
LP
945static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
946 Swap *s = SWAP(u);
e1770af8 947 SwapResult f;
e04aad61
LP
948
949 assert(s);
950 assert(pid >= 0);
951
952 if (pid != s->control_pid)
953 return;
954
955 s->control_pid = 0;
956
96342de6 957 if (is_clean_exit(code, status, NULL))
e1770af8
LP
958 f = SWAP_SUCCESS;
959 else if (code == CLD_EXITED)
960 f = SWAP_FAILURE_EXIT_CODE;
961 else if (code == CLD_KILLED)
962 f = SWAP_FAILURE_SIGNAL;
963 else if (code == CLD_DUMPED)
964 f = SWAP_FAILURE_CORE_DUMP;
965 else
966 assert_not_reached("Unknown code");
967
968 if (f != SWAP_SUCCESS)
969 s->result = f;
e04aad61
LP
970
971 if (s->control_command) {
6ea832a2 972 exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
e1770af8 973
e04aad61
LP
974 s->control_command = NULL;
975 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
976 }
977
f2341e0a
LP
978 log_unit_full(u, f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
979 "Swap process exited, code=%s status=%i", sigchld_code_to_string(code), status);
e04aad61
LP
980
981 switch (s->state) {
982
983 case SWAP_ACTIVATING:
5bcb0f2b 984 case SWAP_ACTIVATING_DONE:
e04aad61
LP
985 case SWAP_ACTIVATING_SIGTERM:
986 case SWAP_ACTIVATING_SIGKILL:
987
e1770af8
LP
988 if (f == SWAP_SUCCESS)
989 swap_enter_active(s, f);
e04aad61 990 else
e1770af8 991 swap_enter_dead(s, f);
e04aad61
LP
992 break;
993
994 case SWAP_DEACTIVATING:
995 case SWAP_DEACTIVATING_SIGKILL:
996 case SWAP_DEACTIVATING_SIGTERM:
997
7bb01eff 998 swap_enter_dead(s, f);
e04aad61
LP
999 break;
1000
1001 default:
1002 assert_not_reached("Uh, control process died at wrong time.");
1003 }
1004
1005 /* Notify clients about changed exit status */
1006 unit_add_to_dbus_queue(u);
e04aad61
LP
1007}
1008
718db961
LP
1009static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
1010 Swap *s = SWAP(userdata);
e04aad61
LP
1011
1012 assert(s);
718db961 1013 assert(s->timer_event_source == source);
e04aad61
LP
1014
1015 switch (s->state) {
1016
1017 case SWAP_ACTIVATING:
5bcb0f2b 1018 case SWAP_ACTIVATING_DONE:
f2341e0a 1019 log_unit_warning(UNIT(s), "Activation timed out. Stopping.");
e1770af8 1020 swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1021 break;
1022
1023 case SWAP_DEACTIVATING:
f2341e0a 1024 log_unit_warning(UNIT(s), "Deactivation timed out. Stopping.");
e1770af8 1025 swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1026 break;
1027
1028 case SWAP_ACTIVATING_SIGTERM:
4819ff03 1029 if (s->kill_context.send_sigkill) {
f2341e0a 1030 log_unit_warning(UNIT(s), "Activation timed out. Killing.");
e1770af8 1031 swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
ba035df2 1032 } else {
f2341e0a 1033 log_unit_warning(UNIT(s), "Activation timed out. Skipping SIGKILL. Ignoring.");
e1770af8 1034 swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
ba035df2 1035 }
e04aad61
LP
1036 break;
1037
1038 case SWAP_DEACTIVATING_SIGTERM:
4819ff03 1039 if (s->kill_context.send_sigkill) {
f2341e0a 1040 log_unit_warning(UNIT(s), "Deactivation timed out. Killing.");
e1770af8 1041 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
ba035df2 1042 } else {
f2341e0a 1043 log_unit_warning(UNIT(s), "Deactivation timed out. Skipping SIGKILL. Ignoring.");
e1770af8 1044 swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
ba035df2 1045 }
e04aad61
LP
1046 break;
1047
1048 case SWAP_ACTIVATING_SIGKILL:
1049 case SWAP_DEACTIVATING_SIGKILL:
f2341e0a 1050 log_unit_warning(UNIT(s), "Swap process still around after SIGKILL. Ignoring.");
e1770af8 1051 swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1052 break;
1053
1054 default:
1055 assert_not_reached("Timeout at wrong time.");
1056 }
718db961
LP
1057
1058 return 0;
e04aad61
LP
1059}
1060
1061static int swap_load_proc_swaps(Manager *m, bool set_flags) {
1062 unsigned i;
1063 int r = 0;
1064
1065 assert(m);
1066
07b0b134 1067 rewind(m->proc_swaps);
bab45044 1068
4e85aff4 1069 (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
07b0b134 1070
e04aad61 1071 for (i = 1;; i++) {
9fb3675e 1072 _cleanup_free_ char *dev = NULL, *d = NULL;
07b0b134
ML
1073 int prio = 0, k;
1074
646134dc
ZJS
1075 k = fscanf(m->proc_swaps,
1076 "%ms " /* device/file */
1077 "%*s " /* type of swap */
1078 "%*s " /* swap size */
1079 "%*s " /* used */
1080 "%i\n", /* priority */
1081 &dev, &prio);
1082 if (k != 2) {
07b0b134 1083 if (k == EOF)
4e85aff4 1084 break;
07b0b134 1085
628c89cc 1086 log_warning("Failed to parse /proc/swaps:%u.", i);
e04aad61 1087 continue;
07b0b134 1088 }
07b0b134 1089
527b7a42 1090 if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
628c89cc
LP
1091 return log_oom();
1092
1093 device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
4e85aff4 1094
628c89cc 1095 k = swap_process_new(m, d, prio, set_flags);
07b0b134 1096 if (k < 0)
e04aad61 1097 r = k;
07b0b134
ML
1098 }
1099
e04aad61
LP
1100 return r;
1101}
1102
718db961
LP
1103static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
1104 Manager *m = userdata;
595ed347 1105 Unit *u;
4e434314
LP
1106 int r;
1107
1108 assert(m);
718db961 1109 assert(revents & EPOLLPRI);
4e434314 1110
646134dc
ZJS
1111 r = swap_load_proc_swaps(m, true);
1112 if (r < 0) {
da927ba9 1113 log_error_errno(r, "Failed to reread /proc/swaps: %m");
e04aad61
LP
1114
1115 /* Reset flags, just in case, for late calls */
595ed347
MS
1116 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
1117 Swap *swap = SWAP(u);
e04aad61
LP
1118
1119 swap->is_active = swap->just_activated = false;
1120 }
1121
1122 return 0;
1123 }
1124
1125 manager_dispatch_load_queue(m);
1126
595ed347
MS
1127 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
1128 Swap *swap = SWAP(u);
e04aad61
LP
1129
1130 if (!swap->is_active) {
1131 /* This has just been deactivated */
1132
e04aad61
LP
1133 swap_unset_proc_swaps(swap);
1134
1135 switch (swap->state) {
1136
1137 case SWAP_ACTIVE:
e1770af8 1138 swap_enter_dead(swap, SWAP_SUCCESS);
e04aad61
LP
1139 break;
1140
1141 default:
5bcb0f2b 1142 /* Fire again */
e04aad61
LP
1143 swap_set_state(swap, swap->state);
1144 break;
1145 }
1146
628c89cc
LP
1147 if (swap->what)
1148 device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
1149
e04aad61
LP
1150 } else if (swap->just_activated) {
1151
1152 /* New swap entry */
1153
1154 switch (swap->state) {
1155
1156 case SWAP_DEAD:
1157 case SWAP_FAILED:
e1770af8 1158 swap_enter_active(swap, SWAP_SUCCESS);
e04aad61
LP
1159 break;
1160
5bcb0f2b
LP
1161 case SWAP_ACTIVATING:
1162 swap_set_state(swap, SWAP_ACTIVATING_DONE);
1163 break;
1164
e04aad61
LP
1165 default:
1166 /* Nothing really changed, but let's
1167 * issue an notification call
1168 * nonetheless, in case somebody is
1169 * waiting for this. */
1170 swap_set_state(swap, swap->state);
1171 break;
1172 }
1173 }
1174
1175 /* Reset the flags for later calls */
1176 swap->is_active = swap->just_activated = false;
1177 }
1178
1179 return 1;
1180}
1181
1182static Unit *swap_following(Unit *u) {
1183 Swap *s = SWAP(u);
1184 Swap *other, *first = NULL;
1185
1186 assert(s);
1187
cdc89820
ZJS
1188 /* If the user configured the swap through /etc/fstab or
1189 * a device unit, follow that. */
1190
1191 if (s->from_fragment)
e04aad61
LP
1192 return NULL;
1193
caac2704 1194 LIST_FOREACH_OTHERS(same_devnode, other, s)
cdc89820
ZJS
1195 if (other->from_fragment)
1196 return UNIT(other);
1197
1198 /* Otherwise make everybody follow the unit that's named after
1199 * the swap device in the kernel */
1200
1201 if (streq_ptr(s->what, s->devnode))
1202 return NULL;
e04aad61 1203
9670d583
LP
1204 LIST_FOREACH_AFTER(same_devnode, other, s)
1205 if (streq_ptr(other->what, other->devnode))
e04aad61
LP
1206 return UNIT(other);
1207
9670d583
LP
1208 LIST_FOREACH_BEFORE(same_devnode, other, s) {
1209 if (streq_ptr(other->what, other->devnode))
e04aad61
LP
1210 return UNIT(other);
1211
1212 first = other;
1213 }
1214
cdc89820 1215 /* Fall back to the first on the list */
e04aad61 1216 return UNIT(first);
07b0b134
ML
1217}
1218
6210e7fc 1219static int swap_following_set(Unit *u, Set **_set) {
5bcb0f2b 1220 Swap *s = SWAP(u), *other;
6210e7fc
LP
1221 Set *set;
1222 int r;
1223
1224 assert(s);
1225 assert(_set);
1226
9670d583 1227 if (LIST_JUST_US(same_devnode, s)) {
6210e7fc
LP
1228 *_set = NULL;
1229 return 0;
1230 }
1231
d5099efc 1232 set = set_new(NULL);
5bcb0f2b 1233 if (!set)
6210e7fc
LP
1234 return -ENOMEM;
1235
caac2704 1236 LIST_FOREACH_OTHERS(same_devnode, other, s) {
5bcb0f2b
LP
1237 r = set_put(set, other);
1238 if (r < 0)
6210e7fc 1239 goto fail;
5bcb0f2b 1240 }
6210e7fc
LP
1241
1242 *_set = set;
1243 return 1;
1244
1245fail:
1246 set_free(set);
1247 return r;
1248}
1249
07b0b134
ML
1250static void swap_shutdown(Manager *m) {
1251 assert(m);
1252
718db961
LP
1253 m->swap_event_source = sd_event_source_unref(m->swap_event_source);
1254
07b0b134
ML
1255 if (m->proc_swaps) {
1256 fclose(m->proc_swaps);
1257 m->proc_swaps = NULL;
1258 }
e04aad61 1259
9670d583
LP
1260 hashmap_free(m->swaps_by_devnode);
1261 m->swaps_by_devnode = NULL;
07b0b134
ML
1262}
1263
07b0b134
ML
1264static int swap_enumerate(Manager *m) {
1265 int r;
9670d583 1266
07b0b134
ML
1267 assert(m);
1268
4e434314 1269 if (!m->proc_swaps) {
646134dc
ZJS
1270 m->proc_swaps = fopen("/proc/swaps", "re");
1271 if (!m->proc_swaps)
718db961 1272 return errno == ENOENT ? 0 : -errno;
4e434314 1273
151b9b96 1274 r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
718db961 1275 if (r < 0)
29083707
LP
1276 goto fail;
1277
1278 /* Dispatch this before we dispatch SIGCHLD, so that
1279 * we always get the events from /proc/swaps before
1280 * the SIGCHLD of /sbin/swapon. */
1281 r = sd_event_source_set_priority(m->swap_event_source, -10);
1282 if (r < 0)
718db961 1283 goto fail;
7dfbe2e3
TG
1284
1285 (void) sd_event_source_set_description(m->swap_event_source, "swap-proc");
4e434314
LP
1286 }
1287
646134dc
ZJS
1288 r = swap_load_proc_swaps(m, false);
1289 if (r < 0)
718db961
LP
1290 goto fail;
1291
1292 return 0;
07b0b134 1293
718db961
LP
1294fail:
1295 swap_shutdown(m);
07b0b134
ML
1296 return r;
1297}
1298
628c89cc 1299int swap_process_device_new(Manager *m, struct udev_device *dev) {
9670d583
LP
1300 struct udev_list_entry *item = NULL, *first = NULL;
1301 _cleanup_free_ char *e = NULL;
1302 const char *dn;
1303 Swap *s;
1304 int r = 0;
1305
1306 assert(m);
1307 assert(dev);
1308
1309 dn = udev_device_get_devnode(dev);
1310 if (!dn)
1311 return 0;
1312
7410616c
LP
1313 r = unit_name_from_path(dn, ".swap", &e);
1314 if (r < 0)
1315 return r;
9670d583
LP
1316
1317 s = hashmap_get(m->units, e);
1318 if (s)
1319 r = swap_set_devnode(s, dn);
1320
1321 first = udev_device_get_devlinks_list_entry(dev);
1322 udev_list_entry_foreach(item, first) {
1323 _cleanup_free_ char *n = NULL;
7410616c 1324 int q;
9670d583 1325
7410616c
LP
1326 q = unit_name_from_path(udev_list_entry_get_name(item), ".swap", &n);
1327 if (q < 0)
1328 return q;
9670d583
LP
1329
1330 s = hashmap_get(m->units, n);
1331 if (s) {
9670d583
LP
1332 q = swap_set_devnode(s, dn);
1333 if (q < 0)
1334 r = q;
1335 }
1336 }
1337
1338 return r;
1339}
1340
628c89cc 1341int swap_process_device_remove(Manager *m, struct udev_device *dev) {
9670d583
LP
1342 const char *dn;
1343 int r = 0;
1344 Swap *s;
1345
1346 dn = udev_device_get_devnode(dev);
1347 if (!dn)
1348 return 0;
1349
1350 while ((s = hashmap_get(m->swaps_by_devnode, dn))) {
1351 int q;
1352
1353 q = swap_set_devnode(s, NULL);
1354 if (q < 0)
1355 r = q;
1356 }
1357
1358 return r;
1359}
1360
fdf20a31 1361static void swap_reset_failed(Unit *u) {
5632e374
LP
1362 Swap *s = SWAP(u);
1363
1364 assert(s);
1365
fdf20a31 1366 if (s->state == SWAP_FAILED)
5632e374 1367 swap_set_state(s, SWAP_DEAD);
e04aad61 1368
e1770af8 1369 s->result = SWAP_SUCCESS;
5632e374
LP
1370}
1371
718db961 1372static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
814cc562 1373 return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
8a0867d6
LP
1374}
1375
68db7a3b
ZJS
1376static int swap_get_timeout(Unit *u, uint64_t *timeout) {
1377 Swap *s = SWAP(u);
1378 int r;
1379
1380 if (!s->timer_event_source)
1381 return 0;
1382
1383 r = sd_event_source_get_time(s->timer_event_source, timeout);
1384 if (r < 0)
1385 return r;
1386
1387 return 1;
1388}
1389
1c2e9646 1390static bool swap_supported(void) {
0faacd47
LP
1391 static int supported = -1;
1392
1393 /* If swap support is not available in the kernel, or we are
1394 * running in a container we don't support swap units, and any
1395 * attempts to starting one should fail immediately. */
1396
1397 if (supported < 0)
1398 supported =
1399 access("/proc/swaps", F_OK) >= 0 &&
75f86906 1400 detect_container() <= 0;
0faacd47
LP
1401
1402 return supported;
1403}
1404
5632e374
LP
1405static const char* const swap_state_table[_SWAP_STATE_MAX] = {
1406 [SWAP_DEAD] = "dead",
e04aad61 1407 [SWAP_ACTIVATING] = "activating",
5bcb0f2b 1408 [SWAP_ACTIVATING_DONE] = "activating-done",
5632e374 1409 [SWAP_ACTIVE] = "active",
e04aad61
LP
1410 [SWAP_DEACTIVATING] = "deactivating",
1411 [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
1412 [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
1413 [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
1414 [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
fdf20a31 1415 [SWAP_FAILED] = "failed"
5632e374
LP
1416};
1417
1418DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
1419
e04aad61
LP
1420static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
1421 [SWAP_EXEC_ACTIVATE] = "ExecActivate",
1422 [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
1423};
1424
1425DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
1426
e1770af8
LP
1427static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
1428 [SWAP_SUCCESS] = "success",
1429 [SWAP_FAILURE_RESOURCES] = "resources",
1430 [SWAP_FAILURE_TIMEOUT] = "timeout",
1431 [SWAP_FAILURE_EXIT_CODE] = "exit-code",
1432 [SWAP_FAILURE_SIGNAL] = "signal",
1433 [SWAP_FAILURE_CORE_DUMP] = "core-dump"
1434};
1435
1436DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
1437
07b0b134 1438const UnitVTable swap_vtable = {
7d17cfbc 1439 .object_size = sizeof(Swap),
718db961
LP
1440 .exec_context_offset = offsetof(Swap, exec_context),
1441 .cgroup_context_offset = offsetof(Swap, cgroup_context),
1442 .kill_context_offset = offsetof(Swap, kill_context),
613b411c 1443 .exec_runtime_offset = offsetof(Swap, exec_runtime),
3ef63c31 1444
f975e971
LP
1445 .sections =
1446 "Unit\0"
1447 "Swap\0"
1448 "Install\0",
4ad49000 1449 .private_section = "Swap",
71645aca 1450
e04aad61 1451 .no_alias = true,
07b0b134
ML
1452 .no_instances = true,
1453
4e85aff4 1454 .init = swap_init,
07b0b134 1455 .load = swap_load,
6e620bec 1456 .done = swap_done,
07b0b134
ML
1457
1458 .coldplug = swap_coldplug,
1459
1460 .dump = swap_dump,
1461
1462 .start = swap_start,
1463 .stop = swap_stop,
1464
8a0867d6
LP
1465 .kill = swap_kill,
1466
68db7a3b
ZJS
1467 .get_timeout = swap_get_timeout,
1468
07b0b134
ML
1469 .serialize = swap_serialize,
1470 .deserialize_item = swap_deserialize_item,
1471
1472 .active_state = swap_active_state,
1473 .sub_state_to_string = swap_sub_state_to_string,
1474
1475 .check_gc = swap_check_gc,
1476
e04aad61 1477 .sigchld_event = swap_sigchld_event,
e04aad61
LP
1478
1479 .reset_failed = swap_reset_failed,
1480
718db961 1481 .bus_vtable = bus_swap_vtable,
74c964d3
LP
1482 .bus_set_property = bus_swap_set_property,
1483 .bus_commit_properties = bus_swap_commit_properties,
07b0b134 1484
e04aad61 1485 .following = swap_following,
6210e7fc 1486 .following_set = swap_following_set,
5632e374 1487
6e620bec 1488 .enumerate = swap_enumerate,
c6918296 1489 .shutdown = swap_shutdown,
0faacd47 1490 .supported = swap_supported,
c6918296
MS
1491
1492 .status_message_formats = {
1493 .starting_stopping = {
1494 [0] = "Activating swap %s...",
1495 [1] = "Deactivating swap %s...",
1496 },
1497 .finished_start_job = {
1498 [JOB_DONE] = "Activated swap %s.",
1499 [JOB_FAILED] = "Failed to activate swap %s.",
c6918296
MS
1500 [JOB_TIMEOUT] = "Timed out activating swap %s.",
1501 },
1502 .finished_stop_job = {
1503 [JOB_DONE] = "Deactivated swap %s.",
1504 [JOB_FAILED] = "Failed deactivating swap %s.",
1505 [JOB_TIMEOUT] = "Timed out deactivating swap %s.",
1506 },
1507 },
07b0b134 1508};