4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2017 by Delphix. All rights reserved.
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/errno.h>
30 #include <sys/vnode.h>
34 #include <sys/pathname.h>
35 #include <sys/dirent.h>
36 #include <sys/debug.h>
37 #include <sys/sysmacros.h>
38 #include <sys/tiuser.h>
39 #include <sys/cmn_err.h>
42 #include <sys/policy.h>
43 #include <rpc/types.h>
46 #include <sys/fs/autofs.h>
47 #include <rpcsvc/autofs_prot.h>
48 #include <sys/fs_subr.h>
51 * Vnode ops for autofs
53 static int auto_open(vnode_t
**, int, cred_t
*, caller_context_t
*);
54 static int auto_close(vnode_t
*, int, int, offset_t
, cred_t
*,
56 static int auto_getattr(vnode_t
*, vattr_t
*, int, cred_t
*,
58 static int auto_setattr(vnode_t
*, vattr_t
*, int, cred_t
*,
60 static int auto_access(vnode_t
*, int, int, cred_t
*, caller_context_t
*);
61 static int auto_lookup(vnode_t
*, char *, vnode_t
**,
62 pathname_t
*, int, vnode_t
*, cred_t
*, caller_context_t
*, int *,
64 static int auto_create(vnode_t
*, char *, vattr_t
*, vcexcl_t
,
65 int, vnode_t
**, cred_t
*, int, caller_context_t
*, vsecattr_t
*);
66 static int auto_remove(vnode_t
*, char *, cred_t
*, caller_context_t
*, int);
67 static int auto_link(vnode_t
*, vnode_t
*, char *, cred_t
*,
68 caller_context_t
*, int);
69 static int auto_rename(vnode_t
*, char *, vnode_t
*, char *, cred_t
*,
70 caller_context_t
*, int);
71 static int auto_mkdir(vnode_t
*, char *, vattr_t
*, vnode_t
**, cred_t
*,
72 caller_context_t
*, int, vsecattr_t
*);
73 static int auto_rmdir(vnode_t
*, char *, vnode_t
*, cred_t
*,
74 caller_context_t
*, int);
75 static int auto_readdir(vnode_t
*, uio_t
*, cred_t
*, int *,
76 caller_context_t
*, int);
77 static int auto_symlink(vnode_t
*, char *, vattr_t
*, char *, cred_t
*,
78 caller_context_t
*, int);
79 static int auto_readlink(vnode_t
*, struct uio
*, cred_t
*,
81 static int auto_fsync(vnode_t
*, int, cred_t
*, caller_context_t
*);
82 static void auto_inactive(vnode_t
*, cred_t
*, caller_context_t
*);
83 static int auto_rwlock(vnode_t
*, int, caller_context_t
*);
84 static void auto_rwunlock(vnode_t
*vp
, int, caller_context_t
*);
85 static int auto_seek(vnode_t
*vp
, offset_t
, offset_t
*, caller_context_t
*);
87 static int auto_trigger_mount(vnode_t
*, cred_t
*, vnode_t
**);
89 const struct vnodeops auto_vnodeops
= {
90 .vnop_name
= "autofs",
91 .vop_open
= auto_open
,
92 .vop_close
= auto_close
,
93 .vop_getattr
= auto_getattr
,
94 .vop_setattr
= auto_setattr
,
95 .vop_access
= auto_access
,
96 .vop_lookup
= auto_lookup
,
97 .vop_create
= auto_create
,
98 .vop_remove
= auto_remove
,
99 .vop_link
= auto_link
,
100 .vop_rename
= auto_rename
,
101 .vop_mkdir
= auto_mkdir
,
102 .vop_rmdir
= auto_rmdir
,
103 .vop_readdir
= auto_readdir
,
104 .vop_symlink
= auto_symlink
,
105 .vop_readlink
= auto_readlink
,
106 .vop_fsync
= auto_fsync
,
107 .vop_inactive
= auto_inactive
,
108 .vop_rwlock
= auto_rwlock
,
109 .vop_rwunlock
= auto_rwunlock
,
110 .vop_seek
= auto_seek
,
111 .vop_frlock
= fs_nosys
,
112 .vop_dispose
= fs_nodispose
,
113 .vop_shrlock
= fs_nosys
,
114 .vop_vnevent
= fs_vnevent_support
,
119 auto_open(vnode_t
**vpp
, int flag
, cred_t
*cred
, caller_context_t
*ct
)
124 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp
));
126 error
= auto_trigger_mount(*vpp
, cred
, &newvp
);
132 * Node is now mounted on.
136 error
= fop_access(*vpp
, VREAD
, 0, cred
, ct
);
138 error
= fop_open(vpp
, flag
, cred
, ct
);
142 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp
,
155 caller_context_t
*ct
)
166 caller_context_t
*ct
)
168 fnnode_t
*fnp
= vntofn(vp
);
173 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp
));
175 if (flags
& ATTR_TRIGGER
) {
177 * Pre-trigger the mount
179 error
= auto_trigger_mount(vp
, cred
, &newvp
);
186 if (error
= vn_vfsrlock_wait(vp
)) {
191 vfsp
= newvp
->v_vfsp
;
195 * Recursive auto_getattr/mount; go to the vfsp == NULL
198 if (vn_vfswlock_held(vp
))
201 if (error
= vn_vfsrlock_wait(vp
))
204 vfsp
= vn_mountedvfs(vp
);
209 * Node is mounted on.
211 error
= VFS_ROOT(vfsp
, &newvp
);
215 mutex_enter(&fnp
->fn_lock
);
216 if (fnp
->fn_seen
== newvp
&& fnp
->fn_thread
== curthread
) {
218 * Recursive auto_getattr(); just release newvp and drop
219 * into the vfsp == NULL case.
221 mutex_exit(&fnp
->fn_lock
);
224 while (fnp
->fn_thread
&& fnp
->fn_thread
!= curthread
) {
225 fnp
->fn_flags
|= MF_ATTR_WAIT
;
226 cv_wait(&fnp
->fn_cv_mount
, &fnp
->fn_lock
);
228 fnp
->fn_thread
= curthread
;
229 fnp
->fn_seen
= newvp
;
230 mutex_exit(&fnp
->fn_lock
);
231 error
= fop_getattr(newvp
, vap
, flags
, cred
, ct
);
233 mutex_enter(&fnp
->fn_lock
);
236 if (fnp
->fn_flags
& MF_ATTR_WAIT
) {
237 fnp
->fn_flags
&= ~MF_ATTR_WAIT
;
238 cv_broadcast(&fnp
->fn_cv_mount
);
240 mutex_exit(&fnp
->fn_lock
);
248 ASSERT(vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
);
251 vap
->va_nlink
= fnp
->fn_linkcnt
;
252 vap
->va_nodeid
= (u_longlong_t
)fnp
->fn_nodeid
;
253 vap
->va_size
= fnp
->fn_size
;
254 vap
->va_atime
= fnp
->fn_atime
;
255 vap
->va_mtime
= fnp
->fn_mtime
;
256 vap
->va_ctime
= fnp
->fn_ctime
;
257 vap
->va_type
= vp
->v_type
;
258 vap
->va_mode
= fnp
->fn_mode
;
259 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
261 vap
->va_blksize
= MAXBSIZE
;
262 vap
->va_nblocks
= (fsblkcnt64_t
)btod(vap
->va_size
);
275 caller_context_t
*ct
)
280 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp
));
282 if (error
= auto_trigger_mount(vp
, cred
, &newvp
))
287 * Node is mounted on.
289 if (vn_is_readonly(newvp
))
292 error
= fop_setattr(newvp
, vap
, flags
, cred
, ct
);
298 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error
));
309 caller_context_t
*ct
)
311 fnnode_t
*fnp
= vntofn(vp
);
315 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp
));
317 if (error
= auto_trigger_mount(vp
, cred
, &newvp
))
322 * Node is mounted on.
324 error
= fop_access(newvp
, mode
, 0, cred
, ct
);
330 * really interested in the autofs node, check the
334 if (crgetuid(cred
) != fnp
->fn_uid
) {
336 if (groupmember(fnp
->fn_gid
, cred
) == 0)
339 error
= secpolicy_vnode_access2(cred
, vp
, fnp
->fn_uid
,
340 fnp
->fn_mode
<< shift
, mode
);
344 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error
));
357 caller_context_t
*ct
,
362 vnode_t
*newvp
= NULL
;
365 fnnode_t
*dfnp
= NULL
;
366 fnnode_t
*fnp
= NULL
;
368 int operation
; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
370 dfnip
= vfstofni(dvp
->v_vfsp
);
371 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
372 (void *)dvp
, dfnip
->fi_map
, nm
));
380 if (error
= fop_access(dvp
, VEXEC
, 0, cred
, ct
))
383 if (nm
[0] == '.' && nm
[1] == 0) {
389 if (nm
[0] == '.' && nm
[1] == '.' && nm
[2] == 0) {
392 pdfnp
= (vntofn(dvp
))->fn_parent
;
393 ASSERT(pdfnp
!= NULL
);
396 * Since it is legitimate to have the VROOT flag set for the
397 * subdirectories of the indirect map in autofs filesystem,
398 * rootfnnodep is checked against fnnode of dvp instead of
399 * just checking whether VROOT flag is set in dvp
402 if (pdfnp
== pdfnp
->fn_globals
->fng_rootfnnodep
) {
405 vfs_rlock_wait(dvp
->v_vfsp
);
406 if (dvp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
) {
407 vfs_unlock(dvp
->v_vfsp
);
410 vp
= dvp
->v_vfsp
->vfs_vnodecovered
;
412 vfs_unlock(dvp
->v_vfsp
);
413 error
= fop_lookup(vp
, nm
, vpp
, pnp
, flags
, rdir
, cred
,
414 ct
, direntflags
, realpnp
);
418 *vpp
= fntovn(pdfnp
);
429 ASSERT(vn_matchops(dvp
, &auto_vnodeops
));
431 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp
,
435 * If a lookup or mount of this node is in progress, wait for it
436 * to finish, and return whatever result it got.
438 mutex_enter(&dfnp
->fn_lock
);
439 if (dfnp
->fn_flags
& (MF_LOOKUP
| MF_INPROG
)) {
440 mutex_exit(&dfnp
->fn_lock
);
441 error
= auto_wait4mount(dfnp
);
442 if (error
== AUTOFS_SHUTDOWN
)
449 mutex_exit(&dfnp
->fn_lock
);
452 error
= vn_vfsrlock_wait(dvp
);
455 vfsp
= vn_mountedvfs(dvp
);
457 error
= VFS_ROOT(vfsp
, &newvp
);
460 error
= fop_lookup(newvp
, nm
, vpp
, pnp
,
461 flags
, rdir
, cred
, ct
, direntflags
, realpnp
);
468 rw_enter(&dfnp
->fn_rwlock
, RW_READER
);
469 error
= auto_search(dfnp
, nm
, &fnp
, cred
);
471 if (dfnip
->fi_flags
& MF_DIRECT
) {
475 if (dfnp
->fn_dirents
) {
477 * Mount previously triggered.
483 * I need to contact the daemon to trigger
484 * the mount. 'dfnp' will be the mountpoint.
486 operation
= AUTOFS_MOUNT
;
487 VN_HOLD(fntovn(dfnp
));
491 } else if (dvp
== dfnip
->fi_rootvp
) {
493 * 'dfnp' is the root of the indirect AUTOFS.
495 if (rw_tryupgrade(&dfnp
->fn_rwlock
) == 0) {
497 * Could not acquire writer lock, release
498 * reader, and wait until available. We
499 * need to search for 'nm' again, since we
500 * had to release the lock before reacquiring
503 rw_exit(&dfnp
->fn_rwlock
);
504 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
505 error
= auto_search(dfnp
, nm
, &fnp
, cred
);
508 ASSERT(RW_WRITE_HELD(&dfnp
->fn_rwlock
));
511 * create node being looked-up and request
514 error
= auto_enter(dfnp
, nm
, &fnp
, kcred
);
516 operation
= AUTOFS_LOOKUP
;
518 } else if ((dfnp
->fn_dirents
== NULL
) &&
519 ((dvp
->v_flag
& VROOT
) == 0) &&
520 ((fntovn(dfnp
->fn_parent
))->v_flag
& VROOT
)) {
522 * dfnp is the actual 'mountpoint' of indirect map,
523 * it is the equivalent of a direct mount,
526 operation
= AUTOFS_MOUNT
;
527 VN_HOLD(fntovn(dfnp
));
530 searchnm
= dfnp
->fn_name
;
534 if (error
== EAGAIN
) {
535 rw_exit(&dfnp
->fn_rwlock
);
539 rw_exit(&dfnp
->fn_rwlock
);
544 * We now have the actual fnnode we're interested in.
545 * The 'MF_LOOKUP' indicates another thread is currently
546 * performing a daemon lookup of this node, therefore we
547 * wait for its completion.
548 * The 'MF_INPROG' indicates another thread is currently
549 * performing a daemon mount of this node, we wait for it
550 * to be done if we are performing a MOUNT. We don't
551 * wait for it if we are performing a LOOKUP.
552 * We can release the reader/writer lock as soon as we acquire
553 * the mutex, since the state of the lock can only change by
554 * first acquiring the mutex.
556 mutex_enter(&fnp
->fn_lock
);
557 rw_exit(&dfnp
->fn_rwlock
);
558 if ((fnp
->fn_flags
& MF_LOOKUP
) ||
559 ((operation
== AUTOFS_MOUNT
) && (fnp
->fn_flags
& MF_INPROG
))) {
560 mutex_exit(&fnp
->fn_lock
);
561 error
= auto_wait4mount(fnp
);
562 VN_RELE(fntovn(fnp
));
563 if (error
== AUTOFS_SHUTDOWN
)
565 if (error
&& error
!= EAGAIN
)
570 if (operation
== 0) {
572 * got the fnnode, check for any errors
573 * on the previous operation on that node.
575 error
= fnp
->fn_error
;
576 if ((error
== EINTR
) || (error
== EAGAIN
)) {
578 * previous operation on this node was
579 * not completed, do a lookup now.
581 operation
= AUTOFS_LOOKUP
;
584 * previous operation completed. Return
585 * a pointer to the node only if there was
588 mutex_exit(&fnp
->fn_lock
);
592 VN_RELE(fntovn(fnp
));
598 * Since I got to this point, it means I'm the one
599 * responsible for triggering the mount/look-up of this node.
603 AUTOFS_BLOCK_OTHERS(fnp
, MF_LOOKUP
);
605 mutex_exit(&fnp
->fn_lock
);
606 error
= auto_lookup_aux(fnp
, searchnm
, cred
);
614 * release our reference to this vnode
617 VN_RELE(fntovn(fnp
));
621 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
623 mutex_exit(&fnp
->fn_lock
);
625 * auto_new_mount_thread fires up a new thread which
626 * calls automountd finishing up the work
628 auto_new_mount_thread(fnp
, searchnm
, cred
);
631 * At this point, we are simply another thread
632 * waiting for the mount to complete
634 error
= auto_wait4mount(fnp
);
635 if (error
== AUTOFS_SHUTDOWN
)
639 * now release our reference to this vnode
641 VN_RELE(fntovn(fnp
));
646 auto_log(dfnp
->fn_globals
->fng_verbose
,
647 dfnp
->fn_globals
->fng_zoneid
, CE_WARN
,
648 "auto_lookup: unknown operation %d",
652 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
653 nm
, (void *)*vpp
, error
));
668 caller_context_t
*ct
,
674 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp
, nm
));
676 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
681 * Node is now mounted on.
683 if (vn_is_readonly(newvp
))
686 error
= fop_create(newvp
, nm
, va
, excl
,
687 mode
, vpp
, cred
, flag
, ct
, vsecp
);
693 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error
));
702 caller_context_t
*ct
,
708 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp
, nm
));
710 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
715 * Node is now mounted on.
717 if (vn_is_readonly(newvp
))
720 error
= fop_remove(newvp
, nm
, cred
, ct
, flags
);
726 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error
));
736 caller_context_t
*ct
,
742 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp
,
745 if (error
= auto_trigger_mount(tdvp
, cred
, &newvp
))
750 * an autonode can not be a link to another node
756 if (vn_is_readonly(newvp
)) {
762 if (vn_matchops(svp
, &auto_vnodeops
)) {
764 * source vp can't be an autonode
771 error
= fop_link(newvp
, svp
, nm
, cred
, ct
, flags
);
775 AUTOFS_DPRINT((5, "auto_link error=%d\n", error
));
786 caller_context_t
*ct
,
789 vnode_t
*o_newvp
, *n_newvp
;
792 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
793 (void *)odvp
, onm
, (void *)ndvp
, nnm
));
796 * we know odvp is an autonode, otherwise this function
797 * could not have ever been called.
799 ASSERT(vn_matchops(odvp
, &auto_vnodeops
));
801 if (error
= auto_trigger_mount(odvp
, cr
, &o_newvp
))
804 if (o_newvp
== NULL
) {
806 * can't rename an autonode
812 if (vn_matchops(ndvp
, &auto_vnodeops
)) {
814 * directory is AUTOFS, need to trigger the
815 * mount of the real filesystem.
817 if (error
= auto_trigger_mount(ndvp
, cr
, &n_newvp
)) {
822 if (n_newvp
== NULL
) {
824 * target can't be an autonode
832 * destination directory mount had been
833 * triggered prior to the call to this function.
838 ASSERT(!vn_matchops(n_newvp
, &auto_vnodeops
));
840 if (vn_is_readonly(n_newvp
)) {
848 error
= fop_rename(o_newvp
, onm
, n_newvp
, nnm
, cr
, ct
, flags
);
854 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error
));
865 caller_context_t
*ct
,
872 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp
, nm
));
874 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
879 * Node is now mounted on.
881 if (vn_is_readonly(newvp
))
884 error
= fop_mkdir(newvp
, nm
, va
, vpp
, cred
, ct
,
891 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error
));
901 caller_context_t
*ct
,
907 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp
, nm
));
909 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
914 * Node is now mounted on.
916 if (vn_is_readonly(newvp
))
919 error
= fop_rmdir(newvp
, nm
, cdir
, cred
, ct
, flags
);
925 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error
));
929 static int autofs_nobrowse
= 0;
934 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
943 caller_context_t
*ct
,
946 struct autofs_rddirargs rda
;
948 fnnode_t
*fnp
= vntofn(vp
);
949 fnnode_t
*cfnp
, *nfnp
;
952 ulong_t outcount
= 0, count
= 0;
956 fninfo_t
*fnip
= vfstofni(vp
->v_vfsp
);
962 struct autofs_globals
*fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
964 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
965 (void *)vp
, uiop
->uio_loffset
));
970 if (uiop
->uio_iovcnt
!= 1)
973 iovp
= uiop
->uio_iov
;
974 alloc_count
= iovp
->iov_len
;
976 gethrestime(&fnp
->fn_atime
);
977 fnp
->fn_ref_time
= fnp
->fn_atime
.tv_sec
;
979 dp
= outbuf
= kmem_zalloc(alloc_count
, KM_SLEEP
);
982 * Held when getdents calls fop_rwlock....
984 ASSERT(RW_READ_HELD(&fnp
->fn_rwlock
));
985 if (uiop
->uio_offset
>= AUTOFS_DAEMONCOOKIE
) {
988 * Do readdir of daemon contents only
989 * Drop readers lock and reacquire after reply.
991 rw_exit(&fnp
->fn_rwlock
);
992 bzero(&rd
, sizeof (struct autofs_rddirres
));
994 rda
.rda_map
= fnip
->fi_map
;
995 rda
.rda_offset
= (uint_t
)uiop
->uio_offset
;
996 rd
.rd_rddir
.rddir_entries
= dp
;
997 rda
.rda_count
= rd
.rd_rddir
.rddir_size
= (uint_t
)alloc_count
;
998 rda
.uid
= crgetuid(cred
);
1000 error
= auto_calldaemon(fngp
->fng_zoneid
,
1002 xdr_autofs_rddirargs
,
1004 xdr_autofs_rddirres
,
1006 sizeof (autofs_rddirres
),
1010 * reacquire previously dropped lock
1012 rw_enter(&fnp
->fn_rwlock
, RW_READER
);
1015 error
= rd
.rd_status
;
1016 dp
= rd
.rd_rddir
.rddir_entries
;
1020 if (error
== AUTOFS_SHUTDOWN
) {
1022 * treat as empty directory
1031 if (rd
.rd_rddir
.rddir_size
) {
1032 dirent64_t
*odp
= dp
; /* next in output buffer */
1033 dirent64_t
*cdp
= dp
; /* current examined entry */
1036 * Check for duplicates here
1039 this_reclen
= cdp
->d_reclen
;
1040 if (auto_search(fnp
, cdp
->d_name
,
1043 * entry not found in kernel list,
1044 * include it in readdir output.
1046 * If we are skipping entries. then
1047 * we need to copy this entry to the
1048 * correct position in the buffer
1053 (size_t)this_reclen
);
1055 outcount
+= this_reclen
;
1058 * Entry was found in the kernel
1059 * list. If it is the first entry
1060 * in this buffer, then just skip it
1067 count
+= this_reclen
;
1068 cdp
= (struct dirent64
*)
1069 ((char *)cdp
+ this_reclen
);
1070 } while (count
< rd
.rd_rddir
.rddir_size
);
1073 error
= uiomove(dp
, outcount
, UIO_READ
, uiop
);
1074 uiop
->uio_offset
= rd
.rd_rddir
.rddir_offset
;
1076 if (rd
.rd_rddir
.rddir_eof
== 0) {
1078 * alloc_count not large enough for one
1084 if (rd
.rd_rddir
.rddir_eof
&& !error
) {
1089 if (!error
&& !myeof
&& outcount
== 0) {
1091 * call daemon with new cookie, all previous
1092 * elements happened to be duplicates
1100 if (uiop
->uio_offset
== 0) {
1102 * first time: so fudge the . and ..
1104 this_reclen
= DIRENT64_RECLEN(1);
1105 if (alloc_count
< this_reclen
) {
1109 dp
->d_ino
= (ino64_t
)fnp
->fn_nodeid
;
1110 dp
->d_off
= (off64_t
)1;
1111 dp
->d_reclen
= (ushort_t
)this_reclen
;
1113 /* use strncpy(9f) to zero out uninitialized bytes */
1115 (void) strncpy(dp
->d_name
, ".",
1116 DIRENT64_NAMELEN(this_reclen
));
1117 outcount
+= dp
->d_reclen
;
1120 this_reclen
= DIRENT64_RECLEN(2);
1121 if (alloc_count
< outcount
+ this_reclen
) {
1125 dp
->d_reclen
= (ushort_t
)this_reclen
;
1126 dp
->d_ino
= (ino64_t
)fnp
->fn_parent
->fn_nodeid
;
1127 dp
->d_off
= (off64_t
)2;
1129 /* use strncpy(9f) to zero out uninitialized bytes */
1131 (void) strncpy(dp
->d_name
, "..",
1132 DIRENT64_NAMELEN(this_reclen
));
1133 outcount
+= dp
->d_reclen
;
1138 cfnp
= fnp
->fn_dirents
;
1139 while (cfnp
!= NULL
) {
1140 nfnp
= cfnp
->fn_next
;
1141 offset
= cfnp
->fn_offset
;
1142 if ((offset
>= uiop
->uio_offset
) &&
1143 (!(cfnp
->fn_flags
& MF_LOOKUP
))) {
1147 * include node only if its offset is greater or
1148 * equal to the one required and it is not in
1149 * transient state (not being looked-up)
1151 namelen
= strlen(cfnp
->fn_name
);
1152 reclen
= (int)DIRENT64_RECLEN(namelen
);
1153 if (outcount
+ reclen
> alloc_count
) {
1157 dp
->d_reclen
= (ushort_t
)reclen
;
1158 dp
->d_ino
= (ino64_t
)cfnp
->fn_nodeid
;
1161 * get the offset of the next element
1163 dp
->d_off
= (off64_t
)nfnp
->fn_offset
;
1166 * This is the last element, make
1167 * offset one plus the current
1169 dp
->d_off
= (off64_t
)cfnp
->fn_offset
+ 1;
1172 /* use strncpy(9f) to zero out uninitialized bytes */
1174 (void) strncpy(dp
->d_name
, cfnp
->fn_name
,
1175 DIRENT64_NAMELEN(reclen
));
1176 outcount
+= dp
->d_reclen
;
1183 error
= uiomove(outbuf
, outcount
, UIO_READ
, uiop
);
1188 * This entry did not get added to the buffer on this,
1189 * call. We need to add it on the next call therefore
1190 * set uio_offset to this entry's offset. If there
1191 * wasn't enough space for one dirent, return EINVAL.
1193 uiop
->uio_offset
= offset
;
1196 } else if (autofs_nobrowse
||
1197 auto_nobrowse_option(fnip
->fi_opts
) ||
1198 (fnip
->fi_flags
& MF_DIRECT
) ||
1199 (fnp
->fn_trigger
!= NULL
) ||
1200 (((vp
->v_flag
& VROOT
) == 0) &&
1201 ((fntovn(fnp
->fn_parent
))->v_flag
& VROOT
) &&
1202 (fnp
->fn_dirents
== NULL
))) {
1204 * done reading directory entries
1206 uiop
->uio_offset
= offset
+ 1;
1211 * Need to get the rest of the entries from the daemon.
1213 uiop
->uio_offset
= AUTOFS_DAEMONCOOKIE
;
1218 kmem_free(outbuf
, alloc_count
);
1219 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1220 (void *)vp
, uiop
->uio_loffset
, myeof
));
1227 char *lnknm
, /* new entry */
1229 char *tnm
, /* existing entry */
1231 caller_context_t
*ct
,
1237 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
1238 (void *)dvp
, lnknm
, tnm
));
1240 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
1243 if (newvp
!= NULL
) {
1245 * Node is mounted on.
1247 if (vn_is_readonly(newvp
))
1250 error
= fop_symlink(newvp
, lnknm
, tva
, tnm
, cred
,
1257 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error
));
1263 auto_readlink(vnode_t
*vp
, struct uio
*uiop
, cred_t
*cr
, caller_context_t
*ct
)
1265 fnnode_t
*fnp
= vntofn(vp
);
1269 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp
));
1272 fnp
->fn_ref_time
= now
.tv_sec
;
1274 if (vp
->v_type
!= VLNK
)
1277 ASSERT(!(fnp
->fn_flags
& (MF_INPROG
| MF_LOOKUP
)));
1278 fnp
->fn_atime
= now
;
1279 error
= uiomove(fnp
->fn_symlink
, MIN(fnp
->fn_symlinklen
,
1280 uiop
->uio_resid
), UIO_READ
, uiop
);
1283 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error
));
1289 auto_fsync(vnode_t
*cp
, int syncflag
, cred_t
*cred
, caller_context_t
*ct
)
1296 auto_inactive(vnode_t
*vp
, cred_t
*cred
, caller_context_t
*ct
)
1298 fnnode_t
*fnp
= vntofn(vp
);
1299 fnnode_t
*dfnp
= fnp
->fn_parent
;
1302 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
1303 (void *)vp
, vp
->v_count
, fnp
->fn_linkcnt
));
1306 * The rwlock should not be already held by this thread.
1307 * The assert relies on the fact that the owner field is cleared
1308 * when the lock is released.
1310 ASSERT(dfnp
!= NULL
);
1311 ASSERT(rw_owner(&dfnp
->fn_rwlock
) != curthread
);
1312 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
1313 mutex_enter(&vp
->v_lock
);
1314 ASSERT(vp
->v_count
> 0);
1316 count
= vp
->v_count
;
1317 mutex_exit(&vp
->v_lock
);
1320 * Free only if node has no subdirectories.
1322 if (fnp
->fn_linkcnt
== 1) {
1323 auto_disconnect(dfnp
, fnp
);
1324 rw_exit(&dfnp
->fn_rwlock
);
1325 auto_freefnnode(fnp
);
1326 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
1331 rw_exit(&dfnp
->fn_rwlock
);
1333 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
1334 (void *)vp
, vp
->v_count
, fnp
->fn_linkcnt
));
1339 auto_rwlock(vnode_t
*vp
, int write_lock
, caller_context_t
*ct
)
1341 fnnode_t
*fnp
= vntofn(vp
);
1343 rw_enter(&fnp
->fn_rwlock
, RW_WRITER
);
1345 rw_enter(&fnp
->fn_rwlock
, RW_READER
);
1346 return (write_lock
);
1351 auto_rwunlock(vnode_t
*vp
, int write_lock
, caller_context_t
*ct
)
1353 fnnode_t
*fnp
= vntofn(vp
);
1354 rw_exit(&fnp
->fn_rwlock
);
1364 caller_context_t
*ct
)
1367 * Return 0 unconditionally, since we expect
1368 * a VDIR all the time
1374 * Triggers the mount if needed. If the mount has been triggered by
1375 * another thread, it will wait for its return status, and return it.
1376 * Whether the mount is triggered by this thread, another thread, or
1377 * if the vnode was already covered, '*newvp' is a
1378 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
1379 * If the node is not mounted on, and should not be mounted on, '*newvp'
1381 * The calling routine may use '*newvp' to do the filesystem jump.
1384 auto_trigger_mount(vnode_t
*vp
, cred_t
*cred
, vnode_t
**newvp
)
1386 fnnode_t
*fnp
= vntofn(vp
);
1387 fninfo_t
*fnip
= vfstofni(vp
->v_vfsp
);
1391 char name
[AUTOFS_MAXPATHLEN
];
1394 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp
));
1399 * Cross-zone mount triggering is disallowed.
1401 if (fnip
->fi_zoneid
!= getzoneid())
1402 return (EPERM
); /* Not owner of mount */
1407 mutex_enter(&fnp
->fn_lock
);
1408 while (fnp
->fn_flags
& (MF_LOOKUP
| MF_INPROG
)) {
1410 * Mount or lookup in progress,
1411 * wait for it before proceeding.
1413 mutex_exit(&fnp
->fn_lock
);
1414 error
= auto_wait4mount(fnp
);
1415 if (error
== AUTOFS_SHUTDOWN
) {
1419 if (error
&& error
!= EAGAIN
)
1422 mutex_enter(&fnp
->fn_lock
);
1426 * If the vfslock can't be acquired for the first time.
1427 * drop the fn_lock and retry next time in blocking mode.
1429 if (vn_vfswlock(vp
)) {
1431 * Lock held by another thread.
1432 * Perform blocking by dropping the
1435 mutex_exit(&fnp
->fn_lock
);
1436 error
= vn_vfswlock_wait(vp
);
1440 * Because fn_lock wasn't held, the state
1441 * of the trigger node might have changed.
1442 * Need to run through the checks on trigger
1449 vfsp
= vn_mountedvfs(vp
);
1451 mutex_exit(&fnp
->fn_lock
);
1452 error
= VFS_ROOT(vfsp
, newvp
);
1457 if ((fnp
->fn_flags
& MF_MOUNTPOINT
) &&
1458 fnp
->fn_trigger
!= NULL
) {
1459 ASSERT(fnp
->fn_dirents
== NULL
);
1460 mutex_exit(&fnp
->fn_lock
);
1462 * The filesystem that used to sit here has been
1463 * forcibly unmounted. Do our best to recover.
1464 * Try to unmount autofs subtree below this node
1465 * and retry the action.
1467 if (unmount_subtree(fnp
, B_TRUE
) != 0) {
1475 ASSERT(vp
->v_type
== VDIR
);
1476 dvp
= fntovn(fnp
->fn_parent
);
1478 if ((fnp
->fn_dirents
== NULL
) &&
1479 ((fnip
->fi_flags
& MF_DIRECT
) == 0) &&
1480 ((vp
->v_flag
& VROOT
) == 0) &&
1481 (dvp
->v_flag
& VROOT
)) {
1483 * If the parent of this node is the root of an indirect
1484 * AUTOFS filesystem, this node is remountable.
1490 ((fnip
->fi_flags
& MF_DIRECT
) && (fnp
->fn_dirents
== NULL
))) {
1492 * Trigger mount since:
1493 * direct mountpoint with no subdirs or
1496 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
1498 mutex_exit(&fnp
->fn_lock
);
1500 (void) strcpy(name
, fnp
->fn_name
);
1502 (void) strcpy(name
, ".");
1503 fnp
->fn_ref_time
= gethrestime_sec();
1504 auto_new_mount_thread(fnp
, name
, cred
);
1506 * At this point we're simply another thread waiting
1507 * for the mount to finish.
1509 error
= auto_wait4mount(fnp
);
1510 if (error
== EAGAIN
)
1512 if (error
== AUTOFS_SHUTDOWN
) {
1517 if (error
= vn_vfsrlock_wait(vp
))
1519 /* Reacquire after dropping locks */
1520 vfsp
= vn_mountedvfs(vp
);
1522 error
= VFS_ROOT(vfsp
, newvp
);
1530 mutex_exit(&fnp
->fn_lock
);
1533 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error
));