From: Karel Zak Date: Mon, 8 Nov 2021 12:38:45 +0000 (+0100) Subject: libfdisk: enlarge partition by move start down X-Git-Tag: v2.38-rc1~185 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=226c844dec2dbda235e74f834d59ba1d25122ce0;p=thirdparty%2Futil-linux.git libfdisk: enlarge partition by move start down Now it's possible move start of the partition only when offset or absolute value is specified. This commit implements resize to "use all available free space before the current start". We already support the same for end of the partition (resize to use all free space after the partition). Signed-off-by: Karel Zak --- diff --git a/libfdisk/src/partition.c b/libfdisk/src/partition.c index 46fddc5242..2677cae264 100644 --- a/libfdisk/src/partition.c +++ b/libfdisk/src/partition.c @@ -1041,7 +1041,7 @@ int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, return rc; } -static struct fdisk_partition *resize_get_by_offset( +static struct fdisk_partition *area_by_offset( struct fdisk_table *tb, struct fdisk_partition *cur, fdisk_sector_t off) @@ -1064,6 +1064,67 @@ static struct fdisk_partition *resize_get_by_offset( return NULL; } +static int resize_get_first_possible( + struct fdisk_table *tb, + struct fdisk_partition *cur, + fdisk_sector_t *start) +{ + struct fdisk_partition *pa = NULL, *first = NULL; + struct fdisk_iter itr; + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + + *start = 0; + DBG(TAB, ul_debugobj(tb, "checking first possible before start=%ju", (uintmax_t) cur->start)); + + + while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { + + if (pa->start > cur->start || pa == cur) + break; + + DBG(TAB, ul_debugobj(tb, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]", + pa, + fdisk_partition_get_partno(pa), + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa), + (uintmax_t) fdisk_partition_get_size(pa), + fdisk_partition_is_freespace(pa) ? " freespace" : "", + fdisk_partition_is_nested(pa) ? " nested" : "", + fdisk_partition_is_container(pa) ? " container" : "")); + + + if (!fdisk_partition_is_freespace(pa)) { + DBG(TAB, ul_debugobj(tb, " ignored (no freespace)")); + first = NULL; + continue; + } + if (!fdisk_partition_has_start(pa) || !fdisk_partition_has_size(pa)) { + DBG(TAB, ul_debugobj(tb, " ignored (no start/size)")); + first = NULL; + continue; + } + /* The current is nested, free space has to be nested within the same parent */ + if (fdisk_partition_is_nested(cur) + && pa->parent_partno != cur->parent_partno) { + DBG(TAB, ul_debugobj(tb, " ignore (nested required)")); + first = NULL; + continue; + } + if (pa->start + pa->size <= cur->start) { + first = pa; + DBG(TAB, ul_debugobj(tb, " entry usable")); + } + } + + if (first) + *start = first->start; + else + DBG(PART, ul_debugobj(cur, "resize: nothing usable before %ju", (uintmax_t) cur->start)); + + return first ? 0 : -1; +} + /* * Verify that area addressed by @start is freespace or the @cur[rent] * partition and continue to the next table entries until it's freespace, and @@ -1211,7 +1272,16 @@ static int recount_resize( DBG(PART, ul_debugobj(tpl, "resize: moving start %s relative, new start: %ju", tpl->movestart == FDISK_MOVE_DOWN ? "DOWN" : "UP", (uintmax_t)start)); - /* 1b) set new start - absolute number */ + /* 1b) set new start - try freespace before the curret partition */ + } else if (tpl->movestart == FDISK_MOVE_DOWN) { + + if (resize_get_first_possible(tb, cur, &start) != 0) + goto erange; + + DBG(PART, ul_debugobj(tpl, "resize: moving start DOWN (first possible), new start: %ju", + (uintmax_t)start)); + + /* 1c) set new start - absolute number */ } else if (fdisk_partition_has_start(tpl)) { start = fdisk_partition_get_start(tpl); DBG(PART, ul_debugobj(tpl, "resize: moving start to absolute offset: %ju", @@ -1220,7 +1290,7 @@ static int recount_resize( /* 2) verify that start is within the current partition or any freespace area */ if (!FDISK_IS_UNDEF(start)) { - struct fdisk_partition *area = resize_get_by_offset(tb, cur, start); + struct fdisk_partition *area = area_by_offset(tb, cur, start); if (area == cur) DBG(PART, ul_debugobj(tpl, "resize: start points to the current partition")); @@ -1326,7 +1396,8 @@ int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, return fdisk_add_partition(cxt, pa, NULL); } - if (pa->resize || fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) { + if (pa->resize || pa->movestart + || fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) { xpa = __copy_partition(pa); if (!xpa) { rc = -ENOMEM;