]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: Sum partitions size to get current disk size instead of using total size
authorJulian Sparber <julian@sparber.net>
Wed, 19 Nov 2025 17:30:04 +0000 (18:30 +0100)
committerJulian Sparber <julian@sparber.net>
Fri, 20 Feb 2026 10:19:10 +0000 (11:19 +0100)
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.

src/repart/repart.c

index ea44775eece9671c1b559233c8693273a0d0428e..31e6413f23da1b012d3ff6d7208d5e6a83c20dcd 100644 (file)
@@ -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, &current_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, &current_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)