Use the last resort systemd swap strategy: wrap the systemd-fstab-generator.
As noted in a previous commit, systemd generators run at boot, with the rootfs mounted read-only, prior to systemd reading any unit files on disk. The systemd-fstab-generator reads /etc/fstab and generates units for any devices in there, including swap devices. Thus, the only way to ensure our swap device fixing happens correctly (and we have to do this in case the image was loaded from an old MFS that might write a swap device with /dev/hda or whatever into /etc/fstab), and doesn't race with systemd, is to preempt it. So now our generator runs the systemd generator each boot, but it post-processes the auto-generated unit files, removing them if any of those devices was 1) an Emulab auto-generated swap device, and 2) it does not exist. Moreover, if there is *no* swap device in /etc/fstab, we hunt down the canonical Emulab swap partition on the root disk, and mkswap it, and generate a unit for it. Of course, we don't use the system template (it is an m4 file in the src dist, so we can't), but hopefully the template won't change much --- and it's basic. We now only mkswap devices if they don't appear as swap devs via blkid. To clean up old Emulab systemd images, do these steps: $ systemctl disable emulab-fstab-fixup.service $ make client-install $ rm -f /usr/local/etc/emulab/initscripts/emulab-systemd-swaps I think that will do it. Worked for me on Ubuntu 16 and Centos 7. Here's the comments from the generator for posterity: This is a systemd generator that wraps systemd-fstab-generator. First, we always run the system generator; and any swap file units it generates are modified to contain a Before=emulab-fstab.fixup.service dependency to ensure the fixup script never races with legitimate systemd unit targets. If it has already run on an Emulab node (and if the second-stage fixup script (emulab-fstab-fixup.service) has also run), we don't run it again; we just run the system fstab generator directly, modify the generated swap unit files to run before the fixup script. Otherwise, on first boot of an Emulab image, we run the system generator and let it generate swap units for any swap devices that were in /etc/fstab. We then check all the auto-Emulab-added swap device entries in /etc/fstab, and if that device does not exist, we remove the auto-generated unit files/symlinks that correspond to it (they are in $1). We cannot edit /etc/fstab ourselves because we're run prior to remount-/-rw; so we make a copy of it in /run/emulab and move the copy to /etc/fstab in emulab-fstab-fixup.service --- the second part of our solution (the fixup service). NB: we do not remove user-added swap devices, even if they are invalid! We check to see if each auto-Emulab-added swap device that was in /etc/fstab is currently a valid swap device (i.e., that it shows up via blkid with a TYPE="swap"). If it is valid, we *do not* run mkswap to create it! If it is not currently a valid swap device, but if the partition is marked as a Linux swap partition, we will run mkswap on it to ensure it is valid by the time systemd runs swapon on it. If we *did* plan to run mkswap, that can be prevented by creating the /etc/emulab/emulab_systemd_fstab_generator_never_mkswap file. This gives the user the ability to create a disk image where swap partitions are not created/wiped on first boot of the image. I can't see a use case for this, but it's easy to do. If there is a swap partition on the device containing the root partition, and if it is not already in /etc/fstab, we try to add a unit ourselves for that swap partition. We do it in the new style, too, by using its UUID, in this case. When scanning /etc/fstab to find auto-Emulab-added devices, we look for a comment above a line containing a swap device, and the comment must match the regexp /^#.*the following.* added by / . Then if the line below the comment refers to an invalid swap device, we remove the unit files that correspond to the device. Otherwise
Showing with 327 additions and 366 deletions