4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/amd/map.c
48 #endif /* HAVE_CONFIG_H */
52 #define smallest_t(t1, t2) (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
53 #define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
54 #define new_gen() (am_gen++)
59 * Generation numbers are allocated to every node created
60 * by amd. When a filehandle is computed and sent to the
61 * kernel, the generation number makes sure that it is safe
62 * to reallocate a node slot even when the kernel has a cached
63 * reference to its old incarnation.
64 * No garbage collection is done, since it is assumed that
65 * there is no way that 2^32 generation numbers could ever
66 * be allocated by a single run of amd - there is simply
67 * not enough cpu time available.
68 * Famous last words... -Ion
70 static u_int am_gen
= 2; /* Initial generation number */
71 static int timeout_mp_id
; /* Id from last call to timeout */
73 static am_node
*root_node
; /* The root of the mount tree */
74 static am_node
**exported_ap
= (am_node
**) NULL
;
75 static int exported_ap_size
= 0;
76 static int first_free_map
= 0; /* First available free slot */
77 static int last_used_map
= -1; /* Last unavailable used slot */
81 * This is the default attributes field which
82 * is copied into every new node to be created.
83 * The individual filesystem fs_init() routines
84 * patch the copy to represent the particular
85 * details for the relevant filesystem type
87 static nfsfattr gen_fattr
=
90 NFSMODE_LNK
| 0777, /* mode */
105 /* forward declarations */
106 static int unmount_node(opaque_t arg
);
107 static void exported_ap_free(am_node
*mp
);
108 static void remove_am(am_node
*mp
);
109 static am_node
*get_root_ap(char *dir
);
113 * Iterator functions for exported_ap[]
116 get_first_exported_ap(int *index
)
119 return get_next_exported_ap(index
);
124 get_next_exported_ap(int *index
)
127 while (*index
< exported_ap_size
) {
128 if (exported_ap
[*index
] != NULL
)
129 return exported_ap
[*index
];
137 * Get exported_ap by index
140 get_exported_ap(int index
)
142 if (index
< 0 || index
>= exported_ap_size
)
144 return exported_ap
[index
];
149 * Get exported_ap by path
152 path_to_exported_ap(char *path
)
157 mp
= get_first_exported_ap(&index
);
159 if (STREQ(mp
->am_path
, path
))
161 mp
= get_next_exported_ap(&index
);
168 * Resize exported_ap map
171 exported_ap_realloc_map(int nsize
)
174 * this shouldn't happen, but...
176 if (nsize
< 0 || nsize
== exported_ap_size
)
179 exported_ap
= (am_node
**) xrealloc((voidp
) exported_ap
, nsize
* sizeof(am_node
*));
181 if (nsize
> exported_ap_size
)
182 memset((char *) (exported_ap
+ exported_ap_size
), 0,
183 (nsize
- exported_ap_size
) * sizeof(am_node
*));
184 exported_ap_size
= nsize
;
192 get_ap_child(am_node
*mp
, char *fname
)
195 mntfs
*mf
= mp
->am_mnt
;
200 new_mp
= exported_ap_alloc();
205 init_map(new_mp
, fname
);
208 * Put it in the table
210 insert_am(new_mp
, mp
);
213 * Fill in some other fields,
214 * path and mount point.
216 * bugfix: do not prepend old am_path if direct map
217 * <wls@astro.umd.edu> William Sebok
219 new_mp
->am_path
= str3cat(new_mp
->am_path
,
220 (mf
->mf_fsflags
& FS_DIRECT
)
223 *fname
== '/' ? "" : "/", fname
);
224 dlog("setting path to %s", new_mp
->am_path
);
231 * Allocate a new mount slot and create
233 * Fills in the map number of the node,
234 * but leaves everything else uninitialized.
237 exported_ap_alloc(void)
242 * First check if there are any slots left, realloc if needed
244 if (first_free_map
>= exported_ap_size
)
245 if (!exported_ap_realloc_map(exported_ap_size
+ NEXP_AP
))
249 * Grab the next free slot
251 mpp
= exported_ap
+ first_free_map
;
252 mp
= *mpp
= ALLOC(struct am_node
);
253 memset((char *) mp
, 0, sizeof(struct am_node
));
255 mp
->am_mapno
= first_free_map
++;
258 * Update free pointer
260 while (first_free_map
< exported_ap_size
&& exported_ap
[first_free_map
])
263 if (first_free_map
> last_used_map
)
264 last_used_map
= first_free_map
- 1;
274 exported_ap_free(am_node
*mp
)
283 * Zero the slot pointer to avoid double free's
285 exported_ap
[mp
->am_mapno
] = NULL
;
288 * Update the free and last_used indices
290 if (mp
->am_mapno
== last_used_map
)
291 while (last_used_map
>= 0 && exported_ap
[last_used_map
] == 0)
294 if (first_free_map
> mp
->am_mapno
)
295 first_free_map
= mp
->am_mapno
;
298 * Free the mount node, and zero out it's internal struct data.
300 memset((char *) mp
, 0, sizeof(am_node
));
306 * Insert mp into the correct place,
307 * where p_mp is its parent node.
308 * A new node gets placed as the youngest sibling
309 * of any other children, and the parent's child
310 * pointer is adjusted to point to the new child node.
313 insert_am(am_node
*mp
, am_node
*p_mp
)
316 * If this is going in at the root then flag it
317 * so that it cannot be unmounted by amq.
319 if (p_mp
== root_node
)
320 mp
->am_flags
|= AMF_ROOT
;
322 * Fill in n-way links
324 mp
->am_parent
= p_mp
;
325 mp
->am_osib
= p_mp
->am_child
;
327 mp
->am_osib
->am_ysib
= mp
;
329 #ifdef HAVE_FS_AUTOFS
330 if (p_mp
->am_mnt
->mf_flags
& MFF_IS_AUTOFS
)
331 mp
->am_flags
|= AMF_AUTOFS
;
332 #endif /* HAVE_FS_AUTOFS */
337 * Remove am from its place in the mount tree
340 remove_am(am_node
*mp
)
343 * 1. Consistency check
345 if (mp
->am_child
&& mp
->am_parent
) {
346 plog(XLOG_WARNING
, "children of \"%s\" still exist - deleting anyway", mp
->am_path
);
350 * 2. Update parent's child pointer
352 if (mp
->am_parent
&& mp
->am_parent
->am_child
== mp
)
353 mp
->am_parent
->am_child
= mp
->am_osib
;
356 * 3. Unlink from sibling chain
359 mp
->am_ysib
->am_osib
= mp
->am_osib
;
361 mp
->am_osib
->am_ysib
= mp
->am_ysib
;
366 * Compute a new time to live value for a node.
372 mp
->am_ttl
= clocktime(&mp
->am_fattr
.na_atime
);
373 mp
->am_ttl
+= mp
->am_timeo
; /* sun's -tl option */
378 mk_fattr(nfsfattr
*fattr
, nfsftype vntype
)
382 fattr
->na_type
= NFDIR
;
383 fattr
->na_mode
= NFSMODE_DIR
| 0555;
385 fattr
->na_size
= 512;
388 fattr
->na_type
= NFLNK
;
389 fattr
->na_mode
= NFSMODE_LNK
| 0777;
394 plog(XLOG_FATAL
, "Unknown fattr type %d - ignored", vntype
);
401 * Initialize an allocated mount node.
402 * It is assumed that the mount node was b-zero'd
403 * before getting here so anything that would
404 * be set to zero isn't done here.
407 init_map(am_node
*mp
, char *dir
)
410 * mp->am_mapno is initialized by exported_ap_alloc
411 * other fields don't need to be set to zero.
413 mp
->am_mnt
= new_mntfs();
414 mp
->am_mfarray
= NULL
;
415 mp
->am_name
= strdup(dir
);
416 mp
->am_path
= strdup(dir
);
417 mp
->am_gen
= new_gen();
418 #ifdef HAVE_FS_AUTOFS
419 mp
->am_autofs_fh
= NULL
;
420 #endif /* HAVE_FS_AUTOFS */
422 mp
->am_timeo
= gopt
.am_timeo
;
423 mp
->am_attr
.ns_status
= NFS_OK
;
424 mp
->am_fattr
= gen_fattr
;
425 mp
->am_fattr
.na_fsid
= 42;
426 mp
->am_fattr
.na_fileid
= mp
->am_gen
;
427 clocktime(&mp
->am_fattr
.na_atime
);
428 /* next line copies a "struct nfstime" among several fields */
429 mp
->am_fattr
.na_mtime
= mp
->am_fattr
.na_ctime
= mp
->am_fattr
.na_atime
;
432 mp
->am_stats
.s_mtime
= mp
->am_fattr
.na_atime
.nt_seconds
;
441 notify_child(am_node
*mp
, au_etype au_etype
, int au_errno
, int au_signal
)
445 if (mp
->am_fd
[1] >= 0) { /* we have a child process */
446 rv
.au_etype
= au_etype
;
447 rv
.au_signal
= au_signal
;
448 rv
.au_errno
= au_errno
;
450 write(mp
->am_fd
[1], &rv
, sizeof(rv
));
459 * The node must be already unmounted.
462 free_map(am_node
*mp
)
466 if (mp
->am_fd
[1] != -1)
467 plog(XLOG_FATAL
, "free_map: called prior to notifying the child for %s.",
479 XFREE(mp
->am_transp
);
482 free_mntfs(mp
->am_mnt
);
484 if (mp
->am_mfarray
) {
486 for (temp_mf
= mp
->am_mfarray
; *temp_mf
; temp_mf
++)
487 free_mntfs(*temp_mf
);
488 XFREE(mp
->am_mfarray
);
491 #ifdef HAVE_FS_AUTOFS
492 if (mp
->am_autofs_fh
)
493 autofs_release_fh(mp
);
494 #endif /* HAVE_FS_AUTOFS */
496 exported_ap_free(mp
);
501 find_ap_recursive(char *dir
, am_node
*mp
)
505 if (STREQ(mp
->am_path
, dir
))
508 if ((mp
->am_mnt
->mf_flags
& MFF_MOUNTED
) &&
509 STREQ(mp
->am_mnt
->mf_mount
, dir
))
512 mp2
= find_ap_recursive(dir
, mp
->am_osib
);
515 return find_ap_recursive(dir
, mp
->am_child
);
523 * Find the mount node corresponding to dir. dir can match either the
524 * automount path or, if the node is mounted, the mount location.
531 for (i
= last_used_map
; i
>= 0; --i
) {
532 am_node
*mp
= exported_ap
[i
];
533 if (mp
&& (mp
->am_flags
& AMF_ROOT
)) {
534 mp
= find_ap_recursive(dir
, exported_ap
[i
]);
546 * Find the mount node corresponding
547 * to the mntfs structure.
554 for (i
= last_used_map
; i
>= 0; --i
) {
555 am_node
*mp
= exported_ap
[i
];
556 if (mp
&& mp
->am_mnt
== mf
)
565 * Get the filehandle for a particular named directory.
566 * This is used during the bootstrap to tell the kernel
567 * the filehandles of the initial automount points.
570 get_root_nfs_fh(char *dir
)
572 static am_nfs_fh nfh
;
573 am_node
*mp
= get_root_ap(dir
);
580 * Should never get here...
582 plog(XLOG_ERROR
, "Can't find root filehandle for %s", dir
);
589 get_root_ap(char *dir
)
591 am_node
*mp
= find_ap(dir
);
593 if (mp
&& mp
->am_parent
== root_node
)
601 * Timeout all nodes waiting on
605 map_flush_srvr(fserver
*fs
)
610 for (i
= last_used_map
; i
>= 0; --i
) {
611 am_node
*mp
= exported_ap
[i
];
612 if (mp
&& mp
->am_mnt
&& mp
->am_mnt
->mf_server
== fs
) {
613 plog(XLOG_INFO
, "Flushed %s; dependent on %s", mp
->am_path
, fs
->fs_host
);
614 mp
->am_ttl
= clocktime(NULL
);
619 reschedule_timeout_mp();
624 * Mount a top level automount node
625 * by calling lookup in the parent
626 * (root) node which will cause the
627 * automount node to be automounted.
630 mount_auto_node(char *dir
, opaque_t arg
)
633 am_node
*mp
= (am_node
*) arg
;
636 new_mp
= mp
->am_mnt
->mf_ops
->lookup_child(mp
, dir
, &error
, VLOOK_CREATE
);
637 if (new_mp
&& error
< 0) {
639 * We can't allow the fileid of the root node to change.
640 * Should be ok to force it to 1, always.
642 new_mp
->am_gen
= new_mp
->am_fattr
.na_fileid
= 1;
644 new_mp
= mp
->am_mnt
->mf_ops
->mount_child(new_mp
, &error
);
648 errno
= error
; /* XXX */
649 plog(XLOG_ERROR
, "Could not mount %s: %m", dir
);
656 * Cause all the top-level mount nodes
663 * Iterate over all the nodes to be started
665 return root_keyiter(mount_auto_node
, root_node
);
670 * Construct top-level node
676 char *rootmap
= ROOT_MAP
;
677 root_node
= exported_ap_alloc();
682 init_map(root_node
, "");
685 * Allocate a new mounted filesystem
687 root_mnt
= find_mntfs(&amfs_root_ops
, (am_opts
*) NULL
, "", rootmap
, "", "", "");
690 * Replace the initial null reference
692 free_mntfs(root_node
->am_mnt
);
693 root_node
->am_mnt
= root_mnt
;
696 * Initialize the root
698 if (root_mnt
->mf_ops
->fs_init
)
699 (*root_mnt
->mf_ops
->fs_init
) (root_mnt
);
704 root_mnt
->mf_error
= root_mnt
->mf_ops
->mount_fs(root_node
, root_mnt
);
709 * Cause all the nodes to be unmounted by timing
713 umount_exported(void)
717 for (i
= last_used_map
; i
>= 0; --i
) {
718 am_node
*mp
= exported_ap
[i
];
725 if (mf
->mf_flags
& MFF_UNMOUNTING
) {
727 * If this node is being unmounted then just ignore it. However,
728 * this could prevent amd from finishing if the unmount gets blocked
729 * since the am_node will never be free'd. am_unmounted needs
730 * telling about this possibility. - XXX
735 if (!(mf
->mf_fsflags
& FS_DIRECTORY
))
737 * When shutting down this had better
738 * look like a directory, otherwise it
739 * can't be unmounted!
741 mk_fattr(&mp
->am_fattr
, NFDIR
);
743 if ((--immediate_abort
< 0 &&
744 !(mp
->am_flags
& AMF_ROOT
) && mp
->am_parent
) ||
745 (mf
->mf_flags
& MFF_RESTART
)) {
748 * Just throw this node away without bothering to unmount it. If
749 * the server is not known to be up then don't discard the mounted
750 * on directory or Amd might hang...
753 (mf
->mf_server
->fs_flags
& (FSF_DOWN
| FSF_VALID
)) != FSF_VALID
)
754 mf
->mf_flags
&= ~MFF_MKMNT
;
755 if (gopt
.flags
& CFM_UNMOUNT_ON_EXIT
|| mp
->am_flags
& AMF_AUTOFS
) {
756 plog(XLOG_INFO
, "on-exit attempt to unmount %s", mf
->mf_mount
);
758 * use unmount_mp, not unmount_node, so that unmounts be
759 * backgrounded as needed.
761 unmount_mp((opaque_t
) mp
);
765 exported_ap
[i
] = NULL
;
768 * Any other node gets forcibly timed out.
770 mp
->am_flags
&= ~AMF_NOTIMEOUT
;
771 mp
->am_mnt
->mf_flags
&= ~MFF_RSTKEEP
;
781 * Try to mount a file system. Can be called directly or in a sub-process by run_task.
783 * Warning: this function might be running in a child process context.
784 * Don't expect any changes made here to survive in the parent amd process.
787 mount_node(opaque_t arg
)
789 am_node
*mp
= (am_node
*) arg
;
790 mntfs
*mf
= mp
->am_mnt
;
793 #ifdef HAVE_FS_AUTOFS
794 if (mp
->am_flags
& AMF_AUTOFS
)
795 error
= autofs_mount_fs(mp
, mf
);
797 #endif /* HAVE_FS_AUTOFS */
798 if (!(mf
->mf_flags
& MFF_MOUNTED
))
799 error
= mf
->mf_ops
->mount_fs(mp
, mf
);
802 dlog("mount_node: call to mf_ops->mount_fs(%s) failed: %s",
803 mp
->am_path
, strerror(error
));
809 unmount_node(opaque_t arg
)
811 am_node
*mp
= (am_node
*) arg
;
812 mntfs
*mf
= mp
->am_mnt
;
815 if (mf
->mf_flags
& MFF_ERROR
) {
819 dlog("No-op unmount of error node %s", mf
->mf_info
);
821 dlog("Unmounting <%s> <%s> (%s) flags %x",
822 mp
->am_path
, mf
->mf_mount
, mf
->mf_info
, mf
->mf_flags
);
823 #ifdef HAVE_FS_AUTOFS
824 if (mp
->am_flags
& AMF_AUTOFS
)
825 error
= autofs_umount_fs(mp
, mf
);
827 #endif /* HAVE_FS_AUTOFS */
828 if (mf
->mf_refc
== 1)
829 error
= mf
->mf_ops
->umount_fs(mp
, mf
);
832 /* do this again, it might have changed */
835 errno
= error
; /* XXX */
836 dlog("%s: unmount: %m", mf
->mf_mount
);
844 free_map_if_success(int rc
, int term
, opaque_t arg
)
846 am_node
*mp
= (am_node
*) arg
;
847 mntfs
*mf
= mp
->am_mnt
;
848 wchan_t wchan
= get_mntfs_wchan(mf
);
851 * Not unmounting any more
853 mf
->mf_flags
&= ~MFF_UNMOUNTING
;
856 * If a timeout was deferred because the underlying filesystem
857 * was busy then arrange for a timeout as soon as possible.
859 if (mf
->mf_flags
& MFF_WANTTIMO
) {
860 mf
->mf_flags
&= ~MFF_WANTTIMO
;
861 reschedule_timeout_mp();
864 notify_child(mp
, AMQ_UMNT_SIGNAL
, 0, term
);
865 plog(XLOG_ERROR
, "unmount for %s got signal %d", mp
->am_path
, term
);
866 #if defined(DEBUG) && defined(SIGTRAP)
868 * dbx likes to put a trap on exit().
869 * Pretend it succeeded for now...
871 if (term
== SIGTRAP
) {
875 #ifdef HAVE_FS_AUTOFS
876 if (mp
->am_flags
& AMF_AUTOFS
)
877 autofs_umount_failed(mp
);
878 #endif /* HAVE_FS_AUTOFS */
881 notify_child(mp
, AMQ_UMNT_FAILED
, rc
, 0);
882 if (mf
->mf_ops
== &amfs_program_ops
|| rc
== EBUSY
)
883 plog(XLOG_STATS
, "\"%s\" on %s still active", mp
->am_path
, mf
->mf_mount
);
885 plog(XLOG_ERROR
, "%s: unmount: %s", mp
->am_path
, strerror(rc
));
886 #ifdef HAVE_FS_AUTOFS
887 if (mf
->mf_flags
& MFF_IS_AUTOFS
)
889 if (mp
->am_flags
& AMF_AUTOFS
)
890 autofs_umount_failed(mp
);
891 #endif /* HAVE_FS_AUTOFS */
895 * am_unmounted() will call notify_child() appropriately.
901 * Wakeup anything waiting for this unmount
908 unmount_mp(am_node
*mp
)
910 int was_backgrounded
= 0;
911 mntfs
*mf
= mp
->am_mnt
;
914 plog(XLOG_INFO
, "\"%s\" on %s timed out (flags 0x%x)",
915 mp
->am_path
, mp
->am_mnt
->mf_mount
, (int) mf
->mf_flags
);
918 #ifndef MNT2_NFS_OPT_SYMTTL
920 * This code is needed to defeat Solaris 2.4's (and newer) symlink
921 * values cache. It forces the last-modified time of the symlink to be
922 * current. It is not needed if the O/S has an nfs flag to turn off the
923 * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
925 * Additionally, Linux currently ignores the nt_useconds field,
926 * so we must update the nt_seconds field every time if clocktime(NULL)
927 * didn't return a new number of seconds.
930 time_t last
= mp
->am_parent
->am_attr
.ns_u
.ns_attr_u
.na_mtime
.nt_seconds
;
931 clocktime(&mp
->am_parent
->am_attr
.ns_u
.ns_attr_u
.na_mtime
);
932 /* defensive programming... can't we assert the above condition? */
933 if (last
== (time_t) mp
->am_parent
->am_attr
.ns_u
.ns_attr_u
.na_mtime
.nt_seconds
)
934 mp
->am_parent
->am_attr
.ns_u
.ns_attr_u
.na_mtime
.nt_seconds
++;
936 #endif /* not MNT2_NFS_OPT_SYMTTL */
938 if (mf
->mf_refc
== 1 && !FSRV_ISUP(mf
->mf_server
)) {
940 * Don't try to unmount from a server that is known to be down
942 if (!(mf
->mf_flags
& MFF_LOGDOWN
)) {
943 /* Only log this once, otherwise gets a bit boring */
944 plog(XLOG_STATS
, "file server %s is down - timeout of \"%s\" ignored", mf
->mf_server
->fs_host
, mp
->am_path
);
945 mf
->mf_flags
|= MFF_LOGDOWN
;
947 notify_child(mp
, AMQ_UMNT_SERVER
, 0, 0);
951 dlog("\"%s\" on %s timed out", mp
->am_path
, mp
->am_mnt
->mf_mount
);
952 mf
->mf_flags
|= MFF_UNMOUNTING
;
954 #ifdef HAVE_FS_AUTOFS
955 if (mf
->mf_flags
& MFF_IS_AUTOFS
)
956 autofs_release_mp(mp
);
957 #endif /* HAVE_FS_AUTOFS */
959 if ((mf
->mf_fsflags
& FS_UBACKGROUND
) &&
960 (mf
->mf_flags
& MFF_MOUNTED
)) {
961 dlog("Trying unmount in background");
962 run_task(unmount_node
, (opaque_t
) mp
,
963 free_map_if_success
, (opaque_t
) mp
);
964 was_backgrounded
= 1;
966 dlog("Trying unmount in foreground");
967 free_map_if_success(unmount_node((opaque_t
) mp
), 0, (opaque_t
) mp
);
968 dlog("unmount attempt done");
971 return was_backgrounded
;
976 timeout_mp(opaque_t v
) /* argument not used?! */
980 time_t now
= clocktime(NULL
);
981 int backoff
= NumChildren
/ 4;
983 dlog("Timing out automount points...");
985 for (i
= last_used_map
; i
>= 0; --i
) {
986 am_node
*mp
= exported_ap
[i
];
990 * Just continue if nothing mounted
996 * Pick up mounted filesystem
1002 #ifdef HAVE_FS_AUTOFS
1003 if (mf
->mf_flags
& MFF_IS_AUTOFS
&& mp
->am_autofs_ttl
!= NEVER
) {
1004 if (now
>= mp
->am_autofs_ttl
)
1005 autofs_timeout_mp(mp
);
1006 t
= smallest_t(t
, mp
->am_autofs_ttl
);
1008 #endif /* HAVE_FS_AUTOFS */
1010 if (mp
->am_flags
& AMF_NOTIMEOUT
)
1014 * Don't delete last reference to a restarted filesystem.
1016 if ((mf
->mf_flags
& MFF_RSTKEEP
) && mf
->mf_refc
== 1)
1020 * If there is action on this filesystem then ignore it
1022 if (!(mf
->mf_flags
& IGNORE_FLAGS
)) {
1024 mf
->mf_flags
&= ~MFF_WANTTIMO
;
1025 if (now
>= mp
->am_ttl
) {
1030 * Move the ttl forward to avoid thrashing effects
1031 * on the next call to timeout!
1033 /* sun's -tw option */
1034 if (mp
->am_timeo_w
< 4 * gopt
.am_timeo_w
)
1035 mp
->am_timeo_w
+= gopt
.am_timeo_w
;
1036 mp
->am_ttl
= now
+ mp
->am_timeo_w
;
1040 * Just backoff this unmount for
1041 * a couple of seconds to avoid
1042 * many multiple unmounts being
1043 * started in parallel.
1045 mp
->am_ttl
= now
+ backoff
+ 1;
1050 * If the next ttl is smallest, use that
1052 t
= smallest_t(t
, mp
->am_ttl
);
1054 if (!mp
->am_child
&& mf
->mf_error
>= 0 && expired
) {
1056 * If the unmount was backgrounded then
1057 * bump the backoff counter.
1059 if (unmount_mp(mp
)) {
1063 } else if (mf
->mf_flags
& MFF_UNMOUNTING
) {
1064 mf
->mf_flags
|= MFF_WANTTIMO
;
1069 dlog("No further timeouts");
1074 * Sanity check to avoid runaways.
1075 * Absolutely should never get this but
1076 * if you do without this trap amd will thrash.
1079 t
= now
+ 6; /* XXX */
1080 plog(XLOG_ERROR
, "Got a zero interval in timeout_mp()!");
1084 * XXX - when shutting down, make things happen faster
1086 if ((int) amd_state
>= (int) Finishing
)
1088 dlog("Next mount timeout in %lds", (long) (t
- now
));
1090 timeout_mp_id
= timeout(t
- now
, timeout_mp
, NULL
);
1095 * Cause timeout_mp to be called soonest
1098 reschedule_timeout_mp(void)
1101 untimeout(timeout_mp_id
);
1102 timeout_mp_id
= timeout(0, timeout_mp
, NULL
);