594167
From 389cc9af2087aa5369ac6bf0124d14877d541966 Mon Sep 17 00:00:00 2001
594167
From: Lennart Poettering <lennart@poettering.net>
594167
Date: Fri, 4 Feb 2022 17:39:44 +0100
594167
Subject: [PATCH] repart: fix sector size handling
594167
594167
This queries the sector size from libfdisk instead of assuming 512, and
594167
uses that when converting from bytes to the offset/size values libfdisk
594167
expects.
594167
594167
This is an alternative to Tom Yan's #21823, but prefers using libfdisk's
594167
own ideas of the sector size instead of going directly to the backing
594167
device via ioctls. (libfdisk can after all also operate on regular
594167
files, where the sector size concept doesn't necessarily apply the same
594167
way.)
594167
594167
This also makes the "grain" variable, i.e. how we'll align the
594167
partitions. Previously this was hardcoded to 4K, and that still will be
594167
the minimum grain we use, but should the sector size be larger than that
594167
we'll use the next multiple of the sector size instead.
594167
594167
(cherry picked from commit 994b303123ebe6a140bf3e56c66aa66119ae7d95)
594167
594167
Related: #2017035
594167
---
594167
 src/partition/repart.c | 212 +++++++++++++++++++++++++----------------
594167
 1 file changed, 132 insertions(+), 80 deletions(-)
594167
594167
diff --git a/src/partition/repart.c b/src/partition/repart.c
594167
index d08f47f2c4..0862a37a8d 100644
594167
--- a/src/partition/repart.c
594167
+++ b/src/partition/repart.c
594167
@@ -195,6 +195,8 @@ struct Context {
594167
         uint64_t start, end, total;
594167
 
594167
         struct fdisk_context *fdisk_context;
594167
+        uint64_t sector_size;
594167
+        uint64_t grain_size;
594167
 
594167
         sd_id128_t seed;
594167
 };
594167
@@ -407,9 +409,12 @@ static bool context_drop_one_priority(Context *context) {
594167
         return true;
594167
 }
594167
 
594167
-static uint64_t partition_min_size(const Partition *p) {
594167
+static uint64_t partition_min_size(Context *context, const Partition *p) {
594167
         uint64_t sz;
594167
 
594167
+        assert(context);
594167
+        assert(p);
594167
+
594167
         /* Calculate the disk space we really need at minimum for this partition. If the partition already
594167
          * exists the current size is what we really need. If it doesn't exist yet refuse to allocate less
594167
          * than 4K.
594167
@@ -428,50 +433,60 @@ static uint64_t partition_min_size(const Partition *p) {
594167
                 uint64_t d = 0;
594167
 
594167
                 if (p->encrypt != ENCRYPT_OFF)
594167
-                        d += round_up_size(LUKS2_METADATA_SIZE, 4096);
594167
+                        d += round_up_size(LUKS2_METADATA_SIZE, context->grain_size);
594167
 
594167
                 if (p->copy_blocks_size != UINT64_MAX)
594167
-                        d += round_up_size(p->copy_blocks_size, 4096);
594167
+                        d += round_up_size(p->copy_blocks_size, context->grain_size);
594167
                 else if (p->format || p->encrypt != ENCRYPT_OFF) {
594167
                         uint64_t f;
594167
 
594167
                         /* If we shall synthesize a file system, take minimal fs size into account (assumed to be 4K if not known) */
594167
-                        f = p->format ? minimal_size_by_fs_name(p->format) : UINT64_MAX;
594167
-                        d += f == UINT64_MAX ? 4096 : f;
594167
+                        f = p->format ? round_up_size(minimal_size_by_fs_name(p->format), context->grain_size) : UINT64_MAX;
594167
+                        d += f == UINT64_MAX ? context->grain_size : f;
594167
                 }
594167
 
594167
                 if (d > sz)
594167
                         sz = d;
594167
         }
594167
 
