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