Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

homework: resize to maximum disk space if disk size is not specified #25066

Merged
merged 1 commit into from
Jun 19, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 54 additions & 12 deletions src/home/homework-luks.c
Original file line number Diff line number Diff line change
Expand Up @@ -2749,6 +2749,43 @@ static int prepare_resize_partition(
return 1;
}

static int get_maximum_partition_size(
int fd,
struct fdisk_partition *p,
uint64_t *ret_maximum_partition_size) {

_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
uint64_t start_lba, start, last_lba, end;
int r;

assert(fd >= 0);
assert(p);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this is actually not correct to assume. if a naked block device is used (i.e. no partition table) this will be NULL.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added partition != NULL condition. This will make it the same as before if it's a naked block device.

assert(ret_maximum_partition_size);

bluca marked this conversation as resolved.
Show resolved Hide resolved
c = fdisk_new_context();
if (!c)
return log_oom();

r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(fd), 0);
if (r < 0)
return log_error_errno(r, "Failed to open device: %m");

start_lba = fdisk_partition_get_start(p);
assert(start_lba <= UINT64_MAX/512);
start = start_lba * 512;

last_lba = fdisk_get_last_lba(c); /* One sector before boundary where usable space ends */
assert(last_lba < UINT64_MAX/512);
end = DISK_SIZE_ROUND_DOWN((last_lba + 1) * 512); /* Round down to multiple of 4K */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, this is problematic if there are partitions behind this one. I guess to to be correct we'd have to iterate through all partitions on the disk, and look for the one whose start offset is smallest of those larger than our partition. And only if no such partition exist use the last LBA value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else if (fdisk_partition_get_end(p) > partition_offset / 512U)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Can't extend, not last partition in image.");
}

prepare_resize_partition() returns error if the partition is not the last. Therefore, this ensures that no more partitions exist.


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before we subtract start from end we shuld really check for overflows, and generate some error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e.

if (start > end)
        return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Last LBA is before partition end.");

or so

if (start > end)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Last LBA is before partition start.");

*ret_maximum_partition_size = DISK_SIZE_ROUND_DOWN(end - start);

return 1;
}

static int ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *userdata) {
char *result;

Expand Down Expand Up @@ -3214,6 +3251,17 @@ int home_resize_luks(
setup->partition_offset + setup->partition_size > old_image_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Old partition doesn't fit in backing storage, refusing.");

/* Get target partition information in here for new_partition_size calculation */
r = prepare_resize_partition(
image_fd,
setup->partition_offset,
setup->partition_size,
&disk_uuid,
&table,
&partition);
if (r < 0)
return r;

if (S_ISREG(st.st_mode)) {
uint64_t partition_table_extra, largest_size;

Expand All @@ -3236,9 +3284,13 @@ int home_resize_luks(
new_partition_size = 0;
intention = INTENTION_SHRINK;
} else {
uint64_t new_partition_size_rounded;
uint64_t new_partition_size_rounded = DISK_SIZE_ROUND_DOWN(h->disk_size);

new_partition_size_rounded = DISK_SIZE_ROUND_DOWN(h->disk_size);
if (h->disk_size == UINT64_MAX && partition) {
r = get_maximum_partition_size(image_fd, partition, &new_partition_size_rounded);
if (r < 0)
return r;
}

if (setup->partition_size >= new_partition_size_rounded &&
setup->partition_size <= h->disk_size) {
Expand Down Expand Up @@ -3332,16 +3384,6 @@ int home_resize_luks(
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
FORMAT_BYTES(new_fs_size));

r = prepare_resize_partition(
image_fd,
setup->partition_offset,
setup->partition_size,
&disk_uuid,
&table,
&partition);
if (r < 0)
return r;

if (new_fs_size > old_fs_size) { /* → Grow */

if (S_ISREG(st.st_mode)) {
Expand Down