Unleashed v1.4
[unleashed.git] / kernel / fs / autofs / auto_subr.c
blob07c9c307bf33b0bf038f0e49e1ca1cbbafc749aa
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) {
166 error = ENOENT;
168 * This node should be a symlink
170 if (*link.link != '\0')
171 error = auto_perform_link(fnp, &link, cred);
172 } else if (mountreq) {
174 * The automount daemon is requesting a mount,
175 * implying this entry must be a wildcard match and
176 * therefore in need of verification that the entry
177 * exists on the server.
179 mutex_enter(&fnp->fn_lock);
180 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
181 fnp->fn_error = 0;
184 * Unblock other lookup requests on this node,
185 * this is needed to let the lookup generated by
186 * the mount call to complete. The caveat is
187 * other lookups on this node can also get by,
188 * i.e., another lookup on this node that occurs
189 * while this lookup is attempting the mount
190 * would return a positive result no matter what.
191 * Therefore two lookups on the this node could
192 * potentially get disparate results.
194 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
195 mutex_exit(&fnp->fn_lock);
197 * auto_new_mount_thread fires up a new thread which
198 * calls automountd finishing up the work
200 auto_new_mount_thread(fnp, name, cred);
203 * At this point, we are simply another thread
204 * waiting for the mount to complete
206 error = auto_wait4mount(fnp);
207 if (error == AUTOFS_SHUTDOWN)
208 error = ENOENT;
212 if (link.link)
213 kmem_free(link.link, strlen(link.link) + 1);
214 if (link.dir)
215 kmem_free(link.dir, strlen(link.dir) + 1);
216 mutex_enter(&fnp->fn_lock);
217 fnp->fn_error = error;
220 * Notify threads waiting for lookup/mount that
221 * it's done.
223 if (mountreq) {
224 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
225 } else {
226 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
228 mutex_exit(&fnp->fn_lock);
229 return (error);
233 * Starting point for thread to handle mount requests with automountd.
234 * XXX auto_mount_thread() is not suspend-safe within the scope of
235 * the present model defined for cpr to suspend the system. Calls
236 * made by the auto_mount_thread() that have been identified to be unsafe
237 * are (1) RPC client handle setup and client calls to automountd which
238 * can block deep down in the RPC library, (2) kmem_alloc() calls with the
239 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*(), and
240 * lookuppnvp() calls which can result in over the wire calls to servers.
241 * The thread should be completely reevaluated to make it suspend-safe in
242 * case of future updates to the cpr model.
244 static void
245 auto_mount_thread(struct autofs_callargs *argsp)
247 struct fninfo *fnip;
248 fnnode_t *fnp;
249 vnode_t *vp;
250 char *name;
251 size_t namelen;
252 cred_t *cred;
253 action_list *alp = NULL;
254 int error;
255 callb_cpr_t cprinfo;
256 kmutex_t auto_mount_thread_cpr_lock;
258 mutex_init(&auto_mount_thread_cpr_lock, NULL, MUTEX_DEFAULT, NULL);
259 CALLB_CPR_INIT(&cprinfo, &auto_mount_thread_cpr_lock,
260 callb_generic_cpr, "auto_mount_thread");
262 fnp = argsp->fnc_fnp;
263 vp = fntovn(fnp);
264 fnip = vfstofni(vp->v_vfsp);
265 name = argsp->fnc_name;
266 cred = argsp->fnc_cred;
267 ASSERT(crgetzoneid(argsp->fnc_cred) == fnip->fi_zoneid);
269 error = auto_mount_request(fnip, name, &alp, cred, TRUE);
270 if (!error)
271 error = auto_perform_actions(fnip, fnp, alp, cred);
272 mutex_enter(&fnp->fn_lock);
273 fnp->fn_error = error;
276 * Notify threads waiting for mount that
277 * it's done.
279 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
280 mutex_exit(&fnp->fn_lock);
282 VN_RELE(vp);
283 crfree(argsp->fnc_cred);
284 namelen = strlen(argsp->fnc_name) + 1;
285 kmem_free(argsp->fnc_name, namelen);
286 kmem_free(argsp, sizeof (*argsp));
288 mutex_enter(&auto_mount_thread_cpr_lock);
289 CALLB_CPR_EXIT(&cprinfo);
290 mutex_destroy(&auto_mount_thread_cpr_lock);
291 zthread_exit();
292 /* NOTREACHED */
295 static int autofs_thr_success = 0;
298 * Creates new thread which calls auto_mount_thread which does
299 * the bulk of the work calling automountd, via 'auto_perform_actions'.
301 void
302 auto_new_mount_thread(fnnode_t *fnp, char *name, cred_t *cred)
304 struct autofs_callargs *argsp;
306 argsp = kmem_alloc(sizeof (*argsp), KM_SLEEP);
307 VN_HOLD(fntovn(fnp));
308 argsp->fnc_fnp = fnp;
309 argsp->fnc_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
310 (void) strcpy(argsp->fnc_name, name);
311 argsp->fnc_origin = curthread;
312 crhold(cred);
313 argsp->fnc_cred = cred;
315 (void) zthread_create(NULL, 0, auto_mount_thread, argsp, 0,
316 minclsyspri);
317 autofs_thr_success++;
320 #define DOOR_BUF_ALIGN (1024*1024)
321 #define DOOR_BUF_MULTIPLIER 3
322 #define DOOR_BUF_DEFAULT_SZ (DOOR_BUF_MULTIPLIER * DOOR_BUF_ALIGN)
323 int doorbuf_defsz = DOOR_BUF_DEFAULT_SZ;
325 /*ARGSUSED*/
327 auto_calldaemon(
328 zoneid_t zoneid,
329 int which,
330 xdrproc_t xarg_func,
331 void *argsp,
332 xdrproc_t xresp_func,
333 void *resp,
334 int reslen,
335 bool_t hard) /* retry forever? */
337 int retry;
338 int error = 0;
339 k_sigset_t smask;
340 door_arg_t door_args;
341 door_handle_t dh;
342 XDR xdrarg;
343 XDR xdrres;
344 struct autofs_globals *fngp = NULL;
345 void *orp = NULL;
346 int orl;
347 int rlen = 0; /* MUST be initialized */
348 autofs_door_args_t *xdr_argsp;
349 int xdr_len = 0;
350 int printed_not_running_msg = 0;
351 klwp_t *lwp = ttolwp(curthread);
354 * We know that the current thread is doing work on
355 * behalf of its own zone, so it's ok to use
356 * curproc->p_zone.
358 ASSERT(zoneid == getzoneid());
359 if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
361 * There's no point in trying to talk to
362 * automountd. Plus, zone_shutdown() is
363 * waiting for us.
365 return (ECONNREFUSED);
368 do {
369 retry = 0;
370 mutex_enter(&autofs_minor_lock);
371 fngp = zone_getspecific(autofs_key, curproc->p_zone);
372 mutex_exit(&autofs_minor_lock);
373 if (fngp == NULL) {
374 if (hard) {
375 AUTOFS_DPRINT((5,
376 "auto_calldaemon: "\
377 "failed to get door handle\n"));
378 if (!printed_not_running_msg) {
379 printed_not_running_msg = 1;
380 zprintf(zoneid, "automountd not "\
381 "running, retrying\n");
383 ddi_sleep(1);
384 retry = 1;
385 } else {
387 * There is no global data so no door.
388 * There's no point in attempting to talk
389 * to automountd if we can't get the door
390 * handle.
392 return (ECONNREFUSED);
395 } while (retry);
397 if (printed_not_running_msg) {
398 fngp->fng_printed_not_running_msg = printed_not_running_msg;
401 ASSERT(fngp != NULL);
403 if (argsp != NULL && (xdr_len = xdr_sizeof(xarg_func, argsp)) == 0)
404 return (EINVAL);
405 xdr_argsp = kmem_zalloc(xdr_len + sizeof (*xdr_argsp), KM_SLEEP);
406 xdr_argsp->xdr_len = xdr_len;
407 xdr_argsp->cmd = which;
409 if (argsp) {
410 xdrmem_create(&xdrarg, (char *)&xdr_argsp->xdr_arg,
411 xdr_argsp->xdr_len, XDR_ENCODE);
413 if (!(*xarg_func)(&xdrarg, argsp)) {
414 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
415 return (EINVAL);
420 * We're saving off the original pointer and length due to the
421 * possibility that the results buffer returned by the door
422 * upcall can be different then what we passed in. This is because
423 * the door will allocate new memory if the results buffer passed
424 * in isn't large enough to hold what we need to send back.
425 * In this case we need to free the memory originally allocated
426 * for that buffer.
428 if (resp)
429 rlen = xdr_sizeof(xresp_func, resp);
430 orl = (rlen == 0) ? doorbuf_defsz : MAX(rlen, doorbuf_defsz);
431 orp = kmem_zalloc(orl, KM_SLEEP);
433 do {
434 retry = 0;
435 mutex_enter(&fngp->fng_autofs_daemon_lock);
436 dh = fngp->fng_autofs_daemon_dh;
437 if (dh)
438 door_ki_hold(dh);
439 mutex_exit(&fngp->fng_autofs_daemon_lock);
441 if (dh == NULL) {
442 if (orp)
443 kmem_free(orp, orl);
444 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
445 return (ENOENT);
447 door_args.data_ptr = (char *)xdr_argsp;
448 door_args.data_size = sizeof (*xdr_argsp) + xdr_argsp->xdr_len;
449 door_args.desc_ptr = NULL;
450 door_args.desc_num = 0;
451 door_args.rbuf = orp ? (char *)orp : NULL;
452 door_args.rsize = orl;
454 sigintr(&smask, 1);
455 error =
456 door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
457 sigunintr(&smask);
459 door_ki_rele(dh);
462 * Handle daemon errors
464 if (!error) {
466 * Upcall successful. Let's check for soft errors
467 * from the daemon. We only recover from overflow
468 * type scenarios. Any other errors, we return to
469 * the caller.
471 autofs_door_res_t *adr =
472 (autofs_door_res_t *)door_args.rbuf;
474 if (door_args.rbuf != NULL) {
475 int nl;
477 switch (error = adr->res_status) {
478 case 0: /* no error; continue */
479 break;
481 case EOVERFLOW:
483 * orig landing buf not big enough.
484 * xdr_len in XDR_BYTES_PER_UNIT
486 if ((nl = adr->xdr_len) > 0 &&
487 (btopr(nl) < freemem/64)) {
488 if (orp)
489 kmem_free(orp, orl);
490 orp = kmem_zalloc(nl, KM_SLEEP);
491 orl = nl;
492 retry = 1;
493 break;
495 /*FALLTHROUGH*/
497 default:
498 kmem_free(xdr_argsp,
499 xdr_len + sizeof (*xdr_argsp));
500 if (orp)
501 kmem_free(orp, orl);
502 return (error);
505 continue;
509 * no daemon errors; now process door/comm errors (if any)
511 switch (error) {
512 case EINTR:
514 * interrupts should be handled properly by the
515 * door upcall. If the door doesn't handle the
516 * interupt completely then we need to bail out.
518 if (lwp && (ISSIG(curthread,
519 JUSTLOOKING) || MUSTRETURN(curproc, curthread))) {
520 if (ISSIG(curthread, FORREAL) ||
521 lwp->lwp_sysabort ||
522 MUSTRETURN(curproc, curthread)) {
523 lwp->lwp_sysabort = 0;
524 return (EINTR);
528 * We may have gotten EINTR for other reasons
529 * like the door being revoked on us. Instead
530 * of trying to extract this out of the door
531 * handle, sleep and try again, if still
532 * revoked we will get EBADF next time
533 * through.
535 * If we have a pending cancellation and we don't
536 * have cancellation disabled, we will get EINTR
537 * forever, no matter how many times we retry,
538 * so just get out now if this is the case.
540 if (schedctl_cancel_pending())
541 break;
542 /* FALLTHROUGH */
543 case EAGAIN: /* process may be forking */
545 * Back off for a bit
547 ddi_sleep(1);
548 retry = 1;
549 break;
550 case EBADF: /* Invalid door */
551 case EINVAL: /* Not a door, wrong target */
553 * A fatal door error, if our failing door
554 * handle is the current door handle, clean
555 * up our state.
557 mutex_enter(&fngp->fng_autofs_daemon_lock);
558 if (dh == fngp->fng_autofs_daemon_dh) {
559 door_ki_rele(fngp->fng_autofs_daemon_dh);
560 fngp->fng_autofs_daemon_dh = NULL;
562 mutex_exit(&fngp->fng_autofs_daemon_lock);
563 AUTOFS_DPRINT((5, "auto_calldaemon error=%d\n", error));
564 if (hard) {
565 if (!fngp->fng_printed_not_running_msg) {
566 fngp->fng_printed_not_running_msg = 1;
567 zprintf(zoneid, "automountd not "
568 "running, retrying\n");
570 ddi_sleep(1);
571 retry = 1;
572 break;
573 } else {
574 error = ECONNREFUSED;
575 kmem_free(xdr_argsp,
576 xdr_len + sizeof (*xdr_argsp));
577 if (orp)
578 kmem_free(orp, orl);
579 return (error);
581 default: /* Unknown must be fatal */
582 error = ENOENT;
583 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
584 if (orp)
585 kmem_free(orp, orl);
586 return (error);
588 } while (retry);
590 if (fngp->fng_printed_not_running_msg == 1) {
591 fngp->fng_printed_not_running_msg = 0;
592 zprintf(zoneid, "automountd OK\n");
595 if (orp && orl) {
596 autofs_door_res_t *door_resp;
597 door_resp = (autofs_door_res_t *)door_args.rbuf;
599 if ((void *)door_args.rbuf != orp)
600 kmem_free(orp, orl);
602 xdrmem_create(&xdrres, (char *)&door_resp->xdr_res,
603 door_resp->xdr_len, XDR_DECODE);
605 if (!((*xresp_func)(&xdrres, resp)))
606 error = EINVAL;
607 kmem_free(door_args.rbuf, door_args.rsize);
609 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
610 return (error);
613 static int
614 auto_null_request(zoneid_t zoneid, bool_t hard)
616 int error;
618 AUTOFS_DPRINT((4, "\tauto_null_request\n"));
620 error = auto_calldaemon(zoneid, NULLPROC,
621 xdr_void, NULL, xdr_void, NULL, 0, hard);
623 AUTOFS_DPRINT((5, "\tauto_null_request: error=%d\n", error));
624 return (error);
627 static int
628 auto_lookup_request(
629 fninfo_t *fnip,
630 char *key,
631 struct linka *lnp,
632 bool_t hard,
633 bool_t *mountreq,
634 cred_t *cred)
636 int error;
637 struct autofs_globals *fngp;
638 struct autofs_lookupargs reqst;
639 autofs_lookupres *resp;
640 struct linka *p;
643 AUTOFS_DPRINT((4, "auto_lookup_equest: path=%s name=%s\n",
644 fnip->fi_path, key));
646 fngp = vntofn(fnip->fi_rootvp)->fn_globals;
648 reqst.map = fnip->fi_map;
649 reqst.path = fnip->fi_path;
651 if (fnip->fi_flags & MF_DIRECT)
652 reqst.name = fnip->fi_key;
653 else
654 reqst.name = key;
655 AUTOFS_DPRINT((4, "auto_lookup_request: using key=%s\n", reqst.name));
657 reqst.subdir = fnip->fi_subdir;
658 reqst.opts = fnip->fi_opts;
659 reqst.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE;
660 reqst.uid = crgetuid(cred);
662 resp = kmem_zalloc(sizeof (*resp), KM_SLEEP);
664 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_LOOKUP,
665 xdr_autofs_lookupargs, &reqst, xdr_autofs_lookupres,
666 (void *)resp, sizeof (autofs_lookupres), hard);
668 if (error) {
669 xdr_free(xdr_autofs_lookupres, (char *)resp);
670 kmem_free(resp, sizeof (*resp));
671 return (error);
674 if (!error) {
675 fngp->fng_verbose = resp->lu_verbose;
676 switch (resp->lu_res) {
677 case AUTOFS_OK:
678 switch (resp->lu_type.action) {
679 case AUTOFS_MOUNT_RQ:
680 lnp->link = NULL;
681 lnp->dir = NULL;
682 *mountreq = TRUE;
683 break;
685 case AUTOFS_LINK_RQ:
686 p = &resp->lu_type.lookup_result_type_u.lt_linka;
687 lnp->dir = kmem_alloc(strlen(p->dir) + 1,
688 KM_SLEEP);
689 (void) strcpy(lnp->dir, p->dir);
690 lnp->link = kmem_alloc(strlen(p->link) + 1,
691 KM_SLEEP);
692 (void) strcpy(lnp->link, p->link);
693 break;
695 case AUTOFS_NONE:
696 lnp->link = NULL;
697 lnp->dir = NULL;
698 break;
700 default:
701 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
702 CE_WARN, "auto_lookup_request: bad action "
703 "type %d", resp->lu_res);
704 error = ENOENT;
706 break;
708 case AUTOFS_NOENT:
709 error = ENOENT;
710 break;
712 default:
713 error = ENOENT;
714 auto_log(fngp->fng_verbose, fngp->fng_zoneid, CE_WARN,
715 "auto_lookup_request: unknown result: %d",
716 resp->lu_res);
717 break;
720 done:
721 xdr_free(xdr_autofs_lookupres, (char *)resp);
722 kmem_free(resp, sizeof (*resp));
723 AUTOFS_DPRINT((5, "auto_lookup_request: path=%s name=%s error=%d\n",
724 fnip->fi_path, key, error));
725 return (error);
728 static int
729 auto_mount_request(
730 fninfo_t *fnip,
731 char *key,
732 action_list **alpp,
733 cred_t *cred,
734 bool_t hard)
736 int error;
737 struct autofs_globals *fngp;
738 autofs_lookupargs reqst;
739 autofs_mountres *xdrres = NULL;
741 AUTOFS_DPRINT((4, "auto_mount_request: path=%s name=%s\n",
742 fnip->fi_path, key));
744 fngp = vntofn(fnip->fi_rootvp)->fn_globals;
745 reqst.map = fnip->fi_map;
746 reqst.path = fnip->fi_path;
748 if (fnip->fi_flags & MF_DIRECT)
749 reqst.name = fnip->fi_key;
750 else
751 reqst.name = key;
753 AUTOFS_DPRINT((4, "auto_mount_request: using key=%s\n", reqst.name));
755 reqst.subdir = fnip->fi_subdir;
756 reqst.opts = fnip->fi_opts;
757 reqst.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE;
758 reqst.uid = crgetuid(cred);
760 xdrres = kmem_zalloc(sizeof (*xdrres), KM_SLEEP);
762 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_MNTINFO,
763 xdr_autofs_lookupargs, &reqst, xdr_autofs_mountres,
764 (void *)xdrres, sizeof (autofs_mountres), hard);
766 if (!error) {
767 fngp->fng_verbose = xdrres->mr_verbose;
768 switch (xdrres->mr_type.status) {
769 case AUTOFS_ACTION:
770 error = 0;
772 * Save the action list since it is used by
773 * the caller. We NULL the action list pointer
774 * in 'result' so that xdr_free() will not free
775 * the list.
777 *alpp = xdrres->mr_type.mount_result_type_u.list;
778 xdrres->mr_type.mount_result_type_u.list = NULL;
779 break;
780 case AUTOFS_DONE:
781 error = xdrres->mr_type.mount_result_type_u.error;
782 break;
783 default:
784 error = ENOENT;
785 auto_log(fngp->fng_verbose, fngp->fng_zoneid, CE_WARN,
786 "auto_mount_request: unknown status %d",
787 xdrres->mr_type.status);
788 break;
792 xdr_free(xdr_autofs_mountres, (char *)xdrres);
793 kmem_free(xdrres, sizeof (*xdrres));
796 AUTOFS_DPRINT((5, "auto_mount_request: path=%s name=%s error=%d\n",
797 fnip->fi_path, key, error));
798 return (error);
802 static int
803 auto_send_unmount_request(
804 fninfo_t *fnip,
805 umntrequest *ul,
806 bool_t hard)
808 int error;
809 umntres xdrres;
811 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
813 AUTOFS_DPRINT((4, "\tauto_send_unmount_request: fstype=%s "
814 " mntpnt=%s\n", ul->fstype, ul->mntpnt));
816 bzero(&xdrres, sizeof (umntres));
817 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_UNMOUNT,
818 xdr_umntrequest, (void *)ul, xdr_umntres, (void *)&xdrres,
819 sizeof (umntres), hard);
821 if (!error)
822 error = xdrres.status;
824 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error));
826 return (error);
829 static int
830 auto_perform_link(fnnode_t *fnp, struct linka *linkp, cred_t *cred)
832 vnode_t *vp;
833 size_t len;
834 char *tmp;
836 AUTOFS_DPRINT((3, "auto_perform_link: fnp=%p dir=%s link=%s\n",
837 (void *)fnp, linkp->dir, linkp->link));
839 len = strlen(linkp->link) + 1; /* include '\0' */
840 tmp = kmem_zalloc(len, KM_SLEEP);
841 (void) kcopy(linkp->link, tmp, len);
842 mutex_enter(&fnp->fn_lock);
843 fnp->fn_symlink = tmp;
844 fnp->fn_symlinklen = (uint_t)len;
845 fnp->fn_flags |= MF_THISUID_MATCH_RQD;
846 crhold(cred);
847 fnp->fn_cred = cred;
848 mutex_exit(&fnp->fn_lock);
850 vp = fntovn(fnp);
851 vp->v_type = VLNK;
853 return (0);
856 static void
857 auto_free_autofs_args(struct mounta *m)
859 autofs_args *aargs = (autofs_args *)m->dataptr;
861 if (aargs->addr.buf)
862 kmem_free(aargs->addr.buf, aargs->addr.len);
863 if (aargs->path)
864 kmem_free(aargs->path, strlen(aargs->path) + 1);
865 if (aargs->opts)
866 kmem_free(aargs->opts, strlen(aargs->opts) + 1);
867 if (aargs->map)
868 kmem_free(aargs->map, strlen(aargs->map) + 1);
869 if (aargs->subdir)
870 kmem_free(aargs->subdir, strlen(aargs->subdir) + 1);
871 if (aargs->key)
872 kmem_free(aargs->key, strlen(aargs->key) + 1);
873 kmem_free(aargs, sizeof (*aargs));
876 static void
877 auto_free_action_list(action_list *alp)
879 struct mounta *m;
880 action_list *lastalp;
881 char *fstype;
883 m = &alp->action.action_list_entry_u.mounta;
884 while (alp != NULL) {
885 fstype = alp->action.action_list_entry_u.mounta.fstype;
886 m = &alp->action.action_list_entry_u.mounta;
887 if (m->dataptr) {
888 if (strcmp(fstype, "autofs") == 0) {
889 auto_free_autofs_args(m);
892 if (m->spec)
893 kmem_free(m->spec, strlen(m->spec) + 1);
894 if (m->dir)
895 kmem_free(m->dir, strlen(m->dir) + 1);
896 if (m->fstype)
897 kmem_free(m->fstype, strlen(m->fstype) + 1);
898 if (m->optptr)
899 kmem_free(m->optptr, m->optlen);
900 lastalp = alp;
901 alp = alp->next;
902 kmem_free(lastalp, sizeof (*lastalp));
906 static boolean_t
907 auto_invalid_autofs(fninfo_t *dfnip, fnnode_t *dfnp, action_list *p)
909 struct mounta *m;
910 struct autofs_args *argsp;
911 vnode_t *dvp;
912 char buff[AUTOFS_MAXPATHLEN];
913 size_t len;
914 struct autofs_globals *fngp;
916 fngp = dfnp->fn_globals;
917 dvp = fntovn(dfnp);
919 m = &p->action.action_list_entry_u.mounta;
921 * Make sure we aren't geting passed NULL values or a "dir" that
922 * isn't "." and doesn't begin with "./".
924 * We also only want to perform autofs mounts, so make sure
925 * no-one is trying to trick us into doing anything else.
927 if (m->spec == NULL || m->dir == NULL || m->dir[0] != '.' ||
928 (m->dir[1] != '/' && m->dir[1] != '\0') ||
929 m->fstype == NULL || strcmp(m->fstype, "autofs") != 0 ||
930 m->dataptr == NULL || m->datalen != sizeof (struct autofs_args) ||
931 m->optptr == NULL)
932 return (B_TRUE);
934 * We also don't like ".."s in the pathname. Symlinks are
935 * handled by the fact that we'll use NOFOLLOW when we do
936 * lookup()s.
938 if (strstr(m->dir, "/../") != NULL ||
939 (len = strlen(m->dir)) > sizeof ("/..") - 1 &&
940 m->dir[len] == '.' && m->dir[len - 1] == '.' &&
941 m->dir[len - 2] == '/')
942 return (B_TRUE);
943 argsp = (struct autofs_args *)m->dataptr;
945 * We don't want NULL values here either.
947 if (argsp->addr.buf == NULL || argsp->path == NULL ||
948 argsp->opts == NULL || argsp->map == NULL || argsp->subdir == NULL)
949 return (B_TRUE);
951 * We know what the claimed pathname *should* look like:
953 * If the parent (dfnp) is a mount point (VROOT), then
954 * the path should be (dfnip->fi_path + m->dir).
956 * Else, we know we're only two levels deep, so we use
957 * (dfnip->fi_path + dfnp->fn_name + m->dir).
959 * Furthermore, "." only makes sense if dfnp is a
960 * trigger node.
962 * At this point it seems like the passed-in path is
963 * redundant.
965 if (dvp->v_flag & VROOT) {
966 if (m->dir[1] == '\0' && !(dfnp->fn_flags & MF_TRIGGER))
967 return (B_TRUE);
968 (void) snprintf(buff, sizeof (buff), "%s%s",
969 dfnip->fi_path, m->dir + 1);
970 } else {
971 (void) snprintf(buff, sizeof (buff), "%s/%s%s",
972 dfnip->fi_path, dfnp->fn_name, m->dir + 1);
974 if (strcmp(argsp->path, buff) != 0) {
975 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
976 CE_WARN, "autofs: expected path of '%s', "
977 "got '%s' instead.", buff, argsp->path);
978 return (B_TRUE);
980 return (B_FALSE); /* looks OK */
984 * auto_invalid_action will validate the action_list received. If all is good
985 * this function returns FALSE, if there is a problem it returns TRUE.
987 static boolean_t
988 auto_invalid_action(fninfo_t *dfnip, fnnode_t *dfnp, action_list *alistpp)
992 * Before we go any further, this better be a mount request.
994 if (alistpp->action.action != AUTOFS_MOUNT_RQ)
995 return (B_TRUE);
996 return (auto_invalid_autofs(dfnip, dfnp, alistpp));
1000 static int
1001 auto_perform_actions(
1002 fninfo_t *dfnip,
1003 fnnode_t *dfnp,
1004 action_list *alp,
1005 cred_t *cred) /* Credentials of the caller */
1008 action_list *p;
1009 struct mounta *m, margs;
1010 struct autofs_args *argsp;
1011 int error, success = 0;
1012 vnode_t *mvp, *dvp, *newvp;
1013 fnnode_t *newfnp, *mfnp;
1014 int auto_mount = 0;
1015 int save_triggers = 0;
1016 int update_times = 0;
1017 char *mntpnt;
1018 char buff[AUTOFS_MAXPATHLEN];
1019 timestruc_t now;
1020 struct autofs_globals *fngp;
1021 cred_t *zcred;
1023 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", (void *)alp));
1025 fngp = dfnp->fn_globals;
1026 dvp = fntovn(dfnp);
1029 * As automountd running in a zone may be compromised, and this may be
1030 * an attack, we can't trust everything passed in by automountd, and we
1031 * need to do argument verification. We'll issue a warning and drop
1032 * the request if it doesn't seem right.
1035 for (p = alp; p != NULL; p = p->next) {
1036 if (auto_invalid_action(dfnip, dfnp, p)) {
1038 * This warning should be sent to the global zone,
1039 * since presumably the zone administrator is the same
1040 * as the attacker.
1042 cmn_err(CE_WARN, "autofs: invalid action list received "
1043 "by automountd in zone %s.",
1044 curproc->p_zone->zone_name);
1046 * This conversation is over.
1048 xdr_free(xdr_action_list, (char *)alp);
1049 return (EINVAL);
1053 zcred = zone_get_kcred(getzoneid());
1054 ASSERT(zcred != NULL);
1056 if (vn_mountedvfs(dvp) != NULL) {
1058 * The daemon successfully mounted a filesystem
1059 * on the AUTOFS root node.
1061 mutex_enter(&dfnp->fn_lock);
1062 dfnp->fn_flags |= MF_MOUNTPOINT;
1063 ASSERT(dfnp->fn_dirents == NULL);
1064 mutex_exit(&dfnp->fn_lock);
1065 success++;
1066 } else {
1068 * Clear MF_MOUNTPOINT.
1070 mutex_enter(&dfnp->fn_lock);
1071 if (dfnp->fn_flags & MF_MOUNTPOINT) {
1072 AUTOFS_DPRINT((10, "autofs: clearing mountpoint "
1073 "flag on %s.", dfnp->fn_name));
1074 ASSERT(dfnp->fn_dirents == NULL);
1075 ASSERT(dfnp->fn_trigger == NULL);
1077 dfnp->fn_flags &= ~MF_MOUNTPOINT;
1078 mutex_exit(&dfnp->fn_lock);
1081 for (p = alp; p != NULL; p = p->next) {
1083 vfs_t *vfsp; /* dummy argument */
1084 vfs_t *mvfsp;
1086 auto_mount = 0;
1088 m = &p->action.action_list_entry_u.mounta;
1089 argsp = (struct autofs_args *)m->dataptr;
1090 ASSERT(strcmp(m->fstype, "autofs") == 0);
1092 * use the parent directory's timeout since it's the
1093 * one specified/inherited by automount.
1095 argsp->mount_to = dfnip->fi_mount_to;
1097 * The mountpoint is relative, and it is guaranteed to
1098 * begin with "."
1101 ASSERT(m->dir[0] == '.');
1102 if (m->dir[0] == '.' && m->dir[1] == '\0') {
1104 * mounting on the trigger node
1106 mvp = dvp;
1107 VN_HOLD(mvp);
1108 goto mount;
1111 * ignore "./" in front of mountpoint
1113 ASSERT(m->dir[1] == '/');
1114 mntpnt = m->dir + 2;
1116 AUTOFS_DPRINT((10, "\tdfnip->fi_path=%s\n", dfnip->fi_path));
1117 AUTOFS_DPRINT((10, "\tdfnip->fi_flags=%x\n", dfnip->fi_flags));
1118 AUTOFS_DPRINT((10, "\tmntpnt=%s\n", mntpnt));
1120 if (dfnip->fi_flags & MF_DIRECT) {
1121 AUTOFS_DPRINT((10, "\tDIRECT\n"));
1122 (void) sprintf(buff, "%s/%s", dfnip->fi_path, mntpnt);
1123 } else {
1124 AUTOFS_DPRINT((10, "\tINDIRECT\n"));
1125 (void) sprintf(buff, "%s/%s/%s",
1126 dfnip->fi_path, dfnp->fn_name, mntpnt);
1129 if (vn_mountedvfs(dvp) == NULL) {
1131 * Daemon didn't mount anything on the root
1132 * We have to create the mountpoint if it
1133 * doesn't exist already
1135 * We use the caller's credentials in case a
1136 * UID-match is required
1137 * (MF_THISUID_MATCH_RQD).
1139 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1140 error = auto_search(dfnp, mntpnt, &mfnp, cred);
1141 if (error == 0) {
1143 * AUTOFS mountpoint exists
1145 if (vn_mountedvfs(fntovn(mfnp)) != NULL) {
1146 cmn_err(CE_PANIC,
1147 "auto_perform_actions:"
1148 " mfnp=%p covered", (void *)mfnp);
1150 } else {
1152 * Create AUTOFS mountpoint
1154 ASSERT((dfnp->fn_flags & MF_MOUNTPOINT) == 0);
1155 error = auto_enter(dfnp, mntpnt, &mfnp, cred);
1156 ASSERT(mfnp->fn_linkcnt == 1);
1157 mfnp->fn_linkcnt++;
1159 if (!error)
1160 update_times = 1;
1161 rw_exit(&dfnp->fn_rwlock);
1162 ASSERT(error != EEXIST);
1163 if (!error) {
1165 * mfnp is already held.
1167 mvp = fntovn(mfnp);
1168 } else {
1169 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
1170 CE_WARN, "autofs: mount of %s "
1171 "failed - can't create"
1172 " mountpoint.", buff);
1173 continue;
1175 } else {
1177 * Find mountpoint in VFS mounted here. If not
1178 * found, fail the submount, though the overall
1179 * mount has succeeded since the root is
1180 * mounted.
1182 if (error = auto_getmntpnt(dvp, mntpnt, &mvp, kcred)) {
1183 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
1184 CE_WARN, "autofs: mount of %s "
1185 "failed - mountpoint doesn't"
1186 " exist.", buff);
1187 continue;
1189 if (mvp->v_type == VLNK) {
1190 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
1191 CE_WARN, "autofs: %s symbolic "
1192 "link: not a valid mountpoint "
1193 "- mount failed", buff);
1194 VN_RELE(mvp);
1195 error = ENOENT;
1196 continue;
1199 mount:
1200 m->flags |= MS_SYSSPACE | MS_OPTIONSTR;
1203 * Copy mounta struct here so we can substitute a
1204 * buffer that is large enough to hold the returned
1205 * option string, if that string is longer than the
1206 * input option string.
1207 * This can happen if there are default options enabled
1208 * that were not in the input option string.
1210 bcopy(m, &margs, sizeof (*m));
1211 margs.optptr = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
1212 margs.optlen = MAX_MNTOPT_STR;
1213 (void) strcpy(margs.optptr, m->optptr);
1214 margs.dir = argsp->path;
1217 * We use the zone's kcred because we don't want the
1218 * zone to be able to thus do something it wouldn't
1219 * normally be able to.
1221 error = domount(NULL, &margs, mvp, zcred, &vfsp);
1222 kmem_free(margs.optptr, MAX_MNTOPT_STR);
1223 if (error != 0) {
1224 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
1225 CE_WARN, "autofs: domount of %s failed "
1226 "error=%d", buff, error);
1227 VN_RELE(mvp);
1228 continue;
1230 VFS_RELE(vfsp);
1233 * If mountpoint is an AUTOFS node, then I'm going to
1234 * flag it that the Filesystem mounted on top was
1235 * mounted in the kernel so that the unmount can be
1236 * done inside the kernel as well.
1237 * I don't care to flag non-AUTOFS mountpoints when an
1238 * AUTOFS in-kernel mount was done on top, because the
1239 * unmount routine already knows that such case was
1240 * done in the kernel.
1242 if (vfs_matchops(dvp->v_vfsp, vfs_getops(mvp->v_vfsp))) {
1243 mfnp = vntofn(mvp);
1244 mutex_enter(&mfnp->fn_lock);
1245 mfnp->fn_flags |= MF_IK_MOUNT;
1246 mutex_exit(&mfnp->fn_lock);
1249 (void) vn_vfswlock_wait(mvp);
1250 mvfsp = vn_mountedvfs(mvp);
1251 if (mvfsp != NULL) {
1252 vfs_lock_wait(mvfsp);
1253 vn_vfsunlock(mvp);
1254 error = VFS_ROOT(mvfsp, &newvp);
1255 vfs_unlock(mvfsp);
1256 if (error) {
1258 * We've dropped the locks, so let's
1259 * get the mounted vfs again in case
1260 * it changed.
1262 (void) vn_vfswlock_wait(mvp);
1263 mvfsp = vn_mountedvfs(mvp);
1264 if (mvfsp != NULL) {
1265 error = dounmount(mvfsp, 0, CRED());
1266 if (error) {
1267 cmn_err(CE_WARN,
1268 "autofs: could not unmount"
1269 " vfs=%p", (void *)mvfsp);
1271 } else
1272 vn_vfsunlock(mvp);
1273 VN_RELE(mvp);
1274 continue;
1276 } else {
1277 vn_vfsunlock(mvp);
1278 VN_RELE(mvp);
1279 continue;
1282 auto_mount = vfs_matchops(dvp->v_vfsp,
1283 vfs_getops(newvp->v_vfsp));
1284 newfnp = vntofn(newvp);
1285 newfnp->fn_parent = dfnp;
1288 * At this time we want to save the AUTOFS filesystem
1289 * as a trigger node. (We only do this if the mount
1290 * occurred on a node different from the root.
1291 * We look at the trigger nodes during
1292 * the automatic unmounting to make sure we remove them
1293 * as a unit and remount them as a unit if the
1294 * filesystem mounted at the root could not be
1295 * unmounted.
1297 if (auto_mount && (error == 0) && (mvp != dvp)) {
1298 save_triggers++;
1300 * Add AUTOFS mount to hierarchy
1302 newfnp->fn_flags |= MF_TRIGGER;
1303 rw_enter(&newfnp->fn_rwlock, RW_WRITER);
1304 newfnp->fn_next = dfnp->fn_trigger;
1305 rw_exit(&newfnp->fn_rwlock);
1306 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1307 dfnp->fn_trigger = newfnp;
1308 rw_exit(&dfnp->fn_rwlock);
1310 * Don't VN_RELE(newvp) here since dfnp now
1311 * holds reference to it as its trigger node.
1313 AUTOFS_DPRINT((10, "\tadding trigger %s to %s\n",
1314 newfnp->fn_name, dfnp->fn_name));
1315 AUTOFS_DPRINT((10, "\tfirst trigger is %s\n",
1316 dfnp->fn_trigger->fn_name));
1317 if (newfnp->fn_next != NULL)
1318 AUTOFS_DPRINT((10, "\tnext trigger is %s\n",
1319 newfnp->fn_next->fn_name));
1320 else
1321 AUTOFS_DPRINT((10, "\tno next trigger\n"));
1322 } else
1323 VN_RELE(newvp);
1325 if (!error)
1326 success++;
1328 if (update_times) {
1329 gethrestime(&now);
1330 dfnp->fn_atime = dfnp->fn_mtime = now;
1333 VN_RELE(mvp);
1336 if (save_triggers) {
1338 * Make sure the parent can't be freed while it has triggers.
1340 VN_HOLD(dvp);
1343 crfree(zcred);
1345 done:
1347 * Return failure if daemon didn't mount anything, and all
1348 * kernel mounts attempted failed.
1350 error = success ? 0 : ENOENT;
1352 if (alp != NULL) {
1353 if ((error == 0) && save_triggers) {
1355 * Save action_list information, so that we can use it
1356 * when it comes time to remount the trigger nodes
1357 * The action list is freed when the directory node
1358 * containing the reference to it is unmounted in
1359 * unmount_tree().
1361 mutex_enter(&dfnp->fn_lock);
1362 ASSERT(dfnp->fn_alp == NULL);
1363 dfnp->fn_alp = alp;
1364 mutex_exit(&dfnp->fn_lock);
1365 } else {
1367 * free the action list now,
1369 xdr_free(xdr_action_list, (char *)alp);
1372 AUTOFS_DPRINT((5, "auto_perform_actions: error=%d\n", error));
1373 return (error);
1376 fnnode_t *
1377 auto_makefnnode(
1378 vtype_t type,
1379 vfs_t *vfsp,
1380 char *name,
1381 cred_t *cred,
1382 struct autofs_globals *fngp)
1384 fnnode_t *fnp;
1385 vnode_t *vp;
1386 char *tmpname;
1387 timestruc_t now;
1389 * autofs uses odd inode numbers
1390 * automountd uses even inode numbers
1392 * To preserve the age-old semantics that inum+devid is unique across
1393 * the system, this variable must be global across zones.
1395 static ino_t nodeid = 3;
1397 fnp = kmem_zalloc(sizeof (*fnp), KM_SLEEP);
1398 fnp->fn_vnode = vn_alloc(KM_SLEEP);
1400 vp = fntovn(fnp);
1401 tmpname = kmem_alloc(strlen(name) + 1, KM_SLEEP);
1402 (void) strcpy(tmpname, name);
1403 fnp->fn_name = &tmpname[0];
1404 fnp->fn_namelen = (int)strlen(tmpname) + 1; /* include '\0' */
1405 fnp->fn_uid = crgetuid(cred);
1406 fnp->fn_gid = crgetgid(cred);
1408 * ".." is added in auto_enter and auto_mount.
1409 * "." is added in auto_mkdir and auto_mount.
1412 * Note that fn_size and fn_linkcnt are already 0 since
1413 * we used kmem_zalloc to allocated fnp
1415 fnp->fn_mode = AUTOFS_MODE;
1416 gethrestime(&now);
1417 fnp->fn_atime = fnp->fn_mtime = fnp->fn_ctime = now;
1418 fnp->fn_ref_time = now.tv_sec;
1419 mutex_enter(&autofs_nodeid_lock);
1420 fnp->fn_nodeid = nodeid;
1421 nodeid += 2;
1422 fnp->fn_globals = fngp;
1423 fngp->fng_fnnode_count++;
1424 mutex_exit(&autofs_nodeid_lock);
1425 vn_setops(vp, &auto_vnodeops);
1426 vp->v_type = type;
1427 vp->v_data = (void *)fnp;
1428 vp->v_vfsp = vfsp;
1429 mutex_init(&fnp->fn_lock, NULL, MUTEX_DEFAULT, NULL);
1430 rw_init(&fnp->fn_rwlock, NULL, RW_DEFAULT, NULL);
1431 cv_init(&fnp->fn_cv_mount, NULL, CV_DEFAULT, NULL);
1432 vn_exists(vp);
1433 return (fnp);
1437 void
1438 auto_freefnnode(fnnode_t *fnp)
1440 vnode_t *vp = fntovn(fnp);
1442 AUTOFS_DPRINT((4, "auto_freefnnode: fnp=%p\n", (void *)fnp));
1444 ASSERT(fnp->fn_linkcnt == 0);
1445 ASSERT(vp->v_count == 0);
1446 ASSERT(fnp->fn_dirents == NULL);
1447 ASSERT(fnp->fn_parent == NULL);
1449 vn_invalid(vp);
1450 kmem_free(fnp->fn_name, fnp->fn_namelen);
1451 if (fnp->fn_symlink) {
1452 ASSERT(fnp->fn_flags & MF_THISUID_MATCH_RQD);
1453 kmem_free(fnp->fn_symlink, fnp->fn_symlinklen);
1455 if (fnp->fn_cred)
1456 crfree(fnp->fn_cred);
1457 mutex_destroy(&fnp->fn_lock);
1458 rw_destroy(&fnp->fn_rwlock);
1459 cv_destroy(&fnp->fn_cv_mount);
1460 vn_free(vp);
1462 mutex_enter(&autofs_nodeid_lock);
1463 fnp->fn_globals->fng_fnnode_count--;
1464 mutex_exit(&autofs_nodeid_lock);
1465 kmem_free(fnp, sizeof (*fnp));
1468 void
1469 auto_disconnect(
1470 fnnode_t *dfnp,
1471 fnnode_t *fnp)
1473 fnnode_t *tmp, **fnpp;
1474 vnode_t *vp = fntovn(fnp);
1475 timestruc_t now;
1477 AUTOFS_DPRINT((4,
1478 "auto_disconnect: dfnp=%p fnp=%p linkcnt=%d\n v_count=%d",
1479 (void *)dfnp, (void *)fnp, fnp->fn_linkcnt, vp->v_count));
1481 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
1482 ASSERT(fnp->fn_linkcnt == 1);
1484 if (vn_mountedvfs(vp) != NULL) {
1485 cmn_err(CE_PANIC, "auto_disconnect: vp %p mounted on",
1486 (void *)vp);
1490 * Decrement by 1 because we're removing the entry in dfnp.
1492 fnp->fn_linkcnt--;
1493 fnp->fn_size--;
1496 * only changed while holding parent's (dfnp) rw_lock
1498 fnp->fn_parent = NULL;
1500 fnpp = &dfnp->fn_dirents;
1501 for (;;) {
1502 tmp = *fnpp;
1503 if (tmp == NULL) {
1504 cmn_err(CE_PANIC,
1505 "auto_disconnect: %p not in %p dirent list",
1506 (void *)fnp, (void *)dfnp);
1508 if (tmp == fnp) {
1509 *fnpp = tmp->fn_next; /* remove it from the list */
1510 ASSERT(vp->v_count == 0);
1511 /* child had a pointer to parent ".." */
1512 dfnp->fn_linkcnt--;
1513 dfnp->fn_size--;
1514 break;
1516 fnpp = &tmp->fn_next;
1519 mutex_enter(&fnp->fn_lock);
1520 gethrestime(&now);
1521 fnp->fn_atime = fnp->fn_mtime = now;
1522 mutex_exit(&fnp->fn_lock);
1524 AUTOFS_DPRINT((5, "auto_disconnect: done\n"));
1528 auto_enter(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1530 struct fnnode *cfnp, **spp;
1531 vnode_t *dvp = fntovn(dfnp);
1532 ushort_t offset = 0;
1533 ushort_t diff;
1535 AUTOFS_DPRINT((4, "auto_enter: dfnp=%p, name=%s ", (void *)dfnp, name));
1537 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
1539 cfnp = dfnp->fn_dirents;
1540 if (cfnp == NULL) {
1542 * offset = 0 for '.' and offset = 1 for '..'
1544 spp = &dfnp->fn_dirents;
1545 offset = 2;
1548 for (; cfnp; cfnp = cfnp->fn_next) {
1549 if (strcmp(cfnp->fn_name, name) == 0) {
1550 mutex_enter(&cfnp->fn_lock);
1551 if (cfnp->fn_flags & MF_THISUID_MATCH_RQD) {
1553 * "thisuser" kind of node, need to
1554 * match CREDs as well
1556 mutex_exit(&cfnp->fn_lock);
1557 if (crcmp(cfnp->fn_cred, cred) == 0)
1558 return (EEXIST);
1559 } else {
1560 mutex_exit(&cfnp->fn_lock);
1561 return (EEXIST);
1565 if (cfnp->fn_next != NULL) {
1566 diff = (ushort_t)
1567 (cfnp->fn_next->fn_offset - cfnp->fn_offset);
1568 ASSERT(diff != 0);
1569 if (diff > 1 && offset == 0) {
1570 offset = (ushort_t)cfnp->fn_offset + 1;
1571 spp = &cfnp->fn_next;
1573 } else if (offset == 0) {
1574 offset = (ushort_t)cfnp->fn_offset + 1;
1575 spp = &cfnp->fn_next;
1579 *fnpp = auto_makefnnode(VDIR, dvp->v_vfsp, name, cred,
1580 dfnp->fn_globals);
1581 if (*fnpp == NULL)
1582 return (ENOMEM);
1585 * I don't hold the mutex on fnpp because I created it, and
1586 * I'm already holding the writers lock for it's parent
1587 * directory, therefore nobody can reference it without me first
1588 * releasing the writers lock.
1590 (*fnpp)->fn_offset = offset;
1591 (*fnpp)->fn_next = *spp;
1592 *spp = *fnpp;
1593 (*fnpp)->fn_parent = dfnp;
1594 (*fnpp)->fn_linkcnt++; /* parent now holds reference to entry */
1595 (*fnpp)->fn_size++;
1598 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock
1600 dfnp->fn_linkcnt++; /* child now holds reference to parent '..' */
1601 dfnp->fn_size++;
1603 dfnp->fn_ref_time = gethrestime_sec();
1605 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp));
1606 return (0);
1610 auto_search(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1612 vnode_t *dvp;
1613 fnnode_t *p;
1614 int error = ENOENT, match = 0;
1616 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n",
1617 (void *)dfnp, name));
1619 dvp = fntovn(dfnp);
1620 if (dvp->v_type != VDIR) {
1621 cmn_err(CE_PANIC, "auto_search: dvp=%p not a directory",
1622 (void *)dvp);
1625 ASSERT(RW_LOCK_HELD(&dfnp->fn_rwlock));
1626 for (p = dfnp->fn_dirents; p != NULL; p = p->fn_next) {
1627 if (strcmp(p->fn_name, name) == 0) {
1628 mutex_enter(&p->fn_lock);
1629 if (p->fn_flags & MF_THISUID_MATCH_RQD) {
1631 * "thisuser" kind of node
1632 * Need to match CREDs as well
1634 mutex_exit(&p->fn_lock);
1635 match = crcmp(p->fn_cred, cred) == 0;
1636 } else {
1638 * No need to check CRED
1640 mutex_exit(&p->fn_lock);
1641 match = 1;
1644 if (match) {
1645 error = 0;
1646 if (fnpp) {
1647 *fnpp = p;
1648 VN_HOLD(fntovn(*fnpp));
1650 break;
1654 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error));
1655 return (error);
1659 * If dvp is mounted on, get path's vnode in the mounted on
1660 * filesystem. Path is relative to dvp, ie "./path".
1661 * If successful, *mvp points to a the held mountpoint vnode.
1663 /* ARGSUSED */
1664 static int
1665 auto_getmntpnt(
1666 vnode_t *dvp,
1667 char *path,
1668 vnode_t **mvpp, /* vnode for mountpoint */
1669 cred_t *cred)
1671 int error = 0;
1672 vnode_t *newvp;
1673 char namebuf[TYPICALMAXPATHLEN];
1674 struct pathname lookpn;
1675 vfs_t *vfsp;
1677 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path));
1679 if (error = vn_vfsrlock_wait(dvp))
1680 return (error);
1683 * Now that we have the vfswlock, check to see if dvp
1684 * is still mounted on. If not, then just bail out as
1685 * there is no need to remount the triggers since the
1686 * higher level mount point has gotten unmounted.
1688 vfsp = vn_mountedvfs(dvp);
1689 if (vfsp == NULL) {
1690 vn_vfsunlock(dvp);
1691 error = EBUSY;
1692 goto done;
1695 * Since mounted on, lookup "path" in the new filesystem,
1696 * it is important that we do the filesystem jump here to
1697 * avoid lookuppn() calling auto_lookup on dvp and deadlock.
1699 error = VFS_ROOT(vfsp, &newvp);
1700 vn_vfsunlock(dvp);
1701 if (error)
1702 goto done;
1705 * We do a VN_HOLD on newvp just in case the first call to
1706 * lookuppnvp() fails with ENAMETOOLONG. We should still have a
1707 * reference to this vnode for the second call to lookuppnvp().
1709 VN_HOLD(newvp);
1712 * Now create the pathname struct so we can make use of lookuppnvp,
1713 * and pn_getcomponent.
1714 * This code is similar to lookupname() in fs/lookup.c.
1716 error = pn_get_buf(path, UIO_SYSSPACE, &lookpn,
1717 namebuf, sizeof (namebuf));
1718 if (error == 0) {
1719 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP,
1720 mvpp, rootdir, newvp, cred);
1721 } else
1722 VN_RELE(newvp);
1723 if (error == ENAMETOOLONG) {
1725 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
1726 * newvp is VN_RELE'd by this call to lookuppnvp.
1728 * Using 'rootdir' in a zone's context is OK here: we already
1729 * ascertained that there are no '..'s in the path, and we're
1730 * not following symlinks.
1732 if ((error = pn_get(path, UIO_SYSSPACE, &lookpn)) == 0) {
1733 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP,
1734 mvpp, rootdir, newvp, cred);
1735 pn_free(&lookpn);
1736 } else
1737 VN_RELE(newvp);
1738 } else {
1740 * Need to release newvp here since we held it.
1742 VN_RELE(newvp);
1745 done:
1746 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n",
1747 path, (void *)*mvpp, error));
1748 return (error);
1751 #define DEEPER(x) (((x)->fn_dirents != NULL) || \
1752 (vn_mountedvfs(fntovn((x)))) != NULL)
1755 * The caller, should have already VN_RELE'd its reference to the
1756 * root vnode of this filesystem.
1758 static int
1759 auto_inkernel_unmount(vfs_t *vfsp)
1761 vnode_t *cvp = vfsp->vfs_vnodecovered;
1762 int error;
1764 AUTOFS_DPRINT((4,
1765 "auto_inkernel_unmount: devid=%lx mntpnt(%p) count %u\n",
1766 vfsp->vfs_dev, (void *)cvp, cvp->v_count));
1768 ASSERT(vn_vfswlock_held(cvp));
1771 * Perform the unmount
1772 * The mountpoint has already been locked by the caller.
1774 error = dounmount(vfsp, 0, kcred);
1776 AUTOFS_DPRINT((5, "auto_inkernel_unmount: exit count %u\n",
1777 cvp->v_count));
1778 return (error);
1782 * unmounts trigger nodes in the kernel.
1784 static void
1785 unmount_triggers(fnnode_t *fnp, action_list **alp)
1787 fnnode_t *tp, *next;
1788 int error = 0;
1789 vfs_t *vfsp;
1790 vnode_t *tvp;
1792 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp));
1793 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1795 *alp = fnp->fn_alp;
1796 next = fnp->fn_trigger;
1797 while ((tp = next) != NULL) {
1798 tvp = fntovn(tp);
1799 ASSERT(tvp->v_count >= 2);
1800 next = tp->fn_next;
1802 * drop writer's lock since the unmount will end up
1803 * disconnecting this node from fnp and needs to acquire
1804 * the writer's lock again.
1805 * next has at least a reference count >= 2 since it's
1806 * a trigger node, therefore can not be accidentally freed
1807 * by a VN_RELE
1809 rw_exit(&fnp->fn_rwlock);
1811 vfsp = tvp->v_vfsp;
1814 * Its parent was holding a reference to it, since this
1815 * is a trigger vnode.
1817 VN_RELE(tvp);
1818 if (error = auto_inkernel_unmount(vfsp)) {
1819 cmn_err(CE_PANIC, "unmount_triggers: "
1820 "unmount of vp=%p failed error=%d",
1821 (void *)tvp, error);
1824 * reacquire writer's lock
1826 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1830 * We were holding a reference to our parent. Drop that.
1832 VN_RELE(fntovn(fnp));
1833 fnp->fn_trigger = NULL;
1834 fnp->fn_alp = NULL;
1836 AUTOFS_DPRINT((5, "unmount_triggers: finished\n"));
1840 * This routine locks the mountpoint of every trigger node if they're
1841 * not busy, or returns EBUSY if any node is busy.
1843 static boolean_t
1844 triggers_busy(fnnode_t *fnp)
1846 int done;
1847 int lck_error = 0;
1848 fnnode_t *tp, *t1p;
1849 vfs_t *vfsp;
1851 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1853 for (tp = fnp->fn_trigger; tp != NULL; tp = tp->fn_next) {
1854 AUTOFS_DPRINT((10, "\ttrigger: %s\n", tp->fn_name));
1855 /* MF_LOOKUP should never be set on trigger nodes */
1856 ASSERT((tp->fn_flags & MF_LOOKUP) == 0);
1857 vfsp = fntovn(tp)->v_vfsp;
1860 * The vn_vfsunlock will be done in auto_inkernel_unmount.
1862 lck_error = vn_vfswlock(vfsp->vfs_vnodecovered);
1864 if (lck_error != 0 || (tp->fn_flags & MF_INPROG) ||
1865 DEEPER(tp) || ((fntovn(tp))->v_count) > 2) {
1867 * couldn't lock it because it's busy,
1868 * It is mounted on or has dirents?
1869 * If reference count is greater than two, then
1870 * somebody else is holding a reference to this vnode.
1871 * One reference is for the mountpoint, and the second
1872 * is for the trigger node.
1874 AUTOFS_DPRINT((10, "\ttrigger busy\n"));
1877 * Unlock previously locked mountpoints
1879 for (done = 0, t1p = fnp->fn_trigger; !done;
1880 t1p = t1p->fn_next) {
1882 * Unlock all nodes previously
1883 * locked. All nodes up to 'tp'
1884 * were successfully locked. If 'lck_err' is
1885 * set, then 'tp' was not locked, and thus
1886 * should not be unlocked. If
1887 * 'lck_err' is not set, then 'tp' was
1888 * successfully locked, and it should
1889 * be unlocked.
1891 if (t1p != tp || !lck_error) {
1892 vfsp = fntovn(t1p)->v_vfsp;
1893 vn_vfsunlock(vfsp->vfs_vnodecovered);
1895 done = (t1p == tp);
1897 return (B_TRUE);
1901 return (B_FALSE);
1905 * It is the caller's responsibility to grab the VVFSLOCK.
1906 * Releases the VVFSLOCK upon return.
1908 static int
1909 unmount_node(vnode_t *cvp, int force)
1911 int error = 0;
1912 fnnode_t *cfnp;
1913 vfs_t *vfsp;
1914 umntrequest ul;
1915 fninfo_t *fnip;
1917 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp));
1919 ASSERT(vn_vfswlock_held(cvp));
1920 cfnp = vntofn(cvp);
1921 vfsp = vn_mountedvfs(cvp);
1923 if (force || cfnp->fn_flags & MF_IK_MOUNT) {
1925 * Mount was performed in the kernel, so
1926 * do an in-kernel unmount. auto_inkernel_unmount()
1927 * will vn_vfsunlock(cvp).
1929 error = auto_inkernel_unmount(vfsp);
1930 } else {
1931 zone_t *zone = NULL;
1932 refstr_t *mntpt, *resource;
1933 size_t mntoptslen;
1936 * Get the mnttab information of the node
1937 * and ask the daemon to unmount it.
1939 bzero(&ul, sizeof (ul));
1940 mntfs_getmntopts(vfsp, &ul.mntopts, &mntoptslen);
1941 if (ul.mntopts == NULL) {
1942 auto_log(cfnp->fn_globals->fng_verbose,
1943 cfnp->fn_globals->fng_zoneid, CE_WARN,
1944 "unmount_node: no memory");
1945 vn_vfsunlock(cvp);
1946 error = ENOMEM;
1947 goto done;
1949 if (mntoptslen > AUTOFS_MAXOPTSLEN)
1950 ul.mntopts[AUTOFS_MAXOPTSLEN - 1] = '\0';
1952 mntpt = vfs_getmntpoint(vfsp);
1953 ul.mntpnt = (char *)refstr_value(mntpt);
1954 resource = vfs_getresource(vfsp);
1955 ul.mntresource = (char *)refstr_value(resource);
1957 fnip = vfstofni(cvp->v_vfsp);
1958 ul.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE;
1961 * Since a zone'd automountd's view of the autofs mount points
1962 * differs from those in the kernel, we need to make sure we
1963 * give it consistent mount points.
1965 ASSERT(fnip->fi_zoneid == getzoneid());
1966 zone = curproc->p_zone;
1968 if (fnip->fi_zoneid != GLOBAL_ZONEID) {
1969 if (ZONE_PATH_VISIBLE(ul.mntpnt, zone)) {
1970 ul.mntpnt =
1971 ZONE_PATH_TRANSLATE(ul.mntpnt, zone);
1973 if (ZONE_PATH_VISIBLE(ul.mntresource, zone)) {
1974 ul.mntresource =
1975 ZONE_PATH_TRANSLATE(ul.mntresource, zone);
1979 ul.fstype = vfssw[vfsp->vfs_fstype].vsw_name;
1980 vn_vfsunlock(cvp);
1982 error = auto_send_unmount_request(fnip, &ul, FALSE);
1983 kmem_free(ul.mntopts, mntoptslen);
1984 refstr_rele(mntpt);
1985 refstr_rele(resource);
1988 done:
1989 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp,
1990 error));
1991 return (error);
1995 * return EBUSY if any thread is holding a reference to this vnode
1996 * other than us. Result of this function cannot be relied on, since
1997 * it doesn't follow proper locking rules (i.e. vp->v_vfsmountedhere
1998 * and fnp->fn_trigger can change throughout this function). However
1999 * it's good enough for rough estimation.
2001 static int
2002 check_auto_node(vnode_t *vp)
2004 fnnode_t *fnp;
2005 int error = 0;
2007 * number of references to expect for
2008 * a non-busy vnode.
2010 uint_t count;
2012 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp));
2013 fnp = vntofn(vp);
2015 count = 1; /* we are holding a reference to vp */
2016 if (fnp->fn_flags & MF_TRIGGER) {
2018 * parent holds a pointer to us (trigger)
2020 count++;
2022 if (fnp->fn_trigger != NULL) {
2024 * The trigger nodes have a hold on us.
2026 count++;
2028 if (vn_ismntpt(vp)) {
2030 * File system is mounted on us.
2032 count++;
2034 mutex_enter(&vp->v_lock);
2035 ASSERT(vp->v_count > 0);
2036 if (vp->v_flag & VROOT)
2037 count++;
2038 AUTOFS_DPRINT((10, "\tcount=%u ", vp->v_count));
2039 if (vp->v_count > count)
2040 error = EBUSY;
2041 mutex_exit(&vp->v_lock);
2043 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error));
2044 return (error);
2048 * rootvp is the root of the AUTOFS filesystem.
2049 * If rootvp is busy (v_count > 1) returns EBUSY.
2050 * else removes every vnode under this tree.
2051 * ASSUMPTION: Assumes that the only node which can be busy is
2052 * the root vnode. This filesystem better be two levels deep only,
2053 * the root and its immediate subdirs.
2054 * The daemon will "AUTOFS direct-mount" only one level below the root.
2056 static void
2057 unmount_autofs(vnode_t *rootvp)
2059 fnnode_t *fnp, *rootfnp, *nfnp;
2061 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp));
2064 * Remove all its immediate subdirectories.
2066 rootfnp = vntofn(rootvp);
2067 rw_enter(&rootfnp->fn_rwlock, RW_WRITER);
2068 for (fnp = rootfnp->fn_dirents; fnp != NULL; fnp = nfnp) {
2069 ASSERT(fntovn(fnp)->v_count == 0);
2070 ASSERT(fnp->fn_dirents == NULL);
2071 ASSERT(fnp->fn_linkcnt == 2);
2072 fnp->fn_linkcnt--;
2073 auto_disconnect(rootfnp, fnp);
2074 nfnp = fnp->fn_next;
2075 auto_freefnnode(fnp);
2077 rw_exit(&rootfnp->fn_rwlock);
2081 * If a node matches all unmount criteria, do:
2082 * destroy subordinate trigger node(s) if there is any
2083 * unmount filesystem mounted on top of the node if there is any
2085 * Function should be called with locked fnp's mutex. The mutex is
2086 * unlocked before return from function.
2088 static int
2089 try_unmount_node(fnnode_t *fnp, boolean_t force)
2091 boolean_t trigger_unmount = B_FALSE;
2092 action_list *alp = NULL;
2093 vnode_t *vp;
2094 int error = 0;
2095 fninfo_t *fnip;
2096 vfs_t *vfsp;
2097 struct autofs_globals *fngp;
2099 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n",
2100 (void *)fnp));
2102 ASSERT(MUTEX_HELD(&fnp->fn_lock));
2104 fngp = fnp->fn_globals;
2105 vp = fntovn(fnp);
2106 fnip = vfstofni(vp->v_vfsp);
2109 * If either a mount, lookup or another unmount of this subtree is in
2110 * progress, don't attempt to unmount at this time.
2112 if (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) {
2113 mutex_exit(&fnp->fn_lock);
2114 return (EBUSY);
2118 * Bail out if someone else is holding reference to this vnode.
2119 * This check isn't just an optimization (someone is probably
2120 * just about to trigger mount). It is necessary to prevent a deadlock
2121 * in domount() called from auto_perform_actions() if unmount of
2122 * trigger parent fails. domount() calls lookupname() to resolve
2123 * special in mount arguments. Special is set to a map name in case
2124 * of autofs triggers (i.e. auto_ws.sun.com). Thus if current
2125 * working directory is set to currently processed node, lookupname()
2126 * calls into autofs vnops in order to resolve special, which deadlocks
2127 * the process.
2129 * Note: This should be fixed. Autofs shouldn't pass the map name
2130 * in special and avoid useless lookup with potentially disasterous
2131 * consequence.
2133 if (check_auto_node(vp) == EBUSY) {
2134 mutex_exit(&fnp->fn_lock);
2135 return (EBUSY);
2139 * If not forced operation, back out if node has been referenced
2140 * recently.
2142 if (!force &&
2143 fnp->fn_ref_time + fnip->fi_mount_to > gethrestime_sec()) {
2144 mutex_exit(&fnp->fn_lock);
2145 return (EBUSY);
2148 /* block mounts/unmounts on the node */
2149 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
2150 fnp->fn_error = 0;
2151 mutex_exit(&fnp->fn_lock);
2153 /* unmount next level triggers if there are any */
2154 rw_enter(&fnp->fn_rwlock, RW_WRITER);
2155 if (fnp->fn_trigger != NULL) {
2156 trigger_unmount = B_TRUE;
2158 if (triggers_busy(fnp)) {
2159 rw_exit(&fnp->fn_rwlock);
2160 mutex_enter(&fnp->fn_lock);
2161 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
2162 mutex_exit(&fnp->fn_lock);
2163 return (EBUSY);
2167 * At this point, we know all trigger nodes are locked,
2168 * and they're not busy or mounted on.
2170 * Attempt to unmount all trigger nodes, save the
2171 * action_list in case we need to remount them later.
2172 * The action_list will be freed later if there was no
2173 * need to remount the trigger nodes.
2175 unmount_triggers(fnp, &alp);
2177 rw_exit(&fnp->fn_rwlock);
2179 (void) vn_vfswlock_wait(vp);
2181 vfsp = vn_mountedvfs(vp);
2182 if (vfsp != NULL) {
2183 /* vn_vfsunlock(vp) is done inside unmount_node() */
2184 error = unmount_node(vp, force);
2185 if (error == ECONNRESET) {
2186 if (vn_mountedvfs(vp) == NULL) {
2188 * The filesystem was unmounted before the
2189 * daemon died. Unfortunately we can not
2190 * determine whether all the cleanup work was
2191 * successfully finished (i.e. update mnttab,
2192 * or notify NFS server of the unmount).
2193 * We should not retry the operation since the
2194 * filesystem has already been unmounted, and
2195 * may have already been removed from mnttab,
2196 * in such case the devid/rdevid we send to
2197 * the daemon will not be matched. So we have
2198 * to be content with the partial unmount.
2199 * Since the mountpoint is no longer covered, we
2200 * clear the error condition.
2202 error = 0;
2203 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
2204 CE_WARN, "autofs: automountd "
2205 "connection dropped when unmounting %s/%s",
2206 fnip->fi_path, (fnip->fi_flags & MF_DIRECT)
2207 ? "" : fnp->fn_name);
2210 } else {
2211 vn_vfsunlock(vp);
2212 /* Destroy all dirents of fnp if we unmounted its triggers */
2213 if (trigger_unmount)
2214 unmount_autofs(vp);
2217 /* If unmount failed, we got to remount triggers */
2218 if (error != 0) {
2219 if (trigger_unmount) {
2220 int ret;
2222 ASSERT((fnp->fn_flags & MF_THISUID_MATCH_RQD) == 0);
2225 * The action list was free'd by auto_perform_actions
2227 ret = auto_perform_actions(fnip, fnp, alp, CRED());
2228 if (ret != 0) {
2229 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
2230 CE_WARN, "autofs: can't remount triggers "
2231 "fnp=%p error=%d", (void *)fnp, ret);
2234 mutex_enter(&fnp->fn_lock);
2235 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
2236 mutex_exit(&fnp->fn_lock);
2237 } else {
2238 /* Free the action list here */
2239 if (trigger_unmount)
2240 xdr_free(xdr_action_list, (char *)alp);
2243 * Other threads may be waiting for this unmount to
2244 * finish. We must let it know that in order to
2245 * proceed, it must trigger the mount itself.
2247 mutex_enter(&fnp->fn_lock);
2248 fnp->fn_flags &= ~MF_IK_MOUNT;
2249 if (fnp->fn_flags & MF_WAITING)
2250 fnp->fn_error = EAGAIN;
2251 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
2252 mutex_exit(&fnp->fn_lock);
2255 return (error);
2259 * This is an implementation of depth-first search in a tree rooted by
2260 * start_fnp and composed from fnnodes. Links between tree levels are
2261 * fn_dirents, fn_trigger in fnnode_t and v_mountedvfs in vnode_t (if
2262 * mounted vfs is autofs). The algorithm keeps track of visited nodes
2263 * by means of a timestamp (fn_unmount_ref_time).
2265 * Upon top-down traversal of the tree we apply following locking scheme:
2266 * lock fn_rwlock of current node
2267 * grab reference to child's vnode (VN_HOLD)
2268 * unlock fn_rwlock
2269 * free reference to current vnode (VN_RELE)
2270 * Similar locking scheme is used for down-top and left-right traversal.
2272 * Algorithm examines the most down-left node in tree, which hasn't been
2273 * visited yet. From this follows that nodes are processed in bottom-up
2274 * fashion.
2276 * Function returns either zero if unmount of root node was successful
2277 * or error code (mostly EBUSY).
2280 unmount_subtree(fnnode_t *rootfnp, boolean_t force)
2282 fnnode_t *currfnp; /* currently examined node in the tree */
2283 fnnode_t *lastfnp; /* previously processed node */
2284 fnnode_t *nextfnp; /* next examined node in the tree */
2285 vnode_t *curvp;
2286 vnode_t *newvp;
2287 vfs_t *vfsp;
2288 time_t timestamp;
2290 ASSERT(fntovn(rootfnp)->v_type != VLNK);
2291 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp,
2292 rootfnp->fn_name));
2295 * Timestamp, which visited nodes are marked with, to distinguish them
2296 * from unvisited nodes.
2298 timestamp = gethrestime_sec();
2299 currfnp = lastfnp = rootfnp;
2301 /* Loop until we examine all nodes in the tree */
2302 mutex_enter(&currfnp->fn_lock);
2303 while (currfnp != rootfnp || rootfnp->fn_unmount_ref_time < timestamp) {
2304 curvp = fntovn(currfnp);
2305 AUTOFS_DPRINT((10, "\tunmount_subtree: entering node %p (%s)\n",
2306 (void *)currfnp, currfnp->fn_name));
2309 * New candidate for processing must have been already visited,
2310 * by us because we want to process tree nodes in bottom-up
2311 * order.
2313 if (currfnp->fn_unmount_ref_time == timestamp &&
2314 currfnp != lastfnp) {
2315 (void) try_unmount_node(currfnp, force);
2316 lastfnp = currfnp;
2317 mutex_enter(&currfnp->fn_lock);
2319 * Fall through to next if-branch to pick
2320 * sibling or parent of this node.
2325 * If this node has been already visited, it means that it's
2326 * dead end and we need to pick sibling or parent as next node.
2328 if (currfnp->fn_unmount_ref_time >= timestamp ||
2329 curvp->v_type == VLNK) {
2330 mutex_exit(&currfnp->fn_lock);
2332 * Obtain parent's readers lock before grabbing
2333 * reference to sibling.
2335 rw_enter(&currfnp->fn_parent->fn_rwlock, RW_READER);
2336 if ((nextfnp = currfnp->fn_next) != NULL) {
2337 VN_HOLD(fntovn(nextfnp));
2338 rw_exit(&currfnp->fn_parent->fn_rwlock);
2339 VN_RELE(curvp);
2340 currfnp = nextfnp;
2341 mutex_enter(&currfnp->fn_lock);
2342 continue;
2344 rw_exit(&currfnp->fn_parent->fn_rwlock);
2347 * All descendants and siblings were visited. Perform
2348 * bottom-up move.
2350 nextfnp = currfnp->fn_parent;
2351 VN_HOLD(fntovn(nextfnp));
2352 VN_RELE(curvp);
2353 currfnp = nextfnp;
2354 mutex_enter(&currfnp->fn_lock);
2355 continue;
2359 * Mark node as visited. Note that the timestamp could have
2360 * been updated by somebody else in the meantime.
2362 if (currfnp->fn_unmount_ref_time < timestamp)
2363 currfnp->fn_unmount_ref_time = timestamp;
2366 * Don't descent below nodes, which are being unmounted/mounted.
2368 * We need to hold both locks at once: fn_lock because we need
2369 * to read MF_INPROG and fn_rwlock to prevent anybody from
2370 * modifying fn_trigger until its used to traverse triggers
2371 * below.
2373 * Acquire fn_rwlock in non-blocking mode to avoid deadlock.
2374 * If it can't be acquired, then acquire locks in correct
2375 * order.
2377 if (!rw_tryenter(&currfnp->fn_rwlock, RW_READER)) {
2378 mutex_exit(&currfnp->fn_lock);
2379 rw_enter(&currfnp->fn_rwlock, RW_READER);
2380 mutex_enter(&currfnp->fn_lock);
2382 if (currfnp->fn_flags & MF_INPROG) {
2383 rw_exit(&currfnp->fn_rwlock);
2384 continue;
2386 mutex_exit(&currfnp->fn_lock);
2389 * Examine descendants in this order: triggers, dirents, autofs
2390 * mounts.
2393 if ((nextfnp = currfnp->fn_trigger) != NULL) {
2394 VN_HOLD(fntovn(nextfnp));
2395 rw_exit(&currfnp->fn_rwlock);
2396 VN_RELE(curvp);
2397 currfnp = nextfnp;
2398 mutex_enter(&currfnp->fn_lock);
2399 continue;
2402 if ((nextfnp = currfnp->fn_dirents) != NULL) {
2403 VN_HOLD(fntovn(nextfnp));
2404 rw_exit(&currfnp->fn_rwlock);
2405 VN_RELE(curvp);
2406 currfnp = nextfnp;
2407 mutex_enter(&currfnp->fn_lock);
2408 continue;
2410 rw_exit(&currfnp->fn_rwlock);
2412 (void) vn_vfswlock_wait(curvp);
2413 vfsp = vn_mountedvfs(curvp);
2414 if (vfsp != NULL &&
2415 vfs_matchops(vfsp, vfs_getops(curvp->v_vfsp))) {
2417 * Deal with /xfn/host/jurassic alikes here...
2419 * We know this call to VFS_ROOT is safe to call while
2420 * holding VVFSLOCK, since it resolves to a call to
2421 * auto_root().
2423 if (VFS_ROOT(vfsp, &newvp)) {
2424 cmn_err(CE_PANIC,
2425 "autofs: VFS_ROOT(vfs=%p) failed",
2426 (void *)vfsp);
2428 vn_vfsunlock(curvp);
2429 VN_RELE(curvp);
2430 currfnp = vntofn(newvp);
2431 mutex_enter(&currfnp->fn_lock);
2432 continue;
2434 vn_vfsunlock(curvp);
2435 mutex_enter(&currfnp->fn_lock);
2439 * Now we deal with the root node (currfnp's mutex is unlocked
2440 * in try_unmount_node()).
2442 return (try_unmount_node(currfnp, force));
2446 * XXX unmount_tree() is not suspend-safe within the scope of
2447 * the present model defined for cpr to suspend the system. Calls made
2448 * by the unmount_tree() that have been identified to be unsafe are
2449 * (1) RPC client handle setup and client calls to automountd which can
2450 * block deep down in the RPC library, (2) kmem_alloc() calls with the
2451 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*() and
2452 * VOP_*() calls which can result in over the wire calls to servers.
2453 * The thread should be completely reevaluated to make it suspend-safe in
2454 * case of future updates to the cpr model.
2456 void
2457 unmount_tree(struct autofs_globals *fngp, boolean_t force)
2459 callb_cpr_t cprinfo;
2460 kmutex_t unmount_tree_cpr_lock;
2461 fnnode_t *root, *fnp, *next;
2463 mutex_init(&unmount_tree_cpr_lock, NULL, MUTEX_DEFAULT, NULL);
2464 CALLB_CPR_INIT(&cprinfo, &unmount_tree_cpr_lock, callb_generic_cpr,
2465 "unmount_tree");
2468 * autofssys() will be calling in from the global zone and doing
2469 * work on the behalf of the given zone, hence we can't always
2470 * assert that we have the right credentials, nor that the
2471 * caller is always in the correct zone.
2473 * We do, however, know that if this is a "forced unmount"
2474 * operation (which autofssys() does), then we won't go down to
2475 * the krpc layers, so we don't need to fudge with the
2476 * credentials.
2478 ASSERT(force || fngp->fng_zoneid == getzoneid());
2481 * If automountd is not running in this zone,
2482 * don't attempt unmounting this round.
2484 if (force || auto_null_request(fngp->fng_zoneid, FALSE) == 0) {
2486 * Iterate over top level autofs filesystems and call
2487 * unmount_subtree() for each of them.
2489 root = fngp->fng_rootfnnodep;
2490 rw_enter(&root->fn_rwlock, RW_READER);
2491 for (fnp = root->fn_dirents; fnp != NULL; fnp = next) {
2492 VN_HOLD(fntovn(fnp));
2493 rw_exit(&root->fn_rwlock);
2494 (void) unmount_subtree(fnp, force);
2495 rw_enter(&root->fn_rwlock, RW_READER);
2496 next = fnp->fn_next;
2497 VN_RELE(fntovn(fnp));
2499 rw_exit(&root->fn_rwlock);
2502 mutex_enter(&unmount_tree_cpr_lock);
2503 CALLB_CPR_EXIT(&cprinfo);
2504 mutex_destroy(&unmount_tree_cpr_lock);
2507 static void
2508 unmount_zone_tree(struct autofs_globals *fngp)
2510 AUTOFS_DPRINT((5, "unmount_zone_tree started. Thread created.\n"));
2512 unmount_tree(fngp, B_FALSE);
2513 mutex_enter(&fngp->fng_unmount_threads_lock);
2514 fngp->fng_unmount_threads--;
2515 mutex_exit(&fngp->fng_unmount_threads_lock);
2517 AUTOFS_DPRINT((5, "unmount_zone_tree done. Thread exiting.\n"));
2519 zthread_exit();
2520 /* NOTREACHED */
2523 void
2524 auto_do_unmount(struct autofs_globals *fngp)
2526 callb_cpr_t cprinfo;
2527 clock_t timeleft;
2528 zone_t *zone = curproc->p_zone;
2530 CALLB_CPR_INIT(&cprinfo, &fngp->fng_unmount_threads_lock,
2531 callb_generic_cpr, "auto_do_unmount");
2533 for (;;) { /* forever */
2534 mutex_enter(&fngp->fng_unmount_threads_lock);
2535 CALLB_CPR_SAFE_BEGIN(&cprinfo);
2536 newthread:
2537 mutex_exit(&fngp->fng_unmount_threads_lock);
2538 timeleft = zone_status_timedwait(zone, ddi_get_lbolt() +
2539 autofs_unmount_thread_timer * hz, ZONE_IS_SHUTTING_DOWN);
2540 mutex_enter(&fngp->fng_unmount_threads_lock);
2542 if (timeleft != -1) { /* didn't time out */
2543 ASSERT(zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN);
2545 * zone is exiting... don't create any new threads.
2546 * fng_unmount_threads_lock is released implicitly by
2547 * the below.
2549 CALLB_CPR_SAFE_END(&cprinfo,
2550 &fngp->fng_unmount_threads_lock);
2551 CALLB_CPR_EXIT(&cprinfo);
2552 zthread_exit();
2553 /* NOTREACHED */
2555 if (fngp->fng_unmount_threads < autofs_unmount_threads) {
2556 fngp->fng_unmount_threads++;
2557 CALLB_CPR_SAFE_END(&cprinfo,
2558 &fngp->fng_unmount_threads_lock);
2559 mutex_exit(&fngp->fng_unmount_threads_lock);
2561 (void) zthread_create(NULL, 0, unmount_zone_tree, fngp,
2562 0, minclsyspri);
2563 } else
2564 goto newthread;
2566 /* NOTREACHED */
2570 * Is nobrowse specified in option string?
2571 * opts should be a null ('\0') terminated string.
2572 * Returns non-zero if nobrowse has been specified.
2575 auto_nobrowse_option(char *opts)
2577 char *buf;
2578 char *p;
2579 char *t;
2580 int nobrowse = 0;
2581 int last_opt = 0;
2582 size_t len;
2584 len = strlen(opts) + 1;
2585 p = buf = kmem_alloc(len, KM_SLEEP);
2586 (void) strcpy(buf, opts);
2587 do {
2588 if (t = strchr(p, ','))
2589 *t++ = '\0';
2590 else
2591 last_opt++;
2592 if (strcmp(p, MNTOPT_NOBROWSE) == 0)
2593 nobrowse = 1;
2594 else if (strcmp(p, MNTOPT_BROWSE) == 0)
2595 nobrowse = 0;
2596 p = t;
2597 } while (!last_opt);
2598 kmem_free(buf, len);
2600 return (nobrowse);
2604 * used to log warnings only if automountd is running
2605 * with verbose mode set
2608 void
2609 auto_log(int verbose, zoneid_t zoneid, int level, const char *fmt, ...)
2611 va_list args;
2613 if (verbose) {
2614 va_start(args, fmt);
2615 vzcmn_err(zoneid, level, fmt, args);
2616 va_end(args);
2620 #ifdef DEBUG
2621 static int autofs_debug = 0;
2624 * Utilities used by both client and server
2625 * Standard levels:
2626 * 0) no debugging
2627 * 1) hard failures
2628 * 2) soft failures
2629 * 3) current test software
2630 * 4) main procedure entry points
2631 * 5) main procedure exit points
2632 * 6) utility procedure entry points
2633 * 7) utility procedure exit points
2634 * 8) obscure procedure entry points
2635 * 9) obscure procedure exit points
2636 * 10) random stuff
2637 * 11) all <= 1
2638 * 12) all <= 2
2639 * 13) all <= 3
2640 * ...
2642 /* PRINTFLIKE2 */
2643 void
2644 auto_dprint(int level, const char *fmt, ...)
2646 va_list args;
2648 if (autofs_debug == level ||
2649 (autofs_debug > 10 && (autofs_debug - 10) >= level)) {
2650 va_start(args, fmt);
2651 (void) vprintf(fmt, args);
2652 va_end(args);
2655 #endif /* DEBUG */