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]
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/param.h>
28 #include <sys/errno.h>
32 #include <sys/vnode.h>
33 #include <sys/pathname.h>
35 #include <sys/mount.h>
36 #include <sys/cmn_err.h>
37 #include <sys/debug.h>
38 #include <sys/systm.h>
39 #include <sys/dirent.h>
40 #include <sys/fs_subr.h>
41 #include <sys/fs/autofs.h>
42 #include <sys/callb.h>
43 #include <sys/sysmacros.h>
46 #include <sys/fs/mntdata.h>
47 #include <nfs/mount.h>
49 #include <rpcsvc/autofs_prot.h>
50 #include <nfs/rnode.h>
51 #include <sys/utsname.h>
52 #include <sys/schedctl.h>
57 * Zones are delegated the responsibility of managing their own autofs mounts
58 * and maps. Each zone runs its own copy of automountd, with its own timeouts,
59 * and other logically "global" parameters. kRPC and virtualization in the
60 * loopback transport (tl) will prevent a zone from communicating with another
63 * Each zone has its own "rootfnnode" and associated tree of auto nodes.
65 * Each zone also has its own set of "unmounter" kernel threads; these are
66 * created and run within the zone's context (ie, they are created via
69 * Cross-zone mount triggers are disallowed. There is a check in
70 * auto_trigger_mount() to this effect; EPERM is returned to indicate that the
71 * mount is not owned by the caller.
73 * autofssys() enables a caller in the global zone to clean up in-kernel (as
74 * well as regular) autofs mounts via the unmount_tree() mechanism. This is
75 * routinely done when all mounts are removed as part of zone shutdown.
77 #define TYPICALMAXPATHLEN 64
79 static kmutex_t autofs_nodeid_lock
;
81 /* max number of unmount threads running */
82 static int autofs_unmount_threads
= 5;
83 static int autofs_unmount_thread_timer
= 120; /* in seconds */
85 static int auto_perform_link(fnnode_t
*, struct linka
*, cred_t
*);
86 static int auto_perform_actions(fninfo_t
*, fnnode_t
*,
87 action_list
*, cred_t
*);
88 static int auto_getmntpnt(vnode_t
*, char *, vnode_t
**, cred_t
*);
89 static int auto_lookup_request(fninfo_t
*, char *, struct linka
*,
90 bool_t
, bool_t
*, cred_t
*);
91 static int auto_mount_request(fninfo_t
*, char *, action_list
**, cred_t
*,
95 * Clears the MF_INPROG flag, and wakes up those threads sleeping on
96 * fn_cv_mount if MF_WAITING is set.
101 uint_t operation
) /* either MF_INPROG or MF_LOOKUP */
103 ASSERT(operation
& (MF_INPROG
| MF_LOOKUP
));
104 fnp
->fn_flags
&= ~operation
;
105 if (fnp
->fn_flags
& MF_WAITING
) {
106 fnp
->fn_flags
&= ~MF_WAITING
;
107 cv_broadcast(&fnp
->fn_cv_mount
);
112 auto_wait4mount(fnnode_t
*fnp
)
117 AUTOFS_DPRINT((4, "auto_wait4mount: fnp=%p\n", (void *)fnp
));
119 mutex_enter(&fnp
->fn_lock
);
120 while (fnp
->fn_flags
& (MF_INPROG
| MF_LOOKUP
)) {
122 * There is a mount or a lookup in progress.
124 fnp
->fn_flags
|= MF_WAITING
;
126 if (!cv_wait_sig(&fnp
->fn_cv_mount
, &fnp
->fn_lock
)) {
128 * Decided not to wait for operation to
132 mutex_exit(&fnp
->fn_lock
);
137 error
= fnp
->fn_error
;
139 if (error
== EINTR
) {
141 * The thread doing the mount got interrupted, we need to
142 * try again, by returning EAGAIN.
146 mutex_exit(&fnp
->fn_lock
);
148 AUTOFS_DPRINT((5, "auto_wait4mount: fnp=%p error=%d\n", (void *)fnp
,
154 auto_lookup_aux(fnnode_t
*fnp
, char *name
, cred_t
*cred
)
158 bool_t mountreq
= FALSE
;
161 fnip
= vfstofni(fntovn(fnp
)->v_vfsp
);
162 bzero(&link
, sizeof (link
));
163 error
= auto_lookup_request(fnip
, name
, &link
, TRUE
, &mountreq
, cred
);
165 if (link
.link
!= NULL
) {
168 * This node should be a symlink
170 if (*link
.link
!= '\0')
171 error
= auto_perform_link(fnp
, &link
, cred
);
172 } else if (mountreq
) {
174 * The automount daemon is requesting a mount,
175 * implying this entry must be a wildcard match and
176 * therefore in need of verification that the entry
177 * exists on the server.
179 mutex_enter(&fnp
->fn_lock
);
180 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
184 * Unblock other lookup requests on this node,
185 * this is needed to let the lookup generated by
186 * the mount call to complete. The caveat is
187 * other lookups on this node can also get by,
188 * i.e., another lookup on this node that occurs
189 * while this lookup is attempting the mount
190 * would return a positive result no matter what.
191 * Therefore two lookups on the this node could
192 * potentially get disparate results.
194 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_LOOKUP
);
195 mutex_exit(&fnp
->fn_lock
);
197 * auto_new_mount_thread fires up a new thread which
198 * calls automountd finishing up the work
200 auto_new_mount_thread(fnp
, name
, cred
);
203 * At this point, we are simply another thread
204 * waiting for the mount to complete
206 error
= auto_wait4mount(fnp
);
207 if (error
== AUTOFS_SHUTDOWN
)
213 kmem_free(link
.link
, strlen(link
.link
) + 1);
215 kmem_free(link
.dir
, strlen(link
.dir
) + 1);
216 mutex_enter(&fnp
->fn_lock
);
217 fnp
->fn_error
= error
;
220 * Notify threads waiting for lookup/mount that
224 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
226 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_LOOKUP
);
228 mutex_exit(&fnp
->fn_lock
);
233 * Starting point for thread to handle mount requests with automountd.
234 * XXX auto_mount_thread() is not suspend-safe within the scope of
235 * the present model defined for cpr to suspend the system. Calls
236 * made by the auto_mount_thread() that have been identified to be unsafe
237 * are (1) RPC client handle setup and client calls to automountd which
238 * can block deep down in the RPC library, (2) kmem_alloc() calls with the
239 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*(), and
240 * lookuppnvp() calls which can result in over the wire calls to servers.
241 * The thread should be completely reevaluated to make it suspend-safe in
242 * case of future updates to the cpr model.
245 auto_mount_thread(struct autofs_callargs
*argsp
)
253 action_list
*alp
= NULL
;
256 kmutex_t auto_mount_thread_cpr_lock
;
258 mutex_init(&auto_mount_thread_cpr_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
259 CALLB_CPR_INIT(&cprinfo
, &auto_mount_thread_cpr_lock
,
260 callb_generic_cpr
, "auto_mount_thread");
262 fnp
= argsp
->fnc_fnp
;
264 fnip
= vfstofni(vp
->v_vfsp
);
265 name
= argsp
->fnc_name
;
266 cred
= argsp
->fnc_cred
;
267 ASSERT(crgetzoneid(argsp
->fnc_cred
) == fnip
->fi_zoneid
);
269 error
= auto_mount_request(fnip
, name
, &alp
, cred
, TRUE
);
271 error
= auto_perform_actions(fnip
, fnp
, alp
, cred
);
272 mutex_enter(&fnp
->fn_lock
);
273 fnp
->fn_error
= error
;
276 * Notify threads waiting for mount that
279 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
280 mutex_exit(&fnp
->fn_lock
);
283 crfree(argsp
->fnc_cred
);
284 namelen
= strlen(argsp
->fnc_name
) + 1;
285 kmem_free(argsp
->fnc_name
, namelen
);
286 kmem_free(argsp
, sizeof (*argsp
));
288 mutex_enter(&auto_mount_thread_cpr_lock
);
289 CALLB_CPR_EXIT(&cprinfo
);
290 mutex_destroy(&auto_mount_thread_cpr_lock
);
295 static int autofs_thr_success
= 0;
298 * Creates new thread which calls auto_mount_thread which does
299 * the bulk of the work calling automountd, via 'auto_perform_actions'.
302 auto_new_mount_thread(fnnode_t
*fnp
, char *name
, cred_t
*cred
)
304 struct autofs_callargs
*argsp
;
306 argsp
= kmem_alloc(sizeof (*argsp
), KM_SLEEP
);
307 VN_HOLD(fntovn(fnp
));
308 argsp
->fnc_fnp
= fnp
;
309 argsp
->fnc_name
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
310 (void) strcpy(argsp
->fnc_name
, name
);
311 argsp
->fnc_origin
= curthread
;
313 argsp
->fnc_cred
= cred
;
315 (void) zthread_create(NULL
, 0, auto_mount_thread
, argsp
, 0,
317 autofs_thr_success
++;
320 #define DOOR_BUF_ALIGN (1024*1024)
321 #define DOOR_BUF_MULTIPLIER 3
322 #define DOOR_BUF_DEFAULT_SZ (DOOR_BUF_MULTIPLIER * DOOR_BUF_ALIGN)
323 int doorbuf_defsz
= DOOR_BUF_DEFAULT_SZ
;
332 xdrproc_t xresp_func
,
335 bool_t hard
) /* retry forever? */
340 door_arg_t door_args
;
344 struct autofs_globals
*fngp
= NULL
;
347 int rlen
= 0; /* MUST be initialized */
348 autofs_door_args_t
*xdr_argsp
;
350 int printed_not_running_msg
= 0;
351 klwp_t
*lwp
= ttolwp(curthread
);
354 * We know that the current thread is doing work on
355 * behalf of its own zone, so it's ok to use
358 ASSERT(zoneid
== getzoneid());
359 if (zone_status_get(curproc
->p_zone
) >= ZONE_IS_SHUTTING_DOWN
) {
361 * There's no point in trying to talk to
362 * automountd. Plus, zone_shutdown() is
365 return (ECONNREFUSED
);
370 mutex_enter(&autofs_minor_lock
);
371 fngp
= zone_getspecific(autofs_key
, curproc
->p_zone
);
372 mutex_exit(&autofs_minor_lock
);
377 "failed to get door handle\n"));
378 if (!printed_not_running_msg
) {
379 printed_not_running_msg
= 1;
380 zprintf(zoneid
, "automountd not "\
381 "running, retrying\n");
387 * There is no global data so no door.
388 * There's no point in attempting to talk
389 * to automountd if we can't get the door
392 return (ECONNREFUSED
);
397 if (printed_not_running_msg
) {
398 fngp
->fng_printed_not_running_msg
= printed_not_running_msg
;
401 ASSERT(fngp
!= NULL
);
403 if (argsp
!= NULL
&& (xdr_len
= xdr_sizeof(xarg_func
, argsp
)) == 0)
405 xdr_argsp
= kmem_zalloc(xdr_len
+ sizeof (*xdr_argsp
), KM_SLEEP
);
406 xdr_argsp
->xdr_len
= xdr_len
;
407 xdr_argsp
->cmd
= which
;
410 xdrmem_create(&xdrarg
, (char *)&xdr_argsp
->xdr_arg
,
411 xdr_argsp
->xdr_len
, XDR_ENCODE
);
413 if (!(*xarg_func
)(&xdrarg
, argsp
)) {
414 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
420 * We're saving off the original pointer and length due to the
421 * possibility that the results buffer returned by the door
422 * upcall can be different then what we passed in. This is because
423 * the door will allocate new memory if the results buffer passed
424 * in isn't large enough to hold what we need to send back.
425 * In this case we need to free the memory originally allocated
429 rlen
= xdr_sizeof(xresp_func
, resp
);
430 orl
= (rlen
== 0) ? doorbuf_defsz
: MAX(rlen
, doorbuf_defsz
);
431 orp
= kmem_zalloc(orl
, KM_SLEEP
);
435 mutex_enter(&fngp
->fng_autofs_daemon_lock
);
436 dh
= fngp
->fng_autofs_daemon_dh
;
439 mutex_exit(&fngp
->fng_autofs_daemon_lock
);
444 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
447 door_args
.data_ptr
= (char *)xdr_argsp
;
448 door_args
.data_size
= sizeof (*xdr_argsp
) + xdr_argsp
->xdr_len
;
449 door_args
.desc_ptr
= NULL
;
450 door_args
.desc_num
= 0;
451 door_args
.rbuf
= orp
? (char *)orp
: NULL
;
452 door_args
.rsize
= orl
;
456 door_ki_upcall_limited(dh
, &door_args
, NULL
, SIZE_MAX
, 0);
462 * Handle daemon errors
466 * Upcall successful. Let's check for soft errors
467 * from the daemon. We only recover from overflow
468 * type scenarios. Any other errors, we return to
471 autofs_door_res_t
*adr
=
472 (autofs_door_res_t
*)door_args
.rbuf
;
474 if (door_args
.rbuf
!= NULL
) {
477 switch (error
= adr
->res_status
) {
478 case 0: /* no error; continue */
483 * orig landing buf not big enough.
484 * xdr_len in XDR_BYTES_PER_UNIT
486 if ((nl
= adr
->xdr_len
) > 0 &&
487 (btopr(nl
) < freemem
/64)) {
490 orp
= kmem_zalloc(nl
, KM_SLEEP
);
499 xdr_len
+ sizeof (*xdr_argsp
));
509 * no daemon errors; now process door/comm errors (if any)
514 * interrupts should be handled properly by the
515 * door upcall. If the door doesn't handle the
516 * interupt completely then we need to bail out.
518 if (lwp
&& (ISSIG(curthread
,
519 JUSTLOOKING
) || MUSTRETURN(curproc
, curthread
))) {
520 if (ISSIG(curthread
, FORREAL
) ||
522 MUSTRETURN(curproc
, curthread
)) {
523 lwp
->lwp_sysabort
= 0;
528 * We may have gotten EINTR for other reasons
529 * like the door being revoked on us. Instead
530 * of trying to extract this out of the door
531 * handle, sleep and try again, if still
532 * revoked we will get EBADF next time
535 * If we have a pending cancellation and we don't
536 * have cancellation disabled, we will get EINTR
537 * forever, no matter how many times we retry,
538 * so just get out now if this is the case.
540 if (schedctl_cancel_pending())
543 case EAGAIN
: /* process may be forking */
550 case EBADF
: /* Invalid door */
551 case EINVAL
: /* Not a door, wrong target */
553 * A fatal door error, if our failing door
554 * handle is the current door handle, clean
557 mutex_enter(&fngp
->fng_autofs_daemon_lock
);
558 if (dh
== fngp
->fng_autofs_daemon_dh
) {
559 door_ki_rele(fngp
->fng_autofs_daemon_dh
);
560 fngp
->fng_autofs_daemon_dh
= NULL
;
562 mutex_exit(&fngp
->fng_autofs_daemon_lock
);
563 AUTOFS_DPRINT((5, "auto_calldaemon error=%d\n", error
));
565 if (!fngp
->fng_printed_not_running_msg
) {
566 fngp
->fng_printed_not_running_msg
= 1;
567 zprintf(zoneid
, "automountd not "
568 "running, retrying\n");
574 error
= ECONNREFUSED
;
576 xdr_len
+ sizeof (*xdr_argsp
));
581 default: /* Unknown must be fatal */
583 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
590 if (fngp
->fng_printed_not_running_msg
== 1) {
591 fngp
->fng_printed_not_running_msg
= 0;
592 zprintf(zoneid
, "automountd OK\n");
596 autofs_door_res_t
*door_resp
;
597 door_resp
= (autofs_door_res_t
*)door_args
.rbuf
;
599 if ((void *)door_args
.rbuf
!= orp
)
602 xdrmem_create(&xdrres
, (char *)&door_resp
->xdr_res
,
603 door_resp
->xdr_len
, XDR_DECODE
);
605 if (!((*xresp_func
)(&xdrres
, resp
)))
607 kmem_free(door_args
.rbuf
, door_args
.rsize
);
609 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
614 auto_null_request(zoneid_t zoneid
, bool_t hard
)
618 AUTOFS_DPRINT((4, "\tauto_null_request\n"));
620 error
= auto_calldaemon(zoneid
, NULLPROC
,
621 xdr_void
, NULL
, xdr_void
, NULL
, 0, hard
);
623 AUTOFS_DPRINT((5, "\tauto_null_request: error=%d\n", error
));
637 struct autofs_globals
*fngp
;
638 struct autofs_lookupargs reqst
;
639 autofs_lookupres
*resp
;
643 AUTOFS_DPRINT((4, "auto_lookup_equest: path=%s name=%s\n",
644 fnip
->fi_path
, key
));
646 fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
648 reqst
.map
= fnip
->fi_map
;
649 reqst
.path
= fnip
->fi_path
;
651 if (fnip
->fi_flags
& MF_DIRECT
)
652 reqst
.name
= fnip
->fi_key
;
655 AUTOFS_DPRINT((4, "auto_lookup_request: using key=%s\n", reqst
.name
));
657 reqst
.subdir
= fnip
->fi_subdir
;
658 reqst
.opts
= fnip
->fi_opts
;
659 reqst
.isdirect
= fnip
->fi_flags
& MF_DIRECT
? TRUE
: FALSE
;
660 reqst
.uid
= crgetuid(cred
);
662 resp
= kmem_zalloc(sizeof (*resp
), KM_SLEEP
);
664 error
= auto_calldaemon(fngp
->fng_zoneid
, AUTOFS_LOOKUP
,
665 xdr_autofs_lookupargs
, &reqst
, xdr_autofs_lookupres
,
666 (void *)resp
, sizeof (autofs_lookupres
), hard
);
669 xdr_free(xdr_autofs_lookupres
, (char *)resp
);
670 kmem_free(resp
, sizeof (*resp
));
675 fngp
->fng_verbose
= resp
->lu_verbose
;
676 switch (resp
->lu_res
) {
678 switch (resp
->lu_type
.action
) {
679 case AUTOFS_MOUNT_RQ
:
686 p
= &resp
->lu_type
.lookup_result_type_u
.lt_linka
;
687 lnp
->dir
= kmem_alloc(strlen(p
->dir
) + 1,
689 (void) strcpy(lnp
->dir
, p
->dir
);
690 lnp
->link
= kmem_alloc(strlen(p
->link
) + 1,
692 (void) strcpy(lnp
->link
, p
->link
);
701 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
702 CE_WARN
, "auto_lookup_request: bad action "
703 "type %d", resp
->lu_res
);
714 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
, CE_WARN
,
715 "auto_lookup_request: unknown result: %d",
721 xdr_free(xdr_autofs_lookupres
, (char *)resp
);
722 kmem_free(resp
, sizeof (*resp
));
723 AUTOFS_DPRINT((5, "auto_lookup_request: path=%s name=%s error=%d\n",
724 fnip
->fi_path
, key
, error
));
737 struct autofs_globals
*fngp
;
738 autofs_lookupargs reqst
;
739 autofs_mountres
*xdrres
= NULL
;
741 AUTOFS_DPRINT((4, "auto_mount_request: path=%s name=%s\n",
742 fnip
->fi_path
, key
));
744 fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
745 reqst
.map
= fnip
->fi_map
;
746 reqst
.path
= fnip
->fi_path
;
748 if (fnip
->fi_flags
& MF_DIRECT
)
749 reqst
.name
= fnip
->fi_key
;
753 AUTOFS_DPRINT((4, "auto_mount_request: using key=%s\n", reqst
.name
));
755 reqst
.subdir
= fnip
->fi_subdir
;
756 reqst
.opts
= fnip
->fi_opts
;
757 reqst
.isdirect
= fnip
->fi_flags
& MF_DIRECT
? TRUE
: FALSE
;
758 reqst
.uid
= crgetuid(cred
);
760 xdrres
= kmem_zalloc(sizeof (*xdrres
), KM_SLEEP
);
762 error
= auto_calldaemon(fngp
->fng_zoneid
, AUTOFS_MNTINFO
,
763 xdr_autofs_lookupargs
, &reqst
, xdr_autofs_mountres
,
764 (void *)xdrres
, sizeof (autofs_mountres
), hard
);
767 fngp
->fng_verbose
= xdrres
->mr_verbose
;
768 switch (xdrres
->mr_type
.status
) {
772 * Save the action list since it is used by
773 * the caller. We NULL the action list pointer
774 * in 'result' so that xdr_free() will not free
777 *alpp
= xdrres
->mr_type
.mount_result_type_u
.list
;
778 xdrres
->mr_type
.mount_result_type_u
.list
= NULL
;
781 error
= xdrres
->mr_type
.mount_result_type_u
.error
;
785 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
, CE_WARN
,
786 "auto_mount_request: unknown status %d",
787 xdrres
->mr_type
.status
);
792 xdr_free(xdr_autofs_mountres
, (char *)xdrres
);
793 kmem_free(xdrres
, sizeof (*xdrres
));
796 AUTOFS_DPRINT((5, "auto_mount_request: path=%s name=%s error=%d\n",
797 fnip
->fi_path
, key
, error
));
803 auto_send_unmount_request(
811 struct autofs_globals
*fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
813 AUTOFS_DPRINT((4, "\tauto_send_unmount_request: fstype=%s "
814 " mntpnt=%s\n", ul
->fstype
, ul
->mntpnt
));
816 bzero(&xdrres
, sizeof (umntres
));
817 error
= auto_calldaemon(fngp
->fng_zoneid
, AUTOFS_UNMOUNT
,
818 xdr_umntrequest
, (void *)ul
, xdr_umntres
, (void *)&xdrres
,
819 sizeof (umntres
), hard
);
822 error
= xdrres
.status
;
824 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error
));
830 auto_perform_link(fnnode_t
*fnp
, struct linka
*linkp
, cred_t
*cred
)
836 AUTOFS_DPRINT((3, "auto_perform_link: fnp=%p dir=%s link=%s\n",
837 (void *)fnp
, linkp
->dir
, linkp
->link
));
839 len
= strlen(linkp
->link
) + 1; /* include '\0' */
840 tmp
= kmem_zalloc(len
, KM_SLEEP
);
841 (void) kcopy(linkp
->link
, tmp
, len
);
842 mutex_enter(&fnp
->fn_lock
);
843 fnp
->fn_symlink
= tmp
;
844 fnp
->fn_symlinklen
= (uint_t
)len
;
845 fnp
->fn_flags
|= MF_THISUID_MATCH_RQD
;
848 mutex_exit(&fnp
->fn_lock
);
857 auto_free_autofs_args(struct mounta
*m
)
859 autofs_args
*aargs
= (autofs_args
*)m
->dataptr
;
862 kmem_free(aargs
->addr
.buf
, aargs
->addr
.len
);
864 kmem_free(aargs
->path
, strlen(aargs
->path
) + 1);
866 kmem_free(aargs
->opts
, strlen(aargs
->opts
) + 1);
868 kmem_free(aargs
->map
, strlen(aargs
->map
) + 1);
870 kmem_free(aargs
->subdir
, strlen(aargs
->subdir
) + 1);
872 kmem_free(aargs
->key
, strlen(aargs
->key
) + 1);
873 kmem_free(aargs
, sizeof (*aargs
));
877 auto_free_action_list(action_list
*alp
)
880 action_list
*lastalp
;
883 m
= &alp
->action
.action_list_entry_u
.mounta
;
884 while (alp
!= NULL
) {
885 fstype
= alp
->action
.action_list_entry_u
.mounta
.fstype
;
886 m
= &alp
->action
.action_list_entry_u
.mounta
;
888 if (strcmp(fstype
, "autofs") == 0) {
889 auto_free_autofs_args(m
);
893 kmem_free(m
->spec
, strlen(m
->spec
) + 1);
895 kmem_free(m
->dir
, strlen(m
->dir
) + 1);
897 kmem_free(m
->fstype
, strlen(m
->fstype
) + 1);
899 kmem_free(m
->optptr
, m
->optlen
);
902 kmem_free(lastalp
, sizeof (*lastalp
));
907 auto_invalid_autofs(fninfo_t
*dfnip
, fnnode_t
*dfnp
, action_list
*p
)
910 struct autofs_args
*argsp
;
912 char buff
[AUTOFS_MAXPATHLEN
];
914 struct autofs_globals
*fngp
;
916 fngp
= dfnp
->fn_globals
;
919 m
= &p
->action
.action_list_entry_u
.mounta
;
921 * Make sure we aren't geting passed NULL values or a "dir" that
922 * isn't "." and doesn't begin with "./".
924 * We also only want to perform autofs mounts, so make sure
925 * no-one is trying to trick us into doing anything else.
927 if (m
->spec
== NULL
|| m
->dir
== NULL
|| m
->dir
[0] != '.' ||
928 (m
->dir
[1] != '/' && m
->dir
[1] != '\0') ||
929 m
->fstype
== NULL
|| strcmp(m
->fstype
, "autofs") != 0 ||
930 m
->dataptr
== NULL
|| m
->datalen
!= sizeof (struct autofs_args
) ||
934 * We also don't like ".."s in the pathname. Symlinks are
935 * handled by the fact that we'll use NOFOLLOW when we do
938 if (strstr(m
->dir
, "/../") != NULL
||
939 (len
= strlen(m
->dir
)) > sizeof ("/..") - 1 &&
940 m
->dir
[len
] == '.' && m
->dir
[len
- 1] == '.' &&
941 m
->dir
[len
- 2] == '/')
943 argsp
= (struct autofs_args
*)m
->dataptr
;
945 * We don't want NULL values here either.
947 if (argsp
->addr
.buf
== NULL
|| argsp
->path
== NULL
||
948 argsp
->opts
== NULL
|| argsp
->map
== NULL
|| argsp
->subdir
== NULL
)
951 * We know what the claimed pathname *should* look like:
953 * If the parent (dfnp) is a mount point (VROOT), then
954 * the path should be (dfnip->fi_path + m->dir).
956 * Else, we know we're only two levels deep, so we use
957 * (dfnip->fi_path + dfnp->fn_name + m->dir).
959 * Furthermore, "." only makes sense if dfnp is a
962 * At this point it seems like the passed-in path is
965 if (dvp
->v_flag
& VROOT
) {
966 if (m
->dir
[1] == '\0' && !(dfnp
->fn_flags
& MF_TRIGGER
))
968 (void) snprintf(buff
, sizeof (buff
), "%s%s",
969 dfnip
->fi_path
, m
->dir
+ 1);
971 (void) snprintf(buff
, sizeof (buff
), "%s/%s%s",
972 dfnip
->fi_path
, dfnp
->fn_name
, m
->dir
+ 1);
974 if (strcmp(argsp
->path
, buff
) != 0) {
975 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
976 CE_WARN
, "autofs: expected path of '%s', "
977 "got '%s' instead.", buff
, argsp
->path
);
980 return (B_FALSE
); /* looks OK */
984 * auto_invalid_action will validate the action_list received. If all is good
985 * this function returns FALSE, if there is a problem it returns TRUE.
988 auto_invalid_action(fninfo_t
*dfnip
, fnnode_t
*dfnp
, action_list
*alistpp
)
992 * Before we go any further, this better be a mount request.
994 if (alistpp
->action
.action
!= AUTOFS_MOUNT_RQ
)
996 return (auto_invalid_autofs(dfnip
, dfnp
, alistpp
));
1001 auto_perform_actions(
1005 cred_t
*cred
) /* Credentials of the caller */
1009 struct mounta
*m
, margs
;
1010 struct autofs_args
*argsp
;
1011 int error
, success
= 0;
1012 vnode_t
*mvp
, *dvp
, *newvp
;
1013 fnnode_t
*newfnp
, *mfnp
;
1015 int save_triggers
= 0;
1016 int update_times
= 0;
1018 char buff
[AUTOFS_MAXPATHLEN
];
1020 struct autofs_globals
*fngp
;
1023 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", (void *)alp
));
1025 fngp
= dfnp
->fn_globals
;
1029 * As automountd running in a zone may be compromised, and this may be
1030 * an attack, we can't trust everything passed in by automountd, and we
1031 * need to do argument verification. We'll issue a warning and drop
1032 * the request if it doesn't seem right.
1035 for (p
= alp
; p
!= NULL
; p
= p
->next
) {
1036 if (auto_invalid_action(dfnip
, dfnp
, p
)) {
1038 * This warning should be sent to the global zone,
1039 * since presumably the zone administrator is the same
1042 cmn_err(CE_WARN
, "autofs: invalid action list received "
1043 "by automountd in zone %s.",
1044 curproc
->p_zone
->zone_name
);
1046 * This conversation is over.
1048 xdr_free(xdr_action_list
, (char *)alp
);
1053 zcred
= zone_get_kcred(getzoneid());
1054 ASSERT(zcred
!= NULL
);
1056 if (vn_mountedvfs(dvp
) != NULL
) {
1058 * The daemon successfully mounted a filesystem
1059 * on the AUTOFS root node.
1061 mutex_enter(&dfnp
->fn_lock
);
1062 dfnp
->fn_flags
|= MF_MOUNTPOINT
;
1063 ASSERT(dfnp
->fn_dirents
== NULL
);
1064 mutex_exit(&dfnp
->fn_lock
);
1068 * Clear MF_MOUNTPOINT.
1070 mutex_enter(&dfnp
->fn_lock
);
1071 if (dfnp
->fn_flags
& MF_MOUNTPOINT
) {
1072 AUTOFS_DPRINT((10, "autofs: clearing mountpoint "
1073 "flag on %s.", dfnp
->fn_name
));
1074 ASSERT(dfnp
->fn_dirents
== NULL
);
1075 ASSERT(dfnp
->fn_trigger
== NULL
);
1077 dfnp
->fn_flags
&= ~MF_MOUNTPOINT
;
1078 mutex_exit(&dfnp
->fn_lock
);
1081 for (p
= alp
; p
!= NULL
; p
= p
->next
) {
1083 vfs_t
*vfsp
; /* dummy argument */
1088 m
= &p
->action
.action_list_entry_u
.mounta
;
1089 argsp
= (struct autofs_args
*)m
->dataptr
;
1090 ASSERT(strcmp(m
->fstype
, "autofs") == 0);
1092 * use the parent directory's timeout since it's the
1093 * one specified/inherited by automount.
1095 argsp
->mount_to
= dfnip
->fi_mount_to
;
1097 * The mountpoint is relative, and it is guaranteed to
1101 ASSERT(m
->dir
[0] == '.');
1102 if (m
->dir
[0] == '.' && m
->dir
[1] == '\0') {
1104 * mounting on the trigger node
1111 * ignore "./" in front of mountpoint
1113 ASSERT(m
->dir
[1] == '/');
1114 mntpnt
= m
->dir
+ 2;
1116 AUTOFS_DPRINT((10, "\tdfnip->fi_path=%s\n", dfnip
->fi_path
));
1117 AUTOFS_DPRINT((10, "\tdfnip->fi_flags=%x\n", dfnip
->fi_flags
));
1118 AUTOFS_DPRINT((10, "\tmntpnt=%s\n", mntpnt
));
1120 if (dfnip
->fi_flags
& MF_DIRECT
) {
1121 AUTOFS_DPRINT((10, "\tDIRECT\n"));
1122 (void) sprintf(buff
, "%s/%s", dfnip
->fi_path
, mntpnt
);
1124 AUTOFS_DPRINT((10, "\tINDIRECT\n"));
1125 (void) sprintf(buff
, "%s/%s/%s",
1126 dfnip
->fi_path
, dfnp
->fn_name
, mntpnt
);
1129 if (vn_mountedvfs(dvp
) == NULL
) {
1131 * Daemon didn't mount anything on the root
1132 * We have to create the mountpoint if it
1133 * doesn't exist already
1135 * We use the caller's credentials in case a
1136 * UID-match is required
1137 * (MF_THISUID_MATCH_RQD).
1139 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
1140 error
= auto_search(dfnp
, mntpnt
, &mfnp
, cred
);
1143 * AUTOFS mountpoint exists
1145 if (vn_mountedvfs(fntovn(mfnp
)) != NULL
) {
1147 "auto_perform_actions:"
1148 " mfnp=%p covered", (void *)mfnp
);
1152 * Create AUTOFS mountpoint
1154 ASSERT((dfnp
->fn_flags
& MF_MOUNTPOINT
) == 0);
1155 error
= auto_enter(dfnp
, mntpnt
, &mfnp
, cred
);
1156 ASSERT(mfnp
->fn_linkcnt
== 1);
1161 rw_exit(&dfnp
->fn_rwlock
);
1162 ASSERT(error
!= EEXIST
);
1165 * mfnp is already held.
1169 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1170 CE_WARN
, "autofs: mount of %s "
1171 "failed - can't create"
1172 " mountpoint.", buff
);
1177 * Find mountpoint in VFS mounted here. If not
1178 * found, fail the submount, though the overall
1179 * mount has succeeded since the root is
1182 if (error
= auto_getmntpnt(dvp
, mntpnt
, &mvp
, kcred
)) {
1183 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1184 CE_WARN
, "autofs: mount of %s "
1185 "failed - mountpoint doesn't"
1189 if (mvp
->v_type
== VLNK
) {
1190 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1191 CE_WARN
, "autofs: %s symbolic "
1192 "link: not a valid mountpoint "
1193 "- mount failed", buff
);
1200 m
->flags
|= MS_SYSSPACE
| MS_OPTIONSTR
;
1203 * Copy mounta struct here so we can substitute a
1204 * buffer that is large enough to hold the returned
1205 * option string, if that string is longer than the
1206 * input option string.
1207 * This can happen if there are default options enabled
1208 * that were not in the input option string.
1210 bcopy(m
, &margs
, sizeof (*m
));
1211 margs
.optptr
= kmem_alloc(MAX_MNTOPT_STR
, KM_SLEEP
);
1212 margs
.optlen
= MAX_MNTOPT_STR
;
1213 (void) strcpy(margs
.optptr
, m
->optptr
);
1214 margs
.dir
= argsp
->path
;
1217 * We use the zone's kcred because we don't want the
1218 * zone to be able to thus do something it wouldn't
1219 * normally be able to.
1221 error
= domount(NULL
, &margs
, mvp
, zcred
, &vfsp
);
1222 kmem_free(margs
.optptr
, MAX_MNTOPT_STR
);
1224 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1225 CE_WARN
, "autofs: domount of %s failed "
1226 "error=%d", buff
, error
);
1233 * If mountpoint is an AUTOFS node, then I'm going to
1234 * flag it that the Filesystem mounted on top was
1235 * mounted in the kernel so that the unmount can be
1236 * done inside the kernel as well.
1237 * I don't care to flag non-AUTOFS mountpoints when an
1238 * AUTOFS in-kernel mount was done on top, because the
1239 * unmount routine already knows that such case was
1240 * done in the kernel.
1242 if (vfs_matchops(dvp
->v_vfsp
, vfs_getops(mvp
->v_vfsp
))) {
1244 mutex_enter(&mfnp
->fn_lock
);
1245 mfnp
->fn_flags
|= MF_IK_MOUNT
;
1246 mutex_exit(&mfnp
->fn_lock
);
1249 (void) vn_vfswlock_wait(mvp
);
1250 mvfsp
= vn_mountedvfs(mvp
);
1251 if (mvfsp
!= NULL
) {
1252 vfs_lock_wait(mvfsp
);
1254 error
= VFS_ROOT(mvfsp
, &newvp
);
1258 * We've dropped the locks, so let's
1259 * get the mounted vfs again in case
1262 (void) vn_vfswlock_wait(mvp
);
1263 mvfsp
= vn_mountedvfs(mvp
);
1264 if (mvfsp
!= NULL
) {
1265 error
= dounmount(mvfsp
, 0, CRED());
1268 "autofs: could not unmount"
1269 " vfs=%p", (void *)mvfsp
);
1282 auto_mount
= vfs_matchops(dvp
->v_vfsp
,
1283 vfs_getops(newvp
->v_vfsp
));
1284 newfnp
= vntofn(newvp
);
1285 newfnp
->fn_parent
= dfnp
;
1288 * At this time we want to save the AUTOFS filesystem
1289 * as a trigger node. (We only do this if the mount
1290 * occurred on a node different from the root.
1291 * We look at the trigger nodes during
1292 * the automatic unmounting to make sure we remove them
1293 * as a unit and remount them as a unit if the
1294 * filesystem mounted at the root could not be
1297 if (auto_mount
&& (error
== 0) && (mvp
!= dvp
)) {
1300 * Add AUTOFS mount to hierarchy
1302 newfnp
->fn_flags
|= MF_TRIGGER
;
1303 rw_enter(&newfnp
->fn_rwlock
, RW_WRITER
);
1304 newfnp
->fn_next
= dfnp
->fn_trigger
;
1305 rw_exit(&newfnp
->fn_rwlock
);
1306 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
1307 dfnp
->fn_trigger
= newfnp
;
1308 rw_exit(&dfnp
->fn_rwlock
);
1310 * Don't VN_RELE(newvp) here since dfnp now
1311 * holds reference to it as its trigger node.
1313 AUTOFS_DPRINT((10, "\tadding trigger %s to %s\n",
1314 newfnp
->fn_name
, dfnp
->fn_name
));
1315 AUTOFS_DPRINT((10, "\tfirst trigger is %s\n",
1316 dfnp
->fn_trigger
->fn_name
));
1317 if (newfnp
->fn_next
!= NULL
)
1318 AUTOFS_DPRINT((10, "\tnext trigger is %s\n",
1319 newfnp
->fn_next
->fn_name
));
1321 AUTOFS_DPRINT((10, "\tno next trigger\n"));
1330 dfnp
->fn_atime
= dfnp
->fn_mtime
= now
;
1336 if (save_triggers
) {
1338 * Make sure the parent can't be freed while it has triggers.
1347 * Return failure if daemon didn't mount anything, and all
1348 * kernel mounts attempted failed.
1350 error
= success
? 0 : ENOENT
;
1353 if ((error
== 0) && save_triggers
) {
1355 * Save action_list information, so that we can use it
1356 * when it comes time to remount the trigger nodes
1357 * The action list is freed when the directory node
1358 * containing the reference to it is unmounted in
1361 mutex_enter(&dfnp
->fn_lock
);
1362 ASSERT(dfnp
->fn_alp
== NULL
);
1364 mutex_exit(&dfnp
->fn_lock
);
1367 * free the action list now,
1369 xdr_free(xdr_action_list
, (char *)alp
);
1372 AUTOFS_DPRINT((5, "auto_perform_actions: error=%d\n", error
));
1382 struct autofs_globals
*fngp
)
1389 * autofs uses odd inode numbers
1390 * automountd uses even inode numbers
1392 * To preserve the age-old semantics that inum+devid is unique across
1393 * the system, this variable must be global across zones.
1395 static ino_t nodeid
= 3;
1397 fnp
= kmem_zalloc(sizeof (*fnp
), KM_SLEEP
);
1398 fnp
->fn_vnode
= vn_alloc(KM_SLEEP
);
1401 tmpname
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
1402 (void) strcpy(tmpname
, name
);
1403 fnp
->fn_name
= &tmpname
[0];
1404 fnp
->fn_namelen
= (int)strlen(tmpname
) + 1; /* include '\0' */
1405 fnp
->fn_uid
= crgetuid(cred
);
1406 fnp
->fn_gid
= crgetgid(cred
);
1408 * ".." is added in auto_enter and auto_mount.
1409 * "." is added in auto_mkdir and auto_mount.
1412 * Note that fn_size and fn_linkcnt are already 0 since
1413 * we used kmem_zalloc to allocated fnp
1415 fnp
->fn_mode
= AUTOFS_MODE
;
1417 fnp
->fn_atime
= fnp
->fn_mtime
= fnp
->fn_ctime
= now
;
1418 fnp
->fn_ref_time
= now
.tv_sec
;
1419 mutex_enter(&autofs_nodeid_lock
);
1420 fnp
->fn_nodeid
= nodeid
;
1422 fnp
->fn_globals
= fngp
;
1423 fngp
->fng_fnnode_count
++;
1424 mutex_exit(&autofs_nodeid_lock
);
1425 vn_setops(vp
, &auto_vnodeops
);
1427 vp
->v_data
= (void *)fnp
;
1429 mutex_init(&fnp
->fn_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1430 rw_init(&fnp
->fn_rwlock
, NULL
, RW_DEFAULT
, NULL
);
1431 cv_init(&fnp
->fn_cv_mount
, NULL
, CV_DEFAULT
, NULL
);
1438 auto_freefnnode(fnnode_t
*fnp
)
1440 vnode_t
*vp
= fntovn(fnp
);
1442 AUTOFS_DPRINT((4, "auto_freefnnode: fnp=%p\n", (void *)fnp
));
1444 ASSERT(fnp
->fn_linkcnt
== 0);
1445 ASSERT(vp
->v_count
== 0);
1446 ASSERT(fnp
->fn_dirents
== NULL
);
1447 ASSERT(fnp
->fn_parent
== NULL
);
1450 kmem_free(fnp
->fn_name
, fnp
->fn_namelen
);
1451 if (fnp
->fn_symlink
) {
1452 ASSERT(fnp
->fn_flags
& MF_THISUID_MATCH_RQD
);
1453 kmem_free(fnp
->fn_symlink
, fnp
->fn_symlinklen
);
1456 crfree(fnp
->fn_cred
);
1457 mutex_destroy(&fnp
->fn_lock
);
1458 rw_destroy(&fnp
->fn_rwlock
);
1459 cv_destroy(&fnp
->fn_cv_mount
);
1462 mutex_enter(&autofs_nodeid_lock
);
1463 fnp
->fn_globals
->fng_fnnode_count
--;
1464 mutex_exit(&autofs_nodeid_lock
);
1465 kmem_free(fnp
, sizeof (*fnp
));
1473 fnnode_t
*tmp
, **fnpp
;
1474 vnode_t
*vp
= fntovn(fnp
);
1478 "auto_disconnect: dfnp=%p fnp=%p linkcnt=%d\n v_count=%d",
1479 (void *)dfnp
, (void *)fnp
, fnp
->fn_linkcnt
, vp
->v_count
));
1481 ASSERT(RW_WRITE_HELD(&dfnp
->fn_rwlock
));
1482 ASSERT(fnp
->fn_linkcnt
== 1);
1484 if (vn_mountedvfs(vp
) != NULL
) {
1485 cmn_err(CE_PANIC
, "auto_disconnect: vp %p mounted on",
1490 * Decrement by 1 because we're removing the entry in dfnp.
1496 * only changed while holding parent's (dfnp) rw_lock
1498 fnp
->fn_parent
= NULL
;
1500 fnpp
= &dfnp
->fn_dirents
;
1505 "auto_disconnect: %p not in %p dirent list",
1506 (void *)fnp
, (void *)dfnp
);
1509 *fnpp
= tmp
->fn_next
; /* remove it from the list */
1510 ASSERT(vp
->v_count
== 0);
1511 /* child had a pointer to parent ".." */
1516 fnpp
= &tmp
->fn_next
;
1519 mutex_enter(&fnp
->fn_lock
);
1521 fnp
->fn_atime
= fnp
->fn_mtime
= now
;
1522 mutex_exit(&fnp
->fn_lock
);
1524 AUTOFS_DPRINT((5, "auto_disconnect: done\n"));
1528 auto_enter(fnnode_t
*dfnp
, char *name
, fnnode_t
**fnpp
, cred_t
*cred
)
1530 struct fnnode
*cfnp
, **spp
;
1531 vnode_t
*dvp
= fntovn(dfnp
);
1532 ushort_t offset
= 0;
1535 AUTOFS_DPRINT((4, "auto_enter: dfnp=%p, name=%s ", (void *)dfnp
, name
));
1537 ASSERT(RW_WRITE_HELD(&dfnp
->fn_rwlock
));
1539 cfnp
= dfnp
->fn_dirents
;
1542 * offset = 0 for '.' and offset = 1 for '..'
1544 spp
= &dfnp
->fn_dirents
;
1548 for (; cfnp
; cfnp
= cfnp
->fn_next
) {
1549 if (strcmp(cfnp
->fn_name
, name
) == 0) {
1550 mutex_enter(&cfnp
->fn_lock
);
1551 if (cfnp
->fn_flags
& MF_THISUID_MATCH_RQD
) {
1553 * "thisuser" kind of node, need to
1554 * match CREDs as well
1556 mutex_exit(&cfnp
->fn_lock
);
1557 if (crcmp(cfnp
->fn_cred
, cred
) == 0)
1560 mutex_exit(&cfnp
->fn_lock
);
1565 if (cfnp
->fn_next
!= NULL
) {
1567 (cfnp
->fn_next
->fn_offset
- cfnp
->fn_offset
);
1569 if (diff
> 1 && offset
== 0) {
1570 offset
= (ushort_t
)cfnp
->fn_offset
+ 1;
1571 spp
= &cfnp
->fn_next
;
1573 } else if (offset
== 0) {
1574 offset
= (ushort_t
)cfnp
->fn_offset
+ 1;
1575 spp
= &cfnp
->fn_next
;
1579 *fnpp
= auto_makefnnode(VDIR
, dvp
->v_vfsp
, name
, cred
,
1585 * I don't hold the mutex on fnpp because I created it, and
1586 * I'm already holding the writers lock for it's parent
1587 * directory, therefore nobody can reference it without me first
1588 * releasing the writers lock.
1590 (*fnpp
)->fn_offset
= offset
;
1591 (*fnpp
)->fn_next
= *spp
;
1593 (*fnpp
)->fn_parent
= dfnp
;
1594 (*fnpp
)->fn_linkcnt
++; /* parent now holds reference to entry */
1598 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock
1600 dfnp
->fn_linkcnt
++; /* child now holds reference to parent '..' */
1603 dfnp
->fn_ref_time
= gethrestime_sec();
1605 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp
));
1610 auto_search(fnnode_t
*dfnp
, char *name
, fnnode_t
**fnpp
, cred_t
*cred
)
1614 int error
= ENOENT
, match
= 0;
1616 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n",
1617 (void *)dfnp
, name
));
1620 if (dvp
->v_type
!= VDIR
) {
1621 cmn_err(CE_PANIC
, "auto_search: dvp=%p not a directory",
1625 ASSERT(RW_LOCK_HELD(&dfnp
->fn_rwlock
));
1626 for (p
= dfnp
->fn_dirents
; p
!= NULL
; p
= p
->fn_next
) {
1627 if (strcmp(p
->fn_name
, name
) == 0) {
1628 mutex_enter(&p
->fn_lock
);
1629 if (p
->fn_flags
& MF_THISUID_MATCH_RQD
) {
1631 * "thisuser" kind of node
1632 * Need to match CREDs as well
1634 mutex_exit(&p
->fn_lock
);
1635 match
= crcmp(p
->fn_cred
, cred
) == 0;
1638 * No need to check CRED
1640 mutex_exit(&p
->fn_lock
);
1648 VN_HOLD(fntovn(*fnpp
));
1654 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error
));
1659 * If dvp is mounted on, get path's vnode in the mounted on
1660 * filesystem. Path is relative to dvp, ie "./path".
1661 * If successful, *mvp points to a the held mountpoint vnode.
1668 vnode_t
**mvpp
, /* vnode for mountpoint */
1673 char namebuf
[TYPICALMAXPATHLEN
];
1674 struct pathname lookpn
;
1677 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path
));
1679 if (error
= vn_vfsrlock_wait(dvp
))
1683 * Now that we have the vfswlock, check to see if dvp
1684 * is still mounted on. If not, then just bail out as
1685 * there is no need to remount the triggers since the
1686 * higher level mount point has gotten unmounted.
1688 vfsp
= vn_mountedvfs(dvp
);
1695 * Since mounted on, lookup "path" in the new filesystem,
1696 * it is important that we do the filesystem jump here to
1697 * avoid lookuppn() calling auto_lookup on dvp and deadlock.
1699 error
= VFS_ROOT(vfsp
, &newvp
);
1705 * We do a VN_HOLD on newvp just in case the first call to
1706 * lookuppnvp() fails with ENAMETOOLONG. We should still have a
1707 * reference to this vnode for the second call to lookuppnvp().
1712 * Now create the pathname struct so we can make use of lookuppnvp,
1713 * and pn_getcomponent.
1714 * This code is similar to lookupname() in fs/lookup.c.
1716 error
= pn_get_buf(path
, UIO_SYSSPACE
, &lookpn
,
1717 namebuf
, sizeof (namebuf
));
1719 error
= lookuppnvp(&lookpn
, NULL
, NO_FOLLOW
, NULLVPP
,
1720 mvpp
, rootdir
, newvp
, cred
);
1723 if (error
== ENAMETOOLONG
) {
1725 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
1726 * newvp is VN_RELE'd by this call to lookuppnvp.
1728 * Using 'rootdir' in a zone's context is OK here: we already
1729 * ascertained that there are no '..'s in the path, and we're
1730 * not following symlinks.
1732 if ((error
= pn_get(path
, UIO_SYSSPACE
, &lookpn
)) == 0) {
1733 error
= lookuppnvp(&lookpn
, NULL
, NO_FOLLOW
, NULLVPP
,
1734 mvpp
, rootdir
, newvp
, cred
);
1740 * Need to release newvp here since we held it.
1746 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n",
1747 path
, (void *)*mvpp
, error
));
1751 #define DEEPER(x) (((x)->fn_dirents != NULL) || \
1752 (vn_mountedvfs(fntovn((x)))) != NULL)
1755 * The caller, should have already VN_RELE'd its reference to the
1756 * root vnode of this filesystem.
1759 auto_inkernel_unmount(vfs_t
*vfsp
)
1761 vnode_t
*cvp
= vfsp
->vfs_vnodecovered
;
1765 "auto_inkernel_unmount: devid=%lx mntpnt(%p) count %u\n",
1766 vfsp
->vfs_dev
, (void *)cvp
, cvp
->v_count
));
1768 ASSERT(vn_vfswlock_held(cvp
));
1771 * Perform the unmount
1772 * The mountpoint has already been locked by the caller.
1774 error
= dounmount(vfsp
, 0, kcred
);
1776 AUTOFS_DPRINT((5, "auto_inkernel_unmount: exit count %u\n",
1782 * unmounts trigger nodes in the kernel.
1785 unmount_triggers(fnnode_t
*fnp
, action_list
**alp
)
1787 fnnode_t
*tp
, *next
;
1792 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp
));
1793 ASSERT(RW_WRITE_HELD(&fnp
->fn_rwlock
));
1796 next
= fnp
->fn_trigger
;
1797 while ((tp
= next
) != NULL
) {
1799 ASSERT(tvp
->v_count
>= 2);
1802 * drop writer's lock since the unmount will end up
1803 * disconnecting this node from fnp and needs to acquire
1804 * the writer's lock again.
1805 * next has at least a reference count >= 2 since it's
1806 * a trigger node, therefore can not be accidentally freed
1809 rw_exit(&fnp
->fn_rwlock
);
1814 * Its parent was holding a reference to it, since this
1815 * is a trigger vnode.
1818 if (error
= auto_inkernel_unmount(vfsp
)) {
1819 cmn_err(CE_PANIC
, "unmount_triggers: "
1820 "unmount of vp=%p failed error=%d",
1821 (void *)tvp
, error
);
1824 * reacquire writer's lock
1826 rw_enter(&fnp
->fn_rwlock
, RW_WRITER
);
1830 * We were holding a reference to our parent. Drop that.
1832 VN_RELE(fntovn(fnp
));
1833 fnp
->fn_trigger
= NULL
;
1836 AUTOFS_DPRINT((5, "unmount_triggers: finished\n"));
1840 * This routine locks the mountpoint of every trigger node if they're
1841 * not busy, or returns EBUSY if any node is busy.
1844 triggers_busy(fnnode_t
*fnp
)
1851 ASSERT(RW_WRITE_HELD(&fnp
->fn_rwlock
));
1853 for (tp
= fnp
->fn_trigger
; tp
!= NULL
; tp
= tp
->fn_next
) {
1854 AUTOFS_DPRINT((10, "\ttrigger: %s\n", tp
->fn_name
));
1855 /* MF_LOOKUP should never be set on trigger nodes */
1856 ASSERT((tp
->fn_flags
& MF_LOOKUP
) == 0);
1857 vfsp
= fntovn(tp
)->v_vfsp
;
1860 * The vn_vfsunlock will be done in auto_inkernel_unmount.
1862 lck_error
= vn_vfswlock(vfsp
->vfs_vnodecovered
);
1864 if (lck_error
!= 0 || (tp
->fn_flags
& MF_INPROG
) ||
1865 DEEPER(tp
) || ((fntovn(tp
))->v_count
) > 2) {
1867 * couldn't lock it because it's busy,
1868 * It is mounted on or has dirents?
1869 * If reference count is greater than two, then
1870 * somebody else is holding a reference to this vnode.
1871 * One reference is for the mountpoint, and the second
1872 * is for the trigger node.
1874 AUTOFS_DPRINT((10, "\ttrigger busy\n"));
1877 * Unlock previously locked mountpoints
1879 for (done
= 0, t1p
= fnp
->fn_trigger
; !done
;
1880 t1p
= t1p
->fn_next
) {
1882 * Unlock all nodes previously
1883 * locked. All nodes up to 'tp'
1884 * were successfully locked. If 'lck_err' is
1885 * set, then 'tp' was not locked, and thus
1886 * should not be unlocked. If
1887 * 'lck_err' is not set, then 'tp' was
1888 * successfully locked, and it should
1891 if (t1p
!= tp
|| !lck_error
) {
1892 vfsp
= fntovn(t1p
)->v_vfsp
;
1893 vn_vfsunlock(vfsp
->vfs_vnodecovered
);
1905 * It is the caller's responsibility to grab the VVFSLOCK.
1906 * Releases the VVFSLOCK upon return.
1909 unmount_node(vnode_t
*cvp
, int force
)
1917 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp
));
1919 ASSERT(vn_vfswlock_held(cvp
));
1921 vfsp
= vn_mountedvfs(cvp
);
1923 if (force
|| cfnp
->fn_flags
& MF_IK_MOUNT
) {
1925 * Mount was performed in the kernel, so
1926 * do an in-kernel unmount. auto_inkernel_unmount()
1927 * will vn_vfsunlock(cvp).
1929 error
= auto_inkernel_unmount(vfsp
);
1931 zone_t
*zone
= NULL
;
1932 refstr_t
*mntpt
, *resource
;
1936 * Get the mnttab information of the node
1937 * and ask the daemon to unmount it.
1939 bzero(&ul
, sizeof (ul
));
1940 mntfs_getmntopts(vfsp
, &ul
.mntopts
, &mntoptslen
);
1941 if (ul
.mntopts
== NULL
) {
1942 auto_log(cfnp
->fn_globals
->fng_verbose
,
1943 cfnp
->fn_globals
->fng_zoneid
, CE_WARN
,
1944 "unmount_node: no memory");
1949 if (mntoptslen
> AUTOFS_MAXOPTSLEN
)
1950 ul
.mntopts
[AUTOFS_MAXOPTSLEN
- 1] = '\0';
1952 mntpt
= vfs_getmntpoint(vfsp
);
1953 ul
.mntpnt
= (char *)refstr_value(mntpt
);
1954 resource
= vfs_getresource(vfsp
);
1955 ul
.mntresource
= (char *)refstr_value(resource
);
1957 fnip
= vfstofni(cvp
->v_vfsp
);
1958 ul
.isdirect
= fnip
->fi_flags
& MF_DIRECT
? TRUE
: FALSE
;
1961 * Since a zone'd automountd's view of the autofs mount points
1962 * differs from those in the kernel, we need to make sure we
1963 * give it consistent mount points.
1965 ASSERT(fnip
->fi_zoneid
== getzoneid());
1966 zone
= curproc
->p_zone
;
1968 if (fnip
->fi_zoneid
!= GLOBAL_ZONEID
) {
1969 if (ZONE_PATH_VISIBLE(ul
.mntpnt
, zone
)) {
1971 ZONE_PATH_TRANSLATE(ul
.mntpnt
, zone
);
1973 if (ZONE_PATH_VISIBLE(ul
.mntresource
, zone
)) {
1975 ZONE_PATH_TRANSLATE(ul
.mntresource
, zone
);
1979 ul
.fstype
= vfssw
[vfsp
->vfs_fstype
].vsw_name
;
1982 error
= auto_send_unmount_request(fnip
, &ul
, FALSE
);
1983 kmem_free(ul
.mntopts
, mntoptslen
);
1985 refstr_rele(resource
);
1989 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp
,
1995 * return EBUSY if any thread is holding a reference to this vnode
1996 * other than us. Result of this function cannot be relied on, since
1997 * it doesn't follow proper locking rules (i.e. vp->v_vfsmountedhere
1998 * and fnp->fn_trigger can change throughout this function). However
1999 * it's good enough for rough estimation.
2002 check_auto_node(vnode_t
*vp
)
2007 * number of references to expect for
2012 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp
));
2015 count
= 1; /* we are holding a reference to vp */
2016 if (fnp
->fn_flags
& MF_TRIGGER
) {
2018 * parent holds a pointer to us (trigger)
2022 if (fnp
->fn_trigger
!= NULL
) {
2024 * The trigger nodes have a hold on us.
2028 if (vn_ismntpt(vp
)) {
2030 * File system is mounted on us.
2034 mutex_enter(&vp
->v_lock
);
2035 ASSERT(vp
->v_count
> 0);
2036 if (vp
->v_flag
& VROOT
)
2038 AUTOFS_DPRINT((10, "\tcount=%u ", vp
->v_count
));
2039 if (vp
->v_count
> count
)
2041 mutex_exit(&vp
->v_lock
);
2043 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error
));
2048 * rootvp is the root of the AUTOFS filesystem.
2049 * If rootvp is busy (v_count > 1) returns EBUSY.
2050 * else removes every vnode under this tree.
2051 * ASSUMPTION: Assumes that the only node which can be busy is
2052 * the root vnode. This filesystem better be two levels deep only,
2053 * the root and its immediate subdirs.
2054 * The daemon will "AUTOFS direct-mount" only one level below the root.
2057 unmount_autofs(vnode_t
*rootvp
)
2059 fnnode_t
*fnp
, *rootfnp
, *nfnp
;
2061 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp
));
2064 * Remove all its immediate subdirectories.
2066 rootfnp
= vntofn(rootvp
);
2067 rw_enter(&rootfnp
->fn_rwlock
, RW_WRITER
);
2068 for (fnp
= rootfnp
->fn_dirents
; fnp
!= NULL
; fnp
= nfnp
) {
2069 ASSERT(fntovn(fnp
)->v_count
== 0);
2070 ASSERT(fnp
->fn_dirents
== NULL
);
2071 ASSERT(fnp
->fn_linkcnt
== 2);
2073 auto_disconnect(rootfnp
, fnp
);
2074 nfnp
= fnp
->fn_next
;
2075 auto_freefnnode(fnp
);
2077 rw_exit(&rootfnp
->fn_rwlock
);
2081 * If a node matches all unmount criteria, do:
2082 * destroy subordinate trigger node(s) if there is any
2083 * unmount filesystem mounted on top of the node if there is any
2085 * Function should be called with locked fnp's mutex. The mutex is
2086 * unlocked before return from function.
2089 try_unmount_node(fnnode_t
*fnp
, boolean_t force
)
2091 boolean_t trigger_unmount
= B_FALSE
;
2092 action_list
*alp
= NULL
;
2097 struct autofs_globals
*fngp
;
2099 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n",
2102 ASSERT(MUTEX_HELD(&fnp
->fn_lock
));
2104 fngp
= fnp
->fn_globals
;
2106 fnip
= vfstofni(vp
->v_vfsp
);
2109 * If either a mount, lookup or another unmount of this subtree is in
2110 * progress, don't attempt to unmount at this time.
2112 if (fnp
->fn_flags
& (MF_INPROG
| MF_LOOKUP
)) {
2113 mutex_exit(&fnp
->fn_lock
);
2118 * Bail out if someone else is holding reference to this vnode.
2119 * This check isn't just an optimization (someone is probably
2120 * just about to trigger mount). It is necessary to prevent a deadlock
2121 * in domount() called from auto_perform_actions() if unmount of
2122 * trigger parent fails. domount() calls lookupname() to resolve
2123 * special in mount arguments. Special is set to a map name in case
2124 * of autofs triggers (i.e. auto_ws.sun.com). Thus if current
2125 * working directory is set to currently processed node, lookupname()
2126 * calls into autofs vnops in order to resolve special, which deadlocks
2129 * Note: This should be fixed. Autofs shouldn't pass the map name
2130 * in special and avoid useless lookup with potentially disasterous
2133 if (check_auto_node(vp
) == EBUSY
) {
2134 mutex_exit(&fnp
->fn_lock
);
2139 * If not forced operation, back out if node has been referenced
2143 fnp
->fn_ref_time
+ fnip
->fi_mount_to
> gethrestime_sec()) {
2144 mutex_exit(&fnp
->fn_lock
);
2148 /* block mounts/unmounts on the node */
2149 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
2151 mutex_exit(&fnp
->fn_lock
);
2153 /* unmount next level triggers if there are any */
2154 rw_enter(&fnp
->fn_rwlock
, RW_WRITER
);
2155 if (fnp
->fn_trigger
!= NULL
) {
2156 trigger_unmount
= B_TRUE
;
2158 if (triggers_busy(fnp
)) {
2159 rw_exit(&fnp
->fn_rwlock
);
2160 mutex_enter(&fnp
->fn_lock
);
2161 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
2162 mutex_exit(&fnp
->fn_lock
);
2167 * At this point, we know all trigger nodes are locked,
2168 * and they're not busy or mounted on.
2170 * Attempt to unmount all trigger nodes, save the
2171 * action_list in case we need to remount them later.
2172 * The action_list will be freed later if there was no
2173 * need to remount the trigger nodes.
2175 unmount_triggers(fnp
, &alp
);
2177 rw_exit(&fnp
->fn_rwlock
);
2179 (void) vn_vfswlock_wait(vp
);
2181 vfsp
= vn_mountedvfs(vp
);
2183 /* vn_vfsunlock(vp) is done inside unmount_node() */
2184 error
= unmount_node(vp
, force
);
2185 if (error
== ECONNRESET
) {
2186 if (vn_mountedvfs(vp
) == NULL
) {
2188 * The filesystem was unmounted before the
2189 * daemon died. Unfortunately we can not
2190 * determine whether all the cleanup work was
2191 * successfully finished (i.e. update mnttab,
2192 * or notify NFS server of the unmount).
2193 * We should not retry the operation since the
2194 * filesystem has already been unmounted, and
2195 * may have already been removed from mnttab,
2196 * in such case the devid/rdevid we send to
2197 * the daemon will not be matched. So we have
2198 * to be content with the partial unmount.
2199 * Since the mountpoint is no longer covered, we
2200 * clear the error condition.
2203 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
2204 CE_WARN
, "autofs: automountd "
2205 "connection dropped when unmounting %s/%s",
2206 fnip
->fi_path
, (fnip
->fi_flags
& MF_DIRECT
)
2207 ? "" : fnp
->fn_name
);
2212 /* Destroy all dirents of fnp if we unmounted its triggers */
2213 if (trigger_unmount
)
2217 /* If unmount failed, we got to remount triggers */
2219 if (trigger_unmount
) {
2222 ASSERT((fnp
->fn_flags
& MF_THISUID_MATCH_RQD
) == 0);
2225 * The action list was free'd by auto_perform_actions
2227 ret
= auto_perform_actions(fnip
, fnp
, alp
, CRED());
2229 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
2230 CE_WARN
, "autofs: can't remount triggers "
2231 "fnp=%p error=%d", (void *)fnp
, ret
);
2234 mutex_enter(&fnp
->fn_lock
);
2235 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
2236 mutex_exit(&fnp
->fn_lock
);
2238 /* Free the action list here */
2239 if (trigger_unmount
)
2240 xdr_free(xdr_action_list
, (char *)alp
);
2243 * Other threads may be waiting for this unmount to
2244 * finish. We must let it know that in order to
2245 * proceed, it must trigger the mount itself.
2247 mutex_enter(&fnp
->fn_lock
);
2248 fnp
->fn_flags
&= ~MF_IK_MOUNT
;
2249 if (fnp
->fn_flags
& MF_WAITING
)
2250 fnp
->fn_error
= EAGAIN
;
2251 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
2252 mutex_exit(&fnp
->fn_lock
);
2259 * This is an implementation of depth-first search in a tree rooted by
2260 * start_fnp and composed from fnnodes. Links between tree levels are
2261 * fn_dirents, fn_trigger in fnnode_t and v_mountedvfs in vnode_t (if
2262 * mounted vfs is autofs). The algorithm keeps track of visited nodes
2263 * by means of a timestamp (fn_unmount_ref_time).
2265 * Upon top-down traversal of the tree we apply following locking scheme:
2266 * lock fn_rwlock of current node
2267 * grab reference to child's vnode (VN_HOLD)
2269 * free reference to current vnode (VN_RELE)
2270 * Similar locking scheme is used for down-top and left-right traversal.
2272 * Algorithm examines the most down-left node in tree, which hasn't been
2273 * visited yet. From this follows that nodes are processed in bottom-up
2276 * Function returns either zero if unmount of root node was successful
2277 * or error code (mostly EBUSY).
2280 unmount_subtree(fnnode_t
*rootfnp
, boolean_t force
)
2282 fnnode_t
*currfnp
; /* currently examined node in the tree */
2283 fnnode_t
*lastfnp
; /* previously processed node */
2284 fnnode_t
*nextfnp
; /* next examined node in the tree */
2290 ASSERT(fntovn(rootfnp
)->v_type
!= VLNK
);
2291 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp
,
2295 * Timestamp, which visited nodes are marked with, to distinguish them
2296 * from unvisited nodes.
2298 timestamp
= gethrestime_sec();
2299 currfnp
= lastfnp
= rootfnp
;
2301 /* Loop until we examine all nodes in the tree */
2302 mutex_enter(&currfnp
->fn_lock
);
2303 while (currfnp
!= rootfnp
|| rootfnp
->fn_unmount_ref_time
< timestamp
) {
2304 curvp
= fntovn(currfnp
);
2305 AUTOFS_DPRINT((10, "\tunmount_subtree: entering node %p (%s)\n",
2306 (void *)currfnp
, currfnp
->fn_name
));
2309 * New candidate for processing must have been already visited,
2310 * by us because we want to process tree nodes in bottom-up
2313 if (currfnp
->fn_unmount_ref_time
== timestamp
&&
2314 currfnp
!= lastfnp
) {
2315 (void) try_unmount_node(currfnp
, force
);
2317 mutex_enter(&currfnp
->fn_lock
);
2319 * Fall through to next if-branch to pick
2320 * sibling or parent of this node.
2325 * If this node has been already visited, it means that it's
2326 * dead end and we need to pick sibling or parent as next node.
2328 if (currfnp
->fn_unmount_ref_time
>= timestamp
||
2329 curvp
->v_type
== VLNK
) {
2330 mutex_exit(&currfnp
->fn_lock
);
2332 * Obtain parent's readers lock before grabbing
2333 * reference to sibling.
2335 rw_enter(&currfnp
->fn_parent
->fn_rwlock
, RW_READER
);
2336 if ((nextfnp
= currfnp
->fn_next
) != NULL
) {
2337 VN_HOLD(fntovn(nextfnp
));
2338 rw_exit(&currfnp
->fn_parent
->fn_rwlock
);
2341 mutex_enter(&currfnp
->fn_lock
);
2344 rw_exit(&currfnp
->fn_parent
->fn_rwlock
);
2347 * All descendants and siblings were visited. Perform
2350 nextfnp
= currfnp
->fn_parent
;
2351 VN_HOLD(fntovn(nextfnp
));
2354 mutex_enter(&currfnp
->fn_lock
);
2359 * Mark node as visited. Note that the timestamp could have
2360 * been updated by somebody else in the meantime.
2362 if (currfnp
->fn_unmount_ref_time
< timestamp
)
2363 currfnp
->fn_unmount_ref_time
= timestamp
;
2366 * Don't descent below nodes, which are being unmounted/mounted.
2368 * We need to hold both locks at once: fn_lock because we need
2369 * to read MF_INPROG and fn_rwlock to prevent anybody from
2370 * modifying fn_trigger until its used to traverse triggers
2373 * Acquire fn_rwlock in non-blocking mode to avoid deadlock.
2374 * If it can't be acquired, then acquire locks in correct
2377 if (!rw_tryenter(&currfnp
->fn_rwlock
, RW_READER
)) {
2378 mutex_exit(&currfnp
->fn_lock
);
2379 rw_enter(&currfnp
->fn_rwlock
, RW_READER
);
2380 mutex_enter(&currfnp
->fn_lock
);
2382 if (currfnp
->fn_flags
& MF_INPROG
) {
2383 rw_exit(&currfnp
->fn_rwlock
);
2386 mutex_exit(&currfnp
->fn_lock
);
2389 * Examine descendants in this order: triggers, dirents, autofs
2393 if ((nextfnp
= currfnp
->fn_trigger
) != NULL
) {
2394 VN_HOLD(fntovn(nextfnp
));
2395 rw_exit(&currfnp
->fn_rwlock
);
2398 mutex_enter(&currfnp
->fn_lock
);
2402 if ((nextfnp
= currfnp
->fn_dirents
) != NULL
) {
2403 VN_HOLD(fntovn(nextfnp
));
2404 rw_exit(&currfnp
->fn_rwlock
);
2407 mutex_enter(&currfnp
->fn_lock
);
2410 rw_exit(&currfnp
->fn_rwlock
);
2412 (void) vn_vfswlock_wait(curvp
);
2413 vfsp
= vn_mountedvfs(curvp
);
2415 vfs_matchops(vfsp
, vfs_getops(curvp
->v_vfsp
))) {
2417 * Deal with /xfn/host/jurassic alikes here...
2419 * We know this call to VFS_ROOT is safe to call while
2420 * holding VVFSLOCK, since it resolves to a call to
2423 if (VFS_ROOT(vfsp
, &newvp
)) {
2425 "autofs: VFS_ROOT(vfs=%p) failed",
2428 vn_vfsunlock(curvp
);
2430 currfnp
= vntofn(newvp
);
2431 mutex_enter(&currfnp
->fn_lock
);
2434 vn_vfsunlock(curvp
);
2435 mutex_enter(&currfnp
->fn_lock
);
2439 * Now we deal with the root node (currfnp's mutex is unlocked
2440 * in try_unmount_node()).
2442 return (try_unmount_node(currfnp
, force
));
2446 * XXX unmount_tree() is not suspend-safe within the scope of
2447 * the present model defined for cpr to suspend the system. Calls made
2448 * by the unmount_tree() that have been identified to be unsafe are
2449 * (1) RPC client handle setup and client calls to automountd which can
2450 * block deep down in the RPC library, (2) kmem_alloc() calls with the
2451 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*() and
2452 * VOP_*() calls which can result in over the wire calls to servers.
2453 * The thread should be completely reevaluated to make it suspend-safe in
2454 * case of future updates to the cpr model.
2457 unmount_tree(struct autofs_globals
*fngp
, boolean_t force
)
2459 callb_cpr_t cprinfo
;
2460 kmutex_t unmount_tree_cpr_lock
;
2461 fnnode_t
*root
, *fnp
, *next
;
2463 mutex_init(&unmount_tree_cpr_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
2464 CALLB_CPR_INIT(&cprinfo
, &unmount_tree_cpr_lock
, callb_generic_cpr
,
2468 * autofssys() will be calling in from the global zone and doing
2469 * work on the behalf of the given zone, hence we can't always
2470 * assert that we have the right credentials, nor that the
2471 * caller is always in the correct zone.
2473 * We do, however, know that if this is a "forced unmount"
2474 * operation (which autofssys() does), then we won't go down to
2475 * the krpc layers, so we don't need to fudge with the
2478 ASSERT(force
|| fngp
->fng_zoneid
== getzoneid());
2481 * If automountd is not running in this zone,
2482 * don't attempt unmounting this round.
2484 if (force
|| auto_null_request(fngp
->fng_zoneid
, FALSE
) == 0) {
2486 * Iterate over top level autofs filesystems and call
2487 * unmount_subtree() for each of them.
2489 root
= fngp
->fng_rootfnnodep
;
2490 rw_enter(&root
->fn_rwlock
, RW_READER
);
2491 for (fnp
= root
->fn_dirents
; fnp
!= NULL
; fnp
= next
) {
2492 VN_HOLD(fntovn(fnp
));
2493 rw_exit(&root
->fn_rwlock
);
2494 (void) unmount_subtree(fnp
, force
);
2495 rw_enter(&root
->fn_rwlock
, RW_READER
);
2496 next
= fnp
->fn_next
;
2497 VN_RELE(fntovn(fnp
));
2499 rw_exit(&root
->fn_rwlock
);
2502 mutex_enter(&unmount_tree_cpr_lock
);
2503 CALLB_CPR_EXIT(&cprinfo
);
2504 mutex_destroy(&unmount_tree_cpr_lock
);
2508 unmount_zone_tree(struct autofs_globals
*fngp
)
2510 AUTOFS_DPRINT((5, "unmount_zone_tree started. Thread created.\n"));
2512 unmount_tree(fngp
, B_FALSE
);
2513 mutex_enter(&fngp
->fng_unmount_threads_lock
);
2514 fngp
->fng_unmount_threads
--;
2515 mutex_exit(&fngp
->fng_unmount_threads_lock
);
2517 AUTOFS_DPRINT((5, "unmount_zone_tree done. Thread exiting.\n"));
2524 auto_do_unmount(struct autofs_globals
*fngp
)
2526 callb_cpr_t cprinfo
;
2528 zone_t
*zone
= curproc
->p_zone
;
2530 CALLB_CPR_INIT(&cprinfo
, &fngp
->fng_unmount_threads_lock
,
2531 callb_generic_cpr
, "auto_do_unmount");
2533 for (;;) { /* forever */
2534 mutex_enter(&fngp
->fng_unmount_threads_lock
);
2535 CALLB_CPR_SAFE_BEGIN(&cprinfo
);
2537 mutex_exit(&fngp
->fng_unmount_threads_lock
);
2538 timeleft
= zone_status_timedwait(zone
, ddi_get_lbolt() +
2539 autofs_unmount_thread_timer
* hz
, ZONE_IS_SHUTTING_DOWN
);
2540 mutex_enter(&fngp
->fng_unmount_threads_lock
);
2542 if (timeleft
!= -1) { /* didn't time out */
2543 ASSERT(zone_status_get(zone
) >= ZONE_IS_SHUTTING_DOWN
);
2545 * zone is exiting... don't create any new threads.
2546 * fng_unmount_threads_lock is released implicitly by
2549 CALLB_CPR_SAFE_END(&cprinfo
,
2550 &fngp
->fng_unmount_threads_lock
);
2551 CALLB_CPR_EXIT(&cprinfo
);
2555 if (fngp
->fng_unmount_threads
< autofs_unmount_threads
) {
2556 fngp
->fng_unmount_threads
++;
2557 CALLB_CPR_SAFE_END(&cprinfo
,
2558 &fngp
->fng_unmount_threads_lock
);
2559 mutex_exit(&fngp
->fng_unmount_threads_lock
);
2561 (void) zthread_create(NULL
, 0, unmount_zone_tree
, fngp
,
2570 * Is nobrowse specified in option string?
2571 * opts should be a null ('\0') terminated string.
2572 * Returns non-zero if nobrowse has been specified.
2575 auto_nobrowse_option(char *opts
)
2584 len
= strlen(opts
) + 1;
2585 p
= buf
= kmem_alloc(len
, KM_SLEEP
);
2586 (void) strcpy(buf
, opts
);
2588 if (t
= strchr(p
, ','))
2592 if (strcmp(p
, MNTOPT_NOBROWSE
) == 0)
2594 else if (strcmp(p
, MNTOPT_BROWSE
) == 0)
2597 } while (!last_opt
);
2598 kmem_free(buf
, len
);
2604 * used to log warnings only if automountd is running
2605 * with verbose mode set
2609 auto_log(int verbose
, zoneid_t zoneid
, int level
, const char *fmt
, ...)
2614 va_start(args
, fmt
);
2615 vzcmn_err(zoneid
, level
, fmt
, args
);
2621 static int autofs_debug
= 0;
2624 * Utilities used by both client and server
2629 * 3) current test software
2630 * 4) main procedure entry points
2631 * 5) main procedure exit points
2632 * 6) utility procedure entry points
2633 * 7) utility procedure exit points
2634 * 8) obscure procedure entry points
2635 * 9) obscure procedure exit points
2644 auto_dprint(int level
, const char *fmt
, ...)
2648 if (autofs_debug
== level
||
2649 (autofs_debug
> 10 && (autofs_debug
- 10) >= level
)) {
2650 va_start(args
, fmt
);
2651 (void) vprintf(fmt
, args
);