Skip to content
  • David Johnson's avatar
    Use the last resort systemd swap strategy: wrap the systemd-fstab-generator. · 828e7acd
    David Johnson authored
    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
    828e7acd