summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-03-19 10:36:48 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-03-23 01:35:30 +0100
commitb132bca9f6dc6ed4965c0ac48bac90e9fc443a9e (patch)
tree30ace7ab16967066cf0a29ba1354e68e09ab22cb
parent85e45e8722cd2732c4a26f535ddc6472dd1fb0a6 (diff)
downloadsystemd-b132bca9f6dc6ed4965c0ac48bac90e9fc443a9e.tar.gz
repart: make sure to grow partition table after growing backing loopback file
This fixes the --size= switch, i.e. where we grow a disk image: after growing it we need to expand the partition table so that its idea of the the medium size matches the new reality. Otherwise our disk size calculations in the subsequent steps might still use the original ungrown size. (This used to work, I guess this was borked when libfdisk learnt the concept of "minimized" partition tables) (cherry picked from commit f9b3afae96c72564cd4cd766555845f17e3c12a9)
-rw-r--r--src/partition/repart.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 6db413ed5e..6d7e51938a 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -3860,6 +3860,40 @@ static int find_root(char **ret, int *ret_fd) {
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device.");
}
+static int resize_pt(int fd) {
+ char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
+ int r;
+
+ /* After resizing the backing file we need to resize the partition table itself too, so that it takes
+ * possession of the enlarged backing file. For this it suffices to open the device with libfdisk and
+ * immediately write it again, with no changes. */
+
+ c = fdisk_new_context();
+ if (!c)
+ return log_oom();
+
+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+ r = fdisk_assign_device(c, procfs_path, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open device '%s': %m", procfs_path);
+
+ r = fdisk_has_label(c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", procfs_path);
+ if (r == 0) {
+ log_debug("Not resizing partition table, as there currently is none.");
+ return 0;
+ }
+
+ r = fdisk_write_disklabel(c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write resized partition table: %m");
+
+ log_info("Resized partition table.");
+ return 1;
+}
+
static int resize_backing_fd(const char *node, int *fd) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
_cleanup_close_ int writable_fd = -1;
@@ -3912,6 +3946,10 @@ static int resize_backing_fd(const char *node, int *fd) {
/* Fallback to truncation, if fallocate() is not supported. */
log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
} else {
+ r = resize_pt(writable_fd);
+ if (r < 0)
+ return r;
+
if (st.st_size == 0) /* Likely regular file just created by us */
log_info("Allocated %s for '%s'.", buf2, node);
else
@@ -3925,6 +3963,10 @@ static int resize_backing_fd(const char *node, int *fd) {
return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
node, buf1, buf2);
+ r = resize_pt(writable_fd);
+ if (r < 0)
+ return r;
+
if (st.st_size == 0) /* Likely regular file just created by us */
log_info("Sized '%s' to %s.", node, buf2);
else