]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: make sure to grow partition table after growing backing loopback file
authorLennart Poettering <lennart@poettering.net>
Fri, 19 Mar 2021 09:36:48 +0000 (10:36 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 19 Mar 2021 17:11:26 +0000 (18:11 +0100)
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)

src/partition/repart.c

index be16f5a067b5ceaab463bf7a7239aa2c1d3363df..7b6201efa8371517175524840a18bd18ba0ee5fa 100644 (file)
@@ -3977,6 +3977,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;
@@ -4029,6 +4063,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
@@ -4042,6 +4080,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