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