138494Sobrien/* 2310490Scy * Copyright (c) 1997-2014 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 19310490Scy * 3. Neither the name of the University nor the names of its contributors 2038494Sobrien * may be used to endorse or promote products derived from this software 2138494Sobrien * without specific prior written permission. 2238494Sobrien * 2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2438494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2538494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2638494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2738494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2838494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2938494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3038494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3138494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3238494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3338494Sobrien * SUCH DAMAGE. 3438494Sobrien * 3538494Sobrien * 36174294Sobrien * File: am-utils/amd/map.c 3738494Sobrien * 3838494Sobrien */ 3938494Sobrien 4038494Sobrien#ifdef HAVE_CONFIG_H 4138494Sobrien# include <config.h> 4238494Sobrien#endif /* HAVE_CONFIG_H */ 4338494Sobrien#include <am_defs.h> 4438494Sobrien#include <amd.h> 4538494Sobrien 4638494Sobrien#define smallest_t(t1, t2) (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2) 4738494Sobrien#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART) 4838494Sobrien#define new_gen() (am_gen++) 4938494Sobrien 5038494Sobrien/* 5138494Sobrien * Generation Numbers. 5238494Sobrien * 5338494Sobrien * Generation numbers are allocated to every node created 5438494Sobrien * by amd. When a filehandle is computed and sent to the 5538494Sobrien * kernel, the generation number makes sure that it is safe 5638494Sobrien * to reallocate a node slot even when the kernel has a cached 5738494Sobrien * reference to its old incarnation. 5838494Sobrien * No garbage collection is done, since it is assumed that 5938494Sobrien * there is no way that 2^32 generation numbers could ever 6038494Sobrien * be allocated by a single run of amd - there is simply 6138494Sobrien * not enough cpu time available. 6282794Sobrien * Famous last words... -Ion 6338494Sobrien */ 6438494Sobrienstatic u_int am_gen = 2; /* Initial generation number */ 6538494Sobrienstatic int timeout_mp_id; /* Id from last call to timeout */ 6638494Sobrien 67174294Sobrienstatic am_node *root_node; /* The root of the mount tree */ 68310490Scystatic am_node **exported_ap = (am_node **) NULL; 69174294Sobrienstatic int exported_ap_size = 0; 70174294Sobrienstatic int first_free_map = 0; /* First available free slot */ 71174294Sobrienstatic int last_used_map = -1; /* Last unavailable used slot */ 7238494Sobrien 7338494Sobrien 7438494Sobrien/* 7538494Sobrien * This is the default attributes field which 7638494Sobrien * is copied into every new node to be created. 7738494Sobrien * The individual filesystem fs_init() routines 7838494Sobrien * patch the copy to represent the particular 7938494Sobrien * details for the relevant filesystem type 8038494Sobrien */ 8138494Sobrienstatic nfsfattr gen_fattr = 8238494Sobrien{ 8338494Sobrien NFLNK, /* type */ 8438494Sobrien NFSMODE_LNK | 0777, /* mode */ 8538494Sobrien 1, /* nlink */ 8638494Sobrien 0, /* uid */ 8738494Sobrien 0, /* gid */ 8838494Sobrien 0, /* size */ 8938494Sobrien 4096, /* blocksize */ 9038494Sobrien 0, /* rdev */ 9138494Sobrien 1, /* blocks */ 9238494Sobrien 0, /* fsid */ 9338494Sobrien 0, /* fileid */ 9438494Sobrien {0, 0}, /* atime */ 9538494Sobrien {0, 0}, /* mtime */ 9638494Sobrien {0, 0}, /* ctime */ 9738494Sobrien}; 9838494Sobrien 9938494Sobrien/* forward declarations */ 100174294Sobrienstatic int unmount_node(opaque_t arg); 10138494Sobrienstatic void exported_ap_free(am_node *mp); 10238494Sobrienstatic void remove_am(am_node *mp); 103174294Sobrienstatic am_node *get_root_ap(char *dir); 10438494Sobrien 10538494Sobrien 10638494Sobrien/* 107174294Sobrien * Iterator functions for exported_ap[] 108174294Sobrien */ 109174294Sobrienam_node * 110174294Sobrienget_first_exported_ap(int *index) 111174294Sobrien{ 112174294Sobrien *index = -1; 113174294Sobrien return get_next_exported_ap(index); 114174294Sobrien} 115174294Sobrien 116174294Sobrien 117174294Sobrienam_node * 118174294Sobrienget_next_exported_ap(int *index) 119174294Sobrien{ 120174294Sobrien (*index)++; 121174294Sobrien while (*index < exported_ap_size) { 122174294Sobrien if (exported_ap[*index] != NULL) 123174294Sobrien return exported_ap[*index]; 124174294Sobrien (*index)++; 125174294Sobrien } 126174294Sobrien return NULL; 127174294Sobrien} 128174294Sobrien 129174294Sobrien 130174294Sobrien/* 131174294Sobrien * Get exported_ap by index 132174294Sobrien */ 133174294Sobrienam_node * 134174294Sobrienget_exported_ap(int index) 135174294Sobrien{ 136174294Sobrien if (index < 0 || index >= exported_ap_size) 137174294Sobrien return 0; 138174294Sobrien return exported_ap[index]; 139174294Sobrien} 140174294Sobrien 141174294Sobrien 142174294Sobrien/* 143174294Sobrien * Get exported_ap by path 144174294Sobrien */ 145174294Sobrienam_node * 146174294Sobrienpath_to_exported_ap(char *path) 147174294Sobrien{ 148174294Sobrien int index; 149174294Sobrien am_node *mp; 150174294Sobrien 151174294Sobrien mp = get_first_exported_ap(&index); 152174294Sobrien while (mp != NULL) { 153174294Sobrien if (STREQ(mp->am_path, path)) 154174294Sobrien break; 155174294Sobrien mp = get_next_exported_ap(&index); 156174294Sobrien } 157174294Sobrien return mp; 158174294Sobrien} 159174294Sobrien 160174294Sobrien 161174294Sobrien/* 16238494Sobrien * Resize exported_ap map 16338494Sobrien */ 16438494Sobrienstatic int 16538494Sobrienexported_ap_realloc_map(int nsize) 16638494Sobrien{ 16738494Sobrien /* 16838494Sobrien * this shouldn't happen, but... 16938494Sobrien */ 17038494Sobrien if (nsize < 0 || nsize == exported_ap_size) 17138494Sobrien return 0; 17238494Sobrien 17338494Sobrien exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node *)); 17438494Sobrien 17538494Sobrien if (nsize > exported_ap_size) 17638494Sobrien memset((char *) (exported_ap + exported_ap_size), 0, 17738494Sobrien (nsize - exported_ap_size) * sizeof(am_node *)); 17838494Sobrien exported_ap_size = nsize; 17938494Sobrien 18038494Sobrien return 1; 18138494Sobrien} 18238494Sobrien 18338494Sobrien 184174294Sobrien 185174294Sobrienam_node * 186174294Sobrienget_ap_child(am_node *mp, char *fname) 187174294Sobrien{ 188174294Sobrien am_node *new_mp; 189310490Scy mntfs *mf = mp->am_al->al_mnt; 190174294Sobrien 191174294Sobrien /* 192174294Sobrien * Allocate a new map 193174294Sobrien */ 194174294Sobrien new_mp = exported_ap_alloc(); 195174294Sobrien if (new_mp) { 196174294Sobrien /* 197174294Sobrien * Fill it in 198174294Sobrien */ 199174294Sobrien init_map(new_mp, fname); 200174294Sobrien 201174294Sobrien /* 202174294Sobrien * Put it in the table 203174294Sobrien */ 204174294Sobrien insert_am(new_mp, mp); 205174294Sobrien 206174294Sobrien /* 207174294Sobrien * Fill in some other fields, 208174294Sobrien * path and mount point. 209174294Sobrien * 210174294Sobrien * bugfix: do not prepend old am_path if direct map 211174294Sobrien * <wls@astro.umd.edu> William Sebok 212174294Sobrien */ 213174294Sobrien new_mp->am_path = str3cat(new_mp->am_path, 214174294Sobrien (mf->mf_fsflags & FS_DIRECT) 215174294Sobrien ? "" 216174294Sobrien : mp->am_path, 217174294Sobrien *fname == '/' ? "" : "/", fname); 218174294Sobrien dlog("setting path to %s", new_mp->am_path); 219174294Sobrien } 220174294Sobrien 221174294Sobrien return new_mp; 222174294Sobrien} 223174294Sobrien 22438494Sobrien/* 22538494Sobrien * Allocate a new mount slot and create 22638494Sobrien * a new node. 22738494Sobrien * Fills in the map number of the node, 22842629Sobrien * but leaves everything else uninitialized. 22938494Sobrien */ 23038494Sobrienam_node * 23138494Sobrienexported_ap_alloc(void) 23238494Sobrien{ 23338494Sobrien am_node *mp, **mpp; 23438494Sobrien 23538494Sobrien /* 23638494Sobrien * First check if there are any slots left, realloc if needed 23738494Sobrien */ 23838494Sobrien if (first_free_map >= exported_ap_size) 23938494Sobrien if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP)) 24038494Sobrien return 0; 24138494Sobrien 24238494Sobrien /* 24338494Sobrien * Grab the next free slot 24438494Sobrien */ 24538494Sobrien mpp = exported_ap + first_free_map; 24638494Sobrien mp = *mpp = ALLOC(struct am_node); 247174294Sobrien memset((char *) mp, 0, sizeof(struct am_node)); 24838494Sobrien 24938494Sobrien mp->am_mapno = first_free_map++; 25038494Sobrien 25138494Sobrien /* 25238494Sobrien * Update free pointer 25338494Sobrien */ 25438494Sobrien while (first_free_map < exported_ap_size && exported_ap[first_free_map]) 25538494Sobrien first_free_map++; 25638494Sobrien 25738494Sobrien if (first_free_map > last_used_map) 25838494Sobrien last_used_map = first_free_map - 1; 25938494Sobrien 26038494Sobrien return mp; 26138494Sobrien} 26238494Sobrien 26338494Sobrien 26438494Sobrien/* 26538494Sobrien * Free a mount slot 26638494Sobrien */ 26738494Sobrienstatic void 26838494Sobrienexported_ap_free(am_node *mp) 26938494Sobrien{ 27038494Sobrien /* 27138494Sobrien * Sanity check 27238494Sobrien */ 27338494Sobrien if (!mp) 27438494Sobrien return; 27538494Sobrien 27638494Sobrien /* 27738494Sobrien * Zero the slot pointer to avoid double free's 27838494Sobrien */ 279310490Scy exported_ap[mp->am_mapno] = NULL; 28038494Sobrien 28138494Sobrien /* 28238494Sobrien * Update the free and last_used indices 28338494Sobrien */ 28438494Sobrien if (mp->am_mapno == last_used_map) 28538494Sobrien while (last_used_map >= 0 && exported_ap[last_used_map] == 0) 28638494Sobrien --last_used_map; 28738494Sobrien 28838494Sobrien if (first_free_map > mp->am_mapno) 28938494Sobrien first_free_map = mp->am_mapno; 29038494Sobrien 29138494Sobrien /* 292174294Sobrien * Free the mount node, and zero out it's internal struct data. 29338494Sobrien */ 294174294Sobrien memset((char *) mp, 0, sizeof(am_node)); 29538494Sobrien XFREE(mp); 29638494Sobrien} 29738494Sobrien 29838494Sobrien 29938494Sobrien/* 30038494Sobrien * Insert mp into the correct place, 30138494Sobrien * where p_mp is its parent node. 30238494Sobrien * A new node gets placed as the youngest sibling 30338494Sobrien * of any other children, and the parent's child 30438494Sobrien * pointer is adjusted to point to the new child node. 30538494Sobrien */ 30638494Sobrienvoid 30738494Sobrieninsert_am(am_node *mp, am_node *p_mp) 30838494Sobrien{ 30938494Sobrien /* 31038494Sobrien * If this is going in at the root then flag it 31138494Sobrien * so that it cannot be unmounted by amq. 31238494Sobrien */ 31338494Sobrien if (p_mp == root_node) 31438494Sobrien mp->am_flags |= AMF_ROOT; 31538494Sobrien /* 31638494Sobrien * Fill in n-way links 31738494Sobrien */ 31838494Sobrien mp->am_parent = p_mp; 31938494Sobrien mp->am_osib = p_mp->am_child; 32038494Sobrien if (mp->am_osib) 32138494Sobrien mp->am_osib->am_ysib = mp; 32238494Sobrien p_mp->am_child = mp; 323174294Sobrien#ifdef HAVE_FS_AUTOFS 324310490Scy if (p_mp->am_al->al_mnt->mf_flags & MFF_IS_AUTOFS) 325174294Sobrien mp->am_flags |= AMF_AUTOFS; 326174294Sobrien#endif /* HAVE_FS_AUTOFS */ 32738494Sobrien} 32838494Sobrien 32938494Sobrien 33038494Sobrien/* 33138494Sobrien * Remove am from its place in the mount tree 33238494Sobrien */ 33338494Sobrienstatic void 33438494Sobrienremove_am(am_node *mp) 33538494Sobrien{ 33638494Sobrien /* 33738494Sobrien * 1. Consistency check 33838494Sobrien */ 33938494Sobrien if (mp->am_child && mp->am_parent) { 34038494Sobrien plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path); 34138494Sobrien } 34238494Sobrien 34338494Sobrien /* 34438494Sobrien * 2. Update parent's child pointer 34538494Sobrien */ 34638494Sobrien if (mp->am_parent && mp->am_parent->am_child == mp) 34738494Sobrien mp->am_parent->am_child = mp->am_osib; 34838494Sobrien 34938494Sobrien /* 35038494Sobrien * 3. Unlink from sibling chain 35138494Sobrien */ 35238494Sobrien if (mp->am_ysib) 35338494Sobrien mp->am_ysib->am_osib = mp->am_osib; 35438494Sobrien if (mp->am_osib) 35538494Sobrien mp->am_osib->am_ysib = mp->am_ysib; 35638494Sobrien} 35738494Sobrien 35838494Sobrien 35938494Sobrien/* 36038494Sobrien * Compute a new time to live value for a node. 36138494Sobrien */ 36238494Sobrienvoid 36338494Sobriennew_ttl(am_node *mp) 36438494Sobrien{ 36538494Sobrien mp->am_timeo_w = 0; 366174294Sobrien mp->am_ttl = clocktime(&mp->am_fattr.na_atime); 36738494Sobrien mp->am_ttl += mp->am_timeo; /* sun's -tl option */ 36838494Sobrien} 36938494Sobrien 37038494Sobrien 37138494Sobrienvoid 372174294Sobrienmk_fattr(nfsfattr *fattr, nfsftype vntype) 37338494Sobrien{ 37438494Sobrien switch (vntype) { 37538494Sobrien case NFDIR: 376174294Sobrien fattr->na_type = NFDIR; 377174294Sobrien fattr->na_mode = NFSMODE_DIR | 0555; 378174294Sobrien fattr->na_nlink = 2; 379174294Sobrien fattr->na_size = 512; 38038494Sobrien break; 38138494Sobrien case NFLNK: 382174294Sobrien fattr->na_type = NFLNK; 383174294Sobrien fattr->na_mode = NFSMODE_LNK | 0777; 384174294Sobrien fattr->na_nlink = 1; 385174294Sobrien fattr->na_size = 0; 38638494Sobrien break; 38738494Sobrien default: 38838494Sobrien plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype); 38938494Sobrien break; 39038494Sobrien } 39138494Sobrien} 39238494Sobrien 39338494Sobrien 39438494Sobrien/* 39542629Sobrien * Initialize an allocated mount node. 39638494Sobrien * It is assumed that the mount node was b-zero'd 39738494Sobrien * before getting here so anything that would 39838494Sobrien * be set to zero isn't done here. 39938494Sobrien */ 40038494Sobrienvoid 40138494Sobrieninit_map(am_node *mp, char *dir) 40238494Sobrien{ 40338494Sobrien /* 40438494Sobrien * mp->am_mapno is initialized by exported_ap_alloc 405174294Sobrien * other fields don't need to be set to zero. 40638494Sobrien */ 407310490Scy 408310490Scy mp->am_al = new_loc(); 409310490Scy mp->am_alarray = NULL; 410310490Scy mp->am_name = xstrdup(dir); 411310490Scy mp->am_path = xstrdup(dir); 41238494Sobrien mp->am_gen = new_gen(); 413174294Sobrien#ifdef HAVE_FS_AUTOFS 414310490Scy mp->am_autofs_fh = NULL; 415174294Sobrien#endif /* HAVE_FS_AUTOFS */ 41638494Sobrien 41738494Sobrien mp->am_timeo = gopt.am_timeo; 41838494Sobrien mp->am_attr.ns_status = NFS_OK; 41938494Sobrien mp->am_fattr = gen_fattr; 42038494Sobrien mp->am_fattr.na_fsid = 42; 42182794Sobrien mp->am_fattr.na_fileid = mp->am_gen; 422174294Sobrien clocktime(&mp->am_fattr.na_atime); 423174294Sobrien /* next line copies a "struct nfstime" among several fields */ 42438494Sobrien mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime; 42538494Sobrien 42638494Sobrien new_ttl(mp); 42738494Sobrien mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds; 428174294Sobrien mp->am_dev = -1; 429174294Sobrien mp->am_rdev = -1; 430310490Scy mp->am_fd[0] = -1; 431310490Scy mp->am_fd[1] = -1; 43238494Sobrien} 43338494Sobrien 43438494Sobrien 435310490Scyvoid 436310490Scynotify_child(am_node *mp, au_etype au_etype, int au_errno, int au_signal) 437310490Scy{ 438310490Scy amq_sync_umnt rv; 439310490Scy int err; 440310490Scy 441310490Scy if (mp->am_fd[1] >= 0) { /* we have a child process */ 442310490Scy rv.au_etype = au_etype; 443310490Scy rv.au_signal = au_signal; 444310490Scy rv.au_errno = au_errno; 445310490Scy 446310490Scy err = write(mp->am_fd[1], &rv, sizeof(rv)); 447310490Scy /* XXX: do something else on err? */ 448310490Scy if (err < sizeof(rv)) 449310490Scy plog(XLOG_INFO, "notify_child: write returned %d instead of %d.", 450310490Scy err, (int) sizeof(rv)); 451310490Scy close(mp->am_fd[1]); 452310490Scy mp->am_fd[1] = -1; 453310490Scy } 454310490Scy} 455310490Scy 456310490Scy 45738494Sobrien/* 45838494Sobrien * Free a mount node. 45938494Sobrien * The node must be already unmounted. 46038494Sobrien */ 46138494Sobrienvoid 46238494Sobrienfree_map(am_node *mp) 46338494Sobrien{ 46438494Sobrien remove_am(mp); 46538494Sobrien 466310490Scy if (mp->am_fd[1] != -1) 467310490Scy plog(XLOG_FATAL, "free_map: called prior to notifying the child for %s.", 468310490Scy mp->am_path); 46938494Sobrien 470310490Scy XFREE(mp->am_link); 471310490Scy XFREE(mp->am_name); 472310490Scy XFREE(mp->am_path); 473310490Scy XFREE(mp->am_pref); 474310490Scy XFREE(mp->am_transp); 47538494Sobrien 476310490Scy if (mp->am_al) 477310490Scy free_loc(mp->am_al); 478310490Scy 479310490Scy if (mp->am_alarray) { 480310490Scy am_loc **temp_al; 481310490Scy for (temp_al = mp->am_alarray; *temp_al; temp_al++) 482310490Scy free_loc(*temp_al); 483310490Scy XFREE(mp->am_alarray); 48438494Sobrien } 48538494Sobrien 486174294Sobrien#ifdef HAVE_FS_AUTOFS 487174294Sobrien if (mp->am_autofs_fh) 488174294Sobrien autofs_release_fh(mp); 489174294Sobrien#endif /* HAVE_FS_AUTOFS */ 49038494Sobrien 491174294Sobrien exported_ap_free(mp); 49238494Sobrien} 49338494Sobrien 49438494Sobrien 495174294Sobrienstatic am_node * 496174294Sobrienfind_ap_recursive(char *dir, am_node *mp) 49738494Sobrien{ 49838494Sobrien if (mp) { 49938494Sobrien am_node *mp2; 50038494Sobrien if (STREQ(mp->am_path, dir)) 50138494Sobrien return mp; 50238494Sobrien 503310490Scy if ((mp->am_al->al_mnt->mf_flags & MFF_MOUNTED) && 504310490Scy STREQ(mp->am_al->al_mnt->mf_mount, dir)) 50538494Sobrien return mp; 50638494Sobrien 507174294Sobrien mp2 = find_ap_recursive(dir, mp->am_osib); 50838494Sobrien if (mp2) 50938494Sobrien return mp2; 510174294Sobrien return find_ap_recursive(dir, mp->am_child); 51138494Sobrien } 51238494Sobrien 51338494Sobrien return 0; 51438494Sobrien} 51538494Sobrien 51638494Sobrien 51738494Sobrien/* 51838494Sobrien * Find the mount node corresponding to dir. dir can match either the 51938494Sobrien * automount path or, if the node is mounted, the mount location. 52038494Sobrien */ 52138494Sobrienam_node * 52238494Sobrienfind_ap(char *dir) 52338494Sobrien{ 52438494Sobrien int i; 52538494Sobrien 52638494Sobrien for (i = last_used_map; i >= 0; --i) { 52738494Sobrien am_node *mp = exported_ap[i]; 52838494Sobrien if (mp && (mp->am_flags & AMF_ROOT)) { 529174294Sobrien mp = find_ap_recursive(dir, exported_ap[i]); 53038494Sobrien if (mp) { 53138494Sobrien return mp; 53238494Sobrien } 53338494Sobrien } 53438494Sobrien } 53538494Sobrien 53638494Sobrien return 0; 53738494Sobrien} 53838494Sobrien 53938494Sobrien 54038494Sobrien/* 54138494Sobrien * Get the filehandle for a particular named directory. 54238494Sobrien * This is used during the bootstrap to tell the kernel 54338494Sobrien * the filehandles of the initial automount points. 54438494Sobrien */ 545310490Scyam_nfs_handle_t * 546310490Scyget_root_nfs_fh(char *dir, am_nfs_handle_t *nfh) 54738494Sobrien{ 548174294Sobrien am_node *mp = get_root_ap(dir); 54938494Sobrien if (mp) { 550310490Scy if (nfs_dispatcher == nfs_program_2) 551310490Scy mp_to_fh(mp, &nfh->v2); 552310490Scy else 553310490Scy mp_to_fh3(mp, &nfh->v3); 554310490Scy return nfh; 55538494Sobrien } 55638494Sobrien 55738494Sobrien /* 55838494Sobrien * Should never get here... 55938494Sobrien */ 56038494Sobrien plog(XLOG_ERROR, "Can't find root filehandle for %s", dir); 56138494Sobrien 56238494Sobrien return 0; 56338494Sobrien} 56438494Sobrien 56538494Sobrien 566174294Sobrienstatic am_node * 567174294Sobrienget_root_ap(char *dir) 56838494Sobrien{ 56938494Sobrien am_node *mp = find_ap(dir); 57038494Sobrien 57138494Sobrien if (mp && mp->am_parent == root_node) 57238494Sobrien return mp; 57338494Sobrien 57438494Sobrien return 0; 57538494Sobrien} 57638494Sobrien 57738494Sobrien 57838494Sobrien/* 57938494Sobrien * Timeout all nodes waiting on 58038494Sobrien * a given Fserver. 58138494Sobrien */ 58238494Sobrienvoid 58338494Sobrienmap_flush_srvr(fserver *fs) 58438494Sobrien{ 58538494Sobrien int i; 58638494Sobrien int done = 0; 58738494Sobrien 58838494Sobrien for (i = last_used_map; i >= 0; --i) { 58938494Sobrien am_node *mp = exported_ap[i]; 590310490Scy 591310490Scy if (mp && mp->am_al->al_mnt && mp->am_al->al_mnt->mf_server == fs) { 59238494Sobrien plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host); 593174294Sobrien mp->am_ttl = clocktime(NULL); 59438494Sobrien done = 1; 59538494Sobrien } 59638494Sobrien } 59738494Sobrien if (done) 59838494Sobrien reschedule_timeout_mp(); 59938494Sobrien} 60038494Sobrien 60138494Sobrien 60238494Sobrien/* 60338494Sobrien * Mount a top level automount node 60438494Sobrien * by calling lookup in the parent 60538494Sobrien * (root) node which will cause the 60638494Sobrien * automount node to be automounted. 60738494Sobrien */ 60838494Sobrienint 609174294Sobrienmount_auto_node(char *dir, opaque_t arg) 61038494Sobrien{ 61138494Sobrien int error = 0; 612174294Sobrien am_node *mp = (am_node *) arg; 613174294Sobrien am_node *new_mp; 61438494Sobrien 615310490Scy new_mp = mp->am_al->al_mnt->mf_ops->lookup_child(mp, dir, &error, VLOOK_CREATE); 616174294Sobrien if (new_mp && error < 0) { 617174294Sobrien /* 618174294Sobrien * We can't allow the fileid of the root node to change. 619174294Sobrien * Should be ok to force it to 1, always. 620174294Sobrien */ 621174294Sobrien new_mp->am_gen = new_mp->am_fattr.na_fileid = 1; 622174294Sobrien 623310490Scy (void) mp->am_al->al_mnt->mf_ops->mount_child(new_mp, &error); 624174294Sobrien } 625174294Sobrien 62638494Sobrien if (error > 0) { 62738494Sobrien errno = error; /* XXX */ 62838494Sobrien plog(XLOG_ERROR, "Could not mount %s: %m", dir); 62938494Sobrien } 63038494Sobrien return error; 63138494Sobrien} 63238494Sobrien 63338494Sobrien 63438494Sobrien/* 63538494Sobrien * Cause all the top-level mount nodes 63638494Sobrien * to be automounted 63738494Sobrien */ 63838494Sobrienint 63938494Sobrienmount_exported(void) 64038494Sobrien{ 64138494Sobrien /* 64238494Sobrien * Iterate over all the nodes to be started 64338494Sobrien */ 644174294Sobrien return root_keyiter(mount_auto_node, root_node); 64538494Sobrien} 64638494Sobrien 64738494Sobrien 64838494Sobrien/* 64938494Sobrien * Construct top-level node 65038494Sobrien */ 65138494Sobrienvoid 65238494Sobrienmake_root_node(void) 65338494Sobrien{ 654310490Scy mntfs *root_mf; 65538494Sobrien char *rootmap = ROOT_MAP; 65638494Sobrien root_node = exported_ap_alloc(); 65738494Sobrien 65838494Sobrien /* 65938494Sobrien * Allocate a new map 66038494Sobrien */ 66138494Sobrien init_map(root_node, ""); 66238494Sobrien 66338494Sobrien /* 66438494Sobrien * Allocate a new mounted filesystem 66538494Sobrien */ 666310490Scy root_mf = find_mntfs(&amfs_root_ops, (am_opts *) NULL, "", rootmap, "", "", ""); 66738494Sobrien 66838494Sobrien /* 66938494Sobrien * Replace the initial null reference 67038494Sobrien */ 671310490Scy free_mntfs(root_node->am_al->al_mnt); 672310490Scy root_node->am_al->al_mnt = root_mf; 67338494Sobrien 67438494Sobrien /* 67542629Sobrien * Initialize the root 67638494Sobrien */ 677310490Scy if (root_mf->mf_ops->fs_init) 678310490Scy (*root_mf->mf_ops->fs_init) (root_mf); 67938494Sobrien 68038494Sobrien /* 68138494Sobrien * Mount the root 68238494Sobrien */ 683310490Scy root_mf->mf_error = root_mf->mf_ops->mount_fs(root_node, root_mf); 68438494Sobrien} 68538494Sobrien 68638494Sobrien 68738494Sobrien/* 68838494Sobrien * Cause all the nodes to be unmounted by timing 68938494Sobrien * them out. 69038494Sobrien */ 69138494Sobrienvoid 69238494Sobrienumount_exported(void) 69338494Sobrien{ 694310490Scy int i, work_done; 69538494Sobrien 696310490Scy do { 697310490Scy work_done = 0; 69838494Sobrien 699310490Scy for (i = last_used_map; i >= 0; --i) { 700310490Scy am_node *mp = exported_ap[i]; 701310490Scy mntfs *mf; 70238494Sobrien 703310490Scy if (!mp) 704310490Scy continue; 70538494Sobrien 706174294Sobrien /* 707310490Scy * Wait for children to be removed first 708174294Sobrien */ 709310490Scy if (mp->am_child) 710310490Scy continue; 71138494Sobrien 712310490Scy mf = mp->am_al->al_mnt; 713310490Scy if (mf->mf_flags & MFF_UNMOUNTING) { 714310490Scy /* 715310490Scy * If this node is being unmounted then just ignore it. However, 716310490Scy * this could prevent amd from finishing if the unmount gets blocked 717310490Scy * since the am_node will never be free'd. am_unmounted needs 718310490Scy * telling about this possibility. - XXX 719310490Scy */ 720310490Scy continue; 721310490Scy } 722174294Sobrien 723310490Scy if (!(mf->mf_fsflags & FS_DIRECTORY)) 72438494Sobrien /* 725310490Scy * When shutting down this had better 726310490Scy * look like a directory, otherwise it 727310490Scy * can't be unmounted! 72838494Sobrien */ 729310490Scy mk_fattr(&mp->am_fattr, NFDIR); 730310490Scy 731310490Scy if ((--immediate_abort < 0 && 732310490Scy !(mp->am_flags & AMF_ROOT) && mp->am_parent) || 733310490Scy (mf->mf_flags & MFF_RESTART)) { 734310490Scy 735310490Scy work_done++; 736310490Scy 737310490Scy /* 738310490Scy * Just throw this node away without bothering to unmount it. If 739310490Scy * the server is not known to be up then don't discard the mounted 740310490Scy * on directory or Amd might hang... 741310490Scy */ 742310490Scy if (mf->mf_server && 743310490Scy (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID) 744310490Scy mf->mf_flags &= ~MFF_MKMNT; 745310490Scy if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) { 746310490Scy plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); 747310490Scy /* 748310490Scy * use unmount_mp, not unmount_node, so that unmounts be 749310490Scy * backgrounded as needed. 750310490Scy */ 751310490Scy unmount_mp((opaque_t) mp); 752310490Scy } else { 753310490Scy am_unmounted(mp); 754310490Scy } 755310490Scy if (!(mf->mf_flags & (MFF_UNMOUNTING|MFF_MOUNTED))) 756310490Scy exported_ap[i] = NULL; 757174294Sobrien } else { 758310490Scy /* 759310490Scy * Any other node gets forcibly timed out. 760310490Scy */ 761310490Scy mp->am_flags &= ~AMF_NOTIMEOUT; 762310490Scy mp->am_al->al_mnt->mf_flags &= ~MFF_RSTKEEP; 763310490Scy mp->am_ttl = 0; 764310490Scy mp->am_timeo = 1; 765310490Scy mp->am_timeo_w = 0; 76638494Sobrien } 76738494Sobrien } 768310490Scy } while (work_done); 76938494Sobrien} 77038494Sobrien 77138494Sobrien 772174294Sobrien/* 773174294Sobrien * Try to mount a file system. Can be called directly or in a sub-process by run_task. 774174294Sobrien * 775174294Sobrien * Warning: this function might be running in a child process context. 776174294Sobrien * Don't expect any changes made here to survive in the parent amd process. 777174294Sobrien */ 778174294Sobrienint 779174294Sobrienmount_node(opaque_t arg) 780174294Sobrien{ 781174294Sobrien am_node *mp = (am_node *) arg; 782310490Scy mntfs *mf = mp->am_al->al_mnt; 783174294Sobrien int error = 0; 784174294Sobrien 785174294Sobrien#ifdef HAVE_FS_AUTOFS 786174294Sobrien if (mp->am_flags & AMF_AUTOFS) 787174294Sobrien error = autofs_mount_fs(mp, mf); 788174294Sobrien else 789174294Sobrien#endif /* HAVE_FS_AUTOFS */ 790174294Sobrien if (!(mf->mf_flags & MFF_MOUNTED)) 791174294Sobrien error = mf->mf_ops->mount_fs(mp, mf); 792174294Sobrien 793174294Sobrien if (error > 0) 794174294Sobrien dlog("mount_node: call to mf_ops->mount_fs(%s) failed: %s", 795174294Sobrien mp->am_path, strerror(error)); 796174294Sobrien return error; 797174294Sobrien} 798174294Sobrien 799174294Sobrien 80038494Sobrienstatic int 801174294Sobrienunmount_node(opaque_t arg) 80238494Sobrien{ 803174294Sobrien am_node *mp = (am_node *) arg; 804310490Scy mntfs *mf = mp->am_al->al_mnt; 805174294Sobrien int error = 0; 80638494Sobrien 807174294Sobrien if (mf->mf_flags & MFF_ERROR) { 80838494Sobrien /* 80938494Sobrien * Just unlink 81038494Sobrien */ 811174294Sobrien dlog("No-op unmount of error node %s", mf->mf_info); 81238494Sobrien } else { 813174294Sobrien dlog("Unmounting <%s> <%s> (%s) flags %x", 814174294Sobrien mp->am_path, mf->mf_mount, mf->mf_info, mf->mf_flags); 815174294Sobrien#ifdef HAVE_FS_AUTOFS 816174294Sobrien if (mp->am_flags & AMF_AUTOFS) 817174294Sobrien error = autofs_umount_fs(mp, mf); 818174294Sobrien else 819174294Sobrien#endif /* HAVE_FS_AUTOFS */ 820174294Sobrien if (mf->mf_refc == 1) 821174294Sobrien error = mf->mf_ops->umount_fs(mp, mf); 82238494Sobrien } 82338494Sobrien 824174294Sobrien /* do this again, it might have changed */ 825310490Scy mf = mp->am_al->al_mnt; 82638494Sobrien if (error) { 82738494Sobrien errno = error; /* XXX */ 82838494Sobrien dlog("%s: unmount: %m", mf->mf_mount); 82938494Sobrien } 83038494Sobrien 83138494Sobrien return error; 83238494Sobrien} 83338494Sobrien 83438494Sobrien 83538494Sobrienstatic void 836174294Sobrienfree_map_if_success(int rc, int term, opaque_t arg) 83738494Sobrien{ 838174294Sobrien am_node *mp = (am_node *) arg; 839310490Scy mntfs *mf = mp->am_al->al_mnt; 840174294Sobrien wchan_t wchan = get_mntfs_wchan(mf); 84138494Sobrien 84238494Sobrien /* 84338494Sobrien * Not unmounting any more 84438494Sobrien */ 84538494Sobrien mf->mf_flags &= ~MFF_UNMOUNTING; 84638494Sobrien 84738494Sobrien /* 84842629Sobrien * If a timeout was deferred because the underlying filesystem 84938494Sobrien * was busy then arrange for a timeout as soon as possible. 85038494Sobrien */ 85138494Sobrien if (mf->mf_flags & MFF_WANTTIMO) { 85238494Sobrien mf->mf_flags &= ~MFF_WANTTIMO; 85338494Sobrien reschedule_timeout_mp(); 85438494Sobrien } 85538494Sobrien if (term) { 856310490Scy notify_child(mp, AMQ_UMNT_SIGNAL, 0, term); 85738494Sobrien plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term); 85838494Sobrien#if defined(DEBUG) && defined(SIGTRAP) 85938494Sobrien /* 86038494Sobrien * dbx likes to put a trap on exit(). 86138494Sobrien * Pretend it succeeded for now... 86238494Sobrien */ 86338494Sobrien if (term == SIGTRAP) { 86438494Sobrien am_unmounted(mp); 86538494Sobrien } 86638494Sobrien#endif /* DEBUG */ 867174294Sobrien#ifdef HAVE_FS_AUTOFS 868174294Sobrien if (mp->am_flags & AMF_AUTOFS) 869174294Sobrien autofs_umount_failed(mp); 870174294Sobrien#endif /* HAVE_FS_AUTOFS */ 87138494Sobrien amd_stats.d_uerr++; 87238494Sobrien } else if (rc) { 873310490Scy notify_child(mp, AMQ_UMNT_FAILED, rc, 0); 874174294Sobrien if (mf->mf_ops == &amfs_program_ops || rc == EBUSY) 87538494Sobrien plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount); 876174294Sobrien else 877174294Sobrien plog(XLOG_ERROR, "%s: unmount: %s", mp->am_path, strerror(rc)); 878174294Sobrien#ifdef HAVE_FS_AUTOFS 879310490Scy if (rc != ENOENT) { 880310490Scy if (mf->mf_flags & MFF_IS_AUTOFS) 881310490Scy autofs_get_mp(mp); 882310490Scy if (mp->am_flags & AMF_AUTOFS) 883310490Scy autofs_umount_failed(mp); 884310490Scy } 885174294Sobrien#endif /* HAVE_FS_AUTOFS */ 88638494Sobrien amd_stats.d_uerr++; 88738494Sobrien } else { 888310490Scy /* 889310490Scy * am_unmounted() will call notify_child() appropriately. 890310490Scy */ 89138494Sobrien am_unmounted(mp); 89238494Sobrien } 89338494Sobrien 89438494Sobrien /* 895119679Smbr * Wakeup anything waiting for this unmount 89638494Sobrien */ 897174294Sobrien wakeup(wchan); 89838494Sobrien} 89938494Sobrien 90038494Sobrien 901174294Sobrienint 90238494Sobrienunmount_mp(am_node *mp) 90338494Sobrien{ 90438494Sobrien int was_backgrounded = 0; 905310490Scy mntfs *mf = mp->am_al->al_mnt; 90638494Sobrien 907174294Sobrien#ifdef notdef 908174294Sobrien plog(XLOG_INFO, "\"%s\" on %s timed out (flags 0x%x)", 909310490Scy mp->am_path, mf->mf_mount, (int) mf->mf_flags); 910174294Sobrien#endif /* notdef */ 911174294Sobrien 91282794Sobrien#ifndef MNT2_NFS_OPT_SYMTTL 91382794Sobrien /* 91482794Sobrien * This code is needed to defeat Solaris 2.4's (and newer) symlink 91582794Sobrien * values cache. It forces the last-modified time of the symlink to be 91682794Sobrien * current. It is not needed if the O/S has an nfs flag to turn off the 91782794Sobrien * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez. 918119679Smbr * 919119679Smbr * Additionally, Linux currently ignores the nt_useconds field, 920174294Sobrien * so we must update the nt_seconds field every time if clocktime(NULL) 921174294Sobrien * didn't return a new number of seconds. 92282794Sobrien */ 923174294Sobrien if (mp->am_parent) { 924174294Sobrien time_t last = mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds; 925174294Sobrien clocktime(&mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime); 92682794Sobrien /* defensive programming... can't we assert the above condition? */ 927174294Sobrien if (last == (time_t) mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds) 928174294Sobrien mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds++; 929174294Sobrien } 93082794Sobrien#endif /* not MNT2_NFS_OPT_SYMTTL */ 93182794Sobrien 932174294Sobrien if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) { 933174294Sobrien /* 934174294Sobrien * Don't try to unmount from a server that is known to be down 935174294Sobrien */ 936174294Sobrien if (!(mf->mf_flags & MFF_LOGDOWN)) { 937174294Sobrien /* Only log this once, otherwise gets a bit boring */ 938174294Sobrien plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path); 939174294Sobrien mf->mf_flags |= MFF_LOGDOWN; 940174294Sobrien } 941310490Scy notify_child(mp, AMQ_UMNT_SERVER, 0, 0); 942174294Sobrien return 0; 943174294Sobrien } 94438494Sobrien 945310490Scy dlog("\"%s\" on %s timed out", mp->am_path, mf->mf_mount); 946174294Sobrien mf->mf_flags |= MFF_UNMOUNTING; 947174294Sobrien 948174294Sobrien#ifdef HAVE_FS_AUTOFS 949174294Sobrien if (mf->mf_flags & MFF_IS_AUTOFS) 950174294Sobrien autofs_release_mp(mp); 951174294Sobrien#endif /* HAVE_FS_AUTOFS */ 952174294Sobrien 953174294Sobrien if ((mf->mf_fsflags & FS_UBACKGROUND) && 954310490Scy (mf->mf_flags & MFF_MOUNTED) && 955310490Scy !(mf->mf_flags & MFF_ON_AUTOFS)) { 956174294Sobrien dlog("Trying unmount in background"); 957174294Sobrien run_task(unmount_node, (opaque_t) mp, 958174294Sobrien free_map_if_success, (opaque_t) mp); 959174294Sobrien was_backgrounded = 1; 96038494Sobrien } else { 96138494Sobrien dlog("Trying unmount in foreground"); 962174294Sobrien free_map_if_success(unmount_node((opaque_t) mp), 0, (opaque_t) mp); 96338494Sobrien dlog("unmount attempt done"); 96438494Sobrien } 96538494Sobrien 96638494Sobrien return was_backgrounded; 96738494Sobrien} 96838494Sobrien 96938494Sobrien 97038494Sobrienvoid 971174294Sobrientimeout_mp(opaque_t v) /* argument not used?! */ 97238494Sobrien{ 97338494Sobrien int i; 97438494Sobrien time_t t = NEVER; 975174294Sobrien time_t now = clocktime(NULL); 976174294Sobrien int backoff = NumChildren / 4; 97738494Sobrien 97838494Sobrien dlog("Timing out automount points..."); 97938494Sobrien 98038494Sobrien for (i = last_used_map; i >= 0; --i) { 98138494Sobrien am_node *mp = exported_ap[i]; 98238494Sobrien mntfs *mf; 98338494Sobrien 98438494Sobrien /* 985174294Sobrien * Just continue if nothing mounted 98638494Sobrien */ 987174294Sobrien if (!mp) 98838494Sobrien continue; 98938494Sobrien 99038494Sobrien /* 99138494Sobrien * Pick up mounted filesystem 99238494Sobrien */ 993310490Scy mf = mp->am_al->al_mnt; 99438494Sobrien if (!mf) 99538494Sobrien continue; 99638494Sobrien 997174294Sobrien#ifdef HAVE_FS_AUTOFS 998174294Sobrien if (mf->mf_flags & MFF_IS_AUTOFS && mp->am_autofs_ttl != NEVER) { 999174294Sobrien if (now >= mp->am_autofs_ttl) 1000174294Sobrien autofs_timeout_mp(mp); 1001174294Sobrien t = smallest_t(t, mp->am_autofs_ttl); 1002174294Sobrien } 1003174294Sobrien#endif /* HAVE_FS_AUTOFS */ 1004174294Sobrien 1005174294Sobrien if (mp->am_flags & AMF_NOTIMEOUT) 1006174294Sobrien continue; 1007174294Sobrien 100838494Sobrien /* 100938494Sobrien * Don't delete last reference to a restarted filesystem. 101038494Sobrien */ 101138494Sobrien if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1) 101238494Sobrien continue; 101338494Sobrien 101438494Sobrien /* 101538494Sobrien * If there is action on this filesystem then ignore it 101638494Sobrien */ 101738494Sobrien if (!(mf->mf_flags & IGNORE_FLAGS)) { 101838494Sobrien int expired = 0; 101938494Sobrien mf->mf_flags &= ~MFF_WANTTIMO; 102038494Sobrien if (now >= mp->am_ttl) { 102138494Sobrien if (!backoff) { 102238494Sobrien expired = 1; 102338494Sobrien 102438494Sobrien /* 102538494Sobrien * Move the ttl forward to avoid thrashing effects 102638494Sobrien * on the next call to timeout! 102738494Sobrien */ 102838494Sobrien /* sun's -tw option */ 102938494Sobrien if (mp->am_timeo_w < 4 * gopt.am_timeo_w) 103038494Sobrien mp->am_timeo_w += gopt.am_timeo_w; 103138494Sobrien mp->am_ttl = now + mp->am_timeo_w; 103238494Sobrien 103338494Sobrien } else { 103438494Sobrien /* 103538494Sobrien * Just backoff this unmount for 103638494Sobrien * a couple of seconds to avoid 103738494Sobrien * many multiple unmounts being 103838494Sobrien * started in parallel. 103938494Sobrien */ 104038494Sobrien mp->am_ttl = now + backoff + 1; 104138494Sobrien } 104238494Sobrien } 104338494Sobrien 104438494Sobrien /* 104538494Sobrien * If the next ttl is smallest, use that 104638494Sobrien */ 104738494Sobrien t = smallest_t(t, mp->am_ttl); 104838494Sobrien 104938494Sobrien if (!mp->am_child && mf->mf_error >= 0 && expired) { 105038494Sobrien /* 105138494Sobrien * If the unmount was backgrounded then 105238494Sobrien * bump the backoff counter. 105338494Sobrien */ 105438494Sobrien if (unmount_mp(mp)) { 105538494Sobrien backoff = 2; 105638494Sobrien } 105738494Sobrien } 105838494Sobrien } else if (mf->mf_flags & MFF_UNMOUNTING) { 105938494Sobrien mf->mf_flags |= MFF_WANTTIMO; 106038494Sobrien } 106138494Sobrien } 106238494Sobrien 106338494Sobrien if (t == NEVER) { 106438494Sobrien dlog("No further timeouts"); 106538494Sobrien t = now + ONE_HOUR; 106638494Sobrien } 106738494Sobrien 106838494Sobrien /* 106938494Sobrien * Sanity check to avoid runaways. 107038494Sobrien * Absolutely should never get this but 107138494Sobrien * if you do without this trap amd will thrash. 107238494Sobrien */ 107338494Sobrien if (t <= now) { 107438494Sobrien t = now + 6; /* XXX */ 107538494Sobrien plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!"); 107638494Sobrien } 107738494Sobrien 107838494Sobrien /* 107938494Sobrien * XXX - when shutting down, make things happen faster 108038494Sobrien */ 108138494Sobrien if ((int) amd_state >= (int) Finishing) 108238494Sobrien t = now + 1; 108351292Sobrien dlog("Next mount timeout in %lds", (long) (t - now)); 108438494Sobrien 1085310490Scy timeout_mp_id = timeout(t - now, timeout_mp, NULL); 108638494Sobrien} 108738494Sobrien 108838494Sobrien 108938494Sobrien/* 109038494Sobrien * Cause timeout_mp to be called soonest 109138494Sobrien */ 109238494Sobrienvoid 109338494Sobrienreschedule_timeout_mp(void) 109438494Sobrien{ 109538494Sobrien if (timeout_mp_id) 109638494Sobrien untimeout(timeout_mp_id); 1097310490Scy timeout_mp_id = timeout(0, timeout_mp, NULL); 109838494Sobrien} 1099