594167
-        return MAX(p->size_min != UINT64_MAX ? p->size_min : DEFAULT_MIN_SIZE, sz);
594167
+        return MAX(round_up_size(p->size_min != UINT64_MAX ? p->size_min : DEFAULT_MIN_SIZE, context->grain_size), sz);
594167
 }
594167
 
594167
-static uint64_t partition_max_size(const Partition *p) {
594167
+static uint64_t partition_max_size(const Context *context, const Partition *p) {
594167
+        uint64_t sm;
594167
+
594167
         /* Calculate how large the partition may become at max. This is generally the configured maximum
594167
          * size, except when it already exists and is larger than that. In that case it's the existing size,
594167
          * since we never want to shrink partitions. */
594167
 
594167
+        assert(context);
594167
+        assert(p);
594167
+
594167
         if (PARTITION_IS_FOREIGN(p)) {
594167
                 /* Don't allow changing size of partitions not managed by us */
594167
                 assert(p->current_size != UINT64_MAX);
594167
                 return p->current_size;
594167
         }
594167
 
594167
+        sm = round_down_size(p->size_max, context->grain_size);
594167
+
594167
         if (p->current_size != UINT64_MAX)
594167
-                return MAX(p->current_size, p->size_max);
594167
+                return MAX(p->current_size, sm);
594167
 
594167
-        return p->size_max;
594167
+        return sm;
594167
 }
594167
 
594167
-static uint64_t partition_min_size_with_padding(const Partition *p) {
594167
+static uint64_t partition_min_size_with_padding(Context *context, const Partition *p) {
594167
         uint64_t sz;
594167
 
594167
         /* Calculate the disk space we need for this partition plus any free space coming after it. This
594167
          * takes user configured padding into account as well as any additional whitespace needed to align
594167
          * the next partition to 4K again. */
594167
 
594167
-        sz = partition_min_size(p);
594167
+        assert(context);
594167
+        assert(p);
594167
+
594167
+        sz = partition_min_size(context, p);
594167
 
594167
         if (p->padding_min != UINT64_MAX)
594167
                 sz += p->padding_min;
594167
@@ -479,11 +494,11 @@ static uint64_t partition_min_size_with_padding(const Partition *p) {
594167
         if (PARTITION_EXISTS(p)) {
594167
                 /* If the partition wasn't aligned, add extra space so that any we might add will be aligned */
594167
                 assert(p->offset != UINT64_MAX);
594167
-                return round_up_size(p->offset + sz, 4096) - p->offset;
594167
+                return round_up_size(p->offset + sz, context->grain_size) - p->offset;
594167
         }
594167
 
594167
         /* If this is a new partition we'll place it aligned, hence we just need to round up the required size here */
594167
-        return round_up_size(sz, 4096);
594167
+        return round_up_size(sz, context->grain_size);
594167
 }
594167
 
594167
 static uint64_t free_area_available(const FreeArea *a) {
594167
@@ -495,9 +510,12 @@ static uint64_t free_area_available(const FreeArea *a) {
594167
         return a->size - a->allocated;
594167
 }
594167
 
594167
-static uint64_t free_area_available_for_new_partitions(const FreeArea *a) {
594167
+static uint64_t free_area_available_for_new_partitions(Context *context, const FreeArea *a) {
594167
         uint64_t avail;
594167
 
594167
+        assert(context);
594167
+        assert(a);
594167
+
594167
         /* Similar to free_area_available(), but takes into account that the required size and padding of the
594167
          * preceding partition is honoured. */
594167
 
594167
@@ -505,16 +523,16 @@ static uint64_t free_area_available_for_new_partitions(const FreeArea *a) {
594167
         if (a->after) {
594167
                 uint64_t need, space_end, new_end;
594167
 
594167
-                need = partition_min_size_with_padding(a->after);
594167
+                need = partition_min_size_with_padding(context, a->after);
594167
 
594167
                 assert(a->after->offset != UINT64_MAX);
594167
                 assert(a->after->current_size != UINT64_MAX);
594167
 
594167
                 /* Calculate where the free area ends, based on the offset of the partition preceding it */
594167
-                space_end = round_up_size(a->after->offset + a->after->current_size, 4096) + avail;
594167
+                space_end = round_up_size(a->after->offset + a->after->current_size, context->grain_size) + avail;
594167
 
594167
                 /* Calculate where the partition would end when we give it as much as it needs */
594167
-                new_end = round_up_size(a->after->offset + need, 4096);
594167
+                new_end = round_up_size(a->after->offset + need, context->grain_size);
594167
 
594167
                 /* Calculate saturated difference of the two: that's how much we have free for other partitions */
594167
                 return LESS_BY(space_end, new_end);
594167
@@ -523,15 +541,18 @@ static uint64_t free_area_available_for_new_partitions(const FreeArea *a) {
594167
         return avail;
594167
 }
594167
 
594167
-static int free_area_compare(FreeArea *const *a, FreeArea *const*b) {
594167
-        return CMP(free_area_available_for_new_partitions(*a),
594167
-                   free_area_available_for_new_partitions(*b));
594167
+static int free_area_compare(FreeArea *const *a, FreeArea *const*b, Context *context) {
594167
+        assert(context);
594167
+
594167
+        return CMP(free_area_available_for_new_partitions(context, *a),
594167
+                   free_area_available_for_new_partitions(context, *b));
594167
 }
594167
 
594167
-static uint64_t charge_size(uint64_t total, uint64_t amount) {
594167
+static uint64_t charge_size(Context *context, uint64_t total, uint64_t amount) {
594167
+        assert(context);
594167
         /* Subtract the specified amount from total, rounding up to multiple of 4K if there's room */
594167
         assert(amount <= total);
594167
-        return LESS_BY(total, round_up_size(amount, 4096));
594167
+        return LESS_BY(total, round_up_size(amount, context->grain_size));
594167
 }
594167
 
594167
 static uint64_t charge_weight(uint64_t total, uint64_t amount) {
594167
@@ -545,14 +566,14 @@ static bool context_allocate_partitions(Context *context, uint64_t *ret_largest_
594167
         assert(context);
594167
 
594167
         /* Sort free areas by size, putting smallest first */
594167
-        typesafe_qsort(context->free_areas, context->n_free_areas, free_area_compare);
594167
+        typesafe_qsort_r(context->free_areas, context->n_free_areas, free_area_compare, context);
594167
 
594167
         /* In any case return size of the largest free area (i.e. not the size of all free areas
594167
          * combined!) */
594167
         if (ret_largest_free_area)
594167
                 *ret_largest_free_area =
594167
                         context->n_free_areas == 0 ? 0 :
594167
-                        free_area_available_for_new_partitions(context->free_areas[context->n_free_areas-1]);
594167
+                        free_area_available_for_new_partitions(context, context->free_areas[context->n_free_areas-1]);
594167
 
594167
         /* A simple first-fit algorithm. We return true if we can fit the partitions in, otherwise false. */
594167
         LIST_FOREACH(partitions, p, context->partitions) {
594167
@@ -565,13 +586,13 @@ static bool context_allocate_partitions(Context *context, uint64_t *ret_largest_
594167
                         continue;
594167
 
594167
                 /* How much do we need to fit? */
594167
-                required = partition_min_size_with_padding(p);
594167
-                assert(required % 4096 == 0);
594167
+                required = partition_min_size_with_padding(context, p);
594167
+                assert(required % context->grain_size == 0);
594167
 
594167
                 for (size_t i = 0; i < context->n_free_areas; i++) {
594167
                         a = context->free_areas[i];
594167
 
594167
-                        if (free_area_available_for_new_partitions(a) >= required) {
594167
+                        if (free_area_available_for_new_partitions(context, a) >= required) {
594167
                                 fits = true;
594167
                                 break;
594167
                         }
594167
@@ -683,8 +704,8 @@ static int context_grow_partitions_phase(
594167
                         if (r < 0)
594167
                                 return r;
594167
 
594167
-                        rsz = partition_min_size(p);
594167
-                        xsz = partition_max_size(p);
594167
+                        rsz = partition_min_size(context, p);
594167
+                        xsz = partition_max_size(context, p);
594167
 
594167
                         if (phase == PHASE_OVERCHARGE && rsz > share) {
594167
                                 /* This partition needs more than its calculated share. Let's assign
594167
@@ -712,13 +733,13 @@ static int context_grow_partitions_phase(
594167
                                         /* Never change of foreign partitions (i.e. those we don't manage) */
594167
                                         p->new_size = p->current_size;
594167
                                 else
594167
-                                        p->new_size = MAX(round_down_size(share, 4096), rsz);
594167
+                                        p->new_size = MAX(round_down_size(share, context->grain_size), rsz);
594167
 
594167
                                 charge = true;
594167
                         }
594167
 
594167
                         if (charge) {
594167
-                                *span = charge_size(*span, p->new_size);
594167
+                                *span = charge_size(context, *span, p->new_size);
594167
                                 *weight_sum = charge_weight(*weight_sum, p->weight);
594167
                         }
594167
 
594167
@@ -742,7 +763,7 @@ static int context_grow_partitions_phase(
594167
                                 charge = try_again = true;
594167
                         } else if (phase == PHASE_DISTRIBUTE) {
594167
 
594167
-                                p->new_padding = round_down_size(share, 4096);
594167
+                                p->new_padding = round_down_size(share, context->grain_size);
594167
                                 if (p->padding_min != UINT64_MAX && p->new_padding < p->padding_min)
594167
                                         p->new_padding = p->padding_min;
594167
 
594167
@@ -750,7 +771,7 @@ static int context_grow_partitions_phase(
594167
                         }
594167
 
594167
                         if (charge) {
594167
-                                *span = charge_size(*span, p->new_padding);
594167
+                                *span = charge_size(context, *span, p->new_padding);
594167
                                 *weight_sum = charge_weight(*weight_sum, p->padding_weight);
594167
                         }
594167
 
594167
@@ -779,7 +800,7 @@ static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) {
594167
                 assert(a->after->offset != UINT64_MAX);
594167
                 assert(a->after->current_size != UINT64_MAX);
594167
 
594167
-                span += round_up_size(a->after->offset + a->after->current_size, 4096) - a->after->offset;
594167
+                span += round_up_size(a->after->offset + a->after->current_size, context->grain_size) - a->after->offset;
594167
         }
594167
 
594167
         for (GrowPartitionPhase phase = 0; phase < _GROW_PARTITION_PHASE_MAX;) {
594167
@@ -799,13 +820,13 @@ static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) {
594167
                 assert(a->after->new_size != UINT64_MAX);
594167
 
594167
                 /* Calculate new size and align (but ensure this doesn't shrink the size) */
594167
-                m = MAX(a->after->new_size, round_down_size(a->after->new_size + span, 4096));
594167
+                m = MAX(a->after->new_size, round_down_size(a->after->new_size + span, context->grain_size));
594167
 
594167
-                xsz = partition_max_size(a->after);
594167
+                xsz = partition_max_size(context, a->after);
594167
                 if (xsz != UINT64_MAX && m > xsz)
594167
                         m = xsz;
594167
 
594167
-                span = charge_size(span, m - a->after->new_size);
594167
+                span = charge_size(context, span, m - a->after->new_size);
594167
                 a->after->new_size = m;
594167
         }
594167
 
594167
@@ -824,13 +845,13 @@ static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) {
594167
                                 continue;
594167
 
594167
                         assert(p->new_size != UINT64_MAX);
594167
-                        m = MAX(p->new_size, round_down_size(p->new_size + span, 4096));
594167
+                        m = MAX(p->new_size, round_down_size(p->new_size + span, context->grain_size));
594167
 
594167
-                        xsz = partition_max_size(p);
594167
+                        xsz = partition_max_size(context, p);
594167
                         if (xsz != UINT64_MAX && m > xsz)
594167
                                 m = xsz;
594167
 
594167
-                        span = charge_size(span, m - p->new_size);
594167
+                        span = charge_size(context, span, m - p->new_size);
594167
                         p->new_size = m;
594167
 
594167
                         if (span == 0)
594167
@@ -910,7 +931,7 @@ static void context_place_partitions(Context *context) {
594167
                 } else
594167
                         start = context->start;
594167
 
594167
-                start = round_up_size(start, 4096);
594167
+                start = round_up_size(start, context->grain_size);
594167
                 left = a->size;
594167
 
594167
                 LIST_FOREACH(partitions, p, context->partitions) {
594167
@@ -1422,6 +1443,8 @@ static int determine_current_padding(
594167
                 struct fdisk_context *c,
594167
                 struct fdisk_table *t,
594167
                 struct fdisk_partition *p,
594167
+                uint64_t secsz,
594167
+                uint64_t grainsz,
594167
                 uint64_t *ret) {
594167
 
594167
         size_t n_partitions;
594167
@@ -1435,8 +1458,8 @@ static int determine_current_padding(
594167
                 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition has no end!");
594167
 
594167
         offset = fdisk_partition_get_end(p);
594167
-        assert(offset < UINT64_MAX / 512);
594167
-        offset *= 512;
594167
+        assert(offset < UINT64_MAX / secsz);
594167
+        offset *= secsz;
594167
 
594167
         n_partitions = fdisk_table_get_nents(t);
594167
         for (size_t i = 0; i < n_partitions; i++)  {
594167
@@ -1454,8 +1477,8 @@ static int determine_current_padding(
594167
                         continue;
594167
 
594167
                 start = fdisk_partition_get_start(q);
594167
-                assert(start < UINT64_MAX / 512);
594167
-                start *= 512;
594167
+                assert(start < UINT64_MAX / secsz);
594167
+                start *= secsz;
594167
 
594167
                 if (start >= offset && (next == UINT64_MAX || next > start))
594167
                         next = start;
594167
@@ -1467,16 +1490,16 @@ static int determine_current_padding(
594167
                 assert(next < UINT64_MAX);
594167
                 next++; /* The last LBA is one sector before the end */
594167
 
594167
-                assert(next < UINT64_MAX / 512);
594167
-                next *= 512;
594167
+                assert(next < UINT64_MAX / secsz);
594167
+                next *= secsz;
594167
 
594167
                 if (offset > next)
594167
                         return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end.");
594167
         }
594167
 
594167
         assert(next >= offset);
594167
-        offset = round_up_size(offset, 4096);
594167
-        next = round_down_size(next, 4096);
594167
+        offset = round_up_size(offset, grainsz);
594167
+        next = round_down_size(next, grainsz);
594167
 
594167
         *ret = LESS_BY(next, offset); /* Saturated subtraction, rounding might have fucked things up */
594167
         return 0;
594167
@@ -1549,6 +1572,8 @@ static int context_load_partition_table(
594167
         bool from_scratch = false;
594167
         sd_id128_t disk_uuid;
594167
         size_t n_partitions;
594167
+        unsigned long secsz;
594167
+        uint64_t grainsz;
594167
         int r;
594167
 
594167
         assert(context);
594167
@@ -1583,8 +1608,12 @@ static int context_load_partition_table(
594167
                 if (r < 0)
594167
                         return log_error_errno(errno, "Failed to stat block device '%s': %m", node);
594167
 
594167
-                if (S_ISREG(st.st_mode) && st.st_size == 0)
594167
+                if (S_ISREG(st.st_mode) && st.st_size == 0) {
594167
+                        /* User the fallback values if we have no better idea */
594167
+                        context->sector_size = 512;
594167
+                        context->grain_size = 4096;
594167
                         return /* from_scratch = */ true;
594167
+                }
594167
 
594167
                 r = -EINVAL;
594167
         }
594167
@@ -1602,6 +1631,23 @@ static int context_load_partition_table(
594167
         if (flock(fdisk_get_devfd(c), arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
594167
                 return log_error_errno(errno, "Failed to lock block device: %m");
594167
 
594167
+        /* The offsets/sizes libfdisk returns to us will be in multiple of the sector size of the
594167
+         * device. This is typically 512, and sometimes 4096. Let's query libfdisk once for it, and then use
594167
+         * it for all our needs. Note that the values we use ourselves always are in bytes though, thus mean
594167
+         * the same thing universally. Also note that regardless what kind of sector size is in use we'll
594167
+         * place partitions at multiples of 4K. */
594167
+        secsz = fdisk_get_sector_size(c);
594167
+
594167
+        /* Insist on a power of two, and that it's a multiple of 512, i.e. the traditional sector size. */
594167
+        if (secsz < 512 || secsz != 1UL << log2u64(secsz))
594167
+                return log_error_errno(errno, "Sector size %lu is not a power of two larger than 512? Refusing.", secsz);
594167
+
594167
+        /* Use at least 4K, and ensure it's a multiple of the sector size, regardless if that is smaller or
594167
+         * larger */
594167
+        grainsz = secsz < 4096 ? 4096 : secsz;
594167
+
594167
+        log_debug("Sector size of device is %lu bytes. Using grain size of %" PRIu64 ".", secsz, grainsz);
594167
+
594167
         switch (arg_empty) {
594167
 
594167
         case EMPTY_REFUSE:
594167
@@ -1732,12 +1778,12 @@ static int context_load_partition_table(
594167
                 }
594167
 
594167
                 sz = fdisk_partition_get_size(p);
594167
-                assert_se(sz <= UINT64_MAX/512);
594167
-                sz *= 512;
594167
+                assert_se(sz <= UINT64_MAX/secsz);
594167
+                sz *= secsz;
594167
 
594167
                 start = fdisk_partition_get_start(p);
594167
-                assert_se(start <= UINT64_MAX/512);
594167
-                start *= 512;
594167
+                assert_se(start <= UINT64_MAX/secsz);
594167
+                start *= secsz;
594167
 
594167
                 partno = fdisk_partition_get_partno(p);
594167
 
594167
@@ -1762,7 +1808,7 @@ static int context_load_partition_table(
594167
                                 pp->current_partition = p;
594167
                                 fdisk_ref_partition(p);
594167
 
594167
-                                r = determine_current_padding(c, t, p, &pp->current_padding);
594167
+                                r = determine_current_padding(c, t, p, secsz, grainsz, &pp->current_padding);
594167
                                 if (r < 0)
594167
                                         return r;
594167
 
594167
@@ -1795,7 +1841,7 @@ static int context_load_partition_table(
594167
                         np->current_partition = p;
594167
                         fdisk_ref_partition(p);
594167
 
594167
-                        r = determine_current_padding(c, t, p, &np->current_padding);
594167
+                        r = determine_current_padding(c, t, p, secsz, grainsz, &np->current_padding);
594167
                         if (r < 0)
594167
                                 return r;
594167
 
594167
@@ -1812,26 +1858,26 @@ static int context_load_partition_table(
594167
 
594167
 add_initial_free_area:
594167
         nsectors = fdisk_get_nsectors(c);
594167
-        assert(nsectors <= UINT64_MAX/512);
594167
-        nsectors *= 512;
594167
+        assert(nsectors <= UINT64_MAX/secsz);
594167
+        nsectors *= secsz;
594167
 
594167
         first_lba = fdisk_get_first_lba(c);
594167
-        assert(first_lba <= UINT64_MAX/512);
594167
-        first_lba *= 512;
594167
+        assert(first_lba <= UINT64_MAX/secsz);
594167
+        first_lba *= secsz;
594167
 
594167
         last_lba = fdisk_get_last_lba(c);
594167
         assert(last_lba < UINT64_MAX);
594167
         last_lba++;
594167
-        assert(last_lba <= UINT64_MAX/512);
594167
-        last_lba *= 512;
594167
+        assert(last_lba <= UINT64_MAX/secsz);
594167
+        last_lba *= secsz;
594167
 
594167
         assert(last_lba >= first_lba);
594167
 
594167
         if (left_boundary == UINT64_MAX) {
594167
                 /* No partitions at all? Then the whole disk is up for grabs. */
594167
 
594167
-                first_lba = round_up_size(first_lba, 4096);
594167
-                last_lba = round_down_size(last_lba, 4096);
594167
+                first_lba = round_up_size(first_lba, grainsz);
594167
+                last_lba = round_down_size(last_lba, grainsz);
594167
 
594167
                 if (last_lba > first_lba) {
594167
                         r = context_add_free_area(context, last_lba - first_lba, NULL);
594167
@@ -1842,9 +1888,9 @@ add_initial_free_area:
594167
                 /* Add space left of first partition */
594167
                 assert(left_boundary >= first_lba);
594167
 
594167
-                first_lba = round_up_size(first_lba, 4096);
594167
-                left_boundary = round_down_size(left_boundary, 4096);
594167
-                last_lba = round_down_size(last_lba, 4096);
594167
+                first_lba = round_up_size(first_lba, grainsz);
594167
+                left_boundary = round_down_size(left_boundary, grainsz);
594167
+                last_lba = round_down_size(last_lba, grainsz);
594167
 
594167
                 if (left_boundary > first_lba) {
594167
                         r = context_add_free_area(context, left_boundary - first_lba, NULL);
594167
@@ -1856,6 +1902,8 @@ add_initial_free_area:
594167
         context->start = first_lba;
594167
         context->end = last_lba;
594167
         context->total = nsectors;
594167
+        context->sector_size = secsz;
594167
+        context->grain_size = grainsz;
594167
         context->fdisk_context = TAKE_PTR(c);
594167
 
594167
         return from_scratch;
594167
@@ -2360,7 +2408,7 @@ static int context_discard_range(
594167
         if (S_ISBLK(st.st_mode)) {
594167
                 uint64_t range[2], end;
594167
 
594167
-                range[0] = round_up_size(offset, 512);
594167
+                range[0] = round_up_size(offset, context->sector_size);
594167
 
594167
                 if (offset > UINT64_MAX - size)
594167
                         return -ERANGE;
594167
@@ -2369,7 +2417,7 @@ static int context_discard_range(
594167
                 if (end <= range[0])
594167
                         return 0;
594167
 
594167
-                range[1] = round_down_size(end - range[0], 512);
594167
+                range[1] = round_down_size(end - range[0], context->sector_size);
594167
                 if (range[1] <= 0)
594167
                         return 0;
594167
 
594167
@@ -2519,6 +2567,7 @@ static int context_wipe_and_discard(Context *context, bool from_scratch) {
594167
 }
594167
 
594167
 static int partition_encrypt(
594167
+                Context *context,
594167
                 Partition *p,
594167
                 const char *node,
594167
                 struct crypt_device **ret_cd,
594167
@@ -2532,6 +2581,7 @@ static int partition_encrypt(
594167
         sd_id128_t uuid;
594167
         int r;
594167
 
594167
+        assert(context);
594167
         assert(p);
594167
         assert(p->encrypt != ENCRYPT_OFF);
594167
 
594167
@@ -2579,7 +2629,7 @@ static int partition_encrypt(
594167
                          volume_key_size,
594167
                          &(struct crypt_params_luks2) {
594167
                                  .label = strempty(p->new_label),
594167
-                                 .sector_size = 512U,
594167
+                                 .sector_size = context->sector_size,
594167
                          });
594167
         if (r < 0)
594167
                 return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
594167
@@ -2735,7 +2785,7 @@ static int context_copy_blocks(Context *context) {
594167
                         if (r < 0)
594167
                                 return log_error_errno(r, "Failed to lock loopback device: %m");
594167
 
594167
-                        r = partition_encrypt(p, d->node, &cd, &encrypted, &encrypted_dev_fd);
594167
+                        r = partition_encrypt(context, p, d->node, &cd, &encrypted, &encrypted_dev_fd);
594167
                         if (r < 0)
594167
                                 return log_error_errno(r, "Failed to encrypt device: %m");
594167
 
594167
@@ -2988,7 +3038,7 @@ static int context_mkfs(Context *context) {
594167
                         return log_error_errno(r, "Failed to lock loopback device: %m");
594167
 
594167
                 if (p->encrypt != ENCRYPT_OFF) {
594167
-                        r = partition_encrypt(p, d->node, &cd, &encrypted, &encrypted_dev_fd);
594167
+                        r = partition_encrypt(context, p, d->node, &cd, &encrypted, &encrypted_dev_fd);
594167
                         if (r < 0)
594167
                                 return log_error_errno(r, "Failed to encrypt device: %m");
594167
 
594167
@@ -3307,13 +3357,13 @@ static int context_mangle_partitions(Context *context) {
594167
 
594167
                         if (p->new_size != p->current_size) {
594167
                                 assert(p->new_size >= p->current_size);
594167
-                                assert(p->new_size % 512 == 0);
594167
+                                assert(p->new_size % context->sector_size == 0);
594167
 
594167
                                 r = fdisk_partition_size_explicit(p->current_partition, true);
594167
                                 if (r < 0)
594167
                                         return log_error_errno(r, "Failed to enable explicit sizing: %m");
594167
 
594167
-                                r = fdisk_partition_set_size(p->current_partition, p->new_size / 512);
594167
+                                r = fdisk_partition_set_size(p->current_partition, p->new_size / context->sector_size);
594167
                                 if (r < 0)
594167
                                         return log_error_errno(r, "Failed to grow partition: %m");
594167
 
594167
@@ -3353,8 +3403,8 @@ static int context_mangle_partitions(Context *context) {
594167
                         _cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
594167
 
594167
                         assert(!p->new_partition);
594167
-                        assert(p->offset % 512 == 0);
594167
-                        assert(p->new_size % 512 == 0);
594167
+                        assert(p->offset % context->sector_size == 0);
594167
+                        assert(p->new_size % context->sector_size == 0);
594167
                         assert(!sd_id128_is_null(p->new_uuid));
594167
                         assert(p->new_label);
594167
 
594167
@@ -3378,11 +3428,11 @@ static int context_mangle_partitions(Context *context) {
594167
                         if (r < 0)
594167
                                 return log_error_errno(r, "Failed to enable explicit sizing: %m");
594167
 
594167
-                        r = fdisk_partition_set_start(q, p->offset / 512);
594167
+                        r = fdisk_partition_set_start(q, p->offset / context->sector_size);
594167
                         if (r < 0)
594167
                                 return log_error_errno(r, "Failed to position partition: %m");
594167
 
594167
-                        r = fdisk_partition_set_size(q, p->new_size / 512);
594167
+                        r = fdisk_partition_set_size(q, p->new_size / context->sector_size);
594167
                         if (r < 0)
594167
                                 return log_error_errno(r, "Failed to grow partition: %m");
594167
 
594167
@@ -4746,18 +4796,20 @@ done:
594167
 }
594167
 
594167
 static int determine_auto_size(Context *c) {
594167
-        uint64_t sum = round_up_size(GPT_METADATA_SIZE, 4096);
594167
+        uint64_t sum;
594167
         Partition *p;
594167
 
594167
         assert_se(c);
594167
 
594167
+        sum = round_up_size(GPT_METADATA_SIZE, 4096);
594167
+
594167
         LIST_FOREACH(partitions, p, c->partitions) {
594167
                 uint64_t m;
594167
 
594167
                 if (p->dropped)
594167
                         continue;
594167
 
594167
-                m = partition_min_size_with_padding(p);
594167
+                m = partition_min_size_with_padding(c, p);
594167
                 if (m > UINT64_MAX - sum)
594167
                         return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Image would grow too large, refusing.");
594167