Skip to content
This repository has been archived by the owner on May 9, 2022. It is now read-only.

Commit

Permalink
workaround for umount bug (#873459)
Browse files Browse the repository at this point in the history
The problem with bind-mounts is that once we switch-root, they all
become *private* mounts. Why does that matter? Well, it means unmounting
/sysroot/boot doesn't actually unmount the original /boot..

..which means /boot is still mounted when we reboot. So we can lose data
in recently-written files. Like that new initramfs we just wrote at the
end of the upgrade. Which leaves our system unbootable. Daaaang. Whoops.

So here's a partial workaround: make the mounts private *before*
switch-root, and unmount the *original* copy of /boot before the switch,
so the /sysroot/boot copy is the *only* one, so when we unmount that the
kernel actually writes everything to disk. Whew.

Unfortunately, this doesn't do anything for the root device, but we can
work something out for that inside the initramfs.
  • Loading branch information
wgwoods committed Nov 13, 2012
1 parent 466156a commit f6f1c68
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions systemd/upgrade-prep.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,18 @@ die() { echo "$@"; exit 1; }
[ -n "$UPGRADEROOT" ] || die "UPGRADEROOT is not set"
[ -d "$UPGRADEROOT" ] || die "$UPGRADEROOT does not exist"

echo "binding / into $UPGRADEROOT"
# bind-mount / into the upgrade chroot so we can upgrade it
echo "moving mounts into $UPGRADEROOT"
# bind everything into the upgrade chroot
mount --rbind / $UPGRADEROOT/sysroot || die "couldn't bind / into upgrade dir"
# make the bind mounts separate from the original mounts
mount --make-rprivate /
# unmount the original mounts, i.e.:
# anything that's a block device, not root, and not under UPGRADEROOT
tac /proc/mounts | while read dev mnt type opts x y; do
if [ -b "$dev" -a "$mnt" != "/" -a "${mnt#$UPGRADEROOT}" == "$mnt" ]; then
umount $mnt && echo "moved $mnt" || echo "failed to move $mnt"
fi
done

# XXX: we can drop this once there's a way to pass args to new init
echo "switching upgraderoot default target to upgrade.target"
Expand Down

0 comments on commit f6f1c68

Please sign in to comment.