I'm copying a large number of files between two lzo compressed BtrFS filesystems on different drives mounted on the same machine. It appears that the files are being de/re-compressed. Is there a way avoid this?


Not really, and it comes down to syscalls. Have an example:

open  ("tuppence", O_RDONLY)                           = 3
fstat (3, {st_mode=S_IFREG|0644, st_size=15, ...})     = 0
open  ("/tmp/tuppence", O_WRONLY|O_CREAT|O_EXCL, 0644) = 4
fstat (4, {st_mode=S_IFREG|0644, st_size=0, ...})      = 0
read  (3, "I have cheese.\n", 32768)                   = 15
write (4, "I have cheese.\n", 15)                      = 15

(This is strace data, cleaned up a bit for clarity, done while copying a file.)

To copy a file from point A to point B, especially across mount-points, Linux will call read on the file to be copied, and then call write on the new one. You can see it in the above trace.

  1. Open the source file, yielding file-descripter number 3.
  2. Open the destination file, yielding the file-descripter number 4.
  3. Read from descripter 3, the source file.
  4. Write the data read in from 3, into descripter 4, the target file.
  5. Close everything.

The read syscall requests the file for use by a process, which triggers BTRFS decompression. This retrieved data is then fed into the write call, which will trigger BTRFS compression on the target. This behavior is fundamental to how the Linux filesystem layers work.

To bypass this, don't use cp. You would have to use a btrfs-specific tool that handles moving datastructures entirely within the btrfs volume. The problem is, I don't know if such tools exist.

  • I see. Very useful, thank you. BtrFS does have a lot of it's own tools, like "df" for example; so unless someone else chimes in, I'll look into the "cp" question at the dev email list. – Diagon Jan 8 '16 at 21:55

As @sysadmin1138 so well illustrated, this problem is unavoidable if using cp/rsync/send-receive across file-systems; but there is a way to avoid it under certain circumstances. If you use a seed device, add a new device (as raid1), and then delete the seed, you will get a duplicate volume that is essentially the same as the source. (Though the UUID will change.)

As pointed out on the dev list, "... the duplicate volume is essentially the same as the source (the process copies chunks), which means the chunk profile is also preserved."

As a note regarding my specific use case, I could have used this method to copy, done my server install into a subvolume, and then just mv'd the files over. That would have saved a substantial amount of work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.