A ZFS Clone is a read-write clone of a filesystem created from a snapshot. It still refers to the snapshot it has been created from, but allows us to make changes. We cannot remove the origin snapshot whilst the clone is in use, unless we promote it. These concepts will become clear during the examples.
Let’s create a test dataset:
|
1 |
# zfs create -o mountpoint=/clonefs datapool/clonefs |
Put some data on the filesystem:
|
1 2 3 4 |
# cp -p /var/adm/messages* /var/log/syslog* /clonefs # zfs list datapool/clonefs NAME USED AVAIL REFER MOUNTPOINT datapool/clonefs 306K 19.4G 306K /clonefs |
We can now take a snapshot of the filesystem:
|
1 2 3 4 |
# zfs snapshot datapool/clonefs@`date +%Y%m%d` # zfs list -t snapshot | grep -v ROOT NAME USED AVAIL REFER MOUNTPOINT datapool/clonefs@20130129 0 - 306K - |
Now, take a clone of this snapshot into a new dataset:
|
1 |
# zfs clone -o mountpoint=/cloned datapool/clonefs@20130129 datapool/cloned |
Here, the clone is being created from the snapshot datapool/clonefs@20130129 into the new dataset datapool/cloned. zfs list shows the new dataset:
|
1 2 3 |
# zfs list datapool/cloned NAME USED AVAIL REFER MOUNTPOINT datapool/cloned 19K 19.4G 306K /cloned |
See that 19KB is used, but the dataset refers to 306KB somewhere else. Where does that originate? The origin property of the ZFS dataset datapool/cloned will show us:
|
1 2 3 |
# zfs get origin datapool/cloned NAME PROPERTY VALUE SOURCE datapool/cloned origin datapool/clonefs@20130129 - |
There we go. We will be unable to delete the origin snapshot (as it’s still required for the clone to function):
|
1 2 3 4 |
# zfs destroy datapool/clonefs@20130129 cannot destroy 'datapool/clonefs@20130129': snapshot has dependent clones use '-R' to destroy the following datasets: datapool/cloned |
No – we don’t want that! Before we complete this, verify that the dataset is in-fact a read-write clone:
|
1 2 3 4 |
# rm /cloned/messages.0 # zfs list datapool/cloned NAME USED AVAIL REFER MOUNTPOINT datapool/cloned 20K 19.4G 48.5K /cloned |
The ZFS dataset can be promoted:
|
1 2 3 4 |
# zfs promote datapool/cloned # zfs get origin datapool/cloned NAME PROPERTY VALUE SOURCE datapool/cloned origin - - |
See that the snapshot is now a snapshot of the CLONED filesystem:
|
1 2 3 |
# zfs list -t snapshot | grep -v ROOT NAME USED AVAIL REFER MOUNTPOINT datapool/cloned@20130129 278K - 306K - |
And that the original filesystem (the one we cloned) is now dependent on this snapshot, and uses it as its origin:
|
1 2 3 |
# zfs get origin datapool/clonefs NAME PROPERTY VALUE SOURCE datapool/clonefs origin datapool/cloned@20130129 - |
Essentially, the parent-child relationship is switched. We can switch it back:
|
1 |
# zfs promote datapool/clonefs |
Switch it back again (dizzy yet?) and then you can destroy the dataset that datapool/cloned was created from (i.e. datapool/clonefs):
|
1 2 |
# zfs promote datapool/cloned # zfs destroy datapool/clonefs |
As the dependent filesystem has now been removed, the snapshot too can be removed:
|
1 |
# zfs destroy datapool/cloned@20130129 |
And we’re done with clones.
Sending/Receiving ZFS Data
ZFS send/receive is essentially ufsdump/ufsrestore on steroids. zfs send can be used to create “streams” from snapshots, and send those streams to files, other systems, or indeed another dataset with zfs recv.
zfs send/recv, along with the snapshot functionality, allow us to create our own complex backup solutions relatively simply.
Start, as usual, with a test dataset with a few files copied to it:
|
1 2 3 4 5 |
# zfs create -o mountpoint=/sendfs datapool/sendfs # cp -p /var/adm/messages* /var/log/syslog* /sendfs # zfs list datapool/sendfs NAME USED AVAIL REFER MOUNTPOINT datapool/sendfs 306K 19.4G 306K /sendfs |
Create a snapshot of the filesystem:
|
1 2 3 4 |
# zfs snapshot datapool/sendfs@sendme # zfs list -t snapshot | grep -v ROOT NAME USED AVAIL REFER MOUNTPOINT datapool/sendfs@sendme 0 - 306K - |
zfs send writes a stream of the current snapshot to STDOUT. zfs recv receives a ZFS data stream on STDIN. Thus, we can just pipe it the output of zfs send into zfs recv and create a new filesystem from the stream on-the-fly:
|
1 |
# zfs send datapool/sendfs@sendme | zfs recv datapool/receiveme |
We can see that the new filesystem has been created:
|
1 2 3 |
# zfs list datapool/receiveme NAME USED AVAIL REFER MOUNTPOINT datapool/receiveme 306K 19.4G 306K /datapool/receiveme |
The snapshot has also been created:
|
1 2 3 4 |
# zfs list -t snapshot | grep -v ROOT NAME USED AVAIL REFER MOUNTPOINT datapool/receiveme@sendme 0 - 306K - datapool/sendfs@sendme 0 - 306K - |
We won’t be needing that, so we can remove it:
|
1 |
# zfs destroy datapool/receiveme@sendme |
We can verify that datapool/receiveme contains the data we sent:
|
1 2 |
# ls /datapool/receiveme messages messages.0 syslog syslog.0 |
zfs send will, by default, send a full backup. You can use zfs send -i to send incremental backups and fashion yourself that backup system I’ve been prattling on about – which is when the ZFS snapshots that it creates on the destination (receiving) dataset are required (so that the filesystem can be restored to a point-in-time, for example). Going into this solution within this article is stretching the scope a little.
As zfs send/recv operate on streams (just like the rest of UNIX), we can do things like:
|
1 2 3 4 |
# zfs send datapool/sendfs@sendme | gzip -9c > /tmp/sendme.gz # gzip -dc9 /tmp/sendme.gz | zfs recv datapool/newpool # ls /datapool/newpool messages messages.0 syslog syslog.0 |
Conclusion
This article has covered the ZFS basics, and a few advanced concepts too. In a later article, I’ll introduce other concepts such as ZFS Delegated administration, setting up NFS/SMB servers using a ZFS backing store, repairing failed zpools (and scrubbing) and much more.