xref: /original-bsd/usr.sbin/amd/amd/map.c (revision 95a66346)
1 /*
2  * $Id: map.c,v 5.2.1.5 91/03/17 17:47:23 jsp Alpha $
3  *
4  * Copyright (c) 1990 Jan-Simon Pendry
5  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Jan-Simon Pendry at Imperial College, London.
11  *
12  * %sccs.include.redist.c%
13  *
14  *	@(#)map.c	5.2 (Berkeley) 03/17/91
15  */
16 
17 #include "am.h"
18 
19 /*
20  * Generation Numbers.
21  *
22  * Generation numbers are allocated to every node created
23  * by amd.  When a filehandle is computed and sent to the
24  * kernel, the generation number makes sure that it is safe
25  * to reallocate a node slot even when the kernel has a cached
26  * reference to its old incarnation.
27  * No garbage collection is done, since it is assumed that
28  * there is no way that 2^32 generation numbers could ever
29  * be allocated by a single run of amd - there is simply
30  * not enough cpu time available.
31  */
32 static unsigned int am_gen = 2;	/* Initial generation number */
33 #define new_gen() (am_gen++)
34 
35 am_node **exported_ap = (am_node **) 0;
36 int exported_ap_size = 0;
37 int first_free_map = 0;		/* First available free slot */
38 int last_used_map = -1;		/* Last unavailable used slot */
39 static int timeout_mp_id;	/* Id from last call to timeout */
40 
41 /*
42  * This is the default attributes field which
43  * is copied into every new node to be created.
44  * The individual filesystem fs_init() routines
45  * patch the copy to represent the particular
46  * details for the relevant filesystem type
47  */
48 static struct fattr gen_fattr = {
49 	NFLNK,				/* type */
50 	NFSMODE_LNK | 0777,		/* mode */
51 	1,				/* nlink */
52 	0,				/* uid */
53 	0,				/* gid */
54 	0,				/* size */
55 	4096,				/* blocksize */
56 	0,				/* rdev */
57 	1,				/* blocks */
58 	0,				/* fsid */
59 	0,				/* fileid */
60 	{ 0, 0 },			/* atime */
61 	{ 0, 0 },			/* mtime */
62 	{ 0, 0 },			/* ctime */
63 };
64 
65 /*
66  * Resize exported_ap map
67  */
68 static int exported_ap_realloc_map P((int nsize));
69 static int exported_ap_realloc_map(nsize)
70 int nsize;
71 {
72 #ifdef notdef
73 	/*
74 	 * If a second realloc occasionally causes Amd to die
75 	 * in then include this check.
76 	 */
77 	if (exported_ap_size != 0)	/* XXX */
78 		return 0;
79 #endif
80 
81 	/*
82 	 * this shouldn't happen, but...
83 	 */
84 	if (nsize < 0 || nsize == exported_ap_size)
85 		return 0;
86 
87 	exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node*));
88 
89 	if (nsize > exported_ap_size)
90 		bzero((char*) (exported_ap+exported_ap_size),
91 			(nsize - exported_ap_size) * sizeof(am_node*));
92 	exported_ap_size = nsize;
93 
94 	return 1;
95 }
96 
97 
98 /*
99  * The root of the mount tree.
100  */
101 am_node *root_node;
102 
103 /*
104  * Allocate a new mount slot and create
105  * a new node.
106  * Fills in the map number of the node,
107  * but leaves everything else uninitialised.
108  */
109 am_node *exported_ap_alloc(P_void)
110 {
111 	am_node *mp, **mpp;
112 
113 	/*
114 	 * First check if there are any slots left, realloc if needed
115 	 */
116 	if (first_free_map >= exported_ap_size)
117 		if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP))
118 			return 0;
119 
120 	/*
121 	 * Grab the next free slot
122 	 */
123 	mpp = exported_ap + first_free_map;
124 	mp = *mpp = ALLOC(am_node);
125 	bzero((char *) mp, sizeof(*mp));
126 
127 	mp->am_mapno = first_free_map++;
128 
129 	/*
130 	 * Update free pointer
131 	 */
132 	while (first_free_map < exported_ap_size && exported_ap[first_free_map])
133 		first_free_map++;
134 
135 	if (first_free_map > last_used_map)
136 		last_used_map = first_free_map - 1;
137 
138 	/*
139 	 * Shrink exported_ap if reasonable
140 	 */
141 	if (last_used_map < exported_ap_size - (NEXP_AP + NEXP_AP_MARGIN))
142 		exported_ap_realloc_map(exported_ap_size - NEXP_AP);
143 
144 #ifdef DEBUG
145 	/*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n",
146 		last_used_map, first_free_map);*/
147 #endif /* DEBUG */
148 
149 	return mp;
150 }
151 
152 /*
153  * Free a mount slot
154  */
155 void exported_ap_free P((am_node *mp));
156 void exported_ap_free(mp)
157 am_node *mp;
158 {
159 	/*
160 	 * Sanity check
161 	 */
162 	if (!mp)
163 		return;
164 
165 	/*
166 	 * Zero the slot pointer to avoid double free's
167 	 */
168 	exported_ap[mp->am_mapno] = 0;
169 
170 	/*
171 	 * Update the free and last_used indices
172 	 */
173 	if (mp->am_mapno == last_used_map)
174 		while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
175 			--last_used_map;
176 
177 	if (first_free_map > mp->am_mapno)
178 		first_free_map = mp->am_mapno;
179 
180 #ifdef DEBUG
181 	/*dlog("free_exp: last_used_map = %d, first_free_map = %d\n",
182 		last_used_map, first_free_map);*/
183 #endif /* DEBUG */
184 
185 	/*
186 	 * Free the mount node
187 	 */
188 	free((voidp) mp);
189 }
190 
191 /*
192  * Insert mp into the correct place,
193  * where p_mp is its parent node.
194  * A new node gets placed as the youngest sibling
195  * of any other children, and the parent's child
196  * pointer is adjusted to point to the new child node.
197  */
198 void insert_am(mp, p_mp)
199 am_node *mp;
200 am_node *p_mp;
201 {
202 	/*
203 	 * If this is going in at the root then flag it
204 	 * so that it cannot be unmounted by amq.
205 	 */
206 	if (p_mp == root_node)
207 		mp->am_flags |= AMF_ROOT;
208 	/*
209 	 * Fill in n-way links
210 	 */
211 	mp->am_parent = p_mp;
212 	mp->am_osib = p_mp->am_child;
213 	if (mp->am_osib)
214 		mp->am_osib->am_ysib = mp;
215 	p_mp->am_child = mp;
216 }
217 
218 /*
219  * Remove am from its place in the mount tree
220  */
221 void remove_am(mp)
222 am_node *mp;
223 {
224 	/*
225 	 * 1.  Consistency check
226 	 */
227 	if (mp->am_child && mp->am_parent) {
228 		plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
229 	}
230 
231 	/*
232 	 * 2.  Update parent's child pointer
233 	 */
234 	if (mp->am_parent && mp->am_parent->am_child == mp)
235 		mp->am_parent->am_child = mp->am_osib;
236 
237 	/*
238 	 * 3.  Unlink from sibling chain
239 	 */
240 	if (mp->am_ysib)
241 		mp->am_ysib->am_osib = mp->am_osib;
242 	if (mp->am_osib)
243 		mp->am_osib->am_ysib = mp->am_ysib;
244 }
245 
246 /*
247  * Compute a new time to live value for a node.
248  */
249 void new_ttl(mp)
250 am_node *mp;
251 {
252 	mp->am_timeo_w = 0;
253 
254 	mp->am_ttl = clocktime();
255 	mp->am_fattr.atime.seconds = mp->am_ttl;
256 	mp->am_ttl += mp->am_timeo;	/* sun's -tl option */
257 }
258 
259 void mk_fattr P((am_node *mp, ftype vntype));
260 void mk_fattr(mp, vntype)
261 am_node *mp;
262 ftype vntype;
263 {
264 	switch (vntype) {
265 	case NFDIR:
266 		mp->am_fattr.type = NFDIR;
267 		mp->am_fattr.mode = NFSMODE_DIR | 0555;
268 		mp->am_fattr.nlink = 2;
269 		mp->am_fattr.size = 512;
270 		break;
271 	case NFLNK:
272 		mp->am_fattr.type = NFLNK;
273 		mp->am_fattr.mode = NFSMODE_LNK | 0777;
274 		mp->am_fattr.nlink = 1;
275 		mp->am_fattr.size = 0;
276 		break;
277 	default:
278 		plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype);
279 		break;
280 	}
281 }
282 
283 /*
284  * Initialise an allocated mount node.
285  * It is assumed that the mount node was bzero'd
286  * before getting here so anything that would
287  * be set to zero isn't done here.
288  */
289 void init_map(mp, dir)
290 am_node *mp;
291 char *dir;
292 {
293 	/* mp->am_mapno initalised by exported_ap_alloc */
294 	mp->am_mnt = new_mntfs();
295 	mp->am_name = strdup(dir);
296 	mp->am_path = strdup(dir);
297 	/*mp->am_link = 0;*/
298 	/*mp->am_parent = 0;*/
299 	/*mp->am_ysib = 0;*/
300 	/*mp->am_osib = 0;*/
301 	/*mp->am_child = 0;*/
302 	/*mp->am_flags = 0;*/
303 	/*mp->am_error = 0;*/
304 	mp->am_gen = new_gen();
305 	/*mp->am_pref = 0;*/
306 
307 	mp->am_timeo = am_timeo;
308 	mp->am_attr.status = NFS_OK;
309 	mp->am_fattr = gen_fattr;
310 	mp->am_fattr.fsid = 42;
311 	mp->am_fattr.fileid = 0;
312 	mp->am_fattr.atime.seconds = clocktime();
313 	mp->am_fattr.atime.useconds = 0;
314 	mp->am_fattr.mtime = mp->am_fattr.ctime = mp->am_fattr.atime;
315 
316 	new_ttl(mp);
317 	mp->am_stats.s_mtime = mp->am_fattr.atime.seconds;
318 	/*mp->am_private = 0;*/
319 }
320 
321 /*
322  * Free a mount node.
323  * The node must be already unmounted.
324  */
325 void free_map(mp)
326 am_node *mp;
327 {
328 	remove_am(mp);
329 
330 	if (mp->am_link)
331 		free(mp->am_link);
332 	if (mp->am_name)
333 		free(mp->am_name);
334 	if (mp->am_path)
335 		free(mp->am_path);
336 	if (mp->am_pref)
337 		free(mp->am_pref);
338 
339 	if (mp->am_mnt)
340 		free_mntfs(mp->am_mnt);
341 
342 	exported_ap_free(mp);
343 }
344 
345 /*
346  * Convert from file handle to
347  * automount node.
348  */
349 am_node *fh_to_mp3(fhp, rp, c_or_d)
350 nfs_fh *fhp;
351 int *rp;
352 int c_or_d;
353 {
354 	struct am_fh *fp = (struct am_fh *) fhp;
355 	am_node *ap = 0;
356 
357 	/*
358 	 * Check process id matches
359 	 * If it doesn't then it is probably
360 	 * from an old kernel cached filehandle
361 	 * which is now out of date.
362 	 */
363 	if (fp->fhh_pid != mypid)
364 		goto drop;
365 
366 	/*
367 	 * Make sure the index is valid before
368 	 * exported_ap is referenced.
369 	 */
370 	if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size)
371 		goto drop;
372 
373 	/*
374 	 * Get hold of the supposed mount node
375 	 */
376 	ap = exported_ap[fp->fhh_id];
377 
378 	/*
379 	 * If it exists then maybe...
380 	 */
381 	if (ap) {
382 		/*
383 		 * Check the generation number in the node
384 		 * matches the one from the kernel.  If not
385 		 * then the old node has been timed out and
386 		 * a new one allocated.
387 		 */
388 		if (ap->am_gen != fp->fhh_gen) {
389 			ap = 0;
390 			goto drop;
391 		}
392 
393 		/*
394 		 * If the node is hung then locate a new node
395 		 * for it.  This implements the replicated filesystem
396 		 * retries.
397 		 */
398 		if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
399 			int error;
400 			am_node *orig_ap = ap;
401 #ifdef DEBUG
402 			dlog("fh_to_mp3: %s (%s) is hung:- call lookup",
403 					orig_ap->am_path, orig_ap->am_mnt->mf_info);
404 #endif /* DEBUG */
405 			/*
406 			 * Update modify time of parent node.
407 			 * With any luck the kernel will re-stat
408 			 * the child node and get new information.
409 			 */
410 			orig_ap->am_fattr.mtime.seconds = clocktime();
411 
412 			/*
413 			 * Call the parent's lookup routine for an object
414 			 * with the same name.  This may return -1 in error
415 			 * if a mount is in progress.  In any case, if no
416 			 * mount node is returned the error code is propagated
417 			 * to the caller.
418 			 */
419 			if (c_or_d == VLOOK_CREATE) {
420 				ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn)(orig_ap->am_parent,
421 						orig_ap->am_name, &error, c_or_d);
422 			} else {
423 				ap = 0;
424 				error = ESTALE;
425 			}
426 			if (ap == 0) {
427 				if (error < 0 && amd_state == Finishing)
428 					error = ENOENT;
429 				*rp = error;
430 				return 0;
431 			}
432 			/*
433 			 * Update last access to original node.  This
434 			 * avoids timing it out and so sending ESTALE
435 			 * back to the kernel.
436 			 * XXX - Not sure we need this anymore (jsp, 90/10/6).
437 			 */
438 			new_ttl(orig_ap);
439 
440 		}
441 		/*
442 		 * Disallow references to objects being unmounted, unless
443 		 * they are automount points.
444 		 */
445 		if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
446 				!(ap->am_flags & AMF_ROOT)) {
447 			if (amd_state == Finishing)
448 				*rp = ENOENT;
449 			else
450 				*rp = -1;
451 			return 0;
452 		}
453 		new_ttl(ap);
454 	}
455 
456 drop:
457 	if (!ap || !ap->am_mnt) {
458 		/*
459 		 * If we are shutting down then it is likely
460 		 * that this node has disappeared because of
461 		 * a fast timeout.  To avoid things thrashing
462 		 * just pretend it doesn't exist at all.  If
463 		 * ESTALE is returned, some NFS clients just
464 		 * keep retrying (stupid or what - if it's
465 		 * stale now, what's it going to be in 5 minutes?)
466 		 */
467 		if (amd_state == Finishing)
468 			*rp = ENOENT;
469 		else
470 			*rp = ESTALE;
471 		amd_stats.d_stale++;
472 	}
473 
474 	return ap;
475 }
476 
477 am_node *fh_to_mp(fhp)
478 nfs_fh *fhp;
479 {
480 	int dummy;
481 	return fh_to_mp2(fhp, &dummy);
482 }
483 
484 /*
485  * Convert from automount node to
486  * file handle.
487  */
488 void mp_to_fh(mp, fhp)
489 am_node *mp;
490 struct nfs_fh *fhp;
491 {
492 	struct am_fh *fp = (struct am_fh *) fhp;
493 
494 	/*
495 	 * Take the process id
496 	 */
497 	fp->fhh_pid = mypid;
498 	/*
499 	 * .. the map number
500 	 */
501 	fp->fhh_id = mp->am_mapno;
502 	/*
503 	 * .. and the generation number
504 	 */
505 	fp->fhh_gen = mp->am_gen;
506 	/*
507 	 * .. to make a "unique" triple that will never
508 	 * be reallocated except across reboots (which doesn't matter)
509 	 * or if we are unlucky enough to be given the same
510 	 * pid as a previous amd (very unlikely).
511 	 */
512 }
513 
514 static am_node *find_ap2 P((char *dir, am_node *mp));
515 static am_node *find_ap2(dir, mp)
516 char *dir;
517 am_node *mp;
518 {
519 	if (mp) {
520 		am_node *mp2;
521 		if (strcmp(mp->am_path, dir) == 0)
522 			return mp;
523 
524 		if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
525 			strcmp(mp->am_mnt->mf_mount, dir) == 0)
526 			return mp;
527 
528 		mp2 = find_ap2(dir, mp->am_osib);
529 		if (mp2)
530 			return mp2;
531 		return find_ap2(dir, mp->am_child);
532 	}
533 
534 	return 0;
535 }
536 
537 /*
538  * Find the mount node corresponding
539  * to dir.  dir can match either the
540  * automount path or, if the node is
541  * mounted, the mount location.
542  */
543 am_node *find_ap P((char *dir));
544 am_node *find_ap(dir)
545 char *dir;
546 {
547 	int i;
548 
549 	for (i = last_used_map; i >= 0; --i) {
550 		am_node *mp = exported_ap[i];
551 		if (mp && (mp->am_flags & AMF_ROOT)) {
552 			mp = find_ap2(dir, exported_ap[i]);
553 			if (mp)
554 				return mp;
555 		}
556 	}
557 
558 	return 0;
559 }
560 
561 /*
562  * Find the mount node corresponding
563  * to the mntfs structure.
564  */
565 am_node *find_mf P((mntfs *mf));
566 am_node *find_mf(mf)
567 mntfs *mf;
568 {
569 	int i;
570 
571 	for (i = last_used_map; i >= 0; --i) {
572 		am_node *mp = exported_ap[i];
573 		if (mp && mp->am_mnt == mf)
574 			return mp;
575 	}
576 	return 0;
577 }
578 
579 /*
580  * Get the filehandle for a particular named directory.
581  * This is used during the bootstrap to tell the kernel
582  * the filehandles of the initial automount points.
583  */
584 nfs_fh *root_fh(dir)
585 char *dir;
586 {
587 	static nfs_fh nfh;
588 	am_node *mp = root_ap(dir, TRUE);
589 	if (mp) {
590 		mp_to_fh(mp, &nfh);
591 		/*
592 		 * Patch up PID to match main server...
593 		 */
594 		if (!foreground) {
595 			long pid = getppid();
596 			((struct am_fh *) &nfh)->fhh_pid = pid;
597 #ifdef DEBUG
598 			dlog("root_fh substitutes pid %d", pid);
599 #endif
600 		}
601 		return &nfh;
602 	}
603 
604 	/*
605 	 * Should never get here...
606 	 */
607 	plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
608 	return 0;
609 }
610 
611 am_node *root_ap(dir, path)
612 char *dir;
613 int path;
614 {
615 	am_node *mp = find_ap(dir);
616 	if (mp && mp->am_parent == root_node)
617 		return mp;
618 
619 	return 0;
620 }
621 
622 /*
623  * Mount a top level automount node
624  * by calling lookup in the parent
625  * (root) node which will cause the
626  * automount node to be automounted.
627  */
628 int mount_auto_node P((char *dir, voidp arg));
629 int mount_auto_node(dir, arg)
630 char *dir;
631 voidp arg;
632 {
633 	int error = 0;
634 	(void) afs_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE);
635 	if (error > 0) {
636 		errno = error; /* XXX */
637 		plog(XLOG_ERROR, "Could not mount %s: %m", dir);
638 	}
639 	return error;
640 }
641 
642 /*
643  * Cause all the top-level mount nodes
644  * to be automounted
645  */
646 int mount_exported P((void));
647 int mount_exported()
648 {
649 	/*
650 	 * Iterate over all the nodes to be started
651 	 */
652 	return root_keyiter((void (*)P((char*,void*))) mount_auto_node, root_node);
653 }
654 
655 /*
656  * Construct top-level node
657  */
658 void make_root_node P((void));
659 void make_root_node()
660 {
661 	mntfs *root_mnt;
662 	char *rootmap = ROOT_MAP;
663 	root_node = exported_ap_alloc();
664 
665 	/*
666 	 * Allocate a new map
667 	 */
668 	init_map(root_node, "");
669 	/*
670 	 * Allocate a new mounted filesystem
671 	 */
672 	root_mnt = find_mntfs(&root_ops, (am_opts *) 0, "", rootmap, "", "");
673 	/*
674 	 * Replace the initial null reference
675 	 */
676 	free_mntfs(root_node->am_mnt);
677 	root_node->am_mnt = root_mnt;
678 
679 	/*
680 	 * Initialise the root
681 	 */
682 	if (root_mnt->mf_ops->fs_init)
683 		(*root_mnt->mf_ops->fs_init)(root_mnt);
684 
685 	/*
686 	 * Mount the root
687 	 */
688 	root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs)(root_node);
689 }
690 
691 /*
692  * Cause all the nodes to be unmounted by timing
693  * them out.
694  */
695 void umount_exported(P_void)
696 {
697 	int i;
698 	for (i = last_used_map; i >= 0; --i) {
699 		am_node *mp = exported_ap[i];
700 		if (mp) {
701 			mntfs *mf = mp->am_mnt;
702 			if (mf->mf_flags & MFF_UNMOUNTING) {
703 				/*
704 				 * If this node is being unmounted then
705 				 * just ignore it.  However, this could
706 				 * prevent amd from finishing if the
707 				 * unmount gets blocked since the am_node
708 				 * will never be free'd.  am_unmounted needs
709 				 * telling about this possibility. - XXX
710 				 */
711 				continue;
712 			}
713 			if (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) {
714 				/*
715 				 * When shutting down this had better
716 				 * look like a directory, otherwise it
717 				 * can't be unmounted!
718 				 */
719 				mk_fattr(mp, NFDIR);
720 			}
721 			if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
722 			    (mf->mf_flags & MFF_RESTART)) {
723 				/*
724 				 * Just throw this node away without
725 				 * bothering to unmount it.  If the
726 				 * server is not known to be up then
727 				 * don't discard the mounted on directory
728 				 * or Amd might hang...
729 				 */
730 				if (mf->mf_server &&
731 					(mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID)
732 					mf->mf_flags &= ~MFF_MKMNT;
733 				am_unmounted(mp);
734 			} else {
735 				/*
736 				 * Any other node gets forcibly
737 				 * timed out
738 				 */
739 				mp->am_flags &= ~AMF_NOTIMEOUT;
740 				mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
741 				mp->am_ttl = 0;
742 				mp->am_timeo = 1;
743 				mp->am_timeo_w = 0;
744 			}
745 		}
746 	}
747 }
748 
749 static int unmount_node P((am_node *mp));
750 static int unmount_node(mp)
751 am_node *mp;
752 {
753 	mntfs *mf = mp->am_mnt;
754 	int error;
755 
756 	if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
757 		/*
758 		 * Just unlink
759 		 */
760 #ifdef DEBUG
761 		if (mf->mf_flags & MFF_ERROR)
762 			dlog("No-op unmount of error node %s", mf->mf_info);
763 #endif /* DEBUG */
764 		error = 0;
765 	} else {
766 #ifdef DEBUG
767 		dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
768 #endif /* DEBUG */
769 		error = (*mf->mf_ops->umount_fs)(mp);
770 	}
771 
772 	if (error) {
773 #ifdef DEBUG
774 		errno = error; /* XXX */
775 		dlog("%s: unmount: %m", mf->mf_mount);
776 #endif /* DEBUG */
777 	}
778 
779 	return error;
780 }
781 
782 #ifdef FLUSH_KERNEL_NAME_CACHE
783 static void flush_kernel_name_cache P((am_node*));
784 static void flush_kernel_name_cache(mp)
785 am_node *mp;
786 {
787 	int islink = (mp->am_mnt->mf_fattr.type == NFLNK);
788 	int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);
789 	int elog = 0;
790 	if (islink) {
791 		if (unlink(mp->am_path) < 0)
792 			elog = 1;
793 	} else if (isdir) {
794 		if (rmdir(mp->am_path) < 0)
795 			elog = 1;
796 	}
797 	if (elog)
798 		plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path);
799 }
800 #endif /* FLUSH_KERNEL_NAME_CACHE */
801 
802 static int unmount_node_wrap P((voidp vp));
803 static int unmount_node_wrap(vp)
804 voidp vp;
805 {
806 #ifndef FLUSH_KERNEL_NAME_CACHE
807 	return unmount_node((am_node*) vp);
808 #else /* FLUSH_KERNEL_NAME_CACHE */
809 	/*
810 	 * This code should just say:
811 	 * return unmount_node((am_node *) vp);
812 	 *
813 	 * However...
814 	 * The kernel keeps a cached copy of filehandles,
815 	 * and doesn't ever uncache them (apparently).  So
816 	 * when Amd times out a node the kernel will have a
817 	 * stale filehandle.  When the kernel next uses the
818 	 * filehandle it gets ESTALE.
819 	 *
820 	 * The workaround:
821 	 * Arrange that when a node is removed an unlink or
822 	 * rmdir is done on that path so that the kernel
823 	 * cache is done.  Yes - yuck.
824 	 *
825 	 * This can all be removed (and the background
826 	 * unmount flag in sfs_ops) if/when the kernel does
827 	 * something smarter.
828 	 *
829 	 * If the unlink or rmdir failed then just log a warning,
830 	 * don't fail the unmount.  This can occur if the kernel
831 	 * client code decides that the object is still referenced
832 	 * and should be renamed rather than discarded.
833 	 *
834 	 * There is still a race condition here...
835 	 * if another process is trying to access the same
836 	 * filesystem at the time we get here, then
837 	 * it will block, since the MF_UNMOUNTING flag will
838 	 * be set.  That may, or may not, cause the entire
839 	 * system to deadlock.  Hmmm...
840 	 */
841 	am_node *mp = (am_node *) vp;
842 	int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);
843 	int error = unmount_node(mp);
844 	if (error)
845 		return error;
846 	if (isauto && (int)amd_state < (int)Finishing)
847 		flush_kernel_name_cache(mp);
848 
849 	return 0;
850 #endif /* FLUSH_KERNEL_NAME_CACHE */
851 }
852 
853 static void free_map_if_success(rc, term, closure)
854 int rc;
855 int term;
856 voidp closure;
857 {
858 	am_node *mp = (am_node *) closure;
859 	mntfs *mf = mp->am_mnt;
860 
861 	/*
862 	 * Not unmounting any more
863 	 */
864 	mf->mf_flags &= ~MFF_UNMOUNTING;
865 
866 	/*
867 	 * If a timeout was defered because the underlying filesystem
868 	 * was busy then arrange for a timeout as soon as possible.
869 	 */
870 	if (mf->mf_flags & MFF_WANTTIMO) {
871 		mf->mf_flags &= ~MFF_WANTTIMO;
872 		reschedule_timeout_mp();
873 	}
874 
875 	if (term) {
876 		plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
877 #if defined(DEBUG) && defined(SIGTRAP)
878 		/*
879 		 * dbx likes to put a trap on exit().
880 		 * Pretend it succeeded for now...
881 		 */
882 		if (term == SIGTRAP) {
883 			am_unmounted(mp);
884 		}
885 #endif /* DEBUG */
886 		amd_stats.d_uerr++;
887 	} else if (rc) {
888 		if (rc == EBUSY) {
889 			plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
890 		} else {
891 			errno = rc;	/* XXX */
892 			plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);
893 		}
894 		amd_stats.d_uerr++;
895 	} else {
896 		am_unmounted(mp);
897 	}
898 
899 	/*
900 	 * Wakeup anything waiting for this mount
901 	 */
902 	wakeup((voidp) mf);
903 }
904 
905 static void unmount_mp(mp)
906 am_node *mp;
907 {
908 	mntfs *mf = mp->am_mnt;
909 #ifdef notdef
910 	plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
911 #endif /* notdef */
912 	if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&
913 			(mf->mf_flags & MFF_MOUNTED)) {
914 		if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
915 			/*
916 			 * Don't try to unmount from a server that is known to be down
917 			 */
918 			if (!(mf->mf_flags & MFF_LOGDOWN)) {
919 				/* Only log this once, otherwise gets a bit boring */
920 				plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
921 				mf->mf_flags |= MFF_LOGDOWN;
922 			}
923 		} else {
924 			/* Clear logdown flag - since the server must be up */
925 			mf->mf_flags &= ~MFF_LOGDOWN;
926 #ifdef DEBUG
927 			dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
928 			/*dlog("Will background the unmount attempt");*/
929 #endif /* DEBUG */
930 			/*
931 			 * Note that we are unmounting this node
932 			 */
933 			mf->mf_flags |= MFF_UNMOUNTING;
934 			run_task(unmount_node_wrap, (voidp) mp,
935 				 free_map_if_success, (voidp) mp);
936 #ifdef DEBUG
937 			dlog("unmount attempt backgrounded");
938 #endif /* DEBUG */
939 		}
940 	} else {
941 #ifdef DEBUG
942 		dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
943 		dlog("Trying unmount in foreground");
944 #endif
945 		mf->mf_flags |= MFF_UNMOUNTING;
946 		free_map_if_success(unmount_node(mp), 0, (voidp) mp);
947 #ifdef DEBUG
948 		dlog("unmount attempt done");
949 #endif /* DEBUG */
950 	}
951 }
952 
953 void timeout_mp()
954 {
955 #define NEVER (time_t) 0
956 #define	smallest_t(t1, t2) \
957 	(t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
958 #define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
959 
960 	int i;
961 	time_t t = NEVER;
962 	time_t now = clocktime();
963 
964 #ifdef DEBUG
965 	dlog("Timing out automount points...");
966 #endif /* DEBUG */
967 	for (i = last_used_map; i >= 0; --i) {
968 		am_node *mp = exported_ap[i];
969 		mntfs *mf;
970 		/*
971 		 * Just continue if nothing mounted, or can't be timed out.
972 		 */
973 		if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
974 			continue;
975 		/*
976 		 * Pick up mounted filesystem
977 		 */
978 		mf = mp->am_mnt;
979 		if (!mf)
980 			continue;
981 		/*
982 		 * Don't delete last reference to a restarted filesystem.
983 		 */
984 		if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
985 			continue;
986 		/*
987 		 * If there is action on this filesystem then ignore it
988 		 */
989 		if (!(mf->mf_flags & IGNORE_FLAGS)) {
990 			int expired = 0;
991 			mf->mf_flags &= ~MFF_WANTTIMO;
992 #ifdef DEBUG
993 			/*dlog("t is initially @%d, zero in %d secs", t, t - now);*/
994 #endif /* DEBUG */
995 			if (now >= mp->am_ttl) {
996 				expired = 1;
997 				/*
998 				 * Move the ttl forward to avoid thrashing effects
999 				 * on the next call to timeout!
1000 				 */
1001 				/* sun's -tw option */
1002 				if (mp->am_timeo_w < 4 * am_timeo_w)
1003 					mp->am_timeo_w += am_timeo_w;
1004 				mp->am_ttl = now + mp->am_timeo_w;
1005 			}
1006 			/*
1007 			 * If the next ttl is smallest, use that
1008 			 */
1009 			t = smallest_t(t, mp->am_ttl);
1010 
1011 #ifdef DEBUG
1012 			/*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/
1013 #endif /* DEBUG */
1014 
1015 			if (!mp->am_child && mf->mf_error >= 0 && expired)
1016 				unmount_mp(mp);
1017 		} else if (mf->mf_flags & MFF_UNMOUNTING) {
1018 			mf->mf_flags |= MFF_WANTTIMO;
1019 		}
1020 	}
1021 
1022 	if (t == NEVER) {
1023 #ifdef DEBUG
1024 		dlog("No further timeouts");
1025 #endif /* DEBUG */
1026 		t = now + ONE_HOUR;
1027 	}
1028 
1029 	/*
1030 	 * Sanity check to avoid runaways.
1031 	 * Absolutely should never get this but
1032 	 * if you do without this trap amd will thrash.
1033 	 */
1034 	if (t <= now) {
1035 		t = now + 6;	/* XXX */
1036 		plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
1037 	}
1038 	/*
1039 	 * XXX - when shutting down, make things happen faster
1040 	 */
1041 	if ((int)amd_state >= (int)Finishing)
1042 		t = now + 1;
1043 #ifdef DEBUG
1044 	dlog("Next mount timeout in %ds", t - now);
1045 #endif /* DEBUG */
1046 
1047 	timeout_mp_id = timeout(t - now, timeout_mp, 0);
1048 
1049 #undef NEVER
1050 #undef smallest_t
1051 #undef IGNORE_FLAGS
1052 }
1053 
1054 /*
1055  * Cause timeout_mp to be called soonest
1056  */
1057 void reschedule_timeout_mp()
1058 {
1059 	if (timeout_mp_id)
1060 		untimeout(timeout_mp_id);
1061 	timeout_mp_id = timeout(0, timeout_mp, 0);
1062 }
1063