1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
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 <fs/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>
53
54 /*
55 * Autofs and Zones:
56 *
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.
62 *
63 * Each zone has its own "rootfnnode" and associated tree of auto nodes.
64 *
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()).
68 *
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.
72 *
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.
76 */
77 #define TYPICALMAXPATHLEN 64
78
79 static kmutex_t autofs_nodeid_lock;
80
81 /* max number of unmount threads running */
82 static int autofs_unmount_threads = 5;
83 static int autofs_unmount_thread_timer = 120; /* in seconds */
84
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);
93
94 /*
95 * Clears the MF_INPROG flag, and wakes up those threads sleeping on
96 * fn_cv_mount if MF_WAITING is set.
97 */
98 void
auto_unblock_others(fnnode_t * fnp,uint_t operation)99 auto_unblock_others(
100 fnnode_t *fnp,
101 uint_t operation) /* either MF_INPROG or MF_LOOKUP */
102 {
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);
108 }
109 }
110
111 int
auto_wait4mount(fnnode_t * fnp)112 auto_wait4mount(fnnode_t *fnp)
113 {
114 int error;
115 k_sigset_t smask;
116
117 AUTOFS_DPRINT((4, "auto_wait4mount: fnp=%p\n", (void *)fnp));
118
119 mutex_enter(&fnp->fn_lock);
120 while (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) {
121 /*
122 * There is a mount or a lookup in progress.
123 */
124 fnp->fn_flags |= MF_WAITING;
125 sigintr(&smask, 1);
126 if (!cv_wait_sig(&fnp->fn_cv_mount, &fnp->fn_lock)) {
127 /*
128 * Decided not to wait for operation to
129 * finish after all.
130 */
131 sigunintr(&smask);
132 mutex_exit(&fnp->fn_lock);
133 return (EINTR);
134 }
135 sigunintr(&smask);
136 }
137 error = fnp->fn_error;
138
139 if (error == EINTR) {
140 /*
141 * The thread doing the mount got interrupted, we need to
142 * try again, by returning EAGAIN.
143 */
144 error = EAGAIN;
145 }
146 mutex_exit(&fnp->fn_lock);
147
148 AUTOFS_DPRINT((5, "auto_wait4mount: fnp=%p error=%d\n", (void *)fnp,
149 error));
150 return (error);
151 }
152
153 int
auto_lookup_aux(fnnode_t * fnp,char * name,cred_t * cred)154 auto_lookup_aux(fnnode_t *fnp, char *name, cred_t *cred)
155 {
156 struct fninfo *fnip;
157 struct linka link;
158 bool_t mountreq = FALSE;
159 int error = 0;
160
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') {
166 /*
167 * This node should be a symlink
168 */
169 error = auto_perform_link(fnp, &link, cred);
170 } else if (mountreq) {
171 /*
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.
176 */
177 mutex_enter(&fnp->fn_lock);
178 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
179 fnp->fn_error = 0;
180
181 /*
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.
191 */
192 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
193 mutex_exit(&fnp->fn_lock);
194 /*
195 * auto_new_mount_thread fires up a new thread which
196 * calls automountd finishing up the work
197 */
198 auto_new_mount_thread(fnp, name, cred);
199
200 /*
201 * At this point, we are simply another thread
202 * waiting for the mount to complete
203 */
204 error = auto_wait4mount(fnp);
205 if (error == AUTOFS_SHUTDOWN)
206 error = ENOENT;
207 }
208 }
209
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;
216
217 /*
218 * Notify threads waiting for lookup/mount that
219 * it's done.
220 */
221 if (mountreq) {
222 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
223 } else {
224 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
225 }
226 mutex_exit(&fnp->fn_lock);
227 return (error);
228 }
229
230 /*
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.
241 */
242 static void
auto_mount_thread(struct autofs_callargs * argsp)243 auto_mount_thread(struct autofs_callargs *argsp)
244 {
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;
255
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");
259
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);
266
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;
272
273 /*
274 * Notify threads waiting for mount that
275 * it's done.
276 */
277 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
278 mutex_exit(&fnp->fn_lock);
279
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));
285
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 */
291 }
292
293 static int autofs_thr_success = 0;
294
295 /*
296 * Creates new thread which calls auto_mount_thread which does
297 * the bulk of the work calling automountd, via 'auto_perform_actions'.
298 */
299 void
auto_new_mount_thread(fnnode_t * fnp,char * name,cred_t * cred)300 auto_new_mount_thread(fnnode_t *fnp, char *name, cred_t *cred)
301 {
302 struct autofs_callargs *argsp;
303
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;
312
313 (void) zthread_create(NULL, 0, auto_mount_thread, argsp, 0,
314 minclsyspri);
315 autofs_thr_success++;
316 }
317
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;
322
323 /*ARGSUSED*/
324 int
auto_calldaemon(zoneid_t zoneid,int which,xdrproc_t xarg_func,void * argsp,xdrproc_t xresp_func,void * resp,int reslen,bool_t hard)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? */
334 {
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);
350
351 /*
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.
355 */
356 ASSERT(zoneid == getzoneid());
357 if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
358 /*
359 * There's no point in trying to talk to
360 * automountd. Plus, zone_shutdown() is
361 * waiting for us.
362 */
363 return (ECONNREFUSED);
364 }
365
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");
380 }
381 delay(hz);
382 retry = 1;
383 } else {
384 /*
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.
389 */
390 return (ECONNREFUSED);
391 }
392 }
393 } while (retry);
394
395 if (printed_not_running_msg) {
396 fngp->fng_printed_not_running_msg = printed_not_running_msg;
397 }
398
399 ASSERT(fngp != NULL);
400
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;
406
407 if (argsp) {
408 xdrmem_create(&xdrarg, (char *)&xdr_argsp->xdr_arg,
409 xdr_argsp->xdr_len, XDR_ENCODE);
410
411 if (!(*xarg_func)(&xdrarg, argsp)) {
412 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
413 return (EINVAL);
414 }
415 }
416
417 /*
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.
425 */
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);
430
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);
438
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);
444 }
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;
451
452 sigintr(&smask, 1);
453 error =
454 door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
455 sigunintr(&smask);
456
457 door_ki_rele(dh);
458
459 /*
460 * Handle daemon errors
461 */
462 if (!error) {
463 /*
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.
468 */
469 autofs_door_res_t *adr =
470 (autofs_door_res_t *)door_args.rbuf;
471
472 if (door_args.rbuf != NULL) {
473 int nl;
474
475 switch (error = adr->res_status) {
476 case 0: /* no error; continue */
477 break;
478
479 case EOVERFLOW:
480 /*
481 * orig landing buf not big enough.
482 * xdr_len in XDR_BYTES_PER_UNIT
483 */
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;
492 }
493 /*FALLTHROUGH*/
494
495 default:
496 kmem_free(xdr_argsp,
497 xdr_len + sizeof (*xdr_argsp));
498 if (orp)
499 kmem_free(orp, orl);
500 return (error);
501 }
502 }
503 continue;
504 }
505
506 /*
507 * no daemon errors; now process door/comm errors (if any)
508 */
509 switch (error) {
510 case EINTR:
511 /*
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.
515 */
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);
523 }
524 }
525 /*
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.
532 *
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.
537 */
538 if (schedctl_cancel_pending())
539 break;
540 /* FALLTHROUGH */
541 case EAGAIN: /* process may be forking */
542 /*
543 * Back off for a bit
544 */
545 delay(hz);
546 retry = 1;
547 break;
548 case EBADF: /* Invalid door */
549 case EINVAL: /* Not a door, wrong target */
550 /*
551 * A fatal door error, if our failing door
552 * handle is the current door handle, clean
553 * up our state.
554 */
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;
559 }
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");
567 }
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);
578 }
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);
585 }
586 } while (retry);
587
588 if (fngp->fng_printed_not_running_msg == 1) {
589 fngp->fng_printed_not_running_msg = 0;
590 zprintf(zoneid, "automountd OK\n");
591 }
592
593 if (orp && orl) {
594 autofs_door_res_t *door_resp;
595 door_resp = (autofs_door_res_t *)door_args.rbuf;
596
597 if ((void *)door_args.rbuf != orp)
598 kmem_free(orp, orl);
599
600 xdrmem_create(&xdrres, (char *)&door_resp->xdr_res,
601 door_resp->xdr_len, XDR_DECODE);
602
603 if (!((*xresp_func)(&xdrres, resp)))
604 error = EINVAL;
605 kmem_free(door_args.rbuf, door_args.rsize);
606 }
607 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
608 return (error);
609 }
610
611 static int
auto_null_request(zoneid_t zoneid,bool_t hard)612 auto_null_request(zoneid_t zoneid, bool_t hard)
613 {
614 int error;
615
616 AUTOFS_DPRINT((4, "\tauto_null_request\n"));
617
618 error = auto_calldaemon(zoneid, NULLPROC,
619 xdr_void, NULL, xdr_void, NULL, 0, hard);
620
621 AUTOFS_DPRINT((5, "\tauto_null_request: error=%d\n", error));
622 return (error);
623 }
624
625 static int
auto_lookup_request(fninfo_t * fnip,char * key,struct linka * lnp,bool_t hard,bool_t * mountreq,cred_t * cred)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)
633 {
634 int error;
635 struct autofs_globals *fngp;
636 struct autofs_lookupargs reqst;
637 autofs_lookupres *resp;
638 struct linka *p;
639
640
641 AUTOFS_DPRINT((4, "auto_lookup_equest: path=%s name=%s\n",
642 fnip->fi_path, key));
643
644 fngp = vntofn(fnip->fi_rootvp)->fn_globals;
645
646 reqst.map = fnip->fi_map;
647 reqst.path = fnip->fi_path;
648
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));
654
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);
659
660 resp = kmem_zalloc(sizeof (*resp), KM_SLEEP);
661
662 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_LOOKUP,
663 xdr_autofs_lookupargs, &reqst, xdr_autofs_lookupres,
664 (void *)resp, sizeof (autofs_lookupres), hard);
665
666 if (error) {
667 xdr_free(xdr_autofs_lookupres, (char *)resp);
668 kmem_free(resp, sizeof (*resp));
669 return (error);
670 }
671
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;
682
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;
692
693 case AUTOFS_NONE:
694 lnp->link = NULL;
695 lnp->dir = NULL;
696 break;
697
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;
703 }
704 break;
705
706 case AUTOFS_NOENT:
707 error = ENOENT;
708 break;
709
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;
716 }
717 }
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);
724 }
725
726 static int
auto_mount_request(fninfo_t * fnip,char * key,action_list ** alpp,cred_t * cred,bool_t hard)727 auto_mount_request(
728 fninfo_t *fnip,
729 char *key,
730 action_list **alpp,
731 cred_t *cred,
732 bool_t hard)
733 {
734 int error;
735 struct autofs_globals *fngp;
736 autofs_lookupargs reqst;
737 autofs_mountres *xdrres = NULL;
738
739 AUTOFS_DPRINT((4, "auto_mount_request: path=%s name=%s\n",
740 fnip->fi_path, key));
741
742 fngp = vntofn(fnip->fi_rootvp)->fn_globals;
743 reqst.map = fnip->fi_map;
744 reqst.path = fnip->fi_path;
745
746 if (fnip->fi_flags & MF_DIRECT)
747 reqst.name = fnip->fi_key;
748 else
749 reqst.name = key;
750
751 AUTOFS_DPRINT((4, "auto_mount_request: using key=%s\n", reqst.name));
752
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);
757
758 xdrres = kmem_zalloc(sizeof (*xdrres), KM_SLEEP);
759
760 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_MNTINFO,
761 xdr_autofs_lookupargs, &reqst, xdr_autofs_mountres,
762 (void *)xdrres, sizeof (autofs_mountres), hard);
763
764 if (!error) {
765 fngp->fng_verbose = xdrres->mr_verbose;
766 switch (xdrres->mr_type.status) {
767 case AUTOFS_ACTION:
768 error = 0;
769 /*
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.
774 */
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;
787 }
788 }
789
790 xdr_free(xdr_autofs_mountres, (char *)xdrres);
791 kmem_free(xdrres, sizeof (*xdrres));
792
793
794 AUTOFS_DPRINT((5, "auto_mount_request: path=%s name=%s error=%d\n",
795 fnip->fi_path, key, error));
796 return (error);
797 }
798
799
800 static int
auto_send_unmount_request(fninfo_t * fnip,umntrequest * ul,bool_t hard)801 auto_send_unmount_request(
802 fninfo_t *fnip,
803 umntrequest *ul,
804 bool_t hard)
805 {
806 int error;
807 umntres xdrres;
808
809 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
810
811 AUTOFS_DPRINT((4, "\tauto_send_unmount_request: fstype=%s "
812 " mntpnt=%s\n", ul->fstype, ul->mntpnt));
813
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);
818
819 if (!error)
820 error = xdrres.status;
821
822 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error));
823
824 return (error);
825 }
826
827 static int
auto_perform_link(fnnode_t * fnp,struct linka * linkp,cred_t * cred)828 auto_perform_link(fnnode_t *fnp, struct linka *linkp, cred_t *cred)
829 {
830 vnode_t *vp;
831 size_t len;
832 char *tmp;
833
834 AUTOFS_DPRINT((3, "auto_perform_link: fnp=%p dir=%s link=%s\n",
835 (void *)fnp, linkp->dir, linkp->link));
836
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);
847
848 vp = fntovn(fnp);
849 vp->v_type = VLNK;
850
851 return (0);
852 }
853
854 static void
auto_free_autofs_args(struct mounta * m)855 auto_free_autofs_args(struct mounta *m)
856 {
857 autofs_args *aargs = (autofs_args *)m->dataptr;
858
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));
872 }
873
874 static void
auto_free_action_list(action_list * alp)875 auto_free_action_list(action_list *alp)
876 {
877 struct mounta *m;
878 action_list *lastalp;
879 char *fstype;
880
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);
888 }
889 }
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));
901 }
902 }
903
904 static boolean_t
auto_invalid_autofs(fninfo_t * dfnip,fnnode_t * dfnp,action_list * p)905 auto_invalid_autofs(fninfo_t *dfnip, fnnode_t *dfnp, action_list *p)
906 {
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;
913
914 fngp = dfnp->fn_globals;
915 dvp = fntovn(dfnp);
916
917 m = &p->action.action_list_entry_u.mounta;
918 /*
919 * Make sure we aren't geting passed NULL values or a "dir" that
920 * isn't "." and doesn't begin with "./".
921 *
922 * We also only want to perform autofs mounts, so make sure
923 * no-one is trying to trick us into doing anything else.
924 */
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);
931 /*
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.
935 */
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;
942 /*
943 * We don't want NULL values here either.
944 */
945 if (argsp->addr.buf == NULL || argsp->path == NULL ||
946 argsp->opts == NULL || argsp->map == NULL || argsp->subdir == NULL)
947 return (B_TRUE);
948 /*
949 * We know what the claimed pathname *should* look like:
950 *
951 * If the parent (dfnp) is a mount point (VROOT), then
952 * the path should be (dfnip->fi_path + m->dir).
953 *
954 * Else, we know we're only two levels deep, so we use
955 * (dfnip->fi_path + dfnp->fn_name + m->dir).
956 *
957 * Furthermore, "." only makes sense if dfnp is a
958 * trigger node.
959 *
960 * At this point it seems like the passed-in path is
961 * redundant.
962 */
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);
971 }
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);
977 }
978 return (B_FALSE); /* looks OK */
979 }
980
981 /*
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.
984 */
985 static boolean_t
auto_invalid_action(fninfo_t * dfnip,fnnode_t * dfnp,action_list * alistpp)986 auto_invalid_action(fninfo_t *dfnip, fnnode_t *dfnp, action_list *alistpp)
987 {
988
989 /*
990 * Before we go any further, this better be a mount request.
991 */
992 if (alistpp->action.action != AUTOFS_MOUNT_RQ)
993 return (B_TRUE);
994 return (auto_invalid_autofs(dfnip, dfnp, alistpp));
995
996 }
997
998 static int
auto_perform_actions(fninfo_t * dfnip,fnnode_t * dfnp,action_list * alp,cred_t * cred)999 auto_perform_actions(
1000 fninfo_t *dfnip,
1001 fnnode_t *dfnp,
1002 action_list *alp,
1003 cred_t *cred) /* Credentials of the caller */
1004 {
1005
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;
1020
1021 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", (void *)alp));
1022
1023 fngp = dfnp->fn_globals;
1024 dvp = fntovn(dfnp);
1025
1026 /*
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.
1031 */
1032
1033 for (p = alp; p != NULL; p = p->next) {
1034 if (auto_invalid_action(dfnip, dfnp, p)) {
1035 /*
1036 * This warning should be sent to the global zone,
1037 * since presumably the zone administrator is the same
1038 * as the attacker.
1039 */
1040 cmn_err(CE_WARN, "autofs: invalid action list received "
1041 "by automountd in zone %s.",
1042 curproc->p_zone->zone_name);
1043 /*
1044 * This conversation is over.
1045 */
1046 xdr_free(xdr_action_list, (char *)alp);
1047 return (EINVAL);
1048 }
1049 }
1050
1051 zcred = zone_get_kcred(getzoneid());
1052 ASSERT(zcred != NULL);
1053
1054 if (vn_mountedvfs(dvp) != NULL) {
1055 /*
1056 * The daemon successfully mounted a filesystem
1057 * on the AUTOFS root node.
1058 */
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 {
1065 /*
1066 * Clear MF_MOUNTPOINT.
1067 */
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);
1074 }
1075 dfnp->fn_flags &= ~MF_MOUNTPOINT;
1076 mutex_exit(&dfnp->fn_lock);
1077 }
1078
1079 for (p = alp; p != NULL; p = p->next) {
1080
1081 vfs_t *vfsp; /* dummy argument */
1082 vfs_t *mvfsp;
1083
1084 auto_mount = 0;
1085
1086 m = &p->action.action_list_entry_u.mounta;
1087 argsp = (struct autofs_args *)m->dataptr;
1088 ASSERT(strcmp(m->fstype, "autofs") == 0);
1089 /*
1090 * use the parent directory's timeout since it's the
1091 * one specified/inherited by automount.
1092 */
1093 argsp->mount_to = dfnip->fi_mount_to;
1094 /*
1095 * The mountpoint is relative, and it is guaranteed to
1096 * begin with "."
1097 *
1098 */
1099 ASSERT(m->dir[0] == '.');
1100 if (m->dir[0] == '.' && m->dir[1] == '\0') {
1101 /*
1102 * mounting on the trigger node
1103 */
1104 mvp = dvp;
1105 VN_HOLD(mvp);
1106 goto mount;
1107 }
1108 /*
1109 * ignore "./" in front of mountpoint
1110 */
1111 ASSERT(m->dir[1] == '/');
1112 mntpnt = m->dir + 2;
1113
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));
1117
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);
1125 }
1126
1127 if (vn_mountedvfs(dvp) == NULL) {
1128 /*
1129 * Daemon didn't mount anything on the root
1130 * We have to create the mountpoint if it
1131 * doesn't exist already
1132 *
1133 * We use the caller's credentials in case a
1134 * UID-match is required
1135 * (MF_THISUID_MATCH_RQD).
1136 */
1137 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1138 error = auto_search(dfnp, mntpnt, &mfnp, cred);
1139 if (error == 0) {
1140 /*
1141 * AUTOFS mountpoint exists
1142 */
1143 if (vn_mountedvfs(fntovn(mfnp)) != NULL) {
1144 cmn_err(CE_PANIC,
1145 "auto_perform_actions:"
1146 " mfnp=%p covered", (void *)mfnp);
1147 }
1148 } else {
1149 /*
1150 * Create AUTOFS mountpoint
1151 */
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++;
1156 }
1157 if (!error)
1158 update_times = 1;
1159 rw_exit(&dfnp->fn_rwlock);
1160 ASSERT(error != EEXIST);
1161 if (!error) {
1162 /*
1163 * mfnp is already held.
1164 */
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;
1172 }
1173 } else {
1174 /*
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.
1179 */
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;
1186 }
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;
1195 }
1196 }
1197 mount:
1198 m->flags |= MS_SYSSPACE | MS_OPTIONSTR;
1199
1200 /*
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.
1207 */
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;
1213
1214 /*
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.
1218 */
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;
1227 }
1228 VFS_RELE(vfsp);
1229
1230 /*
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.
1239 */
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);
1245 }
1246
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) {
1255 /*
1256 * We've dropped the locks, so let's
1257 * get the mounted vfs again in case
1258 * it changed.
1259 */
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);
1268 }
1269 } else
1270 vn_vfsunlock(mvp);
1271 VN_RELE(mvp);
1272 continue;
1273 }
1274 } else {
1275 vn_vfsunlock(mvp);
1276 VN_RELE(mvp);
1277 continue;
1278 }
1279
1280 auto_mount = vfs_matchops(dvp->v_vfsp,
1281 vfs_getops(newvp->v_vfsp));
1282 newfnp = vntofn(newvp);
1283 newfnp->fn_parent = dfnp;
1284
1285 /*
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.
1294 */
1295 if (auto_mount && (error == 0) && (mvp != dvp)) {
1296 save_triggers++;
1297 /*
1298 * Add AUTOFS mount to hierarchy
1299 */
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);
1307 /*
1308 * Don't VN_RELE(newvp) here since dfnp now
1309 * holds reference to it as its trigger node.
1310 */
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);
1322
1323 if (!error)
1324 success++;
1325
1326 if (update_times) {
1327 gethrestime(&now);
1328 dfnp->fn_atime = dfnp->fn_mtime = now;
1329 }
1330
1331 VN_RELE(mvp);
1332 }
1333
1334 if (save_triggers) {
1335 /*
1336 * Make sure the parent can't be freed while it has triggers.
1337 */
1338 VN_HOLD(dvp);
1339 }
1340
1341 crfree(zcred);
1342
1343 done:
1344 /*
1345 * Return failure if daemon didn't mount anything, and all
1346 * kernel mounts attempted failed.
1347 */
1348 error = success ? 0 : ENOENT;
1349
1350 if (alp != NULL) {
1351 if ((error == 0) && save_triggers) {
1352 /*
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().
1358 */
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 {
1364 /*
1365 * free the action list now,
1366 */
1367 xdr_free(xdr_action_list, (char *)alp);
1368 }
1369 }
1370 AUTOFS_DPRINT((5, "auto_perform_actions: error=%d\n", error));
1371 return (error);
1372 }
1373
1374 fnnode_t *
auto_makefnnode(vtype_t type,vfs_t * vfsp,char * name,cred_t * cred,struct autofs_globals * fngp)1375 auto_makefnnode(
1376 vtype_t type,
1377 vfs_t *vfsp,
1378 char *name,
1379 cred_t *cred,
1380 struct autofs_globals *fngp)
1381 {
1382 fnnode_t *fnp;
1383 vnode_t *vp;
1384 char *tmpname;
1385 timestruc_t now;
1386 /*
1387 * autofs uses odd inode numbers
1388 * automountd uses even inode numbers
1389 *
1390 * To preserve the age-old semantics that inum+devid is unique across
1391 * the system, this variable must be global across zones.
1392 */
1393 static ino_t nodeid = 3;
1394
1395 fnp = kmem_zalloc(sizeof (*fnp), KM_SLEEP);
1396 fnp->fn_vnode = vn_alloc(KM_SLEEP);
1397
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);
1405 /*
1406 * ".." is added in auto_enter and auto_mount.
1407 * "." is added in auto_mkdir and auto_mount.
1408 */
1409 /*
1410 * Note that fn_size and fn_linkcnt are already 0 since
1411 * we used kmem_zalloc to allocated fnp
1412 */
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);
1432 }
1433
1434
1435 void
auto_freefnnode(fnnode_t * fnp)1436 auto_freefnnode(fnnode_t *fnp)
1437 {
1438 vnode_t *vp = fntovn(fnp);
1439
1440 AUTOFS_DPRINT((4, "auto_freefnnode: fnp=%p\n", (void *)fnp));
1441
1442 ASSERT(fnp->fn_linkcnt == 0);
1443 ASSERT(vp->v_count == 0);
1444 ASSERT(fnp->fn_dirents == NULL);
1445 ASSERT(fnp->fn_parent == NULL);
1446
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);
1452 }
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);
1459
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));
1464 }
1465
1466 void
auto_disconnect(fnnode_t * dfnp,fnnode_t * fnp)1467 auto_disconnect(
1468 fnnode_t *dfnp,
1469 fnnode_t *fnp)
1470 {
1471 fnnode_t *tmp, **fnpp;
1472 vnode_t *vp = fntovn(fnp);
1473 timestruc_t now;
1474
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));
1478
1479 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
1480 ASSERT(fnp->fn_linkcnt == 1);
1481
1482 if (vn_mountedvfs(vp) != NULL) {
1483 cmn_err(CE_PANIC, "auto_disconnect: vp %p mounted on",
1484 (void *)vp);
1485 }
1486
1487 /*
1488 * Decrement by 1 because we're removing the entry in dfnp.
1489 */
1490 fnp->fn_linkcnt--;
1491 fnp->fn_size--;
1492
1493 /*
1494 * only changed while holding parent's (dfnp) rw_lock
1495 */
1496 fnp->fn_parent = NULL;
1497
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);
1505 }
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;
1513 }
1514 fnpp = &tmp->fn_next;
1515 }
1516
1517 mutex_enter(&fnp->fn_lock);
1518 gethrestime(&now);
1519 fnp->fn_atime = fnp->fn_mtime = now;
1520 mutex_exit(&fnp->fn_lock);
1521
1522 AUTOFS_DPRINT((5, "auto_disconnect: done\n"));
1523 }
1524
1525 int
auto_enter(fnnode_t * dfnp,char * name,fnnode_t ** fnpp,cred_t * cred)1526 auto_enter(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1527 {
1528 struct fnnode *cfnp, **spp;
1529 vnode_t *dvp = fntovn(dfnp);
1530 ushort_t offset = 0;
1531 ushort_t diff;
1532
1533 AUTOFS_DPRINT((4, "auto_enter: dfnp=%p, name=%s ", (void *)dfnp, name));
1534
1535 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
1536
1537 cfnp = dfnp->fn_dirents;
1538 if (cfnp == NULL) {
1539 /*
1540 * offset = 0 for '.' and offset = 1 for '..'
1541 */
1542 spp = &dfnp->fn_dirents;
1543 offset = 2;
1544 }
1545
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) {
1550 /*
1551 * "thisuser" kind of node, need to
1552 * match CREDs as well
1553 */
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);
1560 }
1561 }
1562
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;
1570 }
1571 } else if (offset == 0) {
1572 offset = (ushort_t)cfnp->fn_offset + 1;
1573 spp = &cfnp->fn_next;
1574 }
1575 }
1576
1577 *fnpp = auto_makefnnode(VDIR, dvp->v_vfsp, name, cred,
1578 dfnp->fn_globals);
1579 if (*fnpp == NULL)
1580 return (ENOMEM);
1581
1582 /*
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.
1587 */
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++;
1594
1595 /*
1596 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock
1597 */
1598 dfnp->fn_linkcnt++; /* child now holds reference to parent '..' */
1599 dfnp->fn_size++;
1600
1601 dfnp->fn_ref_time = gethrestime_sec();
1602
1603 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp));
1604 return (0);
1605 }
1606
1607 int
auto_search(fnnode_t * dfnp,char * name,fnnode_t ** fnpp,cred_t * cred)1608 auto_search(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1609 {
1610 vnode_t *dvp;
1611 fnnode_t *p;
1612 int error = ENOENT, match = 0;
1613
1614 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n",
1615 (void *)dfnp, name));
1616
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);
1621 }
1622
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) {
1628 /*
1629 * "thisuser" kind of node
1630 * Need to match CREDs as well
1631 */
1632 mutex_exit(&p->fn_lock);
1633 match = crcmp(p->fn_cred, cred) == 0;
1634 } else {
1635 /*
1636 * No need to check CRED
1637 */
1638 mutex_exit(&p->fn_lock);
1639 match = 1;
1640 }
1641 }
1642 if (match) {
1643 error = 0;
1644 if (fnpp) {
1645 *fnpp = p;
1646 VN_HOLD(fntovn(*fnpp));
1647 }
1648 break;
1649 }
1650 }
1651
1652 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error));
1653 return (error);
1654 }
1655
1656 /*
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.
1660 */
1661 /* ARGSUSED */
1662 static int
auto_getmntpnt(vnode_t * dvp,char * path,vnode_t ** mvpp,cred_t * cred)1663 auto_getmntpnt(
1664 vnode_t *dvp,
1665 char *path,
1666 vnode_t **mvpp, /* vnode for mountpoint */
1667 cred_t *cred)
1668 {
1669 int error = 0;
1670 vnode_t *newvp;
1671 char namebuf[TYPICALMAXPATHLEN];
1672 struct pathname lookpn;
1673 vfs_t *vfsp;
1674
1675 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path));
1676
1677 if (error = vn_vfsrlock_wait(dvp))
1678 return (error);
1679
1680 /*
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.
1685 */
1686 vfsp = vn_mountedvfs(dvp);
1687 if (vfsp == NULL) {
1688 vn_vfsunlock(dvp);
1689 error = EBUSY;
1690 goto done;
1691 }
1692 /*
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.
1696 */
1697 error = VFS_ROOT(vfsp, &newvp);
1698 vn_vfsunlock(dvp);
1699 if (error)
1700 goto done;
1701
1702 /*
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().
1706 */
1707 VN_HOLD(newvp);
1708
1709 /*
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.
1713 */
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) {
1722 /*
1723 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
1724 * newvp is VN_RELE'd by this call to lookuppnvp.
1725 *
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.
1729 */
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 {
1737 /*
1738 * Need to release newvp here since we held it.
1739 */
1740 VN_RELE(newvp);
1741 }
1742
1743 done:
1744 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n",
1745 path, (void *)*mvpp, error));
1746 return (error);
1747 }
1748
1749 #define DEEPER(x) (((x)->fn_dirents != NULL) || \
1750 (vn_mountedvfs(fntovn((x)))) != NULL)
1751
1752 /*
1753 * The caller, should have already VN_RELE'd its reference to the
1754 * root vnode of this filesystem.
1755 */
1756 static int
auto_inkernel_unmount(vfs_t * vfsp)1757 auto_inkernel_unmount(vfs_t *vfsp)
1758 {
1759 vnode_t *cvp = vfsp->vfs_vnodecovered;
1760 int error;
1761
1762 AUTOFS_DPRINT((4,
1763 "auto_inkernel_unmount: devid=%lx mntpnt(%p) count %u\n",
1764 vfsp->vfs_dev, (void *)cvp, cvp->v_count));
1765
1766 ASSERT(vn_vfswlock_held(cvp));
1767
1768 /*
1769 * Perform the unmount
1770 * The mountpoint has already been locked by the caller.
1771 */
1772 error = dounmount(vfsp, 0, kcred);
1773
1774 AUTOFS_DPRINT((5, "auto_inkernel_unmount: exit count %u\n",
1775 cvp->v_count));
1776 return (error);
1777 }
1778
1779 /*
1780 * unmounts trigger nodes in the kernel.
1781 */
1782 static void
unmount_triggers(fnnode_t * fnp,action_list ** alp)1783 unmount_triggers(fnnode_t *fnp, action_list **alp)
1784 {
1785 fnnode_t *tp, *next;
1786 int error = 0;
1787 vfs_t *vfsp;
1788 vnode_t *tvp;
1789
1790 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp));
1791 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1792
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;
1799 /*
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
1806 */
1807 rw_exit(&fnp->fn_rwlock);
1808
1809 vfsp = tvp->v_vfsp;
1810
1811 /*
1812 * Its parent was holding a reference to it, since this
1813 * is a trigger vnode.
1814 */
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);
1820 }
1821 /*
1822 * reacquire writer's lock
1823 */
1824 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1825 }
1826
1827 /*
1828 * We were holding a reference to our parent. Drop that.
1829 */
1830 VN_RELE(fntovn(fnp));
1831 fnp->fn_trigger = NULL;
1832 fnp->fn_alp = NULL;
1833
1834 AUTOFS_DPRINT((5, "unmount_triggers: finished\n"));
1835 }
1836
1837 /*
1838 * This routine locks the mountpoint of every trigger node if they're
1839 * not busy, or returns EBUSY if any node is busy.
1840 */
1841 static boolean_t
triggers_busy(fnnode_t * fnp)1842 triggers_busy(fnnode_t *fnp)
1843 {
1844 int done;
1845 int lck_error = 0;
1846 fnnode_t *tp, *t1p;
1847 vfs_t *vfsp;
1848
1849 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1850
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;
1856
1857 /*
1858 * The vn_vfsunlock will be done in auto_inkernel_unmount.
1859 */
1860 lck_error = vn_vfswlock(vfsp->vfs_vnodecovered);
1861
1862 if (lck_error != 0 || (tp->fn_flags & MF_INPROG) ||
1863 DEEPER(tp) || ((fntovn(tp))->v_count) > 2) {
1864 /*
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.
1871 */
1872 AUTOFS_DPRINT((10, "\ttrigger busy\n"));
1873
1874 /*
1875 * Unlock previously locked mountpoints
1876 */
1877 for (done = 0, t1p = fnp->fn_trigger; !done;
1878 t1p = t1p->fn_next) {
1879 /*
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.
1888 */
1889 if (t1p != tp || !lck_error) {
1890 vfsp = fntovn(t1p)->v_vfsp;
1891 vn_vfsunlock(vfsp->vfs_vnodecovered);
1892 }
1893 done = (t1p == tp);
1894 }
1895 return (B_TRUE);
1896 }
1897 }
1898
1899 return (B_FALSE);
1900 }
1901
1902 /*
1903 * It is the caller's responsibility to grab the VVFSLOCK.
1904 * Releases the VVFSLOCK upon return.
1905 */
1906 static int
unmount_node(vnode_t * cvp,int force)1907 unmount_node(vnode_t *cvp, int force)
1908 {
1909 int error = 0;
1910 fnnode_t *cfnp;
1911 vfs_t *vfsp;
1912 umntrequest ul;
1913 fninfo_t *fnip;
1914
1915 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp));
1916
1917 ASSERT(vn_vfswlock_held(cvp));
1918 cfnp = vntofn(cvp);
1919 vfsp = vn_mountedvfs(cvp);
1920
1921 if (force || cfnp->fn_flags & MF_IK_MOUNT) {
1922 /*
1923 * Mount was performed in the kernel, so
1924 * do an in-kernel unmount. auto_inkernel_unmount()
1925 * will vn_vfsunlock(cvp).
1926 */
1927 error = auto_inkernel_unmount(vfsp);
1928 } else {
1929 zone_t *zone = NULL;
1930 refstr_t *mntpt, *resource;
1931 size_t mntoptslen;
1932
1933 /*
1934 * Get the mnttab information of the node
1935 * and ask the daemon to unmount it.
1936 */
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;
1946 }
1947 if (mntoptslen > AUTOFS_MAXOPTSLEN)
1948 ul.mntopts[AUTOFS_MAXOPTSLEN - 1] = '\0';
1949
1950 mntpt = vfs_getmntpoint(vfsp);
1951 ul.mntpnt = (char *)refstr_value(mntpt);
1952 resource = vfs_getresource(vfsp);
1953 ul.mntresource = (char *)refstr_value(resource);
1954
1955 fnip = vfstofni(cvp->v_vfsp);
1956 ul.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE;
1957
1958 /*
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.
1962 */
1963 ASSERT(fnip->fi_zoneid == getzoneid());
1964 zone = curproc->p_zone;
1965
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);
1970 }
1971 if (ZONE_PATH_VISIBLE(ul.mntresource, zone)) {
1972 ul.mntresource =
1973 ZONE_PATH_TRANSLATE(ul.mntresource, zone);
1974 }
1975 }
1976
1977 ul.fstype = vfssw[vfsp->vfs_fstype].vsw_name;
1978 vn_vfsunlock(cvp);
1979
1980 error = auto_send_unmount_request(fnip, &ul, FALSE);
1981 kmem_free(ul.mntopts, mntoptslen);
1982 refstr_rele(mntpt);
1983 refstr_rele(resource);
1984 }
1985
1986 done:
1987 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp,
1988 error));
1989 return (error);
1990 }
1991
1992 /*
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.
1998 */
1999 static int
check_auto_node(vnode_t * vp)2000 check_auto_node(vnode_t *vp)
2001 {
2002 fnnode_t *fnp;
2003 int error = 0;
2004 /*
2005 * number of references to expect for
2006 * a non-busy vnode.
2007 */
2008 uint_t count;
2009
2010 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp));
2011 fnp = vntofn(vp);
2012
2013 count = 1; /* we are holding a reference to vp */
2014 if (fnp->fn_flags & MF_TRIGGER) {
2015 /*
2016 * parent holds a pointer to us (trigger)
2017 */
2018 count++;
2019 }
2020 if (fnp->fn_trigger != NULL) {
2021 /*
2022 * The trigger nodes have a hold on us.
2023 */
2024 count++;
2025 }
2026 if (vn_ismntpt(vp)) {
2027 /*
2028 * File system is mounted on us.
2029 */
2030 count++;
2031 }
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);
2040
2041 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error));
2042 return (error);
2043 }
2044
2045 /*
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.
2053 */
2054 static void
unmount_autofs(vnode_t * rootvp)2055 unmount_autofs(vnode_t *rootvp)
2056 {
2057 fnnode_t *fnp, *rootfnp, *nfnp;
2058
2059 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp));
2060
2061 /*
2062 * Remove all its immediate subdirectories.
2063 */
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);
2074 }
2075 rw_exit(&rootfnp->fn_rwlock);
2076 }
2077
2078 /*
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
2082 *
2083 * Function should be called with locked fnp's mutex. The mutex is
2084 * unlocked before return from function.
2085 */
2086 static int
try_unmount_node(fnnode_t * fnp,boolean_t force)2087 try_unmount_node(fnnode_t *fnp, boolean_t force)
2088 {
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;
2096
2097 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n",
2098 (void *)fnp));
2099
2100 ASSERT(MUTEX_HELD(&fnp->fn_lock));
2101
2102 fngp = fnp->fn_globals;
2103 vp = fntovn(fnp);
2104 fnip = vfstofni(vp->v_vfsp);
2105
2106 /*
2107 * If either a mount, lookup or another unmount of this subtree is in
2108 * progress, don't attempt to unmount at this time.
2109 */
2110 if (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) {
2111 mutex_exit(&fnp->fn_lock);
2112 return (EBUSY);
2113 }
2114
2115 /*
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.
2126 *
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.
2130 */
2131 if (check_auto_node(vp) == EBUSY) {
2132 mutex_exit(&fnp->fn_lock);
2133 return (EBUSY);
2134 }
2135
2136 /*
2137 * If not forced operation, back out if node has been referenced
2138 * recently.
2139 */
2140 if (!force &&
2141 fnp->fn_ref_time + fnip->fi_mount_to > gethrestime_sec()) {
2142 mutex_exit(&fnp->fn_lock);
2143 return (EBUSY);
2144 }
2145
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);
2150
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;
2155
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);
2162 }
2163
2164 /*
2165 * At this point, we know all trigger nodes are locked,
2166 * and they're not busy or mounted on.
2167 *
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.
2172 */
2173 unmount_triggers(fnp, &alp);
2174 }
2175 rw_exit(&fnp->fn_rwlock);
2176
2177 (void) vn_vfswlock_wait(vp);
2178
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) {
2185 /*
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.
2199 */
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);
2206 }
2207 }
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);
2213 }
2214
2215 /* If unmount failed, we got to remount triggers */
2216 if (error != 0) {
2217 if (trigger_unmount) {
2218 int ret;
2219
2220 ASSERT((fnp->fn_flags & MF_THISUID_MATCH_RQD) == 0);
2221
2222 /*
2223 * The action list was free'd by auto_perform_actions
2224 */
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);
2230 }
2231 }
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);
2239
2240 /*
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.
2244 */
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);
2251 }
2252
2253 return (error);
2254 }
2255
2256 /*
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).
2262 *
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.
2269 *
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.
2273 *
2274 * Function returns either zero if unmount of root node was successful
2275 * or error code (mostly EBUSY).
2276 */
2277 int
unmount_subtree(fnnode_t * rootfnp,boolean_t force)2278 unmount_subtree(fnnode_t *rootfnp, boolean_t force)
2279 {
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;
2287
2288 ASSERT(fntovn(rootfnp)->v_type != VLNK);
2289 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp,
2290 rootfnp->fn_name));
2291
2292 /*
2293 * Timestamp, which visited nodes are marked with, to distinguish them
2294 * from unvisited nodes.
2295 */
2296 timestamp = gethrestime_sec();
2297 currfnp = lastfnp = rootfnp;
2298
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));
2305
2306 /*
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.
2310 */
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);
2316 /*
2317 * Fall through to next if-branch to pick
2318 * sibling or parent of this node.
2319 */
2320 }
2321
2322 /*
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.
2325 */
2326 if (currfnp->fn_unmount_ref_time >= timestamp ||
2327 curvp->v_type == VLNK) {
2328 mutex_exit(&currfnp->fn_lock);
2329 /*
2330 * Obtain parent's readers lock before grabbing
2331 * reference to sibling.
2332 */
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;
2341 }
2342 rw_exit(&currfnp->fn_parent->fn_rwlock);
2343
2344 /*
2345 * All descendants and siblings were visited. Perform
2346 * bottom-up move.
2347 */
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;
2354 }
2355
2356 /*
2357 * Mark node as visited. Note that the timestamp could have
2358 * been updated by somebody else in the meantime.
2359 */
2360 if (currfnp->fn_unmount_ref_time < timestamp)
2361 currfnp->fn_unmount_ref_time = timestamp;
2362
2363 /*
2364 * Don't descent below nodes, which are being unmounted/mounted.
2365 *
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.
2370 *
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.
2374 */
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);
2379 }
2380 if (currfnp->fn_flags & MF_INPROG) {
2381 rw_exit(&currfnp->fn_rwlock);
2382 continue;
2383 }
2384 mutex_exit(&currfnp->fn_lock);
2385
2386 /*
2387 * Examine descendants in this order: triggers, dirents, autofs
2388 * mounts.
2389 */
2390
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;
2398 }
2399
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;
2407 }
2408 rw_exit(&currfnp->fn_rwlock);
2409
2410 (void) vn_vfswlock_wait(curvp);
2411 vfsp = vn_mountedvfs(curvp);
2412 if (vfsp != NULL &&
2413 vfs_matchops(vfsp, vfs_getops(curvp->v_vfsp))) {
2414 /*
2415 * Deal with /xfn/host/jurassic alikes here...
2416 *
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().
2420 */
2421 if (VFS_ROOT(vfsp, &newvp)) {
2422 cmn_err(CE_PANIC,
2423 "autofs: VFS_ROOT(vfs=%p) failed",
2424 (void *)vfsp);
2425 }
2426 vn_vfsunlock(curvp);
2427 VN_RELE(curvp);
2428 currfnp = vntofn(newvp);
2429 mutex_enter(&currfnp->fn_lock);
2430 continue;
2431 }
2432 vn_vfsunlock(curvp);
2433 mutex_enter(&currfnp->fn_lock);
2434 }
2435
2436 /*
2437 * Now we deal with the root node (currfnp's mutex is unlocked
2438 * in try_unmount_node()).
2439 */
2440 return (try_unmount_node(currfnp, force));
2441 }
2442
2443 /*
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.
2453 */
2454 void
unmount_tree(struct autofs_globals * fngp,boolean_t force)2455 unmount_tree(struct autofs_globals *fngp, boolean_t force)
2456 {
2457 callb_cpr_t cprinfo;
2458 kmutex_t unmount_tree_cpr_lock;
2459 fnnode_t *root, *fnp, *next;
2460
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");
2464
2465 /*
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.
2470 *
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.
2475 */
2476 ASSERT(force || fngp->fng_zoneid == getzoneid());
2477
2478 /*
2479 * If automountd is not running in this zone,
2480 * don't attempt unmounting this round.
2481 */
2482 if (force || auto_null_request(fngp->fng_zoneid, FALSE) == 0) {
2483 /*
2484 * Iterate over top level autofs filesystems and call
2485 * unmount_subtree() for each of them.
2486 */
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));
2496 }
2497 rw_exit(&root->fn_rwlock);
2498 }
2499
2500 mutex_enter(&unmount_tree_cpr_lock);
2501 CALLB_CPR_EXIT(&cprinfo);
2502 mutex_destroy(&unmount_tree_cpr_lock);
2503 }
2504
2505 static void
unmount_zone_tree(struct autofs_globals * fngp)2506 unmount_zone_tree(struct autofs_globals *fngp)
2507 {
2508 AUTOFS_DPRINT((5, "unmount_zone_tree started. Thread created.\n"));
2509
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);
2514
2515 AUTOFS_DPRINT((5, "unmount_zone_tree done. Thread exiting.\n"));
2516
2517 zthread_exit();
2518 /* NOTREACHED */
2519 }
2520
2521 void
auto_do_unmount(struct autofs_globals * fngp)2522 auto_do_unmount(struct autofs_globals *fngp)
2523 {
2524 callb_cpr_t cprinfo;
2525 clock_t timeleft;
2526 zone_t *zone = curproc->p_zone;
2527
2528 CALLB_CPR_INIT(&cprinfo, &fngp->fng_unmount_threads_lock,
2529 callb_generic_cpr, "auto_do_unmount");
2530
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);
2539
2540 if (timeleft != -1) { /* didn't time out */
2541 ASSERT(zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN);
2542 /*
2543 * zone is exiting... don't create any new threads.
2544 * fng_unmount_threads_lock is released implicitly by
2545 * the below.
2546 */
2547 CALLB_CPR_SAFE_END(&cprinfo,
2548 &fngp->fng_unmount_threads_lock);
2549 CALLB_CPR_EXIT(&cprinfo);
2550 zthread_exit();
2551 /* NOTREACHED */
2552 }
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);
2558
2559 (void) zthread_create(NULL, 0, unmount_zone_tree, fngp,
2560 0, minclsyspri);
2561 } else
2562 goto newthread;
2563 }
2564 /* NOTREACHED */
2565 }
2566
2567 /*
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.
2571 */
2572 int
auto_nobrowse_option(char * opts)2573 auto_nobrowse_option(char *opts)
2574 {
2575 char *buf;
2576 char *p;
2577 char *t;
2578 int nobrowse = 0;
2579 int last_opt = 0;
2580 size_t len;
2581
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);
2597
2598 return (nobrowse);
2599 }
2600
2601 /*
2602 * used to log warnings only if automountd is running
2603 * with verbose mode set
2604 */
2605
2606 void
auto_log(int verbose,zoneid_t zoneid,int level,const char * fmt,...)2607 auto_log(int verbose, zoneid_t zoneid, int level, const char *fmt, ...)
2608 {
2609 va_list args;
2610
2611 if (verbose) {
2612 va_start(args, fmt);
2613 vzcmn_err(zoneid, level, fmt, args);
2614 va_end(args);
2615 }
2616 }
2617
2618 #ifdef DEBUG
2619 static int autofs_debug = 0;
2620
2621 /*
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 * ...
2639 */
2640 /* PRINTFLIKE2 */
2641 void
auto_dprint(int level,const char * fmt,...)2642 auto_dprint(int level, const char *fmt, ...)
2643 {
2644 va_list args;
2645
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);
2651 }
2652 }
2653 #endif /* DEBUG */
2654