Introduction
  
    The Btrfsfilesystem is believed by some to be the next default filesystem for Linux, replacing the current
    de-facto standard filesystem, ext4, used by default in most distributions. It has many advanced features
    which are not available in the current standard filesystem, such as copy-on-write capability which maintains a
    version of a file at each modification. This allows individual files to be rolled back to previous versions and even
    the entire system to be snapshotted and rolled back to a previous state from a snapshot. Also, among other features
    that make it increasingly in demand by data centers, it is fault tolerant -- not only at the device level but to an
    individual file level, able te repair corrupted files -- as long as the required number of redundant storage devices
    are available and configured appropriately.
  
  
    Ubuntu offers the ZFS filesystem as an option, which has similar fault tolerant features as Btrfs, but
    does not have the file level self healing features of Btrfs. While ZFS is an option at installation,
    the default filesystem on Ubuntu installations is ext4. Users who want the advanced features of Btrfs
    but originally installed with the default ext4 filesystem can easily convert the ext4 filesystem of
    the original installation to Btrfs. And if they want the simple system snapshot and rollback management by
    Snapper, which can incorporate automatic periodic snapshot creation and cleanup, automatic snapshot creation
    at boot, and automatic pre and post snapshots during APT package management transactions, as well as automatic
    mounting of the correct subvolume that contains the filesystem hierarchy root because the default Btrfs
    subvolume is set by Snapper, a little more effort will yield such as system.
  
  
    The process, similar to the one described in A Fedora Installation with an openSUSE Style BtrfsSubvolume Layout and Snapper
        Intergration for System Snapshots and Rollbacks, involves using btrfs-convert, part of the set of
    Btrfs utility progras usually packaged as btrfs-progs, to convert the
    ext4 filesystem while offline from either a live USB or another installation on the same computer. The
    external Linux used in performing the process for this article was an Arch Linux installation which was installed on
    Btrfs with an oenSUSE layout and Snapper integration following the process described in An Arch Linux Installation on a BtrfsFilesystem with Snapper for System Snapshots and
        Rollbacks. Because this external Linux was Btrfs based, the btrfs-progs package was already available. If the external Linux is not Btrfs
    based, the package must be installed before performing the filesystem conversion.
  
  
    After the conversion the openSUSE style subvolume layout was created by mounting the converted filesystem from the
    external system, moving the directories and files in the filesystem hierarchy root, except those parts of the
    hierarchy to be excluded from system snapshots (/opt, /root, /var/cache, etc.) to the desired subvolume. Other
    tasks were also necessary to properly configure the system, including setting the default btrfs subvolume,
    editing the /etc/fstab file to include the subvolumes containing filesystem hierarchy
    paths to be excluded from system snapshots, editing GRUB scripts in /etc/grub.d for
    compatibility with automatic mounting of the subvolume containing the filesystem hierarchy root by /etc/fstab without explicitly specifying the subvolume containing the filesystem
    hierarchy root as a mount option.
  
  
    The following graphic helps to illustrates the process and the desired configuration. The right part depicts the
    final subvolume configuration, including aspects of the configuration such as the subvolume used as the filesystem
    hierarchy root, how this subvolume is mounted, the changes in the subvolume layout as new snapshots are created, and
    the effect of rollbacks to the subvolume layout. The left part depicts intermediate states of the system at various
    stages in the process.
  
  
  
    
    
      
        Figure 1: The Intermediate State of the Subvolume Layout and the Final State of the Subvolume Layout
      
      
      
     
   
    
    
      The process is summarized below, before the full process found later in this article:
    
      - 
        Part 1: Prepare the Ext4 Filesystem to Be Converted to Btrfs
        
There must be an adequate amount of free space on the filesystem. If there is not, enlarge the partition, if
        possible, or delete package caches or other unnecessary files to create free space. Check for filesystem
        fragmentation, as pre-conversion fragmentation will be carried over to the converted filesystem, and defragment
        if necessary. Also, the filesystem must also be free of errors, so a filesystem check and repair -- if necessary
        -- is required before the conversion.
       
      - 
        Part 2: Convert the Ext 4 Partition to Btrfs
        
Use the btrfs-convert program to convert the Filesystem containing the
        root of the Ubuntu installation filesystem hierarchy to Btrfs. Then mount the converted filesystem in the
        external Linux to view the characteristics of the converted filesystem and to delete the backup subvolume
        containing a copy of the preconversion image created by the conversion program.
       
      - 
        Part 3: Create the Subvolumes for the Desired Subvolume Layout
        
While the converted Btrfs partition is still mounted from the previous part, create the subvolume to
        contain all other subvolumes immediately under the automatically created top-level subvolume, at subvolume path
        /@. Also, create the subvolumes to contain filesystem hierarchy paths to be
        excluded from system snapshots at subvolume paths /@/@opt, /@/@root, /@/srv, /@/@usrlocal, /@/@varcache, /@/@varlog and, /@/@vartmp. These will eventually
        contain, respectively, the filesystem hierarchy paths: /opt, /root, /srv, /usr/local, /var/cache, /var/log and, /var/tmp.
       
      - 
        Part 4: Move Files from the Top Level Btrfs Subvolume (subvolume path /, subvolume ID 5) to the Newly Created Subvolumes
        
Move the contents of the top-level subvolume created by the btrfs-convert
        command, which also places the root of the filesystem hierarchy and all existing files and directories in this
        subvolume to the appropriate subvolumes created in the previous Part. First we move the filesystem hierarchy
        paths to be excluded from the system snapshots their respective subvolumes, i.e., /@/@opt, /@/@root, /@/srv, /@/@usrlocal, /@/@varcache, /@/@varlog and, /@/@vartmp. Then move the remaining files, temporarily to the subvolume created to
        contain all other subvolumes, subvolume path /@, subvolume ID 257.
       
      - 
        Part 5: Install Snapper and Create Initial Snapshot Subvolume
        
Next, chroot into the Ubuntu system and install Snapper. Before the chroot we mount the /@ subvolume to be the root of the choot environment. We also mount the subvolumes
        under the chroot root mountpoint, as well as the pseudo filesystems. After the Snapper installation, we
        initialize a Snapper configuration, which also automatically creates a subvolume for snapshots under the
        subvolume currently mounted as the root of the filesystem (subvolume path /@),
        and finally create the initial snapshot subvolume which will contain the root of the filesystem hierarchy at the
        end of the process, and until a rollback is performed. Exit the chroot at the end of this step.
       
      - 
        Part 6: Move Files from Subvolume Path /@ to Subvolume Path /@/.snapshots/1/snapshot
        
After existing the chroot at the end of the previous step, while the mounts created for the chroot are still
        active, move the remaining -- after the move in Part 4 -- files and directories from subvolume path /@ to the initial snapshot subvolume, subvolume path /@/.snapshots/1/snapshot. After this step, our configuration of the subvolume layout
        will be complete and as illustrated in the right pane of the figure at the top of the article.
       
      - 
        Part 7: Modify /etc/fstab to Reflect New Btrfs Filesystem and
            Subvolume Layout
        
Access the Ubuntu installation's /etc/fstab, now in its final home under the
        initial snapshot subvolume, from the external Linux through the mount point at /mnt/ubuntu-root/.snapshots/1/snapshot/etc/fstab and modify the mount for the root
        filesystem hierarchy. Also, add mountpoints for the snapshots subvolume (at subvoume path /@/.snapshots) as well as mountpoints for the subvolumes used to contain the
        filesystem hierarchy paths that are to be excluded from system snapshots.
       
      - 
        Part 8: Modify GRUB Scripts in /etc/grub.d
        
Simiar to the above step with respect to the /etc/fstab,
        access the GRUB scripts /etc/grub/grub.cfg/10_linux and /etc/grub/grub.cfg/20_linux_xen for compatibility with automatic mounting of the
        current snapshot subvolume to the mountpoint of the filesystem hierarchy root through the Btrfs default
        subvolume feature.
       
      - 
        Part 9: Make Directory to Be Used as a Mountpoint for the .snapshots
            Subvolume in the Initial Snapshot Subvolume
        
Make a directory under the initial snapshot subvolume to be used as a mountpoint for the snapshots
        subvolume. This directory will correspond to the mountpoint we have already specified for the .snapshots subvolume when we edited the Ubuntu installation's etc/fstab in Part 7.
       
      - 
        Part 10: Change the Default BtrfsSubvolume from /, Subvolume ID 5 to
            the Initial Snapshot Subvolume /@/.snapshots/1/snapshot
        
Set the Btrfs default subvolume to the initial snapshot subvolume. This will ensure that it is
        mounted automatically at / without mount options that explicitly specify the
        subvolume. When a rollback is performed with Snapper, it will change the default subvolume to the one it
        creates to be used as the new system root, so that it will be mounted automatically.
       
      - 
        Part 11: Chroot to the Installed System and Reinstall GRUB Firmware, Update GRUB, and Regenerate
            Initramfs Reinstall the GRUB firmware to avoid being placed in a GRUB shell when rebooting to the
        Ubuntu system at the end of the process. Also, update GRUB so that its configuration reflects the new kernel
        image and initial RAM filesystem paths in the initial snapshot subvolume mounted as the root of the filesystem
        hierarchy. The initial RAM filesystem must also be regenerated.
        
       
      - 
        Part 12: Reboot Into Converted System with Btrfs Subvolume Layout and Working Snapper Configuration
            and Make Final Adjustments to System Configuration
        
Finally, reboot into the Ubuntu system and make final adjustments to the system, such as adjusting the
        frequency of and conditions for automatic snapshot creation and cleanup, as well as other related parameters.
       
    
    
   
  
    Part 1: Prepare
      the Ext4 Filesystem to Be converted to Btrfs
    
      Before using the btrfs-convert command, the ext4 filesystem must be in a
      suitable state for conversion. The filesystem must be error free; it is recommended to perform a a check and, if
      necessary, a repair of the ext4 filesystem with e2fsck command typically
      available from a package named e2fsprogs. The filesystem must also have adequate
      free space to perform the conversion; btrfs-convert(8) states that although the
      necessary free space can not be predicted before the conversion is performed, several GB of free space may be
      required per 100GB of filesystem size. It may be helpful to delete unnecessary files, check for fragmentation and
      defragment if necessary with the e4defrag command, also available from the e2fsprogs package.
    
    
      The last requirement is that the filesystem block size must be one that is supported by btrfs-convert, which is the same as a valid value for the mkfs.btrfs --sectorsize option. The btrfs-convert man page states that this "is typically the system page size (4KiB on
      x86_64 machines)", which in my case is the same as the value reported by the tune2fs command.(See Reference 6.)
    
    
    
      - 
        Determine the kernel block device name of the partition to be converted as this will be used as an argument to
        the btrfs-convert and any utilities used to prepare the filesystem.
      
 
      - 
        Check the filesystem level block size of the ext4 partition to be converted.
        
