rsalz@uunet.uu.net (Rich Salz) (04/11/90)
Submitted-by: Jan-Simon Pendry <jsp@doc.ic.ac.uk> Posting-number: Volume 21, Issue 98 Archive-name: amd/part10 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 10 (of 13)." # Contents: ChangeLog map.c # Wrapped by rsalz@papaya.bbn.com on Tue Apr 10 15:12:14 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'ChangeLog' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ChangeLog'\" else echo shar: Extracting \"'ChangeLog'\" \(21923 characters\) sed "s/^X//" >'ChangeLog' <<'END_OF_FILE' XThu Jan 11 16:56:41 1990 Jan-Simon Pendry (jsp at achilles) X X * Release 5.1c. X X * (amq*) has new options. -f flushes the map cache and -m prints X information about mounted filesystem and fileservers. X XTue Jan 2 14:44:21 1990 Jan-Simon Pendry (jsp at achilles) X X * (util.c) am_mounted() patches the path for "direct" mounted X filesystems - cosmetic. X X * (afs_ops.c) when possible sets a small kernel attribute cache X timeout on the automount points. X X * (nfs_stubs.c) delete() and rmdir() operations implemented. Used X when a mount point is timed out so the kernel name cache gets to X know about the changes. Fixes most ESTALE errors. X X * (nfs_stubs.c) New do_readlink() function added. This is used to X make sure that a filesystem is mounted at the time a link is read X in the case of "direct" mounts. Done so that the length of the X link is available when the initial getattr is done on the mountpoint. X X * (sfs_ops.c) Changed implementation to avoid race conditions. X The link target is re-arranged so that sublink points to the X target and fs always points at ".". X X * Fixed mount flag bug on Ultrix. X X * Added support from Sjoerd Mullender for Alliant FX/4 and Encore X Multimax. X XThu Dec 7 17:55:29 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) dfs_readlink now does a new_ttl on the node it X returns. X X * (afs_ops.c) next_nonerror_node now implements the task after X which it is named. X XTue Nov 28 17:20:52 1989 Jan-Simon Pendry (jsp at achilles) X X * Release 5.1b. X X * (restart.c) Generates link nodes for any unrecognised filesystem X types and then marks them so that they are never deleted (since X they could never be automounted later). X X * (os-*.h) Irrelevant #undef's deleted. X X * (arch) Now knows about AIX on RTs. X X * (amq.c) Rationalised the output. Now only gives you what you X asked for. X X * (am.h) New macro: FSRV_ISDOWN(fs), which checks whether a X fileserver is down. X X * (afs_ops.c) When a mount fails due to a timeout the underlying X filesystem is ripped away and replaced with an error fs. This X avoids the possibility of being left with a single error reference X to a valid mounted filesystem. X XThu Nov 23 18:04:29 1989 Jan-Simon Pendry (jsp at achilles) X X * (nfs_start.c) Re-order bootstrap sequence to avoid potential X deadlock if restart() ends up accessing one of the automount points. X X * (amq.c) Don't produce default mount output if one of the -l, -x X or -D options was used. X X * (umount_fs.c) Add alternative unmount routine for 4.4 BSD. X XMon Nov 20 16:22:50 1989 Jan-Simon Pendry (jsp at achilles) X X * (os-bsd44.h) Fixed redefinition of UMOUNT_FS. X X * (info_ndbm.c) Added missing #include <sys/stat.h>. X X * (mapc.c) Fixed typo in ifdef around gdbm config entry. X XSat Nov 18 16:39:13 1989 Jan-Simon Pendry (jsp at achilles) X X * (util.c) If "/" is automounted, make sure it is never timed out. X X * (mtab.c) Missing clock invalidation added in read_mtab (from a file). X X * (mntfs.c) realloc_mntfs simplified. X X * (map.c) Closed a race condition during shutdown when second and X subsequent duplicate mounts were deleted prematurely. X X * (afs_ops.c) Duplicate mounts are now given the correct return X code. X XFri Nov 17 18:58:18 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.1 Release. X XThu Nov 16 17:57:02 1989 Jan-Simon Pendry (jsp at achilles) X X * (mntfs.c) Make sure inherit mntfs structures are not cached X after last reference; otherwise a second reference to the X inherited filesystem will get stuck on the inherit rather than the X (now) fully mounted filesystem. X X * (am.c, nfs_start.c) After forking the server, make sure the X parent does not exit until the automount points are mounted. This X allows a clean sequence during system startup. X X * Initial port to 4.4 BSD. Several new configuration abstractions X were added to make this port possible. X XThu Nov 9 21:42:14 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c, opts.c) Added map logging to facilitate mount map X debugging without needing a -DDEBUG version of Amd. X X * (afs_ops.c) Make sure the length of the fs_hostname mount X parameter does not exceed MAXHOSTNAMESZ. X XWed Nov 8 13:44:02 1989 Jan-Simon Pendry (jsp at achilles) X X * Change the message log format to indicate the severity of the X message to allow simpler analysis of the log file. X XTue Nov 7 14:11:36 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 11. X X * (os-bsd44.h) Initial guess at 4.4 BSD definitions. X X * (os-aux.h) Port for Macintosh II from Julian Onions. X X * (amq.c) Output formats cleaned up. AMQ_MNTTREE is still broken X in amq_subr.c though. X X * (afs_ops.c) If a mount timed out, for example an NFS server was X down at the time, it was possible for the error code to remain X unset thus jamming that mount node in a state from which it could X not recover. Just make sure that the mf_error field gets filled X in when an error occurs. X X * (afs_ops.c) strsplit is run over /defaults to avoid problems X with whitespace creeping in. X XSun Nov 5 11:50:51 1989 Jan-Simon Pendry (jsp at achilles) X X * (util.c) am_mounted: Added missing initialisation of stats.s_mtime. X XFri Nov 3 17:33:02 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 10. X X * Changed the copyright. X XThu Nov 2 17:07:53 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 9. X X * (opts.c) new option syntax: == != := X X * (nfs_ops.c) Less caching of filehandles. Now cached errors are X discarded after use. X X * (mtab.c) now attempts to deal with a lack of open file slots (ENFILE). X X * (mount_fs.c) automount entries in the mount table now have a X dev= entry in the same way as NFS and UFS. X X * (mntfs.c) mntfs nodes are now cached after the last reference X and discarded <ALLOWED_MOUNT_TIME> seconds later. This avoids X thrashing during a mount. X X * (mapc.c) map default cache mode is now selected with X "mapdefault", not "default" X X * (amd.tex) numerous clarifications. Still more work required... X X * (amq_subr.c) now allows the -x option of amq to operate. X X * (afs_ops.c) afs_bgmount now keeps track of which filesystem X needed retrying and ensures that the mount node in the X continuation correctly points at an unmounted filesystem. This X fixes a problem whereby a valid mounted filesystem could appear to X have failed to mount. X X * Configure now gives more of a running commentary and checks X whether os-type and arch actually worked. X X * Allow spurious ';'s in a mount location. X XFri Oct 27 14:03:31 1989 Jan-Simon Pendry (jsp at achilles) X X * foo=blah changed to foo:=blah, foo==blah and foo!=blah. X X * -l stderr changed to -l /dev/stderr. X XThu Oct 19 15:34:28 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 6. X X * LOG_INFO messages have been rationalised so that some X statistics, graphs and so on can be generated. X X * Transaction ID's for RPC calls are now allocated by the X individual callers, rather than from a central pool. This X decreases the load on mount daemons and NFS servers since the X same XID is used for retries when needed. X X * Many fine details of the new data structures have been changed. X Some areas have been optimized. X XFri Oct 13 12:31:26 1989 Jan-Simon Pendry (jsp at achilles) X X * Restart code re-implemented to work with the new data structures. X X * Fine tuning applied to new NFS server modeling code. X XThu Oct 12 15:57:24 1989 Jan-Simon Pendry (jsp at achilles) X X * Added ${/var} and ${var/} variable expansions. The first gives X the "basename" component of the variable, the latter gives the X "dirname" component. Additionally, spurious /'s are deleted after X the variable expansions is complete. X X * Added new -C option to allow the machine's cluster name to be X given to amd. ${cluster} fetches the value and can be used as X another selector. X X * Broken the major data struct (am_node) into three layers: X am_node (one for each automount node), mntfs (one for each mounted X filesystem) and fserver (one for each file server). Machine X up/down state is maintained in the fserver layer. Filesystem X mount/unmount state is maintained in the mntfs layer. This change X fixes the last known major problem caused by the lack of a central X focus for filesystem and fileserver status. There is a dummy file X server layer for local filesystems (ufs, link, program, error). X XTue Oct 10 11:15:42 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 5. X X * (nfs_ops.c) the filehandle cache is now flushed when a X filesystem is unmounted. This avoids ending up with stale X information if a server bounces. X X * (clock.c) new module to implement callouts. Many other X routines changed to use callouts instead of messing with ttl X fields. X XSun Oct 1 17:08:20 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 3 & 4. X X * Numerous cleanups. X XWed Sep 13 14:30:05 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 2. X X * (nfs_ops.c) portmap information is not remembered beyond the X basic filehandle cache interval. That avoids problems when a new X portmap and/or rpc.mountd is started and the bound port changes. X X * (mapc.c) cache reloads are automatically done every hour. X X * Removed xlog macro in favour of plog() so that the log level X can be reflected through to syslog(). log() routine renamed to X plog() which takes an extra parameter indicating the log level. X XTue Sep 5 20:00:19 1989 Jan-Simon Pendry (jsp at achilles) X X * (nfs_ops.c) when a server is known to be down, any cached file X handles and port mapping informaton is flushed since that may have X changed when it comes back up. X X * (map.c) timeout no longer attempts to unmount a hung mount point. X XMon Sep 4 14:49:18 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) a mount node which timed out during mount is now X retained for the normal timeout interval rather than for a short X period. This avoids wasting time retrying mounts from a server X which is down. X X * (afs_ops.c) hung mounts are now detected and not used as a X duplicate mount - something which defeated the replacement fs X scheme. X X * (nfs_ops.c) keepalive's now back-off when a server has gone X down. X XThu Aug 31 21:18:35 1989 Jan-Simon Pendry (jsp at achilles) X X * 5.0 Patchlevel 1. X X * Fixed several bugs which showed up in the keepalive X implementation when a gateway went down causing X a different sequence of errors than usual. X XWed Aug 30 11:29:21 1989 Jan-Simon Pendry (jsp at achilles) X X * (amq.x) now uses a Sun assigned program number. X X * Revision 5.0 - can now start using metaconfig. X XTue Aug 29 14:36:48 1989 Jan-Simon Pendry (jsp at achilles) X X * (os-u3_0.h, os-type) now knows about DECstations (mips). X X * (nfs_stubs.c) Added hooks to readlink entry point to call X per-fs readlink routine if it exists, otherwise old behaviour. X X * (afs_ops.c) Added implementation of "type=direct". This is X the same as "type=auto" but is itself the link to the X mount point, rather than being a directory containing a list X of links to mount points. X XMon Aug 28 17:48:15 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) Changed readdir to workaround a problem on X ultrix 3 where it seems to forget that eof has been reached. X XThu Aug 24 15:17:55 1989 Jan-Simon Pendry (jsp at achilles) X X * Created "beta16". X X * (afs_ops.c) /defaults is located along with every key. X this makes it possible to update the /defaults in X a map and get to use it. X X * (mapc.c) added map cache synchronization support. if X a file or ndbm map is updated the cache is junked so avoiding X things getting out of sync. X XWed Aug 23 19:17:52 1989 Jan-Simon Pendry (jsp at achilles) X X * (os-u3_0.h) new file to support Ultrix 3.0 X X * (opts.c) allow environment variables to be accessed via X the same ${env} syntax used for options & selectors. X XTue Aug 22 13:19:49 1989 Jan-Simon Pendry (jsp at achilles) X X * (opts.c, get_args.c) added support for kernel architecture X type to allow /usr/kvm to be automounted under SunOS 4.x. X X * (os-xinu43.h) updated for june '89 release of MORE/bsd. X X * (opts.c) fixed memory allocation problems where some strings X may not have been strdup'ed before they were free'ed so causing X the malloc arena to get into a twist. This caused core dumps on X some machines and infinite loops on others. X X * (*.c) clock handling is now done by a macro. Global variable X clock_valid is > 0 (ie the time) when valid, 0 if invalid. X X * (map.c) timeout code survived a complete rewrite and is now X O(n) rather than O(n^2). X X * (info_hes.c) new database hooks for Hesiod nameserver. X X * (get_args.c) the local sub-domain is picked up from the X hostname if it is not specifed with -d. The subdomain is X then stripped from the hostname. X X * (am.c) when a SIGTERM is received, an immediate abort X occurs - only the top-level automounts are unmounted; all X other mounts stay -- use amd -r to restart. X X * (afs_ops.c) cleaned up key prefix handling. Again updated X the "hostname" string passed to the kernel so that includes X the hostname, pid and mount point. X XTue Aug 8 16:05:23 1989 Jan-Simon Pendry (jsp at achilles) X X * (nfs_ops.c) changed the way the file handle cache is managed. X No longer gets a race condition between something entering the X cache and being used and discard. X XTue Jul 25 20:40:51 1989 Jan-Simon Pendry (jsp at achilles) X X * (map.c) changed fh_to_mp2 so that it does not return X ESTALE during shutdown. it returns ENOENT instead which X avoids thrashing with the kernel. X XSun Jul 23 15:06:10 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) make sure the incoming key from the kernel X does not contain any characters which could cause trouble X during macro expansion (such as `"! etc). X X * (afs_ops.c) fixed contruction of "mtab" entry. X XFri Jul 21 11:01:05 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) some changes to support the new startup X shutdown scheme. X X * (map.c) startup and shutdown are now done using the X standard interfaces. Startup is done by creating a X private cache map ";root;" and then doing lookups X on all the names in it. Shutdown is done by forcibly X timing out all the mount points including the automount X points. X X * (info_*.c) modified to provide interface required by X mapc.c module. X X * (mapc.c) new module to implement map caching. Caching X can be controlled by an fs option. "all" means cache X the entire map (if possible). "inc" means cache things X incrementally. "none" means never cache things. Each X map type has a default caching mode which is used if X cache option "default" is used. X XWed Jul 19 16:14:52 1989 Jan-Simon Pendry (jsp at achilles) X X * (sched.c) implements a general sleep/wakeup scheme and uses X it for sub-process handling. X X * (nfs_start.c) task_notify() called from where it used to X be called. X X * (nfs_ops.c) now implements a non-blocking rpc library. X Everything in nfs_ops was changed to use it. This should X not be in this file and will be moved later. X X * (map.c) if a mount point times out and it is deferred then X issue a wakeup so that it can be retried. X X * (map.c) when creating a new mount point fetches the entry X "/defaults" from the associated map if no other options are X specified. X X * (am.c) implements the -p (print process id) option. X X * (afs_ops.c) a mount attempt now has a time-to-live of twenty X seconds. if only deferred attempts are waiting after that X interval the kernel gets sent ETIMEDOUT. X X * (afs_ops.c) the name by which the kernel knows the filesystem X has changed from pid%d@host to /mountpoint@host. That looks X better to users who get hit by it. X XFri Jul 14 18:46:16 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) now knows about defered mounts - mounts which X are not in progress, not completed, and not failed. X X * (sched.c) added new entry point sched_ast(). This simulates X a completed job. The basic idea is to let something else return X to the main scheduling loop with a guarentee that it will be X called back when some other action has taken place. X X * (nfs_ops.c) implemented a file handle cache. The nfs_init X routine starts up a request for the filehandle and the mount X routine uses it when it arrives. X XThu Jul 13 18:07:58 1989 Jan-Simon Pendry (jsp at achilles) X X * (afs_ops.c) found a race condition between an error occuring X and the am_node being timed out. Fixed by updating the X time-to-live and keepalive counters in the node whenever X AMF_MOUNTING is cleared. Also changed afs_lookuppn() so that X it doesn't destroy the node when it returns the error code. X This stops thrashing and the node is eventually timed out. X Now the only way a node gets deleted is by the timeout code X which seems more elegant. X XTue Jul 11 15:36:44 1989 Jan-Simon Pendry (jsp at achilles) X X * Created "beta15". X X * Fixed *all* references to "u2.2". Some where missed in X the original change. They are now u2_2. X X * (mk-amd-map.c) new command. Converts plain files into X ndbm databases for use by the info_ndbm module. Hooks X included for future support for gdbm just as soon as I X can get a copy. X XSun Jul 9 19:00:22 1989 Jan-Simon Pendry (jsp at achilles) X X * Created "beta14". X X * (get_info.c) code to handle yp and files now split into X new files info_yp.c and info_file.c New support for ndbm X databases is in info_ndbm.c. A table in get_info.c controls X what and in which order things are searched. X X * (map.c, nfs_stubs.c) better handling for hung mount points. X if a filehandle is passed in by the kernel which references X a hung node, then try to find a replacement, possibly by calling X lookup explicitly. X X * (*.c) use new xlog(level)(message) interface X XThu Jun 8 20:28:55 1989 Jan-Simon Pendry (jsp at achilles) X X * (nfs_ops.c, ufs_ops.c) when compiled with DEBUG, display X the fs options being used. X X * (am.c) make test for root a little more polite. X X * (get_args.c) update Usage message to include -r option. X XWed Jun 7 16:28:51 1989 Jan-Simon Pendry (jsp at achilles) X X * (rpc_fwd.c) fwd_reply: if the recvfrom call fails because it X is interrupted then try again. X XTue Jun 6 16:39:15 1989 Jan-Simon Pendry (jsp at achilles) X X * Created "beta12". X X * (afs_ops.c) inheriting mount option list from command line X is now cumulative. A -foo on the command line is prepended X to the default option list taken from the map. This can be X used to override the ``default default'' options in opts.c. X X * (get_args.c, am.c) added new -r (restart) option. Restart of X mounted filesystems is only done if this option is specified. X Should *not* be specified in /etc/rc.local of course. X X * (yp_master.c) make the enumeration error message more verbose X when debugging is enabled. X X * (rpc_fwd.c) rearranged some declarations at the top. Removed X a spurious call to free which was causing grief on some systems, X but not on Sun's. [This problem was the reason for implementing X the -D mem option.] X X * (opts.c) make sure opt_key and opt_path are set to a zero X length string unless otherwise specified. Previously they X were are source of dangling pointers. X X * (nfs_ops.c) make sure that the allocated nfs_private identifiers X are unique even when some filesystem are being restarted. This mean X starting the basic allocation from 1, not zero. X X * (am.h, get_args.c, util.c) added definition and implmentation of X a simple memory allocation trace (D_MEM). X X * (afs_ops.c) afs_lookuppn: tightened up memory allocation and X delay string copying until last possible moment. X XMon Jun 5 18:01:18 1989 Jan-Simon Pendry (jsp at achilles) X X * (Makefile.com) diffs: added new rule to generate diffs X between versions. X X * (get_info.c) search_file: added a new dlog() to note when X wildcards are returned. X X * (afs_ops.c) afs_lookuppn: call to init_map specifies efs as X the default ops structure. If the location list only contained X defaults and no real mounts then this previously caused a null X pointer dereference. X X * (map.c) last_used_map: Added new variable. Keeps track of the X last used map, which may be wildly different from first_free_map. X This fixes bugs in several routines in this file. X X * (util.c) mkdirs, rmdirs: Changed directory make/unmake. It is X not possible to quickly determine how many directories need to X be created or deleted, so we try to make as many as possible. X X * (opts.c) Added default values for rfs, rhost and fs. X The new defaults guarentee unique names to allow the NFS X keepalive stuff to work. X XSun Jun 4 16:12:15 1989 Jan-Simon Pendry (jsp at achilles) X X * First draft of documentation included in the next release. X X * Hooks for TFS added, though this still requires a lot of work. X X * Re-implemented option handling. Options are now allocated X dynamically on a per-mount basis in the continuation structure. X X * Changed os type u2.2 to u2_2 to allow for regular expression X matching in selectors. X X * Format of mount maps is now entirely different. Instead of X guessing which filesystem type is being used, it is now explicitly X stated along with the required options. Variable expansion is X done on the options and selectors are also implemented. The X requested name can also contain any of the selectors. X XWed May 24 15:21:39 1989 Jan-Simon Pendry (jsp at achilles) X X * Re-implemented NFS ping algorithm to use the new RPC forwarding X system. This allowed a large amount of nfs_ops specific code X to be removed from nfs_start.c and moved to nfs_ops.c. X There is still no strategy for hung file systems. At the moment X it will merely try to mount an alternative (or the same again) X to the same place in the file system. X X * Added RPC forwarding package. This supports general RPC gatewaying X over a UDP transport. The idea is to put a packet identifier into X each outgoing RPC packet and then match that up in a database when X a reply comes in. The database records the original packet identifier X (so that it can be replaced), the source address for the packet and X a function to call to do the forwarding. X X * ChangeLog added between beta8 and beta9. Should have done this sooner. END_OF_FILE if test 21923 -ne `wc -c <'ChangeLog'`; then echo shar: \"'ChangeLog'\" unpacked with wrong size! fi # end of 'ChangeLog' fi if test -f 'map.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'map.c'\" else echo shar: Extracting \"'map.c'\" \(19814 characters\) sed "s/^X//" >'map.c' <<'END_OF_FILE' X/* X * $Id: map.c,v 5.1.1.3 90/01/11 17:08:32 jsp Exp Locker: jsp $ X * X * Copyright (c) 1990 Jan-Simon Pendry X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software contributed to Berkeley by X * Jan-Simon Pendry at Imperial College, London. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by Imperial College of Science, Technology and Medicine, London, UK. X * The names of the College and University may not be used to endorse X * or promote products derived from this software without specific X * prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. X * X * %W% (Berkeley) %G% X */ X X#include "am.h" X#include <sys/param.h> /* For NMOUNT */ X X/* X * Generation Numbers. X * X * Generation numbers are allocated to every node created X * by amd. When a filehandle is computed and sent to the X * kernel, the generation number makes sure that it is safe X * to reallocate a node slot even when the kernel has a cached X * reference to its old incarnation. X * No garbage collection is done, since it is assumed that X * there is no way that 2^32 generation numbers could ever X * be allocated by a single run of amd - there is simply X * not enough cpu time available. X */ Xstatic unsigned int am_gen = 2; /* Initial generation number */ X#define new_gen() (am_gen++) X Xstruct am_node *exported_ap[NEXP_AP]; Xint first_free_map = 0; /* First available free slot */ Xint last_used_map = -1; /* Last unavailable used slot */ Xstatic int timeout_mp_id; /* Id from last call to timeout */ X X/* X * The root of the mount tree. X */ Xstatic am_node *root_node; X X/* X * Allocate a new mount slot and create X * a new node. X * Fills in the map number of the node, X * but leaves everything else uninitialised. X */ Xstruct am_node *exported_ap_alloc(P_void) X{ X struct am_node *mp, **mpp; X X /* X * First check if there are any slots left X */ X if (first_free_map >= NEXP_AP) X return 0; X X /* X * Grab the next free slot X */ X mpp = exported_ap + first_free_map; X mp = *mpp = ALLOC(am_node); X bzero((char *) mp, sizeof(*mp)); X X mp->am_mapno = first_free_map++; X X /* X * Update free pointer X */ X while (first_free_map < NEXP_AP && exported_ap[first_free_map]) X first_free_map++; X X if (first_free_map > last_used_map) X last_used_map = first_free_map - 1; X X#ifdef DEBUG X /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n", X last_used_map, first_free_map);*/ X#endif X X return mp; X} X X/* X * Free a mount slot X */ Xvoid exported_ap_free(mp) Xstruct am_node *mp; X{ X /* X * Sanity check X */ X if (!mp) X return; X X /* X * Zero the slot pointer to avoid double free's X */ X exported_ap[mp->am_mapno] = 0; X X /* X * Update the free and last_used indices X */ X if (mp->am_mapno == last_used_map) X while (last_used_map >= 0 && exported_ap[last_used_map] == 0) X --last_used_map; X X if (first_free_map > mp->am_mapno) X first_free_map = mp->am_mapno; X X#ifdef DEBUG X /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n", X last_used_map, first_free_map);*/ X#endif X X /* X * Free the mount node X */ X free(mp); X} X X/* X * Insert mp into the correct place, X * where p_mp is its parent node. X * A new node gets placed as the youngest sibling X * of any other children, and the parent's child X * pointer is adjusted to point to the new child node. X */ Xvoid insert_am(mp, p_mp) Xam_node *mp; Xam_node *p_mp; X{ X /* X * If this is going in at the root then flag it X * so that it cannot be unmounted by amq. X */ X if (p_mp == root_node) X mp->am_flags |= AMF_ROOT; X /* X * Fill in n-way links X */ X mp->am_parent = p_mp; X mp->am_osib = p_mp->am_child; X if (mp->am_osib) X mp->am_osib->am_ysib = mp; X p_mp->am_child = mp; X} X X/* X * Remove am from its place in the mount tree X */ Xvoid remove_am(mp) Xam_node *mp; X{ X /* X * 1. Consistency check X */ X if (mp->am_child && mp->am_parent) { X plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path); X } X X /* X * 2. Update parent's child pointer X */ X if (mp->am_parent && mp->am_parent->am_child == mp) X mp->am_parent->am_child = mp->am_osib; X X /* X * 3. Unlink from sibling chain X */ X if (mp->am_ysib) X mp->am_ysib->am_osib = mp->am_osib; X if (mp->am_osib) X mp->am_osib->am_ysib = mp->am_ysib; X} X X/* X * Compute a new time to live value for a node. X */ Xvoid new_ttl(mp) Xam_node *mp; X{ X mp->am_timeo_w = 0; X X mp->am_ttl = clocktime(); X mp->am_mnt->mf_fattr.atime.seconds = mp->am_ttl; X mp->am_ttl += mp->am_timeo; /* sun's -tl option */ X} X X/* X * Initialise an allocated mount node. X * It is assumed that the mount node was bzero'd X * before getting here so anything that would X * be set to zero isn't done here. X */ Xvoid init_map(mp, dir) Xam_node *mp; Xchar *dir; X{ X /* mp->am_mapno initalised by exported_ap_alloc */ X mp->am_mnt = new_mntfs(); X mp->am_name = strdup(dir); X mp->am_path = strdup(dir); X /*mp->am_link = 0;*/ X /*mp->am_parent = 0;*/ X /*mp->am_ysib = 0;*/ X /*mp->am_osib = 0;*/ X /*mp->am_child = 0;*/ X /*mp->am_flags = 0;*/ X /*mp->am_error = 0;*/ X mp->am_gen = new_gen(); X /*mp->am_pref = 0;*/ X X mp->am_timeo = am_timeo; X new_ttl(mp); X mp->am_stats.s_mtime = mp->am_mnt->mf_fattr.atime.seconds; X /*mp->am_private = 0;*/ X} X X/* X * Free a mount node. X * The node must be already unmounted. X */ Xvoid free_map(mp) Xam_node *mp; X{ X remove_am(mp); X X if (mp->am_link) X free(mp->am_link); X if (mp->am_name) X free(mp->am_name); X if (mp->am_path) X free(mp->am_path); X if (mp->am_pref) X free(mp->am_pref); X X if (mp->am_mnt) X free_mntfs(mp->am_mnt); X X if (mp->am_flags & AMF_MKPATH) X rmdirs(mp->am_path); X exported_ap_free(mp); X} X X/* X * Convert from file handle to X * automount node. X */ Xam_node *fh_to_mp3(fhp, rp, c_or_d) Xnfs_fh *fhp; Xint *rp; Xint c_or_d; X{ X struct am_fh *fp = (struct am_fh *) fhp; X am_node *ap = 0; X X /* X * Check process id matches X * If it doesn't then it is probably X * from an old kernel cached filehandle X * which is now out of date. X */ X if (fp->fhh_pid != mypid) X goto drop; X X /* X * Make sure the index is valid before X * exported_ap is referenced. X */ X if (fp->fhh_id < 0 || fp->fhh_id >= NEXP_AP) X goto drop; X X /* X * Get hold of the supposed mount node X */ X ap = exported_ap[fp->fhh_id]; X X /* X * If it exists then maybe... X */ X if (ap) { X /* X * Check the generation number in the node X * matches the one from the kernel. If not X * then the old node has been timed out and X * a new one allocated. X */ X if (ap->am_gen != fp->fhh_gen) { X ap = 0; X goto drop; X } X X /* X * If the node is hung then locate a new node X * for it. This implements the replicated filesystem X * retries. X */ X if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) { X int error; X#ifdef DEBUG X dlog("fh_to_mp3: %s (%s) is hung:- call lookup", ap->am_path, ap->am_mnt->mf_info); X#endif X /* X * Update last access to original node. This X * avoids timing it out and so sending ESTALE X * back to the kernel. X */ X new_ttl(ap); X X /* X * Call the parent's lookup routine for an object X * with the same name. This may return -1 in error X * if a mount is in progress. In any case, if no X * mount node is returned the error code is propagated X * to the caller. X */ X if (c_or_d == VLOOK_CREATE) { X ap = (*ap->am_parent->am_mnt->mf_ops->lookuppn)(ap->am_parent, X ap->am_name, &error, c_or_d); X } else { X ap = 0; X error = ESTALE; X } X if (ap == 0) { X *rp = error; X return 0; X } X } X /* X * Disallow references to objects being unmounted, unless X * they are automount points. X */ X if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) && X !(ap->am_flags & AMF_ROOT)) { X *rp = -1; X return 0; X } X new_ttl(ap); X } X Xdrop: X if (!ap || !ap->am_mnt) { X /* X * If we are shutting down then it is likely X * that this node has disappeared because of X * a fast timeout. To avoid things thrashing X * just pretend it doesn't exist at all. If X * ESTALE is returned, some NFS clients just X * keep retrying (stupid or what - if it's X * stale now, what's it going to be in 5 minutes?) X */ X if (amd_state == Finishing) X *rp = ENOENT; X else X *rp = ESTALE; X amd_stats.d_stale++; X } X X return ap; X} X Xam_node *fh_to_mp(fhp) Xnfs_fh *fhp; X{ X int dummy; X return fh_to_mp2(fhp, &dummy); X} X X/* X * Convert from automount node to X * file handle. X */ Xvoid mp_to_fh(mp, fhp) Xam_node *mp; Xstruct nfs_fh *fhp; X{ X struct am_fh *fp = (struct am_fh *) fhp; X X /* X * Take the process id X */ X fp->fhh_pid = mypid; X /* X * .. the map number X */ X fp->fhh_id = mp->am_mapno; X /* X * .. and the generation number X */ X fp->fhh_gen = mp->am_gen; X /* X * .. to make a "unique" triple that will never X * be reallocated except across reboots (which doesn't matter) X * or if we are unlucky enough to be given the same X * pid as a previous amd (very unlikely). X */ X} X Xstatic am_node *find_ap2(dir, mp) Xchar *dir; Xam_node *mp; X{ X if (mp) { X am_node *mp2; X if (strcmp(mp->am_path, dir) == 0) X return mp; X X if ((mp->am_mnt->mf_flags & MFF_MOUNTED) && X strcmp(mp->am_mnt->mf_mount, dir) == 0) X return mp; X X mp2 = find_ap2(dir, mp->am_osib); X if (mp2) X return mp2; X return find_ap2(dir, mp->am_child); X } X X return 0; X} X X/* X * Find the mount node corresponding X * to dir. dir can match either the X * automount path or, if the node is X * mounted, the mount location. X */ Xam_node *find_ap(dir) Xchar *dir; X{ X int i; X X for (i = last_used_map; i >= 0; --i) { X am_node *mp = exported_ap[i]; X if (mp && (mp->am_flags & AMF_ROOT)) { X mp = find_ap2(dir, exported_ap[i]); X if (mp) X return mp; X } X } X X return 0; X} X X/* X * Get the filehandle for a particular named directory. X * This is used during the bootstrap to tell the kernel X * the filehandles of the initial automount points. X */ Xnfs_fh *root_fh(dir) Xchar *dir; X{ X static nfs_fh nfh; X am_node *mp = root_ap(dir, TRUE); X if (mp) { X mp_to_fh(mp, &nfh); X return &nfh; X } X X /* X * Should never get here... X */ X plog(XLOG_ERROR, "Can't find root filehandle for %s", dir); X return 0; X} X Xam_node *root_ap(dir, path) Xchar *dir; Xint path; X{ X am_node *mp = find_ap(dir); X if (mp && mp->am_parent == root_node) X return mp; X X return 0; X} X X/* X * Mount a top level automount node X * by calling lookup in the parent X * (root) node which will cause the X * automount node to be automounted (!) X */ Xstatic void mount_auto_node(dir) Xchar *dir; X{ X int error = 0; X (void) afs_ops.lookuppn(root_node, dir, &error, VLOOK_CREATE); X if (error) { X errno = error; /* XXX */ X plog(XLOG_ERROR, "Could not start server on %s: %m", dir); X } X} X X/* X * Cause all the top-level mount nodes X * to be automounted X */ Xint mount_exported() X{ X /* X * Iterate over all the nodes to be started X */ X return root_keyiter(mount_auto_node); X} X X/* X * Construct top-level node X */ Xvoid make_root_node() X{ X mntfs *root_mnt; X char *rootmap = ROOT_MAP; X root_node = exported_ap_alloc(); X X init_map(root_node, ""); X root_mnt = find_mntfs(&afs_ops, (am_opts *) 0, "", rootmap, ""); X root_mnt->mf_mount = strealloc(root_mnt->mf_mount, pid_fsname); X root_mnt->mf_private = (voidp) mapc_find(rootmap, ""); X root_mnt->mf_prfree = mapc_free; X free_mntfs(root_node->am_mnt); X root_node->am_mnt = root_mnt; X root_node->am_flags |= AMF_NOTIMEOUT; X root_mnt->mf_error = 0; X} X X/* X * Cause all the nodes to be unmounted by timing X * them out. X */ Xvoid umount_exported(P_void) X{ X int i; X for (i = last_used_map; i >= 0; --i) { X am_node *mp = exported_ap[i]; X if (mp) { X mntfs *mf = mp->am_mnt; X if (mf->mf_flags & MFF_UNMOUNTING) { X /* X * If this node is being unmounted then X * just ignore it. However, this could X * prevent amd from finishing if the X * unmount gets blocked since the am_node X * will never be free'd. am_unmounted needs X * telling about this possibility. - XXX X */ X continue; X } X if (mf && mf->mf_ops == &dfs_ops) { X /* X * When shutting down this had better X * look like a directory, otherwise it X * can't be unmounted! X */ X mf->mf_fattr.type = NFDIR; X mf->mf_fattr.mode = NFSMODE_DIR | 0555; X } X if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) || X (mf->mf_flags & MFF_RESTART)) { X /* X * Just throw this node away without X * bothering to unmount it. If the X * server is not known to be up then X * don't discard the mounted on directory X * or Amd might hang... X */ X if (mf->mf_server && X (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID) X mf->mf_flags &= ~MFF_MKMNT; X am_unmounted(mp); X } else { X /* X * Any other node gets forcibly X * timed out X */ X mp->am_flags &= ~AMF_NOTIMEOUT; X mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; X mp->am_ttl = 0; X mp->am_timeo = 1; X mp->am_timeo_w = 0; X } X } X } X} X Xstatic int unmount_node P((am_node *mp)); Xstatic int unmount_node(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X int error; X X if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) { X /* X * Just unlink X */ X#ifdef DEBUG X if (mf->mf_flags & MFF_ERROR) X dlog("No-op unmount of error node %s", mf->mf_info); X#endif X error = 0; X } else { X#ifdef DEBUG X dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info); X#endif X error = (*mf->mf_ops->umount_fs)(mp); X } X X if (error) { X#ifdef DEBUG X errno = error; /* XXX */ X dlog("%s: unmount: %m", mf->mf_mount); X#endif X } X X return error; X} X Xstatic int unmount_node_wrap P((voidp vp)); Xstatic int unmount_node_wrap(vp) Xvoidp vp; X{ X /* X * This code should just say: X * return unmount_node((am_node *) vp); X * X * However... X * The kernel keeps a cached copy of filehandles, X * and doesn't ever cache them (apparently). So X * when Amd times out a node the kernel will have a X * stale filehandle. When the kernel next uses the X * filehandle it gets ESTALE. X * X * The workaround: X * Arrange that when a node is removed an unlink or X * rmdir is done on that path so that the kernel X * cache is done. Yes - yuck. X * X * This can all be removed (and the background X * unmount flag in sfs_ops) if/when the kernel does X * something smarter. X */ X am_node *mp = (am_node *) vp; X int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR); X int error = unmount_node(mp); X if (error) X return error; X if (isauto && (int)amd_state < (int)Finishing) { X int islink = (mp->am_mnt->mf_fattr.type == NFLNK); X int isdir = (mp->am_mnt->mf_fattr.type == NFDIR); X if (islink) { X if (unlink(mp->am_path) < 0) X return errno; X } else if (isdir) { X if (rmdir(mp->am_path) < 0) X return errno; X } X } X return 0; X} X Xstatic void free_map_if_success(rc, term, closure) Xint rc; Xint term; Xvoidp closure; X{ X am_node *mp = (am_node *) closure; X mntfs *mf = mp->am_mnt; X X /* X * Not unmounting any more X */ X mf->mf_flags &= ~MFF_UNMOUNTING; X X /* X * If a timeout was defered because the underlying filesystem X * was busy then arrange for a timeout as soon as possible. X */ X if (mf->mf_flags & MFF_WANTTIMO) { X mf->mf_flags &= ~MFF_WANTTIMO; X reschedule_timeout_mp(); X } X X if (term) { X plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term); X#ifdef DEBUG X /* X * dbx likes to put a trap on exit(). X * Pretend it succeeded for now... X */ X if (term == SIGTRAP) { X am_unmounted(mp); X } X#endif X amd_stats.d_uerr++; X } else if (rc) { X if (rc == EBUSY) { X plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount); X } else { X errno = rc; /* XXX */ X plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path); X } X amd_stats.d_uerr++; X } else { X am_unmounted(mp); X } X X /* X * Wakeup anything waiting for this mount X */ X wakeup((voidp) mf); X} X Xstatic void unmount_mp(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X#ifdef notdef X plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); X#endif X if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) && X (mf->mf_flags & MFF_MOUNTED) /* && X mf->mf_refc == 1 */) { X if (FSRV_ISDOWN(mf->mf_server)) { X /* X * Don't try to unmount from a server that is known to be down X */ X if (!(mf->mf_flags & MFF_LOGDOWN)) { X /* Only log this once, otherwise gets a bit boring */ X plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path); X mf->mf_flags |= MFF_LOGDOWN; X } X } else { X /* Clear logdown flag - since the server must be up */ X mf->mf_flags &= ~MFF_LOGDOWN; X#ifdef DEBUG X /*dlog("Will background the unmount attempt");*/ X#endif X /* X * Note that we are unmounting this node X */ X mf->mf_flags |= MFF_UNMOUNTING; X run_task(unmount_node_wrap, (voidp) mp, X free_map_if_success, (voidp) mp); X#ifdef DEBUG X dlog("unmount attempt backgrounded"); X#endif X } X } else { X#ifdef DEBUG X dlog("Trying unmount in foreground"); X#endif X mf->mf_flags |= MFF_UNMOUNTING; X free_map_if_success(unmount_node(mp), 0, (voidp) mp); X#ifdef DEBUG X dlog("unmount attempt done"); X#endif X } X} X Xvoid timeout_mp() X{ X#define NEVER (time_t) 0 X#define smallest_t(t1, t2) \ X (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2) X#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART) X X int i; X time_t t = NEVER; X time_t now = clocktime(); X X#ifdef DEBUG X dlog("Timing out automount points..."); X#endif X for (i = last_used_map; i >= 0; --i) { X am_node *mp = exported_ap[i]; X mntfs *mf; X /* X * Just continue if nothing mounted, or can't be timed out. X */ X if (!mp || (mp->am_flags & AMF_NOTIMEOUT)) X continue; X /* X * Pick up mounted filesystem X */ X mf = mp->am_mnt; X if (!mf) X continue; X /* X * Don't delete last reference to a restarted filesystem. X */ X if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1) X continue; X /* X * If there is action on this filesystem then ignore it X */ X if (!(mf->mf_flags & IGNORE_FLAGS)) { X int expired = 0; X mf->mf_flags &= ~MFF_WANTTIMO; X#ifdef DEBUG X /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/ X#endif X if (now >= mp->am_ttl) { X expired = 1; X /* X * Move the ttl forward to avoid thrashing effects X * on the next call to timeout! X */ X /* sun's -tw option */ X if (mp->am_timeo_w < 4 * am_timeo_w) X mp->am_timeo_w += am_timeo_w; X mp->am_ttl = now + mp->am_timeo_w; X } X /* X * If the next ttl is smallest, use that X */ X t = smallest_t(t, mp->am_ttl); X X#ifdef DEBUG X /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/ X#endif X X if (!mp->am_child && mf->mf_error >= 0 && expired) X unmount_mp(mp); X } else if (mf->mf_flags & MFF_UNMOUNTING) { X mf->mf_flags |= MFF_WANTTIMO; X } X } X X if (t == NEVER) { X#ifdef DEBUG X dlog("No further timeouts"); X#endif X t = now + ONE_HOUR; X } X X /* X * Sanity check to avoid runaways. X * Absolutely should never get this but X * if you do without this trap amd will thrash. X */ X if (t <= now) { X t = now + 6; /* XXX */ X plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!"); X } X /* X * XXX - when shutting down, make things happen faster X */ X if ((int)amd_state >= (int)Finishing) X t = now + 1; X#ifdef DEBUG X dlog("Next mount timeout in %ds", t - now); X#endif X X timeout_mp_id = timeout(t - now, timeout_mp, 0); X X#undef NEVER X#undef smallest_t X#undef IGNORE_FLAGS X} X X/* X * Cause timeout_mp to be called soonest X */ Xvoid reschedule_timeout_mp() X{ X if (timeout_mp_id) X untimeout(timeout_mp_id); X timeout_mp_id = timeout(0, timeout_mp, 0); X} END_OF_FILE if test 19814 -ne `wc -c <'map.c'`; then echo shar: \"'map.c'\" unpacked with wrong size! fi # end of 'map.c' fi echo shar: End of archive 10 \(of 13\). cp /dev/null ark10isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 13 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.