diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2013-09-17 15:12:16 -0500 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2013-09-17 16:44:38 -0400 |
commit | 9fb3675e7ef0c6b7a1780980e51492c44fd1faaf (patch) | |
tree | c8ce724cb92108a6963e0e9a5428ac2214a7b417 /src/shared | |
parent | 22f5f6281fc25f43a85938e9dad2480b2595c471 (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')
-rw-r--r-- | src/shared/sleep-config.c | 80 |
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; } |