home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / amd / part10 / map.c < prev   
Encoding:
C/C++ Source or Header  |  1990-04-10  |  19.3 KB  |  886 lines

  1. /*
  2.  * $Id: map.c,v 5.1.1.3 90/01/11 17:08:32 jsp Exp Locker: jsp $
  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.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. #include "am.h"
  29. #include <sys/param.h>    /* For NMOUNT */
  30.  
  31. /*
  32.  * Generation Numbers.
  33.  *
  34.  * Generation numbers are allocated to every node created
  35.  * by amd.  When a filehandle is computed and sent to the
  36.  * kernel, the generation number makes sure that it is safe
  37.  * to reallocate a node slot even when the kernel has a cached
  38.  * reference to its old incarnation.
  39.  * No garbage collection is done, since it is assumed that
  40.  * there is no way that 2^32 generation numbers could ever
  41.  * be allocated by a single run of amd - there is simply
  42.  * not enough cpu time available.
  43.  */
  44. static unsigned int am_gen = 2;    /* Initial generation number */
  45. #define new_gen() (am_gen++)
  46.  
  47. struct am_node *exported_ap[NEXP_AP];
  48. int first_free_map = 0;        /* First available free slot */
  49. int last_used_map = -1;        /* Last unavailable used slot */
  50. static int timeout_mp_id;    /* Id from last call to timeout */
  51.  
  52. /*
  53.  * The root of the mount tree.
  54.  */
  55. static am_node *root_node;
  56.  
  57. /*
  58.  * Allocate a new mount slot and create
  59.  * a new node.
  60.  * Fills in the map number of the node,
  61.  * but leaves everything else uninitialised.
  62.  */
  63. struct am_node *exported_ap_alloc(P_void)
  64. {
  65.     struct am_node *mp, **mpp;
  66.  
  67.     /*
  68.      * First check if there are any slots left
  69.      */
  70.     if (first_free_map >= NEXP_AP)
  71.         return 0;
  72.  
  73.     /*
  74.      * Grab the next free slot
  75.      */
  76.     mpp = exported_ap + first_free_map;
  77.     mp = *mpp = ALLOC(am_node);
  78.     bzero((char *) mp, sizeof(*mp));
  79.  
  80.     mp->am_mapno = first_free_map++;
  81.  
  82.     /*
  83.      * Update free pointer
  84.      */
  85.     while (first_free_map < NEXP_AP && exported_ap[first_free_map])
  86.         first_free_map++;
  87.  
  88.     if (first_free_map > last_used_map)
  89.         last_used_map = first_free_map - 1;
  90.  
  91. #ifdef DEBUG
  92.     /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n",
  93.         last_used_map, first_free_map);*/
  94. #endif
  95.  
  96.     return mp;
  97. }
  98.  
  99. /*
  100.  * Free a mount slot
  101.  */
  102. void exported_ap_free(mp)
  103. struct am_node *mp;
  104. {
  105.     /*
  106.      * Sanity check
  107.      */
  108.     if (!mp)
  109.         return;
  110.  
  111.     /*
  112.      * Zero the slot pointer to avoid double free's
  113.      */
  114.     exported_ap[mp->am_mapno] = 0;
  115.  
  116.     /*
  117.      * Update the free and last_used indices
  118.      */
  119.     if (mp->am_mapno == last_used_map)
  120.         while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
  121.             --last_used_map;
  122.  
  123.     if (first_free_map > mp->am_mapno)
  124.         first_free_map = mp->am_mapno;
  125.  
  126. #ifdef DEBUG
  127.     /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n",
  128.         last_used_map, first_free_map);*/
  129. #endif
  130.  
  131.     /*
  132.      * Free the mount node
  133.      */
  134.     free(mp);
  135. }
  136.  
  137. /*
  138.  * Insert mp into the correct place,
  139.  * where p_mp is its parent node.
  140.  * A new node gets placed as the youngest sibling
  141.  * of any other children, and the parent's child
  142.  * pointer is adjusted to point to the new child node.
  143.  */
  144. void insert_am(mp, p_mp)
  145. am_node *mp;
  146. am_node *p_mp;
  147. {
  148.     /*
  149.      * If this is going in at the root then flag it
  150.      * so that it cannot be unmounted by amq.
  151.      */
  152.     if (p_mp == root_node)
  153.         mp->am_flags |= AMF_ROOT;
  154.     /*
  155.      * Fill in n-way links
  156.      */
  157.     mp->am_parent = p_mp;
  158.     mp->am_osib = p_mp->am_child;
  159.     if (mp->am_osib)
  160.         mp->am_osib->am_ysib = mp;
  161.     p_mp->am_child = mp;
  162. }
  163.  
  164. /*
  165.  * Remove am from its place in the mount tree
  166.  */
  167. void remove_am(mp)
  168. am_node *mp;
  169. {
  170.     /*
  171.      * 1.  Consistency check
  172.      */
  173.     if (mp->am_child && mp->am_parent) {
  174.         plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
  175.     }
  176.  
  177.     /*
  178.      * 2.  Update parent's child pointer
  179.      */
  180.     if (mp->am_parent && mp->am_parent->am_child == mp)
  181.         mp->am_parent->am_child = mp->am_osib;
  182.  
  183.     /*
  184.      * 3.  Unlink from sibling chain
  185.      */
  186.     if (mp->am_ysib)
  187.         mp->am_ysib->am_osib = mp->am_osib;
  188.     if (mp->am_osib)
  189.         mp->am_osib->am_ysib = mp->am_ysib;
  190. }
  191.  
  192. /*
  193.  * Compute a new time to live value for a node.
  194.  */
  195. void new_ttl(mp)
  196. am_node *mp;
  197. {
  198.     mp->am_timeo_w = 0;
  199.  
  200.     mp->am_ttl = clocktime();
  201.     mp->am_mnt->mf_fattr.atime.seconds = mp->am_ttl;
  202.     mp->am_ttl += mp->am_timeo;    /* sun's -tl option */
  203. }
  204.  
  205. /*
  206.  * Initialise an allocated mount node.
  207.  * It is assumed that the mount node was bzero'd
  208.  * before getting here so anything that would
  209.  * be set to zero isn't done here.
  210.  */
  211. void init_map(mp, dir)
  212. am_node *mp;
  213. char *dir;
  214. {
  215.     /* mp->am_mapno initalised by exported_ap_alloc */
  216.     mp->am_mnt = new_mntfs();
  217.     mp->am_name = strdup(dir);
  218.     mp->am_path = strdup(dir);
  219.     /*mp->am_link = 0;*/
  220.     /*mp->am_parent = 0;*/
  221.     /*mp->am_ysib = 0;*/
  222.     /*mp->am_osib = 0;*/
  223.     /*mp->am_child = 0;*/
  224.     /*mp->am_flags = 0;*/
  225.     /*mp->am_error = 0;*/
  226.     mp->am_gen = new_gen();
  227.     /*mp->am_pref = 0;*/
  228.  
  229.     mp->am_timeo = am_timeo;
  230.     new_ttl(mp);
  231.     mp->am_stats.s_mtime = mp->am_mnt->mf_fattr.atime.seconds;
  232.     /*mp->am_private = 0;*/
  233. }
  234.  
  235. /*
  236.  * Free a mount node.
  237.  * The node must be already unmounted.
  238.  */
  239. void free_map(mp)
  240. am_node *mp;
  241. {
  242.     remove_am(mp);
  243.  
  244.     if (mp->am_link)
  245.         free(mp->am_link);
  246.     if (mp->am_name)
  247.         free(mp->am_name);
  248.     if (mp->am_path)
  249.         free(mp->am_path);
  250.     if (mp->am_pref)
  251.         free(mp->am_pref);
  252.  
  253.     if (mp->am_mnt)
  254.         free_mntfs(mp->am_mnt);
  255.  
  256.     if (mp->am_flags & AMF_MKPATH)
  257.         rmdirs(mp->am_path);
  258.     exported_ap_free(mp);
  259. }
  260.  
  261. /*
  262.  * Convert from file handle to
  263.  * automount node.
  264.  */
  265. am_node *fh_to_mp3(fhp, rp, c_or_d)
  266. nfs_fh *fhp;
  267. int *rp;
  268. int c_or_d;
  269. {
  270.     struct am_fh *fp = (struct am_fh *) fhp;
  271.     am_node *ap = 0;
  272.  
  273.     /*
  274.      * Check process id matches
  275.      * If it doesn't then it is probably
  276.      * from an old kernel cached filehandle
  277.      * which is now out of date.
  278.      */
  279.     if (fp->fhh_pid != mypid)
  280.         goto drop;
  281.  
  282.     /*
  283.      * Make sure the index is valid before
  284.      * exported_ap is referenced.
  285.      */
  286.     if (fp->fhh_id < 0 || fp->fhh_id >= NEXP_AP)
  287.         goto drop;
  288.  
  289.     /*
  290.      * Get hold of the supposed mount node
  291.      */
  292.     ap = exported_ap[fp->fhh_id];
  293.  
  294.     /*
  295.      * If it exists then maybe...
  296.      */
  297.     if (ap) {
  298.         /*
  299.          * Check the generation number in the node
  300.          * matches the one from the kernel.  If not
  301.          * then the old node has been timed out and
  302.          * a new one allocated.
  303.          */
  304.         if (ap->am_gen != fp->fhh_gen) {
  305.             ap = 0;
  306.             goto drop;
  307.         }
  308.  
  309.         /*
  310.          * If the node is hung then locate a new node
  311.          * for it.  This implements the replicated filesystem
  312.          * retries.
  313.          */
  314.         if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
  315.             int error;
  316. #ifdef DEBUG
  317.             dlog("fh_to_mp3: %s (%s) is hung:- call lookup", ap->am_path, ap->am_mnt->mf_info);
  318. #endif
  319.             /*
  320.              * Update last access to original node.  This
  321.              * avoids timing it out and so sending ESTALE
  322.              * back to the kernel.
  323.              */
  324.             new_ttl(ap);
  325.  
  326.             /*
  327.              * Call the parent's lookup routine for an object
  328.              * with the same name.  This may return -1 in error
  329.              * if a mount is in progress.  In any case, if no
  330.              * mount node is returned the error code is propagated
  331.              * to the caller.
  332.              */
  333.             if (c_or_d == VLOOK_CREATE) {
  334.                 ap = (*ap->am_parent->am_mnt->mf_ops->lookuppn)(ap->am_parent,
  335.                         ap->am_name, &error, c_or_d);
  336.             } else {
  337.                 ap = 0;
  338.                 error = ESTALE;
  339.             }
  340.             if (ap == 0) {
  341.                 *rp = error;
  342.                 return 0;
  343.             }
  344.         }
  345.         /*
  346.          * Disallow references to objects being unmounted, unless
  347.          * they are automount points.
  348.          */
  349.         if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
  350.                 !(ap->am_flags & AMF_ROOT)) {
  351.             *rp = -1;
  352.             return 0;
  353.         }
  354.         new_ttl(ap);
  355.     }
  356.  
  357. drop:
  358.     if (!ap || !ap->am_mnt) {
  359.         /*
  360.          * If we are shutting down then it is likely
  361.          * that this node has disappeared because of
  362.          * a fast timeout.  To avoid things thrashing
  363.          * just pretend it doesn't exist at all.  If
  364.          * ESTALE is returned, some NFS clients just
  365.          * keep retrying (stupid or what - if it's
  366.          * stale now, what's it going to be in 5 minutes?)
  367.          */
  368.         if (amd_state == Finishing)
  369.             *rp = ENOENT;
  370.         else
  371.             *rp = ESTALE;
  372.         amd_stats.d_stale++;
  373.     }
  374.  
  375.     return ap;
  376. }
  377.  
  378. am_node *fh_to_mp(fhp)
  379. nfs_fh *fhp;
  380. {
  381.     int dummy;
  382.     return fh_to_mp2(fhp, &dummy);
  383. }
  384.  
  385. /*
  386.  * Convert from automount node to
  387.  * file handle.
  388.  */
  389. void mp_to_fh(mp, fhp)
  390. am_node *mp;
  391. struct nfs_fh *fhp;
  392. {
  393.     struct am_fh *fp = (struct am_fh *) fhp;
  394.  
  395.     /*
  396.      * Take the process id
  397.      */
  398.     fp->fhh_pid = mypid;
  399.     /*
  400.      * .. the map number
  401.      */
  402.     fp->fhh_id = mp->am_mapno;
  403.     /*
  404.      * .. and the generation number
  405.      */
  406.     fp->fhh_gen = mp->am_gen;
  407.     /*
  408.      * .. to make a "unique" triple that will never
  409.      * be reallocated except across reboots (which doesn't matter)
  410.      * or if we are unlucky enough to be given the same
  411.      * pid as a previous amd (very unlikely).
  412.      */
  413. }
  414.  
  415. static am_node *find_ap2(dir, mp)
  416. char *dir;
  417. am_node *mp;
  418. {
  419.     if (mp) {
  420.         am_node *mp2;
  421.         if (strcmp(mp->am_path, dir) == 0)
  422.             return mp;
  423.  
  424.         if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
  425.             strcmp(mp->am_mnt->mf_mount, dir) == 0)
  426.             return mp;
  427.  
  428.         mp2 = find_ap2(dir, mp->am_osib);
  429.         if (mp2)
  430.             return mp2;
  431.         return find_ap2(dir, mp->am_child);
  432.     }
  433.  
  434.     return 0;
  435. }
  436.  
  437. /*
  438.  * Find the mount node corresponding
  439.  * to dir.  dir can match either the
  440.  * automount path or, if the node is
  441.  * mounted, the mount location.
  442.  */
  443. am_node *find_ap(dir)
  444. char *dir;
  445. {
  446.     int i;
  447.  
  448.     for (i = last_used_map; i >= 0; --i) {
  449.         am_node *mp = exported_ap[i];
  450.         if (mp && (mp->am_flags & AMF_ROOT)) {
  451.             mp = find_ap2(dir, exported_ap[i]);
  452.             if (mp)
  453.                 return mp;
  454.         }
  455.     }
  456.  
  457.     return 0;
  458. }
  459.  
  460. /*
  461.  * Get the filehandle for a particular named directory.
  462.  * This is used during the bootstrap to tell the kernel
  463.  * the filehandles of the initial automount points.
  464.  */
  465. nfs_fh *root_fh(dir)
  466. char *dir;
  467. {
  468.     static nfs_fh nfh;
  469.     am_node *mp = root_ap(dir, TRUE);
  470.     if (mp) {
  471.         mp_to_fh(mp, &nfh);
  472.         return &nfh;
  473.     }
  474.  
  475.     /*
  476.      * Should never get here...
  477.      */
  478.     plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
  479.     return 0;
  480. }
  481.  
  482. am_node *root_ap(dir, path)
  483. char *dir;
  484. int path;
  485. {
  486.     am_node *mp = find_ap(dir);
  487.     if (mp && mp->am_parent == root_node)
  488.         return mp;
  489.  
  490.     return 0;
  491. }
  492.  
  493. /*
  494.  * Mount a top level automount node
  495.  * by calling lookup in the parent
  496.  * (root) node which will cause the
  497.  * automount node to be automounted (!)
  498.  */
  499. static void mount_auto_node(dir)
  500. char *dir;
  501. {
  502.     int error = 0;
  503.     (void) afs_ops.lookuppn(root_node, dir, &error, VLOOK_CREATE);
  504.     if (error) {
  505.         errno = error; /* XXX */
  506.         plog(XLOG_ERROR, "Could not start server on %s: %m", dir);
  507.     }
  508. }
  509.  
  510. /*
  511.  * Cause all the top-level mount nodes
  512.  * to be automounted
  513.  */
  514. int mount_exported()
  515. {
  516.     /*
  517.      * Iterate over all the nodes to be started
  518.      */
  519.     return root_keyiter(mount_auto_node);
  520. }
  521.  
  522. /*
  523.  * Construct top-level node
  524.  */
  525. void make_root_node()
  526. {
  527.     mntfs *root_mnt;
  528.     char *rootmap = ROOT_MAP;
  529.     root_node = exported_ap_alloc();
  530.  
  531.     init_map(root_node, "");
  532.     root_mnt = find_mntfs(&afs_ops, (am_opts *) 0, "", rootmap, "");
  533.     root_mnt->mf_mount = strealloc(root_mnt->mf_mount, pid_fsname);
  534.     root_mnt->mf_private = (voidp) mapc_find(rootmap, "");
  535.     root_mnt->mf_prfree = mapc_free;
  536.     free_mntfs(root_node->am_mnt);
  537.     root_node->am_mnt = root_mnt;
  538.     root_node->am_flags |= AMF_NOTIMEOUT;
  539.     root_mnt->mf_error = 0;
  540. }
  541.  
  542. /*
  543.  * Cause all the nodes to be unmounted by timing
  544.  * them out.
  545.  */
  546. void umount_exported(P_void)
  547. {
  548.     int i;
  549.     for (i = last_used_map; i >= 0; --i) {
  550.         am_node *mp = exported_ap[i];
  551.         if (mp) {
  552.             mntfs *mf = mp->am_mnt;
  553.             if (mf->mf_flags & MFF_UNMOUNTING) {
  554.                 /*
  555.                  * If this node is being unmounted then
  556.                  * just ignore it.  However, this could
  557.                  * prevent amd from finishing if the
  558.                  * unmount gets blocked since the am_node
  559.                  * will never be free'd.  am_unmounted needs
  560.                  * telling about this possibility. - XXX
  561.                  */
  562.                 continue;
  563.             }
  564.             if (mf && mf->mf_ops == &dfs_ops) {
  565.                 /*
  566.                  * When shutting down this had better
  567.                  * look like a directory, otherwise it
  568.                  * can't be unmounted!
  569.                  */
  570.                 mf->mf_fattr.type = NFDIR;
  571.                 mf->mf_fattr.mode = NFSMODE_DIR | 0555;
  572.             }
  573.             if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
  574.                 (mf->mf_flags & MFF_RESTART)) {
  575.                 /*
  576.                  * Just throw this node away without
  577.                  * bothering to unmount it.  If the
  578.                  * server is not known to be up then
  579.                  * don't discard the mounted on directory
  580.                  * or Amd might hang...
  581.                  */
  582.                 if (mf->mf_server &&
  583.                     (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID)
  584.                     mf->mf_flags &= ~MFF_MKMNT;
  585.                 am_unmounted(mp);
  586.             } else {
  587.                 /*
  588.                  * Any other node gets forcibly
  589.                  * timed out
  590.                  */
  591.                 mp->am_flags &= ~AMF_NOTIMEOUT;
  592.                 mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
  593.                 mp->am_ttl = 0;
  594.                 mp->am_timeo = 1;
  595.                 mp->am_timeo_w = 0;
  596.             }
  597.         }
  598.     }
  599. }
  600.  
  601. static int unmount_node P((am_node *mp));
  602. static int unmount_node(mp)
  603. am_node *mp;
  604. {
  605.     mntfs *mf = mp->am_mnt;
  606.     int error;
  607.  
  608.     if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
  609.         /*
  610.          * Just unlink
  611.          */
  612. #ifdef DEBUG
  613.         if (mf->mf_flags & MFF_ERROR)
  614.             dlog("No-op unmount of error node %s", mf->mf_info);
  615. #endif
  616.         error = 0;
  617.     } else {
  618. #ifdef DEBUG
  619.         dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
  620. #endif
  621.         error = (*mf->mf_ops->umount_fs)(mp);
  622.     }
  623.  
  624.     if (error) {
  625. #ifdef DEBUG
  626.         errno = error; /* XXX */
  627.         dlog("%s: unmount: %m", mf->mf_mount);
  628. #endif
  629.     }
  630.  
  631.     return error;
  632. }
  633.  
  634. static int unmount_node_wrap P((voidp vp));
  635. static int unmount_node_wrap(vp)
  636. voidp vp;
  637. {
  638.     /*
  639.      * This code should just say:
  640.      * return unmount_node((am_node *) vp);
  641.      *
  642.      * However...
  643.      * The kernel keeps a cached copy of filehandles,
  644.      * and doesn't ever cache them (apparently).  So
  645.      * when Amd times out a node the kernel will have a
  646.      * stale filehandle.  When the kernel next uses the
  647.      * filehandle it gets ESTALE.
  648.      *
  649.      * The workaround:
  650.      * Arrange that when a node is removed an unlink or
  651.      * rmdir is done on that path so that the kernel
  652.      * cache is done.  Yes - yuck.
  653.      *
  654.      * This can all be removed (and the background
  655.      * unmount flag in sfs_ops) if/when the kernel does
  656.      * something smarter.
  657.      */
  658.     am_node *mp = (am_node *) vp;
  659.     int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);
  660.     int error = unmount_node(mp);
  661.     if (error)
  662.         return error;
  663.     if (isauto && (int)amd_state < (int)Finishing) {
  664.         int islink = (mp->am_mnt->mf_fattr.type == NFLNK);
  665.         int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);
  666.         if (islink) {
  667.             if (unlink(mp->am_path) < 0)
  668.                 return errno;
  669.         } else if (isdir) {
  670.             if (rmdir(mp->am_path) < 0)
  671.                 return errno;
  672.         }
  673.     }
  674.     return 0;
  675. }
  676.  
  677. static void free_map_if_success(rc, term, closure)
  678. int rc;
  679. int term;
  680. voidp closure;
  681. {
  682.     am_node *mp = (am_node *) closure;
  683.     mntfs *mf = mp->am_mnt;
  684.  
  685.     /*
  686.      * Not unmounting any more
  687.      */
  688.     mf->mf_flags &= ~MFF_UNMOUNTING;
  689.  
  690.     /*
  691.      * If a timeout was defered because the underlying filesystem
  692.      * was busy then arrange for a timeout as soon as possible.
  693.      */
  694.     if (mf->mf_flags & MFF_WANTTIMO) {
  695.         mf->mf_flags &= ~MFF_WANTTIMO;
  696.         reschedule_timeout_mp();
  697.     }
  698.  
  699.     if (term) {
  700.         plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
  701. #ifdef DEBUG
  702.         /*
  703.          * dbx likes to put a trap on exit().
  704.          * Pretend it succeeded for now...
  705.          */
  706.         if (term == SIGTRAP) {
  707.             am_unmounted(mp);
  708.         }
  709. #endif
  710.         amd_stats.d_uerr++;
  711.     } else if (rc) {
  712.         if (rc == EBUSY) {
  713.             plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
  714.         } else {
  715.             errno = rc;    /* XXX */
  716.             plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);
  717.         }
  718.         amd_stats.d_uerr++;
  719.     } else {
  720.         am_unmounted(mp);
  721.     }
  722.  
  723.     /*
  724.      * Wakeup anything waiting for this mount
  725.      */
  726.     wakeup((voidp) mf);
  727. }
  728.  
  729. static void unmount_mp(mp)
  730. am_node *mp;
  731. {
  732.     mntfs *mf = mp->am_mnt;
  733. #ifdef notdef
  734.     plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
  735. #endif
  736.     if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&
  737.             (mf->mf_flags & MFF_MOUNTED) /* &&
  738.             mf->mf_refc == 1 */) {
  739.         if (FSRV_ISDOWN(mf->mf_server)) {
  740.             /*
  741.              * Don't try to unmount from a server that is known to be down
  742.              */
  743.             if (!(mf->mf_flags & MFF_LOGDOWN)) {
  744.                 /* Only log this once, otherwise gets a bit boring */
  745.                 plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
  746.                 mf->mf_flags |= MFF_LOGDOWN;
  747.             }
  748.         } else {
  749.             /* Clear logdown flag - since the server must be up */
  750.             mf->mf_flags &= ~MFF_LOGDOWN;
  751. #ifdef DEBUG
  752.             /*dlog("Will background the unmount attempt");*/
  753. #endif
  754.             /*
  755.              * Note that we are unmounting this node
  756.              */
  757.             mf->mf_flags |= MFF_UNMOUNTING;
  758.             run_task(unmount_node_wrap, (voidp) mp,
  759.                  free_map_if_success, (voidp) mp);
  760. #ifdef DEBUG
  761.             dlog("unmount attempt backgrounded");
  762. #endif
  763.         }
  764.     } else {
  765. #ifdef DEBUG
  766.         dlog("Trying unmount in foreground");
  767. #endif
  768.         mf->mf_flags |= MFF_UNMOUNTING;
  769.         free_map_if_success(unmount_node(mp), 0, (voidp) mp);
  770. #ifdef DEBUG
  771.         dlog("unmount attempt done");
  772. #endif
  773.     }
  774. }
  775.  
  776. void timeout_mp()
  777. {
  778. #define NEVER (time_t) 0
  779. #define    smallest_t(t1, t2) \
  780.     (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
  781. #define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
  782.  
  783.     int i;
  784.     time_t t = NEVER;
  785.     time_t now = clocktime();
  786.  
  787. #ifdef DEBUG
  788.     dlog("Timing out automount points...");
  789. #endif
  790.     for (i = last_used_map; i >= 0; --i) {
  791.         am_node *mp = exported_ap[i];
  792.         mntfs *mf;
  793.         /*
  794.          * Just continue if nothing mounted, or can't be timed out.
  795.          */
  796.         if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
  797.             continue;
  798.         /*
  799.          * Pick up mounted filesystem
  800.          */
  801.         mf = mp->am_mnt;
  802.         if (!mf)
  803.             continue;
  804.         /*
  805.          * Don't delete last reference to a restarted filesystem.
  806.          */
  807.         if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
  808.             continue;
  809.         /*
  810.          * If there is action on this filesystem then ignore it
  811.          */
  812.         if (!(mf->mf_flags & IGNORE_FLAGS)) {
  813.             int expired = 0;
  814.             mf->mf_flags &= ~MFF_WANTTIMO;
  815. #ifdef DEBUG
  816.             /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/
  817. #endif
  818.             if (now >= mp->am_ttl) {
  819.                 expired = 1;
  820.                 /*
  821.                  * Move the ttl forward to avoid thrashing effects
  822.                  * on the next call to timeout!
  823.                  */
  824.                 /* sun's -tw option */
  825.                 if (mp->am_timeo_w < 4 * am_timeo_w)
  826.                     mp->am_timeo_w += am_timeo_w;
  827.                 mp->am_ttl = now + mp->am_timeo_w;
  828.             }
  829.             /*
  830.              * If the next ttl is smallest, use that
  831.              */
  832.             t = smallest_t(t, mp->am_ttl);
  833.  
  834. #ifdef DEBUG
  835.             /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/
  836. #endif
  837.  
  838.             if (!mp->am_child && mf->mf_error >= 0 && expired)
  839.                 unmount_mp(mp);
  840.         } else if (mf->mf_flags & MFF_UNMOUNTING) {
  841.             mf->mf_flags |= MFF_WANTTIMO;
  842.         }
  843.     }
  844.  
  845.     if (t == NEVER) {
  846. #ifdef DEBUG
  847.         dlog("No further timeouts");
  848. #endif
  849.         t = now + ONE_HOUR;
  850.     }
  851.  
  852.     /*
  853.      * Sanity check to avoid runaways.
  854.      * Absolutely should never get this but
  855.      * if you do without this trap amd will thrash.
  856.      */
  857.     if (t <= now) {
  858.         t = now + 6;    /* XXX */
  859.         plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
  860.     }
  861.     /*
  862.      * XXX - when shutting down, make things happen faster
  863.      */
  864.     if ((int)amd_state >= (int)Finishing)
  865.         t = now + 1;
  866. #ifdef DEBUG
  867.     dlog("Next mount timeout in %ds", t - now);
  868. #endif
  869.  
  870.     timeout_mp_id = timeout(t - now, timeout_mp, 0);
  871.  
  872. #undef NEVER
  873. #undef smallest_t
  874. #undef IGNORE_FLAGS
  875. }
  876.  
  877. /*
  878.  * Cause timeout_mp to be called soonest
  879.  */
  880. void reschedule_timeout_mp()
  881. {
  882.     if (timeout_mp_id)
  883.         untimeout(timeout_mp_id);
  884.     timeout_mp_id = timeout(0, timeout_mp, 0);
  885. }
  886.