Improve the way you make use of ZFS in your company.
Did you know you can rely on Klara engineers for anything from a ZFS performance audit to developing new ZFS features to ultimately deploying an entire storage system on ZFS?
ZFS Support ZFS DevelopmentAdditional Articles
Here are more interesting articles on ZFS that you may find useful:
- Fall 2024 Top Reads for Open Source Enthusiasts
- Deploying pNFS file sharing with FreeBSD
- Applying the ARC Algorithm to the ARC
- Introducing OpenZFS Fast Dedup
- DKMS vs kmod: The Essential Guide for ZFS on Linux
Earlier in this series, we discussed the Basics of ZFS Snapshot Management: how to create OpenZFS snapshots, restore files from a snapshot, and delete snapshots. Today’s article dives a bit deeper into OpenZFS snapshot management with snapshot holds, clone creation and promotion, and assigning permissions to snapshot-related operations.
Holding Snapshots
On a FreeBSD 13.0 test system, I created a series of snapshots of the home directory in the default zroot pool. Here is a listing of the available snapshots:
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot1 80K - 96K -
zroot/usr/home@snapshot2 72K - 1.99M -
zroot/usr/home@snapshot3 64K - 2.03M -
zroot/usr/home@snapshot4 64K - 2.00M -
zroot/usr/home@snapshot5 512K - 260M -
zroot/usr/home@snapshot6 0B - 259M -
By default, as the root user, I can destroy any of these snapshots. Here I delete and verify the deletion of snapshot1:
zfs destroy zroot/usr/home@snapshot1
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot2 72K - 1.99M -
zroot/usr/home@snapshot3 64K - 2.03M -
zroot/usr/home@snapshot4 64K - 2.00M -
zroot/usr/home@snapshot5 512K - 260M -
zroot/usr/home@snapshot6 0B - 259M -
And here goes snapshot4:
zfs destroy zroot/usr/home@snapshot4
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot2 72K - 1.99M -
zroot/usr/home@snapshot3 72K - 2.03M -
zroot/usr/home@snapshot5 520K - 260M -
zroot/usr/home@snapshot6 0B - 259M -
But what if I have a snapshot that I don’t want even the root user or an errant deletion script to destroy? Perhaps that snapshot represents a baseline point-in-time that I might wish to return to. Enter zfs-hold(8): Hold a snapshot to prevent it being removed with the zfs destroy command.
To create a hold, specify a name for the hold (known as a tag) and the name of the snapshot. Here I’ll create a hold tag of keepme on snapshot3:
zfs hold keepme zroot/usr/home@snapshot3
You can use any value you want for the tag that reminds you why you created the hold, as long as the snapshot doesn’t already have a tag using that same value.
To see the list of holds on a snapshot, specify the snapshot name:
zfs holds zroot/usr/home@snapshot3
NAME TAG TIMESTAMP
zroot/usr/home@snapshot3 keepme Thu Aug 19 11:04 2021
Now that this snapshot has a hold, I am unable to delete the snapshot:
zfs destroy zroot/usr/home@snapshot3
cannot destroy snapshot zroot/usr/home@snapshot3: dataset is busy
If I no longer need to hold this snapshot and actually want to delete it, I’ll need to first release its hold. To do so, specify the name of the hold tag and the name of the snapshot:
zfs release keepme zroot/usr/home@snapshot3
zfs holds zroot/usr/home@snapshot3
NAME TAG TIMESTAMP
Now the snapshot deletion will succeed:
zfs destroy zroot/usr/home@snapshot3
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot2 140K - 1.99M -
zroot/usr/home@snapshot5 528K - 260M -
zroot/usr/home@snapshot6 0B - 259M -
Creating Clones
A snapshot, by definition, is a read-only copy of a file system. This is a good thing for file restoration purposes as it allows you to access a file’s version from a known point in time. However, there are times when it is useful to have a read-write copy of a file system. zfsconcepts(8) defines a clone as: a writable volume or file system whose initial contents are the same as another dataset. As with snapshots, creating a clone is nearly instantaneous, and initially consumes no additional space.
As an example use case, consider a dataset containing a directory of virtual images that are each 2 GB in size and which are used for testing by multiple users. If each tester copies an image to their testing directory whenever they need to perform a test, the amount of consumed storage will increase by 2 GB for every test. Contrast that with instead creating a clone for each user. Since clones are created from snapshots, there is a known point in time, a definite benefit in testing. Better yet, the only storage consumed will be any edits made to the clones. This more efficient use of storage can apply to any use case where multiple users are working on large files (another example would be a directory containing videos that need to be edited for production). And, any edits to the clone are independent of the snapshot (your original baseline) as well as the “production” file system the snapshot is based on.
It’s important to note that clones can only be created from a snapshot and that a snapshot cannot be destroyed as long as it has any clones. Interestingly, clones do not inherit the properties of the snapshot, meaning that different properties can be specified when creating the clone. The clone can be located anywhere in the ZFS hierarchy as long as it is in the same pool.
To create a clone from a snapshot, specify the snapshot name followed by the clone location and name. In this example, I’ll verify which snapshots still exist before creating a clone of snapshot5 named clone1 and locate it on the tmp file system in the zroot pool:
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot2 140K - 1.99M -
zroot/usr/home@snapshot5 528K - 260M -
zroot/usr/home@snapshot6 0B - 259M -
zfs clone zroot/usr/home@snapshot5 zroot/tmp/clone1
Since a clone is a readfully writable file system, zfs list doesn’t distinguish between file systems and a cloned snapshot:
zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot 1.17G 11.9G 96K /zroot
zroot/ROOT 932M 11.9G 96K none
zroot/ROOT/default 932M 11.9G 932M /
zroot/tmp 96K 11.9G 96K /tmp
zroot/tmp/clone1 0B 11.9G 260M /tmp/clone1
zroot/usr 260M 11.9G 96K /usr
zroot/usr/home 260M 11.9G 259M /usr/home
zroot/usr/ports 96K 11.9G 96K /usr/ports
zroot/usr/src 96K 11.9G 96K /usr/src
zroot/var 632K 11.9G 96K /var
zroot/var/audit 96K 11.9G 96K /var/audit
zroot/var/crash 96K 11.9G 96K /var/crash
zroot/var/log 152K 11.9G 152K /var/log
zroot/var/mail 96K 11.9G 96K /var/mail
zroot/var/tmp 96K 11.9G 96K /var/tmp
However, the origin property will indicate that it is a clone and give the value of the parent snapshot:
zfs get origin zroot/tmp/clone1
NAME PROPERTY VALUE SOURCE
zroot/tmp/clone1 origin zroot/usr/home@snapshot5 -
Now that I have a clone, let’s see what happens if I try to delete the parent snapshot, snapshot5:
zfs destroy zroot/usr/home@snapshot5
cannot destroy 'zroot/usr/home@snapshot5': snapshot has dependent clones
use '-R' to destroy the following datasets:
zroot/tmp/clone1
The error message clearly indicates that the dataset (the clone) needs to first be destroyed. Once I am finished with the clone, I can delete the clone and then successfully delete the parent snapshot:
zfs destroy zroot/tmp/clone1
zfs destroy zroot/usr/home@snapshot5
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot2 140K - 1.99M -
zroot/usr/home@snapshot6 0B - 259M -
Promoting Clones
But what if you like the changes in the clone more than the data in the original snapshot? A common use case for creating clones is to test changes, and it is desirable to push them into production once testing is complete.
In this case you can promote the clone which reverses the parent-child dependency relationship. In other words, the clone is now a “real” file system and the original snapshot is now a clone with all the old snapshots intact.
Let’s see this in action by creating a clone on one of the remaining snapshots:
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr/home@snapshot2 140K - 1.99M -
zroot/usr/home@snapshot6 0B - 259M -
zfs clone zroot/usr/home@snapshot2 zroot/tmp/promote-me
zfs destroy zroot/usr/home@snapshot2
cannot destroy 'zroot/usr/home@snapshot2': snapshot has dependent clones
use '-R' to destroy the following datasets:
zroot/tmp/promote-me
So far, so good. Let’s see what happens when I promote the promote-me clone:
zfs promote zroot/tmp/promote-me
zfs get origin zroot/tmp/promote-me
NAME PROPERTY VALUE SOURCE
zroot/tmp/promote-me origin - -
As expected, promote-me is no longer dependent on snapshot2. However, this might surprise you:
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/tmp/promote-me@snapshot2 0B - 1.99M -
zroot/usr/home@snapshot6 0B - 259M -
snapshot2 now resides on the zroot/tmp/promote-me file system. Is there a remaining dependency? Let’s check:
zfs get origin
NAME PROPERTY VALUE SOURCE
zroot origin - -
zroot/ROOT origin - -
zroot/ROOT/default origin - -
zroot/tmp origin - -
zroot/tmp/promote-me origin - -
zroot/tmp/promote-me@snapshot2 origin - -
zroot/usr origin - -
zroot/usr/home origin zroot/tmp/promote-me@snapshot2 -
zroot/usr/home@snapshot6 origin - -
<snip>
Now things look much better, don’t they? Enabling compression is good in most cases. The same test can be done changing the recordsize. Let's try with a small one just to see how one single setting can affect space efficiency in a dramatic way. I will disable compression to better understand the numbers:
root@geroda:/testpool # zfs set compression=off testpool
root@geroda:/testpool # zfs set recordsize=4K testpool
root@geroda:/testpool # /root/test_recordsize.sh
1 K size -> 3 K alloc
2 K size -> 3 K alloc
3 K size -> 5 K alloc
4 K size -> 5 K alloc
5 K size -> 13 K alloc
6 K size -> 13 K alloc
7 K size -> 13 K alloc
8 K size -> 13 K alloc
9 K size -> 17 K alloc
23 K size -> 29 K alloc
24 K size -> 29 K alloc
25 K size -> 33 K alloc
31 K size -> 37 K alloc
129 K size -> 137 K alloc
254 K size -> 264 K alloc
255 K size -> 264 K alloc
256 K size -> 264 K alloc
And what happens if I try to delete snapshot2?
zfs destroy zroot/tmp/promote-me@snapshot2
cannot destroy 'zroot/tmp/promote-me@snapshot2': snapshot has dependent clones
use '-R' to destroy the following datasets:
zroot/usr/home@snapshot6
zroot/usr/home
Well, I probably don’t want to destroy zroot/usr/home... This is what zfs-promote(8) means when it says: the origin file system becomes a clone of the specified file system.
Before creating a clone that you eventually plan on promoting to be a “real” file system, you want to give careful thought to where that file system should live. Example 10 in zfs(8) gives a real-world example of replacing a production file system with a testing clone that is now ready for running in production. Note that the example uses zfs rename to change file system names between beta, legacy, and production after performing the promote. You will want to follow a similar workflow in order to differentiate which file system is which when changing to a new production file system and eventually destroying the legacy file system.
Assigning Permissions
Basics of ZFS Snapshot Management gives several examples of assigning a particular user specific permissions to ZFS operations on a specified file system. To see if any non-root users or groups have been assigned permissions to ZFS operations, specify the file system to check. Here I’m checking ZFS operations permissions on the zroot pool of a default FreeBSD installation:
zfs allow zroot
If I only get the prompt back, no permissions have been assigned and most ZFS operations can only be performed by the root user. The following permissions are related to snapshot operations:
- clone
- create
- destroy
- diff
- hold
- promote
- release
- rename
- snapshot
Permissions can be granted (with allow) and revoked (with unallow) to users and groups. Keep in mind that ZFS operations are powerful and act on data, one of your most valuable assets. Be judicious when allowing operational access and periodically review permissions to determine if they are still appropriate. Refer to zfs-allow(8) for syntax guidance.
Conclusion
This article covered some advanced OpenZFS features that can help you get even more out of your snapshots. However, if your needs are more complicated and demand qualified services, the experts at Klara are available to help you with your OpenZFS support.
Dru Lavigne
Dru Lavigne is a retired network and systems administrator, IT instructor, author, and international speaker. Dru is author of BSD Hacks, The Best of FreeBSD Basics, and The Definitive Guide to PC-BSD.
Learn About KlaraGetting expert ZFS advice is as easy as reaching out to us!
At Klara, we have an entire team dedicated to helping you with your ZFS Projects. Whether you’re planning a ZFS project or are in the middle of one and need a bit of extra insight, we are here to help!