Let's say I have a large file (8GB) called example.log on ZFS. I do cp example.log example.bak to make a copy. Then I add or modify a few bytes in original file. What will happen?

Will ZFS copy the entire 8GB file or only the blocks that changed (and all the chain of inodes pointing from the file descriptor to that block)?


As far as I could tell, FreeBSD ZFS does not support copy-on-write using cp; the native cp does not seem to have an option for such lightweight copies, and trying GNU cp with --reflink errors out on the ZFS system I tried with error message "cp: failed to clone 'example.bak' from 'example.log': Operation not supported".

A commenter mentions that Solaris cp has a -z switch to do such copies.

However, and I hope this answers your underlying question, copy-on-write is used for filesystem snapshots: let's say you have 900GB used out of 1000GB available, nothing prevents you from making a snapshot of that filesystem, the snapshot will not occupy 900GB; in fact, it will initially not occupy any new data blocks at all.

After creating a snapshot of your original filesystem containing example.log, you end up with two "copies": the read-only version in the snapshot, and you live version in its original location. What happens when the copy is modified, be it by appending or by being altered in-place? That is where the magic happens: only those blocks that are altered get copied and start using up space. It is not the case that the entire file gets copied as soon as it gets altered.

| improve this answer | |
  • As far as I could tell, ZFS does not support copy-on-writes using cp ZFS on Solaris 11.4 does, via cp -z .... For Linux, XFS w/ kernel 4.8 or later and BTRFS do support reflinks. – Andrew Henle Jan 22 at 11:07

The cp command will create a new file, so there will be a duplicate of every block. Once you modify a few bytes in the original file, ZFS will first copy the block of data which contains those bytes from disk into RAM, apply the new bytes to it, and then write that block out to a new location on disk. The original block will be freed (simplifying here, but that's essentially what happens). The rest of the blocks of the file are left alone.

Regarding the inode part of your question: ZFS does not have inodes. Instead, it maintains "indirect blocks". These are blocks of metadata on disk which point to the data of the file. There can be layers of indirect blocks, depending on the file size and the file's block size. The indirect block(s) which point to the modified block will need to be updated, but the rest are left alone.

| improve this answer | |
  • Do I need to use any special parameters or simple cp <source> <target> is fine? dhag mentioned that I need to use cp --reflink and Andrew Henle suggested using cp -z – HubertNNN Jan 22 at 13:45
  • If you're using Solaris, then cp -z will create a new name for the same blocks of data. It differs from ln in that writing to one file will use copy-on-write to allow the two files to diverge, whereas with ln there is only ever one file. Note that -z is restricted to directories in the same ZFS pool. I don't know about how linux behaves, sorry – mmusante Jan 22 at 16:49

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.