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.
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/errno.h>
29 #include <sys/vnode.h>
31 #include <sys/vfs_opreg.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 vnodeops_t
*auto_vnodeops
;
91 const fs_operation_def_t auto_vnodeops_template
[] = {
92 VOPNAME_OPEN
, { .vop_open
= auto_open
},
93 VOPNAME_CLOSE
, { .vop_close
= auto_close
},
94 VOPNAME_GETATTR
, { .vop_getattr
= auto_getattr
},
95 VOPNAME_SETATTR
, { .vop_setattr
= auto_setattr
},
96 VOPNAME_ACCESS
, { .vop_access
= auto_access
},
97 VOPNAME_LOOKUP
, { .vop_lookup
= auto_lookup
},
98 VOPNAME_CREATE
, { .vop_create
= auto_create
},
99 VOPNAME_REMOVE
, { .vop_remove
= auto_remove
},
100 VOPNAME_LINK
, { .vop_link
= auto_link
},
101 VOPNAME_RENAME
, { .vop_rename
= auto_rename
},
102 VOPNAME_MKDIR
, { .vop_mkdir
= auto_mkdir
},
103 VOPNAME_RMDIR
, { .vop_rmdir
= auto_rmdir
},
104 VOPNAME_READDIR
, { .vop_readdir
= auto_readdir
},
105 VOPNAME_SYMLINK
, { .vop_symlink
= auto_symlink
},
106 VOPNAME_READLINK
, { .vop_readlink
= auto_readlink
},
107 VOPNAME_FSYNC
, { .vop_fsync
= auto_fsync
},
108 VOPNAME_INACTIVE
, { .vop_inactive
= auto_inactive
},
109 VOPNAME_RWLOCK
, { .vop_rwlock
= auto_rwlock
},
110 VOPNAME_RWUNLOCK
, { .vop_rwunlock
= auto_rwunlock
},
111 VOPNAME_SEEK
, { .vop_seek
= auto_seek
},
112 VOPNAME_FRLOCK
, { .error
= fs_nosys
},
113 VOPNAME_DISPOSE
, { .vop_dispose
= fs_nodispose
},
114 VOPNAME_SHRLOCK
, { .error
= fs_nosys
},
115 VOPNAME_VNEVENT
, { .vop_vnevent
= fs_vnevent_support
},
123 auto_open(vnode_t
**vpp
, int flag
, cred_t
*cred
, caller_context_t
*ct
)
128 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp
));
130 error
= auto_trigger_mount(*vpp
, cred
, &newvp
);
136 * Node is now mounted on.
140 error
= fop_access(*vpp
, VREAD
, 0, cred
, ct
);
142 error
= fop_open(vpp
, flag
, cred
, ct
);
146 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp
,
159 caller_context_t
*ct
)
170 caller_context_t
*ct
)
172 fnnode_t
*fnp
= vntofn(vp
);
177 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp
));
179 if (flags
& ATTR_TRIGGER
) {
181 * Pre-trigger the mount
183 error
= auto_trigger_mount(vp
, cred
, &newvp
);
190 if (error
= vn_vfsrlock_wait(vp
)) {
195 vfsp
= newvp
->v_vfsp
;
199 * Recursive auto_getattr/mount; go to the vfsp == NULL
202 if (vn_vfswlock_held(vp
))
205 if (error
= vn_vfsrlock_wait(vp
))
208 vfsp
= vn_mountedvfs(vp
);
213 * Node is mounted on.
215 error
= VFS_ROOT(vfsp
, &newvp
);
219 mutex_enter(&fnp
->fn_lock
);
220 if (fnp
->fn_seen
== newvp
&& fnp
->fn_thread
== curthread
) {
222 * Recursive auto_getattr(); just release newvp and drop
223 * into the vfsp == NULL case.
225 mutex_exit(&fnp
->fn_lock
);
228 while (fnp
->fn_thread
&& fnp
->fn_thread
!= curthread
) {
229 fnp
->fn_flags
|= MF_ATTR_WAIT
;
230 cv_wait(&fnp
->fn_cv_mount
, &fnp
->fn_lock
);
232 fnp
->fn_thread
= curthread
;
233 fnp
->fn_seen
= newvp
;
234 mutex_exit(&fnp
->fn_lock
);
235 error
= fop_getattr(newvp
, vap
, flags
, cred
, ct
);
237 mutex_enter(&fnp
->fn_lock
);
240 if (fnp
->fn_flags
& MF_ATTR_WAIT
) {
241 fnp
->fn_flags
&= ~MF_ATTR_WAIT
;
242 cv_broadcast(&fnp
->fn_cv_mount
);
244 mutex_exit(&fnp
->fn_lock
);
252 ASSERT(vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
);
255 vap
->va_nlink
= fnp
->fn_linkcnt
;
256 vap
->va_nodeid
= (u_longlong_t
)fnp
->fn_nodeid
;
257 vap
->va_size
= fnp
->fn_size
;
258 vap
->va_atime
= fnp
->fn_atime
;
259 vap
->va_mtime
= fnp
->fn_mtime
;
260 vap
->va_ctime
= fnp
->fn_ctime
;
261 vap
->va_type
= vp
->v_type
;
262 vap
->va_mode
= fnp
->fn_mode
;
263 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
265 vap
->va_blksize
= MAXBSIZE
;
266 vap
->va_nblocks
= (fsblkcnt64_t
)btod(vap
->va_size
);
279 caller_context_t
*ct
)
284 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp
));
286 if (error
= auto_trigger_mount(vp
, cred
, &newvp
))
291 * Node is mounted on.
293 if (vn_is_readonly(newvp
))
296 error
= fop_setattr(newvp
, vap
, flags
, cred
, ct
);
302 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error
));
313 caller_context_t
*ct
)
315 fnnode_t
*fnp
= vntofn(vp
);
319 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp
));
321 if (error
= auto_trigger_mount(vp
, cred
, &newvp
))
326 * Node is mounted on.
328 error
= fop_access(newvp
, mode
, 0, cred
, ct
);
334 * really interested in the autofs node, check the
338 if (crgetuid(cred
) != fnp
->fn_uid
) {
340 if (groupmember(fnp
->fn_gid
, cred
) == 0)
343 error
= secpolicy_vnode_access2(cred
, vp
, fnp
->fn_uid
,
344 fnp
->fn_mode
<< shift
, mode
);
348 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error
));
361 caller_context_t
*ct
,
366 vnode_t
*newvp
= NULL
;
369 fnnode_t
*dfnp
= NULL
;
370 fnnode_t
*fnp
= NULL
;
372 int operation
; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
374 dfnip
= vfstofni(dvp
->v_vfsp
);
375 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
376 (void *)dvp
, dfnip
->fi_map
, nm
));
384 if (error
= fop_access(dvp
, VEXEC
, 0, cred
, ct
))
387 if (nm
[0] == '.' && nm
[1] == 0) {
393 if (nm
[0] == '.' && nm
[1] == '.' && nm
[2] == 0) {
396 pdfnp
= (vntofn(dvp
))->fn_parent
;
397 ASSERT(pdfnp
!= NULL
);
400 * Since it is legitimate to have the VROOT flag set for the
401 * subdirectories of the indirect map in autofs filesystem,
402 * rootfnnodep is checked against fnnode of dvp instead of
403 * just checking whether VROOT flag is set in dvp
406 if (pdfnp
== pdfnp
->fn_globals
->fng_rootfnnodep
) {
409 vfs_rlock_wait(dvp
->v_vfsp
);
410 if (dvp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
) {
411 vfs_unlock(dvp
->v_vfsp
);
414 vp
= dvp
->v_vfsp
->vfs_vnodecovered
;
416 vfs_unlock(dvp
->v_vfsp
);
417 error
= fop_lookup(vp
, nm
, vpp
, pnp
, flags
, rdir
, cred
,
418 ct
, direntflags
, realpnp
);
422 *vpp
= fntovn(pdfnp
);
433 ASSERT(vn_matchops(dvp
, auto_vnodeops
));
435 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp
,
439 * If a lookup or mount of this node is in progress, wait for it
440 * to finish, and return whatever result it got.
442 mutex_enter(&dfnp
->fn_lock
);
443 if (dfnp
->fn_flags
& (MF_LOOKUP
| MF_INPROG
)) {
444 mutex_exit(&dfnp
->fn_lock
);
445 error
= auto_wait4mount(dfnp
);
446 if (error
== AUTOFS_SHUTDOWN
)
453 mutex_exit(&dfnp
->fn_lock
);
456 error
= vn_vfsrlock_wait(dvp
);
459 vfsp
= vn_mountedvfs(dvp
);
461 error
= VFS_ROOT(vfsp
, &newvp
);
464 error
= fop_lookup(newvp
, nm
, vpp
, pnp
,
465 flags
, rdir
, cred
, ct
, direntflags
, realpnp
);
472 rw_enter(&dfnp
->fn_rwlock
, RW_READER
);
473 error
= auto_search(dfnp
, nm
, &fnp
, cred
);
475 if (dfnip
->fi_flags
& MF_DIRECT
) {
479 if (dfnp
->fn_dirents
) {
481 * Mount previously triggered.
487 * I need to contact the daemon to trigger
488 * the mount. 'dfnp' will be the mountpoint.
490 operation
= AUTOFS_MOUNT
;
491 VN_HOLD(fntovn(dfnp
));
495 } else if (dvp
== dfnip
->fi_rootvp
) {
497 * 'dfnp' is the root of the indirect AUTOFS.
499 if (rw_tryupgrade(&dfnp
->fn_rwlock
) == 0) {
501 * Could not acquire writer lock, release
502 * reader, and wait until available. We
503 * need to search for 'nm' again, since we
504 * had to release the lock before reacquiring
507 rw_exit(&dfnp
->fn_rwlock
);
508 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
509 error
= auto_search(dfnp
, nm
, &fnp
, cred
);
512 ASSERT(RW_WRITE_HELD(&dfnp
->fn_rwlock
));
515 * create node being looked-up and request
518 error
= auto_enter(dfnp
, nm
, &fnp
, kcred
);
520 operation
= AUTOFS_LOOKUP
;
522 } else if ((dfnp
->fn_dirents
== NULL
) &&
523 ((dvp
->v_flag
& VROOT
) == 0) &&
524 ((fntovn(dfnp
->fn_parent
))->v_flag
& VROOT
)) {
526 * dfnp is the actual 'mountpoint' of indirect map,
527 * it is the equivalent of a direct mount,
530 operation
= AUTOFS_MOUNT
;
531 VN_HOLD(fntovn(dfnp
));
534 searchnm
= dfnp
->fn_name
;
538 if (error
== EAGAIN
) {
539 rw_exit(&dfnp
->fn_rwlock
);
543 rw_exit(&dfnp
->fn_rwlock
);
548 * We now have the actual fnnode we're interested in.
549 * The 'MF_LOOKUP' indicates another thread is currently
550 * performing a daemon lookup of this node, therefore we
551 * wait for its completion.
552 * The 'MF_INPROG' indicates another thread is currently
553 * performing a daemon mount of this node, we wait for it
554 * to be done if we are performing a MOUNT. We don't
555 * wait for it if we are performing a LOOKUP.
556 * We can release the reader/writer lock as soon as we acquire
557 * the mutex, since the state of the lock can only change by
558 * first acquiring the mutex.
560 mutex_enter(&fnp
->fn_lock
);
561 rw_exit(&dfnp
->fn_rwlock
);
562 if ((fnp
->fn_flags
& MF_LOOKUP
) ||
563 ((operation
== AUTOFS_MOUNT
) && (fnp
->fn_flags
& MF_INPROG
))) {
564 mutex_exit(&fnp
->fn_lock
);
565 error
= auto_wait4mount(fnp
);
566 VN_RELE(fntovn(fnp
));
567 if (error
== AUTOFS_SHUTDOWN
)
569 if (error
&& error
!= EAGAIN
)
574 if (operation
== 0) {
576 * got the fnnode, check for any errors
577 * on the previous operation on that node.
579 error
= fnp
->fn_error
;
580 if ((error
== EINTR
) || (error
== EAGAIN
)) {
582 * previous operation on this node was
583 * not completed, do a lookup now.
585 operation
= AUTOFS_LOOKUP
;
588 * previous operation completed. Return
589 * a pointer to the node only if there was
592 mutex_exit(&fnp
->fn_lock
);
596 VN_RELE(fntovn(fnp
));
602 * Since I got to this point, it means I'm the one
603 * responsible for triggering the mount/look-up of this node.
607 AUTOFS_BLOCK_OTHERS(fnp
, MF_LOOKUP
);
609 mutex_exit(&fnp
->fn_lock
);
610 error
= auto_lookup_aux(fnp
, searchnm
, cred
);
618 * release our reference to this vnode
621 VN_RELE(fntovn(fnp
));
625 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
627 mutex_exit(&fnp
->fn_lock
);
629 * auto_new_mount_thread fires up a new thread which
630 * calls automountd finishing up the work
632 auto_new_mount_thread(fnp
, searchnm
, cred
);
635 * At this point, we are simply another thread
636 * waiting for the mount to complete
638 error
= auto_wait4mount(fnp
);
639 if (error
== AUTOFS_SHUTDOWN
)
643 * now release our reference to this vnode
645 VN_RELE(fntovn(fnp
));
650 auto_log(dfnp
->fn_globals
->fng_verbose
,
651 dfnp
->fn_globals
->fng_zoneid
, CE_WARN
,
652 "auto_lookup: unknown operation %d",
656 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
657 nm
, (void *)*vpp
, error
));
672 caller_context_t
*ct
,
678 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp
, nm
));
680 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
685 * Node is now mounted on.
687 if (vn_is_readonly(newvp
))
690 error
= fop_create(newvp
, nm
, va
, excl
,
691 mode
, vpp
, cred
, flag
, ct
, vsecp
);
697 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error
));
706 caller_context_t
*ct
,
712 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp
, nm
));
714 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
719 * Node is now mounted on.
721 if (vn_is_readonly(newvp
))
724 error
= fop_remove(newvp
, nm
, cred
, ct
, flags
);
730 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error
));
740 caller_context_t
*ct
,
746 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp
,
749 if (error
= auto_trigger_mount(tdvp
, cred
, &newvp
))
754 * an autonode can not be a link to another node
760 if (vn_is_readonly(newvp
)) {
766 if (vn_matchops(svp
, auto_vnodeops
)) {
768 * source vp can't be an autonode
775 error
= fop_link(newvp
, svp
, nm
, cred
, ct
, flags
);
779 AUTOFS_DPRINT((5, "auto_link error=%d\n", error
));
790 caller_context_t
*ct
,
793 vnode_t
*o_newvp
, *n_newvp
;
796 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
797 (void *)odvp
, onm
, (void *)ndvp
, nnm
));
800 * we know odvp is an autonode, otherwise this function
801 * could not have ever been called.
803 ASSERT(vn_matchops(odvp
, auto_vnodeops
));
805 if (error
= auto_trigger_mount(odvp
, cr
, &o_newvp
))
808 if (o_newvp
== NULL
) {
810 * can't rename an autonode
816 if (vn_matchops(ndvp
, auto_vnodeops
)) {
818 * directory is AUTOFS, need to trigger the
819 * mount of the real filesystem.
821 if (error
= auto_trigger_mount(ndvp
, cr
, &n_newvp
)) {
826 if (n_newvp
== NULL
) {
828 * target can't be an autonode
836 * destination directory mount had been
837 * triggered prior to the call to this function.
842 ASSERT(!vn_matchops(n_newvp
, auto_vnodeops
));
844 if (vn_is_readonly(n_newvp
)) {
852 error
= fop_rename(o_newvp
, onm
, n_newvp
, nnm
, cr
, ct
, flags
);
858 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error
));
869 caller_context_t
*ct
,
876 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp
, nm
));
878 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
883 * Node is now mounted on.
885 if (vn_is_readonly(newvp
))
888 error
= fop_mkdir(newvp
, nm
, va
, vpp
, cred
, ct
,
895 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error
));
905 caller_context_t
*ct
,
911 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp
, nm
));
913 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
918 * Node is now mounted on.
920 if (vn_is_readonly(newvp
))
923 error
= fop_rmdir(newvp
, nm
, cdir
, cred
, ct
, flags
);
929 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error
));
933 static int autofs_nobrowse
= 0;
938 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
947 caller_context_t
*ct
,
950 struct autofs_rddirargs rda
;
952 fnnode_t
*fnp
= vntofn(vp
);
953 fnnode_t
*cfnp
, *nfnp
;
956 ulong_t outcount
= 0, count
= 0;
960 fninfo_t
*fnip
= vfstofni(vp
->v_vfsp
);
966 struct autofs_globals
*fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
968 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
969 (void *)vp
, uiop
->uio_loffset
));
974 if (uiop
->uio_iovcnt
!= 1)
977 iovp
= uiop
->uio_iov
;
978 alloc_count
= iovp
->iov_len
;
980 gethrestime(&fnp
->fn_atime
);
981 fnp
->fn_ref_time
= fnp
->fn_atime
.tv_sec
;
983 dp
= outbuf
= kmem_zalloc(alloc_count
, KM_SLEEP
);
986 * Held when getdents calls fop_rwlock....
988 ASSERT(RW_READ_HELD(&fnp
->fn_rwlock
));
989 if (uiop
->uio_offset
>= AUTOFS_DAEMONCOOKIE
) {
992 * Do readdir of daemon contents only
993 * Drop readers lock and reacquire after reply.
995 rw_exit(&fnp
->fn_rwlock
);
996 bzero(&rd
, sizeof (struct autofs_rddirres
));
998 rda
.rda_map
= fnip
->fi_map
;
999 rda
.rda_offset
= (uint_t
)uiop
->uio_offset
;
1000 rd
.rd_rddir
.rddir_entries
= dp
;
1001 rda
.rda_count
= rd
.rd_rddir
.rddir_size
= (uint_t
)alloc_count
;
1002 rda
.uid
= crgetuid(cred
);
1004 error
= auto_calldaemon(fngp
->fng_zoneid
,
1006 xdr_autofs_rddirargs
,
1008 xdr_autofs_rddirres
,
1010 sizeof (autofs_rddirres
),
1014 * reacquire previously dropped lock
1016 rw_enter(&fnp
->fn_rwlock
, RW_READER
);
1019 error
= rd
.rd_status
;
1020 dp
= rd
.rd_rddir
.rddir_entries
;
1024 if (error
== AUTOFS_SHUTDOWN
) {
1026 * treat as empty directory
1035 if (rd
.rd_rddir
.rddir_size
) {
1036 dirent64_t
*odp
= dp
; /* next in output buffer */
1037 dirent64_t
*cdp
= dp
; /* current examined entry */
1040 * Check for duplicates here
1043 this_reclen
= cdp
->d_reclen
;
1044 if (auto_search(fnp
, cdp
->d_name
,
1047 * entry not found in kernel list,
1048 * include it in readdir output.
1050 * If we are skipping entries. then
1051 * we need to copy this entry to the
1052 * correct position in the buffer
1057 (size_t)this_reclen
);
1059 outcount
+= this_reclen
;
1062 * Entry was found in the kernel
1063 * list. If it is the first entry
1064 * in this buffer, then just skip it
1071 count
+= this_reclen
;
1072 cdp
= (struct dirent64
*)
1073 ((char *)cdp
+ this_reclen
);
1074 } while (count
< rd
.rd_rddir
.rddir_size
);
1077 error
= uiomove(dp
, outcount
, UIO_READ
, uiop
);
1078 uiop
->uio_offset
= rd
.rd_rddir
.rddir_offset
;
1080 if (rd
.rd_rddir
.rddir_eof
== 0) {
1082 * alloc_count not large enough for one
1088 if (rd
.rd_rddir
.rddir_eof
&& !error
) {
1093 if (!error
&& !myeof
&& outcount
== 0) {
1095 * call daemon with new cookie, all previous
1096 * elements happened to be duplicates
1104 if (uiop
->uio_offset
== 0) {
1106 * first time: so fudge the . and ..
1108 this_reclen
= DIRENT64_RECLEN(1);
1109 if (alloc_count
< this_reclen
) {
1113 dp
->d_ino
= (ino64_t
)fnp
->fn_nodeid
;
1114 dp
->d_off
= (off64_t
)1;
1115 dp
->d_reclen
= (ushort_t
)this_reclen
;
1117 /* use strncpy(9f) to zero out uninitialized bytes */
1119 (void) strncpy(dp
->d_name
, ".",
1120 DIRENT64_NAMELEN(this_reclen
));
1121 outcount
+= dp
->d_reclen
;
1124 this_reclen
= DIRENT64_RECLEN(2);
1125 if (alloc_count
< outcount
+ this_reclen
) {
1129 dp
->d_reclen
= (ushort_t
)this_reclen
;
1130 dp
->d_ino
= (ino64_t
)fnp
->fn_parent
->fn_nodeid
;
1131 dp
->d_off
= (off64_t
)2;
1133 /* use strncpy(9f) to zero out uninitialized bytes */
1135 (void) strncpy(dp
->d_name
, "..",
1136 DIRENT64_NAMELEN(this_reclen
));
1137 outcount
+= dp
->d_reclen
;
1142 cfnp
= fnp
->fn_dirents
;
1143 while (cfnp
!= NULL
) {
1144 nfnp
= cfnp
->fn_next
;
1145 offset
= cfnp
->fn_offset
;
1146 if ((offset
>= uiop
->uio_offset
) &&
1147 (!(cfnp
->fn_flags
& MF_LOOKUP
))) {
1151 * include node only if its offset is greater or
1152 * equal to the one required and it is not in
1153 * transient state (not being looked-up)
1155 namelen
= strlen(cfnp
->fn_name
);
1156 reclen
= (int)DIRENT64_RECLEN(namelen
);
1157 if (outcount
+ reclen
> alloc_count
) {
1161 dp
->d_reclen
= (ushort_t
)reclen
;
1162 dp
->d_ino
= (ino64_t
)cfnp
->fn_nodeid
;
1165 * get the offset of the next element
1167 dp
->d_off
= (off64_t
)nfnp
->fn_offset
;
1170 * This is the last element, make
1171 * offset one plus the current
1173 dp
->d_off
= (off64_t
)cfnp
->fn_offset
+ 1;
1176 /* use strncpy(9f) to zero out uninitialized bytes */
1178 (void) strncpy(dp
->d_name
, cfnp
->fn_name
,
1179 DIRENT64_NAMELEN(reclen
));
1180 outcount
+= dp
->d_reclen
;
1187 error
= uiomove(outbuf
, outcount
, UIO_READ
, uiop
);
1192 * This entry did not get added to the buffer on this,
1193 * call. We need to add it on the next call therefore
1194 * set uio_offset to this entry's offset. If there
1195 * wasn't enough space for one dirent, return EINVAL.
1197 uiop
->uio_offset
= offset
;
1200 } else if (autofs_nobrowse
||
1201 auto_nobrowse_option(fnip
->fi_opts
) ||
1202 (fnip
->fi_flags
& MF_DIRECT
) ||
1203 (fnp
->fn_trigger
!= NULL
) ||
1204 (((vp
->v_flag
& VROOT
) == 0) &&
1205 ((fntovn(fnp
->fn_parent
))->v_flag
& VROOT
) &&
1206 (fnp
->fn_dirents
== NULL
))) {
1208 * done reading directory entries
1210 uiop
->uio_offset
= offset
+ 1;
1215 * Need to get the rest of the entries from the daemon.
1217 uiop
->uio_offset
= AUTOFS_DAEMONCOOKIE
;
1222 kmem_free(outbuf
, alloc_count
);
1223 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1224 (void *)vp
, uiop
->uio_loffset
, myeof
));
1231 char *lnknm
, /* new entry */
1233 char *tnm
, /* existing entry */
1235 caller_context_t
*ct
,
1241 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
1242 (void *)dvp
, lnknm
, tnm
));
1244 if (error
= auto_trigger_mount(dvp
, cred
, &newvp
))
1247 if (newvp
!= NULL
) {
1249 * Node is mounted on.
1251 if (vn_is_readonly(newvp
))
1254 error
= fop_symlink(newvp
, lnknm
, tva
, tnm
, cred
,
1261 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error
));
1267 auto_readlink(vnode_t
*vp
, struct uio
*uiop
, cred_t
*cr
, caller_context_t
*ct
)
1269 fnnode_t
*fnp
= vntofn(vp
);
1273 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp
));
1276 fnp
->fn_ref_time
= now
.tv_sec
;
1278 if (vp
->v_type
!= VLNK
)
1281 ASSERT(!(fnp
->fn_flags
& (MF_INPROG
| MF_LOOKUP
)));
1282 fnp
->fn_atime
= now
;
1283 error
= uiomove(fnp
->fn_symlink
, MIN(fnp
->fn_symlinklen
,
1284 uiop
->uio_resid
), UIO_READ
, uiop
);
1287 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error
));
1293 auto_fsync(vnode_t
*cp
, int syncflag
, cred_t
*cred
, caller_context_t
*ct
)
1300 auto_inactive(vnode_t
*vp
, cred_t
*cred
, caller_context_t
*ct
)
1302 fnnode_t
*fnp
= vntofn(vp
);
1303 fnnode_t
*dfnp
= fnp
->fn_parent
;
1306 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
1307 (void *)vp
, vp
->v_count
, fnp
->fn_linkcnt
));
1310 * The rwlock should not be already held by this thread.
1311 * The assert relies on the fact that the owner field is cleared
1312 * when the lock is released.
1314 ASSERT(dfnp
!= NULL
);
1315 ASSERT(rw_owner(&dfnp
->fn_rwlock
) != curthread
);
1316 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
1317 mutex_enter(&vp
->v_lock
);
1318 ASSERT(vp
->v_count
> 0);
1319 count
= --vp
->v_count
;
1320 mutex_exit(&vp
->v_lock
);
1323 * Free only if node has no subdirectories.
1325 if (fnp
->fn_linkcnt
== 1) {
1326 auto_disconnect(dfnp
, fnp
);
1327 rw_exit(&dfnp
->fn_rwlock
);
1328 auto_freefnnode(fnp
);
1329 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
1334 rw_exit(&dfnp
->fn_rwlock
);
1336 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
1337 (void *)vp
, vp
->v_count
, fnp
->fn_linkcnt
));
1342 auto_rwlock(vnode_t
*vp
, int write_lock
, caller_context_t
*ct
)
1344 fnnode_t
*fnp
= vntofn(vp
);
1346 rw_enter(&fnp
->fn_rwlock
, RW_WRITER
);
1348 rw_enter(&fnp
->fn_rwlock
, RW_READER
);
1349 return (write_lock
);
1354 auto_rwunlock(vnode_t
*vp
, int write_lock
, caller_context_t
*ct
)
1356 fnnode_t
*fnp
= vntofn(vp
);
1357 rw_exit(&fnp
->fn_rwlock
);
1367 caller_context_t
*ct
)
1370 * Return 0 unconditionally, since we expect
1371 * a VDIR all the time
1377 * Triggers the mount if needed. If the mount has been triggered by
1378 * another thread, it will wait for its return status, and return it.
1379 * Whether the mount is triggered by this thread, another thread, or
1380 * if the vnode was already covered, '*newvp' is a
1381 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
1382 * If the node is not mounted on, and should not be mounted on, '*newvp'
1384 * The calling routine may use '*newvp' to do the filesystem jump.
1387 auto_trigger_mount(vnode_t
*vp
, cred_t
*cred
, vnode_t
**newvp
)
1389 fnnode_t
*fnp
= vntofn(vp
);
1390 fninfo_t
*fnip
= vfstofni(vp
->v_vfsp
);
1394 char name
[AUTOFS_MAXPATHLEN
];
1397 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp
));
1402 * Cross-zone mount triggering is disallowed.
1404 if (fnip
->fi_zoneid
!= getzoneid())
1405 return (EPERM
); /* Not owner of mount */
1410 mutex_enter(&fnp
->fn_lock
);
1411 while (fnp
->fn_flags
& (MF_LOOKUP
| MF_INPROG
)) {
1413 * Mount or lookup in progress,
1414 * wait for it before proceeding.
1416 mutex_exit(&fnp
->fn_lock
);
1417 error
= auto_wait4mount(fnp
);
1418 if (error
== AUTOFS_SHUTDOWN
) {
1422 if (error
&& error
!= EAGAIN
)
1425 mutex_enter(&fnp
->fn_lock
);
1429 * If the vfslock can't be acquired for the first time.
1430 * drop the fn_lock and retry next time in blocking mode.
1432 if (vn_vfswlock(vp
)) {
1434 * Lock held by another thread.
1435 * Perform blocking by dropping the
1438 mutex_exit(&fnp
->fn_lock
);
1439 error
= vn_vfswlock_wait(vp
);
1443 * Because fn_lock wasn't held, the state
1444 * of the trigger node might have changed.
1445 * Need to run through the checks on trigger
1452 vfsp
= vn_mountedvfs(vp
);
1454 mutex_exit(&fnp
->fn_lock
);
1455 error
= VFS_ROOT(vfsp
, newvp
);
1460 if ((fnp
->fn_flags
& MF_MOUNTPOINT
) &&
1461 fnp
->fn_trigger
!= NULL
) {
1462 ASSERT(fnp
->fn_dirents
== NULL
);
1463 mutex_exit(&fnp
->fn_lock
);
1465 * The filesystem that used to sit here has been
1466 * forcibly unmounted. Do our best to recover.
1467 * Try to unmount autofs subtree below this node
1468 * and retry the action.
1470 if (unmount_subtree(fnp
, B_TRUE
) != 0) {
1478 ASSERT(vp
->v_type
== VDIR
);
1479 dvp
= fntovn(fnp
->fn_parent
);
1481 if ((fnp
->fn_dirents
== NULL
) &&
1482 ((fnip
->fi_flags
& MF_DIRECT
) == 0) &&
1483 ((vp
->v_flag
& VROOT
) == 0) &&
1484 (dvp
->v_flag
& VROOT
)) {
1486 * If the parent of this node is the root of an indirect
1487 * AUTOFS filesystem, this node is remountable.
1493 ((fnip
->fi_flags
& MF_DIRECT
) && (fnp
->fn_dirents
== NULL
))) {
1495 * Trigger mount since:
1496 * direct mountpoint with no subdirs or
1499 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
1501 mutex_exit(&fnp
->fn_lock
);
1503 (void) strcpy(name
, fnp
->fn_name
);
1505 (void) strcpy(name
, ".");
1506 fnp
->fn_ref_time
= gethrestime_sec();
1507 auto_new_mount_thread(fnp
, name
, cred
);
1509 * At this point we're simply another thread waiting
1510 * for the mount to finish.
1512 error
= auto_wait4mount(fnp
);
1513 if (error
== EAGAIN
)
1515 if (error
== AUTOFS_SHUTDOWN
) {
1520 if (error
= vn_vfsrlock_wait(vp
))
1522 /* Reacquire after dropping locks */
1523 vfsp
= vn_mountedvfs(vp
);
1525 error
= VFS_ROOT(vfsp
, newvp
);
1533 mutex_exit(&fnp
->fn_lock
);
1536 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error
));