tune2fs -l /dev/nvme1n1p7
       
      - 
        Delete unnecessary files if there isn't an adequate amount of free space on the partition.
      
 
      - 
        Determine the level of fragmentation of the ext4 partition to be converted with e4defrag. If so, defragment the filesystem with the same tool. (See Reference 3)
      
 
      - 
        Unmount the ext4 filesystem to be converted, if it is mounted, and check the filesystem and repair with
        the e2fsck command. (See Reference )
      
 
    
    
   
  
    Part 2: Convert the ext4
      Root Partition to Btrfs
    
      The actual Ubuntu root ext4 filesystem conversion is very simple and only requires executing the btrfs-convert command from the external Linux while the Ubuntu root partition is
      unmounted. The command has numerous options that allow specifying the characteristics of the converted
      Btrfs filesystem but can be used without any options to use default options. It only takes one argument
      which specifies the block device identification of the partition to be converted.
    
      - 
        Execute the btrfs-convert command in the external Linux.
        
σ°Ή 100%  18:18:15  USER: brook HOST: ARCH-16ITH6
~  β―$ sudo btrfs-convert /dev/nvme1n1p7
        The output from this command is shown in the left pane of the terminal in the first two images of the following
        set of images, the first taken while the command is still running, and the second after the command has
        completed.
       
      - 
        Mount the converted filesystem.
        
σ°Ή 100%  18:40:30  USER: brook HOST: ARCH-16ITH6
~  β―$ sudo mount /dev/nvme1n1p7 /mnt/ubuntu-root
       
      - 
        Verify the mount.
        
σ°Ή 100%  18:40:55  USER: brook HOST: ARCH-16ITH6
~  β―$ mount | grep /mnt
dev/nvme1n1p7 on /mnt/ubuntu-root type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=5,subvol=/)
       
      - 
        View the statistics of the newly converted filesystem with the commands:
        
btrfs filesystem show
        as shown in the following listing
        σ°Ή 100%  18:42:20  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs filesystem show /mnt/ubuntu-root/
Label: 'UBUNTU_ROOT'  uuid: 72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43
        Total devices 1 FS bytes used 30.72GiB
        devid    1 size 72.50GiB used 52.75GiB path /dev/nvme1n1p7
        and
        btrfs subvolume list
        as shown in the following listing
        σ°Ή 100%  18:42:31  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume list /mnt/ubuntu-root/
ID 256 gen 3 top level 5 path ext2_saved
        The contents of the filesystem can be viewed with the ls command with the mountpoint as an
        argument.
        The left pane of the terminal displayed in the third image of the following set shows the output of the above
        Btrfs commands as well as the directory listing.
       
      - 
        Delete the backup of the original filesystem image saved in a subvolume named ext2_saved created by btrfs-convert.
        
σ°Ή 100%  18:51:55  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume delete /mnt/ubuntu-root/ext2_saved
[sudo] password for brook:
Delete subvolume 256 (no-commit): '/mnt/ubuntu-root/ext2_saved'
       
    
    
    
    
      
      
      
        
          Figures 2a, 2b, and 2c: Converting the Ubuntu Installation's Ext4 Filesystem Hierarchy Root Partition to
          Btrfs
        
        
          The conversion is performed with the btrfs-convert command with an argument identifying the
          partition (unmounted) to be converted.
          
          Click on any of the thumbnails to view a larger image.
        
        
          
        
       
     
    
    
   
  
    Part 3: Create the Subvolumes for the Desired Subvolume Layout
    
      In Part 2, after converting the ext4 filesystem to Btrfs, we mounted the partition, specifically the
      top level subvolume -- the only subvolume at this point, and viewed the filesystem statistics. We continue working
      on the filesystem from our external Linux installation or live ISO.
    
      - 
        Create a the subvolume that will contain all other subvolumes (subvolume path /@).
        
σ°Ή 100%  18:56:42  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@
Create subvolume '/mnt/ubuntu-root/@'
       
      - 
        Create subvolumes under subvolume path /@ for the filesystem hierarchy paths that
        are to be excluded from system snapshots.
        
σ°Ή 100%  18:59:55  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@opt
Create subvolume '/mnt/ubuntu-root/@/@opt'
σ°Ή 100%  19:01:31  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@root
Create subvolume '/mnt/ubuntu-root/@/@root'
σ°Ή 100%  19:01:40  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@srv
Create subvolume '/mnt/ubuntu-root/@/@srv'
σ°Ή 100%  19:01:47  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@usrlocal
Create subvolume '/mnt/ubuntu-root/@/@usrlocal'
σ°Ή 100%  19:01:58  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@varcache
Create subvolume '/mnt/ubuntu-root/@/@varcache'
σ°Ή 100%  19:02:09  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@varlog
Create subvolume '/mnt/ubuntu-root/@/@varlog'
σ°Ή 100%  19:02:16  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume create -p /mnt/ubuntu-root/@/@vartmp
Create subvolume '/mnt/ubuntu-root/@/@vartmp'
       
      - 
        List the subvolumes.
        
σ°Ή 100%  19:02:24  USER: brook HOST: ARCH-16ITH6
 ~  β―$ sudo btrfs subvolume list /mnt/ubuntu-root/
ID 257 gen 1168 top level 5 path @
ID 258 gen 1167 top level 257 path @/@opt
ID 259 gen 1167 top level 257 path @/@root
ID 260 gen 1167 top level 257 path @/@srv
ID 261 gen 1167 top level 257 path @/@usrlocal
ID 262 gen 1168 top level 257 path @/@varcache
ID 263 gen 1168 top level 257 path @/@varlog
ID 264 gen 1168 top level 257 path @/@vartmp
       
      - 
        View the directory listing of the Ubuntu root partition mounted in the external Linux. Because it is a
        filesystem the mount is of a specific subvolume, in this case the top-level subvolume automatically created at
        filesystem creation or conversion to Btrfs.
        
σ°Ή 100%  19:06:54  USER: brook HOST: ARCH-16ITH6
 ~  β―$ ls -la /mnt/ubuntu-root
total 32
drwxr-xr-x 1 root root  238 Oct 11 18:59  ./
drwxr-xr-x 1 root root   22 Oct 10 17:16  ../
drwxr-xr-x 1 root root   90 Oct 11 19:02 '@'/
lrwxrwxrwx 1 root root    7 May 27  2022  bin -> usr/bin/
drwxr-xr-x 1 root root  492 Oct 10 19:20  boot/
drwxr-xr-x 1 root root    0 May 27  2022  cdrom/
drwxr-xr-x 1 root root  128 Apr 19  2022  dev/
drwxr-xr-x 1 root root 5084 Oct 10 19:20  etc/
drwxr-xr-x 1 root root   20 Oct 10 18:21  home/
-rw------- 1 root root   64 Oct 10 19:08  i7lp616G-el
lrwxrwxrwx 1 root root    7 May 27  2022  lib -> usr/lib/
lrwxrwxrwx 1 root root    9 Oct  3 17:54  lib32 -> usr/lib32/
lrwxrwxrwx 1 root root    9 May 27  2022  lib64 -> usr/lib64/
lrwxrwxrwx 1 root root   10 May 27  2022  libx32 -> usr/libx32/
drwx------ 1 root root    0 May 27  2022  lost+found/
drwxr-xr-x 1 root root   44 Jul 10  2023  media/
drwxr-xr-x 1 root root   42 Nov 24  2023  mnt/
drwxr-xr-x 1 root root  106 Oct  3 18:32  opt/
drwxr-xr-x 1 root root    0 Apr 18  2022  proc/
drwx------ 1 root root  256 Oct 11 18:03  root/
drwxr-xr-x 1 root root  284 May 27  2022  run/
lrwxrwxrwx 1 root root    8 May 27  2022  sbin -> usr/sbin/
drwxr-xr-x 1 root root   18 May 26  2023  snap/
drwxr-xr-x 1 root root    0 Apr 19  2022  srv/
drwxr-xr-x 1 root root    0 Apr 18  2022  sys/
drwxrwxrwt 1 root root  384 Oct 10 19:20  tmp/
drwxr-xr-x 1 root root  116 Dec  2  2023  usr/
drwxr-xr-x 1 root root  130 Oct  3 18:18  var/
-rw------- 1 root root   64 Oct  3 18:13  zNUV1bYp-el
        Note the @/ directory which allows us to access the newly created /@ subvolume.
       
      - 
        We can view the contents of this directory.
        
σ°Ή 100%  19:12:52  USER: brook HOST: ARCH-16ITH6
 ~  β―$ ls -la /mnt/ubuntu-root/@
total 0
drwxr-xr-x 1 root root  90 Oct 11 19:02  ./
drwxr-xr-x 1 root root 238 Oct 11 18:59  ../
drwxr-xr-x 1 root root   0 Oct 11 19:01 '@opt'/
drwxr-xr-x 1 root root   0 Oct 11 19:01 '@root'/
drwxr-xr-x 1 root root   0 Oct 11 19:01 '@srv'/
drwxr-xr-x 1 root root   0 Oct 11 19:01 '@usrlocal'/
drwxr-xr-x 1 root root   0 Oct 11 19:02 '@varcache'/
drwxr-xr-x 1 root root   0 Oct 11 19:02 '@varlog'/
drwxr-xr-x 1 root root   0 Oct 11 19:02 '@vartmp'/
        As of now, these directories (and their corresponding subvolumes) are empty. In the next part, we will move the
        contents of the respective filesystem hierarchy paths to the subvolumes.
       
    
    
   
  
    Part 4: Move Files from the Top Level BtrfsSubvolume (subvolume path
      /, subvolume ID 5) to the Newly Created Subvolumes
    
      In this part, we will move the contents of the filesystem hierarchy paths /opt,
      /root, /srv, /usr/local, /var/cache, /var/log and, /var/tmp to the respective subvolumes
      created in the last part to contain them, respectively, /@/@opt, /@/@root, /@/srv, /@/@usrlocal, /@/@varcache, /@/@varlog and, /@/@vartmp. The files and directories
      under these paths will be excluded from system snapshots and remain in these subvolumes in the final system.
    
    
      We will then move the remaining contents of the top-level subvolume (subvolume path /, subvolume ID 5) to the other subvolume created in the previous step (subvolume path
      /@, subvolume ID 257). This is an intermediate step before moving these files and
      directories to their final destination in the initial snapshot subvolume in Part 6, after creating the subvolume
      for the initial snapshot in Part 5.
    
      - 
        It was necessary to switch to root when performing this process at this point
        with the external Linux used in this process.
        
