xref: /onnv-gate/usr/src/uts/common/fs/zfs/zfs_ctldir.c (revision 4543:12bb2876a62e)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
51512Sek110237  * Common Development and Distribution License (the "License").
61512Sek110237  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
21789Sahrens /*
223898Srsb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27789Sahrens 
28789Sahrens /*
29789Sahrens  * ZFS control directory (a.k.a. ".zfs")
30789Sahrens  *
31789Sahrens  * This directory provides a common location for all ZFS meta-objects.
32789Sahrens  * Currently, this is only the 'snapshot' directory, but this may expand in the
33789Sahrens  * future.  The elements are built using the GFS primitives, as the hierarchy
34789Sahrens  * does not actually exist on disk.
35789Sahrens  *
36789Sahrens  * For 'snapshot', we don't want to have all snapshots always mounted, because
37789Sahrens  * this would take up a huge amount of space in /etc/mnttab.  We have three
38789Sahrens  * types of objects:
39789Sahrens  *
40789Sahrens  * 	ctldir ------> snapshotdir -------> snapshot
41789Sahrens  *                                             |
42789Sahrens  *                                             |
43789Sahrens  *                                             V
44789Sahrens  *                                         mounted fs
45789Sahrens  *
46789Sahrens  * The 'snapshot' node contains just enough information to lookup '..' and act
47789Sahrens  * as a mountpoint for the snapshot.  Whenever we lookup a specific snapshot, we
48789Sahrens  * perform an automount of the underlying filesystem and return the
49789Sahrens  * corresponding vnode.
50789Sahrens  *
51789Sahrens  * All mounts are handled automatically by the kernel, but unmounts are
52789Sahrens  * (currently) handled from user land.  The main reason is that there is no
53789Sahrens  * reliable way to auto-unmount the filesystem when it's "no longer in use".
54789Sahrens  * When the user unmounts a filesystem, we call zfsctl_unmount(), which
55789Sahrens  * unmounts any snapshots within the snapshot directory.
56789Sahrens  */
57789Sahrens 
58789Sahrens #include <fs/fs_subr.h>
59789Sahrens #include <sys/zfs_ctldir.h>
60789Sahrens #include <sys/zfs_ioctl.h>
61789Sahrens #include <sys/zfs_vfsops.h>
623898Srsb #include <sys/vfs_opreg.h>
63789Sahrens #include <sys/gfs.h>
64789Sahrens #include <sys/stat.h>
65789Sahrens #include <sys/dmu.h>
66*4543Smarks #include <sys/dsl_deleg.h>
67789Sahrens #include <sys/mount.h>
68789Sahrens 
69789Sahrens typedef struct {
70789Sahrens 	char		*se_name;
71789Sahrens 	vnode_t		*se_root;
72789Sahrens 	avl_node_t	se_node;
73789Sahrens } zfs_snapentry_t;
74789Sahrens 
75789Sahrens static int
76789Sahrens snapentry_compare(const void *a, const void *b)
77789Sahrens {
78789Sahrens 	const zfs_snapentry_t *sa = a;
79789Sahrens 	const zfs_snapentry_t *sb = b;
80789Sahrens 	int ret = strcmp(sa->se_name, sb->se_name);
81789Sahrens 
82789Sahrens 	if (ret < 0)
83789Sahrens 		return (-1);
84789Sahrens 	else if (ret > 0)
85789Sahrens 		return (1);
86789Sahrens 	else
87789Sahrens 		return (0);
88789Sahrens }
89789Sahrens 
90789Sahrens vnodeops_t *zfsctl_ops_root;
91789Sahrens vnodeops_t *zfsctl_ops_snapdir;
92789Sahrens vnodeops_t *zfsctl_ops_snapshot;
93789Sahrens 
94789Sahrens static const fs_operation_def_t zfsctl_tops_root[];
95789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[];
96789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[];
97789Sahrens 
98789Sahrens static vnode_t *zfsctl_mknode_snapdir(vnode_t *);
99789Sahrens static vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset);
100789Sahrens 
101789Sahrens static gfs_opsvec_t zfsctl_opsvec[] = {
102789Sahrens 	{ ".zfs", zfsctl_tops_root, &zfsctl_ops_root },
103789Sahrens 	{ ".zfs/snapshot", zfsctl_tops_snapdir, &zfsctl_ops_snapdir },
104789Sahrens 	{ ".zfs/snapshot/vnode", zfsctl_tops_snapshot, &zfsctl_ops_snapshot },
105789Sahrens 	{ NULL }
106789Sahrens };
107789Sahrens 
108789Sahrens typedef struct zfsctl_node {
109789Sahrens 	gfs_dir_t	zc_gfs_private;
110789Sahrens 	uint64_t	zc_id;
1111571Sek110237 	timestruc_t	zc_cmtime;	/* ctime and mtime, always the same */
112789Sahrens } zfsctl_node_t;
113789Sahrens 
114789Sahrens typedef struct zfsctl_snapdir {
115789Sahrens 	zfsctl_node_t	sd_node;
116789Sahrens 	kmutex_t	sd_lock;
117789Sahrens 	avl_tree_t	sd_snaps;
118789Sahrens } zfsctl_snapdir_t;
119789Sahrens 
120789Sahrens /*
121789Sahrens  * Root directory elements.  We have only a single static entry, 'snapshot'.
122789Sahrens  */
123789Sahrens static gfs_dirent_t zfsctl_root_entries[] = {
124789Sahrens 	{ "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE },
125789Sahrens 	{ NULL }
126789Sahrens };
127789Sahrens 
128789Sahrens /* include . and .. in the calculation */
129789Sahrens #define	NROOT_ENTRIES	((sizeof (zfsctl_root_entries) / \
130789Sahrens     sizeof (gfs_dirent_t)) + 1)
131789Sahrens 
132789Sahrens 
133789Sahrens /*
134789Sahrens  * Initialize the various GFS pieces we'll need to create and manipulate .zfs
135789Sahrens  * directories.  This is called from the ZFS init routine, and initializes the
136789Sahrens  * vnode ops vectors that we'll be using.
137789Sahrens  */
138789Sahrens void
139789Sahrens zfsctl_init(void)
140789Sahrens {
141789Sahrens 	VERIFY(gfs_make_opsvec(zfsctl_opsvec) == 0);
142789Sahrens }
143789Sahrens 
144789Sahrens void
145789Sahrens zfsctl_fini(void)
146789Sahrens {
147789Sahrens 	/*
148789Sahrens 	 * Remove vfsctl vnode ops
149789Sahrens 	 */
150789Sahrens 	if (zfsctl_ops_root)
151789Sahrens 		vn_freevnodeops(zfsctl_ops_root);
152789Sahrens 	if (zfsctl_ops_snapdir)
153789Sahrens 		vn_freevnodeops(zfsctl_ops_snapdir);
154789Sahrens 	if (zfsctl_ops_snapshot)
155789Sahrens 		vn_freevnodeops(zfsctl_ops_snapshot);
156789Sahrens 
157789Sahrens 	zfsctl_ops_root = NULL;
158789Sahrens 	zfsctl_ops_snapdir = NULL;
159789Sahrens 	zfsctl_ops_snapshot = NULL;
160789Sahrens }
161789Sahrens 
162789Sahrens /*
163789Sahrens  * Return the inode number associated with the 'snapshot' directory.
164789Sahrens  */
165789Sahrens /* ARGSUSED */
166789Sahrens static ino64_t
167789Sahrens zfsctl_root_inode_cb(vnode_t *vp, int index)
168789Sahrens {
169789Sahrens 	ASSERT(index == 0);
170789Sahrens 	return (ZFSCTL_INO_SNAPDIR);
171789Sahrens }
172789Sahrens 
173789Sahrens /*
174789Sahrens  * Create the '.zfs' directory.  This directory is cached as part of the VFS
175789Sahrens  * structure.  This results in a hold on the vfs_t.  The code in zfs_umount()
176789Sahrens  * therefore checks against a vfs_count of 2 instead of 1.  This reference
177789Sahrens  * is removed when the ctldir is destroyed in the unmount.
178789Sahrens  */
179789Sahrens void
180789Sahrens zfsctl_create(zfsvfs_t *zfsvfs)
181789Sahrens {
1821571Sek110237 	vnode_t *vp, *rvp;
183789Sahrens 	zfsctl_node_t *zcp;
184789Sahrens 
185789Sahrens 	ASSERT(zfsvfs->z_ctldir == NULL);
186789Sahrens 
187789Sahrens 	vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs,
188789Sahrens 	    zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries,
189789Sahrens 	    zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL);
190789Sahrens 	zcp = vp->v_data;
191789Sahrens 	zcp->zc_id = ZFSCTL_INO_ROOT;
192789Sahrens 
1931571Sek110237 	VERIFY(VFS_ROOT(zfsvfs->z_vfs, &rvp) == 0);
1941571Sek110237 	ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime);
1951571Sek110237 	VN_RELE(rvp);
1961571Sek110237 
197789Sahrens 	/*
198789Sahrens 	 * We're only faking the fact that we have a root of a filesystem for
199789Sahrens 	 * the sake of the GFS interfaces.  Undo the flag manipulation it did
200789Sahrens 	 * for us.
201789Sahrens 	 */
202789Sahrens 	vp->v_flag &= ~(VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT);
203789Sahrens 
204789Sahrens 	zfsvfs->z_ctldir = vp;
205789Sahrens }
206789Sahrens 
207789Sahrens /*
2081298Sperrin  * Destroy the '.zfs' directory.  Only called when the filesystem is unmounted.
2091298Sperrin  * There might still be more references if we were force unmounted, but only
2101298Sperrin  * new zfs_inactive() calls can occur and they don't reference .zfs
211789Sahrens  */
212789Sahrens void
213789Sahrens zfsctl_destroy(zfsvfs_t *zfsvfs)
214789Sahrens {
215789Sahrens 	VN_RELE(zfsvfs->z_ctldir);
216789Sahrens 	zfsvfs->z_ctldir = NULL;
217789Sahrens }
218789Sahrens 
219789Sahrens /*
220789Sahrens  * Given a root znode, retrieve the associated .zfs directory.
221789Sahrens  * Add a hold to the vnode and return it.
222789Sahrens  */
223789Sahrens vnode_t *
224789Sahrens zfsctl_root(znode_t *zp)
225789Sahrens {
226789Sahrens 	ASSERT(zfs_has_ctldir(zp));
227789Sahrens 	VN_HOLD(zp->z_zfsvfs->z_ctldir);
228789Sahrens 	return (zp->z_zfsvfs->z_ctldir);
229789Sahrens }
230789Sahrens 
231789Sahrens /*
232789Sahrens  * Common open routine.  Disallow any write access.
233789Sahrens  */
234789Sahrens /* ARGSUSED */
235789Sahrens static int
236789Sahrens zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr)
237789Sahrens {
238789Sahrens 	if (flags & FWRITE)
239789Sahrens 		return (EACCES);
240789Sahrens 
241789Sahrens 	return (0);
242789Sahrens }
243789Sahrens 
244789Sahrens /*
245789Sahrens  * Common close routine.  Nothing to do here.
246789Sahrens  */
247789Sahrens /* ARGSUSED */
248789Sahrens static int
249789Sahrens zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
250789Sahrens     cred_t *cr)
251789Sahrens {
252789Sahrens 	return (0);
253789Sahrens }
254789Sahrens 
255789Sahrens /*
256789Sahrens  * Common access routine.  Disallow writes.
257789Sahrens  */
258789Sahrens /* ARGSUSED */
259789Sahrens static int
260789Sahrens zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr)
261789Sahrens {
262789Sahrens 	if (mode & VWRITE)
263789Sahrens 		return (EACCES);
264789Sahrens 
265789Sahrens 	return (0);
266789Sahrens }
267789Sahrens 
268789Sahrens /*
269789Sahrens  * Common getattr function.  Fill in basic information.
270789Sahrens  */
271789Sahrens static void
272789Sahrens zfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
273789Sahrens {
2741571Sek110237 	zfsctl_node_t	*zcp = vp->v_data;
2751571Sek110237 	timestruc_t	now;
276789Sahrens 
277789Sahrens 	vap->va_uid = 0;
278789Sahrens 	vap->va_gid = 0;
279789Sahrens 	vap->va_rdev = 0;
280789Sahrens 	/*
281789Sahrens 	 * We are a purly virtual object, so we have no
282789Sahrens 	 * blocksize or allocated blocks.
283789Sahrens 	 */
284789Sahrens 	vap->va_blksize = 0;
285789Sahrens 	vap->va_nblocks = 0;
286789Sahrens 	vap->va_seq = 0;
287789Sahrens 	vap->va_fsid = vp->v_vfsp->vfs_dev;
288789Sahrens 	vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP |
289789Sahrens 	    S_IROTH | S_IXOTH;
290789Sahrens 	vap->va_type = VDIR;
291789Sahrens 	/*
2921571Sek110237 	 * We live in the now (for atime).
293789Sahrens 	 */
294789Sahrens 	gethrestime(&now);
2951571Sek110237 	vap->va_atime = now;
2961571Sek110237 	vap->va_mtime = vap->va_ctime = zcp->zc_cmtime;
297789Sahrens }
298789Sahrens 
299789Sahrens static int
300789Sahrens zfsctl_common_fid(vnode_t *vp, fid_t *fidp)
301789Sahrens {
302789Sahrens 	zfsvfs_t	*zfsvfs = vp->v_vfsp->vfs_data;
303789Sahrens 	zfsctl_node_t	*zcp = vp->v_data;
304789Sahrens 	uint64_t	object = zcp->zc_id;
305789Sahrens 	zfid_short_t	*zfid;
306789Sahrens 	int		i;
307789Sahrens 
308789Sahrens 	ZFS_ENTER(zfsvfs);
309789Sahrens 
310789Sahrens 	if (fidp->fid_len < SHORT_FID_LEN) {
311789Sahrens 		fidp->fid_len = SHORT_FID_LEN;
3121512Sek110237 		ZFS_EXIT(zfsvfs);
313789Sahrens 		return (ENOSPC);
314789Sahrens 	}
315789Sahrens 
316789Sahrens 	zfid = (zfid_short_t *)fidp;
317789Sahrens 
318789Sahrens 	zfid->zf_len = SHORT_FID_LEN;
319789Sahrens 
320789Sahrens 	for (i = 0; i < sizeof (zfid->zf_object); i++)
321789Sahrens 		zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
322789Sahrens 
323789Sahrens 	/* .zfs znodes always have a generation number of 0 */
324789Sahrens 	for (i = 0; i < sizeof (zfid->zf_gen); i++)
325789Sahrens 		zfid->zf_gen[i] = 0;
326789Sahrens 
327789Sahrens 	ZFS_EXIT(zfsvfs);
328789Sahrens 	return (0);
329789Sahrens }
330789Sahrens 
331789Sahrens /*
332789Sahrens  * .zfs inode namespace
333789Sahrens  *
334789Sahrens  * We need to generate unique inode numbers for all files and directories
335789Sahrens  * within the .zfs pseudo-filesystem.  We use the following scheme:
336789Sahrens  *
337789Sahrens  * 	ENTRY			ZFSCTL_INODE
338789Sahrens  * 	.zfs			1
339789Sahrens  * 	.zfs/snapshot		2
340789Sahrens  * 	.zfs/snapshot/<snap>	objectid(snap)
341789Sahrens  */
342789Sahrens 
343789Sahrens #define	ZFSCTL_INO_SNAP(id)	(id)
344789Sahrens 
345789Sahrens /*
346789Sahrens  * Get root directory attributes.
347789Sahrens  */
348789Sahrens /* ARGSUSED */
349789Sahrens static int
350789Sahrens zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
351789Sahrens {
352789Sahrens 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
353789Sahrens 
354789Sahrens 	ZFS_ENTER(zfsvfs);
355789Sahrens 	vap->va_nodeid = ZFSCTL_INO_ROOT;
356789Sahrens 	vap->va_nlink = vap->va_size = NROOT_ENTRIES;
357789Sahrens 
358789Sahrens 	zfsctl_common_getattr(vp, vap);
359789Sahrens 	ZFS_EXIT(zfsvfs);
360789Sahrens 
361789Sahrens 	return (0);
362789Sahrens }
363789Sahrens 
364789Sahrens /*
365789Sahrens  * Special case the handling of "..".
366789Sahrens  */
367789Sahrens /* ARGSUSED */
368789Sahrens int
369789Sahrens zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
370789Sahrens     int flags, vnode_t *rdir, cred_t *cr)
371789Sahrens {
372789Sahrens 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
373789Sahrens 	int err;
374789Sahrens 
375789Sahrens 	ZFS_ENTER(zfsvfs);
376789Sahrens 
377789Sahrens 	if (strcmp(nm, "..") == 0) {
378789Sahrens 		err = VFS_ROOT(dvp->v_vfsp, vpp);
379789Sahrens 	} else {
380789Sahrens 		err = gfs_dir_lookup(dvp, nm, vpp);
381789Sahrens 	}
382789Sahrens 
383789Sahrens 	ZFS_EXIT(zfsvfs);
384789Sahrens 
385789Sahrens 	return (err);
386789Sahrens }
387789Sahrens 
388789Sahrens static const fs_operation_def_t zfsctl_tops_root[] = {
3893898Srsb 	{ VOPNAME_OPEN,		{ .vop_open = zfsctl_common_open }	},
3903898Srsb 	{ VOPNAME_CLOSE,	{ .vop_close = zfsctl_common_close }	},
3913898Srsb 	{ VOPNAME_IOCTL,	{ .error = fs_inval }			},
3923898Srsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = zfsctl_root_getattr }	},
3933898Srsb 	{ VOPNAME_ACCESS,	{ .vop_access = zfsctl_common_access }	},
3943898Srsb 	{ VOPNAME_READDIR,	{ .vop_readdir = gfs_vop_readdir } 	},
3953898Srsb 	{ VOPNAME_LOOKUP,	{ .vop_lookup = zfsctl_root_lookup }	},
3963898Srsb 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek }			},
3973898Srsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = gfs_vop_inactive }	},
3983898Srsb 	{ VOPNAME_FID,		{ .vop_fid = zfsctl_common_fid	}	},
399789Sahrens 	{ NULL }
400789Sahrens };
401789Sahrens 
402789Sahrens static int
403789Sahrens zfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname)
404789Sahrens {
405789Sahrens 	objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os;
406789Sahrens 
407789Sahrens 	dmu_objset_name(os, zname);
4081154Smaybee 	if (strlen(zname) + 1 + strlen(name) >= len)
4091154Smaybee 		return (ENAMETOOLONG);
410789Sahrens 	(void) strcat(zname, "@");
411789Sahrens 	(void) strcat(zname, name);
412789Sahrens 	return (0);
413789Sahrens }
414789Sahrens 
415*4543Smarks int
416789Sahrens zfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr)
417789Sahrens {
418789Sahrens 	zfsctl_snapdir_t *sdp = dvp->v_data;
419789Sahrens 	zfs_snapentry_t search, *sep;
420789Sahrens 	avl_index_t where;
421789Sahrens 	int err;
422789Sahrens 
423789Sahrens 	ASSERT(MUTEX_HELD(&sdp->sd_lock));
424789Sahrens 
425789Sahrens 	search.se_name = (char *)name;
426789Sahrens 	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL)
427789Sahrens 		return (ENOENT);
428789Sahrens 
429789Sahrens 	ASSERT(vn_ismntpt(sep->se_root));
430789Sahrens 
431789Sahrens 	/* this will be dropped by dounmount() */
432789Sahrens 	if ((err = vn_vfswlock(sep->se_root)) != 0)
433789Sahrens 		return (err);
434789Sahrens 
435789Sahrens 	VN_HOLD(sep->se_root);
4361589Smaybee 	err = dounmount(vn_mountedvfs(sep->se_root), force, kcred);
4371589Smaybee 	if (err) {
4381589Smaybee 		VN_RELE(sep->se_root);
439789Sahrens 		return (err);
4401589Smaybee 	}
441789Sahrens 	ASSERT(sep->se_root->v_count == 1);
442789Sahrens 	gfs_vop_inactive(sep->se_root, cr);
443789Sahrens 
444789Sahrens 	avl_remove(&sdp->sd_snaps, sep);
445789Sahrens 	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
446789Sahrens 	kmem_free(sep, sizeof (zfs_snapentry_t));
447789Sahrens 
448789Sahrens 	return (0);
449789Sahrens }
450789Sahrens 
451789Sahrens 
4521154Smaybee static void
453789Sahrens zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
454789Sahrens {
455789Sahrens 	avl_index_t where;
456789Sahrens 	vfs_t *vfsp;
457789Sahrens 	refstr_t *pathref;
458789Sahrens 	char newpath[MAXNAMELEN];
459789Sahrens 	char *tail;
460789Sahrens 
461789Sahrens 	ASSERT(MUTEX_HELD(&sdp->sd_lock));
462789Sahrens 	ASSERT(sep != NULL);
463789Sahrens 
464789Sahrens 	vfsp = vn_mountedvfs(sep->se_root);
465789Sahrens 	ASSERT(vfsp != NULL);
466789Sahrens 
4671154Smaybee 	vfs_lock_wait(vfsp);
468789Sahrens 
469789Sahrens 	/*
470789Sahrens 	 * Change the name in the AVL tree.
471789Sahrens 	 */
472789Sahrens 	avl_remove(&sdp->sd_snaps, sep);
473789Sahrens 	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
474789Sahrens 	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
475789Sahrens 	(void) strcpy(sep->se_name, nm);
476789Sahrens 	VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL);
477789Sahrens 	avl_insert(&sdp->sd_snaps, sep, where);
478789Sahrens 
479789Sahrens 	/*
480789Sahrens 	 * Change the current mountpoint info:
481789Sahrens 	 * 	- update the tail of the mntpoint path
482789Sahrens 	 *	- update the tail of the resource path
483789Sahrens 	 */
484789Sahrens 	pathref = vfs_getmntpoint(vfsp);
4852417Sahrens 	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
4862417Sahrens 	VERIFY((tail = strrchr(newpath, '/')) != NULL);
4872417Sahrens 	*(tail+1) = '\0';
4882417Sahrens 	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
489789Sahrens 	(void) strcat(newpath, nm);
490789Sahrens 	refstr_rele(pathref);
491789Sahrens 	vfs_setmntpoint(vfsp, newpath);
492789Sahrens 
493789Sahrens 	pathref = vfs_getresource(vfsp);
4942417Sahrens 	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
4952417Sahrens 	VERIFY((tail = strrchr(newpath, '@')) != NULL);
4962417Sahrens 	*(tail+1) = '\0';
4972417Sahrens 	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
498789Sahrens 	(void) strcat(newpath, nm);
499789Sahrens 	refstr_rele(pathref);
500789Sahrens 	vfs_setresource(vfsp, newpath);
501789Sahrens 
502789Sahrens 	vfs_unlock(vfsp);
503789Sahrens }
504789Sahrens 
505789Sahrens static int
506789Sahrens zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
507789Sahrens     cred_t *cr)
508789Sahrens {
509789Sahrens 	zfsctl_snapdir_t *sdp = sdvp->v_data;
510789Sahrens 	zfs_snapentry_t search, *sep;
511789Sahrens 	avl_index_t where;
512789Sahrens 	char from[MAXNAMELEN], to[MAXNAMELEN];
513789Sahrens 	int err;
514789Sahrens 
5151154Smaybee 	err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from);
5161154Smaybee 	if (err)
5171154Smaybee 		return (err);
518*4543Smarks 
519*4543Smarks 	err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to);
520789Sahrens 	if (err)
521789Sahrens 		return (err);
522789Sahrens 
523*4543Smarks 	if (err = zfs_secpolicy_rename_perms(from, to, cr))
524*4543Smarks 		return (err);
525789Sahrens 	/*
526789Sahrens 	 * Cannot move snapshots out of the snapdir.
527789Sahrens 	 */
528789Sahrens 	if (sdvp != tdvp)
529789Sahrens 		return (EINVAL);
530789Sahrens 
531789Sahrens 	if (strcmp(snm, tnm) == 0)
532789Sahrens 		return (0);
533789Sahrens 
534789Sahrens 	mutex_enter(&sdp->sd_lock);
535789Sahrens 
536789Sahrens 	search.se_name = (char *)snm;
5371154Smaybee 	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) {
5381154Smaybee 		mutex_exit(&sdp->sd_lock);
5391154Smaybee 		return (ENOENT);
540789Sahrens 	}
541789Sahrens 
5424007Smmusante 	err = dmu_objset_rename(from, to, B_FALSE);
5431154Smaybee 	if (err == 0)
5441154Smaybee 		zfsctl_rename_snap(sdp, sep, tnm);
545789Sahrens 
546789Sahrens 	mutex_exit(&sdp->sd_lock);
547789Sahrens 
548789Sahrens 	return (err);
549789Sahrens }
550789Sahrens 
551789Sahrens /* ARGSUSED */
552789Sahrens static int
553789Sahrens zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
554789Sahrens {
555789Sahrens 	zfsctl_snapdir_t *sdp = dvp->v_data;
556789Sahrens 	char snapname[MAXNAMELEN];
557789Sahrens 	int err;
558789Sahrens 
5591154Smaybee 	err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname);
5601154Smaybee 	if (err)
5611154Smaybee 		return (err);
562*4543Smarks 
563*4543Smarks 	if (err = zfs_secpolicy_destroy_perms(snapname, cr))
564789Sahrens 		return (err);
565789Sahrens 
566789Sahrens 	mutex_enter(&sdp->sd_lock);
567789Sahrens 
568*4543Smarks 	err = zfsctl_unmount_snap(dvp, name, MS_FORCE, cr);
569789Sahrens 	if (err) {
570789Sahrens 		mutex_exit(&sdp->sd_lock);
571789Sahrens 		return (err);
572789Sahrens 	}
573789Sahrens 
574789Sahrens 	err = dmu_objset_destroy(snapname);
575789Sahrens 
576789Sahrens 	mutex_exit(&sdp->sd_lock);
577789Sahrens 
578789Sahrens 	return (err);
579789Sahrens }
580789Sahrens 
581*4543Smarks /* ARGSUSED */
582*4543Smarks static int
583*4543Smarks zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t  **vpp,
584*4543Smarks     cred_t *cr)
585*4543Smarks {
586*4543Smarks 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
587*4543Smarks 	char name[MAXNAMELEN];
588*4543Smarks 	int err;
589*4543Smarks 	static enum symfollow follow = NO_FOLLOW;
590*4543Smarks 	static enum uio_seg seg = UIO_SYSSPACE;
591*4543Smarks 
592*4543Smarks 	dmu_objset_name(zfsvfs->z_os, name);
593*4543Smarks 
594*4543Smarks 	*vpp = NULL;
595*4543Smarks 
596*4543Smarks 	err = zfs_secpolicy_snapshot_perms(name, cr);
597*4543Smarks 	if (err)
598*4543Smarks 		return (err);
599*4543Smarks 
600*4543Smarks 	if (err == 0) {
601*4543Smarks 		err = dmu_objset_snapshot(name, dirname, B_FALSE);
602*4543Smarks 		if (err)
603*4543Smarks 			return (err);
604*4543Smarks 		err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp);
605*4543Smarks 	}
606*4543Smarks 
607*4543Smarks 	return (err);
608*4543Smarks }
609*4543Smarks 
610789Sahrens /*
611789Sahrens  * Lookup entry point for the 'snapshot' directory.  Try to open the
612789Sahrens  * snapshot if it exist, creating the pseudo filesystem vnode as necessary.
613789Sahrens  * Perform a mount of the associated dataset on top of the vnode.
614789Sahrens  */
615789Sahrens /* ARGSUSED */
616789Sahrens static int
617789Sahrens zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
618789Sahrens     int flags, vnode_t *rdir, cred_t *cr)
619789Sahrens {
620789Sahrens 	zfsctl_snapdir_t *sdp = dvp->v_data;
621789Sahrens 	objset_t *snap;
622789Sahrens 	char snapname[MAXNAMELEN];
623789Sahrens 	char *mountpoint;
624789Sahrens 	zfs_snapentry_t *sep, search;
625789Sahrens 	struct mounta margs;
626789Sahrens 	vfs_t *vfsp;
627789Sahrens 	size_t mountpoint_len;
628789Sahrens 	avl_index_t where;
629789Sahrens 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
630789Sahrens 	int err;
631789Sahrens 
632789Sahrens 	ASSERT(dvp->v_type == VDIR);
633789Sahrens 
634789Sahrens 	if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0)
635789Sahrens 		return (0);
636789Sahrens 
637789Sahrens 	/*
638789Sahrens 	 * If we get a recursive call, that means we got called
639789Sahrens 	 * from the domount() code while it was trying to look up the
640789Sahrens 	 * spec (which looks like a local path for zfs).  We need to
641789Sahrens 	 * add some flag to domount() to tell it not to do this lookup.
642789Sahrens 	 */
643789Sahrens 	if (MUTEX_HELD(&sdp->sd_lock))
644789Sahrens 		return (ENOENT);
645789Sahrens 
646789Sahrens 	ZFS_ENTER(zfsvfs);
647789Sahrens 
648789Sahrens 	mutex_enter(&sdp->sd_lock);
649789Sahrens 	search.se_name = (char *)nm;
650789Sahrens 	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) {
651789Sahrens 		*vpp = sep->se_root;
652789Sahrens 		VN_HOLD(*vpp);
6531589Smaybee 		err = traverse(vpp);
6541589Smaybee 		if (err) {
6551589Smaybee 			VN_RELE(*vpp);
6561589Smaybee 			*vpp = NULL;
6571589Smaybee 		} else if (*vpp == sep->se_root) {
6581589Smaybee 			/*
6591589Smaybee 			 * The snapshot was unmounted behind our backs,
6601589Smaybee 			 * try to remount it.
6611589Smaybee 			 */
662789Sahrens 			goto domount;
6631566Smaybee 		}
664789Sahrens 		mutex_exit(&sdp->sd_lock);
665789Sahrens 		ZFS_EXIT(zfsvfs);
6661589Smaybee 		return (err);
667789Sahrens 	}
668789Sahrens 
669789Sahrens 	/*
670789Sahrens 	 * The requested snapshot is not currently mounted, look it up.
671789Sahrens 	 */
6721154Smaybee 	err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname);
6731154Smaybee 	if (err) {
6741154Smaybee 		mutex_exit(&sdp->sd_lock);
6751154Smaybee 		ZFS_EXIT(zfsvfs);
6761154Smaybee 		return (err);
6771154Smaybee 	}
678789Sahrens 	if (dmu_objset_open(snapname, DMU_OST_ZFS,
679789Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &snap) != 0) {
680789Sahrens 		mutex_exit(&sdp->sd_lock);
681789Sahrens 		ZFS_EXIT(zfsvfs);
682789Sahrens 		return (ENOENT);
683789Sahrens 	}
684789Sahrens 
685789Sahrens 	sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP);
686789Sahrens 	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
687789Sahrens 	(void) strcpy(sep->se_name, nm);
688789Sahrens 	*vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap));
689789Sahrens 	avl_insert(&sdp->sd_snaps, sep, where);
690789Sahrens 
691789Sahrens 	dmu_objset_close(snap);
692789Sahrens domount:
693789Sahrens 	mountpoint_len = strlen(refstr_value(dvp->v_vfsp->vfs_mntpt)) +
694789Sahrens 	    strlen("/.zfs/snapshot/") + strlen(nm) + 1;
695789Sahrens 	mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP);
696789Sahrens 	(void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s",
697789Sahrens 	    refstr_value(dvp->v_vfsp->vfs_mntpt), nm);
698789Sahrens 
699789Sahrens 	margs.spec = snapname;
700789Sahrens 	margs.dir = mountpoint;
701789Sahrens 	margs.flags = MS_SYSSPACE | MS_NOMNTTAB;
702789Sahrens 	margs.fstype = "zfs";
703789Sahrens 	margs.dataptr = NULL;
704789Sahrens 	margs.datalen = 0;
705789Sahrens 	margs.optptr = NULL;
706789Sahrens 	margs.optlen = 0;
707789Sahrens 
708789Sahrens 	err = domount("zfs", &margs, *vpp, kcred, &vfsp);
709789Sahrens 	kmem_free(mountpoint, mountpoint_len);
710789Sahrens 
711816Smaybee 	if (err == 0) {
712816Smaybee 		/*
713816Smaybee 		 * Return the mounted root rather than the covered mount point.
714816Smaybee 		 */
715816Smaybee 		VFS_RELE(vfsp);
716816Smaybee 		err = traverse(vpp);
717816Smaybee 	}
718789Sahrens 
719816Smaybee 	if (err == 0) {
720816Smaybee 		/*
721816Smaybee 		 * Fix up the root vnode.
722816Smaybee 		 */
723816Smaybee 		ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs);
724816Smaybee 		VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs;
725816Smaybee 		(*vpp)->v_vfsp = zfsvfs->z_vfs;
726816Smaybee 		(*vpp)->v_flag &= ~VROOT;
727816Smaybee 	}
728789Sahrens 	mutex_exit(&sdp->sd_lock);
729789Sahrens 	ZFS_EXIT(zfsvfs);
730789Sahrens 
7311566Smaybee 	/*
7321566Smaybee 	 * If we had an error, drop our hold on the vnode and
7331566Smaybee 	 * zfsctl_snapshot_inactive() will clean up.
7341566Smaybee 	 */
7351566Smaybee 	if (err) {
736816Smaybee 		VN_RELE(*vpp);
7371566Smaybee 		*vpp = NULL;
7381566Smaybee 	}
739816Smaybee 	return (err);
740789Sahrens }
741789Sahrens 
742789Sahrens /* ARGSUSED */
743789Sahrens static int
744789Sahrens zfsctl_snapdir_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp,
745789Sahrens     offset_t *offp, offset_t *nextp, void *data)
746789Sahrens {
747789Sahrens 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
748789Sahrens 	char snapname[MAXNAMELEN];
749789Sahrens 	uint64_t id, cookie;
750789Sahrens 
751789Sahrens 	ZFS_ENTER(zfsvfs);
752789Sahrens 
753789Sahrens 	cookie = *offp;
754789Sahrens 	if (dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
755789Sahrens 	    &cookie) == ENOENT) {
756789Sahrens 		*eofp = 1;
757789Sahrens 		ZFS_EXIT(zfsvfs);
758789Sahrens 		return (0);
759789Sahrens 	}
760789Sahrens 
761789Sahrens 	(void) strcpy(dp->d_name, snapname);
762789Sahrens 	dp->d_ino = ZFSCTL_INO_SNAP(id);
763789Sahrens 	*nextp = cookie;
764789Sahrens 
765789Sahrens 	ZFS_EXIT(zfsvfs);
766789Sahrens 
767789Sahrens 	return (0);
768789Sahrens }
769789Sahrens 
770789Sahrens vnode_t *
771789Sahrens zfsctl_mknode_snapdir(vnode_t *pvp)
772789Sahrens {
773789Sahrens 	vnode_t *vp;
774789Sahrens 	zfsctl_snapdir_t *sdp;
775789Sahrens 
776789Sahrens 	vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp,
777789Sahrens 	    zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN,
778789Sahrens 	    zfsctl_snapdir_readdir_cb, NULL);
779789Sahrens 	sdp = vp->v_data;
780789Sahrens 	sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR;
7811571Sek110237 	sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
782789Sahrens 	mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL);
783789Sahrens 	avl_create(&sdp->sd_snaps, snapentry_compare,
784789Sahrens 	    sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node));
785789Sahrens 	return (vp);
786789Sahrens }
787789Sahrens 
788789Sahrens /* ARGSUSED */
789789Sahrens static int
790789Sahrens zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
791789Sahrens {
792789Sahrens 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
793789Sahrens 	zfsctl_snapdir_t *sdp = vp->v_data;
794789Sahrens 
795789Sahrens 	ZFS_ENTER(zfsvfs);
796789Sahrens 	zfsctl_common_getattr(vp, vap);
797789Sahrens 	vap->va_nodeid = gfs_file_inode(vp);
798789Sahrens 	vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2;
799789Sahrens 	ZFS_EXIT(zfsvfs);
800789Sahrens 
801789Sahrens 	return (0);
802789Sahrens }
803789Sahrens 
8041566Smaybee /* ARGSUSED */
805789Sahrens static void
806789Sahrens zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr)
807789Sahrens {
808789Sahrens 	zfsctl_snapdir_t *sdp = vp->v_data;
8091566Smaybee 	void *private;
810789Sahrens 
8111566Smaybee 	private = gfs_dir_inactive(vp);
8121566Smaybee 	if (private != NULL) {
8131566Smaybee 		ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
8141566Smaybee 		mutex_destroy(&sdp->sd_lock);
8151566Smaybee 		avl_destroy(&sdp->sd_snaps);
8161566Smaybee 		kmem_free(private, sizeof (zfsctl_snapdir_t));
8171566Smaybee 	}
818789Sahrens }
819789Sahrens 
820789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[] = {
8213898Srsb 	{ VOPNAME_OPEN,		{ .vop_open = zfsctl_common_open }	},
8223898Srsb 	{ VOPNAME_CLOSE,	{ .vop_close = zfsctl_common_close }	},
8233898Srsb 	{ VOPNAME_IOCTL,	{ .error = fs_inval }			},
8243898Srsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = zfsctl_snapdir_getattr } },
8253898Srsb 	{ VOPNAME_ACCESS,	{ .vop_access = zfsctl_common_access }	},
8263898Srsb 	{ VOPNAME_RENAME,	{ .vop_rename = zfsctl_snapdir_rename }	},
8273898Srsb 	{ VOPNAME_RMDIR,	{ .vop_rmdir = zfsctl_snapdir_remove }	},
828*4543Smarks 	{ VOPNAME_MKDIR,	{ .vop_mkdir = zfsctl_snapdir_mkdir }	},
8293898Srsb 	{ VOPNAME_READDIR,	{ .vop_readdir = gfs_vop_readdir }	},
8303898Srsb 	{ VOPNAME_LOOKUP,	{ .vop_lookup = zfsctl_snapdir_lookup }	},
8313898Srsb 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek }			},
8323898Srsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = zfsctl_snapdir_inactive } },
8333898Srsb 	{ VOPNAME_FID,		{ .vop_fid = zfsctl_common_fid }	},
834789Sahrens 	{ NULL }
835789Sahrens };
836789Sahrens 
837789Sahrens static vnode_t *
838789Sahrens zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
839789Sahrens {
840789Sahrens 	vnode_t *vp;
841789Sahrens 	zfsctl_node_t *zcp;
842789Sahrens 
843789Sahrens 	vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp,
844789Sahrens 	    zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL);
845789Sahrens 	zcp = vp->v_data;
846789Sahrens 	zcp->zc_id = objset;
847789Sahrens 
848789Sahrens 	return (vp);
849789Sahrens }
850789Sahrens 
851789Sahrens static void
852789Sahrens zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr)
853789Sahrens {
854789Sahrens 	zfsctl_snapdir_t *sdp;
855789Sahrens 	zfs_snapentry_t *sep, *next;
856789Sahrens 	vnode_t *dvp;
857789Sahrens 
858789Sahrens 	VERIFY(gfs_dir_lookup(vp, "..", &dvp) == 0);
859789Sahrens 	sdp = dvp->v_data;
860789Sahrens 
861789Sahrens 	mutex_enter(&sdp->sd_lock);
862789Sahrens 
863789Sahrens 	if (vp->v_count > 1) {
864789Sahrens 		mutex_exit(&sdp->sd_lock);
865789Sahrens 		return;
866789Sahrens 	}
867789Sahrens 	ASSERT(!vn_ismntpt(vp));
868789Sahrens 
869789Sahrens 	sep = avl_first(&sdp->sd_snaps);
870789Sahrens 	while (sep != NULL) {
871789Sahrens 		next = AVL_NEXT(&sdp->sd_snaps, sep);
872789Sahrens 
873789Sahrens 		if (sep->se_root == vp) {
874789Sahrens 			avl_remove(&sdp->sd_snaps, sep);
875789Sahrens 			kmem_free(sep->se_name, strlen(sep->se_name) + 1);
876789Sahrens 			kmem_free(sep, sizeof (zfs_snapentry_t));
877789Sahrens 			break;
878789Sahrens 		}
879789Sahrens 		sep = next;
880789Sahrens 	}
881789Sahrens 	ASSERT(sep != NULL);
882789Sahrens 
883789Sahrens 	mutex_exit(&sdp->sd_lock);
884789Sahrens 	VN_RELE(dvp);
885789Sahrens 
8861566Smaybee 	/*
8871566Smaybee 	 * Dispose of the vnode for the snapshot mount point.
8881566Smaybee 	 * This is safe to do because once this entry has been removed
8891566Smaybee 	 * from the AVL tree, it can't be found again, so cannot become
8901566Smaybee 	 * "active".  If we lookup the same name again we will end up
8911566Smaybee 	 * creating a new vnode.
8921566Smaybee 	 */
893789Sahrens 	gfs_vop_inactive(vp, cr);
894789Sahrens }
895789Sahrens 
896789Sahrens 
897789Sahrens /*
898789Sahrens  * These VP's should never see the light of day.  They should always
899789Sahrens  * be covered.
900789Sahrens  */
901789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[] = {
9023898Srsb 	VOPNAME_INACTIVE, { .vop_inactive =  zfsctl_snapshot_inactive },
903789Sahrens 	NULL, NULL
904789Sahrens };
905789Sahrens 
906789Sahrens int
907789Sahrens zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
908789Sahrens {
909789Sahrens 	zfsvfs_t *zfsvfs = vfsp->vfs_data;
910789Sahrens 	vnode_t *dvp, *vp;
911789Sahrens 	zfsctl_snapdir_t *sdp;
912789Sahrens 	zfsctl_node_t *zcp;
913789Sahrens 	zfs_snapentry_t *sep;
914789Sahrens 	int error;
915789Sahrens 
916789Sahrens 	ASSERT(zfsvfs->z_ctldir != NULL);
917789Sahrens 	error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
918789Sahrens 	    NULL, 0, NULL, kcred);
919789Sahrens 	if (error != 0)
920789Sahrens 		return (error);
921789Sahrens 	sdp = dvp->v_data;
922789Sahrens 
923789Sahrens 	mutex_enter(&sdp->sd_lock);
924789Sahrens 	sep = avl_first(&sdp->sd_snaps);
925789Sahrens 	while (sep != NULL) {
926789Sahrens 		vp = sep->se_root;
927789Sahrens 		zcp = vp->v_data;
928789Sahrens 		if (zcp->zc_id == objsetid)
929789Sahrens 			break;
930789Sahrens 
931789Sahrens 		sep = AVL_NEXT(&sdp->sd_snaps, sep);
932789Sahrens 	}
933789Sahrens 
934789Sahrens 	if (sep != NULL) {
935789Sahrens 		VN_HOLD(vp);
936789Sahrens 		error = traverse(&vp);
9371589Smaybee 		if (error == 0) {
9381589Smaybee 			if (vp == sep->se_root)
9391589Smaybee 				error = EINVAL;
9401589Smaybee 			else
9411589Smaybee 				*zfsvfsp = VTOZ(vp)->z_zfsvfs;
9421589Smaybee 		}
9431572Snd150628 		mutex_exit(&sdp->sd_lock);
944789Sahrens 		VN_RELE(vp);
945789Sahrens 	} else {
946789Sahrens 		error = EINVAL;
9471572Snd150628 		mutex_exit(&sdp->sd_lock);
948789Sahrens 	}
949789Sahrens 
950789Sahrens 	VN_RELE(dvp);
951789Sahrens 
952789Sahrens 	return (error);
953789Sahrens }
954789Sahrens 
955789Sahrens /*
956789Sahrens  * Unmount any snapshots for the given filesystem.  This is called from
957789Sahrens  * zfs_umount() - if we have a ctldir, then go through and unmount all the
958789Sahrens  * snapshots.
959789Sahrens  */
960789Sahrens int
961789Sahrens zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
962789Sahrens {
963789Sahrens 	zfsvfs_t *zfsvfs = vfsp->vfs_data;
964789Sahrens 	vnode_t *dvp, *svp;
965789Sahrens 	zfsctl_snapdir_t *sdp;
966789Sahrens 	zfs_snapentry_t *sep, *next;
967789Sahrens 	int error;
968789Sahrens 
969789Sahrens 	ASSERT(zfsvfs->z_ctldir != NULL);
970789Sahrens 	error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
971789Sahrens 	    NULL, 0, NULL, cr);
972789Sahrens 	if (error != 0)
973789Sahrens 		return (error);
974789Sahrens 	sdp = dvp->v_data;
975789Sahrens 
976789Sahrens 	mutex_enter(&sdp->sd_lock);
977789Sahrens 
978789Sahrens 	sep = avl_first(&sdp->sd_snaps);
979789Sahrens 	while (sep != NULL) {
980789Sahrens 		svp = sep->se_root;
981789Sahrens 		next = AVL_NEXT(&sdp->sd_snaps, sep);
982789Sahrens 
983789Sahrens 		/*
984789Sahrens 		 * If this snapshot is not mounted, then it must
985789Sahrens 		 * have just been unmounted by somebody else, and
986789Sahrens 		 * will be cleaned up by zfsctl_snapdir_inactive().
987789Sahrens 		 */
988789Sahrens 		if (vn_ismntpt(svp)) {
989789Sahrens 			if ((error = vn_vfswlock(svp)) != 0)
990789Sahrens 				goto out;
991789Sahrens 
992789Sahrens 			VN_HOLD(svp);
993789Sahrens 			error = dounmount(vn_mountedvfs(svp), fflags, cr);
994789Sahrens 			if (error) {
995789Sahrens 				VN_RELE(svp);
996789Sahrens 				goto out;
997789Sahrens 			}
998789Sahrens 
999789Sahrens 			avl_remove(&sdp->sd_snaps, sep);
1000789Sahrens 			kmem_free(sep->se_name, strlen(sep->se_name) + 1);
1001789Sahrens 			kmem_free(sep, sizeof (zfs_snapentry_t));
1002789Sahrens 
1003789Sahrens 			/*
1004789Sahrens 			 * We can't use VN_RELE(), as that will try to
1005789Sahrens 			 * invoke zfsctl_snapdir_inactive(), and that
1006789Sahrens 			 * would lead to an attempt to re-grab the sd_lock.
1007789Sahrens 			 */
1008789Sahrens 			ASSERT3U(svp->v_count, ==, 1);
1009789Sahrens 			gfs_vop_inactive(svp, cr);
1010789Sahrens 		}
1011789Sahrens 		sep = next;
1012789Sahrens 	}
1013789Sahrens out:
1014789Sahrens 	mutex_exit(&sdp->sd_lock);
1015789Sahrens 	VN_RELE(dvp);
1016789Sahrens 
1017789Sahrens 	return (error);
1018789Sahrens }
1019