]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/swap.c
Merge pull request #20346 from poettering/strlen-unsigned-fix
[thirdparty/systemd.git] / src / core / swap.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
07b0b134
ML
2
3#include <errno.h>
07b0b134
ML
4#include <sys/epoll.h>
5#include <sys/stat.h>
4f5dd394 6#include <unistd.h>
07b0b134 7
4366e598 8#include "sd-device.h"
b4bbcaa9 9
b5efdb8a 10#include "alloc-util.h"
07b0b134 11#include "dbus-swap.h"
6fcbec6f 12#include "dbus-unit.h"
4366e598 13#include "device-util.h"
57b7a260 14#include "device.h"
4f5dd394 15#include "escape.h"
9a57c629 16#include "exit-status.h"
3ffd4af2 17#include "fd-util.h"
f97b34a6 18#include "format-util.h"
4f5dd394 19#include "fstab-util.h"
6bedfcbb 20#include "parse-util.h"
9eb977db 21#include "path-util.h"
7b3e062c 22#include "process-util.h"
d68c645b 23#include "serialize.h"
4f5dd394 24#include "special.h"
8b43440b 25#include "string-table.h"
07630cea 26#include "string-util.h"
3ffd4af2 27#include "swap.h"
4f5dd394
LP
28#include "unit-name.h"
29#include "unit.h"
30#include "virt.h"
07b0b134
ML
31
32static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
33 [SWAP_DEAD] = UNIT_INACTIVE,
e04aad61 34 [SWAP_ACTIVATING] = UNIT_ACTIVATING,
5bcb0f2b 35 [SWAP_ACTIVATING_DONE] = UNIT_ACTIVE,
07b0b134 36 [SWAP_ACTIVE] = UNIT_ACTIVE,
e04aad61 37 [SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
e04aad61
LP
38 [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
39 [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
a8b689b7
YW
40 [SWAP_FAILED] = UNIT_FAILED,
41 [SWAP_CLEANING] = UNIT_MAINTENANCE,
07b0b134
ML
42};
43
718db961
LP
44static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
45static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
bcce581d 46static int swap_process_proc_swaps(Manager *m);
718db961 47
dedf3719
LP
48static bool SWAP_STATE_WITH_PROCESS(SwapState state) {
49 return IN_SET(state,
50 SWAP_ACTIVATING,
51 SWAP_ACTIVATING_DONE,
52 SWAP_DEACTIVATING,
53 SWAP_DEACTIVATING_SIGTERM,
a8b689b7
YW
54 SWAP_DEACTIVATING_SIGKILL,
55 SWAP_CLEANING);
dedf3719
LP
56}
57
39c79477
ZJS
58_pure_ static UnitActiveState swap_active_state(Unit *u) {
59 assert(u);
60
61 return state_translation_table[SWAP(u)->state];
62}
63
64_pure_ static const char *swap_sub_state_to_string(Unit *u) {
65 assert(u);
66
67 return swap_state_to_string(SWAP(u)->state);
68}
69
70_pure_ static bool swap_may_gc(Unit *u) {
71 Swap *s = SWAP(u);
72
73 assert(s);
74
75 if (s->from_proc_swaps)
76 return false;
77
78 return true;
79}
80
81_pure_ static bool swap_is_extrinsic(Unit *u) {
82 assert(SWAP(u));
83
84 return MANAGER_IS_USER(u->manager);
85}
86
e04aad61 87static void swap_unset_proc_swaps(Swap *s) {
9670d583
LP
88 assert(s);
89
90 if (!s->from_proc_swaps)
91 return;
92
a1e58e8e 93 s->parameters_proc_swaps.what = mfree(s->parameters_proc_swaps.what);
9670d583
LP
94 s->from_proc_swaps = false;
95}
96
97static int swap_set_devnode(Swap *s, const char *devnode) {
df326b84 98 Hashmap *swaps;
5bcb0f2b 99 Swap *first;
9670d583 100 int r;
e04aad61
LP
101
102 assert(s);
103
548f6937 104 r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, &path_hash_ops);
9670d583
LP
105 if (r < 0)
106 return r;
e04aad61 107
9670d583 108 swaps = UNIT(s)->manager->swaps_by_devnode;
e04aad61 109
9670d583
LP
110 if (s->devnode) {
111 first = hashmap_get(swaps, s->devnode);
e04aad61 112
9670d583
LP
113 LIST_REMOVE(same_devnode, first, s);
114 if (first)
115 hashmap_replace(swaps, first->devnode, first);
116 else
117 hashmap_remove(swaps, s->devnode);
5bcb0f2b 118
a1e58e8e 119 s->devnode = mfree(s->devnode);
9670d583
LP
120 }
121
122 if (devnode) {
123 s->devnode = strdup(devnode);
124 if (!s->devnode)
125 return -ENOMEM;
126
127 first = hashmap_get(swaps, s->devnode);
128 LIST_PREPEND(same_devnode, first, s);
129
130 return hashmap_replace(swaps, first->devnode, first);
131 }
132
133 return 0;
e04aad61
LP
134}
135
f6cebb3b 136static void swap_init(Unit *u) {
6e620bec
LP
137 Swap *s = SWAP(u);
138
139 assert(s);
1124fe6f 140 assert(UNIT(s)->load_state == UNIT_STUB);
6e620bec 141
1f19a534 142 s->timeout_usec = u->manager->default_timeout_start_usec;
e04aad61 143
ac155bb8
MS
144 s->exec_context.std_output = u->manager->default_std_output;
145 s->exec_context.std_error = u->manager->default_std_error;
085afe36 146
e1770af8 147 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
c8f4d764 148
5bcb0f2b 149 u->ignore_on_isolate = true;
e04aad61
LP
150}
151
152static void swap_unwatch_control_pid(Swap *s) {
153 assert(s);
154
155 if (s->control_pid <= 0)
156 return;
157
158 unit_unwatch_pid(UNIT(s), s->control_pid);
159 s->control_pid = 0;
6e620bec
LP
160}
161
4e85aff4
LP
162static void swap_done(Unit *u) {
163 Swap *s = SWAP(u);
07b0b134 164
4e85aff4 165 assert(s);
07b0b134 166
e04aad61 167 swap_unset_proc_swaps(s);
9670d583 168 swap_set_devnode(s, NULL);
e04aad61 169
a1e58e8e
LP
170 s->what = mfree(s->what);
171 s->parameters_fragment.what = mfree(s->parameters_fragment.what);
172 s->parameters_fragment.options = mfree(s->parameters_fragment.options);
86b23b07 173
e8a565cb 174 s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
e04aad61
LP
175 exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
176 s->control_command = NULL;
177
29206d46
LP
178 dynamic_creds_unref(&s->dynamic_creds);
179
e04aad61
LP
180 swap_unwatch_control_pid(s);
181
5dcadb4c 182 s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
718db961
LP
183}
184
36c16a7c 185static int swap_arm_timer(Swap *s, usec_t usec) {
718db961
LP
186 int r;
187
188 assert(s);
189
718db961 190 if (s->timer_event_source) {
36c16a7c 191 r = sd_event_source_set_time(s->timer_event_source, usec);
718db961
LP
192 if (r < 0)
193 return r;
194
195 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
196 }
197
36c16a7c
LP
198 if (usec == USEC_INFINITY)
199 return 0;
200
7dfbe2e3 201 r = sd_event_add_time(
6a0f1f6d
LP
202 UNIT(s)->manager->event,
203 &s->timer_event_source,
204 CLOCK_MONOTONIC,
36c16a7c 205 usec, 0,
6a0f1f6d 206 swap_dispatch_timer, s);
7dfbe2e3
TG
207 if (r < 0)
208 return r;
209
210 (void) sd_event_source_set_description(s->timer_event_source, "swap-timer");
211
212 return 0;
07b0b134
ML
213}
214
61f9cf4e
LP
215static SwapParameters* swap_get_parameters(Swap *s) {
216 assert(s);
217
218 if (s->from_proc_swaps)
219 return &s->parameters_proc_swaps;
220
221 if (s->from_fragment)
222 return &s->parameters_fragment;
223
224 return NULL;
225}
226
eef85c4a 227static int swap_add_device_dependencies(Swap *s) {
61f9cf4e
LP
228 UnitDependencyMask mask;
229 SwapParameters *p;
44b0d1fd 230 int r;
61f9cf4e 231
173a8d04
LP
232 assert(s);
233
234 if (!s->what)
235 return 0;
236
61f9cf4e 237 p = swap_get_parameters(s);
d4a3494e 238 if (!p || !p->what)
f10af76d
LP
239 return 0;
240
61f9cf4e
LP
241 mask = s->from_proc_swaps ? UNIT_DEPENDENCY_PROC_SWAP : UNIT_DEPENDENCY_FILE;
242
44b0d1fd
LP
243 if (is_device_path(p->what)) {
244 r = unit_add_node_dependency(UNIT(s), p->what, UNIT_REQUIRES, mask);
245 if (r < 0)
246 return r;
247
248 return unit_add_blockdev_dependency(UNIT(s), p->what, mask);
249 }
9b88bb50 250
61f9cf4e
LP
251 /* File based swap devices need to be ordered after systemd-remount-fs.service, since they might need
252 * a writable file system. */
253 return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, true, mask);
173a8d04
LP
254}
255
2edd4434 256static int swap_add_default_dependencies(Swap *s) {
8bf23dc7
FB
257 int r;
258
2edd4434
LP
259 assert(s);
260
4c9ea260
LP
261 if (!UNIT(s)->default_dependencies)
262 return 0;
263
463d0d15 264 if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
6b1dc2bd 265 return 0;
2edd4434 266
75f86906 267 if (detect_container() > 0)
c0387ebf
LP
268 return 0;
269
8bf23dc7
FB
270 /* swap units generated for the swap dev links are missing the
271 * ordering dep against the swap target. */
35d8c19a 272 r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
8bf23dc7
FB
273 if (r < 0)
274 return r;
275
5a724170 276 return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
2edd4434
LP
277}
278
4e85aff4 279static int swap_verify(Swap *s) {
7fd1b19b 280 _cleanup_free_ char *e = NULL;
7410616c 281 int r;
4e85aff4 282
75193d41 283 assert(UNIT(s)->load_state == UNIT_LOADED);
4e85aff4 284
7410616c
LP
285 r = unit_name_from_path(s->what, ".swap", &e);
286 if (r < 0)
f2341e0a 287 return log_unit_error_errno(UNIT(s), r, "Failed to generate unit name from path: %m");
4e85aff4 288
d85ff944
YW
289 if (!unit_has_name(UNIT(s), e))
290 return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Value of What= and unit name do not match, not loading.");
4e85aff4 291
d85ff944
YW
292 if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP)
293 return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.");
e04aad61 294
4e85aff4
LP
295 return 0;
296}
297
9670d583 298static int swap_load_devnode(Swap *s) {
4366e598 299 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
9670d583
LP
300 struct stat st;
301 const char *p;
e5ca27b7 302 int r;
9670d583
LP
303
304 assert(s);
305
306 if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode))
307 return 0;
308
a1130022 309 r = sd_device_new_from_stat_rdev(&d, &st);
e5ca27b7 310 if (r < 0) {
8ed6f81b
YW
311 log_unit_full_errno(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
312 "Failed to allocate device for swap %s: %m", s->what);
9670d583 313 return 0;
e5ca27b7 314 }
9670d583 315
4366e598 316 if (sd_device_get_devname(d, &p) < 0)
9670d583
LP
317 return 0;
318
319 return swap_set_devnode(s, p);
320}
321
15332d73 322static int swap_add_extras(Swap *s) {
07b0b134 323 int r;
07b0b134
ML
324
325 assert(s);
07b0b134 326
15332d73
LP
327 if (UNIT(s)->fragment_path)
328 s->from_fragment = true;
07b0b134 329
15332d73
LP
330 if (!s->what) {
331 if (s->parameters_fragment.what)
332 s->what = strdup(s->parameters_fragment.what);
333 else if (s->parameters_proc_swaps.what)
334 s->what = strdup(s->parameters_proc_swaps.what);
335 else {
336 r = unit_name_to_path(UNIT(s)->id, &s->what);
5bcb0f2b 337 if (r < 0)
4e85aff4 338 return r;
5bcb0f2b 339 }
4e85aff4 340
15332d73
LP
341 if (!s->what)
342 return -ENOMEM;
343 }
07b0b134 344
4ff361cc 345 path_simplify(s->what);
07b0b134 346
15332d73
LP
347 if (!UNIT(s)->description) {
348 r = unit_set_description(UNIT(s), s->what);
9670d583
LP
349 if (r < 0)
350 return r;
15332d73 351 }
9670d583 352
15332d73
LP
353 r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
354 if (r < 0)
355 return r;
598459ce 356
15332d73
LP
357 r = swap_add_device_dependencies(s);
358 if (r < 0)
359 return r;
598459ce 360
15332d73
LP
361 r = swap_load_devnode(s);
362 if (r < 0)
363 return r;
a016b922 364
15332d73
LP
365 r = unit_patch_contexts(UNIT(s));
366 if (r < 0)
367 return r;
368
369 r = unit_add_exec_dependencies(UNIT(s), &s->exec_context);
370 if (r < 0)
371 return r;
372
373 r = unit_set_default_slice(UNIT(s));
374 if (r < 0)
375 return r;
376
377 r = swap_add_default_dependencies(s);
378 if (r < 0)
379 return r;
380
381 return 0;
382}
383
384static int swap_load(Unit *u) {
385 Swap *s = SWAP(u);
75193d41 386 int r, q = 0;
15332d73
LP
387
388 assert(s);
389 assert(u->load_state == UNIT_STUB);
390
391 /* Load a .swap file */
c3620770
ZJS
392 bool fragment_optional = s->from_proc_swaps;
393 r = unit_load_fragment_and_dropin(u, !fragment_optional);
15332d73 394
75193d41
ZJS
395 /* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is
396 * already active. */
06721f39
LP
397 if (u->load_state == UNIT_LOADED || s->from_proc_swaps)
398 q = swap_add_extras(s);
15332d73 399
06721f39
LP
400 if (r < 0)
401 return r;
402 if (q < 0)
403 return q;
75193d41
ZJS
404 if (u->load_state != UNIT_LOADED)
405 return 0;
07b0b134
ML
406
407 return swap_verify(s);
408}
409
628c89cc 410static int swap_setup_unit(
4e85aff4
LP
411 Manager *m,
412 const char *what,
e04aad61 413 const char *what_proc_swaps,
4e85aff4 414 int priority,
e04aad61
LP
415 bool set_flags) {
416
7fd1b19b 417 _cleanup_free_ char *e = NULL;
2c7c6144 418 bool delete = false;
5bcb0f2b 419 Unit *u = NULL;
07b0b134 420 int r;
4e85aff4
LP
421 SwapParameters *p;
422
423 assert(m);
424 assert(what);
6b1dc2bd 425 assert(what_proc_swaps);
07b0b134 426
7410616c
LP
427 r = unit_name_from_path(what, ".swap", &e);
428 if (r < 0)
f2341e0a 429 return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
07b0b134 430
e04aad61 431 u = manager_get_unit(m, e);
6b1dc2bd 432 if (u &&
e04aad61 433 SWAP(u)->from_proc_swaps &&
baaa35ad
ZJS
434 !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
435 return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
436 "Swap %s appeared twice with different device paths %s and %s",
437 e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
4e85aff4
LP
438
439 if (!u) {
07b0b134
ML
440 delete = true;
441
a581e45a 442 r = unit_new_for_name(m, sizeof(Swap), e, &u);
7d17cfbc 443 if (r < 0)
e04aad61
LP
444 goto fail;
445
7d17cfbc
MS
446 SWAP(u)->what = strdup(what);
447 if (!SWAP(u)->what) {
628c89cc 448 r = -ENOMEM;
e04aad61
LP
449 goto fail;
450 }
451
452 unit_add_to_load_queue(u);
4e85aff4
LP
453 } else
454 delete = false;
07b0b134 455
6b1dc2bd 456 p = &SWAP(u)->parameters_proc_swaps;
07b0b134 457
6b1dc2bd 458 if (!p->what) {
5bcb0f2b
LP
459 p->what = strdup(what_proc_swaps);
460 if (!p->what) {
461 r = -ENOMEM;
6b1dc2bd
LP
462 goto fail;
463 }
6b1dc2bd 464 }
e04aad61 465
46f94480
LP
466 /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be
467 * loaded. After all we can load it now, from the data in /proc/swaps. */
468 if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
469 u->load_state = UNIT_LOADED;
470 u->load_error = 0;
471 }
472
6b1dc2bd
LP
473 if (set_flags) {
474 SWAP(u)->is_active = true;
475 SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
4e85aff4 476 }
07b0b134 477
6b1dc2bd
LP
478 SWAP(u)->from_proc_swaps = true;
479
4e85aff4 480 p->priority = priority;
7477451b 481 p->priority_set = true;
07b0b134 482
4e85aff4 483 unit_add_to_dbus_queue(u);
07b0b134
ML
484 return 0;
485
486fail:
f2341e0a 487 log_unit_warning_errno(u, r, "Failed to load swap unit: %m");
e04aad61 488
c9d5c9c0 489 if (delete)
07b0b134
ML
490 unit_free(u);
491
4e85aff4 492 return r;
07b0b134
ML
493}
494
6aeb8c89 495static void swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
4366e598
YW
496 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
497 const char *dn, *devlink;
498 struct stat st, st_link;
5bcb0f2b 499 int r;
e04aad61
LP
500
501 assert(m);
502
6aeb8c89
LP
503 if (swap_setup_unit(m, device, device, prio, set_flags) < 0)
504 return;
e04aad61 505
5bcb0f2b
LP
506 /* If this is a block device, then let's add duplicates for
507 * all other names of this block device */
508 if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
6aeb8c89 509 return;
e04aad61 510
a1130022 511 r = sd_device_new_from_stat_rdev(&d, &st);
6aeb8c89
LP
512 if (r < 0)
513 return (void) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
514 "Failed to allocate device for swap %s: %m", device);
e04aad61 515
5bcb0f2b 516 /* Add the main device node */
4366e598 517 if (sd_device_get_devname(d, &dn) >= 0 && !streq(dn, device))
6aeb8c89 518 (void) swap_setup_unit(m, dn, device, prio, set_flags);
e04aad61 519
5bcb0f2b 520 /* Add additional units for all symlinks */
4366e598 521 FOREACH_DEVICE_DEVLINK(d, devlink) {
e04aad61 522
5bcb0f2b 523 /* Don't bother with the /dev/block links */
4366e598 524 if (streq(devlink, device))
5bcb0f2b 525 continue;
e04aad61 526
4366e598 527 if (path_startswith(devlink, "/dev/block/"))
5bcb0f2b 528 continue;
e04aad61 529
4366e598
YW
530 if (stat(devlink, &st_link) >= 0 &&
531 (!S_ISBLK(st_link.st_mode) ||
532 st_link.st_rdev != st.st_rdev))
533 continue;
e04aad61 534
6aeb8c89 535 (void) swap_setup_unit(m, devlink, device, prio, set_flags);
e04aad61 536 }
e04aad61
LP
537}
538
07b0b134
ML
539static void swap_set_state(Swap *s, SwapState state) {
540 SwapState old_state;
37cf8fee 541 Swap *other;
e04aad61 542
07b0b134
ML
543 assert(s);
544
6fcbec6f
LP
545 if (s->state != state)
546 bus_unit_send_pending_change_signal(UNIT(s), false);
547
07b0b134
ML
548 old_state = s->state;
549 s->state = state;
550
dedf3719 551 if (!SWAP_STATE_WITH_PROCESS(state)) {
5dcadb4c 552 s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
e04aad61
LP
553 swap_unwatch_control_pid(s);
554 s->control_command = NULL;
555 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
556 }
557
07b0b134 558 if (state != old_state)
f2341e0a 559 log_unit_debug(UNIT(s), "Changed %s -> %s", swap_state_to_string(old_state), swap_state_to_string(state));
07b0b134 560
2ad2e41a 561 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
37cf8fee
LP
562
563 /* If there other units for the same device node have a job
564 queued it might be worth checking again if it is runnable
565 now. This is necessary, since swap_start() refuses
566 operation with EAGAIN if there's already another job for
567 the same device node queued. */
568 LIST_FOREACH_OTHERS(same_devnode, other, s)
569 if (UNIT(other)->job)
570 job_add_to_run_queue(UNIT(other)->job);
07b0b134
ML
571}
572
be847e82 573static int swap_coldplug(Unit *u) {
07b0b134
ML
574 Swap *s = SWAP(u);
575 SwapState new_state = SWAP_DEAD;
e04aad61 576 int r;
07b0b134
ML
577
578 assert(s);
579 assert(s->state == SWAP_DEAD);
580
581 if (s->deserialized_state != s->state)
582 new_state = s->deserialized_state;
4e85aff4 583 else if (s->from_proc_swaps)
07b0b134
ML
584 new_state = SWAP_ACTIVE;
585
5bcb0f2b
LP
586 if (new_state == s->state)
587 return 0;
e04aad61 588
c386f588
LP
589 if (s->control_pid > 0 &&
590 pid_is_unwaited(s->control_pid) &&
dedf3719 591 SWAP_STATE_WITH_PROCESS(new_state)) {
e04aad61 592
f75f613d 593 r = unit_watch_pid(UNIT(s), s->control_pid, false);
5bcb0f2b
LP
594 if (r < 0)
595 return r;
e04aad61 596
36c16a7c 597 r = swap_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
5bcb0f2b
LP
598 if (r < 0)
599 return r;
e04aad61 600 }
07b0b134 601
e8a565cb 602 if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED)) {
29206d46 603 (void) unit_setup_dynamic_creds(u);
e8a565cb
YW
604 (void) unit_setup_exec_runtime(u);
605 }
29206d46 606
5bcb0f2b 607 swap_set_state(s, new_state);
07b0b134
ML
608 return 0;
609}
610
611static void swap_dump(Unit *u, FILE *f, const char *prefix) {
612 Swap *s = SWAP(u);
4e85aff4 613 SwapParameters *p;
07b0b134
ML
614
615 assert(s);
4e85aff4
LP
616 assert(f);
617
618 if (s->from_proc_swaps)
619 p = &s->parameters_proc_swaps;
620 else if (s->from_fragment)
621 p = &s->parameters_fragment;
b6bfc7bb
LP
622 else
623 p = NULL;
07b0b134
ML
624
625 fprintf(f,
4e85aff4 626 "%sSwap State: %s\n"
e1770af8 627 "%sResult: %s\n"
a8b689b7 628 "%sClean Result: %s\n"
07b0b134 629 "%sWhat: %s\n"
4e85aff4 630 "%sFrom /proc/swaps: %s\n"
39c79477
ZJS
631 "%sFrom fragment: %s\n"
632 "%sExtrinsic: %s\n",
07b0b134 633 prefix, swap_state_to_string(s->state),
e1770af8 634 prefix, swap_result_to_string(s->result),
a8b689b7 635 prefix, swap_result_to_string(s->clean_result),
07b0b134 636 prefix, s->what,
4e85aff4 637 prefix, yes_no(s->from_proc_swaps),
39c79477
ZJS
638 prefix, yes_no(s->from_fragment),
639 prefix, yes_no(swap_is_extrinsic(u)));
e04aad61 640
9670d583
LP
641 if (s->devnode)
642 fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
643
b6bfc7bb
LP
644 if (p)
645 fprintf(f,
646 "%sPriority: %i\n"
47cb901e 647 "%sOptions: %s\n",
b6bfc7bb 648 prefix, p->priority,
47cb901e 649 prefix, strempty(p->options));
b6bfc7bb 650
9bd0e1b8
YW
651 fprintf(f,
652 "%sTimeoutSec: %s\n",
5291f26d 653 prefix, FORMAT_TIMESPAN(s->timeout_usec, USEC_PER_SEC));
9bd0e1b8 654
e04aad61
LP
655 if (s->control_pid > 0)
656 fprintf(f,
de0671ee
ZJS
657 "%sControl PID: "PID_FMT"\n",
658 prefix, s->control_pid);
e04aad61
LP
659
660 exec_context_dump(&s->exec_context, f, prefix);
4819ff03 661 kill_context_dump(&s->kill_context, f, prefix);
bc0623df 662 cgroup_context_dump(UNIT(s), f, prefix);
e04aad61
LP
663}
664
665static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
3c7416b6 666
b9c04eaf 667 _cleanup_(exec_params_clear) ExecParameters exec_params = {
1703fa41 668 .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
c39f1ce2
LP
669 .stdin_fd = -1,
670 .stdout_fd = -1,
671 .stderr_fd = -1,
5686391b 672 .exec_fd = -1,
9fa95f85 673 };
3c7416b6
LP
674 pid_t pid;
675 int r;
e04aad61
LP
676
677 assert(s);
678 assert(c);
679 assert(_pid);
680
3c7416b6 681 r = unit_prepare_exec(UNIT(s));
29206d46 682 if (r < 0)
3c7416b6 683 return r;
29206d46 684
36c16a7c 685 r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
646134dc 686 if (r < 0)
e04aad61
LP
687 goto fail;
688
1ad6e8b3
LP
689 r = unit_set_exec_params(UNIT(s), &exec_params);
690 if (r < 0)
691 goto fail;
9fa95f85 692
f2341e0a
LP
693 r = exec_spawn(UNIT(s),
694 c,
646134dc 695 &s->exec_context,
9fa95f85 696 &exec_params,
613b411c 697 s->exec_runtime,
29206d46 698 &s->dynamic_creds,
646134dc
ZJS
699 &pid);
700 if (r < 0)
e04aad61
LP
701 goto fail;
702
f75f613d 703 r = unit_watch_pid(UNIT(s), pid, true);
646134dc 704 if (r < 0)
e04aad61
LP
705 goto fail;
706
707 *_pid = pid;
708
709 return 0;
710
711fail:
5dcadb4c 712 s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
3536f49e 713
e04aad61 714 return r;
07b0b134
ML
715}
716
e1770af8 717static void swap_enter_dead(Swap *s, SwapResult f) {
07b0b134
ML
718 assert(s);
719
a0fef983 720 if (s->result == SWAP_SUCCESS)
e1770af8 721 s->result = f;
e04aad61 722
aac99f30 723 unit_log_result(UNIT(s), s->result == SWAP_SUCCESS, swap_result_to_string(s->result));
4c425434 724 unit_warn_leftover_processes(UNIT(s), unit_log_leftover_process_stop);
29206d46
LP
725 swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
726
e8a565cb 727 s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
613b411c 728
bb0c0d6f 729 unit_destroy_runtime_data(UNIT(s), &s->exec_context);
e66cf1a3 730
00d9ef85
LP
731 unit_unref_uid_gid(UNIT(s), true);
732
29206d46 733 dynamic_creds_destroy(&s->dynamic_creds);
07b0b134
ML
734}
735
e1770af8 736static void swap_enter_active(Swap *s, SwapResult f) {
e04aad61
LP
737 assert(s);
738
a0fef983 739 if (s->result == SWAP_SUCCESS)
e1770af8 740 s->result = f;
e04aad61
LP
741
742 swap_set_state(s, SWAP_ACTIVE);
743}
744
50864457
LP
745static void swap_enter_dead_or_active(Swap *s, SwapResult f) {
746 assert(s);
747
9c1f969d
HD
748 if (s->from_proc_swaps) {
749 Swap *other;
750
50864457 751 swap_enter_active(s, f);
9c1f969d
HD
752
753 LIST_FOREACH_OTHERS(same_devnode, other, s)
754 if (UNIT(other)->job)
755 swap_enter_dead_or_active(other, f);
756 } else
50864457
LP
757 swap_enter_dead(s, f);
758}
759
a232ebcc
ZJS
760static int state_to_kill_operation(Swap *s, SwapState state) {
761 if (state == SWAP_DEACTIVATING_SIGTERM) {
762 if (unit_has_job_type(UNIT(s), JOB_RESTART))
763 return KILL_RESTART;
764 else
765 return KILL_TERMINATE;
766 }
767
768 return KILL_KILL;
769}
770
e1770af8 771static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
07b0b134
ML
772 int r;
773
774 assert(s);
e04aad61 775
a0fef983 776 if (s->result == SWAP_SUCCESS)
e1770af8 777 s->result = f;
e04aad61 778
a232ebcc
ZJS
779 r = unit_kill_context(UNIT(s),
780 &s->kill_context,
781 state_to_kill_operation(s, state),
782 -1,
783 s->control_pid,
784 false);
cd2086fe
LP
785 if (r < 0)
786 goto fail;
e04aad61 787
cd2086fe 788 if (r > 0) {
36c16a7c 789 r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
646134dc 790 if (r < 0)
e04aad61
LP
791 goto fail;
792
793 swap_set_state(s, state);
50864457 794 } else if (state == SWAP_DEACTIVATING_SIGTERM && s->kill_context.send_sigkill)
ac84d1fb
LP
795 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS);
796 else
50864457 797 swap_enter_dead_or_active(s, SWAP_SUCCESS);
e04aad61
LP
798
799 return;
800
801fail:
f2341e0a 802 log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
50864457 803 swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
804}
805
806static void swap_enter_activating(Swap *s) {
bf1d7ba7
KZ
807 _cleanup_free_ char *opts = NULL;
808 int r;
e04aad61
LP
809
810 assert(s);
811
4c425434 812 unit_warn_leftover_processes(UNIT(s), unit_log_leftover_process_start);
a4634b21 813
e04aad61
LP
814 s->control_command_id = SWAP_EXEC_ACTIVATE;
815 s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
07b0b134 816
86b23b07 817 if (s->from_fragment) {
7477451b 818 int priority = 0;
47cb901e 819
bf1d7ba7
KZ
820 r = fstab_find_pri(s->parameters_fragment.options, &priority);
821 if (r < 0)
af4454cb
LP
822 log_unit_warning_errno(UNIT(s), r, "Failed to parse swap priority \"%s\", ignoring: %m", s->parameters_fragment.options);
823 else if (r > 0 && s->parameters_fragment.priority_set)
824 log_unit_warning(UNIT(s), "Duplicate swap priority configuration by Priority= and Options= fields.");
bf1d7ba7 825
7477451b 826 if (r <= 0 && s->parameters_fragment.priority_set) {
bf1d7ba7
KZ
827 if (s->parameters_fragment.options)
828 r = asprintf(&opts, "%s,pri=%i", s->parameters_fragment.options, s->parameters_fragment.priority);
829 else
830 r = asprintf(&opts, "pri=%i", s->parameters_fragment.priority);
6fca66a7
LP
831 if (r < 0) {
832 r = -ENOMEM;
bf1d7ba7 833 goto fail;
6fca66a7 834 }
e64d5235 835 }
86b23b07
JS
836 }
837
838 r = exec_command_set(s->control_command, "/sbin/swapon", NULL);
839 if (r < 0)
840 goto fail;
4e85aff4 841
bf1d7ba7
KZ
842 if (s->parameters_fragment.options || opts) {
843 r = exec_command_append(s->control_command, "-o",
af4454cb 844 opts ?: s->parameters_fragment.options, NULL);
86b23b07
JS
845 if (r < 0)
846 goto fail;
847 }
e04aad61 848
86b23b07 849 r = exec_command_append(s->control_command, s->what, NULL);
e04aad61
LP
850 if (r < 0)
851 goto fail;
852
853 swap_unwatch_control_pid(s);
854
646134dc
ZJS
855 r = swap_spawn(s, s->control_command, &s->control_pid);
856 if (r < 0)
e04aad61
LP
857 goto fail;
858
859 swap_set_state(s, SWAP_ACTIVATING);
e04aad61
LP
860 return;
861
862fail:
f2341e0a 863 log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapon' task: %m");
50864457 864 swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
865}
866
e1770af8 867static void swap_enter_deactivating(Swap *s) {
e04aad61
LP
868 int r;
869
870 assert(s);
871
e04aad61
LP
872 s->control_command_id = SWAP_EXEC_DEACTIVATE;
873 s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE;
874
646134dc 875 r = exec_command_set(s->control_command,
e04aad61
LP
876 "/sbin/swapoff",
877 s->what,
646134dc
ZJS
878 NULL);
879 if (r < 0)
e04aad61
LP
880 goto fail;
881
882 swap_unwatch_control_pid(s);
883
646134dc
ZJS
884 r = swap_spawn(s, s->control_command, &s->control_pid);
885 if (r < 0)
e04aad61
LP
886 goto fail;
887
888 swap_set_state(s, SWAP_DEACTIVATING);
889
890 return;
891
892fail:
f2341e0a 893 log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapoff' task: %m");
50864457 894 swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
895}
896
31135818
LP
897static void swap_cycle_clear(Swap *s) {
898 assert(s);
899
900 s->result = SWAP_SUCCESS;
901 exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
902 UNIT(s)->reset_accounting = true;
903}
904
e04aad61 905static int swap_start(Unit *u) {
37cf8fee 906 Swap *s = SWAP(u), *other;
07299350 907 int r;
e04aad61
LP
908
909 assert(s);
910
50864457 911 /* We cannot fulfill this request right now, try again later please! */
d31ae548
FB
912 if (IN_SET(s->state,
913 SWAP_DEACTIVATING,
914 SWAP_DEACTIVATING_SIGTERM,
a8b689b7
YW
915 SWAP_DEACTIVATING_SIGKILL,
916 SWAP_CLEANING))
e04aad61
LP
917 return -EAGAIN;
918
50864457 919 /* Already on it! */
e04aad61
LP
920 if (s->state == SWAP_ACTIVATING)
921 return 0;
922
d31ae548 923 assert(IN_SET(s->state, SWAP_DEAD, SWAP_FAILED));
e04aad61 924
75f86906 925 if (detect_container() > 0)
a5c3034f
LP
926 return -EPERM;
927
37cf8fee
LP
928 /* If there's a job for another swap unit for the same node
929 * running, then let's not dispatch this one for now, and wait
930 * until that other job has finished. */
931 LIST_FOREACH_OTHERS(same_devnode, other, s)
932 if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
933 return -EAGAIN;
934
97a3f4ee 935 r = unit_test_start_limit(u);
07299350
LP
936 if (r < 0) {
937 swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
938 return r;
939 }
940
4b58153d
LP
941 r = unit_acquire_invocation_id(u);
942 if (r < 0)
943 return r;
944
31135818 945 swap_cycle_clear(s);
e04aad61 946 swap_enter_activating(s);
82a2b6bb 947 return 1;
07b0b134
ML
948}
949
950static int swap_stop(Unit *u) {
951 Swap *s = SWAP(u);
07b0b134
ML
952
953 assert(s);
954
50864457
LP
955 switch (s->state) {
956
957 case SWAP_DEACTIVATING:
958 case SWAP_DEACTIVATING_SIGTERM:
959 case SWAP_DEACTIVATING_SIGKILL:
960 /* Already on it */
e04aad61 961 return 0;
07b0b134 962
50864457
LP
963 case SWAP_ACTIVATING:
964 case SWAP_ACTIVATING_DONE:
965 /* There's a control process pending, directly enter kill mode */
966 swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_SUCCESS);
967 return 0;
07b0b134 968
50864457
LP
969 case SWAP_ACTIVE:
970 if (detect_container() > 0)
971 return -EPERM;
a5c3034f 972
50864457
LP
973 swap_enter_deactivating(s);
974 return 1;
975
a8b689b7
YW
976 case SWAP_CLEANING:
977 /* If we are currently cleaning, then abort it, brutally. */
978 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS);
979 return 0;
980
50864457
LP
981 default:
982 assert_not_reached("Unexpected state.");
983 }
07b0b134
ML
984}
985
986static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
987 Swap *s = SWAP(u);
988
989 assert(s);
990 assert(f);
991 assert(fds);
992
d68c645b
LP
993 (void) serialize_item(f, "state", swap_state_to_string(s->state));
994 (void) serialize_item(f, "result", swap_result_to_string(s->result));
e04aad61
LP
995
996 if (s->control_pid > 0)
d68c645b 997 (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid);
e04aad61
LP
998
999 if (s->control_command_id >= 0)
d68c645b 1000 (void) serialize_item(f, "control-command", swap_exec_command_to_string(s->control_command_id));
07b0b134
ML
1001
1002 return 0;
1003}
1004
1005static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
1006 Swap *s = SWAP(u);
1007
1008 assert(s);
1009 assert(fds);
1010
1011 if (streq(key, "state")) {
1012 SwapState state;
1013
646134dc
ZJS
1014 state = swap_state_from_string(value);
1015 if (state < 0)
f2341e0a 1016 log_unit_debug(u, "Failed to parse state value: %s", value);
07b0b134
ML
1017 else
1018 s->deserialized_state = state;
e1770af8
LP
1019 } else if (streq(key, "result")) {
1020 SwapResult f;
1021
1022 f = swap_result_from_string(value);
1023 if (f < 0)
f2341e0a 1024 log_unit_debug(u, "Failed to parse result value: %s", value);
e1770af8
LP
1025 else if (f != SWAP_SUCCESS)
1026 s->result = f;
e04aad61
LP
1027 } else if (streq(key, "control-pid")) {
1028 pid_t pid;
1029
1030 if (parse_pid(value, &pid) < 0)
f2341e0a 1031 log_unit_debug(u, "Failed to parse control-pid value: %s", value);
e04aad61
LP
1032 else
1033 s->control_pid = pid;
1034
1035 } else if (streq(key, "control-command")) {
1036 SwapExecCommand id;
1037
646134dc
ZJS
1038 id = swap_exec_command_from_string(value);
1039 if (id < 0)
f2341e0a 1040 log_unit_debug(u, "Failed to parse exec-command value: %s", value);
e04aad61
LP
1041 else {
1042 s->control_command_id = id;
1043 s->control_command = s->exec_command + id;
1044 }
07b0b134 1045 } else
f2341e0a 1046 log_unit_debug(u, "Unknown serialization key: %s", key);
07b0b134
ML
1047
1048 return 0;
1049}
1050
e04aad61
LP
1051static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
1052 Swap *s = SWAP(u);
e1770af8 1053 SwapResult f;
e04aad61
LP
1054
1055 assert(s);
1056 assert(pid >= 0);
1057
1058 if (pid != s->control_pid)
1059 return;
1060
bcce581d
LP
1061 /* Let's scan /proc/swaps before we process SIGCHLD. For the reasoning see the similar code in
1062 * mount.c */
1063 (void) swap_process_proc_swaps(u->manager);
1064
e04aad61
LP
1065 s->control_pid = 0;
1066
1f0958f6 1067 if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
e1770af8
LP
1068 f = SWAP_SUCCESS;
1069 else if (code == CLD_EXITED)
1070 f = SWAP_FAILURE_EXIT_CODE;
1071 else if (code == CLD_KILLED)
1072 f = SWAP_FAILURE_SIGNAL;
1073 else if (code == CLD_DUMPED)
1074 f = SWAP_FAILURE_CORE_DUMP;
1075 else
1076 assert_not_reached("Unknown code");
1077
a0fef983 1078 if (s->result == SWAP_SUCCESS)
e1770af8 1079 s->result = f;
e04aad61
LP
1080
1081 if (s->control_command) {
6ea832a2 1082 exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
e1770af8 1083
e04aad61
LP
1084 s->control_command = NULL;
1085 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
1086 }
1087
91bbd9b7 1088 unit_log_process_exit(
5cc2cd1c 1089 u,
91bbd9b7
LP
1090 "Swap process",
1091 swap_exec_command_to_string(s->control_command_id),
5cc2cd1c 1092 f == SWAP_SUCCESS,
91bbd9b7 1093 code, status);
e04aad61
LP
1094
1095 switch (s->state) {
1096
1097 case SWAP_ACTIVATING:
5bcb0f2b 1098 case SWAP_ACTIVATING_DONE:
e04aad61 1099
50864457 1100 if (f == SWAP_SUCCESS || s->from_proc_swaps)
e1770af8 1101 swap_enter_active(s, f);
e04aad61 1102 else
e1770af8 1103 swap_enter_dead(s, f);
e04aad61
LP
1104 break;
1105
1106 case SWAP_DEACTIVATING:
1107 case SWAP_DEACTIVATING_SIGKILL:
1108 case SWAP_DEACTIVATING_SIGTERM:
1109
50864457 1110 swap_enter_dead_or_active(s, f);
e04aad61
LP
1111 break;
1112
a8b689b7
YW
1113 case SWAP_CLEANING:
1114 if (s->clean_result == SWAP_SUCCESS)
1115 s->clean_result = f;
1116
1117 swap_enter_dead(s, SWAP_SUCCESS);
1118 break;
1119
e04aad61
LP
1120 default:
1121 assert_not_reached("Uh, control process died at wrong time.");
1122 }
1123
1124 /* Notify clients about changed exit status */
1125 unit_add_to_dbus_queue(u);
e04aad61
LP
1126}
1127
718db961
LP
1128static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
1129 Swap *s = SWAP(userdata);
e04aad61
LP
1130
1131 assert(s);
718db961 1132 assert(s->timer_event_source == source);
e04aad61
LP
1133
1134 switch (s->state) {
1135
1136 case SWAP_ACTIVATING:
5bcb0f2b 1137 case SWAP_ACTIVATING_DONE:
f2341e0a 1138 log_unit_warning(UNIT(s), "Activation timed out. Stopping.");
50864457 1139 swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1140 break;
1141
1142 case SWAP_DEACTIVATING:
f2341e0a 1143 log_unit_warning(UNIT(s), "Deactivation timed out. Stopping.");
e1770af8 1144 swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1145 break;
1146
e04aad61 1147 case SWAP_DEACTIVATING_SIGTERM:
4819ff03 1148 if (s->kill_context.send_sigkill) {
50864457 1149 log_unit_warning(UNIT(s), "Swap process timed out. Killing.");
e1770af8 1150 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
ba035df2 1151 } else {
50864457
LP
1152 log_unit_warning(UNIT(s), "Swap process timed out. Skipping SIGKILL. Ignoring.");
1153 swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT);
ba035df2 1154 }
e04aad61
LP
1155 break;
1156
e04aad61 1157 case SWAP_DEACTIVATING_SIGKILL:
f2341e0a 1158 log_unit_warning(UNIT(s), "Swap process still around after SIGKILL. Ignoring.");
50864457 1159 swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1160 break;
1161
a8b689b7
YW
1162 case SWAP_CLEANING:
1163 log_unit_warning(UNIT(s), "Cleaning timed out. killing.");
1164
1165 if (s->clean_result == SWAP_SUCCESS)
1166 s->clean_result = SWAP_FAILURE_TIMEOUT;
1167
1168 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, 0);
1169 break;
1170
e04aad61
LP
1171 default:
1172 assert_not_reached("Timeout at wrong time.");
1173 }
718db961
LP
1174
1175 return 0;
e04aad61
LP
1176}
1177
1178static int swap_load_proc_swaps(Manager *m, bool set_flags) {
e04aad61
LP
1179 assert(m);
1180
07b0b134 1181 rewind(m->proc_swaps);
bab45044 1182
4e85aff4 1183 (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
07b0b134 1184
fe96c0f8 1185 for (unsigned i = 1;; i++) {
9fb3675e 1186 _cleanup_free_ char *dev = NULL, *d = NULL;
07b0b134
ML
1187 int prio = 0, k;
1188
646134dc
ZJS
1189 k = fscanf(m->proc_swaps,
1190 "%ms " /* device/file */
1191 "%*s " /* type of swap */
1192 "%*s " /* swap size */
1193 "%*s " /* used */
1194 "%i\n", /* priority */
1195 &dev, &prio);
1196 if (k != 2) {
07b0b134 1197 if (k == EOF)
4e85aff4 1198 break;
07b0b134 1199
628c89cc 1200 log_warning("Failed to parse /proc/swaps:%u.", i);
e04aad61 1201 continue;
07b0b134 1202 }
07b0b134 1203
e437538f
ZJS
1204 ssize_t l = cunescape(dev, UNESCAPE_RELAX, &d);
1205 if (l < 0)
1206 return log_error_errno(l, "Failed to unescape device path: %m");
628c89cc 1207
485ae697 1208 device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
4e85aff4 1209
eb04385d 1210 (void) swap_process_new(m, d, prio, set_flags);
07b0b134
ML
1211 }
1212
eb04385d 1213 return 0;
e04aad61
LP
1214}
1215
bcce581d 1216static int swap_process_proc_swaps(Manager *m) {
595ed347 1217 Unit *u;
4e434314
LP
1218 int r;
1219
1220 assert(m);
4e434314 1221
646134dc
ZJS
1222 r = swap_load_proc_swaps(m, true);
1223 if (r < 0) {
da927ba9 1224 log_error_errno(r, "Failed to reread /proc/swaps: %m");
e04aad61
LP
1225
1226 /* Reset flags, just in case, for late calls */
595ed347
MS
1227 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
1228 Swap *swap = SWAP(u);
e04aad61
LP
1229
1230 swap->is_active = swap->just_activated = false;
1231 }
1232
1233 return 0;
1234 }
1235
1236 manager_dispatch_load_queue(m);
1237
595ed347
MS
1238 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
1239 Swap *swap = SWAP(u);
e04aad61
LP
1240
1241 if (!swap->is_active) {
e04aad61 1242
e04aad61
LP
1243 swap_unset_proc_swaps(swap);
1244
1245 switch (swap->state) {
1246
1247 case SWAP_ACTIVE:
ba6fbb2c 1248 /* This has just been deactivated */
e1770af8 1249 swap_enter_dead(swap, SWAP_SUCCESS);
e04aad61
LP
1250 break;
1251
1252 default:
5bcb0f2b 1253 /* Fire again */
e04aad61
LP
1254 swap_set_state(swap, swap->state);
1255 break;
1256 }
1257
628c89cc 1258 if (swap->what)
485ae697 1259 device_found_node(m, swap->what, 0, DEVICE_FOUND_SWAP);
628c89cc 1260
e04aad61
LP
1261 } else if (swap->just_activated) {
1262
1263 /* New swap entry */
1264
1265 switch (swap->state) {
1266
1267 case SWAP_DEAD:
1268 case SWAP_FAILED:
31135818
LP
1269 (void) unit_acquire_invocation_id(u);
1270 swap_cycle_clear(swap);
e1770af8 1271 swap_enter_active(swap, SWAP_SUCCESS);
e04aad61
LP
1272 break;
1273
5bcb0f2b
LP
1274 case SWAP_ACTIVATING:
1275 swap_set_state(swap, SWAP_ACTIVATING_DONE);
1276 break;
1277
e04aad61
LP
1278 default:
1279 /* Nothing really changed, but let's
1280 * issue an notification call
1281 * nonetheless, in case somebody is
1282 * waiting for this. */
1283 swap_set_state(swap, swap->state);
1284 break;
1285 }
1286 }
1287
1288 /* Reset the flags for later calls */
1289 swap->is_active = swap->just_activated = false;
1290 }
1291
1292 return 1;
1293}
1294
bcce581d
LP
1295static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
1296 Manager *m = userdata;
1297
1298 assert(m);
1299 assert(revents & EPOLLPRI);
1300
1301 return swap_process_proc_swaps(m);
1302}
1303
e04aad61
LP
1304static Unit *swap_following(Unit *u) {
1305 Swap *s = SWAP(u);
1306 Swap *other, *first = NULL;
1307
1308 assert(s);
1309
cdc89820
ZJS
1310 /* If the user configured the swap through /etc/fstab or
1311 * a device unit, follow that. */
1312
1313 if (s->from_fragment)
e04aad61
LP
1314 return NULL;
1315
caac2704 1316 LIST_FOREACH_OTHERS(same_devnode, other, s)
cdc89820
ZJS
1317 if (other->from_fragment)
1318 return UNIT(other);
1319
b938cb90 1320 /* Otherwise, make everybody follow the unit that's named after
cdc89820
ZJS
1321 * the swap device in the kernel */
1322
1323 if (streq_ptr(s->what, s->devnode))
1324 return NULL;
e04aad61 1325
9670d583
LP
1326 LIST_FOREACH_AFTER(same_devnode, other, s)
1327 if (streq_ptr(other->what, other->devnode))
e04aad61
LP
1328 return UNIT(other);
1329
9670d583
LP
1330 LIST_FOREACH_BEFORE(same_devnode, other, s) {
1331 if (streq_ptr(other->what, other->devnode))
e04aad61
LP
1332 return UNIT(other);
1333
1334 first = other;
1335 }
1336
cdc89820 1337 /* Fall back to the first on the list */
e04aad61 1338 return UNIT(first);
07b0b134
ML
1339}
1340
6210e7fc 1341static int swap_following_set(Unit *u, Set **_set) {
5bcb0f2b 1342 Swap *s = SWAP(u), *other;
af4fa99d 1343 _cleanup_set_free_ Set *set = NULL;
6210e7fc
LP
1344 int r;
1345
1346 assert(s);
1347 assert(_set);
1348
9670d583 1349 if (LIST_JUST_US(same_devnode, s)) {
6210e7fc
LP
1350 *_set = NULL;
1351 return 0;
1352 }
1353
d5099efc 1354 set = set_new(NULL);
5bcb0f2b 1355 if (!set)
6210e7fc
LP
1356 return -ENOMEM;
1357
caac2704 1358 LIST_FOREACH_OTHERS(same_devnode, other, s) {
5bcb0f2b
LP
1359 r = set_put(set, other);
1360 if (r < 0)
95f14a3e 1361 return r;
5bcb0f2b 1362 }
6210e7fc 1363
95f14a3e 1364 *_set = TAKE_PTR(set);
6210e7fc 1365 return 1;
6210e7fc
LP
1366}
1367
07b0b134
ML
1368static void swap_shutdown(Manager *m) {
1369 assert(m);
1370
5dcadb4c 1371 m->swap_event_source = sd_event_source_disable_unref(m->swap_event_source);
74ca738f 1372 m->proc_swaps = safe_fclose(m->proc_swaps);
525d3cc7 1373 m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
07b0b134
ML
1374}
1375
ba64af90 1376static void swap_enumerate(Manager *m) {
07b0b134 1377 int r;
9670d583 1378
07b0b134
ML
1379 assert(m);
1380
4e434314 1381 if (!m->proc_swaps) {
646134dc 1382 m->proc_swaps = fopen("/proc/swaps", "re");
ba64af90
LP
1383 if (!m->proc_swaps) {
1384 if (errno == ENOENT)
cb209a04 1385 log_debug_errno(errno, "Not swap enabled, skipping enumeration.");
ba64af90 1386 else
cb209a04 1387 log_warning_errno(errno, "Failed to open /proc/swaps, ignoring: %m");
ba64af90
LP
1388
1389 return;
1390 }
4e434314 1391
151b9b96 1392 r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
ba64af90
LP
1393 if (r < 0) {
1394 log_error_errno(r, "Failed to watch /proc/swaps: %m");
29083707 1395 goto fail;
ba64af90 1396 }
29083707
LP
1397
1398 /* Dispatch this before we dispatch SIGCHLD, so that
1399 * we always get the events from /proc/swaps before
1400 * the SIGCHLD of /sbin/swapon. */
83231637 1401 r = sd_event_source_set_priority(m->swap_event_source, SD_EVENT_PRIORITY_NORMAL-10);
ba64af90
LP
1402 if (r < 0) {
1403 log_error_errno(r, "Failed to change /proc/swaps priority: %m");
718db961 1404 goto fail;
ba64af90 1405 }
7dfbe2e3
TG
1406
1407 (void) sd_event_source_set_description(m->swap_event_source, "swap-proc");
4e434314
LP
1408 }
1409
646134dc
ZJS
1410 r = swap_load_proc_swaps(m, false);
1411 if (r < 0)
718db961
LP
1412 goto fail;
1413
ba64af90 1414 return;
07b0b134 1415
718db961
LP
1416fail:
1417 swap_shutdown(m);
07b0b134
ML
1418}
1419
4366e598 1420int swap_process_device_new(Manager *m, sd_device *dev) {
9670d583 1421 _cleanup_free_ char *e = NULL;
4366e598 1422 const char *dn, *devlink;
cabf58b2 1423 Unit *u;
c53aafb7 1424 int r;
9670d583
LP
1425
1426 assert(m);
1427 assert(dev);
1428
e82c6e8b 1429 if (sd_device_get_devname(dev, &dn) < 0)
9670d583
LP
1430 return 0;
1431
7410616c 1432 r = unit_name_from_path(dn, ".swap", &e);
e82c6e8b
LP
1433 if (r < 0) {
1434 log_debug_errno(r, "Cannot convert device name '%s' to unit name, ignoring: %m", dn);
1435 return 0;
1436 }
9670d583 1437
cabf58b2
FB
1438 u = manager_get_unit(m, e);
1439 if (u)
1440 r = swap_set_devnode(SWAP(u), dn);
9670d583 1441
4366e598 1442 FOREACH_DEVICE_DEVLINK(dev, devlink) {
9670d583 1443 _cleanup_free_ char *n = NULL;
7410616c 1444 int q;
9670d583 1445
4366e598 1446 q = unit_name_from_path(devlink, ".swap", &n);
598a6a84
LP
1447 if (IN_SET(q, -EINVAL, -ENAMETOOLONG)) /* If name too long or otherwise not convertible to
1448 * unit name, we can't manage it */
1449 continue;
7410616c
LP
1450 if (q < 0)
1451 return q;
9670d583 1452
cabf58b2
FB
1453 u = manager_get_unit(m, n);
1454 if (u) {
1455 q = swap_set_devnode(SWAP(u), dn);
9670d583
LP
1456 if (q < 0)
1457 r = q;
1458 }
1459 }
1460
1461 return r;
1462}
1463
4366e598 1464int swap_process_device_remove(Manager *m, sd_device *dev) {
9670d583 1465 const char *dn;
c53aafb7 1466 int r;
9670d583
LP
1467 Swap *s;
1468
4366e598
YW
1469 r = sd_device_get_devname(dev, &dn);
1470 if (r < 0)
9670d583
LP
1471 return 0;
1472
1473 while ((s = hashmap_get(m->swaps_by_devnode, dn))) {
1474 int q;
1475
1476 q = swap_set_devnode(s, NULL);
1477 if (q < 0)
1478 r = q;
1479 }
1480
1481 return r;
1482}
1483
fdf20a31 1484static void swap_reset_failed(Unit *u) {
5632e374
LP
1485 Swap *s = SWAP(u);
1486
1487 assert(s);
1488
fdf20a31 1489 if (s->state == SWAP_FAILED)
5632e374 1490 swap_set_state(s, SWAP_DEAD);
e04aad61 1491
e1770af8 1492 s->result = SWAP_SUCCESS;
a8b689b7 1493 s->clean_result = SWAP_SUCCESS;
5632e374
LP
1494}
1495
718db961 1496static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
814cc562 1497 return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
8a0867d6
LP
1498}
1499
7a7821c8 1500static int swap_get_timeout(Unit *u, usec_t *timeout) {
68db7a3b 1501 Swap *s = SWAP(u);
7a7821c8 1502 usec_t t;
68db7a3b
ZJS
1503 int r;
1504
1505 if (!s->timer_event_source)
1506 return 0;
1507
7a7821c8 1508 r = sd_event_source_get_time(s->timer_event_source, &t);
68db7a3b
ZJS
1509 if (r < 0)
1510 return r;
7a7821c8
LP
1511 if (t == USEC_INFINITY)
1512 return 0;
68db7a3b 1513
7a7821c8 1514 *timeout = t;
68db7a3b
ZJS
1515 return 1;
1516}
1517
1c2e9646 1518static bool swap_supported(void) {
0faacd47
LP
1519 static int supported = -1;
1520
1521 /* If swap support is not available in the kernel, or we are
1522 * running in a container we don't support swap units, and any
1523 * attempts to starting one should fail immediately. */
1524
1525 if (supported < 0)
1526 supported =
1527 access("/proc/swaps", F_OK) >= 0 &&
75f86906 1528 detect_container() <= 0;
0faacd47
LP
1529
1530 return supported;
1531}
1532
291d565a
LP
1533static int swap_control_pid(Unit *u) {
1534 Swap *s = SWAP(u);
1535
1536 assert(s);
1537
1538 return s->control_pid;
1539}
1540
a8b689b7
YW
1541static int swap_clean(Unit *u, ExecCleanMask mask) {
1542 _cleanup_strv_free_ char **l = NULL;
1543 Swap *s = SWAP(u);
1544 int r;
1545
1546 assert(s);
1547 assert(mask != 0);
1548
1549 if (s->state != SWAP_DEAD)
1550 return -EBUSY;
1551
1552 r = exec_context_get_clean_directories(&s->exec_context, u->manager->prefix, mask, &l);
1553 if (r < 0)
1554 return r;
1555
1556 if (strv_isempty(l))
1557 return -EUNATCH;
1558
1559 swap_unwatch_control_pid(s);
1560 s->clean_result = SWAP_SUCCESS;
1561 s->control_command = NULL;
1562 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
1563
1564 r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->exec_context.timeout_clean_usec));
1565 if (r < 0)
1566 goto fail;
1567
1568 r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
1569 if (r < 0)
1570 goto fail;
1571
1572 swap_set_state(s, SWAP_CLEANING);
1573
1574 return 0;
1575
1576fail:
1577 log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m");
1578 s->clean_result = SWAP_FAILURE_RESOURCES;
5dcadb4c 1579 s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
a8b689b7
YW
1580 return r;
1581}
1582
1583static int swap_can_clean(Unit *u, ExecCleanMask *ret) {
1584 Swap *s = SWAP(u);
1585
1586 assert(s);
1587
1588 return exec_context_get_clean_mask(&s->exec_context, ret);
1589}
1590
e04aad61 1591static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
48d83e33 1592 [SWAP_EXEC_ACTIVATE] = "ExecActivate",
e04aad61
LP
1593 [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
1594};
1595
1596DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
1597
e1770af8 1598static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
48d83e33
ZJS
1599 [SWAP_SUCCESS] = "success",
1600 [SWAP_FAILURE_RESOURCES] = "resources",
1601 [SWAP_FAILURE_TIMEOUT] = "timeout",
1602 [SWAP_FAILURE_EXIT_CODE] = "exit-code",
1603 [SWAP_FAILURE_SIGNAL] = "signal",
1604 [SWAP_FAILURE_CORE_DUMP] = "core-dump",
07299350 1605 [SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
e1770af8
LP
1606};
1607
1608DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
1609
07b0b134 1610const UnitVTable swap_vtable = {
7d17cfbc 1611 .object_size = sizeof(Swap),
718db961
LP
1612 .exec_context_offset = offsetof(Swap, exec_context),
1613 .cgroup_context_offset = offsetof(Swap, cgroup_context),
1614 .kill_context_offset = offsetof(Swap, kill_context),
613b411c 1615 .exec_runtime_offset = offsetof(Swap, exec_runtime),
29206d46 1616 .dynamic_creds_offset = offsetof(Swap, dynamic_creds),
3ef63c31 1617
f975e971
LP
1618 .sections =
1619 "Unit\0"
1620 "Swap\0"
1621 "Install\0",
4ad49000 1622 .private_section = "Swap",
71645aca 1623
c80a9a33
LP
1624 .can_fail = true,
1625
4e85aff4 1626 .init = swap_init,
07b0b134 1627 .load = swap_load,
6e620bec 1628 .done = swap_done,
07b0b134
ML
1629
1630 .coldplug = swap_coldplug,
1631
1632 .dump = swap_dump,
1633
1634 .start = swap_start,
1635 .stop = swap_stop,
1636
8a0867d6 1637 .kill = swap_kill,
a8b689b7
YW
1638 .clean = swap_clean,
1639 .can_clean = swap_can_clean,
8a0867d6 1640
68db7a3b
ZJS
1641 .get_timeout = swap_get_timeout,
1642
07b0b134
ML
1643 .serialize = swap_serialize,
1644 .deserialize_item = swap_deserialize_item,
1645
1646 .active_state = swap_active_state,
1647 .sub_state_to_string = swap_sub_state_to_string,
1648
52a12341
YW
1649 .will_restart = unit_will_restart_default,
1650
f2f725e5 1651 .may_gc = swap_may_gc,
39c79477 1652 .is_extrinsic = swap_is_extrinsic,
07b0b134 1653
e04aad61 1654 .sigchld_event = swap_sigchld_event,
e04aad61
LP
1655
1656 .reset_failed = swap_reset_failed,
1657
291d565a
LP
1658 .control_pid = swap_control_pid,
1659
74c964d3
LP
1660 .bus_set_property = bus_swap_set_property,
1661 .bus_commit_properties = bus_swap_commit_properties,
07b0b134 1662
e04aad61 1663 .following = swap_following,
6210e7fc 1664 .following_set = swap_following_set,
5632e374 1665
6e620bec 1666 .enumerate = swap_enumerate,
c6918296 1667 .shutdown = swap_shutdown,
0faacd47 1668 .supported = swap_supported,
c6918296
MS
1669
1670 .status_message_formats = {
1671 .starting_stopping = {
1672 [0] = "Activating swap %s...",
1673 [1] = "Deactivating swap %s...",
1674 },
1675 .finished_start_job = {
1676 [JOB_DONE] = "Activated swap %s.",
1677 [JOB_FAILED] = "Failed to activate swap %s.",
c6918296
MS
1678 [JOB_TIMEOUT] = "Timed out activating swap %s.",
1679 },
1680 .finished_stop_job = {
1681 [JOB_DONE] = "Deactivated swap %s.",
1682 [JOB_FAILED] = "Failed deactivating swap %s.",
1683 [JOB_TIMEOUT] = "Timed out deactivating swap %s.",
1684 },
1685 },
07b0b134 1686};