xref: /onnv-gate/usr/src/uts/common/fs/zfs/zfs_ctldir.c (revision 10298:a0d52501437c)
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 /*
228547SMark.Shellenbaum@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens /*
27789Sahrens  * ZFS control directory (a.k.a. ".zfs")
28789Sahrens  *
29789Sahrens  * This directory provides a common location for all ZFS meta-objects.
30789Sahrens  * Currently, this is only the 'snapshot' directory, but this may expand in the
31789Sahrens  * future.  The elements are built using the GFS primitives, as the hierarchy
32789Sahrens  * does not actually exist on disk.
33789Sahrens  *
34789Sahrens  * For 'snapshot', we don't want to have all snapshots always mounted, because
35789Sahrens  * this would take up a huge amount of space in /etc/mnttab.  We have three
36789Sahrens  * types of objects:
37789Sahrens  *
38789Sahrens  * 	ctldir ------> snapshotdir -------> snapshot
39789Sahrens  *                                             |
40789Sahrens  *                                             |
41789Sahrens  *                                             V
42789Sahrens  *                                         mounted fs
43789Sahrens  *
44789Sahrens  * The 'snapshot' node contains just enough information to lookup '..' and act
45789Sahrens  * as a mountpoint for the snapshot.  Whenever we lookup a specific snapshot, we
46789Sahrens  * perform an automount of the underlying filesystem and return the
47789Sahrens  * corresponding vnode.
48789Sahrens  *
49789Sahrens  * All mounts are handled automatically by the kernel, but unmounts are
50789Sahrens  * (currently) handled from user land.  The main reason is that there is no
51789Sahrens  * reliable way to auto-unmount the filesystem when it's "no longer in use".
52789Sahrens  * When the user unmounts a filesystem, we call zfsctl_unmount(), which
53789Sahrens  * unmounts any snapshots within the snapshot directory.
545326Sek110237  *
555326Sek110237  * The '.zfs', '.zfs/snapshot', and all directories created under
565326Sek110237  * '.zfs/snapshot' (ie: '.zfs/snapshot/<snapname>') are all GFS nodes and
575326Sek110237  * share the same vfs_t as the head filesystem (what '.zfs' lives under).
585326Sek110237  *
595326Sek110237  * File systems mounted ontop of the GFS nodes '.zfs/snapshot/<snapname>'
605326Sek110237  * (ie: snapshots) are ZFS nodes and have their own unique vfs_t.
615326Sek110237  * However, vnodes within these mounted on file systems have their v_vfsp
625326Sek110237  * fields set to the head filesystem to make NFS happy (see
636068Sck153898  * zfsctl_snapdir_lookup()). We VFS_HOLD the head filesystem's vfs_t
646068Sck153898  * so that it cannot be freed until all snapshots have been unmounted.
65789Sahrens  */
66789Sahrens 
67789Sahrens #include <fs/fs_subr.h>
68789Sahrens #include <sys/zfs_ctldir.h>
69789Sahrens #include <sys/zfs_ioctl.h>
70789Sahrens #include <sys/zfs_vfsops.h>
713898Srsb #include <sys/vfs_opreg.h>
72789Sahrens #include <sys/gfs.h>
73789Sahrens #include <sys/stat.h>
74789Sahrens #include <sys/dmu.h>
754543Smarks #include <sys/dsl_deleg.h>
76789Sahrens #include <sys/mount.h>
776492Stimh #include <sys/sunddi.h>
78789Sahrens 
796658Smarks #include "zfs_namecheck.h"
806658Smarks 
816068Sck153898 typedef struct zfsctl_node {
826068Sck153898 	gfs_dir_t	zc_gfs_private;
836068Sck153898 	uint64_t	zc_id;
846068Sck153898 	timestruc_t	zc_cmtime;	/* ctime and mtime, always the same */
856068Sck153898 } zfsctl_node_t;
866068Sck153898 
876068Sck153898 typedef struct zfsctl_snapdir {
886068Sck153898 	zfsctl_node_t	sd_node;
896068Sck153898 	kmutex_t	sd_lock;
906068Sck153898 	avl_tree_t	sd_snaps;
916068Sck153898 } zfsctl_snapdir_t;
926068Sck153898 
93789Sahrens typedef struct {
94789Sahrens 	char		*se_name;
95789Sahrens 	vnode_t		*se_root;
96789Sahrens 	avl_node_t	se_node;
97789Sahrens } zfs_snapentry_t;
98789Sahrens 
99789Sahrens static int
100789Sahrens snapentry_compare(const void *a, const void *b)
101789Sahrens {
102789Sahrens 	const zfs_snapentry_t *sa = a;
103789Sahrens 	const zfs_snapentry_t *sb = b;
104789Sahrens 	int ret = strcmp(sa->se_name, sb->se_name);
105789Sahrens 
106789Sahrens 	if (ret < 0)
107789Sahrens 		return (-1);
108789Sahrens 	else if (ret > 0)
109789Sahrens 		return (1);
110789Sahrens 	else
111789Sahrens 		return (0);
112789Sahrens }
113789Sahrens 
114789Sahrens vnodeops_t *zfsctl_ops_root;
115789Sahrens vnodeops_t *zfsctl_ops_snapdir;
116789Sahrens vnodeops_t *zfsctl_ops_snapshot;
1178845Samw@Sun.COM vnodeops_t *zfsctl_ops_shares;
1188845Samw@Sun.COM vnodeops_t *zfsctl_ops_shares_dir;
119789Sahrens 
120789Sahrens static const fs_operation_def_t zfsctl_tops_root[];
121789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[];
122789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[];
1238845Samw@Sun.COM static const fs_operation_def_t zfsctl_tops_shares[];
124789Sahrens 
125789Sahrens static vnode_t *zfsctl_mknode_snapdir(vnode_t *);
1268845Samw@Sun.COM static vnode_t *zfsctl_mknode_shares(vnode_t *);
127789Sahrens static vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset);
1286068Sck153898 static int zfsctl_unmount_snap(zfs_snapentry_t *, int, cred_t *);
129789Sahrens 
130789Sahrens static gfs_opsvec_t zfsctl_opsvec[] = {
131789Sahrens 	{ ".zfs", zfsctl_tops_root, &zfsctl_ops_root },
132789Sahrens 	{ ".zfs/snapshot", zfsctl_tops_snapdir, &zfsctl_ops_snapdir },
133789Sahrens 	{ ".zfs/snapshot/vnode", zfsctl_tops_snapshot, &zfsctl_ops_snapshot },
1348845Samw@Sun.COM 	{ ".zfs/shares", zfsctl_tops_shares, &zfsctl_ops_shares_dir },
1358845Samw@Sun.COM 	{ ".zfs/shares/vnode", zfsctl_tops_shares, &zfsctl_ops_shares },
136789Sahrens 	{ NULL }
137789Sahrens };
138789Sahrens 
139789Sahrens /*
1408845Samw@Sun.COM  * Root directory elements.  We only have two entries
1418845Samw@Sun.COM  * snapshot and shares.
142789Sahrens  */
143789Sahrens static gfs_dirent_t zfsctl_root_entries[] = {
144789Sahrens 	{ "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE },
1458845Samw@Sun.COM 	{ "shares", zfsctl_mknode_shares, GFS_CACHE_VNODE },
146789Sahrens 	{ NULL }
147789Sahrens };
148789Sahrens 
149789Sahrens /* include . and .. in the calculation */
150789Sahrens #define	NROOT_ENTRIES	((sizeof (zfsctl_root_entries) / \
151789Sahrens     sizeof (gfs_dirent_t)) + 1)
152789Sahrens 
153789Sahrens 
154789Sahrens /*
155789Sahrens  * Initialize the various GFS pieces we'll need to create and manipulate .zfs
156789Sahrens  * directories.  This is called from the ZFS init routine, and initializes the
157789Sahrens  * vnode ops vectors that we'll be using.
158789Sahrens  */
159789Sahrens void
160789Sahrens zfsctl_init(void)
161789Sahrens {
162789Sahrens 	VERIFY(gfs_make_opsvec(zfsctl_opsvec) == 0);
163789Sahrens }
164789Sahrens 
165789Sahrens void
166789Sahrens zfsctl_fini(void)
167789Sahrens {
168789Sahrens 	/*
169789Sahrens 	 * Remove vfsctl vnode ops
170789Sahrens 	 */
171789Sahrens 	if (zfsctl_ops_root)
172789Sahrens 		vn_freevnodeops(zfsctl_ops_root);
173789Sahrens 	if (zfsctl_ops_snapdir)
174789Sahrens 		vn_freevnodeops(zfsctl_ops_snapdir);
175789Sahrens 	if (zfsctl_ops_snapshot)
176789Sahrens 		vn_freevnodeops(zfsctl_ops_snapshot);
1778845Samw@Sun.COM 	if (zfsctl_ops_shares)
1788845Samw@Sun.COM 		vn_freevnodeops(zfsctl_ops_shares);
1798845Samw@Sun.COM 	if (zfsctl_ops_shares_dir)
1808845Samw@Sun.COM 		vn_freevnodeops(zfsctl_ops_shares_dir);
181789Sahrens 
182789Sahrens 	zfsctl_ops_root = NULL;
183789Sahrens 	zfsctl_ops_snapdir = NULL;
184789Sahrens 	zfsctl_ops_snapshot = NULL;
1858845Samw@Sun.COM 	zfsctl_ops_shares = NULL;
1868845Samw@Sun.COM 	zfsctl_ops_shares_dir = NULL;
187789Sahrens }
188789Sahrens 
189789Sahrens /*
1908845Samw@Sun.COM  * Return the inode number associated with the 'snapshot' or
1918845Samw@Sun.COM  * 'shares' directory.
192789Sahrens  */
193789Sahrens /* ARGSUSED */
194789Sahrens static ino64_t
195789Sahrens zfsctl_root_inode_cb(vnode_t *vp, int index)
196789Sahrens {
1978845Samw@Sun.COM 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
1988845Samw@Sun.COM 
1998845Samw@Sun.COM 	ASSERT(index <= 2);
2008845Samw@Sun.COM 
2018845Samw@Sun.COM 	if (index == 0)
2028845Samw@Sun.COM 		return (ZFSCTL_INO_SNAPDIR);
2038845Samw@Sun.COM 
2048845Samw@Sun.COM 	return (zfsvfs->z_shares_dir);
205789Sahrens }
206789Sahrens 
207789Sahrens /*
208789Sahrens  * Create the '.zfs' directory.  This directory is cached as part of the VFS
209789Sahrens  * structure.  This results in a hold on the vfs_t.  The code in zfs_umount()
210789Sahrens  * therefore checks against a vfs_count of 2 instead of 1.  This reference
211789Sahrens  * is removed when the ctldir is destroyed in the unmount.
212789Sahrens  */
213789Sahrens void
214789Sahrens zfsctl_create(zfsvfs_t *zfsvfs)
215789Sahrens {
2161571Sek110237 	vnode_t *vp, *rvp;
217789Sahrens 	zfsctl_node_t *zcp;
218789Sahrens 
219789Sahrens 	ASSERT(zfsvfs->z_ctldir == NULL);
220789Sahrens 
221789Sahrens 	vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs,
222789Sahrens 	    zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries,
223789Sahrens 	    zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL);
224789Sahrens 	zcp = vp->v_data;
225789Sahrens 	zcp->zc_id = ZFSCTL_INO_ROOT;
226789Sahrens 
2271571Sek110237 	VERIFY(VFS_ROOT(zfsvfs->z_vfs, &rvp) == 0);
2281571Sek110237 	ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime);
2291571Sek110237 	VN_RELE(rvp);
2301571Sek110237 
231789Sahrens 	/*
232789Sahrens 	 * We're only faking the fact that we have a root of a filesystem for
233789Sahrens 	 * the sake of the GFS interfaces.  Undo the flag manipulation it did
234789Sahrens 	 * for us.
235789Sahrens 	 */
236789Sahrens 	vp->v_flag &= ~(VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT);
237789Sahrens 
238789Sahrens 	zfsvfs->z_ctldir = vp;
239789Sahrens }
240789Sahrens 
241789Sahrens /*
2421298Sperrin  * Destroy the '.zfs' directory.  Only called when the filesystem is unmounted.
2431298Sperrin  * There might still be more references if we were force unmounted, but only
2441298Sperrin  * new zfs_inactive() calls can occur and they don't reference .zfs
245789Sahrens  */
246789Sahrens void
247789Sahrens zfsctl_destroy(zfsvfs_t *zfsvfs)
248789Sahrens {
249789Sahrens 	VN_RELE(zfsvfs->z_ctldir);
250789Sahrens 	zfsvfs->z_ctldir = NULL;
251789Sahrens }
252789Sahrens 
253789Sahrens /*
254789Sahrens  * Given a root znode, retrieve the associated .zfs directory.
255789Sahrens  * Add a hold to the vnode and return it.
256789Sahrens  */
257789Sahrens vnode_t *
258789Sahrens zfsctl_root(znode_t *zp)
259789Sahrens {
260789Sahrens 	ASSERT(zfs_has_ctldir(zp));
261789Sahrens 	VN_HOLD(zp->z_zfsvfs->z_ctldir);
262789Sahrens 	return (zp->z_zfsvfs->z_ctldir);
263789Sahrens }
264789Sahrens 
265789Sahrens /*
266789Sahrens  * Common open routine.  Disallow any write access.
267789Sahrens  */
268789Sahrens /* ARGSUSED */
269789Sahrens static int
2705331Samw zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
271789Sahrens {
272789Sahrens 	if (flags & FWRITE)
273789Sahrens 		return (EACCES);
274789Sahrens 
275789Sahrens 	return (0);
276789Sahrens }
277789Sahrens 
278789Sahrens /*
279789Sahrens  * Common close routine.  Nothing to do here.
280789Sahrens  */
281789Sahrens /* ARGSUSED */
282789Sahrens static int
283789Sahrens zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
2845331Samw     cred_t *cr, caller_context_t *ct)
285789Sahrens {
286789Sahrens 	return (0);
287789Sahrens }
288789Sahrens 
289789Sahrens /*
290789Sahrens  * Common access routine.  Disallow writes.
291789Sahrens  */
292789Sahrens /* ARGSUSED */
293789Sahrens static int
2945331Samw zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr,
2955331Samw     caller_context_t *ct)
296789Sahrens {
2978547SMark.Shellenbaum@Sun.COM 	if (flags & V_ACE_MASK) {
2988547SMark.Shellenbaum@Sun.COM 		if (mode & ACE_ALL_WRITE_PERMS)
2998547SMark.Shellenbaum@Sun.COM 			return (EACCES);
3008547SMark.Shellenbaum@Sun.COM 	} else {
3018547SMark.Shellenbaum@Sun.COM 		if (mode & VWRITE)
3028547SMark.Shellenbaum@Sun.COM 			return (EACCES);
3038547SMark.Shellenbaum@Sun.COM 	}
304789Sahrens 
305789Sahrens 	return (0);
306789Sahrens }
307789Sahrens 
308789Sahrens /*
309789Sahrens  * Common getattr function.  Fill in basic information.
310789Sahrens  */
311789Sahrens static void
312789Sahrens zfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
313789Sahrens {
3141571Sek110237 	zfsctl_node_t	*zcp = vp->v_data;
3151571Sek110237 	timestruc_t	now;
316789Sahrens 
317789Sahrens 	vap->va_uid = 0;
318789Sahrens 	vap->va_gid = 0;
319789Sahrens 	vap->va_rdev = 0;
320789Sahrens 	/*
321789Sahrens 	 * We are a purly virtual object, so we have no
322789Sahrens 	 * blocksize or allocated blocks.
323789Sahrens 	 */
324789Sahrens 	vap->va_blksize = 0;
325789Sahrens 	vap->va_nblocks = 0;
326789Sahrens 	vap->va_seq = 0;
327789Sahrens 	vap->va_fsid = vp->v_vfsp->vfs_dev;
328789Sahrens 	vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP |
329789Sahrens 	    S_IROTH | S_IXOTH;
330789Sahrens 	vap->va_type = VDIR;
331789Sahrens 	/*
3321571Sek110237 	 * We live in the now (for atime).
333789Sahrens 	 */
334789Sahrens 	gethrestime(&now);
3351571Sek110237 	vap->va_atime = now;
3361571Sek110237 	vap->va_mtime = vap->va_ctime = zcp->zc_cmtime;
337789Sahrens }
338789Sahrens 
3395331Samw /*ARGSUSED*/
340789Sahrens static int
3415331Samw zfsctl_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
342789Sahrens {
343789Sahrens 	zfsvfs_t	*zfsvfs = vp->v_vfsp->vfs_data;
344789Sahrens 	zfsctl_node_t	*zcp = vp->v_data;
345789Sahrens 	uint64_t	object = zcp->zc_id;
346789Sahrens 	zfid_short_t	*zfid;
347789Sahrens 	int		i;
348789Sahrens 
349789Sahrens 	ZFS_ENTER(zfsvfs);
350789Sahrens 
351789Sahrens 	if (fidp->fid_len < SHORT_FID_LEN) {
352789Sahrens 		fidp->fid_len = SHORT_FID_LEN;
3531512Sek110237 		ZFS_EXIT(zfsvfs);
354789Sahrens 		return (ENOSPC);
355789Sahrens 	}
356789Sahrens 
357789Sahrens 	zfid = (zfid_short_t *)fidp;
358789Sahrens 
359789Sahrens 	zfid->zf_len = SHORT_FID_LEN;
360789Sahrens 
361789Sahrens 	for (i = 0; i < sizeof (zfid->zf_object); i++)
362789Sahrens 		zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
363789Sahrens 
364789Sahrens 	/* .zfs znodes always have a generation number of 0 */
365789Sahrens 	for (i = 0; i < sizeof (zfid->zf_gen); i++)
366789Sahrens 		zfid->zf_gen[i] = 0;
367789Sahrens 
368789Sahrens 	ZFS_EXIT(zfsvfs);
369789Sahrens 	return (0);
370789Sahrens }
371789Sahrens 
3728845Samw@Sun.COM 
3738845Samw@Sun.COM /*ARGSUSED*/
3748845Samw@Sun.COM static int
3758845Samw@Sun.COM zfsctl_shares_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
3768845Samw@Sun.COM {
3778845Samw@Sun.COM 	zfsvfs_t	*zfsvfs = vp->v_vfsp->vfs_data;
3788845Samw@Sun.COM 	znode_t		*dzp;
3798845Samw@Sun.COM 	int		error;
3808845Samw@Sun.COM 
3818845Samw@Sun.COM 	ZFS_ENTER(zfsvfs);
3829030SMark.Shellenbaum@Sun.COM 
3839030SMark.Shellenbaum@Sun.COM 	if (zfsvfs->z_shares_dir == 0) {
3849030SMark.Shellenbaum@Sun.COM 		ZFS_EXIT(zfsvfs);
3859030SMark.Shellenbaum@Sun.COM 		return (ENOTSUP);
3869030SMark.Shellenbaum@Sun.COM 	}
3879030SMark.Shellenbaum@Sun.COM 
3888845Samw@Sun.COM 	if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
3898845Samw@Sun.COM 		error = VOP_FID(ZTOV(dzp), fidp, ct);
3908845Samw@Sun.COM 		VN_RELE(ZTOV(dzp));
3918845Samw@Sun.COM 	}
3928845Samw@Sun.COM 
3938845Samw@Sun.COM 	ZFS_EXIT(zfsvfs);
3948845Samw@Sun.COM 	return (error);
3958845Samw@Sun.COM }
396789Sahrens /*
397789Sahrens  * .zfs inode namespace
398789Sahrens  *
399789Sahrens  * We need to generate unique inode numbers for all files and directories
400789Sahrens  * within the .zfs pseudo-filesystem.  We use the following scheme:
401789Sahrens  *
402789Sahrens  * 	ENTRY			ZFSCTL_INODE
403789Sahrens  * 	.zfs			1
404789Sahrens  * 	.zfs/snapshot		2
405789Sahrens  * 	.zfs/snapshot/<snap>	objectid(snap)
406789Sahrens  */
407789Sahrens 
408789Sahrens #define	ZFSCTL_INO_SNAP(id)	(id)
409789Sahrens 
410789Sahrens /*
411789Sahrens  * Get root directory attributes.
412789Sahrens  */
413789Sahrens /* ARGSUSED */
414789Sahrens static int
4155331Samw zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
4165331Samw     caller_context_t *ct)
417789Sahrens {
418789Sahrens 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
419789Sahrens 
420789Sahrens 	ZFS_ENTER(zfsvfs);
421789Sahrens 	vap->va_nodeid = ZFSCTL_INO_ROOT;
422789Sahrens 	vap->va_nlink = vap->va_size = NROOT_ENTRIES;
423789Sahrens 
424789Sahrens 	zfsctl_common_getattr(vp, vap);
425789Sahrens 	ZFS_EXIT(zfsvfs);
426789Sahrens 
427789Sahrens 	return (0);
428789Sahrens }
429789Sahrens 
430789Sahrens /*
431789Sahrens  * Special case the handling of "..".
432789Sahrens  */
433789Sahrens /* ARGSUSED */
434789Sahrens int
435789Sahrens zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
4365331Samw     int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
4375331Samw     int *direntflags, pathname_t *realpnp)
438789Sahrens {
439789Sahrens 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
440789Sahrens 	int err;
441789Sahrens 
4425331Samw 	/*
4435331Samw 	 * No extended attributes allowed under .zfs
4445331Samw 	 */
4455331Samw 	if (flags & LOOKUP_XATTR)
4465331Samw 		return (EINVAL);
4475331Samw 
448789Sahrens 	ZFS_ENTER(zfsvfs);
449789Sahrens 
450789Sahrens 	if (strcmp(nm, "..") == 0) {
451789Sahrens 		err = VFS_ROOT(dvp->v_vfsp, vpp);
452789Sahrens 	} else {
4536492Stimh 		err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir,
4546492Stimh 		    cr, ct, direntflags, realpnp);
455789Sahrens 	}
456789Sahrens 
457789Sahrens 	ZFS_EXIT(zfsvfs);
458789Sahrens 
459789Sahrens 	return (err);
460789Sahrens }
461789Sahrens 
4628547SMark.Shellenbaum@Sun.COM static int
4638547SMark.Shellenbaum@Sun.COM zfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
4648547SMark.Shellenbaum@Sun.COM     caller_context_t *ct)
4658547SMark.Shellenbaum@Sun.COM {
4668547SMark.Shellenbaum@Sun.COM 	/*
4678547SMark.Shellenbaum@Sun.COM 	 * We only care about ACL_ENABLED so that libsec can
4688547SMark.Shellenbaum@Sun.COM 	 * display ACL correctly and not default to POSIX draft.
4698547SMark.Shellenbaum@Sun.COM 	 */
4708547SMark.Shellenbaum@Sun.COM 	if (cmd == _PC_ACL_ENABLED) {
4718547SMark.Shellenbaum@Sun.COM 		*valp = _ACL_ACE_ENABLED;
4728547SMark.Shellenbaum@Sun.COM 		return (0);
4738547SMark.Shellenbaum@Sun.COM 	}
4748547SMark.Shellenbaum@Sun.COM 
4758547SMark.Shellenbaum@Sun.COM 	return (fs_pathconf(vp, cmd, valp, cr, ct));
4768547SMark.Shellenbaum@Sun.COM }
4778547SMark.Shellenbaum@Sun.COM 
478789Sahrens static const fs_operation_def_t zfsctl_tops_root[] = {
4793898Srsb 	{ VOPNAME_OPEN,		{ .vop_open = zfsctl_common_open }	},
4803898Srsb 	{ VOPNAME_CLOSE,	{ .vop_close = zfsctl_common_close }	},
4813898Srsb 	{ VOPNAME_IOCTL,	{ .error = fs_inval }			},
4823898Srsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = zfsctl_root_getattr }	},
4833898Srsb 	{ VOPNAME_ACCESS,	{ .vop_access = zfsctl_common_access }	},
4843898Srsb 	{ VOPNAME_READDIR,	{ .vop_readdir = gfs_vop_readdir } 	},
4853898Srsb 	{ VOPNAME_LOOKUP,	{ .vop_lookup = zfsctl_root_lookup }	},
4863898Srsb 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek }			},
4873898Srsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = gfs_vop_inactive }	},
4888547SMark.Shellenbaum@Sun.COM 	{ VOPNAME_PATHCONF,	{ .vop_pathconf = zfsctl_pathconf }	},
4893898Srsb 	{ VOPNAME_FID,		{ .vop_fid = zfsctl_common_fid	}	},
490789Sahrens 	{ NULL }
491789Sahrens };
492789Sahrens 
493789Sahrens static int
494789Sahrens zfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname)
495789Sahrens {
496789Sahrens 	objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os;
497789Sahrens 
4986658Smarks 	if (snapshot_namecheck(name, NULL, NULL) != 0)
4996658Smarks 		return (EILSEQ);
500789Sahrens 	dmu_objset_name(os, zname);
5011154Smaybee 	if (strlen(zname) + 1 + strlen(name) >= len)
5021154Smaybee 		return (ENAMETOOLONG);
503789Sahrens 	(void) strcat(zname, "@");
504789Sahrens 	(void) strcat(zname, name);
505789Sahrens 	return (0);
506789Sahrens }
507789Sahrens 
5086068Sck153898 static int
5096068Sck153898 zfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr)
510789Sahrens {
5116068Sck153898 	vnode_t *svp = sep->se_root;
5126068Sck153898 	int error;
513789Sahrens 
5146068Sck153898 	ASSERT(vn_ismntpt(svp));
515789Sahrens 
516789Sahrens 	/* this will be dropped by dounmount() */
5176068Sck153898 	if ((error = vn_vfswlock(svp)) != 0)
5186068Sck153898 		return (error);
519789Sahrens 
5206068Sck153898 	VN_HOLD(svp);
5216068Sck153898 	error = dounmount(vn_mountedvfs(svp), fflags, cr);
5226068Sck153898 	if (error) {
5236068Sck153898 		VN_RELE(svp);
5246068Sck153898 		return (error);
5251589Smaybee 	}
5269214Schris.kirby@sun.com 
5276068Sck153898 	/*
5286068Sck153898 	 * We can't use VN_RELE(), as that will try to invoke
5296068Sck153898 	 * zfsctl_snapdir_inactive(), which would cause us to destroy
5306068Sck153898 	 * the sd_lock mutex held by our caller.
5316068Sck153898 	 */
5326068Sck153898 	ASSERT(svp->v_count == 1);
5336068Sck153898 	gfs_vop_inactive(svp, cr, NULL);
534789Sahrens 
535789Sahrens 	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
536789Sahrens 	kmem_free(sep, sizeof (zfs_snapentry_t));
537789Sahrens 
538789Sahrens 	return (0);
539789Sahrens }
540789Sahrens 
5411154Smaybee static void
542789Sahrens zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
543789Sahrens {
544789Sahrens 	avl_index_t where;
545789Sahrens 	vfs_t *vfsp;
546789Sahrens 	refstr_t *pathref;
547789Sahrens 	char newpath[MAXNAMELEN];
548789Sahrens 	char *tail;
549789Sahrens 
550789Sahrens 	ASSERT(MUTEX_HELD(&sdp->sd_lock));
551789Sahrens 	ASSERT(sep != NULL);
552789Sahrens 
553789Sahrens 	vfsp = vn_mountedvfs(sep->se_root);
554789Sahrens 	ASSERT(vfsp != NULL);
555789Sahrens 
5561154Smaybee 	vfs_lock_wait(vfsp);
557789Sahrens 
558789Sahrens 	/*
559789Sahrens 	 * Change the name in the AVL tree.
560789Sahrens 	 */
561789Sahrens 	avl_remove(&sdp->sd_snaps, sep);
562789Sahrens 	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
563789Sahrens 	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
564789Sahrens 	(void) strcpy(sep->se_name, nm);
565789Sahrens 	VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL);
566789Sahrens 	avl_insert(&sdp->sd_snaps, sep, where);
567789Sahrens 
568789Sahrens 	/*
569789Sahrens 	 * Change the current mountpoint info:
570789Sahrens 	 * 	- update the tail of the mntpoint path
571789Sahrens 	 *	- update the tail of the resource path
572789Sahrens 	 */
573789Sahrens 	pathref = vfs_getmntpoint(vfsp);
5742417Sahrens 	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
5752417Sahrens 	VERIFY((tail = strrchr(newpath, '/')) != NULL);
5762417Sahrens 	*(tail+1) = '\0';
5772417Sahrens 	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
578789Sahrens 	(void) strcat(newpath, nm);
579789Sahrens 	refstr_rele(pathref);
580789Sahrens 	vfs_setmntpoint(vfsp, newpath);
581789Sahrens 
582789Sahrens 	pathref = vfs_getresource(vfsp);
5832417Sahrens 	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
5842417Sahrens 	VERIFY((tail = strrchr(newpath, '@')) != NULL);
5852417Sahrens 	*(tail+1) = '\0';
5862417Sahrens 	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
587789Sahrens 	(void) strcat(newpath, nm);
588789Sahrens 	refstr_rele(pathref);
589789Sahrens 	vfs_setresource(vfsp, newpath);
590789Sahrens 
591789Sahrens 	vfs_unlock(vfsp);
592789Sahrens }
593789Sahrens 
5945331Samw /*ARGSUSED*/
595789Sahrens static int
596789Sahrens zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
5975331Samw     cred_t *cr, caller_context_t *ct, int flags)
598789Sahrens {
599789Sahrens 	zfsctl_snapdir_t *sdp = sdvp->v_data;
600789Sahrens 	zfs_snapentry_t search, *sep;
6016492Stimh 	zfsvfs_t *zfsvfs;
602789Sahrens 	avl_index_t where;
603789Sahrens 	char from[MAXNAMELEN], to[MAXNAMELEN];
6046492Stimh 	char real[MAXNAMELEN];
605789Sahrens 	int err;
606789Sahrens 
6076492Stimh 	zfsvfs = sdvp->v_vfsp->vfs_data;
6086492Stimh 	ZFS_ENTER(zfsvfs);
6096492Stimh 
6106492Stimh 	if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) {
6116492Stimh 		err = dmu_snapshot_realname(zfsvfs->z_os, snm, real,
6126492Stimh 		    MAXNAMELEN, NULL);
6136492Stimh 		if (err == 0) {
6146492Stimh 			snm = real;
6156492Stimh 		} else if (err != ENOTSUP) {
6166492Stimh 			ZFS_EXIT(zfsvfs);
6176492Stimh 			return (err);
6186492Stimh 		}
6196492Stimh 	}
6206492Stimh 
6216492Stimh 	ZFS_EXIT(zfsvfs);
6226492Stimh 
6231154Smaybee 	err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from);
6246492Stimh 	if (!err)
6256492Stimh 		err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to);
6266492Stimh 	if (!err)
6276492Stimh 		err = zfs_secpolicy_rename_perms(from, to, cr);
6281154Smaybee 	if (err)
6291154Smaybee 		return (err);
6304543Smarks 
631789Sahrens 	/*
632789Sahrens 	 * Cannot move snapshots out of the snapdir.
633789Sahrens 	 */
634789Sahrens 	if (sdvp != tdvp)
635789Sahrens 		return (EINVAL);
636789Sahrens 
637789Sahrens 	if (strcmp(snm, tnm) == 0)
638789Sahrens 		return (0);
639789Sahrens 
640789Sahrens 	mutex_enter(&sdp->sd_lock);
641789Sahrens 
642789Sahrens 	search.se_name = (char *)snm;
6431154Smaybee 	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) {
6441154Smaybee 		mutex_exit(&sdp->sd_lock);
6451154Smaybee 		return (ENOENT);
646789Sahrens 	}
647789Sahrens 
6484007Smmusante 	err = dmu_objset_rename(from, to, B_FALSE);
6491154Smaybee 	if (err == 0)
6501154Smaybee 		zfsctl_rename_snap(sdp, sep, tnm);
651789Sahrens 
652789Sahrens 	mutex_exit(&sdp->sd_lock);
653789Sahrens 
654789Sahrens 	return (err);
655789Sahrens }
656789Sahrens 
657789Sahrens /* ARGSUSED */
658789Sahrens static int
6595331Samw zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
6605331Samw     caller_context_t *ct, int flags)
661789Sahrens {
662789Sahrens 	zfsctl_snapdir_t *sdp = dvp->v_data;
6636068Sck153898 	zfs_snapentry_t *sep;
6646068Sck153898 	zfs_snapentry_t search;
6656492Stimh 	zfsvfs_t *zfsvfs;
666789Sahrens 	char snapname[MAXNAMELEN];
6676492Stimh 	char real[MAXNAMELEN];
668789Sahrens 	int err;
669789Sahrens 
6706492Stimh 	zfsvfs = dvp->v_vfsp->vfs_data;
6716492Stimh 	ZFS_ENTER(zfsvfs);
6726492Stimh 
6736492Stimh 	if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) {
6746492Stimh 
6756492Stimh 		err = dmu_snapshot_realname(zfsvfs->z_os, name, real,
6766492Stimh 		    MAXNAMELEN, NULL);
6776492Stimh 		if (err == 0) {
6786492Stimh 			name = real;
6796492Stimh 		} else if (err != ENOTSUP) {
6806492Stimh 			ZFS_EXIT(zfsvfs);
6816492Stimh 			return (err);
6826492Stimh 		}
6836492Stimh 	}
6846492Stimh 
6856492Stimh 	ZFS_EXIT(zfsvfs);
6866492Stimh 
6871154Smaybee 	err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname);
6886492Stimh 	if (!err)
6896492Stimh 		err = zfs_secpolicy_destroy_perms(snapname, cr);
6901154Smaybee 	if (err)
6911154Smaybee 		return (err);
6924543Smarks 
693789Sahrens 	mutex_enter(&sdp->sd_lock);
694789Sahrens 
6956068Sck153898 	search.se_name = name;
6966068Sck153898 	sep = avl_find(&sdp->sd_snaps, &search, NULL);
6976068Sck153898 	if (sep) {
6986068Sck153898 		avl_remove(&sdp->sd_snaps, sep);
6996068Sck153898 		err = zfsctl_unmount_snap(sep, MS_FORCE, cr);
7006068Sck153898 		if (err)
7016068Sck153898 			avl_add(&sdp->sd_snaps, sep);
7026068Sck153898 		else
70310242Schris.kirby@sun.com 			err = dmu_objset_destroy(snapname, B_FALSE);
7046068Sck153898 	} else {
7056068Sck153898 		err = ENOENT;
706789Sahrens 	}
707789Sahrens 
708789Sahrens 	mutex_exit(&sdp->sd_lock);
709789Sahrens 
710789Sahrens 	return (err);
711789Sahrens }
712789Sahrens 
7135326Sek110237 /*
7145326Sek110237  * This creates a snapshot under '.zfs/snapshot'.
7155326Sek110237  */
7164543Smarks /* ARGSUSED */
7174543Smarks static int
7184543Smarks zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t  **vpp,
7195331Samw     cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp)
7204543Smarks {
7214543Smarks 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
7224543Smarks 	char name[MAXNAMELEN];
7234543Smarks 	int err;
7244543Smarks 	static enum symfollow follow = NO_FOLLOW;
7254543Smarks 	static enum uio_seg seg = UIO_SYSSPACE;
7264543Smarks 
7276658Smarks 	if (snapshot_namecheck(dirname, NULL, NULL) != 0)
7286658Smarks 		return (EILSEQ);
7296658Smarks 
7304543Smarks 	dmu_objset_name(zfsvfs->z_os, name);
7314543Smarks 
7324543Smarks 	*vpp = NULL;
7334543Smarks 
7344543Smarks 	err = zfs_secpolicy_snapshot_perms(name, cr);
7354543Smarks 	if (err)
7364543Smarks 		return (err);
7374543Smarks 
7384543Smarks 	if (err == 0) {
7399355SMatthew.Ahrens@Sun.COM 		err = dmu_objset_snapshot(name, dirname, NULL, B_FALSE);
7404543Smarks 		if (err)
7414543Smarks 			return (err);
7424543Smarks 		err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp);
7434543Smarks 	}
7444543Smarks 
7454543Smarks 	return (err);
7464543Smarks }
7474543Smarks 
748789Sahrens /*
749789Sahrens  * Lookup entry point for the 'snapshot' directory.  Try to open the
750789Sahrens  * snapshot if it exist, creating the pseudo filesystem vnode as necessary.
751789Sahrens  * Perform a mount of the associated dataset on top of the vnode.
752789Sahrens  */
753789Sahrens /* ARGSUSED */
754789Sahrens static int
755789Sahrens zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
7565331Samw     int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
7575331Samw     int *direntflags, pathname_t *realpnp)
758789Sahrens {
759789Sahrens 	zfsctl_snapdir_t *sdp = dvp->v_data;
760789Sahrens 	objset_t *snap;
761789Sahrens 	char snapname[MAXNAMELEN];
7626492Stimh 	char real[MAXNAMELEN];
763789Sahrens 	char *mountpoint;
764789Sahrens 	zfs_snapentry_t *sep, search;
765789Sahrens 	struct mounta margs;
766789Sahrens 	vfs_t *vfsp;
767789Sahrens 	size_t mountpoint_len;
768789Sahrens 	avl_index_t where;
769789Sahrens 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
770789Sahrens 	int err;
771789Sahrens 
7725331Samw 	/*
7735331Samw 	 * No extended attributes allowed under .zfs
7745331Samw 	 */
7755331Samw 	if (flags & LOOKUP_XATTR)
7765331Samw 		return (EINVAL);
7775331Samw 
778789Sahrens 	ASSERT(dvp->v_type == VDIR);
779789Sahrens 
780789Sahrens 	/*
781789Sahrens 	 * If we get a recursive call, that means we got called
782789Sahrens 	 * from the domount() code while it was trying to look up the
783789Sahrens 	 * spec (which looks like a local path for zfs).  We need to
784789Sahrens 	 * add some flag to domount() to tell it not to do this lookup.
785789Sahrens 	 */
786789Sahrens 	if (MUTEX_HELD(&sdp->sd_lock))
787789Sahrens 		return (ENOENT);
788789Sahrens 
789789Sahrens 	ZFS_ENTER(zfsvfs);
790789Sahrens 
7919214Schris.kirby@sun.com 	if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) {
7929214Schris.kirby@sun.com 		ZFS_EXIT(zfsvfs);
7939214Schris.kirby@sun.com 		return (0);
7949214Schris.kirby@sun.com 	}
7959214Schris.kirby@sun.com 
7966492Stimh 	if (flags & FIGNORECASE) {
7976492Stimh 		boolean_t conflict = B_FALSE;
7986492Stimh 
7996492Stimh 		err = dmu_snapshot_realname(zfsvfs->z_os, nm, real,
8006492Stimh 		    MAXNAMELEN, &conflict);
8016492Stimh 		if (err == 0) {
8026492Stimh 			nm = real;
8036492Stimh 		} else if (err != ENOTSUP) {
8046492Stimh 			ZFS_EXIT(zfsvfs);
8056492Stimh 			return (err);
8066492Stimh 		}
8076492Stimh 		if (realpnp)
8086492Stimh 			(void) strlcpy(realpnp->pn_buf, nm,
8096492Stimh 			    realpnp->pn_bufsize);
8106492Stimh 		if (conflict && direntflags)
8116492Stimh 			*direntflags = ED_CASE_CONFLICT;
8126492Stimh 	}
8136492Stimh 
814789Sahrens 	mutex_enter(&sdp->sd_lock);
815789Sahrens 	search.se_name = (char *)nm;
816789Sahrens 	if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) {
817789Sahrens 		*vpp = sep->se_root;
818789Sahrens 		VN_HOLD(*vpp);
8191589Smaybee 		err = traverse(vpp);
8201589Smaybee 		if (err) {
8211589Smaybee 			VN_RELE(*vpp);
8221589Smaybee 			*vpp = NULL;
8231589Smaybee 		} else if (*vpp == sep->se_root) {
8241589Smaybee 			/*
8251589Smaybee 			 * The snapshot was unmounted behind our backs,
8261589Smaybee 			 * try to remount it.
8271589Smaybee 			 */
828789Sahrens 			goto domount;
8296068Sck153898 		} else {
8306068Sck153898 			/*
8316068Sck153898 			 * VROOT was set during the traverse call.  We need
8326068Sck153898 			 * to clear it since we're pretending to be part
8336068Sck153898 			 * of our parent's vfs.
8346068Sck153898 			 */
8356068Sck153898 			(*vpp)->v_flag &= ~VROOT;
8361566Smaybee 		}
837789Sahrens 		mutex_exit(&sdp->sd_lock);
838789Sahrens 		ZFS_EXIT(zfsvfs);
8391589Smaybee 		return (err);
840789Sahrens 	}
841789Sahrens 
842789Sahrens 	/*
843789Sahrens 	 * The requested snapshot is not currently mounted, look it up.
844789Sahrens 	 */
8451154Smaybee 	err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname);
8461154Smaybee 	if (err) {
8471154Smaybee 		mutex_exit(&sdp->sd_lock);
8481154Smaybee 		ZFS_EXIT(zfsvfs);
8497229Smarks 		/*
8507229Smarks 		 * handle "ls *" or "?" in a graceful manner,
8517229Smarks 		 * forcing EILSEQ to ENOENT.
8527229Smarks 		 * Since shell ultimately passes "*" or "?" as name to lookup
8537229Smarks 		 */
8547229Smarks 		return (err == EILSEQ ? ENOENT : err);
8551154Smaybee 	}
856*10298SMatthew.Ahrens@Sun.COM 	if (dmu_objset_hold(snapname, FTAG, &snap) != 0) {
857789Sahrens 		mutex_exit(&sdp->sd_lock);
858789Sahrens 		ZFS_EXIT(zfsvfs);
859789Sahrens 		return (ENOENT);
860789Sahrens 	}
861789Sahrens 
862789Sahrens 	sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP);
863789Sahrens 	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
864789Sahrens 	(void) strcpy(sep->se_name, nm);
865789Sahrens 	*vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap));
866789Sahrens 	avl_insert(&sdp->sd_snaps, sep, where);
867789Sahrens 
868*10298SMatthew.Ahrens@Sun.COM 	dmu_objset_rele(snap, FTAG);
869789Sahrens domount:
870789Sahrens 	mountpoint_len = strlen(refstr_value(dvp->v_vfsp->vfs_mntpt)) +
871789Sahrens 	    strlen("/.zfs/snapshot/") + strlen(nm) + 1;
872789Sahrens 	mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP);
873789Sahrens 	(void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s",
874789Sahrens 	    refstr_value(dvp->v_vfsp->vfs_mntpt), nm);
875789Sahrens 
876789Sahrens 	margs.spec = snapname;
877789Sahrens 	margs.dir = mountpoint;
878789Sahrens 	margs.flags = MS_SYSSPACE | MS_NOMNTTAB;
879789Sahrens 	margs.fstype = "zfs";
880789Sahrens 	margs.dataptr = NULL;
881789Sahrens 	margs.datalen = 0;
882789Sahrens 	margs.optptr = NULL;
883789Sahrens 	margs.optlen = 0;
884789Sahrens 
885789Sahrens 	err = domount("zfs", &margs, *vpp, kcred, &vfsp);
886789Sahrens 	kmem_free(mountpoint, mountpoint_len);
887789Sahrens 
888816Smaybee 	if (err == 0) {
889816Smaybee 		/*
890816Smaybee 		 * Return the mounted root rather than the covered mount point.
8915326Sek110237 		 * Takes the GFS vnode at .zfs/snapshot/<snapname> and returns
8925326Sek110237 		 * the ZFS vnode mounted on top of the GFS node.  This ZFS
8939214Schris.kirby@sun.com 		 * vnode is the root of the newly created vfsp.
894816Smaybee 		 */
895816Smaybee 		VFS_RELE(vfsp);
896816Smaybee 		err = traverse(vpp);
897816Smaybee 	}
898789Sahrens 
899816Smaybee 	if (err == 0) {
900816Smaybee 		/*
9015326Sek110237 		 * Fix up the root vnode mounted on .zfs/snapshot/<snapname>.
9024736Sek110237 		 *
9034736Sek110237 		 * This is where we lie about our v_vfsp in order to
9045326Sek110237 		 * make .zfs/snapshot/<snapname> accessible over NFS
9055326Sek110237 		 * without requiring manual mounts of <snapname>.
906816Smaybee 		 */
907816Smaybee 		ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs);
908816Smaybee 		VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs;
909816Smaybee 		(*vpp)->v_vfsp = zfsvfs->z_vfs;
910816Smaybee 		(*vpp)->v_flag &= ~VROOT;
911816Smaybee 	}
912789Sahrens 	mutex_exit(&sdp->sd_lock);
913789Sahrens 	ZFS_EXIT(zfsvfs);
914789Sahrens 
9151566Smaybee 	/*
9161566Smaybee 	 * If we had an error, drop our hold on the vnode and
9171566Smaybee 	 * zfsctl_snapshot_inactive() will clean up.
9181566Smaybee 	 */
9191566Smaybee 	if (err) {
920816Smaybee 		VN_RELE(*vpp);
9211566Smaybee 		*vpp = NULL;
9221566Smaybee 	}
923816Smaybee 	return (err);
924789Sahrens }
925789Sahrens 
926789Sahrens /* ARGSUSED */
927789Sahrens static int
9288845Samw@Sun.COM zfsctl_shares_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
9298845Samw@Sun.COM     int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
9308845Samw@Sun.COM     int *direntflags, pathname_t *realpnp)
9318845Samw@Sun.COM {
9328845Samw@Sun.COM 	zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
9338845Samw@Sun.COM 	znode_t *dzp;
9348845Samw@Sun.COM 	int error;
9358845Samw@Sun.COM 
9368845Samw@Sun.COM 	ZFS_ENTER(zfsvfs);
9378845Samw@Sun.COM 
9388845Samw@Sun.COM 	if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) {
9398845Samw@Sun.COM 		ZFS_EXIT(zfsvfs);
9408845Samw@Sun.COM 		return (0);
9418845Samw@Sun.COM 	}
9428845Samw@Sun.COM 
9439030SMark.Shellenbaum@Sun.COM 	if (zfsvfs->z_shares_dir == 0) {
9449030SMark.Shellenbaum@Sun.COM 		ZFS_EXIT(zfsvfs);
9459030SMark.Shellenbaum@Sun.COM 		return (ENOTSUP);
9469030SMark.Shellenbaum@Sun.COM 	}
9478845Samw@Sun.COM 	if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0)
9488845Samw@Sun.COM 		error = VOP_LOOKUP(ZTOV(dzp), nm, vpp, pnp,
9498845Samw@Sun.COM 		    flags, rdir, cr, ct, direntflags, realpnp);
9508845Samw@Sun.COM 
9518845Samw@Sun.COM 	VN_RELE(ZTOV(dzp));
9528845Samw@Sun.COM 	ZFS_EXIT(zfsvfs);
9538845Samw@Sun.COM 
9548845Samw@Sun.COM 	return (error);
9558845Samw@Sun.COM }
9568845Samw@Sun.COM 
9578845Samw@Sun.COM /* ARGSUSED */
9588845Samw@Sun.COM static int
9595663Sck153898 zfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp,
9605663Sck153898     offset_t *offp, offset_t *nextp, void *data, int flags)
961789Sahrens {
962789Sahrens 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
963789Sahrens 	char snapname[MAXNAMELEN];
964789Sahrens 	uint64_t id, cookie;
9655663Sck153898 	boolean_t case_conflict;
9665663Sck153898 	int error;
967789Sahrens 
968789Sahrens 	ZFS_ENTER(zfsvfs);
969789Sahrens 
970789Sahrens 	cookie = *offp;
9715663Sck153898 	error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
9725663Sck153898 	    &cookie, &case_conflict);
9735663Sck153898 	if (error) {
974789Sahrens 		ZFS_EXIT(zfsvfs);
9755663Sck153898 		if (error == ENOENT) {
9765663Sck153898 			*eofp = 1;
9775663Sck153898 			return (0);
9785663Sck153898 		}
9795663Sck153898 		return (error);
980789Sahrens 	}
981789Sahrens 
9825663Sck153898 	if (flags & V_RDDIR_ENTFLAGS) {
9835663Sck153898 		edirent_t *eodp = dp;
9845663Sck153898 
9855663Sck153898 		(void) strcpy(eodp->ed_name, snapname);
9865663Sck153898 		eodp->ed_ino = ZFSCTL_INO_SNAP(id);
9875663Sck153898 		eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0;
9885663Sck153898 	} else {
9895663Sck153898 		struct dirent64 *odp = dp;
9905663Sck153898 
9915663Sck153898 		(void) strcpy(odp->d_name, snapname);
9925663Sck153898 		odp->d_ino = ZFSCTL_INO_SNAP(id);
9935663Sck153898 	}
994789Sahrens 	*nextp = cookie;
995789Sahrens 
996789Sahrens 	ZFS_EXIT(zfsvfs);
997789Sahrens 
998789Sahrens 	return (0);
999789Sahrens }
1000789Sahrens 
10018845Samw@Sun.COM /* ARGSUSED */
10028845Samw@Sun.COM static int
10038845Samw@Sun.COM zfsctl_shares_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
10048845Samw@Sun.COM     caller_context_t *ct, int flags)
10058845Samw@Sun.COM {
10068845Samw@Sun.COM 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
10078845Samw@Sun.COM 	znode_t *dzp;
10088845Samw@Sun.COM 	int error;
10098845Samw@Sun.COM 
10108845Samw@Sun.COM 	ZFS_ENTER(zfsvfs);
10118845Samw@Sun.COM 
10129030SMark.Shellenbaum@Sun.COM 	if (zfsvfs->z_shares_dir == 0) {
10139030SMark.Shellenbaum@Sun.COM 		ZFS_EXIT(zfsvfs);
10149030SMark.Shellenbaum@Sun.COM 		return (ENOTSUP);
10159030SMark.Shellenbaum@Sun.COM 	}
10168845Samw@Sun.COM 	if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
10178845Samw@Sun.COM 		error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ct, flags);
10188845Samw@Sun.COM 		VN_RELE(ZTOV(dzp));
10198845Samw@Sun.COM 	} else {
10208845Samw@Sun.COM 		*eofp = 1;
10218845Samw@Sun.COM 		error = ENOENT;
10228845Samw@Sun.COM 	}
10238845Samw@Sun.COM 
10248845Samw@Sun.COM 	ZFS_EXIT(zfsvfs);
10258845Samw@Sun.COM 	return (error);
10268845Samw@Sun.COM }
10278845Samw@Sun.COM 
10285326Sek110237 /*
10295326Sek110237  * pvp is the '.zfs' directory (zfsctl_node_t).
10305326Sek110237  * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t).
10315326Sek110237  *
10325326Sek110237  * This function is the callback to create a GFS vnode for '.zfs/snapshot'
10335326Sek110237  * when a lookup is performed on .zfs for "snapshot".
10345326Sek110237  */
1035789Sahrens vnode_t *
1036789Sahrens zfsctl_mknode_snapdir(vnode_t *pvp)
1037789Sahrens {
1038789Sahrens 	vnode_t *vp;
1039789Sahrens 	zfsctl_snapdir_t *sdp;
1040789Sahrens 
1041789Sahrens 	vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp,
1042789Sahrens 	    zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN,
1043789Sahrens 	    zfsctl_snapdir_readdir_cb, NULL);
1044789Sahrens 	sdp = vp->v_data;
1045789Sahrens 	sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR;
10461571Sek110237 	sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
1047789Sahrens 	mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL);
1048789Sahrens 	avl_create(&sdp->sd_snaps, snapentry_compare,
1049789Sahrens 	    sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node));
1050789Sahrens 	return (vp);
1051789Sahrens }
1052789Sahrens 
10538845Samw@Sun.COM vnode_t *
10548845Samw@Sun.COM zfsctl_mknode_shares(vnode_t *pvp)
10558845Samw@Sun.COM {
10568845Samw@Sun.COM 	vnode_t *vp;
10578845Samw@Sun.COM 	zfsctl_node_t *sdp;
10588845Samw@Sun.COM 
10598845Samw@Sun.COM 	vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp,
10608845Samw@Sun.COM 	    zfsctl_ops_shares, NULL, NULL, MAXNAMELEN,
10618845Samw@Sun.COM 	    NULL, NULL);
10628845Samw@Sun.COM 	sdp = vp->v_data;
10638845Samw@Sun.COM 	sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
10648845Samw@Sun.COM 	return (vp);
10658845Samw@Sun.COM 
10668845Samw@Sun.COM }
10678845Samw@Sun.COM 
10688845Samw@Sun.COM /* ARGSUSED */
10698845Samw@Sun.COM static int
10708845Samw@Sun.COM zfsctl_shares_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
10718845Samw@Sun.COM     caller_context_t *ct)
10728845Samw@Sun.COM {
10738845Samw@Sun.COM 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
10748845Samw@Sun.COM 	znode_t *dzp;
10758845Samw@Sun.COM 	int error;
10768845Samw@Sun.COM 
10778845Samw@Sun.COM 	ZFS_ENTER(zfsvfs);
10789030SMark.Shellenbaum@Sun.COM 	if (zfsvfs->z_shares_dir == 0) {
10799030SMark.Shellenbaum@Sun.COM 		ZFS_EXIT(zfsvfs);
10809030SMark.Shellenbaum@Sun.COM 		return (ENOTSUP);
10819030SMark.Shellenbaum@Sun.COM 	}
10828845Samw@Sun.COM 	if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
10838845Samw@Sun.COM 		error = VOP_GETATTR(ZTOV(dzp), vap, flags, cr, ct);
10848845Samw@Sun.COM 		VN_RELE(ZTOV(dzp));
10858845Samw@Sun.COM 	}
10868845Samw@Sun.COM 	ZFS_EXIT(zfsvfs);
10878845Samw@Sun.COM 	return (error);
10888845Samw@Sun.COM 
10898845Samw@Sun.COM 
10908845Samw@Sun.COM }
10918845Samw@Sun.COM 
1092789Sahrens /* ARGSUSED */
1093789Sahrens static int
10945331Samw zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
10955331Samw     caller_context_t *ct)
1096789Sahrens {
1097789Sahrens 	zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
1098789Sahrens 	zfsctl_snapdir_t *sdp = vp->v_data;
1099789Sahrens 
1100789Sahrens 	ZFS_ENTER(zfsvfs);
1101789Sahrens 	zfsctl_common_getattr(vp, vap);
1102789Sahrens 	vap->va_nodeid = gfs_file_inode(vp);
1103789Sahrens 	vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2;
1104789Sahrens 	ZFS_EXIT(zfsvfs);
1105789Sahrens 
1106789Sahrens 	return (0);
1107789Sahrens }
1108789Sahrens 
11091566Smaybee /* ARGSUSED */
1110789Sahrens static void
11115331Samw zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1112789Sahrens {
1113789Sahrens 	zfsctl_snapdir_t *sdp = vp->v_data;
11141566Smaybee 	void *private;
1115789Sahrens 
11161566Smaybee 	private = gfs_dir_inactive(vp);
11171566Smaybee 	if (private != NULL) {
11181566Smaybee 		ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
11191566Smaybee 		mutex_destroy(&sdp->sd_lock);
11201566Smaybee 		avl_destroy(&sdp->sd_snaps);
11211566Smaybee 		kmem_free(private, sizeof (zfsctl_snapdir_t));
11221566Smaybee 	}
1123789Sahrens }
1124789Sahrens 
1125789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[] = {
11263898Srsb 	{ VOPNAME_OPEN,		{ .vop_open = zfsctl_common_open }	},
11273898Srsb 	{ VOPNAME_CLOSE,	{ .vop_close = zfsctl_common_close }	},
11283898Srsb 	{ VOPNAME_IOCTL,	{ .error = fs_inval }			},
11293898Srsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = zfsctl_snapdir_getattr } },
11303898Srsb 	{ VOPNAME_ACCESS,	{ .vop_access = zfsctl_common_access }	},
11313898Srsb 	{ VOPNAME_RENAME,	{ .vop_rename = zfsctl_snapdir_rename }	},
11323898Srsb 	{ VOPNAME_RMDIR,	{ .vop_rmdir = zfsctl_snapdir_remove }	},
11334543Smarks 	{ VOPNAME_MKDIR,	{ .vop_mkdir = zfsctl_snapdir_mkdir }	},
11343898Srsb 	{ VOPNAME_READDIR,	{ .vop_readdir = gfs_vop_readdir }	},
11353898Srsb 	{ VOPNAME_LOOKUP,	{ .vop_lookup = zfsctl_snapdir_lookup }	},
11363898Srsb 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek }			},
11373898Srsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = zfsctl_snapdir_inactive } },
11383898Srsb 	{ VOPNAME_FID,		{ .vop_fid = zfsctl_common_fid }	},
1139789Sahrens 	{ NULL }
1140789Sahrens };
1141789Sahrens 
11428845Samw@Sun.COM static const fs_operation_def_t zfsctl_tops_shares[] = {
11438845Samw@Sun.COM 	{ VOPNAME_OPEN,		{ .vop_open = zfsctl_common_open }	},
11448845Samw@Sun.COM 	{ VOPNAME_CLOSE,	{ .vop_close = zfsctl_common_close }	},
11458845Samw@Sun.COM 	{ VOPNAME_IOCTL,	{ .error = fs_inval }			},
11468845Samw@Sun.COM 	{ VOPNAME_GETATTR,	{ .vop_getattr = zfsctl_shares_getattr } },
11478845Samw@Sun.COM 	{ VOPNAME_ACCESS,	{ .vop_access = zfsctl_common_access }	},
11488845Samw@Sun.COM 	{ VOPNAME_READDIR,	{ .vop_readdir = zfsctl_shares_readdir } },
11498845Samw@Sun.COM 	{ VOPNAME_LOOKUP,	{ .vop_lookup = zfsctl_shares_lookup }	},
11508845Samw@Sun.COM 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek }			},
11518845Samw@Sun.COM 	{ VOPNAME_INACTIVE,	{ .vop_inactive = gfs_vop_inactive } },
11528845Samw@Sun.COM 	{ VOPNAME_FID,		{ .vop_fid = zfsctl_shares_fid } },
11538845Samw@Sun.COM 	{ NULL }
11548845Samw@Sun.COM };
11558845Samw@Sun.COM 
11565326Sek110237 /*
11575326Sek110237  * pvp is the GFS vnode '.zfs/snapshot'.
11585326Sek110237  *
11595326Sek110237  * This creates a GFS node under '.zfs/snapshot' representing each
11605326Sek110237  * snapshot.  This newly created GFS node is what we mount snapshot
11615326Sek110237  * vfs_t's ontop of.
11625326Sek110237  */
1163789Sahrens static vnode_t *
1164789Sahrens zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
1165789Sahrens {
1166789Sahrens 	vnode_t *vp;
1167789Sahrens 	zfsctl_node_t *zcp;
1168789Sahrens 
1169789Sahrens 	vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp,
1170789Sahrens 	    zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL);
1171789Sahrens 	zcp = vp->v_data;
1172789Sahrens 	zcp->zc_id = objset;
1173789Sahrens 
1174789Sahrens 	return (vp);
1175789Sahrens }
1176789Sahrens 
1177789Sahrens static void
11785331Samw zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1179789Sahrens {
1180789Sahrens 	zfsctl_snapdir_t *sdp;
1181789Sahrens 	zfs_snapentry_t *sep, *next;
1182789Sahrens 	vnode_t *dvp;
1183789Sahrens 
11846492Stimh 	VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0);
1185789Sahrens 	sdp = dvp->v_data;
1186789Sahrens 
1187789Sahrens 	mutex_enter(&sdp->sd_lock);
1188789Sahrens 
1189789Sahrens 	if (vp->v_count > 1) {
1190789Sahrens 		mutex_exit(&sdp->sd_lock);
1191789Sahrens 		return;
1192789Sahrens 	}
1193789Sahrens 	ASSERT(!vn_ismntpt(vp));
1194789Sahrens 
1195789Sahrens 	sep = avl_first(&sdp->sd_snaps);
1196789Sahrens 	while (sep != NULL) {
1197789Sahrens 		next = AVL_NEXT(&sdp->sd_snaps, sep);
1198789Sahrens 
1199789Sahrens 		if (sep->se_root == vp) {
1200789Sahrens 			avl_remove(&sdp->sd_snaps, sep);
1201789Sahrens 			kmem_free(sep->se_name, strlen(sep->se_name) + 1);
1202789Sahrens 			kmem_free(sep, sizeof (zfs_snapentry_t));
1203789Sahrens 			break;
1204789Sahrens 		}
1205789Sahrens 		sep = next;
1206789Sahrens 	}
1207789Sahrens 	ASSERT(sep != NULL);
1208789Sahrens 
1209789Sahrens 	mutex_exit(&sdp->sd_lock);
1210789Sahrens 	VN_RELE(dvp);
1211789Sahrens 
12121566Smaybee 	/*
12131566Smaybee 	 * Dispose of the vnode for the snapshot mount point.
12141566Smaybee 	 * This is safe to do because once this entry has been removed
12151566Smaybee 	 * from the AVL tree, it can't be found again, so cannot become
12161566Smaybee 	 * "active".  If we lookup the same name again we will end up
12171566Smaybee 	 * creating a new vnode.
12181566Smaybee 	 */
12195331Samw 	gfs_vop_inactive(vp, cr, ct);
1220789Sahrens }
1221789Sahrens 
1222789Sahrens 
1223789Sahrens /*
1224789Sahrens  * These VP's should never see the light of day.  They should always
1225789Sahrens  * be covered.
1226789Sahrens  */
1227789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[] = {
12283898Srsb 	VOPNAME_INACTIVE, { .vop_inactive =  zfsctl_snapshot_inactive },
1229789Sahrens 	NULL, NULL
1230789Sahrens };
1231789Sahrens 
1232789Sahrens int
1233789Sahrens zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
1234789Sahrens {
1235789Sahrens 	zfsvfs_t *zfsvfs = vfsp->vfs_data;
1236789Sahrens 	vnode_t *dvp, *vp;
1237789Sahrens 	zfsctl_snapdir_t *sdp;
1238789Sahrens 	zfsctl_node_t *zcp;
1239789Sahrens 	zfs_snapentry_t *sep;
1240789Sahrens 	int error;
1241789Sahrens 
1242789Sahrens 	ASSERT(zfsvfs->z_ctldir != NULL);
1243789Sahrens 	error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
12445331Samw 	    NULL, 0, NULL, kcred, NULL, NULL, NULL);
1245789Sahrens 	if (error != 0)
1246789Sahrens 		return (error);
1247789Sahrens 	sdp = dvp->v_data;
1248789Sahrens 
1249789Sahrens 	mutex_enter(&sdp->sd_lock);
1250789Sahrens 	sep = avl_first(&sdp->sd_snaps);
1251789Sahrens 	while (sep != NULL) {
1252789Sahrens 		vp = sep->se_root;
1253789Sahrens 		zcp = vp->v_data;
1254789Sahrens 		if (zcp->zc_id == objsetid)
1255789Sahrens 			break;
1256789Sahrens 
1257789Sahrens 		sep = AVL_NEXT(&sdp->sd_snaps, sep);
1258789Sahrens 	}
1259789Sahrens 
1260789Sahrens 	if (sep != NULL) {
1261789Sahrens 		VN_HOLD(vp);
12625326Sek110237 		/*
12635326Sek110237 		 * Return the mounted root rather than the covered mount point.
12645326Sek110237 		 * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid>
12655326Sek110237 		 * and returns the ZFS vnode mounted on top of the GFS node.
12665326Sek110237 		 * This ZFS vnode is the root of the vfs for objset 'objsetid'.
12675326Sek110237 		 */
1268789Sahrens 		error = traverse(&vp);
12691589Smaybee 		if (error == 0) {
12701589Smaybee 			if (vp == sep->se_root)
12711589Smaybee 				error = EINVAL;
12721589Smaybee 			else
12731589Smaybee 				*zfsvfsp = VTOZ(vp)->z_zfsvfs;
12741589Smaybee 		}
12751572Snd150628 		mutex_exit(&sdp->sd_lock);
1276789Sahrens 		VN_RELE(vp);
1277789Sahrens 	} else {
1278789Sahrens 		error = EINVAL;
12791572Snd150628 		mutex_exit(&sdp->sd_lock);
1280789Sahrens 	}
1281789Sahrens 
1282789Sahrens 	VN_RELE(dvp);
1283789Sahrens 
1284789Sahrens 	return (error);
1285789Sahrens }
1286789Sahrens 
1287789Sahrens /*
1288789Sahrens  * Unmount any snapshots for the given filesystem.  This is called from
1289789Sahrens  * zfs_umount() - if we have a ctldir, then go through and unmount all the
1290789Sahrens  * snapshots.
1291789Sahrens  */
1292789Sahrens int
1293789Sahrens zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
1294789Sahrens {
1295789Sahrens 	zfsvfs_t *zfsvfs = vfsp->vfs_data;
12966068Sck153898 	vnode_t *dvp;
1297789Sahrens 	zfsctl_snapdir_t *sdp;
1298789Sahrens 	zfs_snapentry_t *sep, *next;
1299789Sahrens 	int error;
1300789Sahrens 
1301789Sahrens 	ASSERT(zfsvfs->z_ctldir != NULL);
1302789Sahrens 	error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
13035331Samw 	    NULL, 0, NULL, cr, NULL, NULL, NULL);
1304789Sahrens 	if (error != 0)
1305789Sahrens 		return (error);
1306789Sahrens 	sdp = dvp->v_data;
1307789Sahrens 
1308789Sahrens 	mutex_enter(&sdp->sd_lock);
1309789Sahrens 
1310789Sahrens 	sep = avl_first(&sdp->sd_snaps);
1311789Sahrens 	while (sep != NULL) {
1312789Sahrens 		next = AVL_NEXT(&sdp->sd_snaps, sep);
1313789Sahrens 
1314789Sahrens 		/*
1315789Sahrens 		 * If this snapshot is not mounted, then it must
1316789Sahrens 		 * have just been unmounted by somebody else, and
1317789Sahrens 		 * will be cleaned up by zfsctl_snapdir_inactive().
1318789Sahrens 		 */
13196068Sck153898 		if (vn_ismntpt(sep->se_root)) {
13206068Sck153898 			avl_remove(&sdp->sd_snaps, sep);
13216068Sck153898 			error = zfsctl_unmount_snap(sep, fflags, cr);
1322789Sahrens 			if (error) {
13236068Sck153898 				avl_add(&sdp->sd_snaps, sep);
13246068Sck153898 				break;
1325789Sahrens 			}
1326789Sahrens 		}
1327789Sahrens 		sep = next;
1328789Sahrens 	}
13296068Sck153898 
1330789Sahrens 	mutex_exit(&sdp->sd_lock);
1331789Sahrens 	VN_RELE(dvp);
1332789Sahrens 
1333789Sahrens 	return (error);
1334789Sahrens }
1335