Migrate Qubes VMs from corrupted BTRFS filesystem

Some weird issue caused my laptop to display graphical glitches (think pixelated patterns of a dying gpu) and become unresponsive the other day. While i still don’t understand what caused the issue, a result of that was that my Qubes OS btrfs partition got corrupted. I have a bunch of checksum errors, wrong extent trees and so on. Have been trying to fix the filesystem for the last couple of days, but its just not bootable whatever I do. I got it to a point where i can mount the filesystem and read files from it, but any operation forces it into RO mode.

So the question is the following. How can i migrate the VMs i had to another Qubes installation if i can read everything in /var/lib/qubes? Do i just copy all the .img files from appvms, vm-templates to the new Qubes’ /var/lib/qubes the same way along the qubes.xml or is there some other procedure to follow?

Use the backup tool to create backups, and restore from the other.

How am i supposed to use the backup tool? It needs to interact with qubesdb, which cant run as it cant create the lock files necessary (read only filesystem) + it also creates a backup configuration in /etc/qubes/backup or somewhere, which again is impossible.

AFAIK that should work, assuming the new installation also uses the Btrfs or XFS layout. Don’t forget firewall.xml files and VM kernels. Use cp --sparse=always for the .img files. Omit -precache.img files. You may want to omit @ revision .img files too, it’s difficult to copy them in a space efficient manner if the original filesystem is too broken to use btrfs send.

On the new installation, shut down all VMs and run systemctl stop qubesd before restoring the files, then systemctl start qubesd afterwards.

Make sure the new installation is the same minor Qubes OS release version. E.g. its probably not a good idea restore a R4.2.x qubes.xml to an R4.3 installation.

1 Like

Thanks for the response. The BTRFS on Qubes i know uses reflinks for vm img files. Now that i have the original disk attached to another PC to copy varlibqubes off of it, and the filesystem to which I can copy the files to is ZFS, should I use sparse and reflink options for copying?

Edit: Can i maybe use rsync instead of cp too?

The ZFS filesystem is for a temporary copy (so you can then finally copy that to the new Qubes OS installation), right? You should still use cp -a --sparse=always or rsync -aH --sparse both times. Reflinks are only possible within the same filesystem on a particular device, so this is not applicable in your situation.

1 Like

Yep. Thanks a lot.

And I’m using --sparse=always why exactly? My (broken) partition was/is 1TB. Running du on /var/lib/qubes shows 2.2TB, which im guess is because it doesnt account for btrfs’s CoW nature and the reflinks. Do sparse files have anything to do with that too?

Yes.

No, but the .img files are also sparse in addition to often being reflinks. That sparseness should be preserved during the copy, otherwise it would waste a lot of disk space.

1 Like

And this means that when copying the files from the ZFS back to a fresh Qubes’ btrfs root, i have to somehow tell it to figure out the reflinks (guessing --reflink=auto or always) or the 2.2TBs wont fit in there.

It will not be possible to preserve reflinks when copying from one device to another. The only way to do this would be btrfs send, but this is probably not an option with a broken filesystem.

However you can omit some files: -precache.img; volatile-dirty.img; @ revision .img files; root related .img files inside of appvms/ (except for StandaloneVMs, which do need those files!); if there are any other -dirty.img files they can also be treated specially (e.g. transfer private-dirty.img as private.img and omit the original private.img).

Even so this might still use substantially more space than in the original if some of your VMs were clones of other large VMs.

1 Like

Understood. This is going to be quite difficult it seems.

1 Like

I notice now that some appvms have a root.img inside their directory. I thought one would only see a root.img in vm-templates. Do i need them, and why are there appvms that dont have it?
Examples:

(appvm #1)

[root@archlinux appvms]# ls work
private-dirty.img  private.img	private.img.402@2025-08-25T15:08:48Z  root-dirty.img  root.img	volatile-dirty.img

(appvm #2)

[root@archlinux appvms]# ls personal
private.img  private.img.188@2025-08-18T10:54:34Z  private-precache.img

(standalone vm, i have manually set revision to keep for this to 0, hence why no @ files)

[root@archlinux appvms]# ls investigation/
firewall.xml  private.img  private-precache.img  root.img  root-precache.img

(the templatevm for all the appvms above)

[root@archlinux vm-templates]# ls archlinux/
private.img  private.img.275@2025-08-25T12:56:15Z  private-precache.img  root.img  root.img.277@2025-08-25T12:56:16Z  root-precache.img

For a running AppVM, root.img is an unmodified snapshot of its template’s root.img from just before the AppVM was started, and root-dirty.img is where the AppVM makes modifications to it.

No:

If you’re wondering why StandaloneVMs (and running DisposableVMs - another set of .img files you can omit) are stored in appvms/, it’s for backwards compatibility with an older storage driver.

Clean shutdown of an AppVM deletes its root.img and root-dirty.img. The ones that still have it must have been running when your system crashed.