summaryrefslogtreecommitdiff
path: root/src/shared/sleep-config.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-09-17 15:12:16 -0500
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-09-17 16:44:38 -0400
commit9fb3675e7ef0c6b7a1780980e51492c44fd1faaf (patch)
treec8ce724cb92108a6963e0e9a5428ac2214a7b417 /src/shared/sleep-config.c
parent22f5f6281fc25f43a85938e9dad2480b2595c471 (diff)
Use first partition in /proc/swaps for hibernation test
It seems that the kernel uses the first configured partition for hibernation. If it is too full, hibernation will fail. Test that directly.
Diffstat (limited to 'src/shared/sleep-config.c')
-rw-r--r--src/shared/sleep-config.c80
1 files changed, 63 insertions, 17 deletions
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 148c4dc617..d068bfce3c 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -165,24 +165,70 @@ int can_sleep_disk(char **types) {
#define HIBERNATION_SWAP_THRESHOLD 0.98
-static bool enough_memory_for_hibernation(void) {
- _cleanup_free_ char *active = NULL, *swapfree = NULL;
- unsigned long long act, swap;
- int r;
+static int hibernation_partition_size(size_t *size, size_t *used) {
+ _cleanup_fclose_ FILE *f;
+ int i;
+
+ assert(size);
+ assert(used);
+
+ f = fopen("/proc/swaps", "r");
+ if (!f) {
+ log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+ "Failed to retrieve open /proc/swaps: %m");
+ assert(errno > 0);
+ return -errno;
+ }
- r = get_status_field("/proc/meminfo", "\nSwapFree:", &swapfree);
- if (r < 0) {
- log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING,
- "Failed to retrieve SwapFree from /proc/meminfo: %s", strerror(-r));
- return false;
+ (void) fscanf(f, "%*s %*s %*s %*s %*s\n");
+
+ for (i = 1;; i++) {
+ _cleanup_free_ char *dev = NULL, *d = NULL, *type = NULL;
+ size_t size_field, used_field;
+ int k;
+
+ k = fscanf(f,
+ "%ms " /* device/file */
+ "%ms " /* type of swap */
+ "%zd " /* swap size */
+ "%zd " /* used */
+ "%*i\n", /* priority */
+ &dev, &type, &size_field, &used_field);
+ if (k != 4) {
+ if (k == EOF)
+ break;
+
+ log_warning("Failed to parse /proc/swaps:%u", i);
+ continue;
+ }
+
+ d = cunescape(dev);
+ if (!d)
+ return -ENOMEM;
+
+ if (!streq(type, "partition")) {
+ log_debug("Partition %s has type %s, ignoring.", d, type);
+ continue;
+ }
+
+ *size = size_field;
+ *used = used_field;
+ return 0;
}
- r = safe_atollu(swapfree, &swap);
- if (r < 0) {
- log_error("Failed to parse SwapFree from /proc/meminfo: %s: %s",
- swapfree, strerror(-r));
+ log_debug("No swap partitions were found.");
+ return -ENOSYS;
+}
+
+static bool enough_memory_for_hibernation(void) {
+ _cleanup_free_ char *active = NULL;
+ unsigned long long act;
+ size_t size, used;
+ int r;
+
+ r = hibernation_partition_size(&size, &used);
+ if (r < 0)
return false;
- }
r = get_status_field("/proc/meminfo", "\nActive(anon):", &active);
if (r < 0) {
@@ -197,9 +243,9 @@ static bool enough_memory_for_hibernation(void) {
return false;
}
- r = act <= swap * HIBERNATION_SWAP_THRESHOLD;
- log_debug("Hibernation is %spossible, Active(anon)=%llu kB, SwapFree=%llu kB, threshold=%.2g%%",
- r ? "" : "im", act, swap, 100*HIBERNATION_SWAP_THRESHOLD);
+ r = act <= (size - used) * HIBERNATION_SWAP_THRESHOLD;
+ log_debug("Hibernation is %spossible, Active(anon)=%llu kB, size=%zu kB, used=%zu kB, threshold=%.2g%%",
+ r ? "" : "im", act, size, used, 100*HIBERNATION_SWAP_THRESHOLD);
return r;
}