From 75dc5f2e01ff9ec21aa29e7ee54a742d31e6aefc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 10 Apr 2018 11:23:46 +0200 Subject: [PATCH] shared/sleep-config: get rid of explicit allocation size calculation --- src/shared/sleep-config.c | 123 ++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index fdaa3f39b..15cd439c2 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -4,9 +4,23 @@ Copyright 2013 Zbigniew Jędrzejewski-Szmek Copyright 2018 Dell Inc. + + elogind is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + elogind is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with elogind; If not, see . ***/ //#include +//#include //#include //#include //#include @@ -180,13 +194,10 @@ int can_sleep_disk(char **types) { #define HIBERNATION_SWAP_THRESHOLD 0.98 -static int hibernation_partition_size(size_t *size, size_t *used) { +int find_hibernate_location(char **device, char **type, size_t *size, size_t *used) { _cleanup_fclose_ FILE *f; unsigned i; - assert(size); - assert(used); - f = fopen("/proc/swaps", "re"); if (!f) { log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, @@ -198,7 +209,7 @@ static int hibernation_partition_size(size_t *size, size_t *used) { (void) fscanf(f, "%*s %*s %*s %*s %*s\n"); for (i = 1;; i++) { - _cleanup_free_ char *dev = NULL, *type = NULL; + _cleanup_free_ char *dev_field = NULL, *type_field = NULL; size_t size_field, used_field; int k; @@ -208,7 +219,7 @@ static int hibernation_partition_size(size_t *size, size_t *used) { "%zu " /* swap size */ "%zu " /* used */ "%*i\n", /* priority */ - &dev, &type, &size_field, &used_field); + &dev_field, &type_field, &size_field, &used_field); if (k != 4) { if (k == EOF) break; @@ -217,13 +228,18 @@ static int hibernation_partition_size(size_t *size, size_t *used) { continue; } - if (streq(type, "partition") && endswith(dev, "\\040(deleted)")) { - log_warning("Ignoring deleted swapfile '%s'.", dev); + if (streq(type_field, "partition") && endswith(dev_field, "\\040(deleted)")) { + log_warning("Ignoring deleted swapfile '%s'.", dev_field); continue; } - - *size = size_field; - *used = used_field; + if (device) + *device = TAKE_PTR(dev_field); + if (type) + *type = TAKE_PTR(type_field); + if (size) + *size = size_field; + if (used) + *used = used_field; return 0; } @@ -242,7 +258,7 @@ static bool enough_memory_for_hibernation(void) { return true; #endif // 0 - r = hibernation_partition_size(&size, &used); + r = find_hibernate_location(NULL, NULL, &size, &used); if (r < 0) return false; @@ -266,6 +282,89 @@ static bool enough_memory_for_hibernation(void) { return r; } +int read_fiemap(int fd, struct fiemap **ret) { + _cleanup_free_ struct fiemap *fiemap = NULL, *result_fiemap = NULL; + struct stat statinfo; + uint32_t result_extents = 0; + uint64_t fiemap_start = 0, fiemap_length; + const size_t n_extra = DIV_ROUND_UP(sizeof(struct fiemap), sizeof(struct fiemap_extent)); + size_t fiemap_allocated = n_extra, result_fiemap_allocated = n_extra; + + if (fstat(fd, &statinfo) < 0) + return log_debug_errno(errno, "Cannot determine file size: %m"); + if (!S_ISREG(statinfo.st_mode)) + return -ENOTTY; + fiemap_length = statinfo.st_size; + + /* Zero this out in case we run on a file with no extents */ + fiemap = calloc(n_extra, sizeof(struct fiemap_extent)); + if (!fiemap) + return -ENOMEM; + + result_fiemap = malloc_multiply(n_extra, sizeof(struct fiemap_extent)); + if (!result_fiemap) + return -ENOMEM; + + /* XFS filesystem has incorrect implementation of fiemap ioctl and + * returns extents for only one block-group at a time, so we need + * to handle it manually, starting the next fiemap call from the end + * of the last extent + */ + while (fiemap_start < fiemap_length) { + *fiemap = (struct fiemap) { + .fm_start = fiemap_start, + .fm_length = fiemap_length, + .fm_flags = FIEMAP_FLAG_SYNC, + }; + + /* Find out how many extents there are */ + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) + return log_debug_errno(errno, "Failed to read extents: %m"); + + /* Nothing to process */ + if (fiemap->fm_mapped_extents == 0) + break; + + /* Resize fiemap to allow us to read in the extents, result fiemap has to hold all + * the extents for the whole file. Add space for the initial struct fiemap. */ + if (!greedy_realloc0((void**) &fiemap, &fiemap_allocated, + n_extra + fiemap->fm_mapped_extents, sizeof(struct fiemap_extent))) + return -ENOMEM; + + fiemap->fm_extent_count = fiemap->fm_mapped_extents; + fiemap->fm_mapped_extents = 0; + + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) + return log_debug_errno(errno, "Failed to read extents: %m"); + + /* Resize result_fiemap to allow us to copy in the extents */ + if (!greedy_realloc((void**) &result_fiemap, &result_fiemap_allocated, + n_extra + result_extents + fiemap->fm_mapped_extents, sizeof(struct fiemap_extent))) + return -ENOMEM; + + memcpy(result_fiemap->fm_extents + result_extents, + fiemap->fm_extents, + sizeof(struct fiemap_extent) * fiemap->fm_mapped_extents); + + result_extents += fiemap->fm_mapped_extents; + + /* Highly unlikely that it is zero */ + if (_likely_(fiemap->fm_mapped_extents > 0)) { + uint32_t i = fiemap->fm_mapped_extents - 1; + + fiemap_start = fiemap->fm_extents[i].fe_logical + + fiemap->fm_extents[i].fe_length; + + if (fiemap->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) + break; + } + } + + memcpy(result_fiemap, fiemap, sizeof(struct fiemap)); + result_fiemap->fm_mapped_extents = result_extents; + *ret = TAKE_PTR(result_fiemap); + return 0; +} #if 0 /// elogind has to do, or better, *can* do it differently static bool can_s2h(void) { -- 2.30.2