σ°Ή 100%  19:15:00  USER: brook HOST: ARCH-16ITH6
PCD: 12s ~  β―$ su
Password:
       
      - 
        Move the contents of filesystem hierarchy path /opt, currently at subvolume path
        / in the external Linux path /mnt/ubuntu-root/opt
        to the @opt subvolume, which in the external Linux is at path /mnt/ubuntu-root/@/@opt/.
        
[root@ARCH-16ITH6 brook]# mv -v /mnt/ubuntu-root/opt/* /mnt/ubuntu-root/@/@opt/
created directory '/mnt/ubuntu-root/@/@opt/firefox-beta'
copied '/mnt/ubuntu-root/opt/firefox-beta/application.ini' -> '/mnt/ubuntu-root/@/@opt/firefox-beta/application.ini'
copied '/mnt/ubuntu-root/opt/firefox-beta/libnss3.so' -> '/mnt/ubuntu-root/@/@opt/firefox-beta/libnss3.so'
copied '/mnt/ubuntu-root/opt/firefox-beta/update-settings.ini' -> '/mnt/ubuntu-root/@/@opt/firefox-beta/update-settings.ini'
... truncated ...
       
      - 
        Move the contents of filesystem hierarchy path /root, currently at subvolume path
        / in the external Linux path /mnt/ubuntu-root/root
        to the @root subvolume, which in the external Linux is at path /mnt/ubuntu-root/@/@opt/.
        
