Let’s talk about zfs hold. Based on man zfs-hold:
“If a hold exists on a snapshot, attempts to destroy that snapshot by using the zfs destroy command return EBUSY.”
Let’s apply that to some FreshPorts snapshots which I don’t want going away:
This is your typical FreshPorts website:
[15:03 dvl-nginx01 dvl ~] % zfs list NAME USED AVAIL REFER MOUNTPOINT data02 1.13T 565G 96K none data02/freshports 671G 565G 88K none data02/freshports/jailed 326G 565G 96K none data02/freshports/jailed/dvl-nginx01 1.52M 565G 96K none data02/freshports/jailed/dvl-nginx01/cache 1.34M 565G 148K /var/db/freshports/cache data02/freshports/jailed/dvl-nginx01/cache/categories 96K 565G 96K /var/db/freshports/cache/categories data02/freshports/jailed/dvl-nginx01/cache/commits 96K 565G 96K /var/db/freshports/cache/commits data02/freshports/jailed/dvl-nginx01/cache/daily 204K 565G 140K /var/db/freshports/cache/daily data02/freshports/jailed/dvl-nginx01/cache/general 96K 565G 96K /var/db/freshports/cache/general data02/freshports/jailed/dvl-nginx01/cache/news 160K 565G 96K /var/db/freshports/cache/news data02/freshports/jailed/dvl-nginx01/cache/packages 96K 565G 96K /var/db/freshports/cache/packages data02/freshports/jailed/dvl-nginx01/cache/pages 96K 565G 96K /var/db/freshports/cache/pages data02/freshports/jailed/dvl-nginx01/cache/ports 96K 565G 96K /var/db/freshports/cache/ports data02/freshports/jailed/dvl-nginx01/cache/spooling 184K 565G 120K /var/db/freshports/cache/spooling
It’s the cache which has snapshots.
[15:03 dvl-nginx01 dvl ~] % zfs list -r -t snapshot NAME USED AVAIL REFER MOUNTPOINT data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_15:00:00_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_16:00:12_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_17:00:12_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_18:00:04_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_19:00:03_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_19:45:06_frequently 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_20:00:04_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_20:00:04_frequently 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_20:15:02_frequently 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_20:30:02_frequently 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_20:45:04_frequently 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_21:00:05_hourly 0B - 96K - data02/freshports/jailed/dvl-nginx01@autosnap_2024-02-15_21:00:05_frequently 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_15:00:03_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_16:00:17_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_17:00:05_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_18:00:08_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_19:00:11_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_19:45:02_frequently 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_20:00:03_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_20:00:03_frequently 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_20:15:05_frequently 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_20:30:01_frequently 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_20:45:03_frequently 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_21:00:11_hourly 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache@autosnap_2024-02-15_21:00:11_frequently 0B - 128K - data02/freshports/jailed/dvl-nginx01/cache/categories@empty 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache/commits@empty 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache/daily@empty 64K - 96K - data02/freshports/jailed/dvl-nginx01/cache/general@empty 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache/news@empty 64K - 96K - data02/freshports/jailed/dvl-nginx01/cache/packages@empty 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache/pages@empty 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache/ports@empty 0B - 96K - data02/freshports/jailed/dvl-nginx01/cache/spooling@empty 64K - 96K -
Specifically, it’s the @empty snapshots. If the cache must be emptied, that’s the snapshot we use.
Here is that list of snapshots:
[15:03 dvl-nginx01 dvl ~] % zfs list -r -t snapshot | grep empty | cut -f 1 -w data02/freshports/jailed/dvl-nginx01/cache/categories@empty data02/freshports/jailed/dvl-nginx01/cache/commits@empty data02/freshports/jailed/dvl-nginx01/cache/daily@empty data02/freshports/jailed/dvl-nginx01/cache/general@empty data02/freshports/jailed/dvl-nginx01/cache/news@empty data02/freshports/jailed/dvl-nginx01/cache/packages@empty data02/freshports/jailed/dvl-nginx01/cache/pages@empty data02/freshports/jailed/dvl-nginx01/cache/ports@empty data02/freshports/jailed/dvl-nginx01/cache/spooling@empty
I place a hold on them:
[15:05 dvl-nginx01 dvl ~] % zfs list -r -t snapshot | grep empty | cut -f 1 -w | xargs -n 1 sudo zfs hold freshports
And I list them:
[15:05 dvl-nginx01 dvl ~] % zfs list -r -t snapshot | grep empty | cut -f 1 -w | xargs zfs holds NAME TAG TIMESTAMP data02/freshports/jailed/dvl-nginx01/cache/categories@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/commits@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/daily@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/general@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/news@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/packages@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/pages@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/ports@empty freshports Fri Nov 8 15:05 2024 data02/freshports/jailed/dvl-nginx01/cache/spooling@empty freshports Fri Nov 8 15:05 2024
Testing
First, create and destroy:
[15:10 r730-01 dvl ~] % sudo zfs snapshot zroot/var/log@testing [15:10 r730-01 dvl ~] % sudo zfs destroy zroot/var/log@testing
Works.
Try again, with a hold:
[15:10 r730-01 dvl ~] % sudo zfs snapshot zroot/var/log@testing [15:10 r730-01 dvl ~] % sudo zfs hold for-me zroot/var/log@testing [15:10 r730-01 dvl ~] % sudo zfs destroy zroot/var/log@testing cannot destroy snapshot zroot/var/log@testing: dataset is busy
Fail, successfully.
Try again:
[15:11 r730-01 dvl ~] % sudo zfs release for-me zroot/var/log@testing [15:11 r730-01 dvl ~] % sudo zfs destroy zroot/var/log@testing [15:11 r730-01 dvl ~] %
Success.
Thank you for coming to my TED talk.