1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2018 Dell Inc.
9 #include <linux/magic.h>
12 #include <sys/ioctl.h>
14 #include <sys/types.h>
18 #include "sd-device.h"
20 #include "alloc-util.h"
21 #include "battery-util.h"
22 #include "blockdev-util.h"
23 #include "btrfs-util.h"
24 #include "conf-parser.h"
25 #include "constants.h"
26 #include "device-private.h"
27 #include "device-util.h"
28 #include "devnum-util.h"
30 #include "errno-util.h"
33 #include "hexdecoct.h"
34 #include "id128-util.h"
37 #include "path-util.h"
38 #include "siphash24.h"
39 #include "sleep-config.h"
40 #include "stat-util.h"
41 #include "stdio-util.h"
42 #include "string-table.h"
43 #include "string-util.h"
45 #include "time-util.h"
47 #define DISCHARGE_RATE_FILEPATH "/var/lib/systemd/sleep/battery_discharge_percentage_rate_per_hour"
48 #define BATTERY_DISCHARGE_RATE_HASH_KEY SD_ID128_MAKE(5f,9a,20,18,38,76,46,07,8d,36,58,0b,bb,c4,e0,63)
49 #define SYS_ENTRY_RAW_FILE_TYPE1 "/sys/firmware/dmi/entries/1-0/raw"
51 static void *CAPACITY_TO_PTR(int capacity
) {
52 assert(capacity
>= 0);
53 assert(capacity
<= 100);
54 return INT_TO_PTR(capacity
+ 1);
57 static int PTR_TO_CAPACITY(void *p
) {
58 int capacity
= PTR_TO_INT(p
) - 1;
59 assert(capacity
>= 0);
60 assert(capacity
<= 100);
64 int parse_sleep_config(SleepConfig
**ret_sleep_config
) {
65 _cleanup_(free_sleep_configp
) SleepConfig
*sc
= NULL
;
66 int allow_suspend
= -1, allow_hibernate
= -1,
67 allow_s2h
= -1, allow_hybrid_sleep
= -1;
69 sc
= new(SleepConfig
, 1);
74 .hibernate_delay_usec
= USEC_INFINITY
,
77 const ConfigTableItem items
[] = {
78 { "Sleep", "AllowSuspend", config_parse_tristate
, 0, &allow_suspend
},
79 { "Sleep", "AllowHibernation", config_parse_tristate
, 0, &allow_hibernate
},
80 { "Sleep", "AllowSuspendThenHibernate", config_parse_tristate
, 0, &allow_s2h
},
81 { "Sleep", "AllowHybridSleep", config_parse_tristate
, 0, &allow_hybrid_sleep
},
83 { "Sleep", "SuspendMode", config_parse_strv
, 0, sc
->modes
+ SLEEP_SUSPEND
},
84 { "Sleep", "SuspendState", config_parse_strv
, 0, sc
->states
+ SLEEP_SUSPEND
},
85 { "Sleep", "HibernateMode", config_parse_strv
, 0, sc
->modes
+ SLEEP_HIBERNATE
},
86 { "Sleep", "HibernateState", config_parse_strv
, 0, sc
->states
+ SLEEP_HIBERNATE
},
87 { "Sleep", "HybridSleepMode", config_parse_strv
, 0, sc
->modes
+ SLEEP_HYBRID_SLEEP
},
88 { "Sleep", "HybridSleepState", config_parse_strv
, 0, sc
->states
+ SLEEP_HYBRID_SLEEP
},
90 { "Sleep", "HibernateDelaySec", config_parse_sec
, 0, &sc
->hibernate_delay_usec
},
91 { "Sleep", "SuspendEstimationSec", config_parse_sec
, 0, &sc
->suspend_estimation_usec
},
95 (void) config_parse_config_file("sleep.conf", "Sleep\0",
96 config_item_table_lookup
, items
,
97 CONFIG_PARSE_WARN
, NULL
);
99 /* use default values unless set */
100 sc
->allow
[SLEEP_SUSPEND
] = allow_suspend
!= 0;
101 sc
->allow
[SLEEP_HIBERNATE
] = allow_hibernate
!= 0;
102 sc
->allow
[SLEEP_HYBRID_SLEEP
] = allow_hybrid_sleep
>= 0 ? allow_hybrid_sleep
103 : (allow_suspend
!= 0 && allow_hibernate
!= 0);
104 sc
->allow
[SLEEP_SUSPEND_THEN_HIBERNATE
] = allow_s2h
>= 0 ? allow_s2h
105 : (allow_suspend
!= 0 && allow_hibernate
!= 0);
107 if (!sc
->states
[SLEEP_SUSPEND
])
108 sc
->states
[SLEEP_SUSPEND
] = strv_new("mem", "standby", "freeze");
109 if (!sc
->modes
[SLEEP_HIBERNATE
])
110 sc
->modes
[SLEEP_HIBERNATE
] = strv_new("platform", "shutdown");
111 if (!sc
->states
[SLEEP_HIBERNATE
])
112 sc
->states
[SLEEP_HIBERNATE
] = strv_new("disk");
113 if (!sc
->modes
[SLEEP_HYBRID_SLEEP
])
114 sc
->modes
[SLEEP_HYBRID_SLEEP
] = strv_new("suspend", "platform", "shutdown");
115 if (!sc
->states
[SLEEP_HYBRID_SLEEP
])
116 sc
->states
[SLEEP_HYBRID_SLEEP
] = strv_new("disk");
117 if (sc
->suspend_estimation_usec
== 0)
118 sc
->suspend_estimation_usec
= DEFAULT_SUSPEND_ESTIMATION_USEC
;
120 /* Ensure values set for all required fields */
121 if (!sc
->states
[SLEEP_SUSPEND
] || !sc
->modes
[SLEEP_HIBERNATE
]
122 || !sc
->states
[SLEEP_HIBERNATE
] || !sc
->modes
[SLEEP_HYBRID_SLEEP
] || !sc
->states
[SLEEP_HYBRID_SLEEP
])
125 *ret_sleep_config
= TAKE_PTR(sc
);
130 int get_capacity_by_name(Hashmap
*capacities_by_name
, const char *name
) {
133 assert(capacities_by_name
);
136 p
= hashmap_get(capacities_by_name
, name
);
140 return PTR_TO_CAPACITY(p
);
143 /* Store current capacity of each battery before suspension and timestamp */
144 int fetch_batteries_capacity_by_name(Hashmap
**ret
) {
145 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
146 _cleanup_hashmap_free_ Hashmap
*batteries_capacity_by_name
= NULL
;
152 batteries_capacity_by_name
= hashmap_new(&string_hash_ops_free
);
153 if (!batteries_capacity_by_name
)
154 return log_oom_debug();
156 r
= battery_enumerator_new(&e
);
158 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
160 FOREACH_DEVICE(e
, dev
) {
161 _cleanup_free_
char *battery_name_copy
= NULL
;
162 const char *battery_name
;
163 int battery_capacity
;
165 battery_capacity
= r
= battery_read_capacity_percentage(dev
);
169 r
= sd_device_get_property_value(dev
, "POWER_SUPPLY_NAME", &battery_name
);
171 log_device_debug_errno(dev
, r
, "Failed to get POWER_SUPPLY_NAME property, ignoring: %m");
175 battery_name_copy
= strdup(battery_name
);
176 if (!battery_name_copy
)
177 return log_oom_debug();
179 r
= hashmap_put(batteries_capacity_by_name
, battery_name_copy
, CAPACITY_TO_PTR(battery_capacity
));
181 return log_device_debug_errno(dev
, r
, "Failed to store battery capacity: %m");
183 TAKE_PTR(battery_name_copy
);
186 *ret
= TAKE_PTR(batteries_capacity_by_name
);
191 static int siphash24_compress_device_sysattr(sd_device
*dev
, const char *attr
, struct siphash
*state
) {
199 r
= sd_device_get_sysattr_value(dev
, attr
, &x
);
201 return log_device_debug_errno(dev
, r
, "Failed to read '%s' attribute: %m", attr
);
204 siphash24_compress_string(x
, state
);
209 static int siphash24_compress_id128(int (*getter
)(sd_id128_t
*), const char *name
, struct siphash
*state
) {
218 return log_debug_errno(r
, "Failed to get %s ID: %m", name
);
220 siphash24_compress(&id
, sizeof(sd_id128_t
), state
);
224 /* Read system and battery identifier from specific location and generate hash of it */
225 static int get_system_battery_identifier_hash(sd_device
*dev
, uint64_t *ret
) {
226 struct siphash state
;
231 siphash24_init(&state
, BATTERY_DISCHARGE_RATE_HASH_KEY
.bytes
);
233 (void) siphash24_compress_device_sysattr(dev
, "manufacturer", &state
);
234 (void) siphash24_compress_device_sysattr(dev
, "model_name", &state
);
235 (void) siphash24_compress_device_sysattr(dev
, "serial_number", &state
);
236 (void) siphash24_compress_id128(sd_id128_get_machine
, "machine", &state
);
237 (void) siphash24_compress_id128(id128_get_product
, "product", &state
);
239 *ret
= siphash24_finalize(&state
);
243 /* Return success if battery percentage discharge rate per hour is in the range 1–199 */
244 static bool battery_discharge_rate_is_valid(int battery_discharge_rate
) {
245 return battery_discharge_rate
> 0 && battery_discharge_rate
< 200;
248 /* Battery percentage discharge rate per hour is read from specific file. It is stored along with system
249 * and battery identifier hash to maintain the integrity of discharge rate value */
250 static int get_battery_discharge_rate(sd_device
*dev
, int *ret
) {
251 _cleanup_fclose_
FILE *f
= NULL
;
252 uint64_t current_hash_id
;
259 f
= fopen(DISCHARGE_RATE_FILEPATH
, "re");
261 return log_debug_errno(errno
, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH
": %m");
263 r
= get_system_battery_identifier_hash(dev
, ¤t_hash_id
);
265 return log_device_debug_errno(dev
, r
, "Failed to generate system battery identifier hash: %m");
268 _cleanup_free_
char *stored_hash_id
= NULL
, *stored_discharge_rate
= NULL
, *line
= NULL
;
272 r
= read_line(f
, LONG_LINE_MAX
, &line
);
274 return log_debug_errno(r
, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH
": %m");
279 r
= extract_many_words(&p
, NULL
, 0, &stored_hash_id
, &stored_discharge_rate
, NULL
);
281 return log_debug_errno(r
, "Failed to parse hash_id and discharge_rate read from " DISCHARGE_RATE_FILEPATH
": %m");
283 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid number of items fetched from " DISCHARGE_RATE_FILEPATH
);
285 r
= safe_atou64(stored_hash_id
, &hash_id
);
287 return log_debug_errno(r
, "Failed to parse hash ID read from " DISCHARGE_RATE_FILEPATH
" location: %m");
289 if (current_hash_id
!= hash_id
)
290 /* matching device not found, move to next line */
293 r
= safe_atoi(stored_discharge_rate
, &discharge_rate
);
295 return log_device_debug_errno(dev
, r
, "Failed to parse discharge rate read from " DISCHARGE_RATE_FILEPATH
": %m");
297 if (!battery_discharge_rate_is_valid(discharge_rate
))
298 return log_device_debug_errno(dev
, SYNTHETIC_ERRNO(ERANGE
), "Invalid battery discharge percentage rate per hour: %m");
300 *ret
= discharge_rate
;
301 return 0; /* matching device found, exit iteration */
307 /* Write battery percentage discharge rate per hour along with system and battery identifier hash to file */
308 static int put_battery_discharge_rate(int estimated_battery_discharge_rate
, uint64_t system_hash_id
, bool trunc
) {
311 if (!battery_discharge_rate_is_valid(estimated_battery_discharge_rate
))
312 return log_debug_errno(SYNTHETIC_ERRNO(ERANGE
),
313 "Invalid battery discharge rate %d%% per hour: %m",
314 estimated_battery_discharge_rate
);
316 r
= write_string_filef(
317 DISCHARGE_RATE_FILEPATH
,
318 WRITE_STRING_FILE_CREATE
| WRITE_STRING_FILE_MKDIR_0755
| (trunc
? WRITE_STRING_FILE_TRUNCATE
: 0),
321 estimated_battery_discharge_rate
);
323 return log_debug_errno(r
, "Failed to update %s: %m", DISCHARGE_RATE_FILEPATH
);
325 log_debug("Estimated discharge rate %d%% per hour successfully saved to %s", estimated_battery_discharge_rate
, DISCHARGE_RATE_FILEPATH
);
330 /* Estimate battery discharge rate using stored previous and current capacity over timestamp difference */
331 int estimate_battery_discharge_rate_per_hour(
332 Hashmap
*last_capacity
,
333 Hashmap
*current_capacity
,
334 usec_t before_timestamp
,
335 usec_t after_timestamp
) {
337 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
342 assert(last_capacity
);
343 assert(current_capacity
);
344 assert(before_timestamp
< after_timestamp
);
346 r
= battery_enumerator_new(&e
);
348 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
350 FOREACH_DEVICE(e
, dev
) {
351 int battery_last_capacity
, battery_current_capacity
, battery_discharge_rate
;
352 const char *battery_name
;
353 uint64_t system_hash_id
;
355 r
= sd_device_get_property_value(dev
, "POWER_SUPPLY_NAME", &battery_name
);
357 log_device_debug_errno(dev
, r
, "Failed to read battery name, ignoring: %m");
361 battery_last_capacity
= get_capacity_by_name(last_capacity
, battery_name
);
362 if (battery_last_capacity
< 0)
365 battery_current_capacity
= get_capacity_by_name(current_capacity
, battery_name
);
366 if (battery_current_capacity
< 0)
369 if (battery_current_capacity
>= battery_last_capacity
) {
370 log_device_debug(dev
, "Battery was not discharged during suspension");
374 r
= get_system_battery_identifier_hash(dev
, &system_hash_id
);
376 return log_device_debug_errno(dev
, r
, "Failed to generate system battery identifier hash: %m");
378 log_device_debug(dev
,
379 "%d%% was discharged in %s. Estimating discharge rate...",
380 battery_last_capacity
- battery_current_capacity
,
381 FORMAT_TIMESPAN(after_timestamp
- before_timestamp
, USEC_PER_SEC
));
383 battery_discharge_rate
= (battery_last_capacity
- battery_current_capacity
) * USEC_PER_HOUR
/ (after_timestamp
- before_timestamp
);
384 r
= put_battery_discharge_rate(battery_discharge_rate
, system_hash_id
, trunc
);
386 log_device_warning_errno(dev
, r
, "Failed to update battery discharge rate, ignoring: %m");
394 /* Calculate the suspend interval for each battery and then return their sum */
395 int get_total_suspend_interval(Hashmap
*last_capacity
, usec_t
*ret
) {
396 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
397 usec_t total_suspend_interval
= 0;
401 assert(last_capacity
);
404 r
= battery_enumerator_new(&e
);
406 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
408 FOREACH_DEVICE(e
, dev
) {
409 int battery_last_capacity
, previous_discharge_rate
= 0;
410 const char *battery_name
;
411 usec_t suspend_interval
;
413 r
= sd_device_get_property_value(dev
, "POWER_SUPPLY_NAME", &battery_name
);
415 log_device_debug_errno(dev
, r
, "Failed to read battery name, ignoring: %m");
419 battery_last_capacity
= get_capacity_by_name(last_capacity
, battery_name
);
420 if (battery_last_capacity
<= 0)
423 r
= get_battery_discharge_rate(dev
, &previous_discharge_rate
);
425 log_device_debug_errno(dev
, r
, "Failed to get discharge rate, ignoring: %m");
429 if (previous_discharge_rate
== 0)
432 if (battery_last_capacity
* 2 <= previous_discharge_rate
) {
433 log_device_debug(dev
, "Current battery capacity percentage too low compared to discharge rate");
436 suspend_interval
= battery_last_capacity
* USEC_PER_HOUR
/ previous_discharge_rate
;
438 total_suspend_interval
= usec_add(total_suspend_interval
, suspend_interval
);
440 /* Previous discharge rate is stored in per hour basis converted to usec.
441 * Subtract 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
442 total_suspend_interval
= usec_sub_unsigned(total_suspend_interval
, 30 * USEC_PER_MINUTE
);
443 if (total_suspend_interval
== 0)
446 *ret
= total_suspend_interval
;
451 /* Return true if all batteries have acpi_btp support */
452 int battery_trip_point_alarm_exists(void) {
453 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
457 r
= battery_enumerator_new(&e
);
459 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
461 FOREACH_DEVICE(e
, dev
) {
465 r
= sd_device_get_sysattr_value(dev
, "alarm", &s
);
467 return log_device_debug_errno(dev
, r
, "Failed to read battery alarm: %m");
469 r
= safe_atoi(s
, &battery_alarm
);
471 return log_device_debug_errno(dev
, r
, "Failed to parse battery alarm: %m");
472 if (battery_alarm
<= 0)
479 /* Return true if wakeup type is APM timer */
480 int check_wakeup_type(void) {
481 _cleanup_free_
char *s
= NULL
;
482 uint8_t wakeup_type_byte
, tablesize
;
486 /* implementation via dmi/entries */
487 r
= read_full_virtual_file(SYS_ENTRY_RAW_FILE_TYPE1
, &s
, &readsize
);
489 return log_debug_errno(r
, "Unable to read %s: %m", SYS_ENTRY_RAW_FILE_TYPE1
);
492 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Only read %zu bytes from %s (expected 25)", readsize
, SYS_ENTRY_RAW_FILE_TYPE1
);
494 /* index 1 stores the size of table */
495 tablesize
= (uint8_t) s
[1];
497 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Table size lesser than the index[0x18] where waketype byte is available.");
499 wakeup_type_byte
= (uint8_t) s
[24];
500 /* 0 is Reserved and 8 is AC Power Restored. As per table 12 in
501 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf */
502 if (wakeup_type_byte
>= 128)
503 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Expected value in range 0-127");
505 if (wakeup_type_byte
== 3) {
506 log_debug("DMI BIOS System Information indicates wakeup type is APM Timer");
513 int can_sleep_state(char **types
) {
514 _cleanup_free_
char *text
= NULL
;
517 if (strv_isempty(types
))
520 /* If /sys is read-only we cannot sleep */
521 if (access("/sys/power/state", W_OK
) < 0) {
522 log_debug_errno(errno
, "/sys/power/state is not writable, cannot sleep: %m");
526 r
= read_one_line_file("/sys/power/state", &text
);
528 log_debug_errno(r
, "Failed to read /sys/power/state, cannot sleep: %m");
533 r
= string_contains_word_strv(text
, NULL
, types
, &found
);
535 return log_debug_errno(r
, "Failed to parse /sys/power/state: %m");
537 log_debug("Sleep mode \"%s\" is supported by the kernel.", found
);
538 else if (DEBUG_LOGGING
) {
539 _cleanup_free_
char *t
= strv_join(types
, "/");
540 log_debug("Sleep mode %s not supported by the kernel, sorry.", strnull(t
));
545 int can_sleep_disk(char **types
) {
546 _cleanup_free_
char *text
= NULL
;
549 if (strv_isempty(types
))
552 /* If /sys is read-only we cannot sleep */
553 if (access("/sys/power/disk", W_OK
) < 0) {
554 log_debug_errno(errno
, "/sys/power/disk is not writable: %m");
558 r
= read_one_line_file("/sys/power/disk", &text
);
560 log_debug_errno(r
, "Couldn't read /sys/power/disk: %m");
564 for (const char *p
= text
;;) {
565 _cleanup_free_
char *word
= NULL
;
567 r
= extract_first_word(&p
, &word
, NULL
, 0);
569 return log_debug_errno(r
, "Failed to parse /sys/power/disk: %m");
574 size_t l
= strlen(s
);
575 if (s
[0] == '[' && s
[l
-1] == ']') {
580 if (strv_contains(types
, s
)) {
581 log_debug("Disk sleep mode \"%s\" is supported by the kernel.", s
);
587 _cleanup_free_
char *t
= strv_join(types
, "/");
588 log_debug("Disk sleep mode %s not supported by the kernel, sorry.", strnull(t
));
593 #define HIBERNATION_SWAP_THRESHOLD 0.98
595 SwapEntry
* swap_entry_free(SwapEntry
*se
) {
605 HibernateLocation
* hibernate_location_free(HibernateLocation
*hl
) {
609 swap_entry_free(hl
->swap
);
614 static int swap_device_to_device_id(const SwapEntry
*swap
, dev_t
*ret_dev
) {
619 assert(swap
->device
);
622 r
= stat(swap
->device
, &sb
);
626 if (streq(swap
->type
, "partition")) {
627 if (!S_ISBLK(sb
.st_mode
))
630 *ret_dev
= sb
.st_rdev
;
634 return get_block_device(swap
->device
, ret_dev
);
638 * Attempt to calculate the swap file offset on supported filesystems. On unsupported
639 * filesystems, a debug message is logged and ret_offset is set to UINT64_MAX.
641 static int calculate_swap_file_offset(const SwapEntry
*swap
, uint64_t *ret_offset
) {
642 _cleanup_close_
int fd
= -EBADF
;
643 _cleanup_free_
struct fiemap
*fiemap
= NULL
;
648 assert(swap
->device
);
649 assert(streq(swap
->type
, "file"));
651 fd
= open(swap
->device
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
653 return log_debug_errno(errno
, "Failed to open swap file %s to determine on-disk offset: %m", swap
->device
);
655 if (fstat(fd
, &sb
) < 0)
656 return log_debug_errno(errno
, "Failed to stat %s: %m", swap
->device
);
658 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
660 return log_debug_errno(r
, "Error checking %s for Btrfs filesystem: %m", swap
->device
);
662 log_debug("%s: detection of swap file offset on Btrfs is not supported", swap
->device
);
663 *ret_offset
= UINT64_MAX
;
667 r
= read_fiemap(fd
, &fiemap
);
669 return log_debug_errno(r
, "Unable to read extent map for '%s': %m", swap
->device
);
671 *ret_offset
= fiemap
->fm_extents
[0].fe_physical
/ page_size();
675 static int read_resume_files(dev_t
*ret_resume
, uint64_t *ret_resume_offset
) {
676 _cleanup_free_
char *resume_str
= NULL
, *resume_offset_str
= NULL
;
677 uint64_t resume_offset
= 0;
681 r
= read_one_line_file("/sys/power/resume", &resume_str
);
683 return log_debug_errno(r
, "Error reading /sys/power/resume: %m");
685 r
= parse_devnum(resume_str
, &resume
);
687 return log_debug_errno(r
, "Error parsing /sys/power/resume device: %s: %m", resume_str
);
689 r
= read_one_line_file("/sys/power/resume_offset", &resume_offset_str
);
691 log_debug_errno(r
, "Kernel does not support resume_offset; swap file offset detection will be skipped.");
693 return log_debug_errno(r
, "Error reading /sys/power/resume_offset: %m");
695 r
= safe_atou64(resume_offset_str
, &resume_offset
);
697 return log_debug_errno(r
, "Failed to parse value in /sys/power/resume_offset \"%s\": %m", resume_offset_str
);
700 if (resume_offset
> 0 && resume
== 0)
701 log_debug("Warning: found /sys/power/resume_offset==%" PRIu64
", but /sys/power/resume unset. Misconfiguration?",
704 *ret_resume
= resume
;
705 *ret_resume_offset
= resume_offset
;
711 * Determine if the HibernateLocation matches the resume= (device) and resume_offset= (file).
713 static bool location_is_resume_device(const HibernateLocation
*location
, dev_t sys_resume
, uint64_t sys_offset
) {
717 return sys_resume
> 0 &&
718 sys_resume
== location
->devno
&&
719 (sys_offset
== location
->offset
|| (sys_offset
> 0 && location
->offset
== UINT64_MAX
));
723 * Attempt to find the hibernation location by parsing /proc/swaps, /sys/power/resume, and
724 * /sys/power/resume_offset.
727 * 1 - Values are set in /sys/power/resume and /sys/power/resume_offset.
728 * ret_hibernate_location will represent matching /proc/swap entry if identified or NULL if not.
730 * 0 - No values are set in /sys/power/resume and /sys/power/resume_offset.
731 ret_hibernate_location will represent the highest priority swap with most remaining space discovered in /proc/swaps.
733 * Negative value in the case of error.
735 int find_hibernate_location(HibernateLocation
**ret_hibernate_location
) {
736 _cleanup_fclose_
FILE *f
= NULL
;
737 _cleanup_(hibernate_location_freep
) HibernateLocation
*hibernate_location
= NULL
;
738 dev_t sys_resume
= 0; /* Unnecessary initialization to appease gcc */
739 uint64_t sys_offset
= 0;
740 bool resume_match
= false;
743 /* read the /sys/power/resume & /sys/power/resume_offset values */
744 r
= read_resume_files(&sys_resume
, &sys_offset
);
748 f
= fopen("/proc/swaps", "re");
750 log_debug_errno(errno
, "Failed to open /proc/swaps: %m");
751 return errno
== ENOENT
? -EOPNOTSUPP
: -errno
; /* Convert swap not supported to a recognizable error */
754 (void) fscanf(f
, "%*s %*s %*s %*s %*s\n");
755 for (unsigned i
= 1;; i
++) {
756 _cleanup_(swap_entry_freep
) SwapEntry
*swap
= NULL
;
757 uint64_t swap_offset
= 0;
760 swap
= new0(SwapEntry
, 1);
765 "%ms " /* device/file */
766 "%ms " /* type of swap */
767 "%" PRIu64
/* swap size */
768 "%" PRIu64
/* used */
769 "%i\n", /* priority */
770 &swap
->device
, &swap
->type
, &swap
->size
, &swap
->used
, &swap
->priority
);
774 log_debug("Failed to parse /proc/swaps:%u, ignoring", i
);
778 if (streq(swap
->type
, "file")) {
779 if (endswith(swap
->device
, "\\040(deleted)")) {
780 log_debug("Ignoring deleted swap file '%s'.", swap
->device
);
784 r
= calculate_swap_file_offset(swap
, &swap_offset
);
788 } else if (streq(swap
->type
, "partition")) {
791 fn
= path_startswith(swap
->device
, "/dev/");
792 if (fn
&& startswith(fn
, "zram")) {
793 log_debug("%s: ignoring zram swap", swap
->device
);
798 log_debug("%s: swap type %s is unsupported for hibernation, ignoring", swap
->device
, swap
->type
);
802 /* prefer resume device or highest priority swap with most remaining space */
803 if (sys_resume
== 0) {
804 if (hibernate_location
&& swap
->priority
< hibernate_location
->swap
->priority
) {
805 log_debug("%s: ignoring device with lower priority", swap
->device
);
808 if (hibernate_location
&&
809 (swap
->priority
== hibernate_location
->swap
->priority
810 && swap
->size
- swap
->used
< hibernate_location
->swap
->size
- hibernate_location
->swap
->used
)) {
811 log_debug("%s: ignoring device with lower usable space", swap
->device
);
817 r
= swap_device_to_device_id(swap
, &swap_device
);
819 return log_debug_errno(r
, "%s: failed to query device number: %m", swap
->device
);
820 if (swap_device
== 0)
821 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: not backed by block device.", swap
->device
);
823 hibernate_location
= hibernate_location_free(hibernate_location
);
824 hibernate_location
= new(HibernateLocation
, 1);
825 if (!hibernate_location
)
828 *hibernate_location
= (HibernateLocation
) {
829 .devno
= swap_device
,
830 .offset
= swap_offset
,
831 .swap
= TAKE_PTR(swap
),
834 /* if the swap is the resume device, stop the loop */
835 if (location_is_resume_device(hibernate_location
, sys_resume
, sys_offset
)) {
836 log_debug("%s: device matches configured resume settings.", hibernate_location
->swap
->device
);
841 log_debug("%s: is a candidate device.", hibernate_location
->swap
->device
);
844 /* We found nothing at all */
845 if (!hibernate_location
)
846 return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS
),
847 "No possible swap partitions or files suitable for hibernation were found in /proc/swaps.");
849 /* resume= is set but a matching /proc/swaps entry was not found */
850 if (sys_resume
!= 0 && !resume_match
)
851 return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS
),
852 "No swap partitions or files matching resume config were found in /proc/swaps.");
854 if (hibernate_location
->offset
== UINT64_MAX
) {
856 return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS
), "Offset detection failed and /sys/power/resume_offset is not set.");
858 hibernate_location
->offset
= sys_offset
;
862 log_debug("Hibernation will attempt to use swap entry with path: %s, device: %u:%u, offset: %" PRIu64
", priority: %i",
863 hibernate_location
->swap
->device
, major(hibernate_location
->devno
), minor(hibernate_location
->devno
),
864 hibernate_location
->offset
, hibernate_location
->swap
->priority
);
866 log_debug("/sys/power/resume is not configured; attempting to hibernate with path: %s, device: %u:%u, offset: %" PRIu64
", priority: %i",
867 hibernate_location
->swap
->device
, major(hibernate_location
->devno
), minor(hibernate_location
->devno
),
868 hibernate_location
->offset
, hibernate_location
->swap
->priority
);
870 *ret_hibernate_location
= TAKE_PTR(hibernate_location
);
878 static bool enough_swap_for_hibernation(void) {
879 _cleanup_free_
char *active
= NULL
;
880 _cleanup_(hibernate_location_freep
) HibernateLocation
*hibernate_location
= NULL
;
881 unsigned long long act
= 0;
884 if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
887 r
= find_hibernate_location(&hibernate_location
);
891 /* If /sys/power/{resume,resume_offset} is configured but a matching entry
892 * could not be identified in /proc/swaps, user is likely using Btrfs with a swapfile;
893 * return true and let the system attempt hibernation.
895 if (r
> 0 && !hibernate_location
) {
896 log_debug("Unable to determine remaining swap space; hibernation may fail");
900 if (!hibernate_location
)
903 r
= get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE
, &active
);
905 log_debug_errno(r
, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
909 r
= safe_atollu(active
, &act
);
911 log_debug_errno(r
, "Failed to parse Active(anon) from /proc/meminfo: %s: %m", active
);
915 r
= act
<= (hibernate_location
->swap
->size
- hibernate_location
->swap
->used
) * HIBERNATION_SWAP_THRESHOLD
;
916 log_debug("%s swap for hibernation, Active(anon)=%llu kB, size=%" PRIu64
" kB, used=%" PRIu64
" kB, threshold=%.2g%%",
917 r
? "Enough" : "Not enough", act
, hibernate_location
->swap
->size
, hibernate_location
->swap
->used
, 100*HIBERNATION_SWAP_THRESHOLD
);
922 int read_fiemap(int fd
, struct fiemap
**ret
) {
923 _cleanup_free_
struct fiemap
*fiemap
= NULL
, *result_fiemap
= NULL
;
924 struct stat statinfo
;
925 uint32_t result_extents
= 0;
926 uint64_t fiemap_start
= 0, fiemap_length
;
927 const size_t n_extra
= DIV_ROUND_UP(sizeof(struct fiemap
), sizeof(struct fiemap_extent
));
929 if (fstat(fd
, &statinfo
) < 0)
930 return log_debug_errno(errno
, "Cannot determine file size: %m");
931 if (!S_ISREG(statinfo
.st_mode
))
933 fiemap_length
= statinfo
.st_size
;
935 /* Zero this out in case we run on a file with no extents */
936 fiemap
= calloc(n_extra
, sizeof(struct fiemap_extent
));
940 result_fiemap
= malloc_multiply(n_extra
, sizeof(struct fiemap_extent
));
944 /* XFS filesystem has incorrect implementation of fiemap ioctl and
945 * returns extents for only one block-group at a time, so we need
946 * to handle it manually, starting the next fiemap call from the end
949 while (fiemap_start
< fiemap_length
) {
950 *fiemap
= (struct fiemap
) {
951 .fm_start
= fiemap_start
,
952 .fm_length
= fiemap_length
,
953 .fm_flags
= FIEMAP_FLAG_SYNC
,
956 /* Find out how many extents there are */
957 if (ioctl(fd
, FS_IOC_FIEMAP
, fiemap
) < 0)
958 return log_debug_errno(errno
, "Failed to read extents: %m");
960 /* Nothing to process */
961 if (fiemap
->fm_mapped_extents
== 0)
964 /* Resize fiemap to allow us to read in the extents, result fiemap has to hold all
965 * the extents for the whole file. Add space for the initial struct fiemap. */
966 if (!greedy_realloc0((void**) &fiemap
, n_extra
+ fiemap
->fm_mapped_extents
, sizeof(struct fiemap_extent
)))
969 fiemap
->fm_extent_count
= fiemap
->fm_mapped_extents
;
970 fiemap
->fm_mapped_extents
= 0;
972 if (ioctl(fd
, FS_IOC_FIEMAP
, fiemap
) < 0)
973 return log_debug_errno(errno
, "Failed to read extents: %m");
975 /* Resize result_fiemap to allow us to copy in the extents */
976 if (!greedy_realloc((void**) &result_fiemap
,
977 n_extra
+ result_extents
+ fiemap
->fm_mapped_extents
, sizeof(struct fiemap_extent
)))
980 memcpy(result_fiemap
->fm_extents
+ result_extents
,
982 sizeof(struct fiemap_extent
) * fiemap
->fm_mapped_extents
);
984 result_extents
+= fiemap
->fm_mapped_extents
;
986 /* Highly unlikely that it is zero */
987 if (_likely_(fiemap
->fm_mapped_extents
> 0)) {
988 uint32_t i
= fiemap
->fm_mapped_extents
- 1;
990 fiemap_start
= fiemap
->fm_extents
[i
].fe_logical
+
991 fiemap
->fm_extents
[i
].fe_length
;
993 if (fiemap
->fm_extents
[i
].fe_flags
& FIEMAP_EXTENT_LAST
)
998 memcpy(result_fiemap
, fiemap
, sizeof(struct fiemap
));
999 result_fiemap
->fm_mapped_extents
= result_extents
;
1000 *ret
= TAKE_PTR(result_fiemap
);
1004 static int can_sleep_internal(const SleepConfig
*sleep_config
, SleepOperation operation
, bool check_allowed
);
1006 static bool can_s2h(const SleepConfig
*sleep_config
) {
1008 static const SleepOperation operations
[] = {
1015 if (!clock_supported(CLOCK_BOOTTIME_ALARM
)) {
1016 log_debug("CLOCK_BOOTTIME_ALARM is not supported.");
1020 for (size_t i
= 0; i
< ELEMENTSOF(operations
); i
++) {
1021 r
= can_sleep_internal(sleep_config
, operations
[i
], false);
1022 if (IN_SET(r
, 0, -ENOSPC
)) {
1023 log_debug("Unable to %s system.", sleep_operation_to_string(operations
[i
]));
1027 return log_debug_errno(r
, "Failed to check if %s is possible: %m", sleep_operation_to_string(operations
[i
]));
1033 static int can_sleep_internal(
1034 const SleepConfig
*sleep_config
,
1035 SleepOperation operation
,
1036 bool check_allowed
) {
1038 assert(operation
>= 0);
1039 assert(operation
< _SLEEP_OPERATION_MAX
);
1041 if (check_allowed
&& !sleep_config
->allow
[operation
]) {
1042 log_debug("Sleep mode \"%s\" is disabled by configuration.", sleep_operation_to_string(operation
));
1046 if (operation
== SLEEP_SUSPEND_THEN_HIBERNATE
)
1047 return can_s2h(sleep_config
);
1049 if (can_sleep_state(sleep_config
->states
[operation
]) <= 0 ||
1050 can_sleep_disk(sleep_config
->modes
[operation
]) <= 0)
1053 if (operation
== SLEEP_SUSPEND
)
1056 if (!enough_swap_for_hibernation())
1062 int can_sleep(SleepOperation operation
) {
1063 _cleanup_(free_sleep_configp
) SleepConfig
*sleep_config
= NULL
;
1066 r
= parse_sleep_config(&sleep_config
);
1070 return can_sleep_internal(sleep_config
, operation
, true);
1073 SleepConfig
* free_sleep_config(SleepConfig
*sc
) {
1077 for (SleepOperation i
= 0; i
< _SLEEP_OPERATION_MAX
; i
++) {
1078 strv_free(sc
->modes
[i
]);
1079 strv_free(sc
->states
[i
]);
1085 static const char* const sleep_operation_table
[_SLEEP_OPERATION_MAX
] = {
1086 [SLEEP_SUSPEND
] = "suspend",
1087 [SLEEP_HIBERNATE
] = "hibernate",
1088 [SLEEP_HYBRID_SLEEP
] = "hybrid-sleep",
1089 [SLEEP_SUSPEND_THEN_HIBERNATE
] = "suspend-then-hibernate",
1092 DEFINE_STRING_TABLE_LOOKUP(sleep_operation
, SleepOperation
);