<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Snapshots on inetshell</title><link>https://inet.sh/en/tags/snapshots/</link><description>Recent content in Snapshots on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Wed, 19 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/snapshots/index.xml" rel="self" type="application/rss+xml"/><item><title>Protect ZFS snapshots from destroy with hold</title><link>https://inet.sh/en/posts/zfs/hold-protect-snapshot/</link><pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/zfs/hold-protect-snapshot/</guid><description>zfs hold and zfs release: a keep tag on a snapshot makes zfs destroy fail with dataset is busy.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<p><code>zfs hold keep pool/dataset@snap</code> — <code>zfs destroy</code> fails with <em>dataset is busy</em>. Release with <code>zfs release</code>.</p>
<p>Retention scripts (<code>zfs destroy -r …@auto-…</code>) do not ask. A <strong>hold</strong> is a named lock on a snapshot: <code>destroy</code> fails until you drop the tag.</p>
<p>Use it on the snapshot you are <code>zfs send</code>ing, or on the only known-good rollback after an upgrade.</p>
<h2 id="take-the-hold">Take the hold</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs hold keep tank/home/cindys@snap1
</span></span></code></pre></td></tr></table>
</div>
</div><p>Recursive on a whole tree (snapshot first, then hold):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs snapshot -r tank/home@now
</span></span><span class="line"><span class="cl">zfs hold -r keep tank/home@now
</span></span></code></pre></td></tr></table>
</div>
</div><p>The tag (<code>keep</code>) is yours, but <strong>unique per snapshot</strong>. You can have both <code>keep</code> and <code>offsite</code> on the same <code>@now</code>.</p>
<h2 id="what-destroy-does">What destroy does</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs destroy tank/home/cindys@snap1
</span></span><span class="line"><span class="cl"><span class="c1"># cannot destroy &#39;tank/home/cindys@snap1&#39;: dataset is busy</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>That is the hold, not a mounted filesystem. <code>zfs destroy -d</code> <strong>defers</strong> deletion until holds are gone; it does not override them.</p>
<h2 id="list">List</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs holds tank/home@now
</span></span><span class="line"><span class="cl">zfs holds -r tank/home@now
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">NAME                  TAG   TIMESTAMP
</span></span><span class="line"><span class="cl">tank/home@now         keep  Thu Jul 15 11:25:39 2010
</span></span><span class="line"><span class="cl">tank/home/cindys@now  keep  Thu Jul 15 11:25:39 2010
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="release-then-destroy">Release, then destroy</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs release -r keep tank/home@now
</span></span><span class="line"><span class="cl">zfs destroy -r tank/home@now
</span></span></code></pre></td></tr></table>
</div>
</div><p>If a long <code>send</code> is still running, wait: the hold exists so prune cannot eat your incremental cursor.</p>
<p>Oracle&rsquo;s description (same mechanism on OpenZFS): <a href="https://docs.oracle.com/cd/E19253-01/819-5461/gjdfk/index.html">Holding ZFS snapshots</a>.</p>
<p>See also: <a href="/en/posts/zfs/send-unencrypted-to-encrypted/">send into an encrypted dataset</a>.</p>
]]></content:encoded></item></channel></rss>