17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
539d3e169Sevanl  * Common Development and Distribution License (the "License").
639d3e169Sevanl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22f798ee53SJan Kryl  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23*ade42b55SSebastien Roy  * Copyright (c) 2017 by Delphix. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/param.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/errno.h>
297c478bd9Sstevel@tonic-gate #include <sys/proc.h>
307c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
317c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
32aa59c4cbSrsb #include <sys/vfs_opreg.h>
337c478bd9Sstevel@tonic-gate #include <sys/uio.h>
347c478bd9Sstevel@tonic-gate #include <sys/cred.h>
357c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
367c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
377c478bd9Sstevel@tonic-gate #include <sys/debug.h>
387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/mode.h>
437c478bd9Sstevel@tonic-gate #include <sys/policy.h>
447c478bd9Sstevel@tonic-gate #include <rpc/types.h>
457c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
467c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
477c478bd9Sstevel@tonic-gate #include <sys/fs/autofs.h>
487c478bd9Sstevel@tonic-gate #include <rpcsvc/autofs_prot.h>
497c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  *  Vnode ops for autofs
537c478bd9Sstevel@tonic-gate  */
54da6c28aaSamw static int auto_open(vnode_t **, int, cred_t *, caller_context_t *);
55da6c28aaSamw static int auto_close(vnode_t *, int, int, offset_t, cred_t *,
56da6c28aaSamw 	caller_context_t *);
57da6c28aaSamw static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *,
58da6c28aaSamw 	caller_context_t *);
597c478bd9Sstevel@tonic-gate static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *,
607c478bd9Sstevel@tonic-gate 	caller_context_t *);
61da6c28aaSamw static int auto_access(vnode_t *, int, int, cred_t *, caller_context_t *);
627c478bd9Sstevel@tonic-gate static int auto_lookup(vnode_t *, char *, vnode_t **,
63da6c28aaSamw 	pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
64da6c28aaSamw 	pathname_t *);
657c478bd9Sstevel@tonic-gate static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t,
66da6c28aaSamw 	int, vnode_t **, cred_t *, int, caller_context_t *,  vsecattr_t *);
67da6c28aaSamw static int auto_remove(vnode_t *, char *, cred_t *, caller_context_t *, int);
68da6c28aaSamw static int auto_link(vnode_t *, vnode_t *, char *, cred_t *,
69da6c28aaSamw 	caller_context_t *, int);
70da6c28aaSamw static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
71da6c28aaSamw 	caller_context_t *, int);
72da6c28aaSamw static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
73da6c28aaSamw 	caller_context_t *, int, vsecattr_t *);
74da6c28aaSamw static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
75da6c28aaSamw 	caller_context_t *, int);
76da6c28aaSamw static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *,
77da6c28aaSamw 	caller_context_t *, int);
78da6c28aaSamw static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
79da6c28aaSamw 	caller_context_t *, int);
80da6c28aaSamw static int auto_readlink(vnode_t *, struct uio *, cred_t *,
81da6c28aaSamw 	caller_context_t *);
82da6c28aaSamw static int auto_fsync(vnode_t *, int, cred_t *, caller_context_t *);
83da6c28aaSamw static void auto_inactive(vnode_t *, cred_t *, caller_context_t *);
847c478bd9Sstevel@tonic-gate static int auto_rwlock(vnode_t *, int, caller_context_t *);
857c478bd9Sstevel@tonic-gate static void auto_rwunlock(vnode_t *vp, int, caller_context_t *);
86da6c28aaSamw static int auto_seek(vnode_t *vp, offset_t, offset_t *, caller_context_t *);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate vnodeops_t *auto_vnodeops;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate const fs_operation_def_t auto_vnodeops_template[] = {
93aa59c4cbSrsb 	VOPNAME_OPEN,		{ .vop_open = auto_open },
94aa59c4cbSrsb 	VOPNAME_CLOSE,		{ .vop_close = auto_close },
95aa59c4cbSrsb 	VOPNAME_GETATTR,	{ .vop_getattr = auto_getattr },
96aa59c4cbSrsb 	VOPNAME_SETATTR,	{ .vop_setattr = auto_setattr },
97aa59c4cbSrsb 	VOPNAME_ACCESS,		{ .vop_access = auto_access },
98aa59c4cbSrsb 	VOPNAME_LOOKUP,		{ .vop_lookup = auto_lookup },
99aa59c4cbSrsb 	VOPNAME_CREATE,		{ .vop_create = auto_create },
100aa59c4cbSrsb 	VOPNAME_REMOVE,		{ .vop_remove = auto_remove },
101aa59c4cbSrsb 	VOPNAME_LINK,		{ .vop_link = auto_link },
102aa59c4cbSrsb 	VOPNAME_RENAME,		{ .vop_rename = auto_rename },
103aa59c4cbSrsb 	VOPNAME_MKDIR,		{ .vop_mkdir = auto_mkdir },
104aa59c4cbSrsb 	VOPNAME_RMDIR,		{ .vop_rmdir = auto_rmdir },
105aa59c4cbSrsb 	VOPNAME_READDIR,	{ .vop_readdir = auto_readdir },
106aa59c4cbSrsb 	VOPNAME_SYMLINK,	{ .vop_symlink = auto_symlink },
107aa59c4cbSrsb 	VOPNAME_READLINK,	{ .vop_readlink = auto_readlink },
108aa59c4cbSrsb 	VOPNAME_FSYNC,		{ .vop_fsync = auto_fsync },
109aa59c4cbSrsb 	VOPNAME_INACTIVE,	{ .vop_inactive = auto_inactive },
110aa59c4cbSrsb 	VOPNAME_RWLOCK,		{ .vop_rwlock = auto_rwlock },
111aa59c4cbSrsb 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = auto_rwunlock },
112aa59c4cbSrsb 	VOPNAME_SEEK,		{ .vop_seek = auto_seek },
113aa59c4cbSrsb 	VOPNAME_FRLOCK,		{ .error = fs_error },
114aa59c4cbSrsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
115aa59c4cbSrsb 	VOPNAME_SHRLOCK,	{ .error = fs_error },
116df2381bfSpraks 	VOPNAME_VNEVENT,	{ .vop_vnevent = fs_vnevent_support },
117aa59c4cbSrsb 	NULL,			NULL
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate 
12039d3e169Sevanl 
12139d3e169Sevanl 
1227c478bd9Sstevel@tonic-gate /* ARGSUSED */
1237c478bd9Sstevel@tonic-gate static int
auto_open(vnode_t ** vpp,int flag,cred_t * cred,caller_context_t * ct)124da6c28aaSamw auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
1277c478bd9Sstevel@tonic-gate 	int error;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp));
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	error = auto_trigger_mount(*vpp, cred, &newvp);
1327c478bd9Sstevel@tonic-gate 	if (error)
1337c478bd9Sstevel@tonic-gate 		goto done;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
1367c478bd9Sstevel@tonic-gate 		/*
1377c478bd9Sstevel@tonic-gate 		 * Node is now mounted on.
1387c478bd9Sstevel@tonic-gate 		 */
1397c478bd9Sstevel@tonic-gate 		VN_RELE(*vpp);
1407c478bd9Sstevel@tonic-gate 		*vpp = newvp;
141da6c28aaSamw 		error = VOP_ACCESS(*vpp, VREAD, 0, cred, ct);
1427c478bd9Sstevel@tonic-gate 		if (!error)
143da6c28aaSamw 			error = VOP_OPEN(vpp, flag, cred, ct);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate done:
1477c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp,
1487c478bd9Sstevel@tonic-gate 	    error));
1497c478bd9Sstevel@tonic-gate 	return (error);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /* ARGSUSED */
1537c478bd9Sstevel@tonic-gate static int
auto_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cred,caller_context_t * ct)154da6c28aaSamw auto_close(
155da6c28aaSamw 	vnode_t *vp,
156da6c28aaSamw 	int flag,
157da6c28aaSamw 	int count,
158da6c28aaSamw 	offset_t offset,
159da6c28aaSamw 	cred_t *cred,
160da6c28aaSamw 	caller_context_t *ct)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	return (0);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static int
auto_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cred,caller_context_t * ct)166da6c28aaSamw auto_getattr(
167da6c28aaSamw 	vnode_t *vp,
168da6c28aaSamw 	vattr_t *vap,
169da6c28aaSamw 	int flags,
170da6c28aaSamw 	cred_t *cred,
171da6c28aaSamw 	caller_context_t *ct)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
1747c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
1757c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
1767c478bd9Sstevel@tonic-gate 	int error;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp));
1797c478bd9Sstevel@tonic-gate 
180b9238976Sth 	if (flags & ATTR_TRIGGER) {
181b9238976Sth 		/*
182b9238976Sth 		 * Pre-trigger the mount
183b9238976Sth 		 */
184b9238976Sth 		error = auto_trigger_mount(vp, cred, &newvp);
185b9238976Sth 		if (error)
186b9238976Sth 			return (error);
1875193bcebScasper 
188b9238976Sth 		if (newvp == NULL)
189b9238976Sth 			goto defattr;
190b9238976Sth 
19184d17760SDai Ngo 		if (error = vn_vfsrlock_wait(vp)) {
19284d17760SDai Ngo 			VN_RELE(newvp);
193b9238976Sth 			return (error);
19484d17760SDai Ngo 		}
195b9238976Sth 
196b9238976Sth 		vfsp = newvp->v_vfsp;
19784d17760SDai Ngo 		VN_RELE(newvp);
198b9238976Sth 	} else {
199b9238976Sth 		/*
200b9238976Sth 		 * Recursive auto_getattr/mount; go to the vfsp == NULL
201b9238976Sth 		 * case.
202b9238976Sth 		 */
203b9238976Sth 		if (vn_vfswlock_held(vp))
204b9238976Sth 			goto defattr;
205b9238976Sth 
206b9238976Sth 		if (error = vn_vfsrlock_wait(vp))
207b9238976Sth 			return (error);
208b9238976Sth 
209b9238976Sth 		vfsp = vn_mountedvfs(vp);
210b9238976Sth 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (vfsp != NULL) {
2137c478bd9Sstevel@tonic-gate 		/*
2147c478bd9Sstevel@tonic-gate 		 * Node is mounted on.
2157c478bd9Sstevel@tonic-gate 		 */
2167c478bd9Sstevel@tonic-gate 		error = VFS_ROOT(vfsp, &newvp);
21795b97885Snr 		vn_vfsunlock(vp);
2187c478bd9Sstevel@tonic-gate 		if (error)
2197c478bd9Sstevel@tonic-gate 			return (error);
2207c478bd9Sstevel@tonic-gate 		mutex_enter(&fnp->fn_lock);
2217c478bd9Sstevel@tonic-gate 		if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) {
2227c478bd9Sstevel@tonic-gate 			/*
2237c478bd9Sstevel@tonic-gate 			 * Recursive auto_getattr(); just release newvp and drop
2247c478bd9Sstevel@tonic-gate 			 * into the vfsp == NULL case.
2257c478bd9Sstevel@tonic-gate 			 */
2267c478bd9Sstevel@tonic-gate 			mutex_exit(&fnp->fn_lock);
2277c478bd9Sstevel@tonic-gate 			VN_RELE(newvp);
2287c478bd9Sstevel@tonic-gate 		} else {
2297c478bd9Sstevel@tonic-gate 			while (fnp->fn_thread && fnp->fn_thread != curthread) {
2307c478bd9Sstevel@tonic-gate 				fnp->fn_flags |= MF_ATTR_WAIT;
2317c478bd9Sstevel@tonic-gate 				cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock);
2327c478bd9Sstevel@tonic-gate 			}
2337c478bd9Sstevel@tonic-gate 			fnp->fn_thread = curthread;
2347c478bd9Sstevel@tonic-gate 			fnp->fn_seen = newvp;
2357c478bd9Sstevel@tonic-gate 			mutex_exit(&fnp->fn_lock);
236da6c28aaSamw 			error = VOP_GETATTR(newvp, vap, flags, cred, ct);
2377c478bd9Sstevel@tonic-gate 			VN_RELE(newvp);
2387c478bd9Sstevel@tonic-gate 			mutex_enter(&fnp->fn_lock);
2397c478bd9Sstevel@tonic-gate 			fnp->fn_seen = 0;
2407c478bd9Sstevel@tonic-gate 			fnp->fn_thread = 0;
2417c478bd9Sstevel@tonic-gate 			if (fnp->fn_flags & MF_ATTR_WAIT) {
2427c478bd9Sstevel@tonic-gate 				fnp->fn_flags &= ~MF_ATTR_WAIT;
2437c478bd9Sstevel@tonic-gate 				cv_broadcast(&fnp->fn_cv_mount);
2447c478bd9Sstevel@tonic-gate 			}
2457c478bd9Sstevel@tonic-gate 			mutex_exit(&fnp->fn_lock);
2467c478bd9Sstevel@tonic-gate 			return (error);
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	} else {
2497c478bd9Sstevel@tonic-gate 		vn_vfsunlock(vp);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2525193bcebScasper defattr:
2537c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
2547c478bd9Sstevel@tonic-gate 	vap->va_uid	= 0;
2557c478bd9Sstevel@tonic-gate 	vap->va_gid	= 0;
2567c478bd9Sstevel@tonic-gate 	vap->va_nlink	= fnp->fn_linkcnt;
2577c478bd9Sstevel@tonic-gate 	vap->va_nodeid	= (u_longlong_t)fnp->fn_nodeid;
2587c478bd9Sstevel@tonic-gate 	vap->va_size	= fnp->fn_size;
2597c478bd9Sstevel@tonic-gate 	vap->va_atime	= fnp->fn_atime;
2607c478bd9Sstevel@tonic-gate 	vap->va_mtime	= fnp->fn_mtime;
2617c478bd9Sstevel@tonic-gate 	vap->va_ctime	= fnp->fn_ctime;
2627c478bd9Sstevel@tonic-gate 	vap->va_type	= vp->v_type;
2637c478bd9Sstevel@tonic-gate 	vap->va_mode	= fnp->fn_mode;
2647c478bd9Sstevel@tonic-gate 	vap->va_fsid	= vp->v_vfsp->vfs_dev;
2657c478bd9Sstevel@tonic-gate 	vap->va_rdev	= 0;
2667c478bd9Sstevel@tonic-gate 	vap->va_blksize	= MAXBSIZE;
2677c478bd9Sstevel@tonic-gate 	vap->va_nblocks	= (fsblkcnt64_t)btod(vap->va_size);
2687c478bd9Sstevel@tonic-gate 	vap->va_seq	= 0;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	return (0);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*ARGSUSED4*/
2747c478bd9Sstevel@tonic-gate static int
auto_setattr(vnode_t * vp,struct vattr * vap,int flags,cred_t * cred,caller_context_t * ct)2757c478bd9Sstevel@tonic-gate auto_setattr(
2767c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2777c478bd9Sstevel@tonic-gate 	struct vattr *vap,
2787c478bd9Sstevel@tonic-gate 	int flags,
2797c478bd9Sstevel@tonic-gate 	cred_t *cred,
2807c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
2837c478bd9Sstevel@tonic-gate 	int error;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp));
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(vp, cred, &newvp))
2887c478bd9Sstevel@tonic-gate 		goto done;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
2917c478bd9Sstevel@tonic-gate 		/*
2927c478bd9Sstevel@tonic-gate 		 * Node is mounted on.
2937c478bd9Sstevel@tonic-gate 		 */
2947c478bd9Sstevel@tonic-gate 		if (vn_is_readonly(newvp))
2957c478bd9Sstevel@tonic-gate 			error = EROFS;
2967c478bd9Sstevel@tonic-gate 		else
297da6c28aaSamw 			error = VOP_SETATTR(newvp, vap, flags, cred, ct);
2987c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
2997c478bd9Sstevel@tonic-gate 	} else
3007c478bd9Sstevel@tonic-gate 		error = ENOSYS;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate done:
3037c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error));
3047c478bd9Sstevel@tonic-gate 	return (error);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate /* ARGSUSED */
3087c478bd9Sstevel@tonic-gate static int
auto_access(vnode_t * vp,int mode,int flags,cred_t * cred,caller_context_t * ct)309da6c28aaSamw auto_access(
310da6c28aaSamw 	vnode_t *vp,
311da6c28aaSamw 	int mode,
312da6c28aaSamw 	int flags,
313da6c28aaSamw 	cred_t *cred,
314da6c28aaSamw 	caller_context_t *ct)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
3177c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
3187c478bd9Sstevel@tonic-gate 	int error;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp));
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(vp, cred, &newvp))
3237c478bd9Sstevel@tonic-gate 		goto done;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
3267c478bd9Sstevel@tonic-gate 		/*
3277c478bd9Sstevel@tonic-gate 		 * Node is mounted on.
3287c478bd9Sstevel@tonic-gate 		 */
329da6c28aaSamw 		error = VOP_ACCESS(newvp, mode, 0, cred, ct);
3307c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
3317c478bd9Sstevel@tonic-gate 	} else {
3327c478bd9Sstevel@tonic-gate 		int shift = 0;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		/*
3357c478bd9Sstevel@tonic-gate 		 * really interested in the autofs node, check the
3367c478bd9Sstevel@tonic-gate 		 * access on it
3377c478bd9Sstevel@tonic-gate 		 */
3387c478bd9Sstevel@tonic-gate 		ASSERT(error == 0);
3397c478bd9Sstevel@tonic-gate 		if (crgetuid(cred) != fnp->fn_uid) {
3407c478bd9Sstevel@tonic-gate 			shift += 3;
3417c478bd9Sstevel@tonic-gate 			if (groupmember(fnp->fn_gid, cred) == 0)
3427c478bd9Sstevel@tonic-gate 				shift += 3;
3437c478bd9Sstevel@tonic-gate 		}
344134a1f4eSCasper H.S. Dik 		error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid,
345134a1f4eSCasper H.S. Dik 		    fnp->fn_mode << shift, mode);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate done:
3497c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_access: error=%d\n", error));
3507c478bd9Sstevel@tonic-gate 	return (error);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate static int
auto_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,pathname_t * pnp,int flags,vnode_t * rdir,cred_t * cred,caller_context_t * ct,int * direntflags,pathname_t * realpnp)3547c478bd9Sstevel@tonic-gate auto_lookup(
3557c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
3567c478bd9Sstevel@tonic-gate 	char *nm,
3577c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
3587c478bd9Sstevel@tonic-gate 	pathname_t *pnp,
3597c478bd9Sstevel@tonic-gate 	int flags,
3607c478bd9Sstevel@tonic-gate 	vnode_t *rdir,
361da6c28aaSamw 	cred_t *cred,
362da6c28aaSamw 	caller_context_t *ct,
363da6c28aaSamw 	int *direntflags,
364da6c28aaSamw 	pathname_t *realpnp)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 	int error = 0;
3677c478bd9Sstevel@tonic-gate 	vnode_t *newvp = NULL;
3687c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
3697c478bd9Sstevel@tonic-gate 	fninfo_t *dfnip;
3707c478bd9Sstevel@tonic-gate 	fnnode_t *dfnp = NULL;
3717c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = NULL;
3727c478bd9Sstevel@tonic-gate 	char *searchnm;
3737c478bd9Sstevel@tonic-gate 	int operation;		/* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	dfnip = vfstofni(dvp->v_vfsp);
3767c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
3777c478bd9Sstevel@tonic-gate 	    (void *)dvp, dfnip->fi_map, nm));
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (nm[0] == 0) {
3807c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
3817c478bd9Sstevel@tonic-gate 		*vpp = dvp;
3827c478bd9Sstevel@tonic-gate 		return (0);
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
385da6c28aaSamw 	if (error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct))
3867c478bd9Sstevel@tonic-gate 		return (error);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (nm[0] == '.' && nm[1] == 0) {
3897c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
3907c478bd9Sstevel@tonic-gate 		*vpp = dvp;
3917c478bd9Sstevel@tonic-gate 		return (0);
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) {
3957c478bd9Sstevel@tonic-gate 		fnnode_t *pdfnp;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 		pdfnp = (vntofn(dvp))->fn_parent;
3987c478bd9Sstevel@tonic-gate 		ASSERT(pdfnp != NULL);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		/*
4017c478bd9Sstevel@tonic-gate 		 * Since it is legitimate to have the VROOT flag set for the
4027c478bd9Sstevel@tonic-gate 		 * subdirectories of the indirect map in autofs filesystem,
4037c478bd9Sstevel@tonic-gate 		 * rootfnnodep is checked against fnnode of dvp instead of
4047c478bd9Sstevel@tonic-gate 		 * just checking whether VROOT flag is set in dvp
4057c478bd9Sstevel@tonic-gate 		 */
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) {
4087c478bd9Sstevel@tonic-gate 			vnode_t *vp;
4097c478bd9Sstevel@tonic-gate 
41095b97885Snr 			vfs_rlock_wait(dvp->v_vfsp);
4117c478bd9Sstevel@tonic-gate 			if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
4127c478bd9Sstevel@tonic-gate 				vfs_unlock(dvp->v_vfsp);
4137c478bd9Sstevel@tonic-gate 				return (EIO);
4147c478bd9Sstevel@tonic-gate 			}
4157c478bd9Sstevel@tonic-gate 			vp = dvp->v_vfsp->vfs_vnodecovered;
4167c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
4177c478bd9Sstevel@tonic-gate 			vfs_unlock(dvp->v_vfsp);
418da6c28aaSamw 			error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred,
419da6c28aaSamw 			    ct, direntflags, realpnp);
4207c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
4217c478bd9Sstevel@tonic-gate 			return (error);
4227c478bd9Sstevel@tonic-gate 		} else {
4237c478bd9Sstevel@tonic-gate 			*vpp = fntovn(pdfnp);
4247c478bd9Sstevel@tonic-gate 			VN_HOLD(*vpp);
4257c478bd9Sstevel@tonic-gate 			return (0);
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate top:
4307c478bd9Sstevel@tonic-gate 	dfnp = vntofn(dvp);
4317c478bd9Sstevel@tonic-gate 	searchnm = nm;
4327c478bd9Sstevel@tonic-gate 	operation = 0;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(dvp, auto_vnodeops));
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp,
4377c478bd9Sstevel@tonic-gate 	    (void *)dfnp));
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/*
4407c478bd9Sstevel@tonic-gate 	 * If a lookup or mount of this node is in progress, wait for it
4417c478bd9Sstevel@tonic-gate 	 * to finish, and return whatever result it got.
4427c478bd9Sstevel@tonic-gate 	 */
4437c478bd9Sstevel@tonic-gate 	mutex_enter(&dfnp->fn_lock);
4447c478bd9Sstevel@tonic-gate 	if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
4457c478bd9Sstevel@tonic-gate 		mutex_exit(&dfnp->fn_lock);
4467c478bd9Sstevel@tonic-gate 		error = auto_wait4mount(dfnp);
4477c478bd9Sstevel@tonic-gate 		if (error == AUTOFS_SHUTDOWN)
4487c478bd9Sstevel@tonic-gate 			error = ENOENT;
4497c478bd9Sstevel@tonic-gate 		if (error == EAGAIN)
4507c478bd9Sstevel@tonic-gate 			goto top;
4517c478bd9Sstevel@tonic-gate 		if (error)
4527c478bd9Sstevel@tonic-gate 			return (error);
4537c478bd9Sstevel@tonic-gate 	} else
4547c478bd9Sstevel@tonic-gate 		mutex_exit(&dfnp->fn_lock);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 
45795b97885Snr 	error = vn_vfsrlock_wait(dvp);
4587c478bd9Sstevel@tonic-gate 	if (error)
4597c478bd9Sstevel@tonic-gate 		return (error);
4607c478bd9Sstevel@tonic-gate 	vfsp = vn_mountedvfs(dvp);
4617c478bd9Sstevel@tonic-gate 	if (vfsp != NULL) {
4627c478bd9Sstevel@tonic-gate 		error = VFS_ROOT(vfsp, &newvp);
46395b97885Snr 		vn_vfsunlock(dvp);
4647c478bd9Sstevel@tonic-gate 		if (!error) {
4657c478bd9Sstevel@tonic-gate 			error = VOP_LOOKUP(newvp, nm, vpp, pnp,
466da6c28aaSamw 			    flags, rdir, cred, ct, direntflags, realpnp);
4677c478bd9Sstevel@tonic-gate 			VN_RELE(newvp);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 		return (error);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 	vn_vfsunlock(dvp);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	rw_enter(&dfnp->fn_rwlock, RW_READER);
4747c478bd9Sstevel@tonic-gate 	error = auto_search(dfnp, nm, &fnp, cred);
4757c478bd9Sstevel@tonic-gate 	if (error) {
4767c478bd9Sstevel@tonic-gate 		if (dfnip->fi_flags & MF_DIRECT) {
4777c478bd9Sstevel@tonic-gate 			/*
4787c478bd9Sstevel@tonic-gate 			 * direct map.
4797c478bd9Sstevel@tonic-gate 			 */
4807c478bd9Sstevel@tonic-gate 			if (dfnp->fn_dirents) {
4817c478bd9Sstevel@tonic-gate 				/*
4827c478bd9Sstevel@tonic-gate 				 * Mount previously triggered.
4837c478bd9Sstevel@tonic-gate 				 * 'nm' not found
4847c478bd9Sstevel@tonic-gate 				 */
4857c478bd9Sstevel@tonic-gate 				error = ENOENT;
4867c478bd9Sstevel@tonic-gate 			} else {
4877c478bd9Sstevel@tonic-gate 				/*
4887c478bd9Sstevel@tonic-gate 				 * I need to contact the daemon to trigger
4897c478bd9Sstevel@tonic-gate 				 * the mount. 'dfnp' will be the mountpoint.
4907c478bd9Sstevel@tonic-gate 				 */
4917c478bd9Sstevel@tonic-gate 				operation = AUTOFS_MOUNT;
4927c478bd9Sstevel@tonic-gate 				VN_HOLD(fntovn(dfnp));
4937c478bd9Sstevel@tonic-gate 				fnp = dfnp;
4947c478bd9Sstevel@tonic-gate 				error = 0;
4957c478bd9Sstevel@tonic-gate 			}
4967c478bd9Sstevel@tonic-gate 		} else if (dvp == dfnip->fi_rootvp) {
4977c478bd9Sstevel@tonic-gate 			/*
4987c478bd9Sstevel@tonic-gate 			 * 'dfnp' is the root of the indirect AUTOFS.
4997c478bd9Sstevel@tonic-gate 			 */
5007c478bd9Sstevel@tonic-gate 			if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) {
5017c478bd9Sstevel@tonic-gate 				/*
5027c478bd9Sstevel@tonic-gate 				 * Could not acquire writer lock, release
5037c478bd9Sstevel@tonic-gate 				 * reader, and wait until available. We
5047c478bd9Sstevel@tonic-gate 				 * need to search for 'nm' again, since we
5057c478bd9Sstevel@tonic-gate 				 * had to release the lock before reacquiring
5067c478bd9Sstevel@tonic-gate 				 * it.
5077c478bd9Sstevel@tonic-gate 				 */
5087c478bd9Sstevel@tonic-gate 				rw_exit(&dfnp->fn_rwlock);
5097c478bd9Sstevel@tonic-gate 				rw_enter(&dfnp->fn_rwlock, RW_WRITER);
5107c478bd9Sstevel@tonic-gate 				error = auto_search(dfnp, nm, &fnp, cred);
5117c478bd9Sstevel@tonic-gate 			}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 			ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
5147c478bd9Sstevel@tonic-gate 			if (error) {
5157c478bd9Sstevel@tonic-gate 				/*
5167c478bd9Sstevel@tonic-gate 				 * create node being looked-up and request
5177c478bd9Sstevel@tonic-gate 				 * mount on it.
5187c478bd9Sstevel@tonic-gate 				 */
5197c478bd9Sstevel@tonic-gate 				error = auto_enter(dfnp, nm, &fnp, kcred);
5207c478bd9Sstevel@tonic-gate 				if (!error)
5217c478bd9Sstevel@tonic-gate 					operation = AUTOFS_LOOKUP;
5227c478bd9Sstevel@tonic-gate 			}
5237c478bd9Sstevel@tonic-gate 		} else if ((dfnp->fn_dirents == NULL) &&
5247c478bd9Sstevel@tonic-gate 		    ((dvp->v_flag & VROOT) == 0) &&
5257c478bd9Sstevel@tonic-gate 		    ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) {
5267c478bd9Sstevel@tonic-gate 			/*
5277c478bd9Sstevel@tonic-gate 			 * dfnp is the actual 'mountpoint' of indirect map,
5287c478bd9Sstevel@tonic-gate 			 * it is the equivalent of a direct mount,
5297c478bd9Sstevel@tonic-gate 			 * ie, /home/'user1'
5307c478bd9Sstevel@tonic-gate 			 */
5317c478bd9Sstevel@tonic-gate 			operation = AUTOFS_MOUNT;
5327c478bd9Sstevel@tonic-gate 			VN_HOLD(fntovn(dfnp));
5337c478bd9Sstevel@tonic-gate 			fnp = dfnp;
5347c478bd9Sstevel@tonic-gate 			error = 0;
5357c478bd9Sstevel@tonic-gate 			searchnm = dfnp->fn_name;
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (error == EAGAIN) {
5407c478bd9Sstevel@tonic-gate 		rw_exit(&dfnp->fn_rwlock);
5417c478bd9Sstevel@tonic-gate 		goto top;
5427c478bd9Sstevel@tonic-gate 	}
5437c478bd9Sstevel@tonic-gate 	if (error) {
5447c478bd9Sstevel@tonic-gate 		rw_exit(&dfnp->fn_rwlock);
5457c478bd9Sstevel@tonic-gate 		return (error);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	/*
5497c478bd9Sstevel@tonic-gate 	 * We now have the actual fnnode we're interested in.
5507c478bd9Sstevel@tonic-gate 	 * The 'MF_LOOKUP' indicates another thread is currently
5517c478bd9Sstevel@tonic-gate 	 * performing a daemon lookup of this node, therefore we
5527c478bd9Sstevel@tonic-gate 	 * wait for its completion.
5537c478bd9Sstevel@tonic-gate 	 * The 'MF_INPROG' indicates another thread is currently
5547c478bd9Sstevel@tonic-gate 	 * performing a daemon mount of this node, we wait for it
5557c478bd9Sstevel@tonic-gate 	 * to be done if we are performing a MOUNT. We don't
5567c478bd9Sstevel@tonic-gate 	 * wait for it if we are performing a LOOKUP.
5577c478bd9Sstevel@tonic-gate 	 * We can release the reader/writer lock as soon as we acquire
5587c478bd9Sstevel@tonic-gate 	 * the mutex, since the state of the lock can only change by
5597c478bd9Sstevel@tonic-gate 	 * first acquiring the mutex.
5607c478bd9Sstevel@tonic-gate 	 */
5617c478bd9Sstevel@tonic-gate 	mutex_enter(&fnp->fn_lock);
5627c478bd9Sstevel@tonic-gate 	rw_exit(&dfnp->fn_rwlock);
5637c478bd9Sstevel@tonic-gate 	if ((fnp->fn_flags & MF_LOOKUP) ||
5647c478bd9Sstevel@tonic-gate 	    ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) {
5657c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
5667c478bd9Sstevel@tonic-gate 		error = auto_wait4mount(fnp);
5677c478bd9Sstevel@tonic-gate 		VN_RELE(fntovn(fnp));
5687c478bd9Sstevel@tonic-gate 		if (error == AUTOFS_SHUTDOWN)
5697c478bd9Sstevel@tonic-gate 			error = ENOENT;
5707c478bd9Sstevel@tonic-gate 		if (error && error != EAGAIN)
5717c478bd9Sstevel@tonic-gate 			return (error);
5727c478bd9Sstevel@tonic-gate 		goto top;
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	if (operation == 0) {
5767c478bd9Sstevel@tonic-gate 		/*
5777c478bd9Sstevel@tonic-gate 		 * got the fnnode, check for any errors
5787c478bd9Sstevel@tonic-gate 		 * on the previous operation on that node.
5797c478bd9Sstevel@tonic-gate 		 */
5807c478bd9Sstevel@tonic-gate 		error = fnp->fn_error;
5817c478bd9Sstevel@tonic-gate 		if ((error == EINTR) || (error == EAGAIN)) {
5827c478bd9Sstevel@tonic-gate 			/*
5837c478bd9Sstevel@tonic-gate 			 * previous operation on this node was
5847c478bd9Sstevel@tonic-gate 			 * not completed, do a lookup now.
5857c478bd9Sstevel@tonic-gate 			 */
5867c478bd9Sstevel@tonic-gate 			operation = AUTOFS_LOOKUP;
5877c478bd9Sstevel@tonic-gate 		} else {
5887c478bd9Sstevel@tonic-gate 			/*
5897c478bd9Sstevel@tonic-gate 			 * previous operation completed. Return
5907c478bd9Sstevel@tonic-gate 			 * a pointer to the node only if there was
5917c478bd9Sstevel@tonic-gate 			 * no error.
5927c478bd9Sstevel@tonic-gate 			 */
5937c478bd9Sstevel@tonic-gate 			mutex_exit(&fnp->fn_lock);
5947c478bd9Sstevel@tonic-gate 			if (!error)
5957c478bd9Sstevel@tonic-gate 				*vpp = fntovn(fnp);
5967c478bd9Sstevel@tonic-gate 			else
5977c478bd9Sstevel@tonic-gate 				VN_RELE(fntovn(fnp));
5987c478bd9Sstevel@tonic-gate 			return (error);
5997c478bd9Sstevel@tonic-gate 		}
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/*
6037c478bd9Sstevel@tonic-gate 	 * Since I got to this point, it means I'm the one
6047c478bd9Sstevel@tonic-gate 	 * responsible for triggering the mount/look-up of this node.
6057c478bd9Sstevel@tonic-gate 	 */
6067c478bd9Sstevel@tonic-gate 	switch (operation) {
6077c478bd9Sstevel@tonic-gate 	case AUTOFS_LOOKUP:
6087c478bd9Sstevel@tonic-gate 		AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP);
6097c478bd9Sstevel@tonic-gate 		fnp->fn_error = 0;
6107c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
6117c478bd9Sstevel@tonic-gate 		error = auto_lookup_aux(fnp, searchnm, cred);
6127c478bd9Sstevel@tonic-gate 		if (!error) {
6137c478bd9Sstevel@tonic-gate 			/*
6147c478bd9Sstevel@tonic-gate 			 * Return this vnode
6157c478bd9Sstevel@tonic-gate 			 */
6167c478bd9Sstevel@tonic-gate 			*vpp = fntovn(fnp);
6177c478bd9Sstevel@tonic-gate 		} else {
6187c478bd9Sstevel@tonic-gate 			/*
6197c478bd9Sstevel@tonic-gate 			 * release our reference to this vnode
6207c478bd9Sstevel@tonic-gate 			 * and return error
6217c478bd9Sstevel@tonic-gate 			 */
6227c478bd9Sstevel@tonic-gate 			VN_RELE(fntovn(fnp));
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 		break;
6257c478bd9Sstevel@tonic-gate 	case AUTOFS_MOUNT:
6267c478bd9Sstevel@tonic-gate 		AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
6277c478bd9Sstevel@tonic-gate 		fnp->fn_error = 0;
6287c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
6297c478bd9Sstevel@tonic-gate 		/*
6307c478bd9Sstevel@tonic-gate 		 * auto_new_mount_thread fires up a new thread which
6317c478bd9Sstevel@tonic-gate 		 * calls automountd finishing up the work
6327c478bd9Sstevel@tonic-gate 		 */
6337c478bd9Sstevel@tonic-gate 		auto_new_mount_thread(fnp, searchnm, cred);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		/*
6367c478bd9Sstevel@tonic-gate 		 * At this point, we are simply another thread
6377c478bd9Sstevel@tonic-gate 		 * waiting for the mount to complete
6387c478bd9Sstevel@tonic-gate 		 */
6397c478bd9Sstevel@tonic-gate 		error = auto_wait4mount(fnp);
6407c478bd9Sstevel@tonic-gate 		if (error == AUTOFS_SHUTDOWN)
6417c478bd9Sstevel@tonic-gate 			error = ENOENT;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 		/*
6447c478bd9Sstevel@tonic-gate 		 * now release our reference to this vnode
6457c478bd9Sstevel@tonic-gate 		 */
6467c478bd9Sstevel@tonic-gate 		VN_RELE(fntovn(fnp));
6477c478bd9Sstevel@tonic-gate 		if (!error)
6487c478bd9Sstevel@tonic-gate 			goto top;
6497c478bd9Sstevel@tonic-gate 		break;
6507c478bd9Sstevel@tonic-gate 	default:
65139d3e169Sevanl 		auto_log(dfnp->fn_globals->fng_verbose,
652b9238976Sth 		    dfnp->fn_globals->fng_zoneid, CE_WARN,
653b9238976Sth 		    "auto_lookup: unknown operation %d",
654b9238976Sth 		    operation);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
6587c478bd9Sstevel@tonic-gate 	    nm, (void *)*vpp, error));
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	return (error);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate static int
auto_create(vnode_t * dvp,char * nm,vattr_t * va,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cred,int flag,caller_context_t * ct,vsecattr_t * vsecp)6647c478bd9Sstevel@tonic-gate auto_create(
6657c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
6667c478bd9Sstevel@tonic-gate 	char *nm,
6677c478bd9Sstevel@tonic-gate 	vattr_t *va,
6687c478bd9Sstevel@tonic-gate 	vcexcl_t excl,
6697c478bd9Sstevel@tonic-gate 	int mode,
6707c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
6717c478bd9Sstevel@tonic-gate 	cred_t *cred,
672da6c28aaSamw 	int flag,
673da6c28aaSamw 	caller_context_t *ct,
674da6c28aaSamw 	vsecattr_t *vsecp)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
6777c478bd9Sstevel@tonic-gate 	int error;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm));
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(dvp, cred, &newvp))
6827c478bd9Sstevel@tonic-gate 		goto done;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
6857c478bd9Sstevel@tonic-gate 		/*
6867c478bd9Sstevel@tonic-gate 		 * Node is now mounted on.
6877c478bd9Sstevel@tonic-gate 		 */
6887c478bd9Sstevel@tonic-gate 		if (vn_is_readonly(newvp))
6897c478bd9Sstevel@tonic-gate 			error = EROFS;
6907c478bd9Sstevel@tonic-gate 		else
6917c478bd9Sstevel@tonic-gate 			error = VOP_CREATE(newvp, nm, va, excl,
692da6c28aaSamw 			    mode, vpp, cred, flag, ct, vsecp);
6937c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
6947c478bd9Sstevel@tonic-gate 	} else
6957c478bd9Sstevel@tonic-gate 		error = ENOSYS;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate done:
6987c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_create: error=%d\n", error));
6997c478bd9Sstevel@tonic-gate 	return (error);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate static int
auto_remove(vnode_t * dvp,char * nm,cred_t * cred,caller_context_t * ct,int flags)703da6c28aaSamw auto_remove(
704da6c28aaSamw 	vnode_t *dvp,
705da6c28aaSamw 	char *nm,
706da6c28aaSamw 	cred_t *cred,
707da6c28aaSamw 	caller_context_t *ct,
708da6c28aaSamw 	int flags)
7097c478bd9Sstevel@tonic-gate {
7107c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
7117c478bd9Sstevel@tonic-gate 	int error;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm));
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(dvp, cred, &newvp))
7167c478bd9Sstevel@tonic-gate 		goto done;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
7197c478bd9Sstevel@tonic-gate 		/*
7207c478bd9Sstevel@tonic-gate 		 * Node is now mounted on.
7217c478bd9Sstevel@tonic-gate 		 */
7227c478bd9Sstevel@tonic-gate 		if (vn_is_readonly(newvp))
7237c478bd9Sstevel@tonic-gate 			error = EROFS;
7247c478bd9Sstevel@tonic-gate 		else
725da6c28aaSamw 			error = VOP_REMOVE(newvp, nm, cred, ct, flags);
7267c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
7277c478bd9Sstevel@tonic-gate 	} else
7287c478bd9Sstevel@tonic-gate 		error = ENOSYS;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate done:
7317c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error));
7327c478bd9Sstevel@tonic-gate 	return (error);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate static int
auto_link(vnode_t * tdvp,vnode_t * svp,char * nm,cred_t * cred,caller_context_t * ct,int flags)736da6c28aaSamw auto_link(
737da6c28aaSamw 	vnode_t *tdvp,
738da6c28aaSamw 	vnode_t *svp,
739da6c28aaSamw 	char *nm,
740da6c28aaSamw 	cred_t *cred,
741da6c28aaSamw 	caller_context_t *ct,
742da6c28aaSamw 	int flags)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
7457c478bd9Sstevel@tonic-gate 	int error;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp,
7487c478bd9Sstevel@tonic-gate 	    (void *)svp, nm));
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(tdvp, cred, &newvp))
7517c478bd9Sstevel@tonic-gate 		goto done;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (newvp == NULL) {
7547c478bd9Sstevel@tonic-gate 		/*
7557c478bd9Sstevel@tonic-gate 		 * an autonode can not be a link to another node
7567c478bd9Sstevel@tonic-gate 		 */
7577c478bd9Sstevel@tonic-gate 		error = ENOSYS;
7587c478bd9Sstevel@tonic-gate 		goto done;
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	if (vn_is_readonly(newvp)) {
7627c478bd9Sstevel@tonic-gate 		error = EROFS;
7637c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
7647c478bd9Sstevel@tonic-gate 		goto done;
7657c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	if (vn_matchops(svp, auto_vnodeops)) {
7687c478bd9Sstevel@tonic-gate 		/*
7697c478bd9Sstevel@tonic-gate 		 * source vp can't be an autonode
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		error = ENOSYS;
7727c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
7737c478bd9Sstevel@tonic-gate 		goto done;
7747c478bd9Sstevel@tonic-gate 	}
7757c478bd9Sstevel@tonic-gate 
776da6c28aaSamw 	error = VOP_LINK(newvp, svp, nm, cred, ct, flags);
7777c478bd9Sstevel@tonic-gate 	VN_RELE(newvp);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate done:
7807c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_link error=%d\n", error));
7817c478bd9Sstevel@tonic-gate 	return (error);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate static int
auto_rename(vnode_t * odvp,char * onm,vnode_t * ndvp,char * nnm,cred_t * cr,caller_context_t * ct,int flags)785da6c28aaSamw auto_rename(
786da6c28aaSamw 	vnode_t *odvp,
787da6c28aaSamw 	char *onm,
788da6c28aaSamw 	vnode_t *ndvp,
789da6c28aaSamw 	char *nnm,
790da6c28aaSamw 	cred_t *cr,
791da6c28aaSamw 	caller_context_t *ct,
792da6c28aaSamw 	int flags)
7937c478bd9Sstevel@tonic-gate {
7947c478bd9Sstevel@tonic-gate 	vnode_t *o_newvp, *n_newvp;
7957c478bd9Sstevel@tonic-gate 	int error;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
7987c478bd9Sstevel@tonic-gate 	    (void *)odvp, onm, (void *)ndvp, nnm));
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	/*
8017c478bd9Sstevel@tonic-gate 	 * we know odvp is an autonode, otherwise this function
8027c478bd9Sstevel@tonic-gate 	 * could not have ever been called.
8037c478bd9Sstevel@tonic-gate 	 */
8047c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(odvp, auto_vnodeops));
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(odvp, cr, &o_newvp))
8077c478bd9Sstevel@tonic-gate 		goto done;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	if (o_newvp == NULL) {
8107c478bd9Sstevel@tonic-gate 		/*
8117c478bd9Sstevel@tonic-gate 		 * can't rename an autonode
8127c478bd9Sstevel@tonic-gate 		 */
8137c478bd9Sstevel@tonic-gate 		error = ENOSYS;
8147c478bd9Sstevel@tonic-gate 		goto done;
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	if (vn_matchops(ndvp, auto_vnodeops)) {
8187c478bd9Sstevel@tonic-gate 		/*
8197c478bd9Sstevel@tonic-gate 		 * directory is AUTOFS, need to trigger the
8207c478bd9Sstevel@tonic-gate 		 * mount of the real filesystem.
8217c478bd9Sstevel@tonic-gate 		 */
8227c478bd9Sstevel@tonic-gate 		if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) {
8237c478bd9Sstevel@tonic-gate 			VN_RELE(o_newvp);
8247c478bd9Sstevel@tonic-gate 			goto done;
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 		if (n_newvp == NULL) {
8287c478bd9Sstevel@tonic-gate 			/*
8297c478bd9Sstevel@tonic-gate 			 * target can't be an autonode
8307c478bd9Sstevel@tonic-gate 			 */
8317c478bd9Sstevel@tonic-gate 			error = ENOSYS;
8327c478bd9Sstevel@tonic-gate 			VN_RELE(o_newvp);
8337c478bd9Sstevel@tonic-gate 			goto done;
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 	} else {
8367c478bd9Sstevel@tonic-gate 		/*
8377c478bd9Sstevel@tonic-gate 		 * destination directory mount had been
8387c478bd9Sstevel@tonic-gate 		 * triggered prior to the call to this function.
8397c478bd9Sstevel@tonic-gate 		 */
8407c478bd9Sstevel@tonic-gate 		n_newvp = ndvp;
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	ASSERT(!vn_matchops(n_newvp, auto_vnodeops));
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (vn_is_readonly(n_newvp)) {
8467c478bd9Sstevel@tonic-gate 		error = EROFS;
8477c478bd9Sstevel@tonic-gate 		VN_RELE(o_newvp);
8487c478bd9Sstevel@tonic-gate 		if (n_newvp != ndvp)
8497c478bd9Sstevel@tonic-gate 			VN_RELE(n_newvp);
8507c478bd9Sstevel@tonic-gate 		goto done;
8517c478bd9Sstevel@tonic-gate 	}
8527c478bd9Sstevel@tonic-gate 
853da6c28aaSamw 	error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
8547c478bd9Sstevel@tonic-gate 	VN_RELE(o_newvp);
8557c478bd9Sstevel@tonic-gate 	if (n_newvp != ndvp)
8567c478bd9Sstevel@tonic-gate 		VN_RELE(n_newvp);
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate done:
8597c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_rename error=%d\n", error));
8607c478bd9Sstevel@tonic-gate 	return (error);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate static int
auto_mkdir(vnode_t * dvp,char * nm,vattr_t * va,vnode_t ** vpp,cred_t * cred,caller_context_t * ct,int flags,vsecattr_t * vsecp)864da6c28aaSamw auto_mkdir(
865da6c28aaSamw 	vnode_t *dvp,
866da6c28aaSamw 	char *nm,
867da6c28aaSamw 	vattr_t *va,
868da6c28aaSamw 	vnode_t **vpp,
869da6c28aaSamw 	cred_t *cred,
870da6c28aaSamw 	caller_context_t *ct,
871da6c28aaSamw 	int flags,
872da6c28aaSamw 	vsecattr_t *vsecp)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
8757c478bd9Sstevel@tonic-gate 	int error;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm));
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(dvp, cred, &newvp))
8807c478bd9Sstevel@tonic-gate 		goto done;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
8837c478bd9Sstevel@tonic-gate 		/*
8847c478bd9Sstevel@tonic-gate 		 * Node is now mounted on.
8857c478bd9Sstevel@tonic-gate 		 */
8867c478bd9Sstevel@tonic-gate 		if (vn_is_readonly(newvp))
8877c478bd9Sstevel@tonic-gate 			error = EROFS;
8887c478bd9Sstevel@tonic-gate 		else
889da6c28aaSamw 			error = VOP_MKDIR(newvp, nm, va, vpp, cred, ct,
890da6c28aaSamw 			    flags, vsecp);
8917c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
8927c478bd9Sstevel@tonic-gate 	} else
8937c478bd9Sstevel@tonic-gate 		error = ENOSYS;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate done:
8967c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error));
8977c478bd9Sstevel@tonic-gate 	return (error);
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate static int
auto_rmdir(vnode_t * dvp,char * nm,vnode_t * cdir,cred_t * cred,caller_context_t * ct,int flags)901da6c28aaSamw auto_rmdir(
902da6c28aaSamw 	vnode_t *dvp,
903da6c28aaSamw 	char *nm,
904da6c28aaSamw 	vnode_t *cdir,
905da6c28aaSamw 	cred_t *cred,
906da6c28aaSamw 	caller_context_t *ct,
907da6c28aaSamw 	int flags)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
9107c478bd9Sstevel@tonic-gate 	int error;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm));
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(dvp, cred, &newvp))
9157c478bd9Sstevel@tonic-gate 		goto done;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
9187c478bd9Sstevel@tonic-gate 		/*
9197c478bd9Sstevel@tonic-gate 		 * Node is now mounted on.
9207c478bd9Sstevel@tonic-gate 		 */
9217c478bd9Sstevel@tonic-gate 		if (vn_is_readonly(newvp))
9227c478bd9Sstevel@tonic-gate 			error = EROFS;
9237c478bd9Sstevel@tonic-gate 		else
924da6c28aaSamw 			error = VOP_RMDIR(newvp, nm, cdir, cred, ct, flags);
9257c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
9267c478bd9Sstevel@tonic-gate 	} else
9277c478bd9Sstevel@tonic-gate 		error = ENOSYS;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate done:
9307c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error));
9317c478bd9Sstevel@tonic-gate 	return (error);
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate static int autofs_nobrowse = 0;
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate #ifdef nextdp
9377c478bd9Sstevel@tonic-gate #undef nextdp
9387c478bd9Sstevel@tonic-gate #endif
9397c478bd9Sstevel@tonic-gate #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
9407c478bd9Sstevel@tonic-gate 
941da6c28aaSamw /* ARGSUSED */
9427c478bd9Sstevel@tonic-gate static int
auto_readdir(vnode_t * vp,uio_t * uiop,cred_t * cred,int * eofp,caller_context_t * ct,int flags)943da6c28aaSamw auto_readdir(
944da6c28aaSamw 	vnode_t *vp,
945da6c28aaSamw 	uio_t *uiop,
946da6c28aaSamw 	cred_t *cred,
947da6c28aaSamw 	int *eofp,
948da6c28aaSamw 	caller_context_t *ct,
949da6c28aaSamw 	int flags)
9507c478bd9Sstevel@tonic-gate {
95139d3e169Sevanl 	struct autofs_rddirargs	rda;
95239d3e169Sevanl 	autofs_rddirres rd;
9537c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
9547c478bd9Sstevel@tonic-gate 	fnnode_t *cfnp, *nfnp;
9557c478bd9Sstevel@tonic-gate 	dirent64_t *dp;
9567c478bd9Sstevel@tonic-gate 	ulong_t offset;
9577c478bd9Sstevel@tonic-gate 	ulong_t outcount = 0, count = 0;
9587c478bd9Sstevel@tonic-gate 	size_t namelen;
9597c478bd9Sstevel@tonic-gate 	ulong_t alloc_count;
96039d3e169Sevanl 	void *outbuf = NULL;
9617c478bd9Sstevel@tonic-gate 	fninfo_t *fnip = vfstofni(vp->v_vfsp);
9627c478bd9Sstevel@tonic-gate 	struct iovec *iovp;
9637c478bd9Sstevel@tonic-gate 	int error = 0;
9647c478bd9Sstevel@tonic-gate 	int reached_max = 0;
9657c478bd9Sstevel@tonic-gate 	int myeof = 0;
9667c478bd9Sstevel@tonic-gate 	int this_reclen;
96739d3e169Sevanl 	struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
9707c478bd9Sstevel@tonic-gate 	    (void *)vp, uiop->uio_loffset));
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	if (eofp != NULL)
9737c478bd9Sstevel@tonic-gate 		*eofp = 0;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	if (uiop->uio_iovcnt != 1)
9767c478bd9Sstevel@tonic-gate 		return (EINVAL);
9777c478bd9Sstevel@tonic-gate 
97839d3e169Sevanl 	iovp = uiop->uio_iov;
97939d3e169Sevanl 	alloc_count = iovp->iov_len;
98039d3e169Sevanl 
9817c478bd9Sstevel@tonic-gate 	gethrestime(&fnp->fn_atime);
9827c478bd9Sstevel@tonic-gate 	fnp->fn_ref_time = fnp->fn_atime.tv_sec;
9837c478bd9Sstevel@tonic-gate 
98439d3e169Sevanl 	dp = outbuf = kmem_zalloc(alloc_count, KM_SLEEP);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	/*
9877c478bd9Sstevel@tonic-gate 	 * Held when getdents calls VOP_RWLOCK....
9887c478bd9Sstevel@tonic-gate 	 */
9897c478bd9Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&fnp->fn_rwlock));
9907c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) {
9917c478bd9Sstevel@tonic-gate again:
9927c478bd9Sstevel@tonic-gate 		/*
9937c478bd9Sstevel@tonic-gate 		 * Do readdir of daemon contents only
9947c478bd9Sstevel@tonic-gate 		 * Drop readers lock and reacquire after reply.
9957c478bd9Sstevel@tonic-gate 		 */
9967c478bd9Sstevel@tonic-gate 		rw_exit(&fnp->fn_rwlock);
99739d3e169Sevanl 		bzero(&rd, sizeof (struct autofs_rddirres));
9987c478bd9Sstevel@tonic-gate 		count = 0;
9997c478bd9Sstevel@tonic-gate 		rda.rda_map = fnip->fi_map;
10007c478bd9Sstevel@tonic-gate 		rda.rda_offset = (uint_t)uiop->uio_offset;
10017c478bd9Sstevel@tonic-gate 		rd.rd_rddir.rddir_entries = dp;
10027c478bd9Sstevel@tonic-gate 		rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count;
10033bfb48feSsemery 		rda.uid = crgetuid(cred);
100439d3e169Sevanl 
100539d3e169Sevanl 		error = auto_calldaemon(fngp->fng_zoneid,
1006b9238976Sth 		    AUTOFS_READDIR,
1007b9238976Sth 		    xdr_autofs_rddirargs,
1008b9238976Sth 		    &rda,
1009b9238976Sth 		    xdr_autofs_rddirres,
1010b9238976Sth 		    (void *)&rd,
1011b9238976Sth 		    sizeof (autofs_rddirres),
1012b9238976Sth 		    TRUE);
101339d3e169Sevanl 
10147c478bd9Sstevel@tonic-gate 		/*
10157c478bd9Sstevel@tonic-gate 		 * reacquire previously dropped lock
10167c478bd9Sstevel@tonic-gate 		 */
10177c478bd9Sstevel@tonic-gate 		rw_enter(&fnp->fn_rwlock, RW_READER);
10187c478bd9Sstevel@tonic-gate 
101939d3e169Sevanl 		if (!error) {
10207c478bd9Sstevel@tonic-gate 			error = rd.rd_status;
102139d3e169Sevanl 			dp = rd.rd_rddir.rddir_entries;
102239d3e169Sevanl 		}
102339d3e169Sevanl 
10247c478bd9Sstevel@tonic-gate 		if (error) {
10257c478bd9Sstevel@tonic-gate 			if (error == AUTOFS_SHUTDOWN) {
10267c478bd9Sstevel@tonic-gate 				/*
10277c478bd9Sstevel@tonic-gate 				 * treat as empty directory
10287c478bd9Sstevel@tonic-gate 				 */
10297c478bd9Sstevel@tonic-gate 				error = 0;
10307c478bd9Sstevel@tonic-gate 				myeof = 1;
10317c478bd9Sstevel@tonic-gate 				if (eofp)
10327c478bd9Sstevel@tonic-gate 					*eofp = 1;
10337c478bd9Sstevel@tonic-gate 			}
10347c478bd9Sstevel@tonic-gate 			goto done;
10357c478bd9Sstevel@tonic-gate 		}
10367c478bd9Sstevel@tonic-gate 		if (rd.rd_rddir.rddir_size) {
103739d3e169Sevanl 			dirent64_t *odp = dp;   /* next in output buffer */
103839d3e169Sevanl 			dirent64_t *cdp = dp;   /* current examined entry */
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 			/*
10417c478bd9Sstevel@tonic-gate 			 * Check for duplicates here
10427c478bd9Sstevel@tonic-gate 			 */
10437c478bd9Sstevel@tonic-gate 			do {
10447c478bd9Sstevel@tonic-gate 				this_reclen = cdp->d_reclen;
104539d3e169Sevanl 				if (auto_search(fnp, cdp->d_name,
1046b9238976Sth 				    NULL, cred)) {
10477c478bd9Sstevel@tonic-gate 					/*
10487c478bd9Sstevel@tonic-gate 					 * entry not found in kernel list,
10497c478bd9Sstevel@tonic-gate 					 * include it in readdir output.
10507c478bd9Sstevel@tonic-gate 					 *
10517c478bd9Sstevel@tonic-gate 					 * If we are skipping entries. then
10527c478bd9Sstevel@tonic-gate 					 * we need to copy this entry to the
10537c478bd9Sstevel@tonic-gate 					 * correct position in the buffer
10547c478bd9Sstevel@tonic-gate 					 * to be copied out.
10557c478bd9Sstevel@tonic-gate 					 */
10567c478bd9Sstevel@tonic-gate 					if (cdp != odp)
10577c478bd9Sstevel@tonic-gate 						bcopy(cdp, odp,
1058b9238976Sth 						    (size_t)this_reclen);
10597c478bd9Sstevel@tonic-gate 					odp = nextdp(odp);
10607c478bd9Sstevel@tonic-gate 					outcount += this_reclen;
10617c478bd9Sstevel@tonic-gate 				} else {
10627c478bd9Sstevel@tonic-gate 					/*
10637c478bd9Sstevel@tonic-gate 					 * Entry was found in the kernel
10647c478bd9Sstevel@tonic-gate 					 * list. If it is the first entry
10657c478bd9Sstevel@tonic-gate 					 * in this buffer, then just skip it
10667c478bd9Sstevel@tonic-gate 					 */
10677c478bd9Sstevel@tonic-gate 					if (odp == dp) {
10687c478bd9Sstevel@tonic-gate 						dp = nextdp(dp);
10697c478bd9Sstevel@tonic-gate 						odp = dp;
10707c478bd9Sstevel@tonic-gate 					}
10717c478bd9Sstevel@tonic-gate 				}
10727c478bd9Sstevel@tonic-gate 				count += this_reclen;
10737c478bd9Sstevel@tonic-gate 				cdp = (struct dirent64 *)
1074b9238976Sth 				    ((char *)cdp + this_reclen);
10757c478bd9Sstevel@tonic-gate 			} while (count < rd.rd_rddir.rddir_size);
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 			if (outcount)
10787c478bd9Sstevel@tonic-gate 				error = uiomove(dp, outcount, UIO_READ, uiop);
10797c478bd9Sstevel@tonic-gate 			uiop->uio_offset = rd.rd_rddir.rddir_offset;
10807c478bd9Sstevel@tonic-gate 		} else {
10817c478bd9Sstevel@tonic-gate 			if (rd.rd_rddir.rddir_eof == 0) {
10827c478bd9Sstevel@tonic-gate 				/*
10837c478bd9Sstevel@tonic-gate 				 * alloc_count not large enough for one
10847c478bd9Sstevel@tonic-gate 				 * directory entry
10857c478bd9Sstevel@tonic-gate 				 */
10867c478bd9Sstevel@tonic-gate 				error = EINVAL;
10877c478bd9Sstevel@tonic-gate 			}
10887c478bd9Sstevel@tonic-gate 		}
10897c478bd9Sstevel@tonic-gate 		if (rd.rd_rddir.rddir_eof && !error) {
10907c478bd9Sstevel@tonic-gate 			myeof = 1;
10917c478bd9Sstevel@tonic-gate 			if (eofp)
10927c478bd9Sstevel@tonic-gate 				*eofp = 1;
10937c478bd9Sstevel@tonic-gate 		}
10947c478bd9Sstevel@tonic-gate 		if (!error && !myeof && outcount == 0) {
10957c478bd9Sstevel@tonic-gate 			/*
10967c478bd9Sstevel@tonic-gate 			 * call daemon with new cookie, all previous
10977c478bd9Sstevel@tonic-gate 			 * elements happened to be duplicates
10987c478bd9Sstevel@tonic-gate 			 */
10997c478bd9Sstevel@tonic-gate 			dp = outbuf;
11007c478bd9Sstevel@tonic-gate 			goto again;
11017c478bd9Sstevel@tonic-gate 		}
11027c478bd9Sstevel@tonic-gate 		goto done;
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset == 0) {
11067c478bd9Sstevel@tonic-gate 		/*
11077c478bd9Sstevel@tonic-gate 		 * first time: so fudge the . and ..
11087c478bd9Sstevel@tonic-gate 		 */
11097c478bd9Sstevel@tonic-gate 		this_reclen = DIRENT64_RECLEN(1);
11107c478bd9Sstevel@tonic-gate 		if (alloc_count < this_reclen) {
11117c478bd9Sstevel@tonic-gate 			error = EINVAL;
11127c478bd9Sstevel@tonic-gate 			goto done;
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 		dp->d_ino = (ino64_t)fnp->fn_nodeid;
11157c478bd9Sstevel@tonic-gate 		dp->d_off = (off64_t)1;
11167c478bd9Sstevel@tonic-gate 		dp->d_reclen = (ushort_t)this_reclen;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 		/* use strncpy(9f) to zero out uninitialized bytes */
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 		(void) strncpy(dp->d_name, ".",
1121b9238976Sth 		    DIRENT64_NAMELEN(this_reclen));
11227c478bd9Sstevel@tonic-gate 		outcount += dp->d_reclen;
11237c478bd9Sstevel@tonic-gate 		dp = nextdp(dp);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		this_reclen = DIRENT64_RECLEN(2);
11267c478bd9Sstevel@tonic-gate 		if (alloc_count < outcount + this_reclen) {
11277c478bd9Sstevel@tonic-gate 			error = EINVAL;
11287c478bd9Sstevel@tonic-gate 			goto done;
11297c478bd9Sstevel@tonic-gate 		}
11307c478bd9Sstevel@tonic-gate 		dp->d_reclen = (ushort_t)this_reclen;
11317c478bd9Sstevel@tonic-gate 		dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid;
11327c478bd9Sstevel@tonic-gate 		dp->d_off = (off64_t)2;
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 		/* use strncpy(9f) to zero out uninitialized bytes */
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		(void) strncpy(dp->d_name, "..",
1137b9238976Sth 		    DIRENT64_NAMELEN(this_reclen));
11387c478bd9Sstevel@tonic-gate 		outcount += dp->d_reclen;
11397c478bd9Sstevel@tonic-gate 		dp = nextdp(dp);
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	offset = 2;
11437c478bd9Sstevel@tonic-gate 	cfnp = fnp->fn_dirents;
11447c478bd9Sstevel@tonic-gate 	while (cfnp != NULL) {
11457c478bd9Sstevel@tonic-gate 		nfnp = cfnp->fn_next;
11467c478bd9Sstevel@tonic-gate 		offset = cfnp->fn_offset;
11477c478bd9Sstevel@tonic-gate 		if ((offset >= uiop->uio_offset) &&
1148b9238976Sth 		    (!(cfnp->fn_flags & MF_LOOKUP))) {
11497c478bd9Sstevel@tonic-gate 			int reclen;
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 			/*
11527c478bd9Sstevel@tonic-gate 			 * include node only if its offset is greater or
11537c478bd9Sstevel@tonic-gate 			 * equal to the one required and it is not in
11547c478bd9Sstevel@tonic-gate 			 * transient state (not being looked-up)
11557c478bd9Sstevel@tonic-gate 			 */
11567c478bd9Sstevel@tonic-gate 			namelen = strlen(cfnp->fn_name);
11577c478bd9Sstevel@tonic-gate 			reclen = (int)DIRENT64_RECLEN(namelen);
11587c478bd9Sstevel@tonic-gate 			if (outcount + reclen > alloc_count) {
11597c478bd9Sstevel@tonic-gate 				reached_max = 1;
11607c478bd9Sstevel@tonic-gate 				break;
11617c478bd9Sstevel@tonic-gate 			}
11627c478bd9Sstevel@tonic-gate 			dp->d_reclen = (ushort_t)reclen;
11637c478bd9Sstevel@tonic-gate 			dp->d_ino = (ino64_t)cfnp->fn_nodeid;
11647c478bd9Sstevel@tonic-gate 			if (nfnp != NULL) {
11657c478bd9Sstevel@tonic-gate 				/*
11667c478bd9Sstevel@tonic-gate 				 * get the offset of the next element
11677c478bd9Sstevel@tonic-gate 				 */
11687c478bd9Sstevel@tonic-gate 				dp->d_off = (off64_t)nfnp->fn_offset;
11697c478bd9Sstevel@tonic-gate 			} else {
11707c478bd9Sstevel@tonic-gate 				/*
11717c478bd9Sstevel@tonic-gate 				 * This is the last element, make
11727c478bd9Sstevel@tonic-gate 				 * offset one plus the current
11737c478bd9Sstevel@tonic-gate 				 */
11747c478bd9Sstevel@tonic-gate 				dp->d_off = (off64_t)cfnp->fn_offset + 1;
11757c478bd9Sstevel@tonic-gate 			}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 			/* use strncpy(9f) to zero out uninitialized bytes */
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 			(void) strncpy(dp->d_name, cfnp->fn_name,
1180b9238976Sth 			    DIRENT64_NAMELEN(reclen));
11817c478bd9Sstevel@tonic-gate 			outcount += dp->d_reclen;
11827c478bd9Sstevel@tonic-gate 			dp = nextdp(dp);
11837c478bd9Sstevel@tonic-gate 		}
11847c478bd9Sstevel@tonic-gate 		cfnp = nfnp;
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	if (outcount)
11887c478bd9Sstevel@tonic-gate 		error = uiomove(outbuf, outcount, UIO_READ, uiop);
1189b9238976Sth 
11907c478bd9Sstevel@tonic-gate 	if (!error) {
11917c478bd9Sstevel@tonic-gate 		if (reached_max) {
11927c478bd9Sstevel@tonic-gate 			/*
11937c478bd9Sstevel@tonic-gate 			 * This entry did not get added to the buffer on this,
11947c478bd9Sstevel@tonic-gate 			 * call. We need to add it on the next call therefore
11957c478bd9Sstevel@tonic-gate 			 * set uio_offset to this entry's offset.  If there
11967c478bd9Sstevel@tonic-gate 			 * wasn't enough space for one dirent, return EINVAL.
11977c478bd9Sstevel@tonic-gate 			 */
11987c478bd9Sstevel@tonic-gate 			uiop->uio_offset = offset;
11997c478bd9Sstevel@tonic-gate 			if (outcount == 0)
12007c478bd9Sstevel@tonic-gate 				error = EINVAL;
12017c478bd9Sstevel@tonic-gate 		} else if (autofs_nobrowse ||
1202b9238976Sth 		    auto_nobrowse_option(fnip->fi_opts) ||
1203b9238976Sth 		    (fnip->fi_flags & MF_DIRECT) ||
1204b9238976Sth 		    (fnp->fn_trigger != NULL) ||
1205b9238976Sth 		    (((vp->v_flag & VROOT) == 0) &&
1206b9238976Sth 		    ((fntovn(fnp->fn_parent))->v_flag & VROOT) &&
1207b9238976Sth 		    (fnp->fn_dirents == NULL))) {
12087c478bd9Sstevel@tonic-gate 			/*
12097c478bd9Sstevel@tonic-gate 			 * done reading directory entries
12107c478bd9Sstevel@tonic-gate 			 */
12117c478bd9Sstevel@tonic-gate 			uiop->uio_offset = offset + 1;
12127c478bd9Sstevel@tonic-gate 			if (eofp)
12137c478bd9Sstevel@tonic-gate 				*eofp = 1;
12147c478bd9Sstevel@tonic-gate 		} else {
12157c478bd9Sstevel@tonic-gate 			/*
12167c478bd9Sstevel@tonic-gate 			 * Need to get the rest of the entries from the daemon.
12177c478bd9Sstevel@tonic-gate 			 */
12187c478bd9Sstevel@tonic-gate 			uiop->uio_offset = AUTOFS_DAEMONCOOKIE;
12197c478bd9Sstevel@tonic-gate 		}
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate done:
12237c478bd9Sstevel@tonic-gate 	kmem_free(outbuf, alloc_count);
12247c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1225b9238976Sth 	    (void *)vp, uiop->uio_loffset, myeof));
12267c478bd9Sstevel@tonic-gate 	return (error);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate static int
auto_symlink(vnode_t * dvp,char * lnknm,vattr_t * tva,char * tnm,cred_t * cred,caller_context_t * ct,int flags)12307c478bd9Sstevel@tonic-gate auto_symlink(
12317c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
12327c478bd9Sstevel@tonic-gate 	char *lnknm,		/* new entry */
12337c478bd9Sstevel@tonic-gate 	vattr_t *tva,
12347c478bd9Sstevel@tonic-gate 	char *tnm,		/* existing entry */
1235da6c28aaSamw 	cred_t *cred,
1236da6c28aaSamw 	caller_context_t *ct,
1237da6c28aaSamw 	int flags)
12387c478bd9Sstevel@tonic-gate {
12397c478bd9Sstevel@tonic-gate 	vnode_t *newvp;
12407c478bd9Sstevel@tonic-gate 	int error;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
12437c478bd9Sstevel@tonic-gate 	    (void *)dvp, lnknm, tnm));
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	if (error = auto_trigger_mount(dvp, cred, &newvp))
12467c478bd9Sstevel@tonic-gate 		goto done;
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if (newvp != NULL) {
12497c478bd9Sstevel@tonic-gate 		/*
12507c478bd9Sstevel@tonic-gate 		 * Node is mounted on.
12517c478bd9Sstevel@tonic-gate 		 */
12527c478bd9Sstevel@tonic-gate 		if (vn_is_readonly(newvp))
12537c478bd9Sstevel@tonic-gate 			error = EROFS;
12547c478bd9Sstevel@tonic-gate 		else
1255da6c28aaSamw 			error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred,
1256da6c28aaSamw 			    ct, flags);
12577c478bd9Sstevel@tonic-gate 		VN_RELE(newvp);
12587c478bd9Sstevel@tonic-gate 	} else
12597c478bd9Sstevel@tonic-gate 		error = ENOSYS;
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate done:
12627c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error));
12637c478bd9Sstevel@tonic-gate 	return (error);
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate /* ARGSUSED */
12677c478bd9Sstevel@tonic-gate static int
auto_readlink(vnode_t * vp,struct uio * uiop,cred_t * cr,caller_context_t * ct)1268da6c28aaSamw auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
12697c478bd9Sstevel@tonic-gate {
12707c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
12717c478bd9Sstevel@tonic-gate 	int error;
12727c478bd9Sstevel@tonic-gate 	timestruc_t now;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp));
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	gethrestime(&now);
12777c478bd9Sstevel@tonic-gate 	fnp->fn_ref_time = now.tv_sec;
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 	if (vp->v_type != VLNK)
12807c478bd9Sstevel@tonic-gate 		error = EINVAL;
12817c478bd9Sstevel@tonic-gate 	else {
12827c478bd9Sstevel@tonic-gate 		ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP)));
12837c478bd9Sstevel@tonic-gate 		fnp->fn_atime = now;
12847c478bd9Sstevel@tonic-gate 		error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen,
12857c478bd9Sstevel@tonic-gate 		    uiop->uio_resid), UIO_READ, uiop);
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error));
12897c478bd9Sstevel@tonic-gate 	return (error);
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate /* ARGSUSED */
12937c478bd9Sstevel@tonic-gate static int
auto_fsync(vnode_t * cp,int syncflag,cred_t * cred,caller_context_t * ct)1294da6c28aaSamw auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
12957c478bd9Sstevel@tonic-gate {
12967c478bd9Sstevel@tonic-gate 	return (0);
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate /* ARGSUSED */
13007c478bd9Sstevel@tonic-gate static void
auto_inactive(vnode_t * vp,cred_t * cred,caller_context_t * ct)1301da6c28aaSamw auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
13027c478bd9Sstevel@tonic-gate {
13037c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
13047c478bd9Sstevel@tonic-gate 	fnnode_t *dfnp = fnp->fn_parent;
13057c478bd9Sstevel@tonic-gate 	int count;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
13087c478bd9Sstevel@tonic-gate 	    (void *)vp, vp->v_count, fnp->fn_linkcnt));
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	/*
13117c478bd9Sstevel@tonic-gate 	 * The rwlock should not be already held by this thread.
13127c478bd9Sstevel@tonic-gate 	 * The assert relies on the fact that the owner field is cleared
13137c478bd9Sstevel@tonic-gate 	 * when the lock is released.
13147c478bd9Sstevel@tonic-gate 	 */
13157c478bd9Sstevel@tonic-gate 	ASSERT(dfnp != NULL);
13167c478bd9Sstevel@tonic-gate 	ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread);
13177c478bd9Sstevel@tonic-gate 	rw_enter(&dfnp->fn_rwlock, RW_WRITER);
13187c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
13197c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count > 0);
1320*ade42b55SSebastien Roy 	VN_RELE_LOCKED(vp);
1321*ade42b55SSebastien Roy 	count = vp->v_count;
13227c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
13237c478bd9Sstevel@tonic-gate 	if (count == 0) {
13247c478bd9Sstevel@tonic-gate 		/*
13257c478bd9Sstevel@tonic-gate 		 * Free only if node has no subdirectories.
13267c478bd9Sstevel@tonic-gate 		 */
13277c478bd9Sstevel@tonic-gate 		if (fnp->fn_linkcnt == 1) {
13287c478bd9Sstevel@tonic-gate 			auto_disconnect(dfnp, fnp);
13297c478bd9Sstevel@tonic-gate 			rw_exit(&dfnp->fn_rwlock);
13307c478bd9Sstevel@tonic-gate 			auto_freefnnode(fnp);
13317c478bd9Sstevel@tonic-gate 			AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
13327c478bd9Sstevel@tonic-gate 			    (void *)vp));
13337c478bd9Sstevel@tonic-gate 			return;
13347c478bd9Sstevel@tonic-gate 		}
13357c478bd9Sstevel@tonic-gate 	}
13367c478bd9Sstevel@tonic-gate 	rw_exit(&dfnp->fn_rwlock);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
13397c478bd9Sstevel@tonic-gate 	    (void *)vp, vp->v_count, fnp->fn_linkcnt));
13407c478bd9Sstevel@tonic-gate }
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
13437c478bd9Sstevel@tonic-gate static int
auto_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)13447c478bd9Sstevel@tonic-gate auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
13457c478bd9Sstevel@tonic-gate {
13467c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
13477c478bd9Sstevel@tonic-gate 	if (write_lock)
13487c478bd9Sstevel@tonic-gate 		rw_enter(&fnp->fn_rwlock, RW_WRITER);
13497c478bd9Sstevel@tonic-gate 	else
13507c478bd9Sstevel@tonic-gate 		rw_enter(&fnp->fn_rwlock, RW_READER);
13517c478bd9Sstevel@tonic-gate 	return (write_lock);
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate /* ARGSUSED */
13557c478bd9Sstevel@tonic-gate static void
auto_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)13567c478bd9Sstevel@tonic-gate auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
13577c478bd9Sstevel@tonic-gate {
13587c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
13597c478bd9Sstevel@tonic-gate 	rw_exit(&fnp->fn_rwlock);
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate /* ARGSUSED */
13647c478bd9Sstevel@tonic-gate static int
auto_seek(struct vnode * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)1365da6c28aaSamw auto_seek(
1366da6c28aaSamw 	struct vnode *vp,
1367da6c28aaSamw 	offset_t ooff,
1368da6c28aaSamw 	offset_t *noffp,
1369da6c28aaSamw 	caller_context_t *ct)
13707c478bd9Sstevel@tonic-gate {
13717c478bd9Sstevel@tonic-gate 	/*
13727c478bd9Sstevel@tonic-gate 	 * Return 0 unconditionally, since we expect
13737c478bd9Sstevel@tonic-gate 	 * a VDIR all the time
13747c478bd9Sstevel@tonic-gate 	 */
13757c478bd9Sstevel@tonic-gate 	return (0);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate  * Triggers the mount if needed. If the mount has been triggered by
13807c478bd9Sstevel@tonic-gate  * another thread, it will wait for its return status, and return it.
13817c478bd9Sstevel@tonic-gate  * Whether the mount is triggered by this thread, another thread, or
13827c478bd9Sstevel@tonic-gate  * if the vnode was already covered, '*newvp' is a
13837c478bd9Sstevel@tonic-gate  * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
13847c478bd9Sstevel@tonic-gate  * If the node is not mounted on, and should not be mounted on, '*newvp'
13857c478bd9Sstevel@tonic-gate  * will be NULL.
13867c478bd9Sstevel@tonic-gate  * The calling routine may use '*newvp' to do the filesystem jump.
13877c478bd9Sstevel@tonic-gate  */
13887c478bd9Sstevel@tonic-gate static int
auto_trigger_mount(vnode_t * vp,cred_t * cred,vnode_t ** newvp)13897c478bd9Sstevel@tonic-gate auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp)
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate 	fnnode_t *fnp = vntofn(vp);
13927c478bd9Sstevel@tonic-gate 	fninfo_t *fnip = vfstofni(vp->v_vfsp);
13937c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
13947c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
13957c478bd9Sstevel@tonic-gate 	int delayed_ind;
13967c478bd9Sstevel@tonic-gate 	char name[AUTOFS_MAXPATHLEN];
13977c478bd9Sstevel@tonic-gate 	int error;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp));
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	*newvp = NULL;
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	/*
14047c478bd9Sstevel@tonic-gate 	 * Cross-zone mount triggering is disallowed.
14057c478bd9Sstevel@tonic-gate 	 */
14067c478bd9Sstevel@tonic-gate 	if (fnip->fi_zoneid != getzoneid())
14077c478bd9Sstevel@tonic-gate 		return (EPERM);	/* Not owner of mount */
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate retry:
14107c478bd9Sstevel@tonic-gate 	error = 0;
14117c478bd9Sstevel@tonic-gate 	delayed_ind = 0;
14127c478bd9Sstevel@tonic-gate 	mutex_enter(&fnp->fn_lock);
14137c478bd9Sstevel@tonic-gate 	while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
14147c478bd9Sstevel@tonic-gate 		/*
14157c478bd9Sstevel@tonic-gate 		 * Mount or lookup in progress,
14167c478bd9Sstevel@tonic-gate 		 * wait for it before proceeding.
14177c478bd9Sstevel@tonic-gate 		 */
14187c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
14197c478bd9Sstevel@tonic-gate 		error = auto_wait4mount(fnp);
14207c478bd9Sstevel@tonic-gate 		if (error == AUTOFS_SHUTDOWN) {
14217c478bd9Sstevel@tonic-gate 			error = 0;
14227c478bd9Sstevel@tonic-gate 			goto done;
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 		if (error && error != EAGAIN)
14257c478bd9Sstevel@tonic-gate 			goto done;
14267c478bd9Sstevel@tonic-gate 		error = 0;
14277c478bd9Sstevel@tonic-gate 		mutex_enter(&fnp->fn_lock);
14287c478bd9Sstevel@tonic-gate 	}
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	/*
14317c478bd9Sstevel@tonic-gate 	 * If the vfslock can't be acquired for the first time.
14327c478bd9Sstevel@tonic-gate 	 * drop the fn_lock and retry next time in blocking mode.
14337c478bd9Sstevel@tonic-gate 	 */
14347c478bd9Sstevel@tonic-gate 	if (vn_vfswlock(vp)) {
14357c478bd9Sstevel@tonic-gate 		/*
14367c478bd9Sstevel@tonic-gate 		 * Lock held by another thread.
14377c478bd9Sstevel@tonic-gate 		 * Perform blocking by dropping the
14387c478bd9Sstevel@tonic-gate 		 * fn_lock.
14397c478bd9Sstevel@tonic-gate 		 */
14407c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
14417c478bd9Sstevel@tonic-gate 		error = vn_vfswlock_wait(vp);
14427c478bd9Sstevel@tonic-gate 		if (error)
14437c478bd9Sstevel@tonic-gate 			goto done;
14447c478bd9Sstevel@tonic-gate 		/*
14457c478bd9Sstevel@tonic-gate 		 * Because fn_lock wasn't held, the state
14467c478bd9Sstevel@tonic-gate 		 * of the trigger node might have changed.
14477c478bd9Sstevel@tonic-gate 		 * Need to run through the checks on trigger
14487c478bd9Sstevel@tonic-gate 		 * node again.
14497c478bd9Sstevel@tonic-gate 		 */
14507c478bd9Sstevel@tonic-gate 		vn_vfsunlock(vp);
14517c478bd9Sstevel@tonic-gate 		goto retry;
14527c478bd9Sstevel@tonic-gate 	}
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	vfsp = vn_mountedvfs(vp);
14557c478bd9Sstevel@tonic-gate 	if (vfsp != NULL) {
14567c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
14577c478bd9Sstevel@tonic-gate 		error = VFS_ROOT(vfsp, newvp);
145895b97885Snr 		vn_vfsunlock(vp);
14597c478bd9Sstevel@tonic-gate 		goto done;
14607c478bd9Sstevel@tonic-gate 	} else {
14617c478bd9Sstevel@tonic-gate 		vn_vfsunlock(vp);
14627c478bd9Sstevel@tonic-gate 		if ((fnp->fn_flags & MF_MOUNTPOINT) &&
14637c478bd9Sstevel@tonic-gate 		    fnp->fn_trigger != NULL) {
14647c478bd9Sstevel@tonic-gate 			ASSERT(fnp->fn_dirents == NULL);
1465f798ee53SJan Kryl 			mutex_exit(&fnp->fn_lock);
14667c478bd9Sstevel@tonic-gate 			/*
14677c478bd9Sstevel@tonic-gate 			 * The filesystem that used to sit here has been
1468f798ee53SJan Kryl 			 * forcibly unmounted. Do our best to recover.
1469f798ee53SJan Kryl 			 * Try to unmount autofs subtree below this node
1470f798ee53SJan Kryl 			 * and retry the action.
14717c478bd9Sstevel@tonic-gate 			 */
1472f798ee53SJan Kryl 			if (unmount_subtree(fnp, B_TRUE) != 0) {
1473f798ee53SJan Kryl 				error = EIO;
1474f798ee53SJan Kryl 				goto done;
1475f798ee53SJan Kryl 			}
1476f798ee53SJan Kryl 			goto retry;
14777c478bd9Sstevel@tonic-gate 		}
14787c478bd9Sstevel@tonic-gate 	}
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_type == VDIR);
14817c478bd9Sstevel@tonic-gate 	dvp = fntovn(fnp->fn_parent);
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	if ((fnp->fn_dirents == NULL) &&
14847c478bd9Sstevel@tonic-gate 	    ((fnip->fi_flags & MF_DIRECT) == 0) &&
14857c478bd9Sstevel@tonic-gate 	    ((vp->v_flag & VROOT) == 0) &&
14867c478bd9Sstevel@tonic-gate 	    (dvp->v_flag & VROOT)) {
14877c478bd9Sstevel@tonic-gate 		/*
14887c478bd9Sstevel@tonic-gate 		 * If the parent of this node is the root of an indirect
14897c478bd9Sstevel@tonic-gate 		 * AUTOFS filesystem, this node is remountable.
14907c478bd9Sstevel@tonic-gate 		 */
14917c478bd9Sstevel@tonic-gate 		delayed_ind = 1;
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	if (delayed_ind ||
14957c478bd9Sstevel@tonic-gate 	    ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) {
14967c478bd9Sstevel@tonic-gate 		/*
14977c478bd9Sstevel@tonic-gate 		 * Trigger mount since:
14987c478bd9Sstevel@tonic-gate 		 * direct mountpoint with no subdirs or
14997c478bd9Sstevel@tonic-gate 		 * delayed indirect.
15007c478bd9Sstevel@tonic-gate 		 */
15017c478bd9Sstevel@tonic-gate 		AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
15027c478bd9Sstevel@tonic-gate 		fnp->fn_error = 0;
15037c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
15047c478bd9Sstevel@tonic-gate 		if (delayed_ind)
15057c478bd9Sstevel@tonic-gate 			(void) strcpy(name, fnp->fn_name);
15067c478bd9Sstevel@tonic-gate 		else
15077c478bd9Sstevel@tonic-gate 			(void) strcpy(name, ".");
15087c478bd9Sstevel@tonic-gate 		fnp->fn_ref_time = gethrestime_sec();
15097c478bd9Sstevel@tonic-gate 		auto_new_mount_thread(fnp, name, cred);
15107c478bd9Sstevel@tonic-gate 		/*
15117c478bd9Sstevel@tonic-gate 		 * At this point we're simply another thread waiting
15127c478bd9Sstevel@tonic-gate 		 * for the mount to finish.
15137c478bd9Sstevel@tonic-gate 		 */
15147c478bd9Sstevel@tonic-gate 		error = auto_wait4mount(fnp);
15157c478bd9Sstevel@tonic-gate 		if (error == EAGAIN)
15167c478bd9Sstevel@tonic-gate 			goto retry;
15177c478bd9Sstevel@tonic-gate 		if (error == AUTOFS_SHUTDOWN) {
15187c478bd9Sstevel@tonic-gate 			error = 0;
15197c478bd9Sstevel@tonic-gate 			goto done;
15207c478bd9Sstevel@tonic-gate 		}
15217c478bd9Sstevel@tonic-gate 		if (error == 0) {
152295b97885Snr 			if (error = vn_vfsrlock_wait(vp))
15237c478bd9Sstevel@tonic-gate 				goto done;
15247c478bd9Sstevel@tonic-gate 			/* Reacquire after dropping locks */
15257c478bd9Sstevel@tonic-gate 			vfsp = vn_mountedvfs(vp);
15267c478bd9Sstevel@tonic-gate 			if (vfsp != NULL) {
15277c478bd9Sstevel@tonic-gate 				error = VFS_ROOT(vfsp, newvp);
152895b97885Snr 				vn_vfsunlock(vp);
15297c478bd9Sstevel@tonic-gate 			} else {
15307c478bd9Sstevel@tonic-gate 				vn_vfsunlock(vp);
15317c478bd9Sstevel@tonic-gate 				goto retry;
15327c478bd9Sstevel@tonic-gate 			}
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 	} else
15357c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock);
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate done:
15387c478bd9Sstevel@tonic-gate 	AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error));
15397c478bd9Sstevel@tonic-gate 	return (error);
15407c478bd9Sstevel@tonic-gate }
1541