Browse Source

Resize root filesystem at VM startup if needed

Check if root device was enlarged while domain was powered off and
resize the filesystem in such a case.

QubesOS/qubes-issues#3173
QubesOS/qubes-issues#3143
Marek Marczykowski-Górecki 6 years ago
parent
commit
1ed6e614ab

+ 2 - 0
debian/qubes-core-agent.install

@@ -70,6 +70,7 @@ lib/systemd/system/org.cups.cupsd.socket.d/30_qubes.conf
 lib/systemd/system/qubes-early-vm-config.service
 lib/systemd/system/qubes-misc-post.service
 lib/systemd/system/qubes-mount-dirs.service
+lib/systemd/system/qubes-rootfs-resize.service
 lib/systemd/system/qubes-sysinit.service
 lib/systemd/system/qubes-update-check.service
 lib/systemd/system/qubes-update-check.timer
@@ -110,6 +111,7 @@ usr/lib/qubes/init/mount-dirs.sh
 usr/lib/qubes/init/qubes-early-vm-config.sh
 usr/lib/qubes/init/qubes-random-seed.sh
 usr/lib/qubes/init/qubes-sysinit.sh
+usr/lib/qubes/init/resize-rootfs-if-needed.sh
 usr/lib/qubes/init/setup-rw.sh
 usr/lib/qubes/init/setup-rwdev.sh
 usr/lib/qubes/prepare-suspend

+ 26 - 0
init/resize-rootfs-if-needed.sh

@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Possibly resize root device (partition, filesystem), if underlying device was
+# enlarged.
+
+set -e
+
+# if underlying root device is read-only, don't do anything
+if [ "$(blockdev --getro /dev/xvda)" -eq "1" ]; then
+    echo "xvda is read-only, not resizing" >&2
+    exit 0
+fi
+
+sysfs_root_dev="/sys/dev/block/$(mountpoint -d /)"
+sysfs_xvda="/sys/class/block/xvda"
+
+# if root filesystem use already (almost) the whole dis
+non_rootfs_data=$(( 250 * 1024 * 2 ))
+if [ "$(cat "$sysfs_xvda/size")" -lt \
+       $(( non_rootfs_data + $(cat "$sysfs_root_dev/size") )) ]; then
+   echo "root filesystem already at the right size" >&2
+   exit 0
+fi
+
+# resize needed, do it
+/usr/lib/qubes/resize-rootfs

+ 2 - 0
rpm_spec/core-agent.spec

@@ -617,6 +617,7 @@ rm -f %{name}-%{version}
 /usr/lib/qubes/init/qubes-early-vm-config.sh
 /usr/lib/qubes/init/qubes-random-seed.sh
 /usr/lib/qubes/init/qubes-sysinit.sh
+/usr/lib/qubes/init/resize-rootfs-if-needed.sh
 /usr/lib/qubes/init/setup-rw.sh
 /usr/lib/qubes/init/setup-rwdev.sh
 /usr/lib/qubes/init/functions
@@ -804,6 +805,7 @@ The Qubes core startup configuration for SystemD init.
 %defattr(-,root,root,-)
 /lib/systemd/system/qubes-misc-post.service
 /lib/systemd/system/qubes-mount-dirs.service
+/lib/systemd/system/qubes-rootfs-resize.service
 /lib/systemd/system/qubes-sysinit.service
 /lib/systemd/system/qubes-early-vm-config.service
 /lib/systemd/system/qubes-update-check.service

+ 5 - 0
vm-init.d/qubes-core-early

@@ -15,6 +15,11 @@ start()
 {
 	have_qubesdb || return
 
+	echo -n $"Adjusting root filesystem size:"
+	# shellcheck disable=SC2015
+	/usr/lib/qubes/init/resize-rootfs-if-needed.sh && success || failure
+	echo
+
 	echo -n $"Setting up Qubes persistent file systems:"
     # shellcheck disable=SC2015
 	/usr/lib/qubes/init/mount-dirs.sh && success || failure

+ 2 - 1
vm-systemd/75-qubes-vm.preset

@@ -85,6 +85,7 @@ enable qubes-updates-proxy.service
 enable qubes-network.service
 enable qubes-qrexec-agent.service
 enable qubes-mount-dirs.service
+enable qubes-rootfs-resize.service
 enable qubes-firewall.service
 enable qubes-meminfo-writer.service
 enable qubes-iptables.service
@@ -94,4 +95,4 @@ enable chronyd.service
 enable xendriverdomain.service
 enable systemd-timesyncd.service
 enable qubes-sync-time.service
-enable qubes-sync-time.timer
+enable qubes-sync-time.timer

+ 19 - 0
vm-systemd/qubes-rootfs-resize.service

@@ -0,0 +1,19 @@
+[Unit]
+Description=Adjust root filesystem size
+# There is a dependency on dev-xvdb.device because
+# mount-dirs.sh calls setup-rwdev.sh which
+# must happen only when /dev/xvdb has appeared.
+After=qubes-sysinit.service dev-xvda.device
+DefaultDependencies=no
+Before=local-fs.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/usr/lib/qubes/init/resize-rootfs-if-needed.sh
+# There is no need for an ExecStop because systemd
+# cleans up mount units in the right order, killing
+# processes as needed.
+
+[Install]
+WantedBy=multi-user.target