uts: make emu10k non-verbose
[unleashed.git] / kernel / fs / autofs / auto_subr.c
blobbbf2c4764fcd9aed4ddac23fb58be72bf28dd36c
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/param.h>
27 #include <sys/kmem.h>
28 #include <sys/errno.h>
29 #include <sys/proc.h>
30 #include <sys/disp.h>
31 #include <sys/vfs.h>
32 #include <sys/vnode.h>
33 #include <sys/pathname.h>
34 #include <sys/cred.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>
44 #include <sys/zone.h>
45 #include <sys/door.h>
46 #include <sys/fs/mntdata.h>
47 #include <nfs/mount.h>
48 #include <rpc/clnt.h>
49 #include <rpcsvc/autofs_prot.h>
50 #include <nfs/rnode.h>
51 #include <sys/utsname.h>
52 #include <sys/schedctl.h>
55 * Autofs and Zones:
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
61 * zone's automountd.
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
67 * zthread_create()).
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 *,
92 bool_t);
95 * Clears the MF_INPROG flag, and wakes up those threads sleeping on
96 * fn_cv_mount if MF_WAITING is set.
98 void
99 auto_unblock_others(
100 fnnode_t *fnp,
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)
114 int error;
115 k_sigset_t smask;
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;
125 sigintr(&smask, 1);
126 if (!cv_wait_sig(&fnp->fn_cv_mount, &fnp->fn_lock)) {
128 * Decided not to wait for operation to
129 * finish after all.
131 sigunintr(&smask);
132 mutex_exit(&fnp->fn_lock);
133 return (EINTR);
135 sigunintr(&smask);
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.
144 error = EAGAIN;
146 mutex_exit(&fnp->fn_lock);
148 AUTOFS_DPRINT((5, "auto_wait4mount: fnp=%p error=%d\n", (void *)fnp,
149 error));
150 return (error);
154 auto_lookup_aux(fnnode_t *fnp, char *name, cred_t *cred)
156 struct fninfo *fnip;
157 struct linka link;
158 bool_t mountreq = FALSE;
159 int error = 0;
161 fnip = vfstofni(fntovn(fnp)->v_vfsp);
162 bzero(&link, sizeof (link));
163 error = auto_lookup_request(fnip, name, &link, TRUE, &mountreq, cred);
164 if (!error) {
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);
179 fnp->fn_error = 0;
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)
206 error = ENOENT;
210 if (link.link)
211 kmem_free(link.link, strlen(link.link) + 1);
212 if (link.dir)
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
219 * it's done.
221 if (mountreq) {
222 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
223 } else {
224 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
226 mutex_exit(&fnp->fn_lock);
227 return (error);
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.
242 static void
243 auto_mount_thread(struct autofs_callargs *argsp)
245 struct fninfo *fnip;
246 fnnode_t *fnp;
247 vnode_t *vp;
248 char *name;
249 size_t namelen;
250 cred_t *cred;
251 action_list *alp = NULL;
252 int error;
253 callb_cpr_t cprinfo;
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;
261 vp = fntovn(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);
268 if (!error)
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
275 * it's done.
277 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
278 mutex_exit(&fnp->fn_lock);
280 VN_RELE(vp);
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);
289 zthread_exit();
290 /* NOTREACHED */
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'.
299 void
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;
310 crhold(cred);
311 argsp->fnc_cred = cred;
313 (void) zthread_create(NULL, 0, auto_mount_thread, argsp, 0,
314 minclsyspri);
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;
323 /*ARGSUSED*/
325 auto_calldaemon(
326 zoneid_t zoneid,
327 int which,
328 xdrproc_t xarg_func,
329 void *argsp,
330 xdrproc_t xresp_func,
331 void *resp,
332 int reslen,
333 bool_t hard) /* retry forever? */
335 int retry;
336 int error = 0;
337 k_sigset_t smask;
338 door_arg_t door_args;
339 door_handle_t dh;
340 XDR xdrarg;
341 XDR xdrres;
342 struct autofs_globals *fngp = NULL;
343 void *orp = NULL;
344 int orl;
345 int rlen = 0; /* MUST be initialized */
346 autofs_door_args_t *xdr_argsp;
347 int xdr_len = 0;
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
354 * curproc->p_zone.
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
361 * waiting for us.
363 return (ECONNREFUSED);
366 do {
367 retry = 0;
368 mutex_enter(&autofs_minor_lock);
369 fngp = zone_getspecific(autofs_key, curproc->p_zone);
370 mutex_exit(&autofs_minor_lock);
371 if (fngp == NULL) {
372 if (hard) {
373 AUTOFS_DPRINT((5,
374 "auto_calldaemon: "\
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");
381 delay(hz);
382 retry = 1;
383 } else {
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
388 * handle.
390 return (ECONNREFUSED);
393 } while (retry);
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)
402 return (EINVAL);
403 xdr_argsp = kmem_zalloc(xdr_len + sizeof (*xdr_argsp), KM_SLEEP);
404 xdr_argsp->xdr_len = xdr_len;
405 xdr_argsp->cmd = which;
407 if (argsp) {
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));
413 return (EINVAL);
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
424 * for that buffer.
426 if (resp)
427 rlen = xdr_sizeof(xresp_func, resp);
428 orl = (rlen == 0) ? doorbuf_defsz : MAX(rlen, doorbuf_defsz);
429 orp = kmem_zalloc(orl, KM_SLEEP);
431 do {
432 retry = 0;
433 mutex_enter(&fngp->fng_autofs_daemon_lock);
434 dh = fngp->fng_autofs_daemon_dh;
435 if (dh)
436 door_ki_hold(dh);
437 mutex_exit(&fngp->fng_autofs_daemon_lock);
439 if (dh == NULL) {
440 if (orp)
441 kmem_free(orp, orl);
442 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
443 return (ENOENT);
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;
452 sigintr(&smask, 1);
453 error =
454 door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
455 sigunintr(&smask);
457 door_ki_rele(dh);
460 * Handle daemon errors
462 if (!error) {
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
467 * the caller.
469 autofs_door_res_t *adr =
470 (autofs_door_res_t *)door_args.rbuf;
472 if (door_args.rbuf != NULL) {
473 int nl;
475 switch (error = adr->res_status) {
476 case 0: /* no error; continue */
477 break;
479 case EOVERFLOW:
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)) {
486 if (orp)
487 kmem_free(orp, orl);
488 orp = kmem_zalloc(nl, KM_SLEEP);
489 orl = nl;
490 retry = 1;
491 break;
493 /*FALLTHROUGH*/
495 default:
496 kmem_free(xdr_argsp,
497 xdr_len + sizeof (*xdr_argsp));
498 if (orp)
499 kmem_free(orp, orl);
500 return (error);
503 continue;
507 * no daemon errors; now process door/comm errors (if any)
509 switch (error) {
510 case EINTR:
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) ||
519 lwp->lwp_sysabort ||
520 MUSTRETURN(curproc, curthread)) {
521 lwp->lwp_sysabort = 0;
522 return (EINTR);
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
531 * through.
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())
539 break;
540 /* FALLTHROUGH */
541 case EAGAIN: /* process may be forking */
543 * Back off for a bit
545 delay(hz);
546 retry = 1;
547 break;
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
553 * up our state.
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));
562 if (hard) {
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");
568 delay(hz);
569 retry = 1;
570 break;
571 } else {
572 error = ECONNREFUSED;
573 kmem_free(xdr_argsp,
574 xdr_len + sizeof (*xdr_argsp));
575 if (orp)
576 kmem_free(orp, orl);
577 return (error);
579 default: /* Unknown must be fatal */
580 error = ENOENT;
581 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
582 if (orp)
583 kmem_free(orp, orl);
584 return (error);
586 } while (retry);
588 if (fngp->fng_printed_not_running_msg == 1) {
589 fngp->fng_printed_not_running_msg = 0;
590 zprintf(zoneid, "automountd OK\n");
593 if (orp && orl) {
594 autofs_door_res_t *door_resp;
595 door_resp = (autofs_door_res_t *)door_args.rbuf;
597 if ((void *)door_args.rbuf != orp)
598 kmem_free(orp, orl);
600 xdrmem_create(&xdrres, (char *)&door_resp->xdr_res,
601 door_resp->xdr_len, XDR_DECODE);
603 if (!((*xresp_func)(&xdrres, resp)))
604 error = EINVAL;
605 kmem_free(door_args.rbuf, door_args.rsize);
607 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
608 return (error);
611 static int
612 auto_null_request(zoneid_t zoneid, bool_t hard)
614 int error;
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));
622 return (error);
625 static int
626 auto_lookup_request(
627 fninfo_t *fnip,
628 char *key,
629 struct linka *lnp,
630 bool_t hard,
631 bool_t *mountreq,
632 cred_t *cred)
634 int error;
635 struct autofs_globals *fngp;
636 struct autofs_lookupargs reqst;
637 autofs_lookupres *resp;
638 struct linka *p;
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;
651 else
652 reqst.name = 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);
666 if (error) {
667 xdr_free(xdr_autofs_lookupres, (char *)resp);
668 kmem_free(resp, sizeof (*resp));
669 return (error);
672 if (!error) {
673 fngp->fng_verbose = resp->lu_verbose;
674 switch (resp->lu_res) {
675 case AUTOFS_OK:
676 switch (resp->lu_type.action) {
677 case AUTOFS_MOUNT_RQ:
678 lnp->link = NULL;
679 lnp->dir = NULL;
680 *mountreq = TRUE;
681 break;
683 case AUTOFS_LINK_RQ:
684 p = &resp->lu_type.lookup_result_type_u.lt_linka;
685 lnp->dir = kmem_alloc(strlen(p->dir) + 1,
686 KM_SLEEP);
687 (void) strcpy(lnp->dir, p->dir);
688 lnp->link = kmem_alloc(strlen(p->link) + 1,
689 KM_SLEEP);
690 (void) strcpy(lnp->link, p->link);
691 break;
693 case AUTOFS_NONE:
694 lnp->link = NULL;
695 lnp->dir = NULL;
696 break;
698 default:
699 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
700 CE_WARN, "auto_lookup_request: bad action "
701 "type %d", resp->lu_res);
702 error = ENOENT;
704 break;
706 case AUTOFS_NOENT:
707 error = ENOENT;
708 break;
710 default:
711 error = ENOENT;
712 auto_log(fngp->fng_verbose, fngp->fng_zoneid, CE_WARN,
713 "auto_lookup_request: unknown result: %d",
714 resp->lu_res);
715 break;
718 done:
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));
723 return (error);
726 static int
727 auto_mount_request(
728 fninfo_t *fnip,
729 char *key,
730 action_list **alpp,
731 cred_t *cred,
732 bool_t hard)
734 int 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;
748 else
749 reqst.name = 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);
764 if (!error) {
765 fngp->fng_verbose = xdrres->mr_verbose;
766 switch (xdrres->mr_type.status) {
767 case AUTOFS_ACTION:
768 error = 0;
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
773 * the list.
775 *alpp = xdrres->mr_type.mount_result_type_u.list;
776 xdrres->mr_type.mount_result_type_u.list = NULL;
777 break;
778 case AUTOFS_DONE:
779 error = xdrres->mr_type.mount_result_type_u.error;
780 break;
781 default:
782 error = ENOENT;
783 auto_log(fngp->fng_verbose, fngp->fng_zoneid, CE_WARN,
784 "auto_mount_request: unknown status %d",
785 xdrres->mr_type.status);
786 break;
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));
796 return (error);
800 static int
801 auto_send_unmount_request(
802 fninfo_t *fnip,
803 umntrequest *ul,
804 bool_t hard)
806 int error;
807 umntres xdrres;
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);
819 if (!error)
820 error = xdrres.status;
822 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error));
824 return (error);
827 static int
828 auto_perform_link(fnnode_t *fnp, struct linka *linkp, cred_t *cred)
830 vnode_t *vp;
831 size_t len;
832 char *tmp;
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;
844 crhold(cred);
845 fnp->fn_cred = cred;
846 mutex_exit(&fnp->fn_lock);
848 vp = fntovn(fnp);
849 vp->v_type = VLNK;
851 return (0);
854 static void
855 auto_free_autofs_args(struct mounta *m)
857 autofs_args *aargs = (autofs_args *)m->dataptr;
859 if (aargs->addr.buf)
860 kmem_free(aargs->addr.buf, aargs->addr.len);
861 if (aargs->path)
862 kmem_free(aargs->path, strlen(aargs->path) + 1);
863 if (aargs->opts)
864 kmem_free(aargs->opts, strlen(aargs->opts) + 1);
865 if (aargs->map)
866 kmem_free(aargs->map, strlen(aargs->map) + 1);
867 if (aargs->subdir)
868 kmem_free(aargs->subdir, strlen(aargs->subdir) + 1);
869 if (aargs->key)
870 kmem_free(aargs->key, strlen(aargs->key) + 1);
871 kmem_free(aargs, sizeof (*aargs));
874 static void
875 auto_free_action_list(action_list *alp)
877 struct mounta *m;
878 action_list *lastalp;
879 char *fstype;
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;
885 if (m->dataptr) {
886 if (strcmp(fstype, "autofs") == 0) {
887 auto_free_autofs_args(m);
890 if (m->spec)
891 kmem_free(m->spec, strlen(m->spec) + 1);
892 if (m->dir)
893 kmem_free(m->dir, strlen(m->dir) + 1);
894 if (m->fstype)
895 kmem_free(m->fstype, strlen(m->fstype) + 1);
896 if (m->optptr)
897 kmem_free(m->optptr, m->optlen);
898 lastalp = alp;
899 alp = alp->next;
900 kmem_free(lastalp, sizeof (*lastalp));
904 static boolean_t
905 auto_invalid_autofs(fninfo_t *dfnip, fnnode_t *dfnp, action_list *p)
907 struct mounta *m;
908 struct autofs_args *argsp;
909 vnode_t *dvp;
910 char buff[AUTOFS_MAXPATHLEN];
911 size_t len;
912 struct autofs_globals *fngp;
914 fngp = dfnp->fn_globals;
915 dvp = fntovn(dfnp);
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) ||
929 m->optptr == NULL)
930 return (B_TRUE);
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
934 * lookup()s.
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] == '/')
940 return (B_TRUE);
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)
947 return (B_TRUE);
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
958 * trigger node.
960 * At this point it seems like the passed-in path is
961 * redundant.
963 if (dvp->v_flag & VROOT) {
964 if (m->dir[1] == '\0' && !(dfnp->fn_flags & MF_TRIGGER))
965 return (B_TRUE);
966 (void) snprintf(buff, sizeof (buff), "%s%s",
967 dfnip->fi_path, m->dir + 1);
968 } else {
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);
976 return (B_TRUE);
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.
985 static boolean_t
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)
993 return (B_TRUE);
994 return (auto_invalid_autofs(dfnip, dfnp, alistpp));
998 static int
999 auto_perform_actions(
1000 fninfo_t *dfnip,
1001 fnnode_t *dfnp,
1002 action_list *alp,
1003 cred_t *cred) /* Credentials of the caller */
1006 action_list *p;
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;
1012 int auto_mount = 0;
1013 int save_triggers = 0;
1014 int update_times = 0;
1015 char *mntpnt;
1016 char buff[AUTOFS_MAXPATHLEN];
1017 timestruc_t now;
1018 struct autofs_globals *fngp;
1019 cred_t *zcred;
1021 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", (void *)alp));
1023 fngp = dfnp->fn_globals;
1024 dvp = fntovn(dfnp);
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
1038 * as the attacker.
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);
1047 return (EINVAL);
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);
1063 success++;
1064 } else {
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 */
1082 vfs_t *mvfsp;
1084 auto_mount = 0;
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
1096 * begin with "."
1099 ASSERT(m->dir[0] == '.');
1100 if (m->dir[0] == '.' && m->dir[1] == '\0') {
1102 * mounting on the trigger node
1104 mvp = dvp;
1105 VN_HOLD(mvp);
1106 goto mount;
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);
1121 } else {
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);
1139 if (error == 0) {
1141 * AUTOFS mountpoint exists
1143 if (vn_mountedvfs(fntovn(mfnp)) != NULL) {
1144 cmn_err(CE_PANIC,
1145 "auto_perform_actions:"
1146 " mfnp=%p covered", (void *)mfnp);
1148 } else {
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);
1155 mfnp->fn_linkcnt++;
1157 if (!error)
1158 update_times = 1;
1159 rw_exit(&dfnp->fn_rwlock);
1160 ASSERT(error != EEXIST);
1161 if (!error) {
1163 * mfnp is already held.
1165 mvp = fntovn(mfnp);
1166 } else {
1167 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
1168 CE_WARN, "autofs: mount of %s "
1169 "failed - can't create"
1170 " mountpoint.", buff);
1171 continue;
1173 } else {
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
1178 * mounted.
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"
1184 " exist.", buff);
1185 continue;
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);
1192 VN_RELE(mvp);
1193 error = ENOENT;
1194 continue;
1197 mount:
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);
1221 if (error != 0) {
1222 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
1223 CE_WARN, "autofs: domount of %s failed "
1224 "error=%d", buff, error);
1225 VN_RELE(mvp);
1226 continue;
1228 VFS_RELE(vfsp);
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))) {
1241 mfnp = vntofn(mvp);
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);
1251 vn_vfsunlock(mvp);
1252 error = VFS_ROOT(mvfsp, &newvp);
1253 vfs_unlock(mvfsp);
1254 if (error) {
1256 * We've dropped the locks, so let's
1257 * get the mounted vfs again in case
1258 * it changed.
1260 (void) vn_vfswlock_wait(mvp);
1261 mvfsp = vn_mountedvfs(mvp);
1262 if (mvfsp != NULL) {
1263 error = dounmount(mvfsp, 0, CRED());
1264 if (error) {
1265 cmn_err(CE_WARN,
1266 "autofs: could not unmount"
1267 " vfs=%p", (void *)mvfsp);
1269 } else
1270 vn_vfsunlock(mvp);
1271 VN_RELE(mvp);
1272 continue;
1274 } else {
1275 vn_vfsunlock(mvp);
1276 VN_RELE(mvp);
1277 continue;
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
1293 * unmounted.
1295 if (auto_mount && (error == 0) && (mvp != dvp)) {
1296 save_triggers++;
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));
1318 else
1319 AUTOFS_DPRINT((10, "\tno next trigger\n"));
1320 } else
1321 VN_RELE(newvp);
1323 if (!error)
1324 success++;
1326 if (update_times) {
1327 gethrestime(&now);
1328 dfnp->fn_atime = dfnp->fn_mtime = now;
1331 VN_RELE(mvp);
1334 if (save_triggers) {
1336 * Make sure the parent can't be freed while it has triggers.
1338 VN_HOLD(dvp);
1341 crfree(zcred);
1343 done:
1345 * Return failure if daemon didn't mount anything, and all
1346 * kernel mounts attempted failed.
1348 error = success ? 0 : ENOENT;
1350 if (alp != NULL) {
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
1357 * unmount_tree().
1359 mutex_enter(&dfnp->fn_lock);
1360 ASSERT(dfnp->fn_alp == NULL);
1361 dfnp->fn_alp = alp;
1362 mutex_exit(&dfnp->fn_lock);
1363 } else {
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));
1371 return (error);
1374 fnnode_t *
1375 auto_makefnnode(
1376 vtype_t type,
1377 vfs_t *vfsp,
1378 char *name,
1379 cred_t *cred,
1380 struct autofs_globals *fngp)
1382 fnnode_t *fnp;
1383 vnode_t *vp;
1384 char *tmpname;
1385 timestruc_t now;
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);
1398 vp = fntovn(fnp);
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;
1414 gethrestime(&now);
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;
1419 nodeid += 2;
1420 fnp->fn_globals = fngp;
1421 fngp->fng_fnnode_count++;
1422 mutex_exit(&autofs_nodeid_lock);
1423 vn_setops(vp, auto_vnodeops);
1424 vp->v_type = type;
1425 vp->v_data = (void *)fnp;
1426 vp->v_vfsp = vfsp;
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);
1430 vn_exists(vp);
1431 return (fnp);
1435 void
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);
1447 vn_invalid(vp);
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);
1453 if (fnp->fn_cred)
1454 crfree(fnp->fn_cred);
1455 mutex_destroy(&fnp->fn_lock);
1456 rw_destroy(&fnp->fn_rwlock);
1457 cv_destroy(&fnp->fn_cv_mount);
1458 vn_free(vp);
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));
1466 void
1467 auto_disconnect(
1468 fnnode_t *dfnp,
1469 fnnode_t *fnp)
1471 fnnode_t *tmp, **fnpp;
1472 vnode_t *vp = fntovn(fnp);
1473 timestruc_t now;
1475 AUTOFS_DPRINT((4,
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",
1484 (void *)vp);
1488 * Decrement by 1 because we're removing the entry in dfnp.
1490 fnp->fn_linkcnt--;
1491 fnp->fn_size--;
1494 * only changed while holding parent's (dfnp) rw_lock
1496 fnp->fn_parent = NULL;
1498 fnpp = &dfnp->fn_dirents;
1499 for (;;) {
1500 tmp = *fnpp;
1501 if (tmp == NULL) {
1502 cmn_err(CE_PANIC,
1503 "auto_disconnect: %p not in %p dirent list",
1504 (void *)fnp, (void *)dfnp);
1506 if (tmp == fnp) {
1507 *fnpp = tmp->fn_next; /* remove it from the list */
1508 ASSERT(vp->v_count == 0);
1509 /* child had a pointer to parent ".." */
1510 dfnp->fn_linkcnt--;
1511 dfnp->fn_size--;
1512 break;
1514 fnpp = &tmp->fn_next;
1517 mutex_enter(&fnp->fn_lock);
1518 gethrestime(&now);
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;
1531 ushort_t diff;
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;
1538 if (cfnp == NULL) {
1540 * offset = 0 for '.' and offset = 1 for '..'
1542 spp = &dfnp->fn_dirents;
1543 offset = 2;
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)
1556 return (EEXIST);
1557 } else {
1558 mutex_exit(&cfnp->fn_lock);
1559 return (EEXIST);
1563 if (cfnp->fn_next != NULL) {
1564 diff = (ushort_t)
1565 (cfnp->fn_next->fn_offset - cfnp->fn_offset);
1566 ASSERT(diff != 0);
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,
1578 dfnp->fn_globals);
1579 if (*fnpp == NULL)
1580 return (ENOMEM);
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;
1590 *spp = *fnpp;
1591 (*fnpp)->fn_parent = dfnp;
1592 (*fnpp)->fn_linkcnt++; /* parent now holds reference to entry */
1593 (*fnpp)->fn_size++;
1596 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock
1598 dfnp->fn_linkcnt++; /* child now holds reference to parent '..' */
1599 dfnp->fn_size++;
1601 dfnp->fn_ref_time = gethrestime_sec();
1603 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp));
1604 return (0);
1608 auto_search(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1610 vnode_t *dvp;
1611 fnnode_t *p;
1612 int error = ENOENT, match = 0;
1614 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n",
1615 (void *)dfnp, name));
1617 dvp = fntovn(dfnp);
1618 if (dvp->v_type != VDIR) {
1619 cmn_err(CE_PANIC, "auto_search: dvp=%p not a directory",
1620 (void *)dvp);
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;
1634 } else {
1636 * No need to check CRED
1638 mutex_exit(&p->fn_lock);
1639 match = 1;
1642 if (match) {
1643 error = 0;
1644 if (fnpp) {
1645 *fnpp = p;
1646 VN_HOLD(fntovn(*fnpp));
1648 break;
1652 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error));
1653 return (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.
1661 /* ARGSUSED */
1662 static int
1663 auto_getmntpnt(
1664 vnode_t *dvp,
1665 char *path,
1666 vnode_t **mvpp, /* vnode for mountpoint */
1667 cred_t *cred)
1669 int error = 0;
1670 vnode_t *newvp;
1671 char namebuf[TYPICALMAXPATHLEN];
1672 struct pathname lookpn;
1673 vfs_t *vfsp;
1675 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path));
1677 if (error = vn_vfsrlock_wait(dvp))
1678 return (error);
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);
1687 if (vfsp == NULL) {
1688 vn_vfsunlock(dvp);
1689 error = EBUSY;
1690 goto done;
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);
1698 vn_vfsunlock(dvp);
1699 if (error)
1700 goto done;
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().
1707 VN_HOLD(newvp);
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));
1716 if (error == 0) {
1717 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP,
1718 mvpp, rootdir, newvp, cred);
1719 } else
1720 VN_RELE(newvp);
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);
1733 pn_free(&lookpn);
1734 } else
1735 VN_RELE(newvp);
1736 } else {
1738 * Need to release newvp here since we held it.
1740 VN_RELE(newvp);
1743 done:
1744 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n",
1745 path, (void *)*mvpp, error));
1746 return (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.
1756 static int
1757 auto_inkernel_unmount(vfs_t *vfsp)
1759 vnode_t *cvp = vfsp->vfs_vnodecovered;
1760 int error;
1762 AUTOFS_DPRINT((4,
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",
1775 cvp->v_count));
1776 return (error);
1780 * unmounts trigger nodes in the kernel.
1782 static void
1783 unmount_triggers(fnnode_t *fnp, action_list **alp)
1785 fnnode_t *tp, *next;
1786 int error = 0;
1787 vfs_t *vfsp;
1788 vnode_t *tvp;
1790 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp));
1791 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1793 *alp = fnp->fn_alp;
1794 next = fnp->fn_trigger;
1795 while ((tp = next) != NULL) {
1796 tvp = fntovn(tp);
1797 ASSERT(tvp->v_count >= 2);
1798 next = tp->fn_next;
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
1805 * by a VN_RELE
1807 rw_exit(&fnp->fn_rwlock);
1809 vfsp = tvp->v_vfsp;
1812 * Its parent was holding a reference to it, since this
1813 * is a trigger vnode.
1815 VN_RELE(tvp);
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;
1832 fnp->fn_alp = 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.
1841 static boolean_t
1842 triggers_busy(fnnode_t *fnp)
1844 int done;
1845 int lck_error = 0;
1846 fnnode_t *tp, *t1p;
1847 vfs_t *vfsp;
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
1887 * be unlocked.
1889 if (t1p != tp || !lck_error) {
1890 vfsp = fntovn(t1p)->v_vfsp;
1891 vn_vfsunlock(vfsp->vfs_vnodecovered);
1893 done = (t1p == tp);
1895 return (B_TRUE);
1899 return (B_FALSE);
1903 * It is the caller's responsibility to grab the VVFSLOCK.
1904 * Releases the VVFSLOCK upon return.
1906 static int
1907 unmount_node(vnode_t *cvp, int force)
1909 int error = 0;
1910 fnnode_t *cfnp;
1911 vfs_t *vfsp;
1912 umntrequest ul;
1913 fninfo_t *fnip;
1915 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp));
1917 ASSERT(vn_vfswlock_held(cvp));
1918 cfnp = vntofn(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);
1928 } else {
1929 zone_t *zone = NULL;
1930 refstr_t *mntpt, *resource;
1931 size_t mntoptslen;
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");
1943 vn_vfsunlock(cvp);
1944 error = ENOMEM;
1945 goto done;
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)) {
1968 ul.mntpnt =
1969 ZONE_PATH_TRANSLATE(ul.mntpnt, zone);
1971 if (ZONE_PATH_VISIBLE(ul.mntresource, zone)) {
1972 ul.mntresource =
1973 ZONE_PATH_TRANSLATE(ul.mntresource, zone);
1977 ul.fstype = vfssw[vfsp->vfs_fstype].vsw_name;
1978 vn_vfsunlock(cvp);
1980 error = auto_send_unmount_request(fnip, &ul, FALSE);
1981 kmem_free(ul.mntopts, mntoptslen);
1982 refstr_rele(mntpt);
1983 refstr_rele(resource);
1986 done:
1987 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp,
1988 error));
1989 return (error);
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.
1999 static int
2000 check_auto_node(vnode_t *vp)
2002 fnnode_t *fnp;
2003 int error = 0;
2005 * number of references to expect for
2006 * a non-busy vnode.
2008 uint_t count;
2010 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp));
2011 fnp = vntofn(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)
2018 count++;
2020 if (fnp->fn_trigger != NULL) {
2022 * The trigger nodes have a hold on us.
2024 count++;
2026 if (vn_ismntpt(vp)) {
2028 * File system is mounted on us.
2030 count++;
2032 mutex_enter(&vp->v_lock);
2033 ASSERT(vp->v_count > 0);
2034 if (vp->v_flag & VROOT)
2035 count++;
2036 AUTOFS_DPRINT((10, "\tcount=%u ", vp->v_count));
2037 if (vp->v_count > count)
2038 error = EBUSY;
2039 mutex_exit(&vp->v_lock);
2041 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error));
2042 return (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.
2054 static void
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);
2070 fnp->fn_linkcnt--;
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.
2086 static int
2087 try_unmount_node(fnnode_t *fnp, boolean_t force)
2089 boolean_t trigger_unmount = B_FALSE;
2090 action_list *alp = NULL;
2091 vnode_t *vp;
2092 int error = 0;
2093 fninfo_t *fnip;
2094 vfs_t *vfsp;
2095 struct autofs_globals *fngp;
2097 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n",
2098 (void *)fnp));
2100 ASSERT(MUTEX_HELD(&fnp->fn_lock));
2102 fngp = fnp->fn_globals;
2103 vp = fntovn(fnp);
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);
2112 return (EBUSY);
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
2125 * the process.
2127 * Note: This should be fixed. Autofs shouldn't pass the map name
2128 * in special and avoid useless lookup with potentially disasterous
2129 * consequence.
2131 if (check_auto_node(vp) == EBUSY) {
2132 mutex_exit(&fnp->fn_lock);
2133 return (EBUSY);
2137 * If not forced operation, back out if node has been referenced
2138 * recently.
2140 if (!force &&
2141 fnp->fn_ref_time + fnip->fi_mount_to > gethrestime_sec()) {
2142 mutex_exit(&fnp->fn_lock);
2143 return (EBUSY);
2146 /* block mounts/unmounts on the node */
2147 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
2148 fnp->fn_error = 0;
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);
2161 return (EBUSY);
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);
2180 if (vfsp != NULL) {
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.
2200 error = 0;
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);
2208 } else {
2209 vn_vfsunlock(vp);
2210 /* Destroy all dirents of fnp if we unmounted its triggers */
2211 if (trigger_unmount)
2212 unmount_autofs(vp);
2215 /* If unmount failed, we got to remount triggers */
2216 if (error != 0) {
2217 if (trigger_unmount) {
2218 int ret;
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());
2226 if (ret != 0) {
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);
2235 } else {
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);
2253 return (error);
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)
2266 * unlock fn_rwlock
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
2272 * fashion.
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 */
2283 vnode_t *curvp;
2284 vnode_t *newvp;
2285 vfs_t *vfsp;
2286 time_t timestamp;
2288 ASSERT(fntovn(rootfnp)->v_type != VLNK);
2289 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp,
2290 rootfnp->fn_name));
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
2309 * order.
2311 if (currfnp->fn_unmount_ref_time == timestamp &&
2312 currfnp != lastfnp) {
2313 (void) try_unmount_node(currfnp, force);
2314 lastfnp = currfnp;
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);
2337 VN_RELE(curvp);
2338 currfnp = nextfnp;
2339 mutex_enter(&currfnp->fn_lock);
2340 continue;
2342 rw_exit(&currfnp->fn_parent->fn_rwlock);
2345 * All descendants and siblings were visited. Perform
2346 * bottom-up move.
2348 nextfnp = currfnp->fn_parent;
2349 VN_HOLD(fntovn(nextfnp));
2350 VN_RELE(curvp);
2351 currfnp = nextfnp;
2352 mutex_enter(&currfnp->fn_lock);
2353 continue;
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
2369 * below.
2371 * Acquire fn_rwlock in non-blocking mode to avoid deadlock.
2372 * If it can't be acquired, then acquire locks in correct
2373 * order.
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);
2382 continue;
2384 mutex_exit(&currfnp->fn_lock);
2387 * Examine descendants in this order: triggers, dirents, autofs
2388 * mounts.
2391 if ((nextfnp = currfnp->fn_trigger) != NULL) {
2392 VN_HOLD(fntovn(nextfnp));
2393 rw_exit(&currfnp->fn_rwlock);
2394 VN_RELE(curvp);
2395 currfnp = nextfnp;
2396 mutex_enter(&currfnp->fn_lock);
2397 continue;
2400 if ((nextfnp = currfnp->fn_dirents) != NULL) {
2401 VN_HOLD(fntovn(nextfnp));
2402 rw_exit(&currfnp->fn_rwlock);
2403 VN_RELE(curvp);
2404 currfnp = nextfnp;
2405 mutex_enter(&currfnp->fn_lock);
2406 continue;
2408 rw_exit(&currfnp->fn_rwlock);
2410 (void) vn_vfswlock_wait(curvp);
2411 vfsp = vn_mountedvfs(curvp);
2412 if (vfsp != NULL &&
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
2419 * auto_root().
2421 if (VFS_ROOT(vfsp, &newvp)) {
2422 cmn_err(CE_PANIC,
2423 "autofs: VFS_ROOT(vfs=%p) failed",
2424 (void *)vfsp);
2426 vn_vfsunlock(curvp);
2427 VN_RELE(curvp);
2428 currfnp = vntofn(newvp);
2429 mutex_enter(&currfnp->fn_lock);
2430 continue;
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.
2454 void
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,
2463 "unmount_tree");
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
2474 * credentials.
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);
2505 static void
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"));
2517 zthread_exit();
2518 /* NOTREACHED */
2521 void
2522 auto_do_unmount(struct autofs_globals *fngp)
2524 callb_cpr_t cprinfo;
2525 clock_t timeleft;
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);
2534 newthread:
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
2545 * the below.
2547 CALLB_CPR_SAFE_END(&cprinfo,
2548 &fngp->fng_unmount_threads_lock);
2549 CALLB_CPR_EXIT(&cprinfo);
2550 zthread_exit();
2551 /* NOTREACHED */
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,
2560 0, minclsyspri);
2561 } else
2562 goto newthread;
2564 /* NOTREACHED */
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)
2575 char *buf;
2576 char *p;
2577 char *t;
2578 int nobrowse = 0;
2579 int last_opt = 0;
2580 size_t len;
2582 len = strlen(opts) + 1;
2583 p = buf = kmem_alloc(len, KM_SLEEP);
2584 (void) strcpy(buf, opts);
2585 do {
2586 if (t = strchr(p, ','))
2587 *t++ = '\0';
2588 else
2589 last_opt++;
2590 if (strcmp(p, MNTOPT_NOBROWSE) == 0)
2591 nobrowse = 1;
2592 else if (strcmp(p, MNTOPT_BROWSE) == 0)
2593 nobrowse = 0;
2594 p = t;
2595 } while (!last_opt);
2596 kmem_free(buf, len);
2598 return (nobrowse);
2602 * used to log warnings only if automountd is running
2603 * with verbose mode set
2606 void
2607 auto_log(int verbose, zoneid_t zoneid, int level, const char *fmt, ...)
2609 va_list args;
2611 if (verbose) {
2612 va_start(args, fmt);
2613 vzcmn_err(zoneid, level, fmt, args);
2614 va_end(args);
2618 #ifdef DEBUG
2619 static int autofs_debug = 0;
2622 * Utilities used by both client and server
2623 * Standard levels:
2624 * 0) no debugging
2625 * 1) hard failures
2626 * 2) soft failures
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
2634 * 10) random stuff
2635 * 11) all <= 1
2636 * 12) all <= 2
2637 * 13) all <= 3
2638 * ...
2640 /* PRINTFLIKE2 */
2641 void
2642 auto_dprint(int level, const char *fmt, ...)
2644 va_list args;
2646 if (autofs_debug == level ||
2647 (autofs_debug > 10 && (autofs_debug - 10) >= level)) {
2648 va_start(args, fmt);
2649 (void) vprintf(fmt, args);
2650 va_end(args);
2653 #endif /* DEBUG */