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