Bug 248105 - Some zfs snapshots are busy within the ZCP domain but can still be destroyed from userland
Summary: Some zfs snapshots are busy within the ZCP domain but can still be destroyed ...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 12.1-STABLE
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-fs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-07-19 13:44 UTC by Bertrand Petit
Modified: 2020-07-23 21:52 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Bertrand Petit 2020-07-19 13:44:44 UTC
On a host running 12-STABLE (rev 360207) I observe an inconsistent behavior from zfs when attempting to destroy snapshots. From a zfs channel program, a call to zfs.sync.destroy() fails and return EBUSY. That is extremely strange as the affected snapshot is not a clone source and can be destroyed without error with the 'zfs destroy' command.

I observed that the ZCP I'm using stopped functioning correctly due to this bug after I accessed the contents of another (more recent) snapshot via the .zfs/snapshot facility. Snapshots created after accessing .zfs/snapshot are not deemed busy while all snapshots created before the access are busy from the ZCP domain. By accessing .zfs/snapshot I mean listing the contents of .zfs/snapshot, listing the contents of a given snapshot, and eventually copying a file from that same snapshot.

As a summary, please consider the following layout:

pool/fs@snapA
pool/fs@snapB
pool/fs@snapC
pool/fs@snapD

on which the following actions are applied (with their outcome):

zfs.sync.destroy("pool/fs@snapA")  -- will succeed
$ ls pool/fs/.zfs/snapC
$ ls pool/fs/.zfs/snapC/
$ cp pool/fs/.zfs/snapC/file /tmp/discard
zfs.sync.destroy("pool/fs@snapB")  -- will fail
$ zfs destroy pool/fs@snapB        #  will succeed
$ zfs snapshot pool/fs@snapE
zfs.sync.destroy("pool/fs@snapE")  -- will succeed
zfs.sync.destroy("pool/fs@snapD")  -- will fail
$ zfs destroy pool/fs@snapD        #  will succeed
Comment 1 Andriy Gapon freebsd_committer freebsd_triage 2020-07-20 07:07:36 UTC
The difference between zfs destroy and zfs.sync.destroy is that the former will unmount a snapshot if it's mounted while the latter will fail with EBUSY.

Why operations involving .zfs/snapC would mount other snapshots is a puzzle.
Comment 2 Andriy Gapon freebsd_committer freebsd_triage 2020-07-20 10:07:33 UTC
Only after copy pasting from your report into my comment #1 I realized that some commands in your report are incorrect.
There is no .zfs/snapC directory, there is .zfs/snapshot/snapC.
So, I wonder if at some stage you did something like ls .zfs/snapshot.
That would mount all snapshots.
Comment 3 Bertrand Petit 2020-07-23 21:52:18 UTC
(In reply to Andriy Gapon from comments #2)

> There is no .zfs/snapC directory, there is .zfs/snapshot/snapC.
> So, I wonder if at some stage you did something like ls .zfs/snapshot.

You are right, when simplifying the structure it looks I did one M-DEL too far.

The commands are:

$ ls pool/fs/.zfs/snapshot/snapC
$ ls pool/fs/.zfs/snapshot/snapC/
$ cp pool/fs/.zfs/snapshot/snapC/file /tmp/discard

Also, an implicit opendir() readdir() must had been executed by the shell at some point on pool/fs/.zfs/ and pool/fs/.zfs/snapshot/ due to filename completion.

> That would mount all snapshots.

I can not see a way to unmount them, these mounts are not listed when executing
mount(8) without argument. The "mounted" property on those snapshots is reported as being unset: "-". Shouldn't these implicit mounts be automatically unmounted once the last file descriptor referencing them get closed?