zfs_ctldir.c revision 170281
1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd/*
22168404Spjd * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23168404Spjd * Use is subject to license terms.
24168404Spjd */
25168404Spjd
26168404Spjd#pragma ident	"%Z%%M%	%I%	%E% SMI"
27168404Spjd
28168404Spjd/*
29168404Spjd * ZFS control directory (a.k.a. ".zfs")
30168404Spjd *
31168404Spjd * This directory provides a common location for all ZFS meta-objects.
32168404Spjd * Currently, this is only the 'snapshot' directory, but this may expand in the
33168404Spjd * future.  The elements are built using the GFS primitives, as the hierarchy
34168404Spjd * does not actually exist on disk.
35168404Spjd *
36168404Spjd * For 'snapshot', we don't want to have all snapshots always mounted, because
37168404Spjd * this would take up a huge amount of space in /etc/mnttab.  We have three
38168404Spjd * types of objects:
39168404Spjd *
40168404Spjd * 	ctldir ------> snapshotdir -------> snapshot
41168404Spjd *                                             |
42168404Spjd *                                             |
43168404Spjd *                                             V
44168404Spjd *                                         mounted fs
45168404Spjd *
46168404Spjd * The 'snapshot' node contains just enough information to lookup '..' and act
47168404Spjd * as a mountpoint for the snapshot.  Whenever we lookup a specific snapshot, we
48168404Spjd * perform an automount of the underlying filesystem and return the
49168404Spjd * corresponding vnode.
50168404Spjd *
51168404Spjd * All mounts are handled automatically by the kernel, but unmounts are
52168404Spjd * (currently) handled from user land.  The main reason is that there is no
53168404Spjd * reliable way to auto-unmount the filesystem when it's "no longer in use".
54168404Spjd * When the user unmounts a filesystem, we call zfsctl_unmount(), which
55168404Spjd * unmounts any snapshots within the snapshot directory.
56168404Spjd */
57168404Spjd
58168404Spjd#include <sys/zfs_context.h>
59168404Spjd#include <sys/zfs_ctldir.h>
60168404Spjd#include <sys/zfs_ioctl.h>
61168404Spjd#include <sys/zfs_vfsops.h>
62168404Spjd#include <sys/namei.h>
63168404Spjd#include <sys/gfs.h>
64168404Spjd#include <sys/stat.h>
65168404Spjd#include <sys/dmu.h>
66168404Spjd#include <sys/mount.h>
67168404Spjd
68168404Spjdtypedef struct {
69168404Spjd	char		*se_name;
70168404Spjd	vnode_t		*se_root;
71168404Spjd	avl_node_t	se_node;
72168404Spjd} zfs_snapentry_t;
73168404Spjd
74168404Spjdstatic int
75168404Spjdsnapentry_compare(const void *a, const void *b)
76168404Spjd{
77168404Spjd	const zfs_snapentry_t *sa = a;
78168404Spjd	const zfs_snapentry_t *sb = b;
79168404Spjd	int ret = strcmp(sa->se_name, sb->se_name);
80168404Spjd
81168404Spjd	if (ret < 0)
82168404Spjd		return (-1);
83168404Spjd	else if (ret > 0)
84168404Spjd		return (1);
85168404Spjd	else
86168404Spjd		return (0);
87168404Spjd}
88168404Spjd
89168404Spjdstatic struct vop_vector zfsctl_ops_root;
90168404Spjdstatic struct vop_vector zfsctl_ops_snapdir;
91168404Spjdstatic struct vop_vector zfsctl_ops_snapshot;
92168404Spjd
93168404Spjdstatic vnode_t *zfsctl_mknode_snapdir(vnode_t *);
94168404Spjdstatic vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset);
95168404Spjd
96168404Spjdtypedef struct zfsctl_node {
97168404Spjd	gfs_dir_t	zc_gfs_private;
98168404Spjd	uint64_t	zc_id;
99168404Spjd	timestruc_t	zc_cmtime;	/* ctime and mtime, always the same */
100168404Spjd} zfsctl_node_t;
101168404Spjd
102168404Spjdtypedef struct zfsctl_snapdir {
103168404Spjd	zfsctl_node_t	sd_node;
104168404Spjd	kmutex_t	sd_lock;
105168404Spjd	avl_tree_t	sd_snaps;
106168404Spjd} zfsctl_snapdir_t;
107168404Spjd
108168404Spjd/*
109168404Spjd * Root directory elements.  We have only a single static entry, 'snapshot'.
110168404Spjd */
111168404Spjdstatic gfs_dirent_t zfsctl_root_entries[] = {
112168404Spjd	{ "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE },
113168404Spjd	{ NULL }
114168404Spjd};
115168404Spjd
116168404Spjd/* include . and .. in the calculation */
117168404Spjd#define	NROOT_ENTRIES	((sizeof (zfsctl_root_entries) / \
118168404Spjd    sizeof (gfs_dirent_t)) + 1)
119168404Spjd
120168404Spjd
121168404Spjd/*
122168404Spjd * Initialize the various GFS pieces we'll need to create and manipulate .zfs
123168404Spjd * directories.  This is called from the ZFS init routine, and initializes the
124168404Spjd * vnode ops vectors that we'll be using.
125168404Spjd */
126168404Spjdvoid
127168404Spjdzfsctl_init(void)
128168404Spjd{
129168404Spjd}
130168404Spjd
131168404Spjdvoid
132168404Spjdzfsctl_fini(void)
133168404Spjd{
134168404Spjd}
135168404Spjd
136168404Spjd/*
137168404Spjd * Return the inode number associated with the 'snapshot' directory.
138168404Spjd */
139168404Spjd/* ARGSUSED */
140168404Spjdstatic ino64_t
141168404Spjdzfsctl_root_inode_cb(vnode_t *vp, int index)
142168404Spjd{
143168404Spjd	ASSERT(index == 0);
144168404Spjd	return (ZFSCTL_INO_SNAPDIR);
145168404Spjd}
146168404Spjd
147168404Spjd/*
148168404Spjd * Create the '.zfs' directory.  This directory is cached as part of the VFS
149168404Spjd * structure.  This results in a hold on the vfs_t.  The code in zfs_umount()
150168404Spjd * therefore checks against a vfs_count of 2 instead of 1.  This reference
151168404Spjd * is removed when the ctldir is destroyed in the unmount.
152168404Spjd */
153168404Spjdvoid
154168404Spjdzfsctl_create(zfsvfs_t *zfsvfs)
155168404Spjd{
156168404Spjd	vnode_t *vp, *rvp;
157168404Spjd	zfsctl_node_t *zcp;
158168404Spjd
159168404Spjd	ASSERT(zfsvfs->z_ctldir == NULL);
160168404Spjd
161168404Spjd	vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs,
162168404Spjd	    &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries,
163168404Spjd	    zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL);
164168404Spjd	zcp = vp->v_data;
165168404Spjd	zcp->zc_id = ZFSCTL_INO_ROOT;
166168404Spjd
167168404Spjd	VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp, curthread) == 0);
168168404Spjd	ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime);
169168404Spjd	VN_URELE(rvp);
170168404Spjd
171168404Spjd	/*
172168404Spjd	 * We're only faking the fact that we have a root of a filesystem for
173168404Spjd	 * the sake of the GFS interfaces.  Undo the flag manipulation it did
174168404Spjd	 * for us.
175168404Spjd	 */
176168404Spjd	vp->v_vflag &= ~VV_ROOT;
177168404Spjd
178168404Spjd	zfsvfs->z_ctldir = vp;
179168404Spjd}
180168404Spjd
181168404Spjd/*
182168404Spjd * Destroy the '.zfs' directory.  Only called when the filesystem is unmounted.
183168404Spjd * There might still be more references if we were force unmounted, but only
184168404Spjd * new zfs_inactive() calls can occur and they don't reference .zfs
185168404Spjd */
186168404Spjdvoid
187168404Spjdzfsctl_destroy(zfsvfs_t *zfsvfs)
188168404Spjd{
189168404Spjd	VN_RELE(zfsvfs->z_ctldir);
190168404Spjd	zfsvfs->z_ctldir = NULL;
191168404Spjd}
192168404Spjd
193168404Spjd/*
194168404Spjd * Given a root znode, retrieve the associated .zfs directory.
195168404Spjd * Add a hold to the vnode and return it.
196168404Spjd */
197168404Spjdvnode_t *
198168404Spjdzfsctl_root(znode_t *zp)
199168404Spjd{
200168404Spjd	ASSERT(zfs_has_ctldir(zp));
201168404Spjd	VN_HOLD(zp->z_zfsvfs->z_ctldir);
202168404Spjd	return (zp->z_zfsvfs->z_ctldir);
203168404Spjd}
204168404Spjd
205168404Spjd/*
206168404Spjd * Common open routine.  Disallow any write access.
207168404Spjd */
208168404Spjd/* ARGSUSED */
209168404Spjdstatic int
210168404Spjdzfsctl_common_open(struct vop_open_args *ap)
211168404Spjd{
212168404Spjd	int flags = ap->a_mode;
213168404Spjd
214168404Spjd	if (flags & FWRITE)
215168404Spjd		return (EACCES);
216168404Spjd
217168404Spjd	return (0);
218168404Spjd}
219168404Spjd
220168404Spjd/*
221168404Spjd * Common close routine.  Nothing to do here.
222168404Spjd */
223168404Spjd/* ARGSUSED */
224168404Spjdstatic int
225168404Spjdzfsctl_common_close(struct vop_close_args *ap)
226168404Spjd{
227168404Spjd	return (0);
228168404Spjd}
229168404Spjd
230168404Spjd/*
231168404Spjd * Common access routine.  Disallow writes.
232168404Spjd */
233168404Spjd/* ARGSUSED */
234168404Spjdstatic int
235168404Spjdzfsctl_common_access(ap)
236168404Spjd	struct vop_access_args /* {
237168404Spjd		struct vnode *a_vp;
238168404Spjd		int  a_mode;
239168404Spjd		struct ucred *a_cred;
240168404Spjd		struct thread *a_td;
241168404Spjd	} */ *ap;
242168404Spjd{
243168404Spjd	int mode = ap->a_mode;
244168404Spjd
245168404Spjd	if (mode & VWRITE)
246168404Spjd		return (EACCES);
247168404Spjd
248168404Spjd	return (0);
249168404Spjd}
250168404Spjd
251168404Spjd/*
252168404Spjd * Common getattr function.  Fill in basic information.
253168404Spjd */
254168404Spjdstatic void
255168404Spjdzfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
256168404Spjd{
257168404Spjd	zfsctl_node_t	*zcp = vp->v_data;
258168404Spjd	timestruc_t	now;
259168404Spjd
260168404Spjd	vap->va_uid = 0;
261168404Spjd	vap->va_gid = 0;
262168404Spjd	vap->va_rdev = 0;
263168404Spjd	/*
264168404Spjd	 * We are a purly virtual object, so we have no
265168404Spjd	 * blocksize or allocated blocks.
266168404Spjd	 */
267168404Spjd	vap->va_blksize = 0;
268168404Spjd	vap->va_nblocks = 0;
269168404Spjd	vap->va_seq = 0;
270168404Spjd	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
271168404Spjd	vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP |
272168404Spjd	    S_IROTH | S_IXOTH;
273168404Spjd	vap->va_type = VDIR;
274168404Spjd	/*
275168404Spjd	 * We live in the now (for atime).
276168404Spjd	 */
277168404Spjd	gethrestime(&now);
278168404Spjd	vap->va_atime = now;
279168404Spjd	vap->va_mtime = vap->va_ctime = vap->va_birthtime = zcp->zc_cmtime;
280168404Spjd	/* FreeBSD: Reset chflags(2) flags. */
281168404Spjd	vap->va_flags = 0;
282168404Spjd}
283168404Spjd
284168404Spjdstatic int
285168404Spjdzfsctl_common_fid(ap)
286168404Spjd	struct vop_fid_args /* {
287168404Spjd		struct vnode *a_vp;
288168404Spjd		struct fid *a_fid;
289168404Spjd	} */ *ap;
290168404Spjd{
291168404Spjd	vnode_t		*vp = ap->a_vp;
292168404Spjd	fid_t		*fidp = (void *)ap->a_fid;
293168404Spjd	zfsvfs_t	*zfsvfs = vp->v_vfsp->vfs_data;
294168404Spjd	zfsctl_node_t	*zcp = vp->v_data;
295168404Spjd	uint64_t	object = zcp->zc_id;
296168404Spjd	zfid_short_t	*zfid;
297168404Spjd	int		i;
298168404Spjd
299168404Spjd	ZFS_ENTER(zfsvfs);
300168404Spjd
301168404Spjd	fidp->fid_len = SHORT_FID_LEN;
302168404Spjd
303168404Spjd	zfid = (zfid_short_t *)fidp;
304168404Spjd
305168404Spjd	zfid->zf_len = SHORT_FID_LEN;
306168404Spjd
307168404Spjd	for (i = 0; i < sizeof (zfid->zf_object); i++)
308168404Spjd		zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
309168404Spjd
310168404Spjd	/* .zfs znodes always have a generation number of 0 */
311168404Spjd	for (i = 0; i < sizeof (zfid->zf_gen); i++)
312168404Spjd		zfid->zf_gen[i] = 0;
313168404Spjd
314168404Spjd	ZFS_EXIT(zfsvfs);
315168404Spjd	return (0);
316168404Spjd}
317168404Spjd
318168404Spjdstatic int
319168404Spjdzfsctl_common_reclaim(ap)
320168404Spjd	struct vop_reclaim_args /* {
321168404Spjd		struct vnode *a_vp;
322168404Spjd		struct thread *a_td;
323168404Spjd	} */ *ap;
324168404Spjd{
325168404Spjd	vnode_t *vp = ap->a_vp;
326168404Spjd
327168404Spjd	/*
328168404Spjd	 * Destroy the vm object and flush associated pages.
329168404Spjd	 */
330168404Spjd	vnode_destroy_vobject(vp);
331168404Spjd	VI_LOCK(vp);
332168404Spjd	vp->v_data = NULL;
333168404Spjd	VI_UNLOCK(vp);
334168404Spjd	return (0);
335168404Spjd}
336168404Spjd
337168404Spjd/*
338168404Spjd * .zfs inode namespace
339168404Spjd *
340168404Spjd * We need to generate unique inode numbers for all files and directories
341168404Spjd * within the .zfs pseudo-filesystem.  We use the following scheme:
342168404Spjd *
343168404Spjd * 	ENTRY			ZFSCTL_INODE
344168404Spjd * 	.zfs			1
345168404Spjd * 	.zfs/snapshot		2
346168404Spjd * 	.zfs/snapshot/<snap>	objectid(snap)
347168404Spjd */
348168404Spjd
349168404Spjd#define	ZFSCTL_INO_SNAP(id)	(id)
350168404Spjd
351168404Spjd/*
352168404Spjd * Get root directory attributes.
353168404Spjd */
354168404Spjd/* ARGSUSED */
355168404Spjdstatic int
356168404Spjdzfsctl_root_getattr(ap)
357168404Spjd	struct vop_getattr_args /* {
358168404Spjd		struct vnode *a_vp;
359168404Spjd		struct vattr *a_vap;
360168404Spjd		struct ucred *a_cred;
361168404Spjd		struct thread *a_td;
362168404Spjd	} */ *ap;
363168404Spjd{
364168404Spjd	struct vnode *vp = ap->a_vp;
365168404Spjd	struct vattr *vap = ap->a_vap;
366168404Spjd	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
367168404Spjd
368168404Spjd	ZFS_ENTER(zfsvfs);
369168404Spjd	vap->va_nodeid = ZFSCTL_INO_ROOT;
370168404Spjd	vap->va_nlink = vap->va_size = NROOT_ENTRIES;
371168404Spjd
372168404Spjd	zfsctl_common_getattr(vp, vap);
373168404Spjd	ZFS_EXIT(zfsvfs);
374168404Spjd
375168404Spjd	return (0);
376168404Spjd}
377168404Spjd
378168404Spjd/*
379168404Spjd * Special case the handling of "..".
380168404Spjd */
381168404Spjd/* ARGSUSED */
382168404Spjdint
383168404Spjdzfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
384168404Spjd    int flags, vnode_t *rdir, cred_t *cr)
385168404Spjd{
386168404Spjd	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
387168404Spjd	int err;
388168404Spjd
389168404Spjd	ZFS_ENTER(zfsvfs);
390168404Spjd
391168404Spjd	if (strcmp(nm, "..") == 0) {
392168404Spjd		err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp, curthread);
393168404Spjd		if (err == 0)
394168404Spjd			VOP_UNLOCK(*vpp, 0, curthread);
395168404Spjd	} else {
396168404Spjd		err = gfs_dir_lookup(dvp, nm, vpp);
397168404Spjd	}
398168404Spjd
399168404Spjd	ZFS_EXIT(zfsvfs);
400168404Spjd
401168404Spjd	return (err);
402168404Spjd}
403168404Spjd
404168404Spjd/*
405168404Spjd * Special case the handling of "..".
406168404Spjd */
407168404Spjd/* ARGSUSED */
408168404Spjdint
409168404Spjdzfsctl_root_lookup_vop(ap)
410168404Spjd	struct vop_lookup_args /* {
411168404Spjd		struct vnode *a_dvp;
412168404Spjd		struct vnode **a_vpp;
413168404Spjd		struct componentname *a_cnp;
414168404Spjd	} */ *ap;
415168404Spjd{
416168404Spjd	vnode_t *dvp = ap->a_dvp;
417168404Spjd	vnode_t **vpp = ap->a_vpp;
418168404Spjd	cred_t *cr = ap->a_cnp->cn_cred;
419168404Spjd	int flags = ap->a_cnp->cn_flags;
420168404Spjd	int nameiop = ap->a_cnp->cn_nameiop;
421168404Spjd	char nm[NAME_MAX + 1];
422168404Spjd	int err;
423168404Spjd
424168404Spjd	if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE))
425168404Spjd		return (EOPNOTSUPP);
426168404Spjd
427168404Spjd	ASSERT(ap->a_cnp->cn_namelen < sizeof(nm));
428168404Spjd	strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1);
429168404Spjd
430168404Spjd	err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr);
431168404Spjd	if (err == 0 && (nm[0] != '.' || nm[1] != '\0'))
432168404Spjd		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, ap->a_cnp->cn_thread);
433168404Spjd
434168404Spjd	return (err);
435168404Spjd}
436168404Spjd
437168404Spjdstatic struct vop_vector zfsctl_ops_root = {
438168404Spjd	.vop_default =	&default_vnodeops,
439168404Spjd	.vop_open =	zfsctl_common_open,
440168404Spjd	.vop_close =	zfsctl_common_close,
441168404Spjd	.vop_ioctl =	VOP_EINVAL,
442168404Spjd	.vop_getattr =	zfsctl_root_getattr,
443168404Spjd	.vop_access =	zfsctl_common_access,
444168404Spjd	.vop_readdir =	gfs_vop_readdir,
445168404Spjd	.vop_lookup =	zfsctl_root_lookup_vop,
446168404Spjd	.vop_inactive =	gfs_vop_inactive,
447168404Spjd	.vop_reclaim =	zfsctl_common_reclaim,
448168404Spjd	.vop_fid =	zfsctl_common_fid,
449168404Spjd};
450168404Spjd
451168404Spjdstatic int
452168404Spjdzfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname)
453168404Spjd{
454168404Spjd	objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os;
455168404Spjd
456168404Spjd	dmu_objset_name(os, zname);
457168404Spjd	if (strlen(zname) + 1 + strlen(name) >= len)
458168404Spjd		return (ENAMETOOLONG);
459168404Spjd	(void) strcat(zname, "@");
460168404Spjd	(void) strcat(zname, name);
461168404Spjd	return (0);
462168404Spjd}
463168404Spjd
464168404Spjdstatic int
465168404Spjdzfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr)
466168404Spjd{
467168404Spjd	zfsctl_snapdir_t *sdp = dvp->v_data;
468168404Spjd	zfs_snapentry_t search, *sep;
469168404Spjd	struct vop_inactive_args ap;
470168404Spjd	avl_index_t where;
471168404Spjd	int err;
472168404Spjd
473168404Spjd	ASSERT(MUTEX_HELD(&sdp->sd_lock));
474168404Spjd
475168404Spjd	search.se_name = (char *)name;
476168404Spjd	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL)
477168404Spjd		return (ENOENT);
478168404Spjd
479168404Spjd	ASSERT(vn_ismntpt(sep->se_root));
480168404Spjd
481168404Spjd	/* this will be dropped by dounmount() */
482168404Spjd	if ((err = vn_vfswlock(sep->se_root)) != 0)
483168404Spjd		return (err);
484168404Spjd
485168404Spjd	err = dounmount(vn_mountedvfs(sep->se_root), force, curthread);
486168404Spjd	if (err)
487168404Spjd		return (err);
488168404Spjd	ASSERT(sep->se_root->v_count == 1);
489168404Spjd	ap.a_vp = sep->se_root;
490168404Spjd	gfs_vop_inactive(&ap);
491168404Spjd
492168404Spjd	avl_remove(&sdp->sd_snaps, sep);
493168404Spjd	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
494168404Spjd	kmem_free(sep, sizeof (zfs_snapentry_t));
495168404Spjd
496168404Spjd	return (0);
497168404Spjd}
498168404Spjd
499168404Spjd#if 0
500168404Spjdstatic void
501168404Spjdzfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
502168404Spjd{
503168404Spjd	avl_index_t where;
504168404Spjd	vfs_t *vfsp;
505168404Spjd	refstr_t *pathref;
506168404Spjd	char newpath[MAXNAMELEN];
507168404Spjd	char *tail;
508168404Spjd
509168404Spjd	ASSERT(MUTEX_HELD(&sdp->sd_lock));
510168404Spjd	ASSERT(sep != NULL);
511168404Spjd
512168404Spjd	vfsp = vn_mountedvfs(sep->se_root);
513168404Spjd	ASSERT(vfsp != NULL);
514168404Spjd
515168404Spjd	vfs_lock_wait(vfsp);
516168404Spjd
517168404Spjd	/*
518168404Spjd	 * Change the name in the AVL tree.
519168404Spjd	 */
520168404Spjd	avl_remove(&sdp->sd_snaps, sep);
521168404Spjd	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
522168404Spjd	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
523168404Spjd	(void) strcpy(sep->se_name, nm);
524168404Spjd	VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL);
525168404Spjd	avl_insert(&sdp->sd_snaps, sep, where);
526168404Spjd
527168404Spjd	/*
528168404Spjd	 * Change the current mountpoint info:
529168404Spjd	 * 	- update the tail of the mntpoint path
530168404Spjd	 *	- update the tail of the resource path
531168404Spjd	 */
532168404Spjd	pathref = vfs_getmntpoint(vfsp);
533168404Spjd	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
534168404Spjd	VERIFY((tail = strrchr(newpath, '/')) != NULL);
535168404Spjd	*(tail+1) = '\0';
536168404Spjd	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
537168404Spjd	(void) strcat(newpath, nm);
538168404Spjd	refstr_rele(pathref);
539168404Spjd	vfs_setmntpoint(vfsp, newpath);
540168404Spjd
541168404Spjd	pathref = vfs_getresource(vfsp);
542168404Spjd	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
543168404Spjd	VERIFY((tail = strrchr(newpath, '@')) != NULL);
544168404Spjd	*(tail+1) = '\0';
545168404Spjd	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
546168404Spjd	(void) strcat(newpath, nm);
547168404Spjd	refstr_rele(pathref);
548168404Spjd	vfs_setresource(vfsp, newpath);
549168404Spjd
550168404Spjd	vfs_unlock(vfsp);
551168404Spjd}
552168404Spjd#endif
553168404Spjd
554168404Spjd#if 0
555168404Spjdstatic int
556168404Spjdzfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
557168404Spjd    cred_t *cr)
558168404Spjd{
559168404Spjd	zfsctl_snapdir_t *sdp = sdvp->v_data;
560168404Spjd	zfs_snapentry_t search, *sep;
561168404Spjd	avl_index_t where;
562168404Spjd	char from[MAXNAMELEN], to[MAXNAMELEN];
563168404Spjd	int err;
564168404Spjd
565168404Spjd	err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from);
566168404Spjd	if (err)
567168404Spjd		return (err);
568168404Spjd	err = zfs_secpolicy_write(from, cr);
569168404Spjd	if (err)
570168404Spjd		return (err);
571168404Spjd
572168404Spjd	/*
573168404Spjd	 * Cannot move snapshots out of the snapdir.
574168404Spjd	 */
575168404Spjd	if (sdvp != tdvp)
576168404Spjd		return (EINVAL);
577168404Spjd
578168404Spjd	if (strcmp(snm, tnm) == 0)
579168404Spjd		return (0);
580168404Spjd
581168404Spjd	err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to);
582168404Spjd	if (err)
583168404Spjd		return (err);
584168404Spjd
585168404Spjd	mutex_enter(&sdp->sd_lock);
586168404Spjd
587168404Spjd	search.se_name = (char *)snm;
588168404Spjd	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) {
589168404Spjd		mutex_exit(&sdp->sd_lock);
590168404Spjd		return (ENOENT);
591168404Spjd	}
592168404Spjd
593168676Spjd	err = dmu_objset_rename(from, to, B_FALSE);
594168404Spjd	if (err == 0)
595168404Spjd		zfsctl_rename_snap(sdp, sep, tnm);
596168404Spjd
597168404Spjd	mutex_exit(&sdp->sd_lock);
598168404Spjd
599168404Spjd	return (err);
600168404Spjd}
601168404Spjd#endif
602168404Spjd
603168404Spjd#if 0
604168404Spjd/* ARGSUSED */
605168404Spjdstatic int
606168404Spjdzfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
607168404Spjd{
608169170Spjd	zfsctl_snapdir_t *sdp = dvp->v_data;
609169170Spjd	char snapname[MAXNAMELEN];
610169170Spjd	int err;
611168404Spjd
612169170Spjd	err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname);
613169170Spjd	if (err)
614169170Spjd		return (err);
615169170Spjd	err = zfs_secpolicy_write(snapname, cr);
616169170Spjd	if (err)
617169170Spjd		return (err);
618168404Spjd
619169170Spjd	mutex_enter(&sdp->sd_lock);
620168404Spjd
621169170Spjd	err = zfsctl_unmount_snap(dvp, name, 0, cr);
622169170Spjd	if (err) {
623169170Spjd		mutex_exit(&sdp->sd_lock);
624169170Spjd		return (err);
625169170Spjd	}
626168404Spjd
627169170Spjd	err = dmu_objset_destroy(snapname);
628168404Spjd
629169170Spjd	mutex_exit(&sdp->sd_lock);
630168404Spjd
631169170Spjd	return (err);
632168404Spjd}
633168404Spjd#endif
634168404Spjd
635168404Spjd/*
636168404Spjd * Lookup entry point for the 'snapshot' directory.  Try to open the
637168404Spjd * snapshot if it exist, creating the pseudo filesystem vnode as necessary.
638168404Spjd * Perform a mount of the associated dataset on top of the vnode.
639168404Spjd */
640168404Spjd/* ARGSUSED */
641168404Spjdint
642168404Spjdzfsctl_snapdir_lookup(ap)
643168404Spjd	struct vop_lookup_args /* {
644168404Spjd		struct vnode *a_dvp;
645168404Spjd		struct vnode **a_vpp;
646168404Spjd		struct componentname *a_cnp;
647168404Spjd	} */ *ap;
648168404Spjd{
649168404Spjd	vnode_t *dvp = ap->a_dvp;
650168404Spjd	vnode_t **vpp = ap->a_vpp;
651168404Spjd	char nm[NAME_MAX + 1];
652168404Spjd	zfsctl_snapdir_t *sdp = dvp->v_data;
653168404Spjd	objset_t *snap;
654168404Spjd	char snapname[MAXNAMELEN];
655168404Spjd	char *mountpoint;
656168404Spjd	zfs_snapentry_t *sep, search;
657168404Spjd	size_t mountpoint_len;
658168404Spjd	avl_index_t where;
659168404Spjd	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
660168404Spjd	int err;
661168404Spjd
662168404Spjd	ASSERT(ap->a_cnp->cn_namelen < sizeof(nm));
663168404Spjd	strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1);
664168404Spjd
665168404Spjd	ASSERT(dvp->v_type == VDIR);
666168404Spjd
667168404Spjd	if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0)
668168404Spjd		return (0);
669168404Spjd
670168404Spjd	*vpp = NULL;
671168404Spjd
672168404Spjd	/*
673168404Spjd	 * If we get a recursive call, that means we got called
674168404Spjd	 * from the domount() code while it was trying to look up the
675168404Spjd	 * spec (which looks like a local path for zfs).  We need to
676168404Spjd	 * add some flag to domount() to tell it not to do this lookup.
677168404Spjd	 */
678168404Spjd	if (MUTEX_HELD(&sdp->sd_lock))
679168404Spjd		return (ENOENT);
680168404Spjd
681168404Spjd	ZFS_ENTER(zfsvfs);
682168404Spjd
683168404Spjd	mutex_enter(&sdp->sd_lock);
684168404Spjd	search.se_name = (char *)nm;
685168404Spjd	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) {
686168404Spjd		*vpp = sep->se_root;
687168404Spjd		VN_HOLD(*vpp);
688168404Spjd		if ((*vpp)->v_mountedhere == NULL) {
689168404Spjd			/*
690168404Spjd			 * The snapshot was unmounted behind our backs,
691168404Spjd			 * try to remount it.
692168404Spjd			 */
693168404Spjd			goto domount;
694168404Spjd		}
695168404Spjd		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, ap->a_cnp->cn_thread);
696168404Spjd		mutex_exit(&sdp->sd_lock);
697168404Spjd		ZFS_EXIT(zfsvfs);
698168404Spjd		return (0);
699168404Spjd	}
700168404Spjd
701168404Spjd	/*
702168404Spjd	 * The requested snapshot is not currently mounted, look it up.
703168404Spjd	 */
704168404Spjd	err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname);
705168404Spjd	if (err) {
706168404Spjd		mutex_exit(&sdp->sd_lock);
707168404Spjd		ZFS_EXIT(zfsvfs);
708168404Spjd		return (err);
709168404Spjd	}
710168404Spjd	if (dmu_objset_open(snapname, DMU_OST_ZFS,
711168404Spjd	    DS_MODE_STANDARD | DS_MODE_READONLY, &snap) != 0) {
712168404Spjd		mutex_exit(&sdp->sd_lock);
713168404Spjd		ZFS_EXIT(zfsvfs);
714168404Spjd		return (ENOENT);
715168404Spjd	}
716168404Spjd
717168404Spjd	sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP);
718168404Spjd	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
719168404Spjd	(void) strcpy(sep->se_name, nm);
720168404Spjd	*vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap));
721168404Spjd	VN_HOLD(*vpp);
722168404Spjd	avl_insert(&sdp->sd_snaps, sep, where);
723168404Spjd
724168404Spjd	dmu_objset_close(snap);
725168404Spjddomount:
726168404Spjd	mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) +
727168404Spjd	    strlen("/.zfs/snapshot/") + strlen(nm) + 1;
728168404Spjd	mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP);
729168404Spjd	(void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s",
730168404Spjd	    dvp->v_vfsp->mnt_stat.f_mntonname, nm);
731168404Spjd	err = domount(curthread, *vpp, "zfs", mountpoint, snapname, 0);
732168404Spjd	kmem_free(mountpoint, mountpoint_len);
733168404Spjd	/* FreeBSD: This line was moved from below to avoid a lock recursion. */
734168404Spjd	if (err == 0)
735168404Spjd		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curthread);
736168404Spjd	mutex_exit(&sdp->sd_lock);
737168404Spjd
738168404Spjd	/*
739168404Spjd	 * If we had an error, drop our hold on the vnode and
740168404Spjd	 * zfsctl_snapshot_inactive() will clean up.
741168404Spjd	 */
742168404Spjd	if (err) {
743168404Spjd		VN_RELE(*vpp);
744168404Spjd		*vpp = NULL;
745168404Spjd	}
746168404Spjd	return (err);
747168404Spjd}
748168404Spjd
749168404Spjd/* ARGSUSED */
750168404Spjdstatic int
751168404Spjdzfsctl_snapdir_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp,
752168404Spjd    offset_t *offp, offset_t *nextp, void *data)
753168404Spjd{
754168404Spjd	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
755168404Spjd	char snapname[MAXNAMELEN];
756168404Spjd	uint64_t id, cookie;
757168404Spjd
758168404Spjd	ZFS_ENTER(zfsvfs);
759168404Spjd
760168404Spjd	cookie = *offp;
761168404Spjd	if (dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
762168404Spjd	    &cookie) == ENOENT) {
763168404Spjd		*eofp = 1;
764168404Spjd		ZFS_EXIT(zfsvfs);
765168404Spjd		return (0);
766168404Spjd	}
767168404Spjd
768168404Spjd	(void) strcpy(dp->d_name, snapname);
769168404Spjd	dp->d_ino = ZFSCTL_INO_SNAP(id);
770168404Spjd	*nextp = cookie;
771168404Spjd
772168404Spjd	ZFS_EXIT(zfsvfs);
773168404Spjd
774168404Spjd	return (0);
775168404Spjd}
776168404Spjd
777168404Spjdvnode_t *
778168404Spjdzfsctl_mknode_snapdir(vnode_t *pvp)
779168404Spjd{
780168404Spjd	vnode_t *vp;
781168404Spjd	zfsctl_snapdir_t *sdp;
782168404Spjd
783168404Spjd	vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, pvp->v_vfsp,
784168404Spjd	    &zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN,
785168404Spjd	    zfsctl_snapdir_readdir_cb, NULL);
786168404Spjd	sdp = vp->v_data;
787168404Spjd	sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR;
788168404Spjd	sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
789168404Spjd	mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL);
790168404Spjd	avl_create(&sdp->sd_snaps, snapentry_compare,
791168404Spjd	    sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node));
792168404Spjd	return (vp);
793168404Spjd}
794168404Spjd
795168404Spjd/* ARGSUSED */
796168404Spjdstatic int
797168404Spjdzfsctl_snapdir_getattr(ap)
798168404Spjd	struct vop_getattr_args /* {
799168404Spjd		struct vnode *a_vp;
800168404Spjd		struct vattr *a_vap;
801168404Spjd		struct ucred *a_cred;
802168404Spjd		struct thread *a_td;
803168404Spjd	} */ *ap;
804168404Spjd{
805168404Spjd	struct vnode *vp = ap->a_vp;
806168404Spjd	struct vattr *vap = ap->a_vap;
807168404Spjd	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
808168404Spjd	zfsctl_snapdir_t *sdp = vp->v_data;
809168404Spjd
810168404Spjd	ZFS_ENTER(zfsvfs);
811168404Spjd	zfsctl_common_getattr(vp, vap);
812168404Spjd	vap->va_nodeid = gfs_file_inode(vp);
813168404Spjd	vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2;
814168404Spjd	ZFS_EXIT(zfsvfs);
815168404Spjd
816168404Spjd	return (0);
817168404Spjd}
818168404Spjd
819168404Spjd/* ARGSUSED */
820168404Spjdstatic int
821168404Spjdzfsctl_snapdir_inactive(ap)
822168404Spjd	struct vop_inactive_args /* {
823168404Spjd		struct vnode *a_vp;
824168404Spjd		struct thread *a_td;
825168404Spjd	} */ *ap;
826168404Spjd{
827168404Spjd	vnode_t *vp = ap->a_vp;
828168404Spjd	zfsctl_snapdir_t *sdp = vp->v_data;
829168404Spjd	void *private;
830168404Spjd
831168404Spjd	private = gfs_dir_inactive(vp);
832168404Spjd	if (private != NULL) {
833168404Spjd		ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
834168404Spjd		mutex_destroy(&sdp->sd_lock);
835168404Spjd		avl_destroy(&sdp->sd_snaps);
836168404Spjd		kmem_free(private, sizeof (zfsctl_snapdir_t));
837168404Spjd	}
838168404Spjd	return (0);
839168404Spjd}
840168404Spjd
841168404Spjdstatic struct vop_vector zfsctl_ops_snapdir = {
842168404Spjd	.vop_default =	&default_vnodeops,
843168404Spjd	.vop_open =	zfsctl_common_open,
844168404Spjd	.vop_close =	zfsctl_common_close,
845168404Spjd	.vop_ioctl =	VOP_EINVAL,
846168404Spjd	.vop_getattr =	zfsctl_snapdir_getattr,
847168404Spjd	.vop_access =	zfsctl_common_access,
848168404Spjd	.vop_readdir =	gfs_vop_readdir,
849168404Spjd	.vop_lookup =	zfsctl_snapdir_lookup,
850168404Spjd	.vop_inactive =	zfsctl_snapdir_inactive,
851168404Spjd	.vop_reclaim =	zfsctl_common_reclaim,
852168404Spjd	.vop_fid =	zfsctl_common_fid,
853168404Spjd};
854168404Spjd
855168404Spjdstatic vnode_t *
856168404Spjdzfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
857168404Spjd{
858168404Spjd	vnode_t *vp;
859168404Spjd	zfsctl_node_t *zcp;
860168404Spjd
861168404Spjd	vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp,
862168404Spjd	    &zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL);
863168404Spjd	zcp = vp->v_data;
864168404Spjd	zcp->zc_id = objset;
865168404Spjd
866168404Spjd	return (vp);
867168404Spjd}
868168404Spjd
869168404Spjdstatic int
870168404Spjdzfsctl_snapshot_inactive(ap)
871168404Spjd	struct vop_inactive_args /* {
872168404Spjd		struct vnode *a_vp;
873168404Spjd		struct thread *a_td;
874168404Spjd	} */ *ap;
875168404Spjd{
876168404Spjd	vnode_t *vp = ap->a_vp;
877168404Spjd	struct vop_inactive_args iap;
878168404Spjd	zfsctl_snapdir_t *sdp;
879168404Spjd	zfs_snapentry_t *sep, *next;
880168404Spjd	int locked;
881168404Spjd	vnode_t *dvp;
882168404Spjd
883168404Spjd	VERIFY(gfs_dir_lookup(vp, "..", &dvp) == 0);
884168404Spjd	sdp = dvp->v_data;
885168404Spjd	VOP_UNLOCK(dvp, 0, ap->a_td);
886168404Spjd
887168404Spjd	if (!(locked = MUTEX_HELD(&sdp->sd_lock)))
888168404Spjd		mutex_enter(&sdp->sd_lock);
889168404Spjd
890168404Spjd	if (vp->v_count > 1) {
891168404Spjd		if (!locked)
892168404Spjd			mutex_exit(&sdp->sd_lock);
893168404Spjd		return (0);
894168404Spjd	}
895168404Spjd	ASSERT(!vn_ismntpt(vp));
896168404Spjd
897168404Spjd	sep = avl_first(&sdp->sd_snaps);
898168404Spjd	while (sep != NULL) {
899168404Spjd		next = AVL_NEXT(&sdp->sd_snaps, sep);
900168404Spjd
901168404Spjd		if (sep->se_root == vp) {
902168404Spjd			avl_remove(&sdp->sd_snaps, sep);
903168404Spjd			kmem_free(sep->se_name, strlen(sep->se_name) + 1);
904168404Spjd			kmem_free(sep, sizeof (zfs_snapentry_t));
905168404Spjd			break;
906168404Spjd		}
907168404Spjd		sep = next;
908168404Spjd	}
909168404Spjd	ASSERT(sep != NULL);
910168404Spjd
911168404Spjd	if (!locked)
912168404Spjd		mutex_exit(&sdp->sd_lock);
913168404Spjd	VN_RELE(dvp);
914168404Spjd
915168404Spjd	/*
916168404Spjd	 * Dispose of the vnode for the snapshot mount point.
917168404Spjd	 * This is safe to do because once this entry has been removed
918168404Spjd	 * from the AVL tree, it can't be found again, so cannot become
919168404Spjd	 * "active".  If we lookup the same name again we will end up
920168404Spjd	 * creating a new vnode.
921168404Spjd	 */
922168404Spjd	iap.a_vp = vp;
923168404Spjd	return (gfs_vop_inactive(&iap));
924168404Spjd}
925168404Spjd
926168404Spjdstatic int
927170281Spjdzfsctl_traverse_begin(vnode_t **vpp, int lktype, kthread_t *td)
928168404Spjd{
929168404Spjd
930168404Spjd	VN_HOLD(*vpp);
931168404Spjd	/* Snapshot should be already mounted, but just in case. */
932168404Spjd	if (vn_mountedvfs(*vpp) == NULL)
933168404Spjd		return (ENOENT);
934170281Spjd	return (traverse(vpp, lktype));
935168404Spjd}
936168404Spjd
937168404Spjdstatic void
938168404Spjdzfsctl_traverse_end(vnode_t *vp, int err)
939168404Spjd{
940168404Spjd
941168404Spjd	if (err == 0)
942168404Spjd		vput(vp);
943168404Spjd	else
944168404Spjd		VN_RELE(vp);
945168404Spjd}
946168404Spjd
947168404Spjdstatic int
948168404Spjdzfsctl_snapshot_getattr(ap)
949168404Spjd	struct vop_getattr_args /* {
950168404Spjd		struct vnode *a_vp;
951168404Spjd		struct vattr *a_vap;
952168404Spjd		struct ucred *a_cred;
953168404Spjd		struct thread *a_td;
954168404Spjd	} */ *ap;
955168404Spjd{
956168404Spjd	vnode_t *vp = ap->a_vp;
957168404Spjd	int err;
958168404Spjd
959170281Spjd	err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY, ap->a_td);
960168404Spjd	if (err == 0)
961168404Spjd		err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_td);
962168404Spjd	zfsctl_traverse_end(vp, err);
963168404Spjd	return (err);
964168404Spjd}
965168404Spjd
966168404Spjdstatic int
967168404Spjdzfsctl_snapshot_fid(ap)
968168404Spjd	struct vop_fid_args /* {
969168404Spjd		struct vnode *a_vp;
970168404Spjd		struct fid *a_fid;
971168404Spjd	} */ *ap;
972168404Spjd{
973168404Spjd	vnode_t *vp = ap->a_vp;
974168404Spjd	int err;
975168404Spjd
976170281Spjd	err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY, curthread);
977168404Spjd	if (err == 0)
978168404Spjd		err = VOP_VPTOFH(vp, (void *)ap->a_fid);
979168404Spjd	zfsctl_traverse_end(vp, err);
980168404Spjd	return (err);
981168404Spjd}
982168404Spjd
983168404Spjd/*
984168404Spjd * These VP's should never see the light of day.  They should always
985168404Spjd * be covered.
986168404Spjd */
987168404Spjdstatic struct vop_vector zfsctl_ops_snapshot = {
988168404Spjd	.vop_default =	&default_vnodeops,
989168404Spjd	.vop_inactive =	zfsctl_snapshot_inactive,
990168404Spjd	.vop_reclaim =	zfsctl_common_reclaim,
991168404Spjd	.vop_getattr =	zfsctl_snapshot_getattr,
992168404Spjd	.vop_fid =	zfsctl_snapshot_fid,
993168404Spjd};
994168404Spjd
995168404Spjdint
996168404Spjdzfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
997168404Spjd{
998168404Spjd	zfsvfs_t *zfsvfs = vfsp->vfs_data;
999168404Spjd	vnode_t *dvp, *vp;
1000168404Spjd	zfsctl_snapdir_t *sdp;
1001168404Spjd	zfsctl_node_t *zcp;
1002168404Spjd	zfs_snapentry_t *sep;
1003168404Spjd	int error;
1004168404Spjd
1005168404Spjd	ASSERT(zfsvfs->z_ctldir != NULL);
1006168404Spjd	error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
1007168404Spjd	    NULL, 0, NULL, kcred);
1008168404Spjd	if (error != 0)
1009168404Spjd		return (error);
1010168404Spjd	sdp = dvp->v_data;
1011168404Spjd
1012168404Spjd	mutex_enter(&sdp->sd_lock);
1013168404Spjd	sep = avl_first(&sdp->sd_snaps);
1014168404Spjd	while (sep != NULL) {
1015168404Spjd		vp = sep->se_root;
1016168404Spjd		zcp = vp->v_data;
1017168404Spjd		if (zcp->zc_id == objsetid)
1018168404Spjd			break;
1019168404Spjd
1020168404Spjd		sep = AVL_NEXT(&sdp->sd_snaps, sep);
1021168404Spjd	}
1022168404Spjd
1023168404Spjd	if (sep != NULL) {
1024168404Spjd		VN_HOLD(vp);
1025170281Spjd		error = traverse(&vp, LK_SHARED | LK_RETRY);
1026168404Spjd		if (error == 0) {
1027168404Spjd			if (vp == sep->se_root)
1028168404Spjd				error = EINVAL;
1029168404Spjd			else
1030168404Spjd				*zfsvfsp = VTOZ(vp)->z_zfsvfs;
1031168404Spjd		}
1032168404Spjd		mutex_exit(&sdp->sd_lock);
1033170281Spjd		if (error == 0)
1034170281Spjd			VN_URELE(vp);
1035170281Spjd		else
1036170281Spjd			VN_RELE(vp);
1037168404Spjd	} else {
1038168404Spjd		error = EINVAL;
1039168404Spjd		mutex_exit(&sdp->sd_lock);
1040168404Spjd	}
1041168404Spjd
1042168404Spjd	VN_RELE(dvp);
1043168404Spjd
1044168404Spjd	return (error);
1045168404Spjd}
1046168404Spjd
1047168404Spjd/*
1048168404Spjd * Unmount any snapshots for the given filesystem.  This is called from
1049168404Spjd * zfs_umount() - if we have a ctldir, then go through and unmount all the
1050168404Spjd * snapshots.
1051168404Spjd */
1052168404Spjdint
1053168404Spjdzfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
1054168404Spjd{
1055168404Spjd	struct vop_inactive_args ap;
1056168404Spjd	zfsvfs_t *zfsvfs = vfsp->vfs_data;
1057168404Spjd	vnode_t *dvp, *svp;
1058168404Spjd	zfsctl_snapdir_t *sdp;
1059168404Spjd	zfs_snapentry_t *sep, *next;
1060168404Spjd	int error;
1061168404Spjd
1062168404Spjd	ASSERT(zfsvfs->z_ctldir != NULL);
1063168404Spjd	error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
1064168404Spjd	    NULL, 0, NULL, cr);
1065168404Spjd	if (error != 0)
1066168404Spjd		return (error);
1067168404Spjd	sdp = dvp->v_data;
1068168404Spjd
1069168404Spjd	mutex_enter(&sdp->sd_lock);
1070168404Spjd
1071168404Spjd	sep = avl_first(&sdp->sd_snaps);
1072168404Spjd	while (sep != NULL) {
1073168404Spjd		svp = sep->se_root;
1074168404Spjd		next = AVL_NEXT(&sdp->sd_snaps, sep);
1075168404Spjd
1076168404Spjd		/*
1077168404Spjd		 * If this snapshot is not mounted, then it must
1078168404Spjd		 * have just been unmounted by somebody else, and
1079168404Spjd		 * will be cleaned up by zfsctl_snapdir_inactive().
1080168404Spjd		 */
1081168404Spjd		if (vn_ismntpt(svp)) {
1082168404Spjd			if ((error = vn_vfswlock(svp)) != 0)
1083168404Spjd				goto out;
1084168404Spjd
1085168404Spjd			/*
1086168404Spjd			 * Increase usecount, so dounmount() won't vrele() it
1087168404Spjd			 * to 0 and call zfsctl_snapdir_inactive().
1088168404Spjd			 */
1089168404Spjd			VN_HOLD(svp);
1090168404Spjd			vfsp = vn_mountedvfs(svp);
1091168404Spjd			mtx_lock(&Giant);
1092168404Spjd			error = dounmount(vfsp, fflags, curthread);
1093168404Spjd			mtx_unlock(&Giant);
1094168404Spjd			if (error != 0) {
1095168404Spjd				VN_RELE(svp);
1096168404Spjd				goto out;
1097168404Spjd			}
1098168404Spjd
1099168404Spjd			avl_remove(&sdp->sd_snaps, sep);
1100168404Spjd			kmem_free(sep->se_name, strlen(sep->se_name) + 1);
1101168404Spjd			kmem_free(sep, sizeof (zfs_snapentry_t));
1102168404Spjd
1103168404Spjd			/*
1104168404Spjd			 * We can't use VN_RELE(), as that will try to
1105168404Spjd			 * invoke zfsctl_snapdir_inactive(), and that
1106168404Spjd			 * would lead to an attempt to re-grab the sd_lock.
1107168404Spjd			 */
1108168404Spjd			ASSERT3U(svp->v_count, ==, 1);
1109168404Spjd			ap.a_vp = svp;
1110168404Spjd			gfs_vop_inactive(&ap);
1111168404Spjd		}
1112168404Spjd		sep = next;
1113168404Spjd	}
1114168404Spjdout:
1115168404Spjd	mutex_exit(&sdp->sd_lock);
1116168404Spjd	VN_RELE(dvp);
1117168404Spjd
1118168404Spjd	return (error);
1119168404Spjd}
1120