[root@ARCH-16ITH6 brook]# mv -v /mnt/ubuntu-root/root/* /mnt/ubuntu-root/@/@root/
... truncated ...
        We can confirm all files were moved from /mnt/ubuntu-root/root to /mnt/ubuntu-root/@/@root (from within subvolume path 
        to subvolume /@/@root in terms of the Ubuntu's new Btrfs partition):
        [root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/@/@root
total 36
drwxr-xr-x 1 root root   256 Oct 11 19:19 .
drwxr-xr-x 1 root root    90 Oct 11 19:02 ..
-rw------- 1 root root  1181 Oct 11 18:06 .bash_history
-rw-r--r-- 1 root root  3106 Oct 15  2021 .bashrc
drwx------ 1 root root   238 Nov 23  2023 .cache
drwx------ 1 root root    18 Mar 14  2023 .config
drwx------ 1 root root    22 Feb 25  2023 .dbus
drwx------ 1 root root    34 May 24  2022 .launchpadlib
-rw------- 1 root root    44 Oct 11 18:03 .lesshst
drwxr-xr-x 1 root root    20 Nov 27  2023 .local
-rw-r--r-- 1 root root   161 Jul  9  2019 .profile
drwx------ 1 root root    84 May 27  2022 snap
drwx------ 1 root root     0 May 26  2023 .ssh
-rw-r--r-- 1 root root     0 Mar  8  2023 .sudo_as_admin_successful
drwxr-xr-x 1 root root    20 Dec  2  2023 .vim
-rw------- 1 root root 13339 Dec  2  2023 .viminfo
-rw-r--r-- 1 root root   165 Nov 24  2023 .wget-hsts
        Note that in this case all files, including hidden files, have been moved, However, depending on the shell and
        the external Linux's shell configuration, hidden files may not be moved when using mv with the
        * glob. (See Reference 7.)
       
      - 
        Move the contents of filesystem hierarchy path /usr/local, currently at subvolume
        path / in the external Linux path /mnt/ubuntu-root/usr/local to the @usrlocal subvolume,
        which in the external Linux is at path /mnt/ubuntu-root/@/@usrlocal/.
        
[root@ARCH-16ITH6 brook]# mv -v /mnt/ubuntu-root/usr/local/* /mnt/ubuntu-root/@/@usrlocal/
... truncated ...
       
      - 
        Move the contents of filesystem hierarchy path /var/cache, currently at subvolume
        path / in the external Linux path /mnt/ubuntu-root/var/cache to the @varcache subvolume,
        which in the external Linux is at path /mnt/ubuntu-root/@/@varcache/.
        
[root@ARCH-16ITH6 brook]# mv -v /mnt/ubuntu-root/var/cache/* /mnt/ubuntu-root/@/@varcache/
... truncated ...
       
      - 
        Move the contents of filesystem hierarchy path /var/log, currently at subvolume
        path / in the external Linux path /mnt/ubuntu-root/var/log to the @varlog subvolume,
        which in the external Linux is at path /mnt/ubuntu-root/@/@varlog/.
        
[root@ARCH-16ITH6 brook]# mv -v /mnt/ubuntu-root/var/log/* /mnt/ubuntu-root/@/@varlog/
... truncated ...
       
      - 
        Move the contents of filesystem hierarchy path /var/tmp, currently at subvolume
        path / in the external Linux path /mnt/ubuntu-root/var/tmp to the @vartmp subvolume,
        which in the external Linux is at path /mnt/ubuntu-root/@/@vartmp/.
        
[root@ARCH-16ITH6 brook]# mv -v /mnt/ubuntu-root/var/tmp/* /mnt/ubuntu-root/@/@vartmp/
... truncated ...
       
      - 
        List the contents of the top-level subvolume, subvolume path / currently mounted
        in the external Linux at /mnt/ubuntu-root
        
[root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/
total 32
drwxr-xr-x 1 root root  238 Oct 11 18:59 .
drwxr-xr-x 1 root root   22 Oct 10 17:16 ..
drwxr-xr-x 1 root root   90 Oct 11 19:02 @
lrwxrwxrwx 1 root root    7 May 27  2022 bin -> usr/bin
drwxr-xr-x 1 root root  492 Oct 10 19:20 boot
drwxr-xr-x 1 root root    0 May 27  2022 cdrom
drwxr-xr-x 1 root root  128 Apr 19  2022 dev
drwxr-xr-x 1 root root 5084 Oct 10 19:20 etc
drwxr-xr-x 1 root root   20 Oct 10 18:21 home
-rw------- 1 root root   64 Oct 10 19:08 i7lp616G-el
lrwxrwxrwx 1 root root    7 May 27  2022 lib -> usr/lib
lrwxrwxrwx 1 root root    9 Oct  3 17:54 lib32 -> usr/lib32
lrwxrwxrwx 1 root root    9 May 27  2022 lib64 -> usr/lib64
lrwxrwxrwx 1 root root   10 May 27  2022 libx32 -> usr/libx32
drwx------ 1 root root    0 May 27  2022 lost+found
drwxr-xr-x 1 root root   44 Jul 10  2023 media
drwxr-xr-x 1 root root   42 Nov 24  2023 mnt
drwxr-xr-x 1 root root    0 Oct 11 19:16 opt
drwxr-xr-x 1 root root    0 Apr 18  2022 proc
drwx------ 1 root root    0 Oct 11 19:19 root
drwxr-xr-x 1 root root  284 May 27  2022 run
lrwxrwxrwx 1 root root    8 May 27  2022 sbin -> usr/sbin
drwxr-xr-x 1 root root   18 May 26  2023 snap
drwxr-xr-x 1 root root    0 Apr 19  2022 srv
drwxr-xr-x 1 root root    0 Apr 18  2022 sys
drwxrwxrwt 1 root root  384 Oct 10 19:20 tmp
drwxr-xr-x 1 root root  116 Dec  2  2023 usr
drwxr-xr-x 1 root root  130 Oct  3 18:18 var
-rw------- 1 root root   64 Oct  3 18:13 zNUV1bYp-el
       
      - 
        Remove the directories at filesystem paths that are to be excluded from the system snapshots. Since we moved
        them in Steps 2 - 7, above, they are now empty. This is evident in the above listing for /opt and /root.
        
[root@ARCH-16ITH6 brook]# rm -r /mnt/ubuntu-root/{opt,root,srv,usr/local,var/cache,var/log,var/tmp}
       
      - 
        For comparison with the state after the next step, list the contents of the /@
        subvolume in the Ubuntu Btrfsfilesystem, currently accessible in the external Linux at /mnt/ubuntu-root/@
        
[root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/@
total 0
drwxr-xr-x 1 root root   90 Oct 11 19:02 .
drwxr-xr-x 1 root root  218 Oct 11 19:36 ..
drwxr-xr-x 1 root root  106 Oct 11 19:16 @opt
drwxr-xr-x 1 root root  256 Oct 11 19:19 @root
drwxr-xr-x 1 root root    0 Oct 11 19:01 @srv
drwxr-xr-x 1 root root   86 Oct 11 19:20 @usrlocal
drwxr-xr-x 1 root root  306 Oct 11 19:23 @varcache
drwxr-xr-x 1 root root 2808 Oct 11 19:24 @varlog
drwxr-xr-x 1 root root    0 Oct 11 19:02 @vartmp
        Note that it is empty of actual files and directories. The output shows the subvolumes represented as
        directories since the top level subvolume, subvolume / is mounted in the external
        Linux at /mnt/ubuntu-root.
       
      - 
        Move the remaining contents of top level subvolume (subvolume path /) to
        subvolume path /@.
        
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/* /mnt/ubuntu-root/@/
mv: cannot move '/mnt/ubuntu-root/@' to a subdirectory of itself, '/mnt/ubuntu-root/@/@'
        The error displayed does not matter; the remaining contents of /mnt/ubuntu-root
        have been moved to /mnt/ubuntu-root/@ in terms of the external Linux filesystem
        hierarchy, and in terms of the Btrfssubvolumes on the Ubuntu partition, /
        to /@. The following listing confirms this.
        [root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/@
total 32
drwxr-xr-x 1 root root  306 Oct 11 19:41 .
drwxr-xr-x 1 root root    2 Oct 11 19:41 ..
lrwxrwxrwx 1 root root    7 May 27  2022 bin -> usr/bin
drwxr-xr-x 1 root root  492 Oct 10 19:20 boot
drwxr-xr-x 1 root root    0 May 27  2022 cdrom
drwxr-xr-x 1 root root  128 Apr 19  2022 dev
drwxr-xr-x 1 root root 5084 Oct 10 19:20 etc
drwxr-xr-x 1 root root   20 Oct 10 18:21 home
-rw------- 1 root root   64 Oct 10 19:08 i7lp616G-el
lrwxrwxrwx 1 root root    7 May 27  2022 lib -> usr/lib
lrwxrwxrwx 1 root root    9 Oct  3 17:54 lib32 -> usr/lib32
lrwxrwxrwx 1 root root    9 May 27  2022 lib64 -> usr/lib64
lrwxrwxrwx 1 root root   10 May 27  2022 libx32 -> usr/libx32
drwx------ 1 root root    0 May 27  2022 lost+found
drwxr-xr-x 1 root root   44 Jul 10  2023 media
drwxr-xr-x 1 root root   42 Nov 24  2023 mnt
drwxr-xr-x 1 root root  106 Oct 11 19:16 @opt
drwxr-xr-x 1 root root    0 Apr 18  2022 proc
drwxr-xr-x 1 root root  256 Oct 11 19:19 @root
drwxr-xr-x 1 root root  284 May 27  2022 run
lrwxrwxrwx 1 root root    8 May 27  2022 sbin -> usr/sbin
drwxr-xr-x 1 root root   18 May 26  2023 snap
drwxr-xr-x 1 root root    0 Oct 11 19:01 @srv
drwxr-xr-x 1 root root    0 Apr 18  2022 sys
drwxrwxrwt 1 root root  384 Oct 10 19:20 tmp
drwxr-xr-x 1 root root  106 Oct 11 19:36 usr
drwxr-xr-x 1 root root   86 Oct 11 19:20 @usrlocal
drwxr-xr-x 1 root root  108 Oct 11 19:36 var
drwxr-xr-x 1 root root  306 Oct 11 19:23 @varcache
drwxr-xr-x 1 root root 2808 Oct 11 19:24 @varlog
drwxr-xr-x 1 root root    0 Oct 11 19:02 @vartmp
-rw------- 1 root root   64 Oct  3 18:13 zNUV1bYp-el
       
      - 
        Unmount the Ubuntu partition.
        
[root@ARCH-16ITH6 brook]# umount --recursive /mnt/ubuntu-root
       
    
    
   
  
    
    
    
  
  
    Part 5: Install Snapper and Create Initial Snapshot Subvolume
    
      In this part, we will install Snapper and initialize its configuration, which will automatically create a
      subvolume for snapshots named .snapshots directly under the subvolume mounted at
      the filesystem hierarchy root when the initialization command is executed; the subvolume path of this subvolume
      will be at /@/.snapshots. Then we will create the initial snapshot subvolume at
      subvolume path /@/.snapshots/1/snapshot, which at the end of the process will
      contain the Ubuntu installation's filesystem hierarchy root, except the paths that are excluded from system
      snapshots which will be in their own respective subvolumes, e.g., /opt at /@/@opt, /root at /@/@root, etc.
    
    
      To do this we will chroot into the installed Ubuntu system, mounting the /@
      subvolume -- which currently contains the filesystem hierarchy root of the Ubuntu installation after the actions
      in Part 4 -- at /mnt/ubuntu-root and the other subvolumes at appropriate
      mountpoints, e.g., /@/@opt at /mnt/ubuntu-root/opt.
    
    
    
      - 
        Mount the new /@ subvolume, the other new subvolumes created for filesystem
        hieraarchy paths to be excluded from snapshots, the EFI System Partition and all of the pseudo filesystems
        needed for the chroot.
        
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root -o subvol=/@
[root@ARCH-16ITH6 brook]# mount UUID="dbe875a9-94a3-4831-8697-0e869ec4a65f" /mnt/ubuntu-root/home
[root@ARCH-16ITH6 brook]# mount UUID="CEFD-1322" /mnt/ubuntu-root/boot/efi
[root@ARCH-16ITH6 brook]# mount -t proc /proc /mnt/ubuntu-root/proc/
[root@ARCH-16ITH6 brook]# mount -t sysfs /sys /mnt/ubuntu-root/sys/
[root@ARCH-16ITH6 brook]# mount -o bind /dev /mnt/ubuntu-root/dev/
[root@ARCH-16ITH6 brook]# mount -o bind /dev/pts /mnt/ubuntu-root/dev/pts/
[root@ARCH-16ITH6 brook]# mount -o bind /run /mnt/ubuntu-root/run/
[root@ARCH-16ITH6 brook]# mount -o bind /sys/firmware/efi/efivars /mnt/ubuntu-root/sys/firmware/efi/efivars/
[root@ARCH-16ITH6 brook]# mkdir /mnt/ubuntu-root/{opt,root,srv,usr/local,var/cache,var/log,var/tmp}
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/opt -o subvol=/@/@opt
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/root -o subvol=/@/@root
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/srv -o subvol=/@/@srv
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/var/cache -o subvol=/@/@varcache
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/var/log -o subvol=/@/@varlog
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/var/tmp -o subvol=/@/@vartmp
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/usr/local -o subvol=/@/@usrlocal
       
      - 
        Copy /etc/resolv.conf from the external Linux chroot host to the installed
        Ubuntu, the installation into which we are chrooting.
        
[root@ARCH-16ITH6 brook]# cp /etc/resolv.conf /mnt/ubuntu-root/etc/resolv.conf
        If the Ubuntu installation uses systemd-resolved service, /etc/resolv.conf will be a symbolic link to /run/systemd/resolv/stub-resolv.conf. It will be necessary to unlink the file with
        unlink /mnt/ubuntu-root/etc/resolv.conf
       
      - 
        Chroot into the installed Ubuntu system.
        
[root@ARCH-16ITH6 brook]# chroot /mnt/ubuntu-root /bin/bash
       
      - 
        Verify the chroot by viewing the contents of /etc/os-release. The external Linux
        used for this process was Arch, so the output in the following listing confirms the chroot is active.
        
root@ARCH-16ITH6:/# cat /etc/os-release
PRETTY_NAME="Ubuntu 24.10"
NAME="Ubuntu"
VERSION_ID="24.10"
VERSION="24.10 (Oracular Oriole)"
VERSION_CODENAME=oracular
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=oracular
LOGO=ubuntu-logo
       
      - 
        Install Snapper.
        
root@ARCH-16ITH6:/# apt install snapper
The following package was automatically installed and is no longer required:
  libiw30t64
Use 'apt autoremove' to remove it.
Installing:
  snapper
Installing dependencies:
  libbtrfs0t64  libsnapper7t64
Summary:
  Upgrading: 0, Installing: 3, Removing: 0, Not Upgrading: 1
  Download size: 761 kB
  Space needed: 2,930 kB / 45.8 GB available
Continue? [Y/n]
Get:1 http://us.archive.ubuntu.com/ubuntu oracular/main amd64 libbtrfs0t64 amd64 6.6.3-1.2 [13.5 kB]
Get:2 http://us.archive.ubuntu.com/ubuntu oracular/universe amd64 libsnapper7t64 amd64 0.10.6-1.1build1 [307 kB]
Get:3 http://us.archive.ubuntu.com/ubuntu oracular/universe amd64 snapper amd64 0.10.6-1.1build1 [441 kB]
Fetched 761 kB in 1s (917 kB/s)
Selecting previously unselected package libbtrfs0t64:amd64.
(Reading database ... 426979 files and directories currently installed.)
Preparing to unpack .../libbtrfs0t64_6.6.3-1.2_amd64.deb ...
Unpacking libbtrfs0t64:amd64 (6.6.3-1.2) ...
Selecting previously unselected package libsnapper7t64:amd64.
Preparing to unpack .../libsnapper7t64_0.10.6-1.1build1_amd64.deb ...
Unpacking libsnapper7t64:amd64 (0.10.6-1.1build1) ...
Selecting previously unselected package snapper.
Preparing to unpack .../snapper_0.10.6-1.1build1_amd64.deb ...
Unpacking snapper (0.10.6-1.1build1) ...
Setting up libbtrfs0t64:amd64 (6.6.3-1.2) ...
Setting up libsnapper7t64:amd64 (0.10.6-1.1build1) ...
Setting up snapper (0.10.6-1.1build1) ...
Created symlink '/etc/systemd/system/timers.target.wants/snapper-boot.timer' β
'/usr/lib/systemd/system/snapper-boot.timer'.
Created symlink '/etc/systemd/system/timers.target.wants/snapper-cleanup.timer' β
'/usr/lib/systemd/system/snapper-cleanup.timer'.
Created symlink '/etc/systemd/system/timers.target.wants/snapper-timeline.timer' β
'/usr/lib/systemd/system/snapper-timeline.timer'.
Created symlink '/etc/systemd/system/sysinit.target.wants/snapperd.service' β
'/usr/lib/systemd/system/snapperd.service'.
Running in chroot, ignoring command 'daemon-reload'
Running in chroot, ignoring command 'is-active'
snapper-boot.service is a disabled or a static unit, not starting it.
Running in chroot, ignoring command 'is-active'
Running in chroot, ignoring command 'is-active'
snapper-cleanup.service is a disabled or a static unit, not starting it.
Running in chroot, ignoring command 'is-active'
Running in chroot, ignoring command 'is-active'
snapper-timeline.service is a disabled or a static unit, not starting it.
Running in chroot, ignoring command 'is-active'
Running in chroot, ignoring command 'is-active'
Running in chroot, ignoring command 'start'
Processing triggers for man-db (2.12.1-3) ...
Processing triggers for dbus (1.14.10-4ubuntu5) ...
Processing triggers for libc-bin (2.40-1ubuntu3) ...
       
      - 
        List the subvolumes for comparison of the current state to the state after the next step.
        
root@ARCH-16ITH6:/# btrfs subvolume list /
ID 257 gen 1192 top level 5 path @
ID 258 gen 1171 top level 257 path @opt
ID 259 gen 1190 top level 257 path @root
ID 260 gen 1177 top level 257 path @srv
ID 261 gen 1192 top level 257 path @usrlocal
ID 262 gen 1193 top level 257 path @varcache
ID 263 gen 1192 top level 257 path @varlog
ID 264 gen 1179 top level 257 path @vartmp
       
      - 
        Create the Snapper configuration for managing snapshots of the subvolume mounted at the filesystem
        hierarchy root.
        
root@ARCH-16ITH6:/# snapper --no-dbus -c root create-config /
       
      - 
        List the subvolumes to compare to the previous state. Now, after the Snapper configuration command, there
        is a new subvolume called .snapshots under the /@
        subvolume.
        
root@ARCH-16ITH6:/# btrfs subvolume list /
ID 257 gen 1192 top level 5 path @
ID 258 gen 1171 top level 257 path @opt
ID 259 gen 1190 top level 257 path @root
ID 260 gen 1177 top level 257 path @srv
ID 261 gen 1192 top level 257 path @usrlocal
ID 262 gen 1193 top level 257 path @varcache
ID 263 gen 1192 top level 257 path @varlog
ID 264 gen 1179 top level 257 path @vartmp
ID 265 gen 1194 top level 257 path .snapshots
       
      - 
        Create initial snapshot subvolume under /@/.snapshots.
        
root@ARCH-16ITH6:/# btrfs subvolume create -p /.snapshots/1/snapshot
Create subvolume '/.snapshots/1/snapshot'
       
      - 
        List the subvolumes. There is a new subvolume at subvolume path /@/.snapshots/1/snapshot.
        
root@ARCH-16ITH6:/# btrfs subvolume list /
ID 257 gen 1194 top level 5 path @
ID 258 gen 1171 top level 257 path @opt
ID 259 gen 1190 top level 257 path @root
ID 260 gen 1177 top level 257 path @srv
ID 261 gen 1192 top level 257 path @usrlocal
ID 262 gen 1193 top level 257 path @varcache
ID 263 gen 1192 top level 257 path @varlog
ID 264 gen 1179 top level 257 path @vartmp
ID 265 gen 1194 top level 257 path .snapshots
ID 266 gen 1195 top level 265 path .snapshots/1/snapshot
       
      - 
        Exit the chroot.
        
root@ARCH-16ITH6:/# exit
exit
       
    
    
   
  
    Part 6: Move Files from Subvolume Path /@ to
      Subvolume Path /@/.snapshots/1/snapshot
    
      At this point in the process, the contents of the paths /opt, /root, /usr/local, /var/cache, /var/log, and /var/tmp that were in the top-level subvolume immediately after the conversion have
      been relocated to their respective subvolumes under subvolume path /@. The
      remaining contents of the top-level subvolume were moved temporarily to /@. In this
      part we move the contents of /@ to the initial snapshot subvolume, /@/.snapshots/1/snapshot, realizing the desired subvolume layout illustrated in the
      right part of the image at the top of the article.
    
      - 
        Move files from subvolume path /@ to subvolume path /@/.snapshots/1/snapshot. To avoid the errors shown in the output, first unmount the
        EFI System Partition and the pseudo filesystems, mounted for the chroot.
        
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/* /mnt/ubuntu-root/.snapshots/1/snapshot/
mv: cannot move '/mnt/ubuntu-root/boot/efi' to '/mnt/ubuntu-root/.snapshots/1/snapshot/boot/efi': Device or resource busy
mv: cannot move '/mnt/ubuntu-root/dev' to '/mnt/ubuntu-root/.snapshots/1/snapshot/dev': Device or resource busy
mv: cannot move '/mnt/ubuntu-root/proc' to '/mnt/ubuntu-root/.snapshots/1/snapshot/proc': Device or resource busy
mv: cannot move '/mnt/ubuntu-root/run' to '/mnt/ubuntu-root/.snapshots/1/snapshot/run': Device or resource busy
mv: cannot move '/mnt/ubuntu-root/sys' to '/mnt/ubuntu-root/.snapshots/1/snapshot/sys': Device or resource busy
        [root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root /mnt/ubuntu-root/.snapshots/1/snapshot
/mnt/ubuntu-root:
total 0
drwxr-xr-x   1 root root   54 Oct 11 20:32 .
drwxr-xr-x   1 root root   22 Oct 10 17:16 ..
drwxr-xr-x   1 root root  492 Oct 10 19:20 boot
drwxr-xr-x  24 root root 5500 Oct 11 16:50 dev
dr-xr-xr-x 505 root root    0 Oct 11 19:51 proc
drwxr-xr-x  34 root root  960 Oct 11 18:50 run
drwxr-x---   1 root root    2 Oct 11 20:08 .snapshots
dr-xr-xr-x  13 root root    0 Oct 11 20:14 sys
/mnt/ubuntu-root/.snapshots/1/snapshot:
total 32
drwxr-xr-x 1 root root  300 Oct 11 20:32 .
drwxr-xr-x 1 root root   16 Oct 11 20:08 ..
lrwxrwxrwx 1 root root    7 May 27  2022 bin -> usr/bin
drwxr-xr-x 1 root root  486 Oct 10 19:20 boot
drwxr-xr-x 1 root root    0 May 27  2022 cdrom
drwxr-xr-x 1 root root 5098 Oct 11 20:06 etc
drwxr-xr-x 1 root root   20 Oct 10 18:21 home
-rw------- 1 root root   64 Oct 10 19:08 i7lp616G-el
lrwxrwxrwx 1 root root    7 May 27  2022 lib -> usr/lib
lrwxrwxrwx 1 root root    9 Oct  3 17:54 lib32 -> usr/lib32
lrwxrwxrwx 1 root root    9 May 27  2022 lib64 -> usr/lib64
lrwxrwxrwx 1 root root   10 May 27  2022 libx32 -> usr/libx32
drwx------ 1 root root    0 May 27  2022 lost+found
drwxr-xr-x 1 root root   44 Jul 10  2023 media
drwxr-xr-x 1 root root   42 Nov 24  2023 mnt
drwxr-xr-x 1 root root  106 Oct 11 19:16 @opt
drwxr-xr-x 1 root root    0 Oct 11 19:59 opt
drwxr-xr-x 1 root root  256 Oct 11 19:19 @root
drwxr-xr-x 1 root root    0 Oct 11 19:59 root
lrwxrwxrwx 1 root root    8 May 27  2022 sbin -> usr/sbin
drwxr-xr-x 1 root root   18 May 26  2023 snap
drwxr-xr-x 1 root root    0 Oct 11 19:01 @srv
drwxr-xr-x 1 root root    0 Oct 11 19:59 srv
drwxrwxrwt 1 root root  384 Oct 10 19:20 tmp
drwxr-xr-x 1 root root  116 Oct 11 19:59 usr
drwxr-xr-x 1 root root   86 Oct 11 19:20 @usrlocal
drwxr-xr-x 1 root root  130 Oct 11 19:59 var
drwxr-xr-x 1 root root  306 Oct 11 19:23 @varcache
drwxr-xr-x 1 root root 2808 Oct 11 19:24 @varlog
drwxr-xr-x 1 root root    0 Oct 11 19:02 @vartmp
-rw------- 1 root root   64 Oct  3 18:13 zNUV1bYp-el
[root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/.* /mnt/ubuntu-root/.snapshots/1/snapshot
/mnt/ubuntu-root/.snapshots:
total 0
drwxr-x--- 1 root root 2 Oct 11 20:08 .
drwxr-xr-x 1 root root 54 Oct 11 20:32 ..
drwxr-xr-x 1 root root 16 Oct 11 20:08 1
/mnt/ubuntu-root/.snapshots/1/snapshot:
total 32
drwxr-xr-x 1 root root 300 Oct 11 20:32 .
drwxr-xr-x 1 root root 16 Oct 11 20:08 ..
lrwxrwxrwx 1 root root 7 May 27 2022 bin -> usr/bin
drwxr-xr-x 1 root root 486 Oct 10 19:20 boot
drwxr-xr-x 1 root root 0 May 27 2022 cdrom
drwxr-xr-x 1 root root 5098 Oct 11 20:06 etc
drwxr-xr-x 1 root root 20 Oct 10 18:21 home
-rw------- 1 root root 64 Oct 10 19:08 i7lp616G-el
lrwxrwxrwx 1 root root 7 May 27 2022 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Oct 3 17:54 lib32 -> usr/lib32
lrwxrwxrwx 1 root root 9 May 27 2022 lib64 -> usr/lib64
lrwxrwxrwx 1 root root 10 May 27 2022 libx32 -> usr/libx32
drwx------ 1 root root 0 May 27 2022 lost+found
drwxr-xr-x 1 root root 44 Jul 10 2023 media
drwxr-xr-x 1 root root 42 Nov 24 2023 mnt
drwxr-xr-x 1 root root 106 Oct 11 19:16 @opt
drwxr-xr-x 1 root root 0 Oct 11 19:59 opt
drwxr-xr-x 1 root root 256 Oct 11 19:19 @root
drwxr-xr-x 1 root root 0 Oct 11 19:59 root
lrwxrwxrwx 1 root root 8 May 27 2022 sbin -> usr/sbin
drwxr-xr-x 1 root root 18 May 26 2023 snap
drwxr-xr-x 1 root root 0 Oct 11 19:01 @srv
drwxr-xr-x 1 root root 0 Oct 11 19:59 srv
drwxrwxrwt 1 root root 384 Oct 10 19:20 tmp
drwxr-xr-x 1 root root 116 Oct 11 19:59 usr
drwxr-xr-x 1 root root 86 Oct 11 19:20 @usrlocal
drwxr-xr-x 1 root root 130 Oct 11 19:59 var
drwxr-xr-x 1 root root 306 Oct 11 19:23 @varcache
drwxr-xr-x 1 root root 2808 Oct 11 19:24 @varlog
drwxr-xr-x 1 root root 0 Oct 11 19:02 @vartmp
-rw------- 1 root root 64 Oct 3 18:13 zNUV1bYp-el
        [root@ARCH-16ITH6 brook]# btrfs subvolume list /mnt/ubuntu-root
ID 257 gen 1209 top level 5 path @
ID 258 gen 1171 top level 266 path .snapshots/1/snapshot/@opt
ID 259 gen 1196 top level 266 path .snapshots/1/snapshot/@root
ID 260 gen 1177 top level 266 path .snapshots/1/snapshot/@srv
ID 261 gen 1192 top level 266 path .snapshots/1/snapshot/@usrlocal
ID 262 gen 1193 top level 266 path .snapshots/1/snapshot/@varcache
ID 263 gen 1192 top level 266 path .snapshots/1/snapshot/@varlog
ID 264 gen 1179 top level 266 path .snapshots/1/snapshot/@vartmp
ID 265 gen 1210 top level 257 path .snapshots
ID 266 gen 1211 top level 265 path .snapshots/1/snapshot
       
      - 
        Correct the error in the previous step.
        
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@opt /mnt/ubuntu-root/
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@root /mnt/ubuntu-root/
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@srv /mnt/ubuntu-root/
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@usrlocal /mnt/ubuntu-root/
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@varcache /mnt/ubuntu-root/
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@vartmp /mnt/ubuntu-root/
[root@ARCH-16ITH6 brook]# mv /mnt/ubuntu-root/.snapshots/1/snapshot/@varlog /mnt/ubuntu-root/
        [root@ARCH-16ITH6 brook]# btrfs subvolume list /mnt/ubuntu-root
ID 257 gen 1212 top level 5 path @
ID 258 gen 1171 top level 257 path @opt
ID 259 gen 1196 top level 257 path @root
ID 260 gen 1177 top level 257 path @srv
ID 261 gen 1192 top level 257 path @usrlocal
ID 262 gen 1193 top level 257 path @varcache
ID 263 gen 1192 top level 257 path @varlog
ID 264 gen 1179 top level 257 path @vartmp
ID 265 gen 1210 top level 257 path .snapshots
ID 266 gen 1212 top level 265 path .ssnapshots/1/snapshot
        We can also verify that files that should be in the subvolume and not in the initial snapshot subvolume are
        where they should be. For example the contents of what would normally in /var/cache are now in the @varcache subvolume. Later
        we will mount this subvolume to /var/cache in /etc/fstab, along with the other subvolumes that should be excluded from the snapshot
        subvolume.
        [root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/.snapshots/1/snapshot/var/cache /mnt/ubuntu-root/@varcache
/mnt/ubuntu-root/.snapshots/1/snapshot/var/cache:
total 0
drwxr-xr-x 1 root root   0 Oct 11 19:59 .
drwxr-xr-x 1 root root 130 Oct 11 19:59 ..
/mnt/ubuntu-root/@varcache:
total 0
drwxr-xr-x 1 root root      306 Oct 11 19:23 .
drwxr-xr-x 1 root root      144 Oct 11 20:45 ..
drwxr-xr-x 1 root root        0 May 17  2022 adduser
drwxr-xr-x 1 root root      160 Oct  3 18:18 apparmor
drwxr-xr-x 1 root root        8 Apr 19  2022 app-info
drwxr-xr-x 1 root root       70 Oct 11 20:06 apt
drwxr-xr-x 1 root root      120 Apr 19  2022 cracklib
drwxrwx--- 1 root      7    112 Oct 10 19:08 cups
drwxr-xr-x 1  132    122      0 May 26  2023 cups-browsed
drwxr-xr-x 1 root root      146 Oct 10 19:09 debconf
drwxr-xr-x 1 root root      310 Apr 19  2022 dictionaries-common
drwxr-xr-x 1 root root   695866 Oct 10 19:20 fontconfig
drwxr-xr-x 1 root root        0 Sep  4  2021 fonts
drwxr-xr-x 1 root root       98 Oct  3 18:11 fwupd
drwxr-xr-x 1  129 usbmux      0 Jun 29  2022 fwupdmgr
drwx------ 1 root root       18 Oct 11 20:06 ldconfig
drwxr-xr-x 1 root root        8 May 27  2022 lightdm
drwxr-xr-x 1    6 mail      304 Oct 11 20:06 man
drwxr-xr-x 1 root root       18 Apr 19  2022 PackageKit
drwx------ 1 root root        0 Feb 25  2023 private
drwxr-xr-x 1 root root        0 Mar 31  2023 samba
drwxr-xr-x 1 root root       10 Apr 19  2022 swcatalog
        This is the case for the /root
        [root@ARCH-16ITH6 brook]# ls -la /mnt/ubuntu-root/.snapshots/1/snapshot/root /mnt/ubuntu-root/@root
/mnt/ubuntu-root/@root:
total 36
drwxr-xr-x 1 root root   256 Oct 11 19:19 .
drwxr-xr-x 1 root root   144 Oct 11 20:45 ..
-rw------- 1 root root  1390 Oct 11 20:12 .bash_history
-rw-r--r-- 1 root root  3106 Oct 15  2021 .bashrc
drwx------ 1 root root   238 Nov 23  2023 .cache
drwx------ 1 root root    18 Mar 14  2023 .config
drwx------ 1 root root    22 Feb 25  2023 .dbus
drwx------ 1 root root    34 May 24  2022 .launchpadlib
-rw------- 1 root root    44 Oct 11 18:03 .lesshst
drwxr-xr-x 1 root root    20 Nov 27  2023 .local
-rw-r--r-- 1 root root   161 Jul  9  2019 .profile
drwx------ 1 root root    84 May 27  2022 snap
drwx------ 1 root root     0 May 26  2023 .ssh
-rw-r--r-- 1 root root     0 Mar  8  2023 .sudo_as_admin_successful
drwxr-xr-x 1 root root    20 Dec  2  2023 .vim
-rw------- 1 root root 13339 Dec  2  2023 .viminfo
-rw-r--r-- 1 root root   165 Nov 24  2023 .wget-hsts
/mnt/ubuntu-root/.snapshots/1/snapshot/root:
total 0
drwxr-xr-x 1 root root   0 Oct 11 19:59 .
drwxr-xr-x 1 root root 210 Oct 11 20:45 ..
        The listings of the other excluded subvolumes are not shown, but they are like /var/cache and /root, in their respective subvolumes.
       
    
    
   
  
    Part 7: Modify /etc/fstab to Reflect New
      BtrfsFilesystem and Subvolume Layout
    
    
      - 
        Edit the /etc/fstab file by accessing it in the mount at its new location under
        the initial snapshot subvolume that will be the new filesystem hierarchy root.
        
[root@ARCH-16ITH6 brook]# vim /mnt/ubuntu-root/.snapshots/1/snapshot/etc/fstab
        After the edit the file should look like the following listing (obtained after rebooting into the converted
        Ubuntu system with the subvolume layout configuration completed).
         ββ user: brook // host: UBUNTU-16ITH6 in ~ as π§ took 5m4s
 β°βΞ» cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
#                                                                                                
# / was on /dev/nvme0n1p7 during installation
#UUID=be2c6775-9f46-4851-84da-74a979206977      /                               ext4    errors=remount-ro                               0       1
# After conversion to Btrfs
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /                               btrfs   compress=zstd:3                                 0       0
# /boot/efi was on /dev/nvme0n1p1 during installation
UUID=CEFD-1322                                  /boot/efi                       vfat    umask=0077                                      0       1
# /home was on /dev/nvme1n1p4 during installation
UUID=dbe875a9-94a3-4831-8697-0e869ec4a65f       /home                           ext4    defaults                                        0       2
# swap was on /dev/nvme1n1p1 during installation
UUID=980ddbbf-9b79-4390-be21-850e62b7ebb2       none                            swap    sw                                              0       0
# After conversion to Btrfs. New .snapshots subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /.snapshots                     btrfs   subvol=@/.snapshots,compress=zstd:3             0       0
# After conversion to Btrfs. New @opt subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /opt                            btrfs   subvol=@/@opt,compress=zstd:3                   0       0
# After conversion to Btrfs. New @root subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /root                           btrfs   subvol=@/@root,compress=zstd:3                  0       0
# After conversion to Btrfs. New @srv subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /srv                            btrfs   subvol=@/@srv,compress=zstd:3                   0       0
# After conversion to Btrfs. New @usrlocal subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /usr/local                      btrfs   subvol=@/@usrlocal,compress=zstd:3              0       0
# After conversion to Btrfs. New @varcache subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /var/cache                      btrfs   subvol=@/@varcache,compress=zstd:3              0       0
# After conversion to Btrfs. New @varlog subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /var/log                        btrfs   subvol=@/@varlog,compress=zstd:3                0       0
# After conversion to Btrfs. New @vartmp subvolume
UUID=72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43       /var/tmp                        btrfs   subvol=@/@vartmp,compress=zstd:3                0       0
############################################################################################################
UUID=4ad30c04-8dc6-4a6b-9052-315a1d22a48f       /home/brook/DataEXT4-16ITH6     ext4    defaults                                        0       2
UUID=3AC1235B3FBAFA8C                           /home/brook/DataNTFS-16ITH6     ntfs3   uid=1000,gid=100,dmask=022,fmask=133,discard    0       2
UUID=bb03c8fc-c6f8-452d-a28b-360f405b7c97       /home/brook/VMs                 ext4    defaults                                        0       2
 ββ user: brook // host: UBUNTU-16ITH6 in ~ as π§ took 3ms
 β°βΞ» 
        The before edit and after edit state of the file from the external Linux at this point in the process is shown
        in the following set of images.
       
      
        
          
          
            
              Figures 3a and 3b: Editing /etc/fstab
            
            
              The file is in the subvolume -- in terms of subvolume path -- /@/.snapshots/1/snapshot, which we will be automatically mounted at the
              filesystem hierarchy root when we set it as the Btrfsdefault subvolume.
            
           
         
       
    
    
   
  
    Part 8: Modify GRUB Scripts in /etc/grub.d
    
      The next step is to modify two of the GRUB scripts in /etc/grub.d that are executed
      when making the or updating the GRUB configuration file, /etc/grub/grub.cfg by
      grub-mkconfig, or in Ubuntu by update-grub,
      which actually executes grub-mkconfig. These two scripts set the subvolume to be
      used as the root of the filesystem hierarchy in a way that is not compatible with our desired layout and Snapper.
    
      - 
        Modify the Ubuntu installation's /etc/grub.d/10_linux file by accessing it in the
        mount at its new location under the initial snapshot subvolume that will be the new filesystem hierarchy root by
        removing the string rootflags=subvol=${rootsubvol} .
        
[root@ARCH-16ITH6 brook]# vim /mnt/ubuntu-root/.snapshots/1/snapshot/etc/grub.d/10_linux
        
          
            
            
              
                Figures 4a, 4b, and 4c: Editing /etc/grub.d/10_linux
              
              
              
             
           
         
        The above images show the original state of the file, the state of the file as it is being modifyied in vim, and the state of the file after the modification.
       
      - 
        Modify the Ubuntu installation's /etc/grub.d/20_linux_xen file by accessing it in
        the mount at its new location under the initial snapshot subvolume that will be the new filesystem hierarchy
        root by removing the string rootflags=subvol=${rootsubvol} .
        
[root@ARCH-16ITH6 brook]# vim /mnt/ubuntu-root/.snapshots/1/snapshot/etc/grub.d/20_linux_xen
        
          
            
            
              
                Figures 5a, 5b, and 5c: Editing /etc/grub.d/20_linux_xen
              
              
              
             
           
         
       
    
    
   
  
    Part 9: Make Directory to Be Used as a Mountpoint for the .snapshots Subvolume in the Initial Snapshot Subvolume
    
      In our final converted Ubuntu system, the snapshots subvolume will be mounted at /.snapshots filesystem hierarchy path. Remember that in Part 7 we have already created
      an entry in the Ubuntu installation's /etc/fstab for this mount. We now make a
      directory to mount our snapshots subvolume. Because in the final system the fileystem hierarchy root is actually
      the subvolume /@/.snapshots/1/snapshot, and because at this point in the process
      the Ubuntu installation's /@ subvolume is mounted in the external Linux at /mnt/ubuntu-root, we can make the directory at /mnt/ubuntu-root/.snapshots/1/snapshot/.snapshot. When we reboot into the Ubuntu
      system, the snapshots subvolume will be accessible at /.snapshots as intended and
      as requied by Snapper.
    
      - 
        Make the directory for mounting the snapshots subvolume.
        
[root@ARCH-16ITH6 brook]# mkdir /mnt/ubuntu-root/.snapshots/1/snapshot/.snapshots
       
    
    
   
  
    Part 10: Change the Default BtrfsSubvolume from /, Subvolume ID 5 to the Initial Snapshot Subvolume /@/.snapshots/1/snapshot
    
    
      - 
        View the current default subvolume as set by the btrfs-convert program.
        
[root@ARCH-16ITH6 brook]# btrfs subvolume get-default /mnt/ubuntu-root
ID 5 (FS_TREE)
       
      - 
        Get the subvolume ID of the initial snapshots subvolume.
        
[root@ARCH-16ITH6 brook]# sudo btrfs subvolume list /mnt/ubuntu-root
ID 257 gen 1214 top level 5 path @
ID 258 gen 1216 top level 257 path @opt
ID 259 gen 1216 top level 257 path @root
ID 260 gen 1177 top level 257 path @srv
ID 261 gen 1192 top level 257 path @usrlocal
ID 262 gen 1215 top level 257 path @varcache
ID 263 gen 1215 top level 257 path @varlog
ID 264 gen 1216 top level 257 path @vartmp
ID 265 gen 1210 top level 257 path .snapshots
ID 266 gen 1223 top level 265 path .snapshots/1/snapshot
        From the listing we can see the subvolume ID of the initial snapshot subvolume at subvolume path /@/.snapshots/1/snapshot is 266.
       
      - 
        Set the Btrfsdefault subvolume to subvolume ID 266.
        
[root@ARCH-16ITH6 brook]# btrfs subvolume set-default 266 /mnt/ubuntu-root
       
      - 
        Verify that the default subvolume was changed to subvolume ID 266.
        
[root@ARCH-16ITH6 brook]# btrfs subvolume get-default /mnt/ubuntu-root
ID 266 gen 1223 top level 265 path @/.snapshots/1/snapshot
       
      - 
        Unmount the Btrfspartition containing the Ubuntu installation.
        
[root@ARCH-16ITH6 brook]# umount --recursive /mnt/ubuntu-root
       
      - 
        Verify that the partition and any of the subvolumes are no longer mounted.
        
[root@ARCH-16ITH6 brook]# mount | grep /mnt
        There should not be any output.
       
    
    
   
  
    Part 11: Chroot to Installed System and Reinstall GRUB Firmware, Update GRUB,
      and Regenerate Initramfs
    
    
      - 
        In the external Linux installation or the live ISO, mount the initial snapshot subvolume, i.e., subvolume path
        /@/snapshots/1/snapshot.
        
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root
       
      - 
        Verify the mount.
        
[root@ARCH-16ITH6 brook]# mount | grep /mnt
/dev/nvme1n1p7 on /mnt/ubuntu-root type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=266,subvol=/@/.snapshots/1/snapshot)
       
      - 
        Mount the home partition.
        
mount UUID="dbe875a9-94a3-4831-8697-0e869ec4a65f" /mnt/ubuntu-root/home
       
      - 
        Make a mount point for the EFI System Partition and mount it.
        
[root@ARCH-16ITH6 brook]# mkdir /mnt/ubuntu-root/boot/efi
[root@ARCH-16ITH6 brook]# mount UUID="CEFD-1322" /mnt/ubuntu-root/boot/efi
       
      - 
        Mount the subvolumes for the excluded filesystem hierarchy paths.
        
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/opt -o subvol=/@/@opt
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/root -o subvol=/@/@root
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/srv -o subvol=/@/@srv
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/var/cache -o subvol=/@/@varcache
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/var/log -o subvol=/@/@varlog
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/var/tmp -o subvol=/@/@vartmp
[root@ARCH-16ITH6 brook]# mount UUID="72aaa46b-9109-4c3d-9b63-8c8e3cc7fd43" /mnt/ubuntu-root/usr/local -o subvol=/@/@usrlocal
       
      - 
        Make mountpoints for the pseudo filesystems and mount them.
        
[root@ARCH-16ITH6 brook]# mkdir -p /mnt/ubuntu-root/{dev,dev/pts,proc,run,sys}
[root@ARCH-16ITH6 brook]# mount -t proc /proc /mnt/ubuntu-root/proc/
[root@ARCH-16ITH6 brook]# mount -t sysfs /sys /mnt/ubuntu-root/sys/
[root@ARCH-16ITH6 brook]# mount -o bind /dev /mnt/ubuntu-root/dev/
[root@ARCH-16ITH6 brook]# mount -o bind /dev/pts /mnt/ubuntu-root/dev/pts/
[root@ARCH-16ITH6 brook]# mount -o bind /run /mnt/ubuntu-root/run/
[root@ARCH-16ITH6 brook]# mount -o bind /sys/firmware/efi/efivars /mnt/ubuntu-root/sys/firmware/efi/efivars/
       
      - 
        Copy /etc/resolv.conf from the host system to the installed Ubuntu that we will
        chroot into.
        
[root@ARCH-16ITH6 brook]# cp /etc/resolv.conf /mnt/ubuntu-root/etc/resolv.conf
       
      - 
        Before chrooting, verify the mounted subvolumes.
        
[root@ARCH-16ITH6 brook]# mount | grep /mnt/ubuntu-root
/dev/nvme1n1p7 on /mnt/ubuntu-root type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=266,subvol=/@/.snapshots/1/snapshot)
/dev/nvme0n1p4 on /mnt/ubuntu-root/home type ext4 (rw,relatime)
/dev/nvme1n1p1 on /mnt/ubuntu-root/boot/efi type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
/dev/nvme1n1p7 on /mnt/ubuntu-root/opt type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=258,subvol=/@/@opt)
/dev/nvme1n1p7 on /mnt/ubuntu-root/root type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=259,subvol=/@/@root)
/dev/nvme1n1p7 on /mnt/ubuntu-root/srv type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=260,subvol=/@/@srv)
/dev/nvme1n1p7 on /mnt/ubuntu-root/var/cache type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=262,subvol=/@/@varcache)
/dev/nvme1n1p7 on /mnt/ubuntu-root/var/log type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=263,subvol=/@/@varlog)
/dev/nvme1n1p7 on /mnt/ubuntu-root/var/tmp type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=264,subvol=/@/@vartmp)
/dev/nvme1n1p7 on /mnt/ubuntu-root/usr/local type btrfs (rw,relatime,ssd,discard=async,space_cache=v2,subvolid=261,subvol=/@/@usrlocal)
/proc on /mnt/ubuntu-root/proc type proc (rw,relatime)
/sys on /mnt/ubuntu-root/sys type sysfs (rw,relatime)
dev on /mnt/ubuntu-root/dev type devtmpfs (rw,nosuid,relatime,size=12158680k,nr_inodes=3039670,mode=755,inode64)
devpts on /mnt/ubuntu-root/dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
run on /mnt/ubuntu-root/run type tmpfs (rw,nosuid,nodev,relatime,mode=755,inode64)
efivarfs on /mnt/ubuntu-root/sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime)
       
      - 
        Chroot into the Ubuntu system from the external Linux.
        
[root@ARCH-16ITH6 brook]# chroot /mnt/ubuntu-root /bin/bash
       
      - 
        Verify the chroot.
        
root@ARCH-16ITH6:/# cat /etc/os-release
PRETTY_NAME="Ubuntu 24.10"
NAME="Ubuntu"
VERSION_ID="24.10"
VERSION="24.10 (Oracular Oriole)"
VERSION_CODENAME=oracular
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=oracular
LOGO=ubuntu-logo
       
      - 
        Swich to root.
        
root@ARCH-16ITH6:/# su
       
      - 
        View GRUB variables.
        
root@ARCH-16ITH6:/# grub-editenv list
        Unlike in Fedora (see ), there are no GRUB variables in my Ubuntu installation,
        continuously upgraded since 22.04.
       
      - 
        Re-install GRUB EFI application to ESP.
        
root@ARCH-16ITH6:/# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Ubuntu
        Oct 12 20:21:01 UBUNTU-16ITH6 sudo[7250]:    brook : TTY=pts/1 ; PWD=/home/brook ; USER=root ; COMMAND=/usr/sbin/grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Ubuntu
       
      - 
        Update GRUB configuration.
        
root@ARCH-16ITH6:/# update-grub
        Oct 12 20:34:27 UBUNTU-16ITH6 sudo[9003]:    brook : TTY=pts/1 ; PWD=/home/brook ; USER=root ; COMMAND=/usr/sbin/update-grub
       
      - 
        Update the initramfs.
        
root@ARCH-16ITH6:/# update-initramfs
        Oct 14 22:30:38 UBUNTU-16ITH6 sudo[37896]:    brook : TTY=pts/2 ; PWD=/home/brook ; USER=root ; COMMAND=/usr/sbin/update-initramfs -v -c -k all
       
    
    
    
    
      
      
        
          Figure 6: Reinstalling the GRUB Firmware Application and Updating the GRUB Configuration
        
        
        
       
     
    
   
  
    Part 12: Reboot Into Converted System with BtrfsSubvolume Layout and
      Working Snapper Configuration and Make Final Adjustments to System Configuration
    
      We can now reboot into the converted Ubuntu system, which at this point will have the subvolume layout illustrated
      in the diagram at the top of the article, similar to the one used by openSUSE. The initial snapshot subvolume is
      automatically mounted at the filesystem hierarchy root / without explicitly
      specifying the subvolume identifiers in the /etc/fstab mount options.
      Snapper has been configured and is usable, fully able to rollback the system and set the new post-rollback
      read-write snapshot it creates as the new subvolume for the filesystem hierarchy root. Snapper is even
      integrated into APT (see, below) such that pre and post snapshots are automatically created during package
      management transactions.
    
    
      The following image of some Konsole panes with outputs of various commands show the characteristics of the
      system.
    
      
      
        
          Figure 7: The Converted Ubuntu Installation's Btrfs characteristics
        
        
        
       
     
    
    APT Integration for Automatic Snapshot Creation Druing Package Management Transactions
    
    
      As shown in the following image, snapshots are automatically created during package management transactions. The image shows two Konsole panes. At the top of the left pane is the output of a pakcage managment transaction. Below that is the execution and output of  sudo snapper list, which shows the two snapshots created for the package management transaction -- the pre transaction snapshot, Snapshot #48, and the post transaction snapshot, Snapshot #49. The top of the right pane also shows these two new snapshot subvolumes in the output of
      
sudo btrfs subvolume list /
    
      
      
        
          Figure 8: Snapper Snapshots on the Converted Ubuntu and Corresponding Subvolumes
        
        
        
       
     
    
    
      What makes this integration of Snapper into apt transactions is the file /etc/apt/apt.conf.d/80snapper, owned by the snapper package, with the contents:
      
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=770938
DPkg::Pre-Invoke  { "if [ -e /etc/default/snapper ]; then . /etc/default/snapper; fi; if [ -x /usr/bin/snapper ] && [ ! x$DISABLE_APT_SNAPSHOT = 'xyes' ] && [ -e /etc/snapper/configs/root ]; then rm -f /var/tmp/snapper-apt || true ; snapper create -d apt -c number -t pre -p > /var/tmp/snapper-apt || true ; snapper cleanup number || true ; fi"; };
DPkg::Post-Invoke { "if [ -e /etc/default/snapper ]; then . /etc/default/snapper; fi; if [ -x /usr/bin/snapper ] && [ ! x$DISABLE_APT_SNAPSHOT = 'xyes' ] && [ -e /var/tmp/snapper-apt ]; then snapper create -d apt -c number -t post --pre-number=`cat /var/tmp/snapper-apt` || true ; snapper cleanup number || true ; fi"; };
          This uses the 
DPkg::Pre-Invoke and 
DPkg::Post-Invoke configuration parameters, which act as pre-invocation and post-invocation hooks to the transaction, to execute 
Snapper commands.
     
    
Automatic Snapper Snapshot Creation with systemd
      Timers
      
        On Ubuntu and derivatives the Snapper helper systemd timers snapper-boot.timer, snapper-timeline.timer,
        and snapper-cleanup.timer which, respectively, create a snapshot automatically
        at boot, create hourly, daily, weekly, and monthly periodic snapshots, and delete old snapshots -- keeping the
        specified number of each type of periodic snapshot and the total number, as specified in other configuration
        parameters, are enabled automatically. These timers activate corresponding systemd services
        which in turn cause the actual commands that perform the actions are executed.
      
      
        The following listing shows that the timeline timer has already been enabled by the preset default.
      
ββ user: brook // host: UBUNTU-16ITH6 in ~ took 19m13s
β°βΞ» sudo systemctl status snapper-{boot,timeline,cleanup}.timer
[sudo] password for brook: 
β snapper-boot.timer - Take snapper snapshot of root on boot
    Loaded: loaded (/usr/lib/systemd/system/snapper-boot.timer; enabled; preset: enabled)
    Active: active (elapsed) since Mon 2025-11-03 16:28:47 EST; 44min ago
Invocation: 011548ab4e2449528f2a035ead44ed04
    Trigger: n/a
  Triggers: β snapper-boot.service
Nov 03 16:28:47 UBUNTU-16ITH6 systemd[1]: Started snapper-boot.timer - Take snapper snapshot of root on boot.
β snapper-timeline.timer - Timeline of Snapper Snapshots
    Loaded: loaded (/usr/lib/systemd/system/snapper-timeline.timer; enabled; preset: enabled)
    Active: active (waiting) since Mon 2025-11-03 16:28:47 EST; 44min ago
Invocation: 7d94ab8b9c84408fa6d3f9260550f31e
    Trigger: Mon 2025-11-03 18:00:00 EST; 47min left
  Triggers: β snapper-timeline.service
      Docs: man:snapper(8)
            man:snapper-configs(5)
Nov 03 16:28:47 UBUNTU-16ITH6 systemd[1]: Started snapper-timeline.timer - Timeline of Snapper Snapshots.
β snapper-cleanup.timer - Daily Cleanup of Snapper Snapshots
    Loaded: loaded (/usr/lib/systemd/system/snapper-cleanup.timer; enabled; preset: enabled)
    Active: active (waiting) since Mon 2025-11-03 16:28:47 EST; 44min ago
Invocation: 016ce82e7bba46ceab5872fcade322c5
    Trigger: Tue 2025-11-04 16:38:40 EST; 23h left
  Triggers: β snapper-cleanup.service
      Docs: man:snapper(8)
            man:snapper-configs(5)
Nov 03 16:28:47 UBUNTU-16ITH6 systemd[1]: Started snapper-cleanup.timer - Daily Cleanup of Snapper Snapshots.
       
          
      
      Modify the Snapper Configuration
	
		The default Snapper configuration file for the subvolume mounted at / written automatically by Snapper when we issued the snapper create command specifies -- possibly -- an excessive number of automatic snapshots to be created. This can be a problem if the size of the Btrfs partition is not appropriately large.   
	
	
		Snapper allows automatic snapshots to be created periodically, at boot, and during package management transactions. Periodic snapshots can be created hourly, daily, monthly and yearly. It specifies up to 10 hourly snapshots, up to 10 daily snapshots, up to 10 monthly snapshots and up to 10 yearly snapshots to be retained. It specifies that the automatic cleanup of snapshots retain an overall number of 50 snapshots, whether they are periodic snapshots or those created during package management transactions. These settings are excessive for the 72 GB Btrfs partition for the filesystem root of this installation. 
	
	
		So, we will modify the settings to limit the number of snapshots that are created and decrease the number of snapshots that are preserved by the timeline cleanup algorithm, by editing the values of configuration parameters TIMELINE_LIMIT_HOURLY,  TIMELINE_LIMIT_DAILY, TIMELINE_LIMIT_WEEKLY, TIMELINE_LIMIT_MONTHLY, and TIMELINE_LIMIT_YEARLY to appropriate values. The modified values of these parameters are shown in the following listing of /etc/snapper/configs/root. We will also modify the settings related to the number cleanup algorithm by reducing the values of the parameters NUMBER_LIMIT and NUMBER_LIMIT_IMPORTANT
		
# subvolume to snapshot
SUBVOLUME="/"
# filesystem type
FSTYPE="btrfs"
# btrfs qgroup for space aware cleanup algorithms
QGROUP=""
# fraction or absolute size of the filesystems space the snapshots may use
SPACE_LIMIT="0.5"
# fraction or absolute size of the filesystems space that should be free
FREE_LIMIT="0.2"
# users and groups allowed to work with config
ALLOW_USERS=""
ALLOW_GROUPS=""
# sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
# directory
SYNC_ACL="no"
# start comparing pre- and post-snapshot in background after creating
# post-snapshot
BACKGROUND_COMPARISON="yes"
# run daily number cleanup
NUMBER_CLEANUP="yes"
# limit for number cleanup
NUMBER_MIN_AGE="1800"
NUMBER_LIMIT="25"
NUMBER_LIMIT_IMPORTANT="5"
# create hourly snapshots
TIMELINE_CREATE="yes"
# cleanup hourly snapshots after some time
TIMELINE_CLEANUP="yes"
# limits for timeline cleanup
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="2"
TIMELINE_LIMIT_DAILY="2"
TIMELINE_LIMIT_WEEKLY="1"
TIMELINE_LIMIT_MONTHLY="1"
TIMELINE_LIMIT_YEARLY="0"
# cleanup empty pre-post-pairs
EMPTY_PRE_POST_CLEANUP="yes"
# limits for empty pre-post-pair cleanup
EMPTY_PRE_POST_MIN_AGE="1800"
	
       Install btrfsmaintenance and enable Related systemd
            Timers
          
            The btrfsmaintenance provides several systemd timers -- btrfs-balance.timer, btrfs-scrub.timer,
            btrfs-defrag.timer -- which activate corresponding services, which in turn
            execute scripts, which themselves invoke btrfs provided commands to perform
            Btrfs balance, scrub, and defrag operations on the filesystem. We install the
            package and enable the timers as follows.
          
          
            Install the package with:
          
sudo apt install btrfsmaintenance
          The command with the output:
          
ββ user: brook // host: UBUNTU-16ITH6 in ~ as π§ took 1s
β°βΞ» sudo apt install btrfsmaintenance
The following packages were automatically installed and are no longer required:
  libllvm19:i386                   linux-image-6.14.0-23-generic          linux-tools-6.14.0-23          vim-runtime
  linux-headers-6.14.0-23          linux-modules-6.14.0-23-generic        linux-tools-6.14.0-23-generic
  linux-headers-6.14.0-23-generic  linux-modules-extra-6.14.0-23-generic  nvidia-firmware-570-570.169
Use 'sudo apt autoremove' to remove them.
Installing:
  btrfsmaintenance
Summary:
  Upgrading: 0, Installing: 1, Removing: 0, Not Upgrading: 132
  Download size: 24.6 kB
  Space needed: 79.9 kB / 17.8 GB available
Get:1 http://us.archive.ubuntu.com/ubuntu plucky/universe amd64 btrfsmaintenance all 0.5.2-1 [24.6 kB]
Fetched 24.6 kB in 17s (1,409 B/s)          
Selecting previously unselected package btrfsmaintenance.
(Reading database ... 561280 files and directories currently installed.)
Preparing to unpack .../btrfsmaintenance_0.5.2-1_all.deb ...
Unpacking btrfsmaintenance (0.5.2-1) ...
Setting up btrfsmaintenance (0.5.2-1) ...
Processing triggers for man-db (2.13.0-1) ...
                  
          
          
            Enable the related services with the command:
          
systemctl enable --now btrfs-{balance,scrub,defrag}.timer
                  
          The command with the output:
          
ββ user: brook // host: UBUNTU-16ITH6 in ~ as π§ took 4s
[π΄] Γ sudo systemctl enable --now btrfs-{balance,scrub,defrag}.timer
Created symlink '/etc/systemd/system/timers.target.wants/btrfs-balance.timer' β '/usr/lib/systemd/system/btrfs-balance.timer'.
Created symlink '/etc/systemd/system/timers.target.wants/btrfs-scrub.timer' β '/usr/lib/systemd/system/btrfs-scrub.timer'.
Created symlink '/etc/systemd/system/timers.target.wants/btrfs-defrag.timer' β '/usr/lib/systemd/system/btrfs-defrag.timer'.
     
      
   
  
    
    
    
  
  
    Testing Rollbacks
    
    
      
        
        
          
            Figures 9a, 9b, 9c, and 9d: Performing a Rollback with Snapper