From: Julian Sparber Date: Wed, 19 Nov 2025 17:30:04 +0000 (+0100) Subject: repart: Sum partitions size to get current disk size instead of using total size X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5036c9f59634326039f06f70e0b0c89890943884;p=thirdparty%2Fsystemd.git repart: Sum partitions size to get current disk size instead of using total size When working on disks the disk may have a total size bigger then the actual allocated size, therefore sum up the current partitions to calculate the current disk size instead of asuming that the entire disk is currently allocated. --- diff --git a/src/repart/repart.c b/src/repart/repart.c index ea44775eece..31e6413f23d 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -10065,44 +10065,52 @@ done: static int determine_auto_size( Context *c, int level, - bool ignore_allocated, /* If true, determines unallocated space needed */ - uint64_t *ret) { + uint64_t *ret_current_size, + uint64_t *ret_minimal_size) { - uint64_t sum; + uint64_t current_size, minimal_size; assert(c); - sum = round_up_size(GPT_METADATA_SIZE, 4096); + minimal_size = round_up_size(GPT_METADATA_SIZE, 4096); + + if (c->from_scratch) + current_size = 0; + else + current_size = round_up_size(GPT_METADATA_SIZE, 4096); LIST_FOREACH(partitions, p, c->partitions) { uint64_t m; + if (PARTITION_EXISTS(p)) + current_size += p->current_size; + if (p->dropped || PARTITION_SUPPRESSED(p)) continue; m = partition_min_size_with_padding(c, p); - if (m > UINT64_MAX - sum) + if (m > UINT64_MAX - minimal_size) return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Image would grow too large, refusing."); - if (ignore_allocated && PARTITION_EXISTS(p)) - m = LESS_BY(m, p->current_size + p->current_padding); - - sum += m; + minimal_size += m; } - if (c->total != UINT64_MAX) + if (current_size != 0) /* Image already allocated? Then show its size. */ log_full(level, "Automatically determined minimal disk image size as %s, current block device/image size is %s.", - FORMAT_BYTES(sum), FORMAT_BYTES(c->total)); + FORMAT_BYTES(minimal_size), FORMAT_BYTES(current_size)); else /* If the image is being created right now, then it has no previous size, suppress any comment about it hence. */ log_full(level, "Automatically determined minimal disk image size as %s.", - FORMAT_BYTES(sum)); + FORMAT_BYTES(minimal_size)); + + if (ret_current_size) + *ret_current_size = current_size; + if (ret_minimal_size) + *ret_minimal_size = minimal_size; - if (ret) - *ret = sum; return 0; } @@ -10341,53 +10349,56 @@ static int vl_method_run( /* If we have no node, just sum up how much space we need */ if (!context->node) { /* Check if space issue is caused by the whole disk being too small */ - uint64_t size; - r = determine_auto_size(context, LOG_DEBUG, /* ignore_allocated= */ false, &size); + uint64_t minimal_size; + r = determine_auto_size(context, LOG_DEBUG, /* ret_current_size= */ NULL, &minimal_size); if (r < 0) return r; return sd_varlink_replybo( link, - SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", size)); + SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", minimal_size)); } r = context_ponder(context); if (r == -ENOSPC) { + uint64_t current_size, minimal_size; + + r = determine_auto_size(context, LOG_DEBUG, ¤t_size, &minimal_size); + if (r < 0) + return r; + /* Check if space issue is caused by the whole disk being too small */ - uint64_t size = UINT64_MAX; - (void) determine_auto_size(context, LOG_DEBUG, /* ignore_allocated= */ false, &size); - if (size != UINT64_MAX && context->total != UINT64_MAX && size > context->total) + if (minimal_size > context->total) return sd_varlink_errorbo( link, "io.systemd.Repart.DiskTooSmall", - SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", size), - SD_JSON_BUILD_PAIR_UNSIGNED("currentSizeBytes", context->total)); + SD_JSON_BUILD_PAIR_UNSIGNED("currentSizeBytes", current_size), + SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", minimal_size)); /* Or if the disk would fit, but theres's not enough unallocated space */ - uint64_t need_free = UINT64_MAX; - (void) determine_auto_size(context, LOG_DEBUG, /* ignore_allocated= */ true, &need_free); + uint64_t need_free = LESS_BY(minimal_size, current_size); return sd_varlink_errorbo( link, "io.systemd.Repart.InsufficientFreeSpace", - JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("minimalSizeBytes", size, UINT64_MAX), - JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("needFreeBytes", need_free, UINT64_MAX), - JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("currentSizeBytes", context->total, UINT64_MAX)); + SD_JSON_BUILD_PAIR_UNSIGNED("currentSizeBytes", current_size), + JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("needFreeBytes", need_free), + SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", minimal_size)); } if (r < 0) return r; if (p.dry_run) { - uint64_t size; + uint64_t current_size, minimal_size; /* If we are doing a dry-run, report the minimal size. */ - r = determine_auto_size(context, LOG_DEBUG, /* ignore_allocated= */ false, &size); + r = determine_auto_size(context, LOG_DEBUG, ¤t_size, &minimal_size); if (r < 0) return r; return sd_varlink_replybo( link, - SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", size), - JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("currentSizeBytes", context->total, UINT64_MAX)); + SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", minimal_size), + SD_JSON_BUILD_PAIR_UNSIGNED("currentSizeBytes", current_size)); } r = context_write_partition_table(context); @@ -10633,12 +10644,12 @@ static int run(int argc, char *argv[]) { return r; if (arg_node_none) { - (void) determine_auto_size(context, LOG_INFO, /* ignore_allocated= */ false, /* ret= */ NULL); + (void) determine_auto_size(context, LOG_INFO, /* ret_current_size= */ NULL, /* ret_minimal_size= */ NULL); return 0; } if (arg_size_auto) { - r = determine_auto_size(context, LOG_INFO, /* ignore_allocated= */ false, &arg_size); + r = determine_auto_size(context, LOG_INFO, /* ret_current_size= */ NULL, &arg_size); if (r < 0) return r; @@ -10663,7 +10674,7 @@ static int run(int argc, char *argv[]) { r = context_ponder(context); if (r == -ENOSPC) { /* When we hit space issues, tell the user the minimal size. */ - (void) determine_auto_size(context, LOG_INFO, /* ignore_allocated= */ false, /* ret= */ NULL); + (void) determine_auto_size(context, LOG_INFO, /* ret_current_size= */ NULL, /* ret_minimal_size= */ NULL); return r; } if (r < 0)