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
|| link
.link
!= '\0') {
167 * This node should be a symlink
169 error
= auto_perform_link(fnp
, &link
, cred
);
170 } else if (mountreq
) {
172 * The automount daemon is requesting a mount,
173 * implying this entry must be a wildcard match and
174 * therefore in need of verification that the entry
175 * exists on the server.
177 mutex_enter(&fnp
->fn_lock
);
178 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
182 * Unblock other lookup requests on this node,
183 * this is needed to let the lookup generated by
184 * the mount call to complete. The caveat is
185 * other lookups on this node can also get by,
186 * i.e., another lookup on this node that occurs
187 * while this lookup is attempting the mount
188 * would return a positive result no matter what.
189 * Therefore two lookups on the this node could
190 * potentially get disparate results.
192 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_LOOKUP
);
193 mutex_exit(&fnp
->fn_lock
);
195 * auto_new_mount_thread fires up a new thread which
196 * calls automountd finishing up the work
198 auto_new_mount_thread(fnp
, name
, cred
);
201 * At this point, we are simply another thread
202 * waiting for the mount to complete
204 error
= auto_wait4mount(fnp
);
205 if (error
== AUTOFS_SHUTDOWN
)
211 kmem_free(link
.link
, strlen(link
.link
) + 1);
213 kmem_free(link
.dir
, strlen(link
.dir
) + 1);
214 mutex_enter(&fnp
->fn_lock
);
215 fnp
->fn_error
= error
;
218 * Notify threads waiting for lookup/mount that
222 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
224 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_LOOKUP
);
226 mutex_exit(&fnp
->fn_lock
);
231 * Starting point for thread to handle mount requests with automountd.
232 * XXX auto_mount_thread() is not suspend-safe within the scope of
233 * the present model defined for cpr to suspend the system. Calls
234 * made by the auto_mount_thread() that have been identified to be unsafe
235 * are (1) RPC client handle setup and client calls to automountd which
236 * can block deep down in the RPC library, (2) kmem_alloc() calls with the
237 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*(), and
238 * lookuppnvp() calls which can result in over the wire calls to servers.
239 * The thread should be completely reevaluated to make it suspend-safe in
240 * case of future updates to the cpr model.
243 auto_mount_thread(struct autofs_callargs
*argsp
)
251 action_list
*alp
= NULL
;
254 kmutex_t auto_mount_thread_cpr_lock
;
256 mutex_init(&auto_mount_thread_cpr_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
257 CALLB_CPR_INIT(&cprinfo
, &auto_mount_thread_cpr_lock
,
258 callb_generic_cpr
, "auto_mount_thread");
260 fnp
= argsp
->fnc_fnp
;
262 fnip
= vfstofni(vp
->v_vfsp
);
263 name
= argsp
->fnc_name
;
264 cred
= argsp
->fnc_cred
;
265 ASSERT(crgetzoneid(argsp
->fnc_cred
) == fnip
->fi_zoneid
);
267 error
= auto_mount_request(fnip
, name
, &alp
, cred
, TRUE
);
269 error
= auto_perform_actions(fnip
, fnp
, alp
, cred
);
270 mutex_enter(&fnp
->fn_lock
);
271 fnp
->fn_error
= error
;
274 * Notify threads waiting for mount that
277 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
278 mutex_exit(&fnp
->fn_lock
);
281 crfree(argsp
->fnc_cred
);
282 namelen
= strlen(argsp
->fnc_name
) + 1;
283 kmem_free(argsp
->fnc_name
, namelen
);
284 kmem_free(argsp
, sizeof (*argsp
));
286 mutex_enter(&auto_mount_thread_cpr_lock
);
287 CALLB_CPR_EXIT(&cprinfo
);
288 mutex_destroy(&auto_mount_thread_cpr_lock
);
293 static int autofs_thr_success
= 0;
296 * Creates new thread which calls auto_mount_thread which does
297 * the bulk of the work calling automountd, via 'auto_perform_actions'.
300 auto_new_mount_thread(fnnode_t
*fnp
, char *name
, cred_t
*cred
)
302 struct autofs_callargs
*argsp
;
304 argsp
= kmem_alloc(sizeof (*argsp
), KM_SLEEP
);
305 VN_HOLD(fntovn(fnp
));
306 argsp
->fnc_fnp
= fnp
;
307 argsp
->fnc_name
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
308 (void) strcpy(argsp
->fnc_name
, name
);
309 argsp
->fnc_origin
= curthread
;
311 argsp
->fnc_cred
= cred
;
313 (void) zthread_create(NULL
, 0, auto_mount_thread
, argsp
, 0,
315 autofs_thr_success
++;
318 #define DOOR_BUF_ALIGN (1024*1024)
319 #define DOOR_BUF_MULTIPLIER 3
320 #define DOOR_BUF_DEFAULT_SZ (DOOR_BUF_MULTIPLIER * DOOR_BUF_ALIGN)
321 int doorbuf_defsz
= DOOR_BUF_DEFAULT_SZ
;
330 xdrproc_t xresp_func
,
333 bool_t hard
) /* retry forever? */
338 door_arg_t door_args
;
342 struct autofs_globals
*fngp
= NULL
;
345 int rlen
= 0; /* MUST be initialized */
346 autofs_door_args_t
*xdr_argsp
;
348 int printed_not_running_msg
= 0;
349 klwp_t
*lwp
= ttolwp(curthread
);
352 * We know that the current thread is doing work on
353 * behalf of its own zone, so it's ok to use
356 ASSERT(zoneid
== getzoneid());
357 if (zone_status_get(curproc
->p_zone
) >= ZONE_IS_SHUTTING_DOWN
) {
359 * There's no point in trying to talk to
360 * automountd. Plus, zone_shutdown() is
363 return (ECONNREFUSED
);
368 mutex_enter(&autofs_minor_lock
);
369 fngp
= zone_getspecific(autofs_key
, curproc
->p_zone
);
370 mutex_exit(&autofs_minor_lock
);
375 "failed to get door handle\n"));
376 if (!printed_not_running_msg
) {
377 printed_not_running_msg
= 1;
378 zprintf(zoneid
, "automountd not "\
379 "running, retrying\n");
385 * There is no global data so no door.
386 * There's no point in attempting to talk
387 * to automountd if we can't get the door
390 return (ECONNREFUSED
);
395 if (printed_not_running_msg
) {
396 fngp
->fng_printed_not_running_msg
= printed_not_running_msg
;
399 ASSERT(fngp
!= NULL
);
401 if (argsp
!= NULL
&& (xdr_len
= xdr_sizeof(xarg_func
, argsp
)) == 0)
403 xdr_argsp
= kmem_zalloc(xdr_len
+ sizeof (*xdr_argsp
), KM_SLEEP
);
404 xdr_argsp
->xdr_len
= xdr_len
;
405 xdr_argsp
->cmd
= which
;
408 xdrmem_create(&xdrarg
, (char *)&xdr_argsp
->xdr_arg
,
409 xdr_argsp
->xdr_len
, XDR_ENCODE
);
411 if (!(*xarg_func
)(&xdrarg
, argsp
)) {
412 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
418 * We're saving off the original pointer and length due to the
419 * possibility that the results buffer returned by the door
420 * upcall can be different then what we passed in. This is because
421 * the door will allocate new memory if the results buffer passed
422 * in isn't large enough to hold what we need to send back.
423 * In this case we need to free the memory originally allocated
427 rlen
= xdr_sizeof(xresp_func
, resp
);
428 orl
= (rlen
== 0) ? doorbuf_defsz
: MAX(rlen
, doorbuf_defsz
);
429 orp
= kmem_zalloc(orl
, KM_SLEEP
);
433 mutex_enter(&fngp
->fng_autofs_daemon_lock
);
434 dh
= fngp
->fng_autofs_daemon_dh
;
437 mutex_exit(&fngp
->fng_autofs_daemon_lock
);
442 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
445 door_args
.data_ptr
= (char *)xdr_argsp
;
446 door_args
.data_size
= sizeof (*xdr_argsp
) + xdr_argsp
->xdr_len
;
447 door_args
.desc_ptr
= NULL
;
448 door_args
.desc_num
= 0;
449 door_args
.rbuf
= orp
? (char *)orp
: NULL
;
450 door_args
.rsize
= orl
;
454 door_ki_upcall_limited(dh
, &door_args
, NULL
, SIZE_MAX
, 0);
460 * Handle daemon errors
464 * Upcall successful. Let's check for soft errors
465 * from the daemon. We only recover from overflow
466 * type scenarios. Any other errors, we return to
469 autofs_door_res_t
*adr
=
470 (autofs_door_res_t
*)door_args
.rbuf
;
472 if (door_args
.rbuf
!= NULL
) {
475 switch (error
= adr
->res_status
) {
476 case 0: /* no error; continue */
481 * orig landing buf not big enough.
482 * xdr_len in XDR_BYTES_PER_UNIT
484 if ((nl
= adr
->xdr_len
) > 0 &&
485 (btopr(nl
) < freemem
/64)) {
488 orp
= kmem_zalloc(nl
, KM_SLEEP
);
497 xdr_len
+ sizeof (*xdr_argsp
));
507 * no daemon errors; now process door/comm errors (if any)
512 * interrupts should be handled properly by the
513 * door upcall. If the door doesn't handle the
514 * interupt completely then we need to bail out.
516 if (lwp
&& (ISSIG(curthread
,
517 JUSTLOOKING
) || MUSTRETURN(curproc
, curthread
))) {
518 if (ISSIG(curthread
, FORREAL
) ||
520 MUSTRETURN(curproc
, curthread
)) {
521 lwp
->lwp_sysabort
= 0;
526 * We may have gotten EINTR for other reasons
527 * like the door being revoked on us. Instead
528 * of trying to extract this out of the door
529 * handle, sleep and try again, if still
530 * revoked we will get EBADF next time
533 * If we have a pending cancellation and we don't
534 * have cancellation disabled, we will get EINTR
535 * forever, no matter how many times we retry,
536 * so just get out now if this is the case.
538 if (schedctl_cancel_pending())
541 case EAGAIN
: /* process may be forking */
548 case EBADF
: /* Invalid door */
549 case EINVAL
: /* Not a door, wrong target */
551 * A fatal door error, if our failing door
552 * handle is the current door handle, clean
555 mutex_enter(&fngp
->fng_autofs_daemon_lock
);
556 if (dh
== fngp
->fng_autofs_daemon_dh
) {
557 door_ki_rele(fngp
->fng_autofs_daemon_dh
);
558 fngp
->fng_autofs_daemon_dh
= NULL
;
560 mutex_exit(&fngp
->fng_autofs_daemon_lock
);
561 AUTOFS_DPRINT((5, "auto_calldaemon error=%d\n", error
));
563 if (!fngp
->fng_printed_not_running_msg
) {
564 fngp
->fng_printed_not_running_msg
= 1;
565 zprintf(zoneid
, "automountd not "
566 "running, retrying\n");
572 error
= ECONNREFUSED
;
574 xdr_len
+ sizeof (*xdr_argsp
));
579 default: /* Unknown must be fatal */
581 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
588 if (fngp
->fng_printed_not_running_msg
== 1) {
589 fngp
->fng_printed_not_running_msg
= 0;
590 zprintf(zoneid
, "automountd OK\n");
594 autofs_door_res_t
*door_resp
;
595 door_resp
= (autofs_door_res_t
*)door_args
.rbuf
;
597 if ((void *)door_args
.rbuf
!= orp
)
600 xdrmem_create(&xdrres
, (char *)&door_resp
->xdr_res
,
601 door_resp
->xdr_len
, XDR_DECODE
);
603 if (!((*xresp_func
)(&xdrres
, resp
)))
605 kmem_free(door_args
.rbuf
, door_args
.rsize
);
607 kmem_free(xdr_argsp
, xdr_len
+ sizeof (*xdr_argsp
));
612 auto_null_request(zoneid_t zoneid
, bool_t hard
)
616 AUTOFS_DPRINT((4, "\tauto_null_request\n"));
618 error
= auto_calldaemon(zoneid
, NULLPROC
,
619 xdr_void
, NULL
, xdr_void
, NULL
, 0, hard
);
621 AUTOFS_DPRINT((5, "\tauto_null_request: error=%d\n", error
));
635 struct autofs_globals
*fngp
;
636 struct autofs_lookupargs reqst
;
637 autofs_lookupres
*resp
;
641 AUTOFS_DPRINT((4, "auto_lookup_equest: path=%s name=%s\n",
642 fnip
->fi_path
, key
));
644 fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
646 reqst
.map
= fnip
->fi_map
;
647 reqst
.path
= fnip
->fi_path
;
649 if (fnip
->fi_flags
& MF_DIRECT
)
650 reqst
.name
= fnip
->fi_key
;
653 AUTOFS_DPRINT((4, "auto_lookup_request: using key=%s\n", reqst
.name
));
655 reqst
.subdir
= fnip
->fi_subdir
;
656 reqst
.opts
= fnip
->fi_opts
;
657 reqst
.isdirect
= fnip
->fi_flags
& MF_DIRECT
? TRUE
: FALSE
;
658 reqst
.uid
= crgetuid(cred
);
660 resp
= kmem_zalloc(sizeof (*resp
), KM_SLEEP
);
662 error
= auto_calldaemon(fngp
->fng_zoneid
, AUTOFS_LOOKUP
,
663 xdr_autofs_lookupargs
, &reqst
, xdr_autofs_lookupres
,
664 (void *)resp
, sizeof (autofs_lookupres
), hard
);
667 xdr_free(xdr_autofs_lookupres
, (char *)resp
);
668 kmem_free(resp
, sizeof (*resp
));
673 fngp
->fng_verbose
= resp
->lu_verbose
;
674 switch (resp
->lu_res
) {
676 switch (resp
->lu_type
.action
) {
677 case AUTOFS_MOUNT_RQ
:
684 p
= &resp
->lu_type
.lookup_result_type_u
.lt_linka
;
685 lnp
->dir
= kmem_alloc(strlen(p
->dir
) + 1,
687 (void) strcpy(lnp
->dir
, p
->dir
);
688 lnp
->link
= kmem_alloc(strlen(p
->link
) + 1,
690 (void) strcpy(lnp
->link
, p
->link
);
699 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
700 CE_WARN
, "auto_lookup_request: bad action "
701 "type %d", resp
->lu_res
);
712 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
, CE_WARN
,
713 "auto_lookup_request: unknown result: %d",
719 xdr_free(xdr_autofs_lookupres
, (char *)resp
);
720 kmem_free(resp
, sizeof (*resp
));
721 AUTOFS_DPRINT((5, "auto_lookup_request: path=%s name=%s error=%d\n",
722 fnip
->fi_path
, key
, error
));
735 struct autofs_globals
*fngp
;
736 autofs_lookupargs reqst
;
737 autofs_mountres
*xdrres
= NULL
;
739 AUTOFS_DPRINT((4, "auto_mount_request: path=%s name=%s\n",
740 fnip
->fi_path
, key
));
742 fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
743 reqst
.map
= fnip
->fi_map
;
744 reqst
.path
= fnip
->fi_path
;
746 if (fnip
->fi_flags
& MF_DIRECT
)
747 reqst
.name
= fnip
->fi_key
;
751 AUTOFS_DPRINT((4, "auto_mount_request: using key=%s\n", reqst
.name
));
753 reqst
.subdir
= fnip
->fi_subdir
;
754 reqst
.opts
= fnip
->fi_opts
;
755 reqst
.isdirect
= fnip
->fi_flags
& MF_DIRECT
? TRUE
: FALSE
;
756 reqst
.uid
= crgetuid(cred
);
758 xdrres
= kmem_zalloc(sizeof (*xdrres
), KM_SLEEP
);
760 error
= auto_calldaemon(fngp
->fng_zoneid
, AUTOFS_MNTINFO
,
761 xdr_autofs_lookupargs
, &reqst
, xdr_autofs_mountres
,
762 (void *)xdrres
, sizeof (autofs_mountres
), hard
);
765 fngp
->fng_verbose
= xdrres
->mr_verbose
;
766 switch (xdrres
->mr_type
.status
) {
770 * Save the action list since it is used by
771 * the caller. We NULL the action list pointer
772 * in 'result' so that xdr_free() will not free
775 *alpp
= xdrres
->mr_type
.mount_result_type_u
.list
;
776 xdrres
->mr_type
.mount_result_type_u
.list
= NULL
;
779 error
= xdrres
->mr_type
.mount_result_type_u
.error
;
783 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
, CE_WARN
,
784 "auto_mount_request: unknown status %d",
785 xdrres
->mr_type
.status
);
790 xdr_free(xdr_autofs_mountres
, (char *)xdrres
);
791 kmem_free(xdrres
, sizeof (*xdrres
));
794 AUTOFS_DPRINT((5, "auto_mount_request: path=%s name=%s error=%d\n",
795 fnip
->fi_path
, key
, error
));
801 auto_send_unmount_request(
809 struct autofs_globals
*fngp
= vntofn(fnip
->fi_rootvp
)->fn_globals
;
811 AUTOFS_DPRINT((4, "\tauto_send_unmount_request: fstype=%s "
812 " mntpnt=%s\n", ul
->fstype
, ul
->mntpnt
));
814 bzero(&xdrres
, sizeof (umntres
));
815 error
= auto_calldaemon(fngp
->fng_zoneid
, AUTOFS_UNMOUNT
,
816 xdr_umntrequest
, (void *)ul
, xdr_umntres
, (void *)&xdrres
,
817 sizeof (umntres
), hard
);
820 error
= xdrres
.status
;
822 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error
));
828 auto_perform_link(fnnode_t
*fnp
, struct linka
*linkp
, cred_t
*cred
)
834 AUTOFS_DPRINT((3, "auto_perform_link: fnp=%p dir=%s link=%s\n",
835 (void *)fnp
, linkp
->dir
, linkp
->link
));
837 len
= strlen(linkp
->link
) + 1; /* include '\0' */
838 tmp
= kmem_zalloc(len
, KM_SLEEP
);
839 (void) kcopy(linkp
->link
, tmp
, len
);
840 mutex_enter(&fnp
->fn_lock
);
841 fnp
->fn_symlink
= tmp
;
842 fnp
->fn_symlinklen
= (uint_t
)len
;
843 fnp
->fn_flags
|= MF_THISUID_MATCH_RQD
;
846 mutex_exit(&fnp
->fn_lock
);
855 auto_free_autofs_args(struct mounta
*m
)
857 autofs_args
*aargs
= (autofs_args
*)m
->dataptr
;
860 kmem_free(aargs
->addr
.buf
, aargs
->addr
.len
);
862 kmem_free(aargs
->path
, strlen(aargs
->path
) + 1);
864 kmem_free(aargs
->opts
, strlen(aargs
->opts
) + 1);
866 kmem_free(aargs
->map
, strlen(aargs
->map
) + 1);
868 kmem_free(aargs
->subdir
, strlen(aargs
->subdir
) + 1);
870 kmem_free(aargs
->key
, strlen(aargs
->key
) + 1);
871 kmem_free(aargs
, sizeof (*aargs
));
875 auto_free_action_list(action_list
*alp
)
878 action_list
*lastalp
;
881 m
= &alp
->action
.action_list_entry_u
.mounta
;
882 while (alp
!= NULL
) {
883 fstype
= alp
->action
.action_list_entry_u
.mounta
.fstype
;
884 m
= &alp
->action
.action_list_entry_u
.mounta
;
886 if (strcmp(fstype
, "autofs") == 0) {
887 auto_free_autofs_args(m
);
891 kmem_free(m
->spec
, strlen(m
->spec
) + 1);
893 kmem_free(m
->dir
, strlen(m
->dir
) + 1);
895 kmem_free(m
->fstype
, strlen(m
->fstype
) + 1);
897 kmem_free(m
->optptr
, m
->optlen
);
900 kmem_free(lastalp
, sizeof (*lastalp
));
905 auto_invalid_autofs(fninfo_t
*dfnip
, fnnode_t
*dfnp
, action_list
*p
)
908 struct autofs_args
*argsp
;
910 char buff
[AUTOFS_MAXPATHLEN
];
912 struct autofs_globals
*fngp
;
914 fngp
= dfnp
->fn_globals
;
917 m
= &p
->action
.action_list_entry_u
.mounta
;
919 * Make sure we aren't geting passed NULL values or a "dir" that
920 * isn't "." and doesn't begin with "./".
922 * We also only want to perform autofs mounts, so make sure
923 * no-one is trying to trick us into doing anything else.
925 if (m
->spec
== NULL
|| m
->dir
== NULL
|| m
->dir
[0] != '.' ||
926 (m
->dir
[1] != '/' && m
->dir
[1] != '\0') ||
927 m
->fstype
== NULL
|| strcmp(m
->fstype
, "autofs") != 0 ||
928 m
->dataptr
== NULL
|| m
->datalen
!= sizeof (struct autofs_args
) ||
932 * We also don't like ".."s in the pathname. Symlinks are
933 * handled by the fact that we'll use NOFOLLOW when we do
936 if (strstr(m
->dir
, "/../") != NULL
||
937 (len
= strlen(m
->dir
)) > sizeof ("/..") - 1 &&
938 m
->dir
[len
] == '.' && m
->dir
[len
- 1] == '.' &&
939 m
->dir
[len
- 2] == '/')
941 argsp
= (struct autofs_args
*)m
->dataptr
;
943 * We don't want NULL values here either.
945 if (argsp
->addr
.buf
== NULL
|| argsp
->path
== NULL
||
946 argsp
->opts
== NULL
|| argsp
->map
== NULL
|| argsp
->subdir
== NULL
)
949 * We know what the claimed pathname *should* look like:
951 * If the parent (dfnp) is a mount point (VROOT), then
952 * the path should be (dfnip->fi_path + m->dir).
954 * Else, we know we're only two levels deep, so we use
955 * (dfnip->fi_path + dfnp->fn_name + m->dir).
957 * Furthermore, "." only makes sense if dfnp is a
960 * At this point it seems like the passed-in path is
963 if (dvp
->v_flag
& VROOT
) {
964 if (m
->dir
[1] == '\0' && !(dfnp
->fn_flags
& MF_TRIGGER
))
966 (void) snprintf(buff
, sizeof (buff
), "%s%s",
967 dfnip
->fi_path
, m
->dir
+ 1);
969 (void) snprintf(buff
, sizeof (buff
), "%s/%s%s",
970 dfnip
->fi_path
, dfnp
->fn_name
, m
->dir
+ 1);
972 if (strcmp(argsp
->path
, buff
) != 0) {
973 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
974 CE_WARN
, "autofs: expected path of '%s', "
975 "got '%s' instead.", buff
, argsp
->path
);
978 return (B_FALSE
); /* looks OK */
982 * auto_invalid_action will validate the action_list received. If all is good
983 * this function returns FALSE, if there is a problem it returns TRUE.
986 auto_invalid_action(fninfo_t
*dfnip
, fnnode_t
*dfnp
, action_list
*alistpp
)
990 * Before we go any further, this better be a mount request.
992 if (alistpp
->action
.action
!= AUTOFS_MOUNT_RQ
)
994 return (auto_invalid_autofs(dfnip
, dfnp
, alistpp
));
999 auto_perform_actions(
1003 cred_t
*cred
) /* Credentials of the caller */
1007 struct mounta
*m
, margs
;
1008 struct autofs_args
*argsp
;
1009 int error
, success
= 0;
1010 vnode_t
*mvp
, *dvp
, *newvp
;
1011 fnnode_t
*newfnp
, *mfnp
;
1013 int save_triggers
= 0;
1014 int update_times
= 0;
1016 char buff
[AUTOFS_MAXPATHLEN
];
1018 struct autofs_globals
*fngp
;
1021 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", (void *)alp
));
1023 fngp
= dfnp
->fn_globals
;
1027 * As automountd running in a zone may be compromised, and this may be
1028 * an attack, we can't trust everything passed in by automountd, and we
1029 * need to do argument verification. We'll issue a warning and drop
1030 * the request if it doesn't seem right.
1033 for (p
= alp
; p
!= NULL
; p
= p
->next
) {
1034 if (auto_invalid_action(dfnip
, dfnp
, p
)) {
1036 * This warning should be sent to the global zone,
1037 * since presumably the zone administrator is the same
1040 cmn_err(CE_WARN
, "autofs: invalid action list received "
1041 "by automountd in zone %s.",
1042 curproc
->p_zone
->zone_name
);
1044 * This conversation is over.
1046 xdr_free(xdr_action_list
, (char *)alp
);
1051 zcred
= zone_get_kcred(getzoneid());
1052 ASSERT(zcred
!= NULL
);
1054 if (vn_mountedvfs(dvp
) != NULL
) {
1056 * The daemon successfully mounted a filesystem
1057 * on the AUTOFS root node.
1059 mutex_enter(&dfnp
->fn_lock
);
1060 dfnp
->fn_flags
|= MF_MOUNTPOINT
;
1061 ASSERT(dfnp
->fn_dirents
== NULL
);
1062 mutex_exit(&dfnp
->fn_lock
);
1066 * Clear MF_MOUNTPOINT.
1068 mutex_enter(&dfnp
->fn_lock
);
1069 if (dfnp
->fn_flags
& MF_MOUNTPOINT
) {
1070 AUTOFS_DPRINT((10, "autofs: clearing mountpoint "
1071 "flag on %s.", dfnp
->fn_name
));
1072 ASSERT(dfnp
->fn_dirents
== NULL
);
1073 ASSERT(dfnp
->fn_trigger
== NULL
);
1075 dfnp
->fn_flags
&= ~MF_MOUNTPOINT
;
1076 mutex_exit(&dfnp
->fn_lock
);
1079 for (p
= alp
; p
!= NULL
; p
= p
->next
) {
1081 vfs_t
*vfsp
; /* dummy argument */
1086 m
= &p
->action
.action_list_entry_u
.mounta
;
1087 argsp
= (struct autofs_args
*)m
->dataptr
;
1088 ASSERT(strcmp(m
->fstype
, "autofs") == 0);
1090 * use the parent directory's timeout since it's the
1091 * one specified/inherited by automount.
1093 argsp
->mount_to
= dfnip
->fi_mount_to
;
1095 * The mountpoint is relative, and it is guaranteed to
1099 ASSERT(m
->dir
[0] == '.');
1100 if (m
->dir
[0] == '.' && m
->dir
[1] == '\0') {
1102 * mounting on the trigger node
1109 * ignore "./" in front of mountpoint
1111 ASSERT(m
->dir
[1] == '/');
1112 mntpnt
= m
->dir
+ 2;
1114 AUTOFS_DPRINT((10, "\tdfnip->fi_path=%s\n", dfnip
->fi_path
));
1115 AUTOFS_DPRINT((10, "\tdfnip->fi_flags=%x\n", dfnip
->fi_flags
));
1116 AUTOFS_DPRINT((10, "\tmntpnt=%s\n", mntpnt
));
1118 if (dfnip
->fi_flags
& MF_DIRECT
) {
1119 AUTOFS_DPRINT((10, "\tDIRECT\n"));
1120 (void) sprintf(buff
, "%s/%s", dfnip
->fi_path
, mntpnt
);
1122 AUTOFS_DPRINT((10, "\tINDIRECT\n"));
1123 (void) sprintf(buff
, "%s/%s/%s",
1124 dfnip
->fi_path
, dfnp
->fn_name
, mntpnt
);
1127 if (vn_mountedvfs(dvp
) == NULL
) {
1129 * Daemon didn't mount anything on the root
1130 * We have to create the mountpoint if it
1131 * doesn't exist already
1133 * We use the caller's credentials in case a
1134 * UID-match is required
1135 * (MF_THISUID_MATCH_RQD).
1137 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
1138 error
= auto_search(dfnp
, mntpnt
, &mfnp
, cred
);
1141 * AUTOFS mountpoint exists
1143 if (vn_mountedvfs(fntovn(mfnp
)) != NULL
) {
1145 "auto_perform_actions:"
1146 " mfnp=%p covered", (void *)mfnp
);
1150 * Create AUTOFS mountpoint
1152 ASSERT((dfnp
->fn_flags
& MF_MOUNTPOINT
) == 0);
1153 error
= auto_enter(dfnp
, mntpnt
, &mfnp
, cred
);
1154 ASSERT(mfnp
->fn_linkcnt
== 1);
1159 rw_exit(&dfnp
->fn_rwlock
);
1160 ASSERT(error
!= EEXIST
);
1163 * mfnp is already held.
1167 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1168 CE_WARN
, "autofs: mount of %s "
1169 "failed - can't create"
1170 " mountpoint.", buff
);
1175 * Find mountpoint in VFS mounted here. If not
1176 * found, fail the submount, though the overall
1177 * mount has succeeded since the root is
1180 if (error
= auto_getmntpnt(dvp
, mntpnt
, &mvp
, kcred
)) {
1181 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1182 CE_WARN
, "autofs: mount of %s "
1183 "failed - mountpoint doesn't"
1187 if (mvp
->v_type
== VLNK
) {
1188 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1189 CE_WARN
, "autofs: %s symbolic "
1190 "link: not a valid mountpoint "
1191 "- mount failed", buff
);
1198 m
->flags
|= MS_SYSSPACE
| MS_OPTIONSTR
;
1201 * Copy mounta struct here so we can substitute a
1202 * buffer that is large enough to hold the returned
1203 * option string, if that string is longer than the
1204 * input option string.
1205 * This can happen if there are default options enabled
1206 * that were not in the input option string.
1208 bcopy(m
, &margs
, sizeof (*m
));
1209 margs
.optptr
= kmem_alloc(MAX_MNTOPT_STR
, KM_SLEEP
);
1210 margs
.optlen
= MAX_MNTOPT_STR
;
1211 (void) strcpy(margs
.optptr
, m
->optptr
);
1212 margs
.dir
= argsp
->path
;
1215 * We use the zone's kcred because we don't want the
1216 * zone to be able to thus do something it wouldn't
1217 * normally be able to.
1219 error
= domount(NULL
, &margs
, mvp
, zcred
, &vfsp
);
1220 kmem_free(margs
.optptr
, MAX_MNTOPT_STR
);
1222 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
1223 CE_WARN
, "autofs: domount of %s failed "
1224 "error=%d", buff
, error
);
1231 * If mountpoint is an AUTOFS node, then I'm going to
1232 * flag it that the Filesystem mounted on top was
1233 * mounted in the kernel so that the unmount can be
1234 * done inside the kernel as well.
1235 * I don't care to flag non-AUTOFS mountpoints when an
1236 * AUTOFS in-kernel mount was done on top, because the
1237 * unmount routine already knows that such case was
1238 * done in the kernel.
1240 if (vfs_matchops(dvp
->v_vfsp
, vfs_getops(mvp
->v_vfsp
))) {
1242 mutex_enter(&mfnp
->fn_lock
);
1243 mfnp
->fn_flags
|= MF_IK_MOUNT
;
1244 mutex_exit(&mfnp
->fn_lock
);
1247 (void) vn_vfswlock_wait(mvp
);
1248 mvfsp
= vn_mountedvfs(mvp
);
1249 if (mvfsp
!= NULL
) {
1250 vfs_lock_wait(mvfsp
);
1252 error
= VFS_ROOT(mvfsp
, &newvp
);
1256 * We've dropped the locks, so let's
1257 * get the mounted vfs again in case
1260 (void) vn_vfswlock_wait(mvp
);
1261 mvfsp
= vn_mountedvfs(mvp
);
1262 if (mvfsp
!= NULL
) {
1263 error
= dounmount(mvfsp
, 0, CRED());
1266 "autofs: could not unmount"
1267 " vfs=%p", (void *)mvfsp
);
1280 auto_mount
= vfs_matchops(dvp
->v_vfsp
,
1281 vfs_getops(newvp
->v_vfsp
));
1282 newfnp
= vntofn(newvp
);
1283 newfnp
->fn_parent
= dfnp
;
1286 * At this time we want to save the AUTOFS filesystem
1287 * as a trigger node. (We only do this if the mount
1288 * occurred on a node different from the root.
1289 * We look at the trigger nodes during
1290 * the automatic unmounting to make sure we remove them
1291 * as a unit and remount them as a unit if the
1292 * filesystem mounted at the root could not be
1295 if (auto_mount
&& (error
== 0) && (mvp
!= dvp
)) {
1298 * Add AUTOFS mount to hierarchy
1300 newfnp
->fn_flags
|= MF_TRIGGER
;
1301 rw_enter(&newfnp
->fn_rwlock
, RW_WRITER
);
1302 newfnp
->fn_next
= dfnp
->fn_trigger
;
1303 rw_exit(&newfnp
->fn_rwlock
);
1304 rw_enter(&dfnp
->fn_rwlock
, RW_WRITER
);
1305 dfnp
->fn_trigger
= newfnp
;
1306 rw_exit(&dfnp
->fn_rwlock
);
1308 * Don't VN_RELE(newvp) here since dfnp now
1309 * holds reference to it as its trigger node.
1311 AUTOFS_DPRINT((10, "\tadding trigger %s to %s\n",
1312 newfnp
->fn_name
, dfnp
->fn_name
));
1313 AUTOFS_DPRINT((10, "\tfirst trigger is %s\n",
1314 dfnp
->fn_trigger
->fn_name
));
1315 if (newfnp
->fn_next
!= NULL
)
1316 AUTOFS_DPRINT((10, "\tnext trigger is %s\n",
1317 newfnp
->fn_next
->fn_name
));
1319 AUTOFS_DPRINT((10, "\tno next trigger\n"));
1328 dfnp
->fn_atime
= dfnp
->fn_mtime
= now
;
1334 if (save_triggers
) {
1336 * Make sure the parent can't be freed while it has triggers.
1345 * Return failure if daemon didn't mount anything, and all
1346 * kernel mounts attempted failed.
1348 error
= success
? 0 : ENOENT
;
1351 if ((error
== 0) && save_triggers
) {
1353 * Save action_list information, so that we can use it
1354 * when it comes time to remount the trigger nodes
1355 * The action list is freed when the directory node
1356 * containing the reference to it is unmounted in
1359 mutex_enter(&dfnp
->fn_lock
);
1360 ASSERT(dfnp
->fn_alp
== NULL
);
1362 mutex_exit(&dfnp
->fn_lock
);
1365 * free the action list now,
1367 xdr_free(xdr_action_list
, (char *)alp
);
1370 AUTOFS_DPRINT((5, "auto_perform_actions: error=%d\n", error
));
1380 struct autofs_globals
*fngp
)
1387 * autofs uses odd inode numbers
1388 * automountd uses even inode numbers
1390 * To preserve the age-old semantics that inum+devid is unique across
1391 * the system, this variable must be global across zones.
1393 static ino_t nodeid
= 3;
1395 fnp
= kmem_zalloc(sizeof (*fnp
), KM_SLEEP
);
1396 fnp
->fn_vnode
= vn_alloc(KM_SLEEP
);
1399 tmpname
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
1400 (void) strcpy(tmpname
, name
);
1401 fnp
->fn_name
= &tmpname
[0];
1402 fnp
->fn_namelen
= (int)strlen(tmpname
) + 1; /* include '\0' */
1403 fnp
->fn_uid
= crgetuid(cred
);
1404 fnp
->fn_gid
= crgetgid(cred
);
1406 * ".." is added in auto_enter and auto_mount.
1407 * "." is added in auto_mkdir and auto_mount.
1410 * Note that fn_size and fn_linkcnt are already 0 since
1411 * we used kmem_zalloc to allocated fnp
1413 fnp
->fn_mode
= AUTOFS_MODE
;
1415 fnp
->fn_atime
= fnp
->fn_mtime
= fnp
->fn_ctime
= now
;
1416 fnp
->fn_ref_time
= now
.tv_sec
;
1417 mutex_enter(&autofs_nodeid_lock
);
1418 fnp
->fn_nodeid
= nodeid
;
1420 fnp
->fn_globals
= fngp
;
1421 fngp
->fng_fnnode_count
++;
1422 mutex_exit(&autofs_nodeid_lock
);
1423 vn_setops(vp
, &auto_vnodeops
);
1425 vp
->v_data
= (void *)fnp
;
1427 mutex_init(&fnp
->fn_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1428 rw_init(&fnp
->fn_rwlock
, NULL
, RW_DEFAULT
, NULL
);
1429 cv_init(&fnp
->fn_cv_mount
, NULL
, CV_DEFAULT
, NULL
);
1436 auto_freefnnode(fnnode_t
*fnp
)
1438 vnode_t
*vp
= fntovn(fnp
);
1440 AUTOFS_DPRINT((4, "auto_freefnnode: fnp=%p\n", (void *)fnp
));
1442 ASSERT(fnp
->fn_linkcnt
== 0);
1443 ASSERT(vp
->v_count
== 0);
1444 ASSERT(fnp
->fn_dirents
== NULL
);
1445 ASSERT(fnp
->fn_parent
== NULL
);
1448 kmem_free(fnp
->fn_name
, fnp
->fn_namelen
);
1449 if (fnp
->fn_symlink
) {
1450 ASSERT(fnp
->fn_flags
& MF_THISUID_MATCH_RQD
);
1451 kmem_free(fnp
->fn_symlink
, fnp
->fn_symlinklen
);
1454 crfree(fnp
->fn_cred
);
1455 mutex_destroy(&fnp
->fn_lock
);
1456 rw_destroy(&fnp
->fn_rwlock
);
1457 cv_destroy(&fnp
->fn_cv_mount
);
1460 mutex_enter(&autofs_nodeid_lock
);
1461 fnp
->fn_globals
->fng_fnnode_count
--;
1462 mutex_exit(&autofs_nodeid_lock
);
1463 kmem_free(fnp
, sizeof (*fnp
));
1471 fnnode_t
*tmp
, **fnpp
;
1472 vnode_t
*vp
= fntovn(fnp
);
1476 "auto_disconnect: dfnp=%p fnp=%p linkcnt=%d\n v_count=%d",
1477 (void *)dfnp
, (void *)fnp
, fnp
->fn_linkcnt
, vp
->v_count
));
1479 ASSERT(RW_WRITE_HELD(&dfnp
->fn_rwlock
));
1480 ASSERT(fnp
->fn_linkcnt
== 1);
1482 if (vn_mountedvfs(vp
) != NULL
) {
1483 cmn_err(CE_PANIC
, "auto_disconnect: vp %p mounted on",
1488 * Decrement by 1 because we're removing the entry in dfnp.
1494 * only changed while holding parent's (dfnp) rw_lock
1496 fnp
->fn_parent
= NULL
;
1498 fnpp
= &dfnp
->fn_dirents
;
1503 "auto_disconnect: %p not in %p dirent list",
1504 (void *)fnp
, (void *)dfnp
);
1507 *fnpp
= tmp
->fn_next
; /* remove it from the list */
1508 ASSERT(vp
->v_count
== 0);
1509 /* child had a pointer to parent ".." */
1514 fnpp
= &tmp
->fn_next
;
1517 mutex_enter(&fnp
->fn_lock
);
1519 fnp
->fn_atime
= fnp
->fn_mtime
= now
;
1520 mutex_exit(&fnp
->fn_lock
);
1522 AUTOFS_DPRINT((5, "auto_disconnect: done\n"));
1526 auto_enter(fnnode_t
*dfnp
, char *name
, fnnode_t
**fnpp
, cred_t
*cred
)
1528 struct fnnode
*cfnp
, **spp
;
1529 vnode_t
*dvp
= fntovn(dfnp
);
1530 ushort_t offset
= 0;
1533 AUTOFS_DPRINT((4, "auto_enter: dfnp=%p, name=%s ", (void *)dfnp
, name
));
1535 ASSERT(RW_WRITE_HELD(&dfnp
->fn_rwlock
));
1537 cfnp
= dfnp
->fn_dirents
;
1540 * offset = 0 for '.' and offset = 1 for '..'
1542 spp
= &dfnp
->fn_dirents
;
1546 for (; cfnp
; cfnp
= cfnp
->fn_next
) {
1547 if (strcmp(cfnp
->fn_name
, name
) == 0) {
1548 mutex_enter(&cfnp
->fn_lock
);
1549 if (cfnp
->fn_flags
& MF_THISUID_MATCH_RQD
) {
1551 * "thisuser" kind of node, need to
1552 * match CREDs as well
1554 mutex_exit(&cfnp
->fn_lock
);
1555 if (crcmp(cfnp
->fn_cred
, cred
) == 0)
1558 mutex_exit(&cfnp
->fn_lock
);
1563 if (cfnp
->fn_next
!= NULL
) {
1565 (cfnp
->fn_next
->fn_offset
- cfnp
->fn_offset
);
1567 if (diff
> 1 && offset
== 0) {
1568 offset
= (ushort_t
)cfnp
->fn_offset
+ 1;
1569 spp
= &cfnp
->fn_next
;
1571 } else if (offset
== 0) {
1572 offset
= (ushort_t
)cfnp
->fn_offset
+ 1;
1573 spp
= &cfnp
->fn_next
;
1577 *fnpp
= auto_makefnnode(VDIR
, dvp
->v_vfsp
, name
, cred
,
1583 * I don't hold the mutex on fnpp because I created it, and
1584 * I'm already holding the writers lock for it's parent
1585 * directory, therefore nobody can reference it without me first
1586 * releasing the writers lock.
1588 (*fnpp
)->fn_offset
= offset
;
1589 (*fnpp
)->fn_next
= *spp
;
1591 (*fnpp
)->fn_parent
= dfnp
;
1592 (*fnpp
)->fn_linkcnt
++; /* parent now holds reference to entry */
1596 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock
1598 dfnp
->fn_linkcnt
++; /* child now holds reference to parent '..' */
1601 dfnp
->fn_ref_time
= gethrestime_sec();
1603 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp
));
1608 auto_search(fnnode_t
*dfnp
, char *name
, fnnode_t
**fnpp
, cred_t
*cred
)
1612 int error
= ENOENT
, match
= 0;
1614 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n",
1615 (void *)dfnp
, name
));
1618 if (dvp
->v_type
!= VDIR
) {
1619 cmn_err(CE_PANIC
, "auto_search: dvp=%p not a directory",
1623 ASSERT(RW_LOCK_HELD(&dfnp
->fn_rwlock
));
1624 for (p
= dfnp
->fn_dirents
; p
!= NULL
; p
= p
->fn_next
) {
1625 if (strcmp(p
->fn_name
, name
) == 0) {
1626 mutex_enter(&p
->fn_lock
);
1627 if (p
->fn_flags
& MF_THISUID_MATCH_RQD
) {
1629 * "thisuser" kind of node
1630 * Need to match CREDs as well
1632 mutex_exit(&p
->fn_lock
);
1633 match
= crcmp(p
->fn_cred
, cred
) == 0;
1636 * No need to check CRED
1638 mutex_exit(&p
->fn_lock
);
1646 VN_HOLD(fntovn(*fnpp
));
1652 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error
));
1657 * If dvp is mounted on, get path's vnode in the mounted on
1658 * filesystem. Path is relative to dvp, ie "./path".
1659 * If successful, *mvp points to a the held mountpoint vnode.
1666 vnode_t
**mvpp
, /* vnode for mountpoint */
1671 char namebuf
[TYPICALMAXPATHLEN
];
1672 struct pathname lookpn
;
1675 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path
));
1677 if (error
= vn_vfsrlock_wait(dvp
))
1681 * Now that we have the vfswlock, check to see if dvp
1682 * is still mounted on. If not, then just bail out as
1683 * there is no need to remount the triggers since the
1684 * higher level mount point has gotten unmounted.
1686 vfsp
= vn_mountedvfs(dvp
);
1693 * Since mounted on, lookup "path" in the new filesystem,
1694 * it is important that we do the filesystem jump here to
1695 * avoid lookuppn() calling auto_lookup on dvp and deadlock.
1697 error
= VFS_ROOT(vfsp
, &newvp
);
1703 * We do a VN_HOLD on newvp just in case the first call to
1704 * lookuppnvp() fails with ENAMETOOLONG. We should still have a
1705 * reference to this vnode for the second call to lookuppnvp().
1710 * Now create the pathname struct so we can make use of lookuppnvp,
1711 * and pn_getcomponent.
1712 * This code is similar to lookupname() in fs/lookup.c.
1714 error
= pn_get_buf(path
, UIO_SYSSPACE
, &lookpn
,
1715 namebuf
, sizeof (namebuf
));
1717 error
= lookuppnvp(&lookpn
, NULL
, NO_FOLLOW
, NULLVPP
,
1718 mvpp
, rootdir
, newvp
, cred
);
1721 if (error
== ENAMETOOLONG
) {
1723 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
1724 * newvp is VN_RELE'd by this call to lookuppnvp.
1726 * Using 'rootdir' in a zone's context is OK here: we already
1727 * ascertained that there are no '..'s in the path, and we're
1728 * not following symlinks.
1730 if ((error
= pn_get(path
, UIO_SYSSPACE
, &lookpn
)) == 0) {
1731 error
= lookuppnvp(&lookpn
, NULL
, NO_FOLLOW
, NULLVPP
,
1732 mvpp
, rootdir
, newvp
, cred
);
1738 * Need to release newvp here since we held it.
1744 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n",
1745 path
, (void *)*mvpp
, error
));
1749 #define DEEPER(x) (((x)->fn_dirents != NULL) || \
1750 (vn_mountedvfs(fntovn((x)))) != NULL)
1753 * The caller, should have already VN_RELE'd its reference to the
1754 * root vnode of this filesystem.
1757 auto_inkernel_unmount(vfs_t
*vfsp
)
1759 vnode_t
*cvp
= vfsp
->vfs_vnodecovered
;
1763 "auto_inkernel_unmount: devid=%lx mntpnt(%p) count %u\n",
1764 vfsp
->vfs_dev
, (void *)cvp
, cvp
->v_count
));
1766 ASSERT(vn_vfswlock_held(cvp
));
1769 * Perform the unmount
1770 * The mountpoint has already been locked by the caller.
1772 error
= dounmount(vfsp
, 0, kcred
);
1774 AUTOFS_DPRINT((5, "auto_inkernel_unmount: exit count %u\n",
1780 * unmounts trigger nodes in the kernel.
1783 unmount_triggers(fnnode_t
*fnp
, action_list
**alp
)
1785 fnnode_t
*tp
, *next
;
1790 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp
));
1791 ASSERT(RW_WRITE_HELD(&fnp
->fn_rwlock
));
1794 next
= fnp
->fn_trigger
;
1795 while ((tp
= next
) != NULL
) {
1797 ASSERT(tvp
->v_count
>= 2);
1800 * drop writer's lock since the unmount will end up
1801 * disconnecting this node from fnp and needs to acquire
1802 * the writer's lock again.
1803 * next has at least a reference count >= 2 since it's
1804 * a trigger node, therefore can not be accidentally freed
1807 rw_exit(&fnp
->fn_rwlock
);
1812 * Its parent was holding a reference to it, since this
1813 * is a trigger vnode.
1816 if (error
= auto_inkernel_unmount(vfsp
)) {
1817 cmn_err(CE_PANIC
, "unmount_triggers: "
1818 "unmount of vp=%p failed error=%d",
1819 (void *)tvp
, error
);
1822 * reacquire writer's lock
1824 rw_enter(&fnp
->fn_rwlock
, RW_WRITER
);
1828 * We were holding a reference to our parent. Drop that.
1830 VN_RELE(fntovn(fnp
));
1831 fnp
->fn_trigger
= NULL
;
1834 AUTOFS_DPRINT((5, "unmount_triggers: finished\n"));
1838 * This routine locks the mountpoint of every trigger node if they're
1839 * not busy, or returns EBUSY if any node is busy.
1842 triggers_busy(fnnode_t
*fnp
)
1849 ASSERT(RW_WRITE_HELD(&fnp
->fn_rwlock
));
1851 for (tp
= fnp
->fn_trigger
; tp
!= NULL
; tp
= tp
->fn_next
) {
1852 AUTOFS_DPRINT((10, "\ttrigger: %s\n", tp
->fn_name
));
1853 /* MF_LOOKUP should never be set on trigger nodes */
1854 ASSERT((tp
->fn_flags
& MF_LOOKUP
) == 0);
1855 vfsp
= fntovn(tp
)->v_vfsp
;
1858 * The vn_vfsunlock will be done in auto_inkernel_unmount.
1860 lck_error
= vn_vfswlock(vfsp
->vfs_vnodecovered
);
1862 if (lck_error
!= 0 || (tp
->fn_flags
& MF_INPROG
) ||
1863 DEEPER(tp
) || ((fntovn(tp
))->v_count
) > 2) {
1865 * couldn't lock it because it's busy,
1866 * It is mounted on or has dirents?
1867 * If reference count is greater than two, then
1868 * somebody else is holding a reference to this vnode.
1869 * One reference is for the mountpoint, and the second
1870 * is for the trigger node.
1872 AUTOFS_DPRINT((10, "\ttrigger busy\n"));
1875 * Unlock previously locked mountpoints
1877 for (done
= 0, t1p
= fnp
->fn_trigger
; !done
;
1878 t1p
= t1p
->fn_next
) {
1880 * Unlock all nodes previously
1881 * locked. All nodes up to 'tp'
1882 * were successfully locked. If 'lck_err' is
1883 * set, then 'tp' was not locked, and thus
1884 * should not be unlocked. If
1885 * 'lck_err' is not set, then 'tp' was
1886 * successfully locked, and it should
1889 if (t1p
!= tp
|| !lck_error
) {
1890 vfsp
= fntovn(t1p
)->v_vfsp
;
1891 vn_vfsunlock(vfsp
->vfs_vnodecovered
);
1903 * It is the caller's responsibility to grab the VVFSLOCK.
1904 * Releases the VVFSLOCK upon return.
1907 unmount_node(vnode_t
*cvp
, int force
)
1915 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp
));
1917 ASSERT(vn_vfswlock_held(cvp
));
1919 vfsp
= vn_mountedvfs(cvp
);
1921 if (force
|| cfnp
->fn_flags
& MF_IK_MOUNT
) {
1923 * Mount was performed in the kernel, so
1924 * do an in-kernel unmount. auto_inkernel_unmount()
1925 * will vn_vfsunlock(cvp).
1927 error
= auto_inkernel_unmount(vfsp
);
1929 zone_t
*zone
= NULL
;
1930 refstr_t
*mntpt
, *resource
;
1934 * Get the mnttab information of the node
1935 * and ask the daemon to unmount it.
1937 bzero(&ul
, sizeof (ul
));
1938 mntfs_getmntopts(vfsp
, &ul
.mntopts
, &mntoptslen
);
1939 if (ul
.mntopts
== NULL
) {
1940 auto_log(cfnp
->fn_globals
->fng_verbose
,
1941 cfnp
->fn_globals
->fng_zoneid
, CE_WARN
,
1942 "unmount_node: no memory");
1947 if (mntoptslen
> AUTOFS_MAXOPTSLEN
)
1948 ul
.mntopts
[AUTOFS_MAXOPTSLEN
- 1] = '\0';
1950 mntpt
= vfs_getmntpoint(vfsp
);
1951 ul
.mntpnt
= (char *)refstr_value(mntpt
);
1952 resource
= vfs_getresource(vfsp
);
1953 ul
.mntresource
= (char *)refstr_value(resource
);
1955 fnip
= vfstofni(cvp
->v_vfsp
);
1956 ul
.isdirect
= fnip
->fi_flags
& MF_DIRECT
? TRUE
: FALSE
;
1959 * Since a zone'd automountd's view of the autofs mount points
1960 * differs from those in the kernel, we need to make sure we
1961 * give it consistent mount points.
1963 ASSERT(fnip
->fi_zoneid
== getzoneid());
1964 zone
= curproc
->p_zone
;
1966 if (fnip
->fi_zoneid
!= GLOBAL_ZONEID
) {
1967 if (ZONE_PATH_VISIBLE(ul
.mntpnt
, zone
)) {
1969 ZONE_PATH_TRANSLATE(ul
.mntpnt
, zone
);
1971 if (ZONE_PATH_VISIBLE(ul
.mntresource
, zone
)) {
1973 ZONE_PATH_TRANSLATE(ul
.mntresource
, zone
);
1977 ul
.fstype
= vfssw
[vfsp
->vfs_fstype
].vsw_name
;
1980 error
= auto_send_unmount_request(fnip
, &ul
, FALSE
);
1981 kmem_free(ul
.mntopts
, mntoptslen
);
1983 refstr_rele(resource
);
1987 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp
,
1993 * return EBUSY if any thread is holding a reference to this vnode
1994 * other than us. Result of this function cannot be relied on, since
1995 * it doesn't follow proper locking rules (i.e. vp->v_vfsmountedhere
1996 * and fnp->fn_trigger can change throughout this function). However
1997 * it's good enough for rough estimation.
2000 check_auto_node(vnode_t
*vp
)
2005 * number of references to expect for
2010 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp
));
2013 count
= 1; /* we are holding a reference to vp */
2014 if (fnp
->fn_flags
& MF_TRIGGER
) {
2016 * parent holds a pointer to us (trigger)
2020 if (fnp
->fn_trigger
!= NULL
) {
2022 * The trigger nodes have a hold on us.
2026 if (vn_ismntpt(vp
)) {
2028 * File system is mounted on us.
2032 mutex_enter(&vp
->v_lock
);
2033 ASSERT(vp
->v_count
> 0);
2034 if (vp
->v_flag
& VROOT
)
2036 AUTOFS_DPRINT((10, "\tcount=%u ", vp
->v_count
));
2037 if (vp
->v_count
> count
)
2039 mutex_exit(&vp
->v_lock
);
2041 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error
));
2046 * rootvp is the root of the AUTOFS filesystem.
2047 * If rootvp is busy (v_count > 1) returns EBUSY.
2048 * else removes every vnode under this tree.
2049 * ASSUMPTION: Assumes that the only node which can be busy is
2050 * the root vnode. This filesystem better be two levels deep only,
2051 * the root and its immediate subdirs.
2052 * The daemon will "AUTOFS direct-mount" only one level below the root.
2055 unmount_autofs(vnode_t
*rootvp
)
2057 fnnode_t
*fnp
, *rootfnp
, *nfnp
;
2059 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp
));
2062 * Remove all its immediate subdirectories.
2064 rootfnp
= vntofn(rootvp
);
2065 rw_enter(&rootfnp
->fn_rwlock
, RW_WRITER
);
2066 for (fnp
= rootfnp
->fn_dirents
; fnp
!= NULL
; fnp
= nfnp
) {
2067 ASSERT(fntovn(fnp
)->v_count
== 0);
2068 ASSERT(fnp
->fn_dirents
== NULL
);
2069 ASSERT(fnp
->fn_linkcnt
== 2);
2071 auto_disconnect(rootfnp
, fnp
);
2072 nfnp
= fnp
->fn_next
;
2073 auto_freefnnode(fnp
);
2075 rw_exit(&rootfnp
->fn_rwlock
);
2079 * If a node matches all unmount criteria, do:
2080 * destroy subordinate trigger node(s) if there is any
2081 * unmount filesystem mounted on top of the node if there is any
2083 * Function should be called with locked fnp's mutex. The mutex is
2084 * unlocked before return from function.
2087 try_unmount_node(fnnode_t
*fnp
, boolean_t force
)
2089 boolean_t trigger_unmount
= B_FALSE
;
2090 action_list
*alp
= NULL
;
2095 struct autofs_globals
*fngp
;
2097 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n",
2100 ASSERT(MUTEX_HELD(&fnp
->fn_lock
));
2102 fngp
= fnp
->fn_globals
;
2104 fnip
= vfstofni(vp
->v_vfsp
);
2107 * If either a mount, lookup or another unmount of this subtree is in
2108 * progress, don't attempt to unmount at this time.
2110 if (fnp
->fn_flags
& (MF_INPROG
| MF_LOOKUP
)) {
2111 mutex_exit(&fnp
->fn_lock
);
2116 * Bail out if someone else is holding reference to this vnode.
2117 * This check isn't just an optimization (someone is probably
2118 * just about to trigger mount). It is necessary to prevent a deadlock
2119 * in domount() called from auto_perform_actions() if unmount of
2120 * trigger parent fails. domount() calls lookupname() to resolve
2121 * special in mount arguments. Special is set to a map name in case
2122 * of autofs triggers (i.e. auto_ws.sun.com). Thus if current
2123 * working directory is set to currently processed node, lookupname()
2124 * calls into autofs vnops in order to resolve special, which deadlocks
2127 * Note: This should be fixed. Autofs shouldn't pass the map name
2128 * in special and avoid useless lookup with potentially disasterous
2131 if (check_auto_node(vp
) == EBUSY
) {
2132 mutex_exit(&fnp
->fn_lock
);
2137 * If not forced operation, back out if node has been referenced
2141 fnp
->fn_ref_time
+ fnip
->fi_mount_to
> gethrestime_sec()) {
2142 mutex_exit(&fnp
->fn_lock
);
2146 /* block mounts/unmounts on the node */
2147 AUTOFS_BLOCK_OTHERS(fnp
, MF_INPROG
);
2149 mutex_exit(&fnp
->fn_lock
);
2151 /* unmount next level triggers if there are any */
2152 rw_enter(&fnp
->fn_rwlock
, RW_WRITER
);
2153 if (fnp
->fn_trigger
!= NULL
) {
2154 trigger_unmount
= B_TRUE
;
2156 if (triggers_busy(fnp
)) {
2157 rw_exit(&fnp
->fn_rwlock
);
2158 mutex_enter(&fnp
->fn_lock
);
2159 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
2160 mutex_exit(&fnp
->fn_lock
);
2165 * At this point, we know all trigger nodes are locked,
2166 * and they're not busy or mounted on.
2168 * Attempt to unmount all trigger nodes, save the
2169 * action_list in case we need to remount them later.
2170 * The action_list will be freed later if there was no
2171 * need to remount the trigger nodes.
2173 unmount_triggers(fnp
, &alp
);
2175 rw_exit(&fnp
->fn_rwlock
);
2177 (void) vn_vfswlock_wait(vp
);
2179 vfsp
= vn_mountedvfs(vp
);
2181 /* vn_vfsunlock(vp) is done inside unmount_node() */
2182 error
= unmount_node(vp
, force
);
2183 if (error
== ECONNRESET
) {
2184 if (vn_mountedvfs(vp
) == NULL
) {
2186 * The filesystem was unmounted before the
2187 * daemon died. Unfortunately we can not
2188 * determine whether all the cleanup work was
2189 * successfully finished (i.e. update mnttab,
2190 * or notify NFS server of the unmount).
2191 * We should not retry the operation since the
2192 * filesystem has already been unmounted, and
2193 * may have already been removed from mnttab,
2194 * in such case the devid/rdevid we send to
2195 * the daemon will not be matched. So we have
2196 * to be content with the partial unmount.
2197 * Since the mountpoint is no longer covered, we
2198 * clear the error condition.
2201 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
2202 CE_WARN
, "autofs: automountd "
2203 "connection dropped when unmounting %s/%s",
2204 fnip
->fi_path
, (fnip
->fi_flags
& MF_DIRECT
)
2205 ? "" : fnp
->fn_name
);
2210 /* Destroy all dirents of fnp if we unmounted its triggers */
2211 if (trigger_unmount
)
2215 /* If unmount failed, we got to remount triggers */
2217 if (trigger_unmount
) {
2220 ASSERT((fnp
->fn_flags
& MF_THISUID_MATCH_RQD
) == 0);
2223 * The action list was free'd by auto_perform_actions
2225 ret
= auto_perform_actions(fnip
, fnp
, alp
, CRED());
2227 auto_log(fngp
->fng_verbose
, fngp
->fng_zoneid
,
2228 CE_WARN
, "autofs: can't remount triggers "
2229 "fnp=%p error=%d", (void *)fnp
, ret
);
2232 mutex_enter(&fnp
->fn_lock
);
2233 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
2234 mutex_exit(&fnp
->fn_lock
);
2236 /* Free the action list here */
2237 if (trigger_unmount
)
2238 xdr_free(xdr_action_list
, (char *)alp
);
2241 * Other threads may be waiting for this unmount to
2242 * finish. We must let it know that in order to
2243 * proceed, it must trigger the mount itself.
2245 mutex_enter(&fnp
->fn_lock
);
2246 fnp
->fn_flags
&= ~MF_IK_MOUNT
;
2247 if (fnp
->fn_flags
& MF_WAITING
)
2248 fnp
->fn_error
= EAGAIN
;
2249 AUTOFS_UNBLOCK_OTHERS(fnp
, MF_INPROG
);
2250 mutex_exit(&fnp
->fn_lock
);
2257 * This is an implementation of depth-first search in a tree rooted by
2258 * start_fnp and composed from fnnodes. Links between tree levels are
2259 * fn_dirents, fn_trigger in fnnode_t and v_mountedvfs in vnode_t (if
2260 * mounted vfs is autofs). The algorithm keeps track of visited nodes
2261 * by means of a timestamp (fn_unmount_ref_time).
2263 * Upon top-down traversal of the tree we apply following locking scheme:
2264 * lock fn_rwlock of current node
2265 * grab reference to child's vnode (VN_HOLD)
2267 * free reference to current vnode (VN_RELE)
2268 * Similar locking scheme is used for down-top and left-right traversal.
2270 * Algorithm examines the most down-left node in tree, which hasn't been
2271 * visited yet. From this follows that nodes are processed in bottom-up
2274 * Function returns either zero if unmount of root node was successful
2275 * or error code (mostly EBUSY).
2278 unmount_subtree(fnnode_t
*rootfnp
, boolean_t force
)
2280 fnnode_t
*currfnp
; /* currently examined node in the tree */
2281 fnnode_t
*lastfnp
; /* previously processed node */
2282 fnnode_t
*nextfnp
; /* next examined node in the tree */
2288 ASSERT(fntovn(rootfnp
)->v_type
!= VLNK
);
2289 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp
,
2293 * Timestamp, which visited nodes are marked with, to distinguish them
2294 * from unvisited nodes.
2296 timestamp
= gethrestime_sec();
2297 currfnp
= lastfnp
= rootfnp
;
2299 /* Loop until we examine all nodes in the tree */
2300 mutex_enter(&currfnp
->fn_lock
);
2301 while (currfnp
!= rootfnp
|| rootfnp
->fn_unmount_ref_time
< timestamp
) {
2302 curvp
= fntovn(currfnp
);
2303 AUTOFS_DPRINT((10, "\tunmount_subtree: entering node %p (%s)\n",
2304 (void *)currfnp
, currfnp
->fn_name
));
2307 * New candidate for processing must have been already visited,
2308 * by us because we want to process tree nodes in bottom-up
2311 if (currfnp
->fn_unmount_ref_time
== timestamp
&&
2312 currfnp
!= lastfnp
) {
2313 (void) try_unmount_node(currfnp
, force
);
2315 mutex_enter(&currfnp
->fn_lock
);
2317 * Fall through to next if-branch to pick
2318 * sibling or parent of this node.
2323 * If this node has been already visited, it means that it's
2324 * dead end and we need to pick sibling or parent as next node.
2326 if (currfnp
->fn_unmount_ref_time
>= timestamp
||
2327 curvp
->v_type
== VLNK
) {
2328 mutex_exit(&currfnp
->fn_lock
);
2330 * Obtain parent's readers lock before grabbing
2331 * reference to sibling.
2333 rw_enter(&currfnp
->fn_parent
->fn_rwlock
, RW_READER
);
2334 if ((nextfnp
= currfnp
->fn_next
) != NULL
) {
2335 VN_HOLD(fntovn(nextfnp
));
2336 rw_exit(&currfnp
->fn_parent
->fn_rwlock
);
2339 mutex_enter(&currfnp
->fn_lock
);
2342 rw_exit(&currfnp
->fn_parent
->fn_rwlock
);
2345 * All descendants and siblings were visited. Perform
2348 nextfnp
= currfnp
->fn_parent
;
2349 VN_HOLD(fntovn(nextfnp
));
2352 mutex_enter(&currfnp
->fn_lock
);
2357 * Mark node as visited. Note that the timestamp could have
2358 * been updated by somebody else in the meantime.
2360 if (currfnp
->fn_unmount_ref_time
< timestamp
)
2361 currfnp
->fn_unmount_ref_time
= timestamp
;
2364 * Don't descent below nodes, which are being unmounted/mounted.
2366 * We need to hold both locks at once: fn_lock because we need
2367 * to read MF_INPROG and fn_rwlock to prevent anybody from
2368 * modifying fn_trigger until its used to traverse triggers
2371 * Acquire fn_rwlock in non-blocking mode to avoid deadlock.
2372 * If it can't be acquired, then acquire locks in correct
2375 if (!rw_tryenter(&currfnp
->fn_rwlock
, RW_READER
)) {
2376 mutex_exit(&currfnp
->fn_lock
);
2377 rw_enter(&currfnp
->fn_rwlock
, RW_READER
);
2378 mutex_enter(&currfnp
->fn_lock
);
2380 if (currfnp
->fn_flags
& MF_INPROG
) {
2381 rw_exit(&currfnp
->fn_rwlock
);
2384 mutex_exit(&currfnp
->fn_lock
);
2387 * Examine descendants in this order: triggers, dirents, autofs
2391 if ((nextfnp
= currfnp
->fn_trigger
) != NULL
) {
2392 VN_HOLD(fntovn(nextfnp
));
2393 rw_exit(&currfnp
->fn_rwlock
);
2396 mutex_enter(&currfnp
->fn_lock
);
2400 if ((nextfnp
= currfnp
->fn_dirents
) != NULL
) {
2401 VN_HOLD(fntovn(nextfnp
));
2402 rw_exit(&currfnp
->fn_rwlock
);
2405 mutex_enter(&currfnp
->fn_lock
);
2408 rw_exit(&currfnp
->fn_rwlock
);
2410 (void) vn_vfswlock_wait(curvp
);
2411 vfsp
= vn_mountedvfs(curvp
);
2413 vfs_matchops(vfsp
, vfs_getops(curvp
->v_vfsp
))) {
2415 * Deal with /xfn/host/jurassic alikes here...
2417 * We know this call to VFS_ROOT is safe to call while
2418 * holding VVFSLOCK, since it resolves to a call to
2421 if (VFS_ROOT(vfsp
, &newvp
)) {
2423 "autofs: VFS_ROOT(vfs=%p) failed",
2426 vn_vfsunlock(curvp
);
2428 currfnp
= vntofn(newvp
);
2429 mutex_enter(&currfnp
->fn_lock
);
2432 vn_vfsunlock(curvp
);
2433 mutex_enter(&currfnp
->fn_lock
);
2437 * Now we deal with the root node (currfnp's mutex is unlocked
2438 * in try_unmount_node()).
2440 return (try_unmount_node(currfnp
, force
));
2444 * XXX unmount_tree() is not suspend-safe within the scope of
2445 * the present model defined for cpr to suspend the system. Calls made
2446 * by the unmount_tree() that have been identified to be unsafe are
2447 * (1) RPC client handle setup and client calls to automountd which can
2448 * block deep down in the RPC library, (2) kmem_alloc() calls with the
2449 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*() and
2450 * VOP_*() calls which can result in over the wire calls to servers.
2451 * The thread should be completely reevaluated to make it suspend-safe in
2452 * case of future updates to the cpr model.
2455 unmount_tree(struct autofs_globals
*fngp
, boolean_t force
)
2457 callb_cpr_t cprinfo
;
2458 kmutex_t unmount_tree_cpr_lock
;
2459 fnnode_t
*root
, *fnp
, *next
;
2461 mutex_init(&unmount_tree_cpr_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
2462 CALLB_CPR_INIT(&cprinfo
, &unmount_tree_cpr_lock
, callb_generic_cpr
,
2466 * autofssys() will be calling in from the global zone and doing
2467 * work on the behalf of the given zone, hence we can't always
2468 * assert that we have the right credentials, nor that the
2469 * caller is always in the correct zone.
2471 * We do, however, know that if this is a "forced unmount"
2472 * operation (which autofssys() does), then we won't go down to
2473 * the krpc layers, so we don't need to fudge with the
2476 ASSERT(force
|| fngp
->fng_zoneid
== getzoneid());
2479 * If automountd is not running in this zone,
2480 * don't attempt unmounting this round.
2482 if (force
|| auto_null_request(fngp
->fng_zoneid
, FALSE
) == 0) {
2484 * Iterate over top level autofs filesystems and call
2485 * unmount_subtree() for each of them.
2487 root
= fngp
->fng_rootfnnodep
;
2488 rw_enter(&root
->fn_rwlock
, RW_READER
);
2489 for (fnp
= root
->fn_dirents
; fnp
!= NULL
; fnp
= next
) {
2490 VN_HOLD(fntovn(fnp
));
2491 rw_exit(&root
->fn_rwlock
);
2492 (void) unmount_subtree(fnp
, force
);
2493 rw_enter(&root
->fn_rwlock
, RW_READER
);
2494 next
= fnp
->fn_next
;
2495 VN_RELE(fntovn(fnp
));
2497 rw_exit(&root
->fn_rwlock
);
2500 mutex_enter(&unmount_tree_cpr_lock
);
2501 CALLB_CPR_EXIT(&cprinfo
);
2502 mutex_destroy(&unmount_tree_cpr_lock
);
2506 unmount_zone_tree(struct autofs_globals
*fngp
)
2508 AUTOFS_DPRINT((5, "unmount_zone_tree started. Thread created.\n"));
2510 unmount_tree(fngp
, B_FALSE
);
2511 mutex_enter(&fngp
->fng_unmount_threads_lock
);
2512 fngp
->fng_unmount_threads
--;
2513 mutex_exit(&fngp
->fng_unmount_threads_lock
);
2515 AUTOFS_DPRINT((5, "unmount_zone_tree done. Thread exiting.\n"));
2522 auto_do_unmount(struct autofs_globals
*fngp
)
2524 callb_cpr_t cprinfo
;
2526 zone_t
*zone
= curproc
->p_zone
;
2528 CALLB_CPR_INIT(&cprinfo
, &fngp
->fng_unmount_threads_lock
,
2529 callb_generic_cpr
, "auto_do_unmount");
2531 for (;;) { /* forever */
2532 mutex_enter(&fngp
->fng_unmount_threads_lock
);
2533 CALLB_CPR_SAFE_BEGIN(&cprinfo
);
2535 mutex_exit(&fngp
->fng_unmount_threads_lock
);
2536 timeleft
= zone_status_timedwait(zone
, ddi_get_lbolt() +
2537 autofs_unmount_thread_timer
* hz
, ZONE_IS_SHUTTING_DOWN
);
2538 mutex_enter(&fngp
->fng_unmount_threads_lock
);
2540 if (timeleft
!= -1) { /* didn't time out */
2541 ASSERT(zone_status_get(zone
) >= ZONE_IS_SHUTTING_DOWN
);
2543 * zone is exiting... don't create any new threads.
2544 * fng_unmount_threads_lock is released implicitly by
2547 CALLB_CPR_SAFE_END(&cprinfo
,
2548 &fngp
->fng_unmount_threads_lock
);
2549 CALLB_CPR_EXIT(&cprinfo
);
2553 if (fngp
->fng_unmount_threads
< autofs_unmount_threads
) {
2554 fngp
->fng_unmount_threads
++;
2555 CALLB_CPR_SAFE_END(&cprinfo
,
2556 &fngp
->fng_unmount_threads_lock
);
2557 mutex_exit(&fngp
->fng_unmount_threads_lock
);
2559 (void) zthread_create(NULL
, 0, unmount_zone_tree
, fngp
,
2568 * Is nobrowse specified in option string?
2569 * opts should be a null ('\0') terminated string.
2570 * Returns non-zero if nobrowse has been specified.
2573 auto_nobrowse_option(char *opts
)
2582 len
= strlen(opts
) + 1;
2583 p
= buf
= kmem_alloc(len
, KM_SLEEP
);
2584 (void) strcpy(buf
, opts
);
2586 if (t
= strchr(p
, ','))
2590 if (strcmp(p
, MNTOPT_NOBROWSE
) == 0)
2592 else if (strcmp(p
, MNTOPT_BROWSE
) == 0)
2595 } while (!last_opt
);
2596 kmem_free(buf
, len
);
2602 * used to log warnings only if automountd is running
2603 * with verbose mode set
2607 auto_log(int verbose
, zoneid_t zoneid
, int level
, const char *fmt
, ...)
2612 va_start(args
, fmt
);
2613 vzcmn_err(zoneid
, level
, fmt
, args
);
2619 static int autofs_debug
= 0;
2622 * Utilities used by both client and server
2627 * 3) current test software
2628 * 4) main procedure entry points
2629 * 5) main procedure exit points
2630 * 6) utility procedure entry points
2631 * 7) utility procedure exit points
2632 * 8) obscure procedure entry points
2633 * 9) obscure procedure exit points
2642 auto_dprint(int level
, const char *fmt
, ...)
2646 if (autofs_debug
== level
||
2647 (autofs_debug
> 10 && (autofs_debug
- 10) >= level
)) {
2648 va_start(args
, fmt
);
2649 (void) vprintf(fmt
, args
);