Trouble understanding btrfs-replace

I am trying to move my system from an SSD that’s running out of space, onto a larger nvme drive, but I’m having some trouble understanding the syntax of the commands. Would really appreciate some assistance in clearing up my confusion.

I created a fat 32 for the ESP on the other drive and used dd to copy everything over. For the rest of the nvme, I made one big btrfs partion.

Now, I want to run btrfs-replace and move everything over to the other drive, including the top level of the btrfs system, the timeshift-btrfs snapshots, etc. An exact copy basically. However, I cannot for the life of me understand the syntax for the btrfs-replace command, despsite reading the docs, man pages and countless guides and forum posts.

The part that trips me up is this part of the man pages/docs:

start [options] <srcdev>|<devid> <targetdev> <path>

Is <path> referring to the path that <srcdev> is mounted, or <targetdev>?

This it the lsblk output for the relevant drives (I want to move everything from /dev/sdc2 to /dev/nvme0n1p2):

sdc           8:32   0 232.9G  0 disk 
├─sdc1        8:33   0   511M  0 part /boot/efi
└─sdc2        8:34   0 232.4G  0 part /mnt/top-level
                                      /var/lib/docker/btrfs
                                      /var/cache/pacman/pkg
                                      /home
                                      /
nvme0n1     259:0    0 953.9G  0 disk 
├─nvme0n1p1 259:1    0   550M  0 part 
└─nvme0n1p2 259:2    0 953.3G  0 part 

Now, thinking that <path> refers to <srcdev> I wasn’t sure what mountpoint to use, since I have several subvolumes, mounted in different places.

See my fstab:

# <file system>                             <mount point>         <type>  <options>                                                                            <dump> <pass>

UUID=FDE3-B78F                              /boot/efi             vfat    umask=0077                                                                           0      2 

UUID=313dc380-0d06-44ec-8652-062bd60bd5c6   /                     btrfs   subvol=@,defaults,noatime,space_cache,noautodefrag,compress=zstd                     0      0
UUID=313dc380-0d06-44ec-8652-062bd60bd5c6   /home                 btrfs   subvol=@home,defaults,noatime,space_cache,noautodefrag,compress=zstd                 0      0
UUID=313dc380-0d06-44ec-8652-062bd60bd5c6   /var/lib/docker/btrfs btrfs   subvol=@docker,defaults,noatime,space_cache,compress=zlib 0 0
UUID=313dc380-0d06-44ec-8652-062bd60bd5c6   /var/cache/pacman/pkg btrfs   subvol=@var-cache-pacman-pkg,defaults,noatime,space_cache,noautodefrag,compress=zstd 0      0

tmpfs                                       /tmp                  tmpfs   defaults,noatime,mode=1777                                                           0      0

UUID="51596fec-9d35-4522-87c5-64bacce1314c" /mnt/hdd              ext4    defaults,errors=remount-ro                                                           0      2 
UUID="92bd7cf2-8b9a-4806-a0d8-4384f5afb5ed" /mnt/newdata          ext4    defaults,errors=remount-ro                                                           0      2

When I run btrfs filesystem show, I get:

Label: none  uuid: 313dc380-0d06-44ec-8652-062bd60bd5c6
        Total devices 1 FS bytes used 167.78GiB
        devid    1 size 232.39GiB used 232.38GiB path /dev/sdc2

Do I put in /dev/sd2 for the <path> part? Or should I use /, or /mnt/top-level where I temporarily mounted /dev/sdc2 - so I could access snapshots in timeshift-bfrfs?

Any insight into this would be greatly appreciated, also any tips for how to get the system up and running after I hopefully pull of btrfs-send.


On a related note: If I want to send a snapshot or snapshots to another non-BTRFS device, how can I do it?

I saw from my research that you can create a file version of a snapshot with btrfs-send, using the -f flag.

From my understanding the btrfs snapshot would have to be read-only for this to work. So if I set a snapshot to ro=true, can I just do something like this:

sudo btrfs send -f 2024_12_15-11-00-00 timeshift-btrfs/snapshots/2024-12-15_11-00-00/@/ 

Where ‘2024_12_15-11-00-00’ is the name of the f ile. If so, can I just rsync that file over to another drive?

If there were an easy way to send every snapshot in the timeshift-btrfs directory (at the top level of the btrfs system) to a backup directory on a non-btrfs drive, that’d be even better.

Yes.

The man page has a usage example a little further down which may help clear this up for you:

EXAMPLES
   Replacing an online drive with a bigger one
       Given the following filesystem mounted at /mnt/my-vault

          Label: 'MyVault'  uuid: ae20903e-b72d-49ba-b944-901fc6d888a1
                  Total devices 2 FS bytes used 1TiB
                  devid    1 size 1TiB used 500.00GiB path /dev/sda
                  devid    2 size 1TiB used 500.00GiB path /dev/sdb

       In order to replace /dev/sda (devid 1) with a bigger drive located at /dev/sdc you would run the following:

          btrfs replace start 1 /dev/sdc /mnt/my-vault/

       You can monitor progress via:

          btrfs replace status /mnt/my-vault/

       After  the  replacement is complete, as per the docs at btrfs-filesystem(8) in order to use the entire storage space of
       the new drive you need to run:

          btrfs filesystem resize 1:max /mnt/my-vault/

In the example, /dev/sdc is the new device. It is replacing /dev/sda (which is devid 1). The mount point for the old device (which is about to become the mount point for the new device) is /mnt/my-vault.

It is a little confusing how they use devid in the command, but I guess if you have a Btrfs filesystem made up of multiple disks you would need that. In the case of Btrfs filesystems where the whole filesystem is on a single partition (which is probably the most common setup), devid is always going to be 1.

So in your case, the replace command would be like this:

btrfs replace start 1 /dev/nvme0n1p2 /mnt/top-level

It doesn’t really matter which mount point you use, as long as it is a valid mount point of the Btrfs filesystem for on /dev/sdc2.

That’s right. Actually, btrfs send itself only works with RO snapshots (regardless of the options in use).

Looks good to me. Test it out and let us know how it goes.

It seems like writing a small script would be the way to go. Probably only a few lines would be needed.

  • Timeshift creates the snapshot;
  • btrfs send -f to create a file version of the snapshot;
  • rsync the file to the backup target;
  • Delete the file version of the snapshot.

Or if you want to check out another project, btrbk supports sending snapshot backups to non-Btrfs targets. https://github.com/digint/btrbk

2 Likes

Thank you for confirming and the tips for backing up snapshots!

I ended up trusting my gut and running it pointing at /mnt/top_level…but it kept unexpectedly cancelling, with journalctl showing that /dev/sdc2 didn’t have enough space, which was confusing to me, because it was showing about 100GB free.

I removed some snapshots, but still no luck. Finally figured I could run btrfs balance, which turned out was the solution.

Then however I was having issue with grub, tried the old arch-chroot trick (that I’ve had lots of opportunities to practice), but then running grub-install kept telling me it couldn’t find the efi…turns out after much too much trial and error I realised I should have mounted the first partition as /mnt/boot/efi not /mnt/efi. :sweat_smile:

I’d like to say this took me only a few hours, but this whole process has taken me the better of two days!

Now what to do with the smaller drive…I’d like to use it for my Steam library maybe…but I’m wondering if btrfs would have any benefits there, or if good old ext4 will do. It’s certainly simpler…

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.