Upgrading Silverblue from 35 to 36, manually move `/var` to new subvolume?

I see that Fedora Silverblue 36 will default to /var being on a separate btrfs subvolume for new installs: Changes/VarSubvol4SilverblueKinoite - Fedora Project Wiki

I know that upgrades from F35 won’t get this change applied, but I wonder if anyone upgrading from F35 (who are maybe already using the F36 beta), have tried moving /var manually to a new subvolume? Assuming I’m comfortable wrangling subvolumes and /etc/fstab, any gotchas to be aware of if I were to do this manually?

1 Like

I did my install partitioning manually and already had /var as it’s own subvolume along with /home and / so this change is alligning with what I already have in place, woohoo! But in your case it should be as simple as using the advanced partitioning tool Blivet of the installer to create it there then re-install over your existing leaving your /home subvolume as is. However, if you don’t feel comfortable messing around with that you could back up your important data and do a complete re-install with the new defaults and restore data afterwards.

As much as I’d like to be in a position where a re-install would be simple, I’m afraid I have plenty of little customisations that I’d rather not have to reconfigure.

After I upgrade to F36, I guess I’ll give it a shot manually creating creating the new subvolume for /var. I’ll try to report back.

I have had success by doing a re-install with not including the /home partition in formatting. I did this by using the advanced gui for the installation, and deleting the old / subvolume then creating two new subvolumes at / and at /var leaving /home as it was. I have also done a btrfs send/receive snapshot method successfully to restore my /home. This had the added benefit of becoming my /home backup snapshot afterwards. In that method I just did a new clean install and setup my user then restored my data from the snapshot which was on the same physical drive.

That all makes sense. I have weird configuration outside of /home that I don’t want to re-do. Snapper, flatpak remotes, layered packages, rpm repos, grub tweaks to workaround text rendering issues, weird bcache things… Honestly I’d rather not have to get all those things working again.

I think I’ll chance the approach of upgrading then shifting /var into a subvolume.

Hi, I’m following this thread because I’d be interested in knowing how to do this migration and also to learn a bit more about how Silverblue works under the hood.

Can someone explain to me (or point me to documentation) how /var is implemented? That is, I believe in the current version (F35), the contents of /var are actually stored in the ostree directory at /sysroot/ostree/deploy/fedora/var. How is this directory mirrored to /var? As far as I can tell, /var is not a symlink to /sysroot/ostree/deploy/fedora/var.

I feel like understanding that will help me in determining how to do this migration. It seems that the /sysroot/ostree/deploy/fedora/var directory is still present in F36 Beta. In F36, it seems there are items in that directory as well as the new /var subvolume. I’m curious how ostree is handling these, and also how it handles the case where users upgrade from F35 and there is no /var subvolume.

1 Like

For Silverblue filesystem layout you should start here Technical Information :: Fedora Docs. The immutable portion(s) are symlinked to the respective areas in /var which holds the runtime state of the system. The mapping is shown at the link.

1 Like

Thanks @jakfrost. I figured out some of it last night. From what I’ve been able to figure out:

  1. /sysroot/ostree/deploy/fedora/var is bind mounted to /var at boot by var.mount, which is created by ostree-system-generator. Which explains how those 2 directories are kept the same.

  2. In order to keep var.mount from colliding/overriding a manual var subvolume mount in /etc/fstab, it looks like there is logic in the generator code (libostree-2022.1/src/libostree/ostree-impl-system-generator.c) that checks for this:

ostree-impl-system-generator.c Snippet
/* Generate var.mount */
static gboolean
fstab_generator (const char *ostree_cmdline,
                 const char *normal_dir,
                 const char *early_dir,
                 const char *late_dir,
                 GError    **error)
{
#ifdef HAVE_LIBMOUNT
  /* Not currently cancellable, but define a var in case we care later */
  GCancellable *cancellable = NULL;
  /* Some path constants to avoid typos */
  static const char fstab_path[] = "/etc/fstab";
  static const char var_path[] = "/var";

...

  /* Load /etc/fstab if it exists, and look for a /var mount */
  g_autoptr(OtLibMountFile) fstab = setmntent (fstab_path, "re");
  gboolean found_var_mnt = FALSE;
  if (!fstab)
    {
      if (errno != ENOENT)
        return glnx_throw_errno_prefix (error, "Reading %s", fstab_path);
    }
  else
    {
      /* Parse it */
      struct mntent *me;
      while ((me = getmntent (fstab)))
        {
          g_autofree char *where = g_strdup (me->mnt_dir);
          if (is_path (where))
            path_kill_slashes (where);

          /* We're only looking for /var here */
          if (strcmp (where, var_path) != 0)
            continue;

          found_var_mnt = TRUE;
          break;
        }
    }

  /* If we found /var, we're done */
  if (found_var_mnt)
    return TRUE;

  ...
}

