2 * Copyright (c) 1997-2006 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * File: am-utils/amd/map.c
46 #endif /* HAVE_CONFIG_H */
50 #define smallest_t(t1, t2) (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
51 #define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
52 #define new_gen() (am_gen++)
57 * Generation numbers are allocated to every node created
58 * by amd. When a filehandle is computed and sent to the
59 * kernel, the generation number makes sure that it is safe
60 * to reallocate a node slot even when the kernel has a cached
61 * reference to its old incarnation.
62 * No garbage collection is done, since it is assumed that
63 * there is no way that 2^32 generation numbers could ever
64 * be allocated by a single run of amd - there is simply
65 * not enough cpu time available.
66 * Famous last words... -Ion
68 static u_int am_gen = 2; /* Initial generation number */
69 static int timeout_mp_id; /* Id from last call to timeout */
71 static am_node *root_node; /* The root of the mount tree */
72 static am_node **exported_ap = (am_node **) 0;
73 static int exported_ap_size = 0;
74 static int first_free_map = 0; /* First available free slot */
75 static int last_used_map = -1; /* Last unavailable used slot */
79 * This is the default attributes field which
80 * is copied into every new node to be created.
81 * The individual filesystem fs_init() routines
82 * patch the copy to represent the particular
83 * details for the relevant filesystem type
85 static nfsfattr gen_fattr =
88 NFSMODE_LNK | 0777, /* mode */
103 /* forward declarations */
104 static int unmount_node(opaque_t arg);
105 static void exported_ap_free(am_node *mp);
106 static void remove_am(am_node *mp);
107 static am_node *get_root_ap(char *dir);
111 * Iterator functions for exported_ap[]
114 get_first_exported_ap(int *index)
117 return get_next_exported_ap(index);
122 get_next_exported_ap(int *index)
125 while (*index < exported_ap_size) {
126 if (exported_ap[*index] != NULL)
127 return exported_ap[*index];
135 * Get exported_ap by index
138 get_exported_ap(int index)
140 if (index < 0 || index >= exported_ap_size)
142 return exported_ap[index];
147 * Get exported_ap by path
150 path_to_exported_ap(char *path)
155 mp = get_first_exported_ap(&index);
157 if (STREQ(mp->am_path, path))
159 mp = get_next_exported_ap(&index);
166 * Resize exported_ap map
169 exported_ap_realloc_map(int nsize)
172 * this shouldn't happen, but...
174 if (nsize < 0 || nsize == exported_ap_size)
177 exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node *));
179 if (nsize > exported_ap_size)
180 memset((char *) (exported_ap + exported_ap_size), 0,
181 (nsize - exported_ap_size) * sizeof(am_node *));
182 exported_ap_size = nsize;
190 get_ap_child(am_node *mp, char *fname)
193 mntfs *mf = mp->am_mnt;
198 new_mp = exported_ap_alloc();
203 init_map(new_mp, fname);
206 * Put it in the table
208 insert_am(new_mp, mp);
211 * Fill in some other fields,
212 * path and mount point.
214 * bugfix: do not prepend old am_path if direct map
215 * <wls@astro.umd.edu> William Sebok
217 new_mp->am_path = str3cat(new_mp->am_path,
218 (mf->mf_fsflags & FS_DIRECT)
221 *fname == '/' ? "" : "/", fname);
222 dlog("setting path to %s", new_mp->am_path);
229 * Allocate a new mount slot and create
231 * Fills in the map number of the node,
232 * but leaves everything else uninitialized.
235 exported_ap_alloc(void)
240 * First check if there are any slots left, realloc if needed
242 if (first_free_map >= exported_ap_size)
243 if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP))
247 * Grab the next free slot
249 mpp = exported_ap + first_free_map;
250 mp = *mpp = ALLOC(struct am_node);
251 memset((char *) mp, 0, sizeof(struct am_node));
253 mp->am_mapno = first_free_map++;
256 * Update free pointer
258 while (first_free_map < exported_ap_size && exported_ap[first_free_map])
261 if (first_free_map > last_used_map)
262 last_used_map = first_free_map - 1;
272 exported_ap_free(am_node *mp)
281 * Zero the slot pointer to avoid double free's
283 exported_ap[mp->am_mapno] = 0;
286 * Update the free and last_used indices
288 if (mp->am_mapno == last_used_map)
289 while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
292 if (first_free_map > mp->am_mapno)
293 first_free_map = mp->am_mapno;
296 * Free the mount node, and zero out it's internal struct data.
298 memset((char *) mp, 0, sizeof(am_node));
304 * Insert mp into the correct place,
305 * where p_mp is its parent node.
306 * A new node gets placed as the youngest sibling
307 * of any other children, and the parent's child
308 * pointer is adjusted to point to the new child node.
311 insert_am(am_node *mp, am_node *p_mp)
314 * If this is going in at the root then flag it
315 * so that it cannot be unmounted by amq.
317 if (p_mp == root_node)
318 mp->am_flags |= AMF_ROOT;
320 * Fill in n-way links
322 mp->am_parent = p_mp;
323 mp->am_osib = p_mp->am_child;
325 mp->am_osib->am_ysib = mp;
327 #ifdef HAVE_FS_AUTOFS
328 if (p_mp->am_mnt->mf_flags & MFF_IS_AUTOFS)
329 mp->am_flags |= AMF_AUTOFS;
330 #endif /* HAVE_FS_AUTOFS */
335 * Remove am from its place in the mount tree
338 remove_am(am_node *mp)
341 * 1. Consistency check
343 if (mp->am_child && mp->am_parent) {
344 plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
348 * 2. Update parent's child pointer
350 if (mp->am_parent && mp->am_parent->am_child == mp)
351 mp->am_parent->am_child = mp->am_osib;
354 * 3. Unlink from sibling chain
357 mp->am_ysib->am_osib = mp->am_osib;
359 mp->am_osib->am_ysib = mp->am_ysib;
364 * Compute a new time to live value for a node.
370 mp->am_ttl = clocktime(&mp->am_fattr.na_atime);
371 mp->am_ttl += mp->am_timeo; /* sun's -tl option */
376 mk_fattr(nfsfattr *fattr, nfsftype vntype)
380 fattr->na_type = NFDIR;
381 fattr->na_mode = NFSMODE_DIR | 0555;
383 fattr->na_size = 512;
386 fattr->na_type = NFLNK;
387 fattr->na_mode = NFSMODE_LNK | 0777;
392 plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype);
399 * Initialize an allocated mount node.
400 * It is assumed that the mount node was b-zero'd
401 * before getting here so anything that would
402 * be set to zero isn't done here.
405 init_map(am_node *mp, char *dir)
408 * mp->am_mapno is initialized by exported_ap_alloc
409 * other fields don't need to be set to zero.
411 mp->am_mnt = new_mntfs();
413 mp->am_name = strdup(dir);
414 mp->am_path = strdup(dir);
415 mp->am_gen = new_gen();
416 #ifdef HAVE_FS_AUTOFS
417 mp->am_autofs_fh = 0;
418 #endif /* HAVE_FS_AUTOFS */
420 mp->am_timeo = gopt.am_timeo;
421 mp->am_attr.ns_status = NFS_OK;
422 mp->am_fattr = gen_fattr;
423 mp->am_fattr.na_fsid = 42;
424 mp->am_fattr.na_fileid = mp->am_gen;
425 clocktime(&mp->am_fattr.na_atime);
426 /* next line copies a "struct nfstime" among several fields */
427 mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime;
430 mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds;
438 * The node must be already unmounted.
441 free_map(am_node *mp)
454 XFREE(mp->am_transp);
457 free_mntfs(mp->am_mnt);
459 if (mp->am_mfarray) {
461 for (temp_mf = mp->am_mfarray; *temp_mf; temp_mf++)
462 free_mntfs(*temp_mf);
463 XFREE(mp->am_mfarray);
466 #ifdef HAVE_FS_AUTOFS
467 if (mp->am_autofs_fh)
468 autofs_release_fh(mp);
469 #endif /* HAVE_FS_AUTOFS */
471 exported_ap_free(mp);
476 find_ap_recursive(char *dir, am_node *mp)
480 if (STREQ(mp->am_path, dir))
483 if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
484 STREQ(mp->am_mnt->mf_mount, dir))
487 mp2 = find_ap_recursive(dir, mp->am_osib);
490 return find_ap_recursive(dir, mp->am_child);
498 * Find the mount node corresponding to dir. dir can match either the
499 * automount path or, if the node is mounted, the mount location.
506 for (i = last_used_map; i >= 0; --i) {
507 am_node *mp = exported_ap[i];
508 if (mp && (mp->am_flags & AMF_ROOT)) {
509 mp = find_ap_recursive(dir, exported_ap[i]);
521 * Find the mount node corresponding
522 * to the mntfs structure.
529 for (i = last_used_map; i >= 0; --i) {
530 am_node *mp = exported_ap[i];
531 if (mp && mp->am_mnt == mf)
540 * Get the filehandle for a particular named directory.
541 * This is used during the bootstrap to tell the kernel
542 * the filehandles of the initial automount points.
545 get_root_nfs_fh(char *dir)
547 static am_nfs_fh nfh;
548 am_node *mp = get_root_ap(dir);
555 * Should never get here...
557 plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
564 get_root_ap(char *dir)
566 am_node *mp = find_ap(dir);
568 if (mp && mp->am_parent == root_node)
576 * Timeout all nodes waiting on
580 map_flush_srvr(fserver *fs)
585 for (i = last_used_map; i >= 0; --i) {
586 am_node *mp = exported_ap[i];
587 if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) {
588 plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host);
589 mp->am_ttl = clocktime(NULL);
594 reschedule_timeout_mp();
599 * Mount a top level automount node
600 * by calling lookup in the parent
601 * (root) node which will cause the
602 * automount node to be automounted.
605 mount_auto_node(char *dir, opaque_t arg)
608 am_node *mp = (am_node *) arg;
611 new_mp = mp->am_mnt->mf_ops->lookup_child(mp, dir, &error, VLOOK_CREATE);
612 if (new_mp && error < 0) {
614 * We can't allow the fileid of the root node to change.
615 * Should be ok to force it to 1, always.
617 new_mp->am_gen = new_mp->am_fattr.na_fileid = 1;
619 new_mp = mp->am_mnt->mf_ops->mount_child(new_mp, &error);
623 errno = error; /* XXX */
624 plog(XLOG_ERROR, "Could not mount %s: %m", dir);
631 * Cause all the top-level mount nodes
638 * Iterate over all the nodes to be started
640 return root_keyiter(mount_auto_node, root_node);
645 * Construct top-level node
651 char *rootmap = ROOT_MAP;
652 root_node = exported_ap_alloc();
657 init_map(root_node, "");
660 * Allocate a new mounted filesystem
662 root_mnt = find_mntfs(&amfs_root_ops, (am_opts *) 0, "", rootmap, "", "", "");
665 * Replace the initial null reference
667 free_mntfs(root_node->am_mnt);
668 root_node->am_mnt = root_mnt;
671 * Initialize the root
673 if (root_mnt->mf_ops->fs_init)
674 (*root_mnt->mf_ops->fs_init) (root_mnt);
679 root_mnt->mf_error = root_mnt->mf_ops->mount_fs(root_node, root_mnt);
684 * Cause all the nodes to be unmounted by timing
688 umount_exported(void)
692 for (i = last_used_map; i >= 0; --i) {
693 am_node *mp = exported_ap[i];
700 if (mf->mf_flags & MFF_UNMOUNTING) {
702 * If this node is being unmounted then just ignore it. However,
703 * this could prevent amd from finishing if the unmount gets blocked
704 * since the am_node will never be free'd. am_unmounted needs
705 * telling about this possibility. - XXX
710 if (!(mf->mf_fsflags & FS_DIRECTORY))
712 * When shutting down this had better
713 * look like a directory, otherwise it
714 * can't be unmounted!
716 mk_fattr(&mp->am_fattr, NFDIR);
718 if ((--immediate_abort < 0 &&
719 !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
720 (mf->mf_flags & MFF_RESTART)) {
723 * Just throw this node away without bothering to unmount it. If
724 * the server is not known to be up then don't discard the mounted
725 * on directory or Amd might hang...
728 (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID)
729 mf->mf_flags &= ~MFF_MKMNT;
730 if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) {
731 plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount);
733 * use unmount_mp, not unmount_node, so that unmounts be
734 * backgrounded as needed.
736 unmount_mp((opaque_t) mp);
743 * Any other node gets forcibly timed out.
745 mp->am_flags &= ~AMF_NOTIMEOUT;
746 mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
756 * Try to mount a file system. Can be called directly or in a sub-process by run_task.
758 * Warning: this function might be running in a child process context.
759 * Don't expect any changes made here to survive in the parent amd process.
762 mount_node(opaque_t arg)
764 am_node *mp = (am_node *) arg;
765 mntfs *mf = mp->am_mnt;
768 #ifdef HAVE_FS_AUTOFS
769 if (mp->am_flags & AMF_AUTOFS)
770 error = autofs_mount_fs(mp, mf);
772 #endif /* HAVE_FS_AUTOFS */
773 if (!(mf->mf_flags & MFF_MOUNTED))
774 error = mf->mf_ops->mount_fs(mp, mf);
777 dlog("mount_node: call to mf_ops->mount_fs(%s) failed: %s",
778 mp->am_path, strerror(error));
784 unmount_node(opaque_t arg)
786 am_node *mp = (am_node *) arg;
787 mntfs *mf = mp->am_mnt;
790 if (mf->mf_flags & MFF_ERROR) {
794 dlog("No-op unmount of error node %s", mf->mf_info);
796 dlog("Unmounting <%s> <%s> (%s) flags %x",
797 mp->am_path, mf->mf_mount, mf->mf_info, mf->mf_flags);
798 #ifdef HAVE_FS_AUTOFS
799 if (mp->am_flags & AMF_AUTOFS)
800 error = autofs_umount_fs(mp, mf);
802 #endif /* HAVE_FS_AUTOFS */
803 if (mf->mf_refc == 1)
804 error = mf->mf_ops->umount_fs(mp, mf);
807 /* do this again, it might have changed */
810 errno = error; /* XXX */
811 dlog("%s: unmount: %m", mf->mf_mount);
819 free_map_if_success(int rc, int term, opaque_t arg)
821 am_node *mp = (am_node *) arg;
822 mntfs *mf = mp->am_mnt;
823 wchan_t wchan = get_mntfs_wchan(mf);
826 * Not unmounting any more
828 mf->mf_flags &= ~MFF_UNMOUNTING;
831 * If a timeout was deferred because the underlying filesystem
832 * was busy then arrange for a timeout as soon as possible.
834 if (mf->mf_flags & MFF_WANTTIMO) {
835 mf->mf_flags &= ~MFF_WANTTIMO;
836 reschedule_timeout_mp();
839 plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
840 #if defined(DEBUG) && defined(SIGTRAP)
842 * dbx likes to put a trap on exit().
843 * Pretend it succeeded for now...
845 if (term == SIGTRAP) {
849 #ifdef HAVE_FS_AUTOFS
850 if (mp->am_flags & AMF_AUTOFS)
851 autofs_umount_failed(mp);
852 #endif /* HAVE_FS_AUTOFS */
855 if (mf->mf_ops == &amfs_program_ops || rc == EBUSY)
856 plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
858 plog(XLOG_ERROR, "%s: unmount: %s", mp->am_path, strerror(rc));
859 #ifdef HAVE_FS_AUTOFS
860 if (mf->mf_flags & MFF_IS_AUTOFS)
862 if (mp->am_flags & AMF_AUTOFS)
863 autofs_umount_failed(mp);
864 #endif /* HAVE_FS_AUTOFS */
871 * Wakeup anything waiting for this unmount
878 unmount_mp(am_node *mp)
880 int was_backgrounded = 0;
881 mntfs *mf = mp->am_mnt;
884 plog(XLOG_INFO, "\"%s\" on %s timed out (flags 0x%x)",
885 mp->am_path, mp->am_mnt->mf_mount, (int) mf->mf_flags);
888 #ifndef MNT2_NFS_OPT_SYMTTL
890 * This code is needed to defeat Solaris 2.4's (and newer) symlink
891 * values cache. It forces the last-modified time of the symlink to be
892 * current. It is not needed if the O/S has an nfs flag to turn off the
893 * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
895 * Additionally, Linux currently ignores the nt_useconds field,
896 * so we must update the nt_seconds field every time if clocktime(NULL)
897 * didn't return a new number of seconds.
900 time_t last = mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds;
901 clocktime(&mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime);
902 /* defensive programming... can't we assert the above condition? */
903 if (last == (time_t) mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds)
904 mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds++;
906 #endif /* not MNT2_NFS_OPT_SYMTTL */
908 if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
910 * Don't try to unmount from a server that is known to be down
912 if (!(mf->mf_flags & MFF_LOGDOWN)) {
913 /* Only log this once, otherwise gets a bit boring */
914 plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
915 mf->mf_flags |= MFF_LOGDOWN;
920 dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
921 mf->mf_flags |= MFF_UNMOUNTING;
923 #ifdef HAVE_FS_AUTOFS
924 if (mf->mf_flags & MFF_IS_AUTOFS)
925 autofs_release_mp(mp);
926 #endif /* HAVE_FS_AUTOFS */
928 if ((mf->mf_fsflags & FS_UBACKGROUND) &&
929 (mf->mf_flags & MFF_MOUNTED)) {
930 dlog("Trying unmount in background");
931 run_task(unmount_node, (opaque_t) mp,
932 free_map_if_success, (opaque_t) mp);
933 was_backgrounded = 1;
935 dlog("Trying unmount in foreground");
936 free_map_if_success(unmount_node((opaque_t) mp), 0, (opaque_t) mp);
937 dlog("unmount attempt done");
940 return was_backgrounded;
945 timeout_mp(opaque_t v) /* argument not used?! */
949 time_t now = clocktime(NULL);
950 int backoff = NumChildren / 4;
952 dlog("Timing out automount points...");
954 for (i = last_used_map; i >= 0; --i) {
955 am_node *mp = exported_ap[i];
959 * Just continue if nothing mounted
965 * Pick up mounted filesystem
971 #ifdef HAVE_FS_AUTOFS
972 if (mf->mf_flags & MFF_IS_AUTOFS && mp->am_autofs_ttl != NEVER) {
973 if (now >= mp->am_autofs_ttl)
974 autofs_timeout_mp(mp);
975 t = smallest_t(t, mp->am_autofs_ttl);
977 #endif /* HAVE_FS_AUTOFS */
979 if (mp->am_flags & AMF_NOTIMEOUT)
983 * Don't delete last reference to a restarted filesystem.
985 if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
989 * If there is action on this filesystem then ignore it
991 if (!(mf->mf_flags & IGNORE_FLAGS)) {
993 mf->mf_flags &= ~MFF_WANTTIMO;
994 if (now >= mp->am_ttl) {
999 * Move the ttl forward to avoid thrashing effects
1000 * on the next call to timeout!
1002 /* sun's -tw option */
1003 if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
1004 mp->am_timeo_w += gopt.am_timeo_w;
1005 mp->am_ttl = now + mp->am_timeo_w;
1009 * Just backoff this unmount for
1010 * a couple of seconds to avoid
1011 * many multiple unmounts being
1012 * started in parallel.
1014 mp->am_ttl = now + backoff + 1;
1019 * If the next ttl is smallest, use that
1021 t = smallest_t(t, mp->am_ttl);
1023 if (!mp->am_child && mf->mf_error >= 0 && expired) {
1025 * If the unmount was backgrounded then
1026 * bump the backoff counter.
1028 if (unmount_mp(mp)) {
1032 } else if (mf->mf_flags & MFF_UNMOUNTING) {
1033 mf->mf_flags |= MFF_WANTTIMO;
1038 dlog("No further timeouts");
1043 * Sanity check to avoid runaways.
1044 * Absolutely should never get this but
1045 * if you do without this trap amd will thrash.
1048 t = now + 6; /* XXX */
1049 plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
1053 * XXX - when shutting down, make things happen faster
1055 if ((int) amd_state >= (int) Finishing)
1057 dlog("Next mount timeout in %lds", (long) (t - now));
1059 timeout_mp_id = timeout(t - now, timeout_mp, 0);
1064 * Cause timeout_mp to be called soonest
1067 reschedule_timeout_mp(void)
1070 untimeout(timeout_mp_id);
1071 timeout_mp_id = timeout(0, timeout_mp, 0);