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