So with all that, I *think * it would be okay to: create a new var subvolume, create a new entry in /etc/fstab to mount that subvolume, then move all the contents of /sysroot/ostree/deploy/fedora/var to the new subvolume… and everything should just work. But, in a fresh F36 Silverblue install, there are still things in the /sysroot/ostree/deploy/fedora/var directory (screenshot below). I’m still not sure why those are there. Supposedly that directory is never mounted anywhere in F36, so it should be useless? So during a manual migration from F35 to F36, I’m unsure if I can leave the /sysroot/ostree/deploy/fedora/var directory empty, or if these entries need to be manually created or left behind for some reason.

Screenshot

Ok, after digging into it I felt comfortable enough to try it out in a VM and on a non-production bare metal install. VM is running F35 Silverblue and bare metal is F35 Kinoite. So far I have not encountered any issues, but it’s still early testing - I’ll update this if anything crops up. But here are the steps I took to make the modification, in case anyone wants to do this:

  1. Booted into the F35 Silverblue/Kinoite installation, run cat /proc/cmdline and take note of the directory of the currently booted deployment which is the string after ostree= in the output - this is needed later.
  2. Boot into a Live session (I used the LXQt spin of Fedora Linux 35, but presumably any Live disc should work as long as it has the btrfs utilities available).
  3. Open a terminal and mount your main boot partition (should be named ‘fedora_fedora’) somewhere convenient - I created /mnt/fedora
  4. Create the new var subvolume in /mnt/fedora. Sanity check: you should see the other 2 pre-created subvolumes root and home here as well.
  5. Move the old var contents from /mnt/fedora/root/ostree/deploy/fedora/var/* to the new var subvolume.
    • Optionally you can do a cp instead of a mv here, at the expense of some extra disk space. The files can be deleted from /sysroot/ostree/deploy/fedora/var in the future from the booted F35/36 system if everything works.
  6. We need to modify fstab to mount the new var subvolume.
    • First cd into the root folder/subvolume. Then navigate to the directory that we noted in step 1 above. E.g. cd ostree/boot.0/fedora/somereallylonghashstring/0
    • vi etc/fstab - we are now modifying the fstab that resides in the deployment that we want to boot into.
    • Copy the existing line in fstab for /home and paste a new line at the bottom of the file. In the new pasted line, change /home to /var and subvol=home to subvol=var. Save and exit.

And that should be it. Shut down, remove the Live disc, and boot as normal.

example - commands from Live session
$ su
# cd /mnt
# mkdir fedora
# mount /dev/sda3 fedora
# cd fedora
# btrfs subvolume create var
# mv root/ostree/deploy/fedora/var/* var/
# cd root/ostree/boot.0/fedora/somereallylongshashstring/0
# vi etc/fstab
4 Likes

Thank you very much for looking into this, and providing such details! I have now similarly moved /var to a subvolume on my F35 SB system.

Comments from my migration:

  • I had some hidden dotfiles in the root of /var. I had to do more than a simple var/* glob to make sure I captured those.
  • I did the migration while booted into silverblue - I didn’t use a live session.
    • I took a subvolume snapshot before performing the copy, and copied from the snapshot. This ensured I got a consistent copy of the contents of var despite the system being booted. After reboot I would lose the changes made to var since the snapshot was made, so I made sure the system was as idle as could be during that period. In retrospect using a live session would have been the safer and simpler approach.
    • Since I was using the live system, I could edit /etc/fstab rather than hunt or it within an ostree boot directory.
  • I have left behind an empty var directory in the old location. I’m curious if this can be deleted…
  • Silverblue has many bind mounts, and findmnt is the way to list the bind mounts. I previously wasn’t aware of this command but found it very useful to confirm what was going on.
2 Likes

Thank you both! Followed the steps and it worked great.

If anybody want to follow this, and has an encrypted drive like me, use cryptsetup before mounting it.

cryptsetup open /dev/sda3 crypted
mount /dev/mapper/crypted /mnt/fedora

Thanks again for sharing the instructions.

2 Likes

Learn from my mistakes, remember to use cp -a to preserve permissions and links, or your system won’t be bootable. Thankfully I was able to rollback to the previous deployment and try again.

2 Likes