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) {
166 error = ENOENT;
167 /*
168 * This node should be a symlink
169 */
170 if (*link.link != '\0')
171 error = auto_perform_link(fnp, &link, cred);
172 } else if (mountreq) {
173 /*
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.
178 */
179 mutex_enter(&fnp->fn_lock);
180 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
181 fnp->fn_error = 0;
182
183 /*
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.
193 */
194 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
195 mutex_exit(&fnp->fn_lock);
196 /*
197 * auto_new_mount_thread fires up a new thread which
198 * calls automountd finishing up the work
199 */
200 auto_new_mount_thread(fnp, name, cred);
201
202 /*
203 * At this point, we are simply another thread
204 * waiting for the mount to complete
205 */
206 error = auto_wait4mount(fnp);
207 if (error == AUTOFS_SHUTDOWN)
208 error = ENOENT;
209 }
210 }
211
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;
218
219 /*
220 * Notify threads waiting for lookup/mount that
221 * it's done.
222 */
223 if (mountreq) {
224 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
225 } else {
226 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP);
227 }
228 mutex_exit(&fnp->fn_lock);
229 return (error);
230 }
231
232 /*
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.
243 */
244 static void
auto_mount_thread(struct autofs_callargs * argsp)245 auto_mount_thread(struct autofs_callargs *argsp)
246 {
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;
257
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");
261
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);
268
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;
274
275 /*
276 * Notify threads waiting for mount that
277 * it's done.
278 */
279 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
280 mutex_exit(&fnp->fn_lock);
281
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));
287
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 */
293 }
294
295 static int autofs_thr_success = 0;
296
297 /*
298 * Creates new thread which calls auto_mount_thread which does
299 * the bulk of the work calling automountd, via 'auto_perform_actions'.
300 */
301 void
auto_new_mount_thread(fnnode_t * fnp,char * name,cred_t * cred)302 auto_new_mount_thread(fnnode_t *fnp, char *name, cred_t *cred)
303 {
304 struct autofs_callargs *argsp;
305
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;
314
315 (void) zthread_create(NULL, 0, auto_mount_thread, argsp, 0,
316 minclsyspri);
317 autofs_thr_success++;
318 }
319
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;
324
325 /*ARGSUSED*/
326 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)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? */
336 {
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);
352
353 /*
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.
357 */
358 ASSERT(zoneid == getzoneid());
359 if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
360 /*
361 * There's no point in trying to talk to
362 * automountd. Plus, zone_shutdown() is
363 * waiting for us.
364 */
365 return (ECONNREFUSED);
366 }
367
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");
382 }
383 delay(hz);
384 retry = 1;
385 } else {
386 /*
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.
391 */
392 return (ECONNREFUSED);
393 }
394 }
395 } while (retry);
396
397 if (printed_not_running_msg) {
398 fngp->fng_printed_not_running_msg = printed_not_running_msg;
399 }
400
401 ASSERT(fngp != NULL);
402
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;
408
409 if (argsp) {
410 xdrmem_create(&xdrarg, (char *)&xdr_argsp->xdr_arg,
411 xdr_argsp->xdr_len, XDR_ENCODE);
412
413 if (!(*xarg_func)(&xdrarg, argsp)) {
414 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
415 return (EINVAL);
416 }
417 }
418
419 /*
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.
427 */
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);
432
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);
440
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);
446 }
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;
453
454 sigintr(&smask, 1);
455 error =
456 door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
457 sigunintr(&smask);
458
459 door_ki_rele(dh);
460
461 /*
462 * Handle daemon errors
463 */
464 if (!error) {
465 /*
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.
470 */
471 autofs_door_res_t *adr =
472 (autofs_door_res_t *)door_args.rbuf;
473
474 if (door_args.rbuf != NULL) {
475 int nl;
476
477 switch (error = adr->res_status) {
478 case 0: /* no error; continue */
479 break;
480
481 case EOVERFLOW:
482 /*
483 * orig landing buf not big enough.
484 * xdr_len in XDR_BYTES_PER_UNIT
485 */
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;
494 }
495 /*FALLTHROUGH*/
496
497 default:
498 kmem_free(xdr_argsp,
499 xdr_len + sizeof (*xdr_argsp));
500 if (orp)
501 kmem_free(orp, orl);
502 return (error);
503 }
504 }
505 continue;
506 }
507
508 /*
509 * no daemon errors; now process door/comm errors (if any)
510 */
511 switch (error) {
512 case EINTR:
513 /*
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.
517 */
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);
525 }
526 }
527 /*
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.
534 *
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.
539 */
540 if (schedctl_cancel_pending())
541 break;
542 /* FALLTHROUGH */
543 case EAGAIN: /* process may be forking */
544 /*
545 * Back off for a bit
546 */
547 delay(hz);
548 retry = 1;
549 break;
550 case EBADF: /* Invalid door */
551 case EINVAL: /* Not a door, wrong target */
552 /*
553 * A fatal door error, if our failing door
554 * handle is the current door handle, clean
555 * up our state.
556 */
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;
561 }
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");
569 }
570 delay(hz);
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);
580 }
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);
587 }
588 } while (retry);
589
590 if (fngp->fng_printed_not_running_msg == 1) {
591 fngp->fng_printed_not_running_msg = 0;
592 zprintf(zoneid, "automountd OK\n");
593 }
594
595 if (orp && orl) {
596 autofs_door_res_t *door_resp;
597 door_resp = (autofs_door_res_t *)door_args.rbuf;
598
599 if ((void *)door_args.rbuf != orp)
600 kmem_free(orp, orl);
601
602 xdrmem_create(&xdrres, (char *)&door_resp->xdr_res,
603 door_resp->xdr_len, XDR_DECODE);
604
605 if (!((*xresp_func)(&xdrres, resp)))
606 error = EINVAL;
607 kmem_free(door_args.rbuf, door_args.rsize);
608 }
609 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
610 return (error);
611 }
612
613 static int
auto_null_request(zoneid_t zoneid,bool_t hard)614 auto_null_request(zoneid_t zoneid, bool_t hard)
615 {
616 int error;
617
618 AUTOFS_DPRINT((4, "\tauto_null_request\n"));
619
620 error = auto_calldaemon(zoneid, NULLPROC,
621 xdr_void, NULL, xdr_void, NULL, 0, hard);
622
623 AUTOFS_DPRINT((5, "\tauto_null_request: error=%d\n", error));
624 return (error);
625 }
626
627 static int
auto_lookup_request(fninfo_t * fnip,char * key,struct linka * lnp,bool_t hard,bool_t * mountreq,cred_t * cred)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)
635 {
636 int error;
637 struct autofs_globals *fngp;
638 struct autofs_lookupargs reqst;
639 autofs_lookupres *resp;
640 struct linka *p;
641
642
643 AUTOFS_DPRINT((4, "auto_lookup_equest: path=%s name=%s\n",
644 fnip->fi_path, key));
645
646 fngp = vntofn(fnip->fi_rootvp)->fn_globals;
647
648 reqst.map = fnip->fi_map;
649 reqst.path = fnip->fi_path;
650
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));
656
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);
661
662 resp = kmem_zalloc(sizeof (*resp), KM_SLEEP);
663
664 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_LOOKUP,
665 xdr_autofs_lookupargs, &reqst, xdr_autofs_lookupres,
666 (void *)resp, sizeof (autofs_lookupres), hard);
667
668 if (error) {
669 xdr_free(xdr_autofs_lookupres, (char *)resp);
670 kmem_free(resp, sizeof (*resp));
671 return (error);
672 }
673
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;
684
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;
694
695 case AUTOFS_NONE:
696 lnp->link = NULL;
697 lnp->dir = NULL;
698 break;
699
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;
705 }
706 break;
707
708 case AUTOFS_NOENT:
709 error = ENOENT;
710 break;
711
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;
718 }
719 }
720
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);
726 }
727
728 static int
auto_mount_request(fninfo_t * fnip,char * key,action_list ** alpp,cred_t * cred,bool_t hard)729 auto_mount_request(
730 fninfo_t *fnip,
731 char *key,
732 action_list **alpp,
733 cred_t *cred,
734 bool_t hard)
735 {
736 int error;
737 struct autofs_globals *fngp;
738 autofs_lookupargs reqst;
739 autofs_mountres *xdrres = NULL;
740
741 AUTOFS_DPRINT((4, "auto_mount_request: path=%s name=%s\n",
742 fnip->fi_path, key));
743
744 fngp = vntofn(fnip->fi_rootvp)->fn_globals;
745 reqst.map = fnip->fi_map;
746 reqst.path = fnip->fi_path;
747
748 if (fnip->fi_flags & MF_DIRECT)
749 reqst.name = fnip->fi_key;
750 else
751 reqst.name = key;
752
753 AUTOFS_DPRINT((4, "auto_mount_request: using key=%s\n", reqst.name));
754
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);
759
760 xdrres = kmem_zalloc(sizeof (*xdrres), KM_SLEEP);
761
762 error = auto_calldaemon(fngp->fng_zoneid, AUTOFS_MNTINFO,
763 xdr_autofs_lookupargs, &reqst, xdr_autofs_mountres,
764 (void *)xdrres, sizeof (autofs_mountres), hard);
765
766 if (!error) {
767 fngp->fng_verbose = xdrres->mr_verbose;
768 switch (xdrres->mr_type.status) {
769 case AUTOFS_ACTION:
770 error = 0;
771 /*
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.
776 */
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;
789 }
790 }
791
792 xdr_free(xdr_autofs_mountres, (char *)xdrres);
793 kmem_free(xdrres, sizeof (*xdrres));
794
795
796 AUTOFS_DPRINT((5, "auto_mount_request: path=%s name=%s error=%d\n",
797 fnip->fi_path, key, error));
798 return (error);
799 }
800
801
802 static int
auto_send_unmount_request(fninfo_t * fnip,umntrequest * ul,bool_t hard)803 auto_send_unmount_request(
804 fninfo_t *fnip,
805 umntrequest *ul,
806 bool_t hard)
807 {
808 int error;
809 umntres xdrres;
810
811 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
812
813 AUTOFS_DPRINT((4, "\tauto_send_unmount_request: fstype=%s "
814 " mntpnt=%s\n", ul->fstype, ul->mntpnt));
815
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);
820
821 if (!error)
822 error = xdrres.status;
823
824 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error));
825
826 return (error);
827 }
828
829 static int
auto_perform_link(fnnode_t * fnp,struct linka * linkp,cred_t * cred)830 auto_perform_link(fnnode_t *fnp, struct linka *linkp, cred_t *cred)
831 {
832 vnode_t *vp;
833 size_t len;
834 char *tmp;
835
836 AUTOFS_DPRINT((3, "auto_perform_link: fnp=%p dir=%s link=%s\n",
837 (void *)fnp, linkp->dir, linkp->link));
838
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);
849
850 vp = fntovn(fnp);
851 vp->v_type = VLNK;
852
853 return (0);
854 }
855
856 static void
auto_free_autofs_args(struct mounta * m)857 auto_free_autofs_args(struct mounta *m)
858 {
859 autofs_args *aargs = (autofs_args *)m->dataptr;
860
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));
874 }
875
876 static void
auto_free_action_list(action_list * alp)877 auto_free_action_list(action_list *alp)
878 {
879 struct mounta *m;
880 action_list *lastalp;
881 char *fstype;
882
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);
890 }
891 }
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));
903 }
904 }
905
906 static boolean_t
auto_invalid_autofs(fninfo_t * dfnip,fnnode_t * dfnp,action_list * p)907 auto_invalid_autofs(fninfo_t *dfnip, fnnode_t *dfnp, action_list *p)
908 {
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;
915
916 fngp = dfnp->fn_globals;
917 dvp = fntovn(dfnp);
918
919 m = &p->action.action_list_entry_u.mounta;
920 /*
921 * Make sure we aren't geting passed NULL values or a "dir" that
922 * isn't "." and doesn't begin with "./".
923 *
924 * We also only want to perform autofs mounts, so make sure
925 * no-one is trying to trick us into doing anything else.
926 */
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);
933 /*
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.
937 */
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;
944 /*
945 * We don't want NULL values here either.
946 */
947 if (argsp->addr.buf == NULL || argsp->path == NULL ||
948 argsp->opts == NULL || argsp->map == NULL || argsp->subdir == NULL)
949 return (B_TRUE);
950 /*
951 * We know what the claimed pathname *should* look like:
952 *
953 * If the parent (dfnp) is a mount point (VROOT), then
954 * the path should be (dfnip->fi_path + m->dir).
955 *
956 * Else, we know we're only two levels deep, so we use
957 * (dfnip->fi_path + dfnp->fn_name + m->dir).
958 *
959 * Furthermore, "." only makes sense if dfnp is a
960 * trigger node.
961 *
962 * At this point it seems like the passed-in path is
963 * redundant.
964 */
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);
973 }
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);
979 }
980 return (B_FALSE); /* looks OK */
981 }
982
983 /*
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.
986 */
987 static boolean_t
auto_invalid_action(fninfo_t * dfnip,fnnode_t * dfnp,action_list * alistpp)988 auto_invalid_action(fninfo_t *dfnip, fnnode_t *dfnp, action_list *alistpp)
989 {
990
991 /*
992 * Before we go any further, this better be a mount request.
993 */
994 if (alistpp->action.action != AUTOFS_MOUNT_RQ)
995 return (B_TRUE);
996 return (auto_invalid_autofs(dfnip, dfnp, alistpp));
997
998 }
999
1000 static int
auto_perform_actions(fninfo_t * dfnip,fnnode_t * dfnp,action_list * alp,cred_t * cred)1001 auto_perform_actions(
1002 fninfo_t *dfnip,
1003 fnnode_t *dfnp,
1004 action_list *alp,
1005 cred_t *cred) /* Credentials of the caller */
1006 {
1007
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;
1022
1023 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", (void *)alp));
1024
1025 fngp = dfnp->fn_globals;
1026 dvp = fntovn(dfnp);
1027
1028 /*
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.
1033 */
1034
1035 for (p = alp; p != NULL; p = p->next) {
1036 if (auto_invalid_action(dfnip, dfnp, p)) {
1037 /*
1038 * This warning should be sent to the global zone,
1039 * since presumably the zone administrator is the same
1040 * as the attacker.
1041 */
1042 cmn_err(CE_WARN, "autofs: invalid action list received "
1043 "by automountd in zone %s.",
1044 curproc->p_zone->zone_name);
1045 /*
1046 * This conversation is over.
1047 */
1048 xdr_free(xdr_action_list, (char *)alp);
1049 return (EINVAL);
1050 }
1051 }
1052
1053 zcred = zone_get_kcred(getzoneid());
1054 ASSERT(zcred != NULL);
1055
1056 if (vn_mountedvfs(dvp) != NULL) {
1057 /*
1058 * The daemon successfully mounted a filesystem
1059 * on the AUTOFS root node.
1060 */
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 {
1067 /*
1068 * Clear MF_MOUNTPOINT.
1069 */
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);
1076 }
1077 dfnp->fn_flags &= ~MF_MOUNTPOINT;
1078 mutex_exit(&dfnp->fn_lock);
1079 }
1080
1081 for (p = alp; p != NULL; p = p->next) {
1082
1083 vfs_t *vfsp; /* dummy argument */
1084 vfs_t *mvfsp;
1085
1086 auto_mount = 0;
1087
1088 m = &p->action.action_list_entry_u.mounta;
1089 argsp = (struct autofs_args *)m->dataptr;
1090 ASSERT(strcmp(m->fstype, "autofs") == 0);
1091 /*
1092 * use the parent directory's timeout since it's the
1093 * one specified/inherited by automount.
1094 */
1095 argsp->mount_to = dfnip->fi_mount_to;
1096 /*
1097 * The mountpoint is relative, and it is guaranteed to
1098 * begin with "."
1099 *
1100 */
1101 ASSERT(m->dir[0] == '.');
1102 if (m->dir[0] == '.' && m->dir[1] == '\0') {
1103 /*
1104 * mounting on the trigger node
1105 */
1106 mvp = dvp;
1107 VN_HOLD(mvp);
1108 goto mount;
1109 }
1110 /*
1111 * ignore "./" in front of mountpoint
1112 */
1113 ASSERT(m->dir[1] == '/');
1114 mntpnt = m->dir + 2;
1115
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));
1119
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);
1127 }
1128
1129 if (vn_mountedvfs(dvp) == NULL) {
1130 /*
1131 * Daemon didn't mount anything on the root
1132 * We have to create the mountpoint if it
1133 * doesn't exist already
1134 *
1135 * We use the caller's credentials in case a
1136 * UID-match is required
1137 * (MF_THISUID_MATCH_RQD).
1138 */
1139 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1140 error = auto_search(dfnp, mntpnt, &mfnp, cred);
1141 if (error == 0) {
1142 /*
1143 * AUTOFS mountpoint exists
1144 */
1145 if (vn_mountedvfs(fntovn(mfnp)) != NULL) {
1146 cmn_err(CE_PANIC,
1147 "auto_perform_actions:"
1148 " mfnp=%p covered", (void *)mfnp);
1149 }
1150 } else {
1151 /*
1152 * Create AUTOFS mountpoint
1153 */
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++;
1158 }
1159 if (!error)
1160 update_times = 1;
1161 rw_exit(&dfnp->fn_rwlock);
1162 ASSERT(error != EEXIST);
1163 if (!error) {
1164 /*
1165 * mfnp is already held.
1166 */
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;
1174 }
1175 } else {
1176 /*
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.
1181 */
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;
1188 }
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;
1197 }
1198 }
1199 mount:
1200 m->flags |= MS_SYSSPACE | MS_OPTIONSTR;
1201
1202 /*
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.
1209 */
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;
1215
1216 /*
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.
1220 */
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;
1229 }
1230 VFS_RELE(vfsp);
1231
1232 /*
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.
1241 */
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);
1247 }
1248
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) {
1257 /*
1258 * We've dropped the locks, so let's
1259 * get the mounted vfs again in case
1260 * it changed.
1261 */
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);
1270 }
1271 } else
1272 vn_vfsunlock(mvp);
1273 VN_RELE(mvp);
1274 continue;
1275 }
1276 } else {
1277 vn_vfsunlock(mvp);
1278 VN_RELE(mvp);
1279 continue;
1280 }
1281
1282 auto_mount = vfs_matchops(dvp->v_vfsp,
1283 vfs_getops(newvp->v_vfsp));
1284 newfnp = vntofn(newvp);
1285 newfnp->fn_parent = dfnp;
1286
1287 /*
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.
1296 */
1297 if (auto_mount && (error == 0) && (mvp != dvp)) {
1298 save_triggers++;
1299 /*
1300 * Add AUTOFS mount to hierarchy
1301 */
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);
1309 /*
1310 * Don't VN_RELE(newvp) here since dfnp now
1311 * holds reference to it as its trigger node.
1312 */
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);
1324
1325 if (!error)
1326 success++;
1327
1328 if (update_times) {
1329 gethrestime(&now);
1330 dfnp->fn_atime = dfnp->fn_mtime = now;
1331 }
1332
1333 VN_RELE(mvp);
1334 }
1335
1336 if (save_triggers) {
1337 /*
1338 * Make sure the parent can't be freed while it has triggers.
1339 */
1340 VN_HOLD(dvp);
1341 }
1342
1343 crfree(zcred);
1344
1345 /*
1346 * Return failure if daemon didn't mount anything, and all
1347 * kernel mounts attempted failed.
1348 */
1349 error = success ? 0 : ENOENT;
1350
1351 if (alp != NULL) {
1352 if ((error == 0) && save_triggers) {
1353 /*
1354 * Save action_list information, so that we can use it
1355 * when it comes time to remount the trigger nodes
1356 * The action list is freed when the directory node
1357 * containing the reference to it is unmounted in
1358 * unmount_tree().
1359 */
1360 mutex_enter(&dfnp->fn_lock);
1361 ASSERT(dfnp->fn_alp == NULL);
1362 dfnp->fn_alp = alp;
1363 mutex_exit(&dfnp->fn_lock);
1364 } else {
1365 /*
1366 * free the action list now,
1367 */
1368 xdr_free(xdr_action_list, (char *)alp);
1369 }
1370 }
1371 AUTOFS_DPRINT((5, "auto_perform_actions: error=%d\n", error));
1372 return (error);
1373 }
1374
1375 fnnode_t *
auto_makefnnode(vtype_t type,vfs_t * vfsp,char * name,cred_t * cred,struct autofs_globals * fngp)1376 auto_makefnnode(
1377 vtype_t type,
1378 vfs_t *vfsp,
1379 char *name,
1380 cred_t *cred,
1381 struct autofs_globals *fngp)
1382 {
1383 fnnode_t *fnp;
1384 vnode_t *vp;
1385 char *tmpname;
1386 timestruc_t now;
1387 /*
1388 * autofs uses odd inode numbers
1389 * automountd uses even inode numbers
1390 *
1391 * To preserve the age-old semantics that inum+devid is unique across
1392 * the system, this variable must be global across zones.
1393 */
1394 static ino_t nodeid = 3;
1395
1396 fnp = kmem_zalloc(sizeof (*fnp), KM_SLEEP);
1397 fnp->fn_vnode = vn_alloc(KM_SLEEP);
1398
1399 vp = fntovn(fnp);
1400 tmpname = kmem_alloc(strlen(name) + 1, KM_SLEEP);
1401 (void) strcpy(tmpname, name);
1402 fnp->fn_name = &tmpname[0];
1403 fnp->fn_namelen = (int)strlen(tmpname) + 1; /* include '\0' */
1404 fnp->fn_uid = crgetuid(cred);
1405 fnp->fn_gid = crgetgid(cred);
1406 /*
1407 * ".." is added in auto_enter and auto_mount.
1408 * "." is added in auto_mkdir and auto_mount.
1409 */
1410 /*
1411 * Note that fn_size and fn_linkcnt are already 0 since
1412 * we used kmem_zalloc to allocated fnp
1413 */
1414 fnp->fn_mode = AUTOFS_MODE;
1415 gethrestime(&now);
1416 fnp->fn_atime = fnp->fn_mtime = fnp->fn_ctime = now;
1417 fnp->fn_ref_time = now.tv_sec;
1418 mutex_enter(&autofs_nodeid_lock);
1419 fnp->fn_nodeid = nodeid;
1420 nodeid += 2;
1421 fnp->fn_globals = fngp;
1422 fngp->fng_fnnode_count++;
1423 mutex_exit(&autofs_nodeid_lock);
1424 vn_setops(vp, auto_vnodeops);
1425 vp->v_type = type;
1426 vp->v_data = (void *)fnp;
1427 vp->v_vfsp = vfsp;
1428 mutex_init(&fnp->fn_lock, NULL, MUTEX_DEFAULT, NULL);
1429 rw_init(&fnp->fn_rwlock, NULL, RW_DEFAULT, NULL);
1430 cv_init(&fnp->fn_cv_mount, NULL, CV_DEFAULT, NULL);
1431 vn_exists(vp);
1432 return (fnp);
1433 }
1434
1435
1436 void
auto_freefnnode(fnnode_t * fnp)1437 auto_freefnnode(fnnode_t *fnp)
1438 {
1439 vnode_t *vp = fntovn(fnp);
1440
1441 AUTOFS_DPRINT((4, "auto_freefnnode: fnp=%p\n", (void *)fnp));
1442
1443 ASSERT(fnp->fn_linkcnt == 0);
1444 ASSERT(vp->v_count == 0);
1445 ASSERT(fnp->fn_dirents == NULL);
1446 ASSERT(fnp->fn_parent == NULL);
1447
1448 vn_invalid(vp);
1449 kmem_free(fnp->fn_name, fnp->fn_namelen);
1450 if (fnp->fn_symlink) {
1451 ASSERT(fnp->fn_flags & MF_THISUID_MATCH_RQD);
1452 kmem_free(fnp->fn_symlink, fnp->fn_symlinklen);
1453 }
1454 if (fnp->fn_cred)
1455 crfree(fnp->fn_cred);
1456 mutex_destroy(&fnp->fn_lock);
1457 rw_destroy(&fnp->fn_rwlock);
1458 cv_destroy(&fnp->fn_cv_mount);
1459 vn_free(vp);
1460
1461 mutex_enter(&autofs_nodeid_lock);
1462 fnp->fn_globals->fng_fnnode_count--;
1463 mutex_exit(&autofs_nodeid_lock);
1464 kmem_free(fnp, sizeof (*fnp));
1465 }
1466
1467 void
auto_disconnect(fnnode_t * dfnp,fnnode_t * fnp)1468 auto_disconnect(
1469 fnnode_t *dfnp,
1470 fnnode_t *fnp)
1471 {
1472 fnnode_t *tmp, **fnpp;
1473 vnode_t *vp = fntovn(fnp);
1474 timestruc_t now;
1475
1476 AUTOFS_DPRINT((4,
1477 "auto_disconnect: dfnp=%p fnp=%p linkcnt=%d\n v_count=%d",
1478 (void *)dfnp, (void *)fnp, fnp->fn_linkcnt, vp->v_count));
1479
1480 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
1481 ASSERT(fnp->fn_linkcnt == 1);
1482
1483 if (vn_mountedvfs(vp) != NULL) {
1484 cmn_err(CE_PANIC, "auto_disconnect: vp %p mounted on",
1485 (void *)vp);
1486 }
1487
1488 /*
1489 * Decrement by 1 because we're removing the entry in dfnp.
1490 */
1491 fnp->fn_linkcnt--;
1492 fnp->fn_size--;
1493
1494 /*
1495 * only changed while holding parent's (dfnp) rw_lock
1496 */
1497 fnp->fn_parent = NULL;
1498
1499 fnpp = &dfnp->fn_dirents;
1500 for (;;) {
1501 tmp = *fnpp;
1502 if (tmp == NULL) {
1503 cmn_err(CE_PANIC,
1504 "auto_disconnect: %p not in %p dirent list",
1505 (void *)fnp, (void *)dfnp);
1506 }
1507 if (tmp == fnp) {
1508 *fnpp = tmp->fn_next; /* remove it from the list */
1509 ASSERT(vp->v_count == 0);
1510 /* child had a pointer to parent ".." */
1511 dfnp->fn_linkcnt--;
1512 dfnp->fn_size--;
1513 break;
1514 }
1515 fnpp = &tmp->fn_next;
1516 }
1517
1518 mutex_enter(&fnp->fn_lock);
1519 gethrestime(&now);
1520 fnp->fn_atime = fnp->fn_mtime = now;
1521 mutex_exit(&fnp->fn_lock);
1522
1523 AUTOFS_DPRINT((5, "auto_disconnect: done\n"));
1524 }
1525
1526 int
auto_enter(fnnode_t * dfnp,char * name,fnnode_t ** fnpp,cred_t * cred)1527 auto_enter(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1528 {
1529 struct fnnode *cfnp, **spp;
1530 vnode_t *dvp = fntovn(dfnp);
1531 ushort_t offset = 0;
1532 ushort_t diff;
1533
1534 AUTOFS_DPRINT((4, "auto_enter: dfnp=%p, name=%s ", (void *)dfnp, name));
1535
1536 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
1537
1538 cfnp = dfnp->fn_dirents;
1539 if (cfnp == NULL) {
1540 /*
1541 * offset = 0 for '.' and offset = 1 for '..'
1542 */
1543 spp = &dfnp->fn_dirents;
1544 offset = 2;
1545 }
1546
1547 for (; cfnp; cfnp = cfnp->fn_next) {
1548 if (strcmp(cfnp->fn_name, name) == 0) {
1549 mutex_enter(&cfnp->fn_lock);
1550 if (cfnp->fn_flags & MF_THISUID_MATCH_RQD) {
1551 /*
1552 * "thisuser" kind of node, need to
1553 * match CREDs as well
1554 */
1555 mutex_exit(&cfnp->fn_lock);
1556 if (crcmp(cfnp->fn_cred, cred) == 0)
1557 return (EEXIST);
1558 } else {
1559 mutex_exit(&cfnp->fn_lock);
1560 return (EEXIST);
1561 }
1562 }
1563
1564 if (cfnp->fn_next != NULL) {
1565 diff = (ushort_t)
1566 (cfnp->fn_next->fn_offset - cfnp->fn_offset);
1567 ASSERT(diff != 0);
1568 if (diff > 1 && offset == 0) {
1569 offset = (ushort_t)cfnp->fn_offset + 1;
1570 spp = &cfnp->fn_next;
1571 }
1572 } else if (offset == 0) {
1573 offset = (ushort_t)cfnp->fn_offset + 1;
1574 spp = &cfnp->fn_next;
1575 }
1576 }
1577
1578 *fnpp = auto_makefnnode(VDIR, dvp->v_vfsp, name, cred,
1579 dfnp->fn_globals);
1580 if (*fnpp == NULL)
1581 return (ENOMEM);
1582
1583 /*
1584 * I don't hold the mutex on fnpp because I created it, and
1585 * I'm already holding the writers lock for it's parent
1586 * directory, therefore nobody can reference it without me first
1587 * releasing the writers lock.
1588 */
1589 (*fnpp)->fn_offset = offset;
1590 (*fnpp)->fn_next = *spp;
1591 *spp = *fnpp;
1592 (*fnpp)->fn_parent = dfnp;
1593 (*fnpp)->fn_linkcnt++; /* parent now holds reference to entry */
1594 (*fnpp)->fn_size++;
1595
1596 /*
1597 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock
1598 */
1599 dfnp->fn_linkcnt++; /* child now holds reference to parent '..' */
1600 dfnp->fn_size++;
1601
1602 dfnp->fn_ref_time = gethrestime_sec();
1603
1604 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp));
1605 return (0);
1606 }
1607
1608 int
auto_search(fnnode_t * dfnp,char * name,fnnode_t ** fnpp,cred_t * cred)1609 auto_search(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred)
1610 {
1611 vnode_t *dvp;
1612 fnnode_t *p;
1613 int error = ENOENT, match = 0;
1614
1615 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n",
1616 (void *)dfnp, name));
1617
1618 dvp = fntovn(dfnp);
1619 if (dvp->v_type != VDIR) {
1620 cmn_err(CE_PANIC, "auto_search: dvp=%p not a directory",
1621 (void *)dvp);
1622 }
1623
1624 ASSERT(RW_LOCK_HELD(&dfnp->fn_rwlock));
1625 for (p = dfnp->fn_dirents; p != NULL; p = p->fn_next) {
1626 if (strcmp(p->fn_name, name) == 0) {
1627 mutex_enter(&p->fn_lock);
1628 if (p->fn_flags & MF_THISUID_MATCH_RQD) {
1629 /*
1630 * "thisuser" kind of node
1631 * Need to match CREDs as well
1632 */
1633 mutex_exit(&p->fn_lock);
1634 match = crcmp(p->fn_cred, cred) == 0;
1635 } else {
1636 /*
1637 * No need to check CRED
1638 */
1639 mutex_exit(&p->fn_lock);
1640 match = 1;
1641 }
1642 }
1643 if (match) {
1644 error = 0;
1645 if (fnpp) {
1646 *fnpp = p;
1647 VN_HOLD(fntovn(*fnpp));
1648 }
1649 break;
1650 }
1651 }
1652
1653 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error));
1654 return (error);
1655 }
1656
1657 /*
1658 * If dvp is mounted on, get path's vnode in the mounted on
1659 * filesystem. Path is relative to dvp, ie "./path".
1660 * If successful, *mvp points to a the held mountpoint vnode.
1661 */
1662 /* ARGSUSED */
1663 static int
auto_getmntpnt(vnode_t * dvp,char * path,vnode_t ** mvpp,cred_t * cred)1664 auto_getmntpnt(
1665 vnode_t *dvp,
1666 char *path,
1667 vnode_t **mvpp, /* vnode for mountpoint */
1668 cred_t *cred)
1669 {
1670 int error = 0;
1671 vnode_t *newvp;
1672 char namebuf[TYPICALMAXPATHLEN];
1673 struct pathname lookpn;
1674 vfs_t *vfsp;
1675
1676 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path));
1677
1678 if (error = vn_vfsrlock_wait(dvp))
1679 return (error);
1680
1681 /*
1682 * Now that we have the vfswlock, check to see if dvp
1683 * is still mounted on. If not, then just bail out as
1684 * there is no need to remount the triggers since the
1685 * higher level mount point has gotten unmounted.
1686 */
1687 vfsp = vn_mountedvfs(dvp);
1688 if (vfsp == NULL) {
1689 vn_vfsunlock(dvp);
1690 error = EBUSY;
1691 goto done;
1692 }
1693 /*
1694 * Since mounted on, lookup "path" in the new filesystem,
1695 * it is important that we do the filesystem jump here to
1696 * avoid lookuppn() calling auto_lookup on dvp and deadlock.
1697 */
1698 error = VFS_ROOT(vfsp, &newvp);
1699 vn_vfsunlock(dvp);
1700 if (error)
1701 goto done;
1702
1703 /*
1704 * We do a VN_HOLD on newvp just in case the first call to
1705 * lookuppnvp() fails with ENAMETOOLONG. We should still have a
1706 * reference to this vnode for the second call to lookuppnvp().
1707 */
1708 VN_HOLD(newvp);
1709
1710 /*
1711 * Now create the pathname struct so we can make use of lookuppnvp,
1712 * and pn_getcomponent.
1713 * This code is similar to lookupname() in fs/lookup.c.
1714 */
1715 error = pn_get_buf(path, UIO_SYSSPACE, &lookpn,
1716 namebuf, sizeof (namebuf));
1717 if (error == 0) {
1718 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP,
1719 mvpp, rootdir, newvp, cred);
1720 } else
1721 VN_RELE(newvp);
1722 if (error == ENAMETOOLONG) {
1723 /*
1724 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
1725 * newvp is VN_RELE'd by this call to lookuppnvp.
1726 *
1727 * Using 'rootdir' in a zone's context is OK here: we already
1728 * ascertained that there are no '..'s in the path, and we're
1729 * not following symlinks.
1730 */
1731 if ((error = pn_get(path, UIO_SYSSPACE, &lookpn)) == 0) {
1732 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP,
1733 mvpp, rootdir, newvp, cred);
1734 pn_free(&lookpn);
1735 } else
1736 VN_RELE(newvp);
1737 } else {
1738 /*
1739 * Need to release newvp here since we held it.
1740 */
1741 VN_RELE(newvp);
1742 }
1743
1744 done:
1745 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n",
1746 path, (void *)*mvpp, error));
1747 return (error);
1748 }
1749
1750 #define DEEPER(x) (((x)->fn_dirents != NULL) || \
1751 (vn_mountedvfs(fntovn((x)))) != NULL)
1752
1753 /*
1754 * The caller, should have already VN_RELE'd its reference to the
1755 * root vnode of this filesystem.
1756 */
1757 static int
auto_inkernel_unmount(vfs_t * vfsp)1758 auto_inkernel_unmount(vfs_t *vfsp)
1759 {
1760 vnode_t *cvp = vfsp->vfs_vnodecovered;
1761 int error;
1762
1763 AUTOFS_DPRINT((4,
1764 "auto_inkernel_unmount: devid=%lx mntpnt(%p) count %u\n",
1765 vfsp->vfs_dev, (void *)cvp, cvp->v_count));
1766
1767 ASSERT(vn_vfswlock_held(cvp));
1768
1769 /*
1770 * Perform the unmount
1771 * The mountpoint has already been locked by the caller.
1772 */
1773 error = dounmount(vfsp, 0, kcred);
1774
1775 AUTOFS_DPRINT((5, "auto_inkernel_unmount: exit count %u\n",
1776 cvp->v_count));
1777 return (error);
1778 }
1779
1780 /*
1781 * unmounts trigger nodes in the kernel.
1782 */
1783 static void
unmount_triggers(fnnode_t * fnp,action_list ** alp)1784 unmount_triggers(fnnode_t *fnp, action_list **alp)
1785 {
1786 fnnode_t *tp, *next;
1787 int error = 0;
1788 vfs_t *vfsp;
1789 vnode_t *tvp;
1790
1791 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp));
1792 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1793
1794 *alp = fnp->fn_alp;
1795 next = fnp->fn_trigger;
1796 while ((tp = next) != NULL) {
1797 tvp = fntovn(tp);
1798 ASSERT(tvp->v_count >= 2);
1799 next = tp->fn_next;
1800 /*
1801 * drop writer's lock since the unmount will end up
1802 * disconnecting this node from fnp and needs to acquire
1803 * the writer's lock again.
1804 * next has at least a reference count >= 2 since it's
1805 * a trigger node, therefore can not be accidentally freed
1806 * by a VN_RELE
1807 */
1808 rw_exit(&fnp->fn_rwlock);
1809
1810 vfsp = tvp->v_vfsp;
1811
1812 /*
1813 * Its parent was holding a reference to it, since this
1814 * is a trigger vnode.
1815 */
1816 VN_RELE(tvp);
1817 if (error = auto_inkernel_unmount(vfsp)) {
1818 cmn_err(CE_PANIC, "unmount_triggers: "
1819 "unmount of vp=%p failed error=%d",
1820 (void *)tvp, error);
1821 }
1822 /*
1823 * reacquire writer's lock
1824 */
1825 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1826 }
1827
1828 /*
1829 * We were holding a reference to our parent. Drop that.
1830 */
1831 VN_RELE(fntovn(fnp));
1832 fnp->fn_trigger = NULL;
1833 fnp->fn_alp = NULL;
1834
1835 AUTOFS_DPRINT((5, "unmount_triggers: finished\n"));
1836 }
1837
1838 /*
1839 * This routine locks the mountpoint of every trigger node if they're
1840 * not busy, or returns EBUSY if any node is busy.
1841 */
1842 static boolean_t
triggers_busy(fnnode_t * fnp)1843 triggers_busy(fnnode_t *fnp)
1844 {
1845 int done;
1846 int lck_error = 0;
1847 fnnode_t *tp, *t1p;
1848 vfs_t *vfsp;
1849
1850 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock));
1851
1852 for (tp = fnp->fn_trigger; tp != NULL; tp = tp->fn_next) {
1853 AUTOFS_DPRINT((10, "\ttrigger: %s\n", tp->fn_name));
1854 /* MF_LOOKUP should never be set on trigger nodes */
1855 ASSERT((tp->fn_flags & MF_LOOKUP) == 0);
1856 vfsp = fntovn(tp)->v_vfsp;
1857
1858 /*
1859 * The vn_vfsunlock will be done in auto_inkernel_unmount.
1860 */
1861 lck_error = vn_vfswlock(vfsp->vfs_vnodecovered);
1862
1863 if (lck_error != 0 || (tp->fn_flags & MF_INPROG) ||
1864 DEEPER(tp) || ((fntovn(tp))->v_count) > 2) {
1865 /*
1866 * couldn't lock it because it's busy,
1867 * It is mounted on or has dirents?
1868 * If reference count is greater than two, then
1869 * somebody else is holding a reference to this vnode.
1870 * One reference is for the mountpoint, and the second
1871 * is for the trigger node.
1872 */
1873 AUTOFS_DPRINT((10, "\ttrigger busy\n"));
1874
1875 /*
1876 * Unlock previously locked mountpoints
1877 */
1878 for (done = 0, t1p = fnp->fn_trigger; !done;
1879 t1p = t1p->fn_next) {
1880 /*
1881 * Unlock all nodes previously
1882 * locked. All nodes up to 'tp'
1883 * were successfully locked. If 'lck_err' is
1884 * set, then 'tp' was not locked, and thus
1885 * should not be unlocked. If
1886 * 'lck_err' is not set, then 'tp' was
1887 * successfully locked, and it should
1888 * be unlocked.
1889 */
1890 if (t1p != tp || !lck_error) {
1891 vfsp = fntovn(t1p)->v_vfsp;
1892 vn_vfsunlock(vfsp->vfs_vnodecovered);
1893 }
1894 done = (t1p == tp);
1895 }
1896 return (B_TRUE);
1897 }
1898 }
1899
1900 return (B_FALSE);
1901 }
1902
1903 /*
1904 * It is the caller's responsibility to grab the VVFSLOCK.
1905 * Releases the VVFSLOCK upon return.
1906 */
1907 static int
unmount_node(vnode_t * cvp,int force)1908 unmount_node(vnode_t *cvp, int force)
1909 {
1910 int error = 0;
1911 fnnode_t *cfnp;
1912 vfs_t *vfsp;
1913 umntrequest ul;
1914 fninfo_t *fnip;
1915
1916 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp));
1917
1918 ASSERT(vn_vfswlock_held(cvp));
1919 cfnp = vntofn(cvp);
1920 vfsp = vn_mountedvfs(cvp);
1921
1922 if (force || cfnp->fn_flags & MF_IK_MOUNT) {
1923 /*
1924 * Mount was performed in the kernel, so
1925 * do an in-kernel unmount. auto_inkernel_unmount()
1926 * will vn_vfsunlock(cvp).
1927 */
1928 error = auto_inkernel_unmount(vfsp);
1929 } else {
1930 zone_t *zone = NULL;
1931 refstr_t *mntpt, *resource;
1932 size_t mntoptslen;
1933
1934 /*
1935 * Get the mnttab information of the node
1936 * and ask the daemon to unmount it.
1937 */
1938 bzero(&ul, sizeof (ul));
1939 mntfs_getmntopts(vfsp, &ul.mntopts, &mntoptslen);
1940 if (ul.mntopts == NULL) {
1941 auto_log(cfnp->fn_globals->fng_verbose,
1942 cfnp->fn_globals->fng_zoneid, CE_WARN,
1943 "unmount_node: no memory");
1944 vn_vfsunlock(cvp);
1945 error = ENOMEM;
1946 goto done;
1947 }
1948 if (mntoptslen > AUTOFS_MAXOPTSLEN)
1949 ul.mntopts[AUTOFS_MAXOPTSLEN - 1] = '\0';
1950
1951 mntpt = vfs_getmntpoint(vfsp);
1952 ul.mntpnt = (char *)refstr_value(mntpt);
1953 resource = vfs_getresource(vfsp);
1954 ul.mntresource = (char *)refstr_value(resource);
1955
1956 fnip = vfstofni(cvp->v_vfsp);
1957 ul.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE;
1958
1959 /*
1960 * Since a zone'd automountd's view of the autofs mount points
1961 * differs from those in the kernel, we need to make sure we
1962 * give it consistent mount points.
1963 */
1964 ASSERT(fnip->fi_zoneid == getzoneid());
1965 zone = curproc->p_zone;
1966
1967 if (fnip->fi_zoneid != GLOBAL_ZONEID) {
1968 if (ZONE_PATH_VISIBLE(ul.mntpnt, zone)) {
1969 ul.mntpnt =
1970 ZONE_PATH_TRANSLATE(ul.mntpnt, zone);
1971 }
1972 if (ZONE_PATH_VISIBLE(ul.mntresource, zone)) {
1973 ul.mntresource =
1974 ZONE_PATH_TRANSLATE(ul.mntresource, zone);
1975 }
1976 }
1977
1978 ul.fstype = vfssw[vfsp->vfs_fstype].vsw_name;
1979 vn_vfsunlock(cvp);
1980
1981 error = auto_send_unmount_request(fnip, &ul, FALSE);
1982 kmem_free(ul.mntopts, mntoptslen);
1983 refstr_rele(mntpt);
1984 refstr_rele(resource);
1985 }
1986
1987 done:
1988 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp,
1989 error));
1990 return (error);
1991 }
1992
1993 /*
1994 * return EBUSY if any thread is holding a reference to this vnode
1995 * other than us. Result of this function cannot be relied on, since
1996 * it doesn't follow proper locking rules (i.e. vp->v_vfsmountedhere
1997 * and fnp->fn_trigger can change throughout this function). However
1998 * it's good enough for rough estimation.
1999 */
2000 static int
check_auto_node(vnode_t * vp)2001 check_auto_node(vnode_t *vp)
2002 {
2003 fnnode_t *fnp;
2004 int error = 0;
2005 /*
2006 * number of references to expect for
2007 * a non-busy vnode.
2008 */
2009 uint_t count;
2010
2011 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp));
2012 fnp = vntofn(vp);
2013
2014 count = 1; /* we are holding a reference to vp */
2015 if (fnp->fn_flags & MF_TRIGGER) {
2016 /*
2017 * parent holds a pointer to us (trigger)
2018 */
2019 count++;
2020 }
2021 if (fnp->fn_trigger != NULL) {
2022 /*
2023 * The trigger nodes have a hold on us.
2024 */
2025 count++;
2026 }
2027 if (vn_ismntpt(vp)) {
2028 /*
2029 * File system is mounted on us.
2030 */
2031 count++;
2032 }
2033 mutex_enter(&vp->v_lock);
2034 ASSERT(vp->v_count > 0);
2035 if (vp->v_flag & VROOT)
2036 count++;
2037 AUTOFS_DPRINT((10, "\tcount=%u ", vp->v_count));
2038 if (vp->v_count > count)
2039 error = EBUSY;
2040 mutex_exit(&vp->v_lock);
2041
2042 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error));
2043 return (error);
2044 }
2045
2046 /*
2047 * rootvp is the root of the AUTOFS filesystem.
2048 * If rootvp is busy (v_count > 1) returns EBUSY.
2049 * else removes every vnode under this tree.
2050 * ASSUMPTION: Assumes that the only node which can be busy is
2051 * the root vnode. This filesystem better be two levels deep only,
2052 * the root and its immediate subdirs.
2053 * The daemon will "AUTOFS direct-mount" only one level below the root.
2054 */
2055 static void
unmount_autofs(vnode_t * rootvp)2056 unmount_autofs(vnode_t *rootvp)
2057 {
2058 fnnode_t *fnp, *rootfnp, *nfnp;
2059
2060 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp));
2061
2062 /*
2063 * Remove all its immediate subdirectories.
2064 */
2065 rootfnp = vntofn(rootvp);
2066 rw_enter(&rootfnp->fn_rwlock, RW_WRITER);
2067 for (fnp = rootfnp->fn_dirents; fnp != NULL; fnp = nfnp) {
2068 ASSERT(fntovn(fnp)->v_count == 0);
2069 ASSERT(fnp->fn_dirents == NULL);
2070 ASSERT(fnp->fn_linkcnt == 2);
2071 fnp->fn_linkcnt--;
2072 auto_disconnect(rootfnp, fnp);
2073 nfnp = fnp->fn_next;
2074 auto_freefnnode(fnp);
2075 }
2076 rw_exit(&rootfnp->fn_rwlock);
2077 }
2078
2079 /*
2080 * If a node matches all unmount criteria, do:
2081 * destroy subordinate trigger node(s) if there is any
2082 * unmount filesystem mounted on top of the node if there is any
2083 *
2084 * Function should be called with locked fnp's mutex. The mutex is
2085 * unlocked before return from function.
2086 */
2087 static int
try_unmount_node(fnnode_t * fnp,boolean_t force)2088 try_unmount_node(fnnode_t *fnp, boolean_t force)
2089 {
2090 boolean_t trigger_unmount = B_FALSE;
2091 action_list *alp = NULL;
2092 vnode_t *vp;
2093 int error = 0;
2094 fninfo_t *fnip;
2095 vfs_t *vfsp;
2096 struct autofs_globals *fngp;
2097
2098 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n",
2099 (void *)fnp));
2100
2101 ASSERT(MUTEX_HELD(&fnp->fn_lock));
2102
2103 fngp = fnp->fn_globals;
2104 vp = fntovn(fnp);
2105 fnip = vfstofni(vp->v_vfsp);
2106
2107 /*
2108 * If either a mount, lookup or another unmount of this subtree is in
2109 * progress, don't attempt to unmount at this time.
2110 */
2111 if (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) {
2112 mutex_exit(&fnp->fn_lock);
2113 return (EBUSY);
2114 }
2115
2116 /*
2117 * Bail out if someone else is holding reference to this vnode.
2118 * This check isn't just an optimization (someone is probably
2119 * just about to trigger mount). It is necessary to prevent a deadlock
2120 * in domount() called from auto_perform_actions() if unmount of
2121 * trigger parent fails. domount() calls lookupname() to resolve
2122 * special in mount arguments. Special is set to a map name in case
2123 * of autofs triggers (i.e. auto_ws.sun.com). Thus if current
2124 * working directory is set to currently processed node, lookupname()
2125 * calls into autofs vnops in order to resolve special, which deadlocks
2126 * the process.
2127 *
2128 * Note: This should be fixed. Autofs shouldn't pass the map name
2129 * in special and avoid useless lookup with potentially disasterous
2130 * consequence.
2131 */
2132 if (check_auto_node(vp) == EBUSY) {
2133 mutex_exit(&fnp->fn_lock);
2134 return (EBUSY);
2135 }
2136
2137 /*
2138 * If not forced operation, back out if node has been referenced
2139 * recently.
2140 */
2141 if (!force &&
2142 fnp->fn_ref_time + fnip->fi_mount_to > gethrestime_sec()) {
2143 mutex_exit(&fnp->fn_lock);
2144 return (EBUSY);
2145 }
2146
2147 /* block mounts/unmounts on the node */
2148 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
2149 fnp->fn_error = 0;
2150 mutex_exit(&fnp->fn_lock);
2151
2152 /* unmount next level triggers if there are any */
2153 rw_enter(&fnp->fn_rwlock, RW_WRITER);
2154 if (fnp->fn_trigger != NULL) {
2155 trigger_unmount = B_TRUE;
2156
2157 if (triggers_busy(fnp)) {
2158 rw_exit(&fnp->fn_rwlock);
2159 mutex_enter(&fnp->fn_lock);
2160 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
2161 mutex_exit(&fnp->fn_lock);
2162 return (EBUSY);
2163 }
2164
2165 /*
2166 * At this point, we know all trigger nodes are locked,
2167 * and they're not busy or mounted on.
2168 *
2169 * Attempt to unmount all trigger nodes, save the
2170 * action_list in case we need to remount them later.
2171 * The action_list will be freed later if there was no
2172 * need to remount the trigger nodes.
2173 */
2174 unmount_triggers(fnp, &alp);
2175 }
2176 rw_exit(&fnp->fn_rwlock);
2177
2178 (void) vn_vfswlock_wait(vp);
2179
2180 vfsp = vn_mountedvfs(vp);
2181 if (vfsp != NULL) {
2182 /* vn_vfsunlock(vp) is done inside unmount_node() */
2183 error = unmount_node(vp, force);
2184 if (error == ECONNRESET) {
2185 if (vn_mountedvfs(vp) == NULL) {
2186 /*
2187 * The filesystem was unmounted before the
2188 * daemon died. Unfortunately we can not
2189 * determine whether all the cleanup work was
2190 * successfully finished (i.e. update mnttab,
2191 * or notify NFS server of the unmount).
2192 * We should not retry the operation since the
2193 * filesystem has already been unmounted, and
2194 * may have already been removed from mnttab,
2195 * in such case the devid/rdevid we send to
2196 * the daemon will not be matched. So we have
2197 * to be content with the partial unmount.
2198 * Since the mountpoint is no longer covered, we
2199 * clear the error condition.
2200 */
2201 error = 0;
2202 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
2203 CE_WARN, "autofs: automountd "
2204 "connection dropped when unmounting %s/%s",
2205 fnip->fi_path, (fnip->fi_flags & MF_DIRECT)
2206 ? "" : fnp->fn_name);
2207 }
2208 }
2209 } else {
2210 vn_vfsunlock(vp);
2211 /* Destroy all dirents of fnp if we unmounted its triggers */
2212 if (trigger_unmount)
2213 unmount_autofs(vp);
2214 }
2215
2216 /* If unmount failed, we got to remount triggers */
2217 if (error != 0) {
2218 if (trigger_unmount) {
2219 int ret;
2220
2221 ASSERT((fnp->fn_flags & MF_THISUID_MATCH_RQD) == 0);
2222
2223 /*
2224 * The action list was free'd by auto_perform_actions
2225 */
2226 ret = auto_perform_actions(fnip, fnp, alp, CRED());
2227 if (ret != 0) {
2228 auto_log(fngp->fng_verbose, fngp->fng_zoneid,
2229 CE_WARN, "autofs: can't remount triggers "
2230 "fnp=%p error=%d", (void *)fnp, ret);
2231 }
2232 }
2233 mutex_enter(&fnp->fn_lock);
2234 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
2235 mutex_exit(&fnp->fn_lock);
2236 } else {
2237 /* Free the action list here */
2238 if (trigger_unmount)
2239 xdr_free(xdr_action_list, (char *)alp);
2240
2241 /*
2242 * Other threads may be waiting for this unmount to
2243 * finish. We must let it know that in order to
2244 * proceed, it must trigger the mount itself.
2245 */
2246 mutex_enter(&fnp->fn_lock);
2247 fnp->fn_flags &= ~MF_IK_MOUNT;
2248 if (fnp->fn_flags & MF_WAITING)
2249 fnp->fn_error = EAGAIN;
2250 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG);
2251 mutex_exit(&fnp->fn_lock);
2252 }
2253
2254 return (error);
2255 }
2256
2257 /*
2258 * This is an implementation of depth-first search in a tree rooted by
2259 * start_fnp and composed from fnnodes. Links between tree levels are
2260 * fn_dirents, fn_trigger in fnnode_t and v_mountedvfs in vnode_t (if
2261 * mounted vfs is autofs). The algorithm keeps track of visited nodes
2262 * by means of a timestamp (fn_unmount_ref_time).
2263 *
2264 * Upon top-down traversal of the tree we apply following locking scheme:
2265 * lock fn_rwlock of current node
2266 * grab reference to child's vnode (VN_HOLD)
2267 * unlock fn_rwlock
2268 * free reference to current vnode (VN_RELE)
2269 * Similar locking scheme is used for down-top and left-right traversal.
2270 *
2271 * Algorithm examines the most down-left node in tree, which hasn't been
2272 * visited yet. From this follows that nodes are processed in bottom-up
2273 * fashion.
2274 *
2275 * Function returns either zero if unmount of root node was successful
2276 * or error code (mostly EBUSY).
2277 */
2278 int
unmount_subtree(fnnode_t * rootfnp,boolean_t force)2279 unmount_subtree(fnnode_t *rootfnp, boolean_t force)
2280 {
2281 fnnode_t *currfnp; /* currently examined node in the tree */
2282 fnnode_t *lastfnp; /* previously processed node */
2283 fnnode_t *nextfnp; /* next examined node in the tree */
2284 vnode_t *curvp;
2285 vnode_t *newvp;
2286 vfs_t *vfsp;
2287 time_t timestamp;
2288
2289 ASSERT(fntovn(rootfnp)->v_type != VLNK);
2290 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp,
2291 rootfnp->fn_name));
2292
2293 /*
2294 * Timestamp, which visited nodes are marked with, to distinguish them
2295 * from unvisited nodes.
2296 */
2297 timestamp = gethrestime_sec();
2298 currfnp = lastfnp = rootfnp;
2299
2300 /* Loop until we examine all nodes in the tree */
2301 mutex_enter(&currfnp->fn_lock);
2302 while (currfnp != rootfnp || rootfnp->fn_unmount_ref_time < timestamp) {
2303 curvp = fntovn(currfnp);
2304 AUTOFS_DPRINT((10, "\tunmount_subtree: entering node %p (%s)\n",
2305 (void *)currfnp, currfnp->fn_name));
2306
2307 /*
2308 * New candidate for processing must have been already visited,
2309 * by us because we want to process tree nodes in bottom-up
2310 * order.
2311 */
2312 if (currfnp->fn_unmount_ref_time == timestamp &&
2313 currfnp != lastfnp) {
2314 (void) try_unmount_node(currfnp, force);
2315 lastfnp = currfnp;
2316 mutex_enter(&currfnp->fn_lock);
2317 /*
2318 * Fall through to next if-branch to pick
2319 * sibling or parent of this node.
2320 */
2321 }
2322
2323 /*
2324 * If this node has been already visited, it means that it's
2325 * dead end and we need to pick sibling or parent as next node.
2326 */
2327 if (currfnp->fn_unmount_ref_time >= timestamp ||
2328 curvp->v_type == VLNK) {
2329 mutex_exit(&currfnp->fn_lock);
2330 /*
2331 * Obtain parent's readers lock before grabbing
2332 * reference to sibling.
2333 */
2334 rw_enter(&currfnp->fn_parent->fn_rwlock, RW_READER);
2335 if ((nextfnp = currfnp->fn_next) != NULL) {
2336 VN_HOLD(fntovn(nextfnp));
2337 rw_exit(&currfnp->fn_parent->fn_rwlock);
2338 VN_RELE(curvp);
2339 currfnp = nextfnp;
2340 mutex_enter(&currfnp->fn_lock);
2341 continue;
2342 }
2343 rw_exit(&currfnp->fn_parent->fn_rwlock);
2344
2345 /*
2346 * All descendants and siblings were visited. Perform
2347 * bottom-up move.
2348 */
2349 nextfnp = currfnp->fn_parent;
2350 VN_HOLD(fntovn(nextfnp));
2351 VN_RELE(curvp);
2352 currfnp = nextfnp;
2353 mutex_enter(&currfnp->fn_lock);
2354 continue;
2355 }
2356
2357 /*
2358 * Mark node as visited. Note that the timestamp could have
2359 * been updated by somebody else in the meantime.
2360 */
2361 if (currfnp->fn_unmount_ref_time < timestamp)
2362 currfnp->fn_unmount_ref_time = timestamp;
2363
2364 /*
2365 * Don't descent below nodes, which are being unmounted/mounted.
2366 *
2367 * We need to hold both locks at once: fn_lock because we need
2368 * to read MF_INPROG and fn_rwlock to prevent anybody from
2369 * modifying fn_trigger until its used to traverse triggers
2370 * below.
2371 *
2372 * Acquire fn_rwlock in non-blocking mode to avoid deadlock.
2373 * If it can't be acquired, then acquire locks in correct
2374 * order.
2375 */
2376 if (!rw_tryenter(&currfnp->fn_rwlock, RW_READER)) {
2377 mutex_exit(&currfnp->fn_lock);
2378 rw_enter(&currfnp->fn_rwlock, RW_READER);
2379 mutex_enter(&currfnp->fn_lock);
2380 }
2381 if (currfnp->fn_flags & MF_INPROG) {
2382 rw_exit(&currfnp->fn_rwlock);
2383 continue;
2384 }
2385 mutex_exit(&currfnp->fn_lock);
2386
2387 /*
2388 * Examine descendants in this order: triggers, dirents, autofs
2389 * mounts.
2390 */
2391
2392 if ((nextfnp = currfnp->fn_trigger) != NULL) {
2393 VN_HOLD(fntovn(nextfnp));
2394 rw_exit(&currfnp->fn_rwlock);
2395 VN_RELE(curvp);
2396 currfnp = nextfnp;
2397 mutex_enter(&currfnp->fn_lock);
2398 continue;
2399 }
2400
2401 if ((nextfnp = currfnp->fn_dirents) != NULL) {
2402 VN_HOLD(fntovn(nextfnp));
2403 rw_exit(&currfnp->fn_rwlock);
2404 VN_RELE(curvp);
2405 currfnp = nextfnp;
2406 mutex_enter(&currfnp->fn_lock);
2407 continue;
2408 }
2409 rw_exit(&currfnp->fn_rwlock);
2410
2411 (void) vn_vfswlock_wait(curvp);
2412 vfsp = vn_mountedvfs(curvp);
2413 if (vfsp != NULL &&
2414 vfs_matchops(vfsp, vfs_getops(curvp->v_vfsp))) {
2415 /*
2416 * Deal with /xfn/host/jurassic alikes here...
2417 *
2418 * We know this call to VFS_ROOT is safe to call while
2419 * holding VVFSLOCK, since it resolves to a call to
2420 * auto_root().
2421 */
2422 if (VFS_ROOT(vfsp, &newvp)) {
2423 cmn_err(CE_PANIC,
2424 "autofs: VFS_ROOT(vfs=%p) failed",
2425 (void *)vfsp);
2426 }
2427 vn_vfsunlock(curvp);
2428 VN_RELE(curvp);
2429 currfnp = vntofn(newvp);
2430 mutex_enter(&currfnp->fn_lock);
2431 continue;
2432 }
2433 vn_vfsunlock(curvp);
2434 mutex_enter(&currfnp->fn_lock);
2435 }
2436
2437 /*
2438 * Now we deal with the root node (currfnp's mutex is unlocked
2439 * in try_unmount_node()).
2440 */
2441 return (try_unmount_node(currfnp, force));
2442 }
2443
2444 /*
2445 * XXX unmount_tree() is not suspend-safe within the scope of
2446 * the present model defined for cpr to suspend the system. Calls made
2447 * by the unmount_tree() that have been identified to be unsafe are
2448 * (1) RPC client handle setup and client calls to automountd which can
2449 * block deep down in the RPC library, (2) kmem_alloc() calls with the
2450 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*() and
2451 * VOP_*() calls which can result in over the wire calls to servers.
2452 * The thread should be completely reevaluated to make it suspend-safe in
2453 * case of future updates to the cpr model.
2454 */
2455 void
unmount_tree(struct autofs_globals * fngp,boolean_t force)2456 unmount_tree(struct autofs_globals *fngp, boolean_t force)
2457 {
2458 callb_cpr_t cprinfo;
2459 kmutex_t unmount_tree_cpr_lock;
2460 fnnode_t *root, *fnp, *next;
2461
2462 mutex_init(&unmount_tree_cpr_lock, NULL, MUTEX_DEFAULT, NULL);
2463 CALLB_CPR_INIT(&cprinfo, &unmount_tree_cpr_lock, callb_generic_cpr,
2464 "unmount_tree");
2465
2466 /*
2467 * autofssys() will be calling in from the global zone and doing
2468 * work on the behalf of the given zone, hence we can't always
2469 * assert that we have the right credentials, nor that the
2470 * caller is always in the correct zone.
2471 *
2472 * We do, however, know that if this is a "forced unmount"
2473 * operation (which autofssys() does), then we won't go down to
2474 * the krpc layers, so we don't need to fudge with the
2475 * credentials.
2476 */
2477 ASSERT(force || fngp->fng_zoneid == getzoneid());
2478
2479 /*
2480 * If automountd is not running in this zone,
2481 * don't attempt unmounting this round.
2482 */
2483 if (force || auto_null_request(fngp->fng_zoneid, FALSE) == 0) {
2484 /*
2485 * Iterate over top level autofs filesystems and call
2486 * unmount_subtree() for each of them.
2487 */
2488 root = fngp->fng_rootfnnodep;
2489 rw_enter(&root->fn_rwlock, RW_READER);
2490 for (fnp = root->fn_dirents; fnp != NULL; fnp = next) {
2491 VN_HOLD(fntovn(fnp));
2492 rw_exit(&root->fn_rwlock);
2493 (void) unmount_subtree(fnp, force);
2494 rw_enter(&root->fn_rwlock, RW_READER);
2495 next = fnp->fn_next;
2496 VN_RELE(fntovn(fnp));
2497 }
2498 rw_exit(&root->fn_rwlock);
2499 }
2500
2501 mutex_enter(&unmount_tree_cpr_lock);
2502 CALLB_CPR_EXIT(&cprinfo);
2503 mutex_destroy(&unmount_tree_cpr_lock);
2504 }
2505
2506 static void
unmount_zone_tree(struct autofs_globals * fngp)2507 unmount_zone_tree(struct autofs_globals *fngp)
2508 {
2509 AUTOFS_DPRINT((5, "unmount_zone_tree started. Thread created.\n"));
2510
2511 unmount_tree(fngp, B_FALSE);
2512 mutex_enter(&fngp->fng_unmount_threads_lock);
2513 fngp->fng_unmount_threads--;
2514 mutex_exit(&fngp->fng_unmount_threads_lock);
2515
2516 AUTOFS_DPRINT((5, "unmount_zone_tree done. Thread exiting.\n"));
2517
2518 zthread_exit();
2519 /* NOTREACHED */
2520 }
2521
2522 void
auto_do_unmount(struct autofs_globals * fngp)2523 auto_do_unmount(struct autofs_globals *fngp)
2524 {
2525 callb_cpr_t cprinfo;
2526 clock_t timeleft;
2527 zone_t *zone = curproc->p_zone;
2528
2529 CALLB_CPR_INIT(&cprinfo, &fngp->fng_unmount_threads_lock,
2530 callb_generic_cpr, "auto_do_unmount");
2531
2532 for (;;) { /* forever */
2533 mutex_enter(&fngp->fng_unmount_threads_lock);
2534 CALLB_CPR_SAFE_BEGIN(&cprinfo);
2535 newthread:
2536 mutex_exit(&fngp->fng_unmount_threads_lock);
2537 timeleft = zone_status_timedwait(zone, ddi_get_lbolt() +
2538 autofs_unmount_thread_timer * hz, ZONE_IS_SHUTTING_DOWN);
2539 mutex_enter(&fngp->fng_unmount_threads_lock);
2540
2541 if (timeleft != -1) { /* didn't time out */
2542 ASSERT(zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN);
2543 /*
2544 * zone is exiting... don't create any new threads.
2545 * fng_unmount_threads_lock is released implicitly by
2546 * the below.
2547 */
2548 CALLB_CPR_SAFE_END(&cprinfo,
2549 &fngp->fng_unmount_threads_lock);
2550 CALLB_CPR_EXIT(&cprinfo);
2551 zthread_exit();
2552 /* NOTREACHED */
2553 }
2554 if (fngp->fng_unmount_threads < autofs_unmount_threads) {
2555 fngp->fng_unmount_threads++;
2556 CALLB_CPR_SAFE_END(&cprinfo,
2557 &fngp->fng_unmount_threads_lock);
2558 mutex_exit(&fngp->fng_unmount_threads_lock);
2559
2560 (void) zthread_create(NULL, 0, unmount_zone_tree, fngp,
2561 0, minclsyspri);
2562 } else
2563 goto newthread;
2564 }
2565 /* NOTREACHED */
2566 }
2567
2568 /*
2569 * Is nobrowse specified in option string?
2570 * opts should be a null ('\0') terminated string.
2571 * Returns non-zero if nobrowse has been specified.
2572 */
2573 int
auto_nobrowse_option(char * opts)2574 auto_nobrowse_option(char *opts)
2575 {
2576 char *buf;
2577 char *p;
2578 char *t;
2579 int nobrowse = 0;
2580 int last_opt = 0;
2581 size_t len;
2582
2583 len = strlen(opts) + 1;
2584 p = buf = kmem_alloc(len, KM_SLEEP);
2585 (void) strcpy(buf, opts);
2586 do {
2587 if (t = strchr(p, ','))
2588 *t++ = '\0';
2589 else
2590 last_opt++;
2591 if (strcmp(p, MNTOPT_NOBROWSE) == 0)
2592 nobrowse = 1;
2593 else if (strcmp(p, MNTOPT_BROWSE) == 0)
2594 nobrowse = 0;
2595 p = t;
2596 } while (!last_opt);
2597 kmem_free(buf, len);
2598
2599 return (nobrowse);
2600 }
2601
2602 /*
2603 * used to log warnings only if automountd is running
2604 * with verbose mode set
2605 */
2606
2607 void
auto_log(int verbose,zoneid_t zoneid,int level,const char * fmt,...)2608 auto_log(int verbose, zoneid_t zoneid, int level, const char *fmt, ...)
2609 {
2610 va_list args;
2611
2612 if (verbose) {
2613 va_start(args, fmt);
2614 vzcmn_err(zoneid, level, fmt, args);
2615 va_end(args);
2616 }
2617 }
2618
2619 #ifdef DEBUG
2620 static int autofs_debug = 0;
2621
2622 /*
2623 * Utilities used by both client and server
2624 * Standard levels:
2625 * 0) no debugging
2626 * 1) hard failures
2627 * 2) soft failures
2628 * 3) current test software
2629 * 4) main procedure entry points
2630 * 5) main procedure exit points
2631 * 6) utility procedure entry points
2632 * 7) utility procedure exit points
2633 * 8) obscure procedure entry points
2634 * 9) obscure procedure exit points
2635 * 10) random stuff
2636 * 11) all <= 1
2637 * 12) all <= 2
2638 * 13) all <= 3
2639 * ...
2640 */
2641 /* PRINTFLIKE2 */
2642 void
auto_dprint(int level,const char * fmt,...)2643 auto_dprint(int level, const char *fmt, ...)
2644 {
2645 va_list args;
2646
2647 if (autofs_debug == level ||
2648 (autofs_debug > 10 && (autofs_debug - 10) >= level)) {
2649 va_start(args, fmt);
2650 (void) vprintf(fmt, args);
2651 va_end(args);
2652 }
2653 }
2654 #endif /* DEBUG */
2655