I am trying to make cow-copies of some files/directories, but of the several ways I know of, all seem sub-optimal.

For example, btrfs can, with the use of cp --reflink=auto quickly generate cow-copies of files.

What I have tried:

  1. Symlinks: No good. Renamed file, broken link.
  2. Hardlinks: Better, but still no good. Changes to one file will change the other, and I don't necessarily want the other file changed.
  3. Create a snapshot of the dataset, then clone the snapshot: This can work, but not well. Often I'm not looking for a copy of the whole dataset, or for the copies to act like another dataset. Then there are the parent/child relationships between the clone/snapshot/original, which as I understand it are hard, if not impossible to break.
  4. Using zfs send/receive, and enabled dedup, replicate the dataset to a new dataset: This avoids the parent/child relationships of using a clone, but still needlessly creates another dataset, and still suffers from the slowness involved in the files having to be read 100% and the blocks referenced again instead of written.
  5. Copy files and let dedup do its job: This works, but is slow because the file(s) have to be 100% read and then the blocks referenced again instead of writing.

Slowness of zfs send/receive and physically copying or rsyncing is further exacerbated because most things are stored compressed, and have to be decompressed during read, then compressed before dedup kicks in to reference duplicate blocks.

In all of my research, I have not been able to find anything remotely resembling the simplicity of --reflink in btrfs.

So, is there a way to create cow-copies in ZFS? Or is "physically" copying and letting dedup do its job the only real option?

2 Answers 2


I think option 3 as you have described above is probably your best bet. The biggest problem with what you want is that ZFS really only handles this copy-on-write at the dataset/snapshot level.

I would strongly suggest avoiding using dedup unless you have verified that it works well with your exact environment. I have personal experience with dedup working great until one more user or VM store is moved in, and then it falls off a performance cliff and causes a lot of problems. Just because it looks like it's working great with your first ten users, your machine might fall over when you add the eleventh (or twelfth, or thirteenth, or whatever). If you want to go this route, make absolutely sure that you have a test environment that exactly mimics your production environment and that it works well in that environment.

Back to option 3, you'll need to set up a specific data set to hold each of the file system trees that you want to manage in this way. Once you've got it set up and initially populated, take your snapshots (one per dataset that will differ slightly) and promote then into clones. Never touch the original dataset again.

Yes, this solution has problems. I'm not saying it doesn't, but given the restrictions of ZFS, it's still probably the best one. I did find this reference to someone using clones effectively: http://thegreyblog.blogspot.com/2009/05/sparing-disk-space-with-zfs-clones.html

I'm not real familiar with btrfs, but if it supports the options that you want, have you considered setting up a separate server just to support these datasets, using Linux and btrfs on that server?

  • This is good food for thought. If the "master" (and thus the children) need large enough changes, a clone of the master could be made, improved, promoted to the new master position, then any subsidiary clones that are far enough different could have rsync-determined variations held aside, the clones destroyed and recrafted from the new master, and the changes pulled back from the held-aside material. This isn't looking like a great solution, but it is starting to look like a good solution, and does save the overhead of having dedup enabled. Must think on this more.
    – killermist
    Jul 9, 2012 at 13:20
  • Yeah, it's not a great solution, but it seems to be the least painful of the ones you've described and I wasn't able to think of any others.
    – jlp
    Jul 9, 2012 at 23:01
  • Summary of your point is illustrated by github.com/zfsonlinux/zfs/issues/405 Basically, ZFS doesn't support file-based COW, only dataset COW, so there is no equivalent to BTRFS cp --reflink=auto.
    – mtalexan
    Jun 5, 2018 at 22:49

Option 5 is the best one.

With regard to parent/child datasets in option 3, you can promote a clone and it will no longer be a child of the cloned dataset. It still won't use up extra blocks. Edit: Noted that this only reverses parent/child relationship, not destroys it.

With regard to things being compressed/encrypted and that slowing down the copy, that is completely false. Your processor is far faster than your block device is (even if using SSDs). Just for some example numbers, let's say that it takes 10 seconds to read a block, but it only takes one second to decompress it and 2 seconds to decrypt it. Block 1 gets read in 10 seconds and sent to the CPU. The CPU begins decompressing and decrypting while the disk begins reading block 2. The CPU will finish its task in 3 seconds and then spend the next 7 seconds waiting on the disk. The disk meanwhile has spent the exact same amount of time reading those two blocks (20 seconds) regardless of whether the blocks are compressed or not.

Likewise while writing, only the first block is delayed. The CPU compresses/encrypts block 1 and sends it to the disk. While the disk is writing block 1 the CPU will start compressing/encrypting subsequent blocks. The CPU will chew through blocks much faster than the disk can write them so it's not an issue. (Yes, it's more complex than this, but this is the gist.)

Sorry for the overly long explanation of a minor point in your question, but I wanted to clear up that misconception.

  • 2
    Promoting a clone just switches which is considered the parent and which is considered the child. It remains impossible to destroy the snapshot in between because the original parent is now a child of the snapshot, which is now a child of the promoted clone. On top of that, it is still unnecessarily creating dataset-like constructs where I was just looking to replicate files within the dataset.
    – killermist
    Jun 26, 2012 at 18:05
  • Additionally, on a pool with dedup enabled, I have to disagree with the conclusion on compression slowdown. Copying from a dataset with compression enabled to a dataset with compression enabled, speeds rarely exceeded 5Mb/sec. If one dataset or the other has compression disabled, speeds jump to 10-15Mb/sec on average. With both sides compression disabled, I'm seeing 20Mb/sec easily with spikes higher than that (probably because portions are hitting the dedup table in ram instead of pulling from slower media).
    – killermist
    Jun 26, 2012 at 18:09
  • 2
    I updated my answer with regard to the cloning. As for compression/encryption/dedup, the slowdowns are more caused by updating the DDT than they are compression or encryption. In my experience the impact of compression and encryption have always been negligible. I guess YMMV.
    – bahamat
    Jun 26, 2012 at 18:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .