How to get a large file on a completely full `btrfs` partition back into a “workable” state, e.g. by truncating it?

I have a hard disk with a single btrfs partition (sdc1):

# lsblk
[...]
sdc      8:32   0 465.8G  0 disk 
└─sdc1   8:33   0 465.8G  0 part /mnt/exthd

This partition is currently completely full:

# btrfs fi show /dev/sdc1
Label: none  uuid: 3130b777-c72d-4375-a344-43571afc3e92
    Total devices 1 FS bytes used 448.74GiB
    devid    1 size 465.76GiB used 465.76GiB path /dev/sdc1

# btrfs fi df /mnt/exthd
Data, single: total=463.73GiB, used=448.22GiB
System, DUP: total=8.00MiB, used=80.00KiB
Metadata, DUP: total=1.01GiB, used=533.98MiB
GlobalReserve, single: total=498.27MiB, used=0.00B

All the partition’s space is currently allocated to one single image file:

# ls -l /mnt/exthd
total 514224320
-rw-r--r-- 1 root root 526676328448 Aug 16  2024 backup.img

Note: I’m using transparent zstd compression. That’s why the size of the file (> 490GiB) is even larger than would theoretically fit on the disk.

backup.img is an image of a hard disk that is currently failing, created using ddrescue. I would like to let ddrescue continue working on “as much” of this partially completed image file “as possible” because I don’t know how long the failing hard disk will last – so maybe what I have already successfully rescued might soon be gone for good. However, with the btrfs partition being in this full state, ddrescue always exits with a “No space left on device” error message.

I’ve therefore decided to process the hard disk in two parts: One part should cover as much as I have already rescued (so around 400-450 GiB of the existing backup.img) and the other part should cover the rest. (So something like ddrescue --size=400G /dev/failinghd /mnt/exthd1/part1.img and ddrescue --input-position=400G /dev/failinghd /mnt/exthd2/part2.img)

To get the file & partition back into a state that ddrescue can work with without erroring out, I decided to truncate 10-30 GiB of the end of the file. This means that I accept the risk of possibly truncating data on sectors that I could never recover, but at least I could still continue working with the most of the file as-is. So I tried running:

# truncate -s 448G backup.img 
truncate: failed to truncate 'backup.img' at 481036337152 bytes: No space left on device

And then also:

# truncate -s 400G backup.img 
truncate: failed to truncate 'backup.img' at 429496729600 bytes: No space left on device

But as you can see: I’m still getting the “No space left on device” error messages.

I’ve also tried balancing without success, again because of no space being left:

# btrfs balance start /mnt/exthd -dlimit=3
ERROR: error during balancing '/mnt/exthd': No space left on device

This leads me to my question: What’s my best option for enabling myself to continue working with as much of the file that ddrescue was able to produce so far?

I’ve been thinking about the following options:

  • truncate-ing the file (as described above), which does not seem to work
  • (temporarily) adding another device to the btrfs filesystem (e.g. a USB stick), then truncate-ing the file, then removing the device from the filesystem again (in the hope that I will have truncated the image file enough to have it fit fully onto the “actual” backup hard drive again)

Are there other/better options that I should look into? How do they compare?

And before I forget: I’ve also found the btrfs FAQ article “Help! Btrfs claims I’m out of space, but it looks like I should have lots left!” – but it only provides guidance how to diagnose the “No space left on device” message, but no guidance on how to address it.