153 lines
4.7 KiB
Diff
153 lines
4.7 KiB
Diff
|
diff -up am-utils-6.1.5/amd/map.c.orig am-utils-6.1.5/amd/map.c
|
||
|
--- am-utils-6.1.5/amd/map.c.orig 2014-03-19 19:34:23.000000000 +0800
|
||
|
+++ am-utils-6.1.5/amd/map.c 2014-03-19 19:44:17.918101095 +0800
|
||
|
@@ -687,68 +687,80 @@ make_root_node(void)
|
||
|
void
|
||
|
umount_exported(void)
|
||
|
{
|
||
|
- int i;
|
||
|
+ int i, work_done;
|
||
|
|
||
|
- for (i = last_used_map; i >= 0; --i) {
|
||
|
- am_node *mp = exported_ap[i];
|
||
|
- mntfs *mf;
|
||
|
+ do {
|
||
|
+ work_done = 0;
|
||
|
|
||
|
- if (!mp)
|
||
|
- continue;
|
||
|
+ for (i = last_used_map; i >= 0; --i) {
|
||
|
+ am_node *mp = exported_ap[i];
|
||
|
+ mntfs *mf;
|
||
|
|
||
|
- mf = mp->am_mnt;
|
||
|
- if (mf->mf_flags & MFF_UNMOUNTING) {
|
||
|
- /*
|
||
|
- * If this node is being unmounted then just ignore it. However,
|
||
|
- * this could prevent amd from finishing if the unmount gets blocked
|
||
|
- * since the am_node will never be free'd. am_unmounted needs
|
||
|
- * telling about this possibility. - XXX
|
||
|
- */
|
||
|
- continue;
|
||
|
- }
|
||
|
+ if (!mp)
|
||
|
+ continue;
|
||
|
|
||
|
- if (!(mf->mf_fsflags & FS_DIRECTORY))
|
||
|
/*
|
||
|
- * When shutting down this had better
|
||
|
- * look like a directory, otherwise it
|
||
|
- * can't be unmounted!
|
||
|
+ * Wait for children to be removed first
|
||
|
*/
|
||
|
- mk_fattr(&mp->am_fattr, NFDIR);
|
||
|
+ if (mp->am_child)
|
||
|
+ continue;
|
||
|
|
||
|
- if ((--immediate_abort < 0 &&
|
||
|
- !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
|
||
|
- (mf->mf_flags & MFF_RESTART)) {
|
||
|
+ mf = mp->am_mnt;
|
||
|
+ if (mf->mf_flags & MFF_UNMOUNTING) {
|
||
|
+ /*
|
||
|
+ * If this node is being unmounted then just ignore it. However,
|
||
|
+ * this could prevent amd from finishing if the unmount gets blocked
|
||
|
+ * since the am_node will never be free'd. am_unmounted needs
|
||
|
+ * telling about this possibility. - XXX
|
||
|
+ */
|
||
|
+ continue;
|
||
|
+ }
|
||
|
|
||
|
- /*
|
||
|
- * Just throw this node away without bothering to unmount it. If
|
||
|
- * the server is not known to be up then don't discard the mounted
|
||
|
- * on directory or Amd might hang...
|
||
|
- */
|
||
|
- if (mf->mf_server &&
|
||
|
+ if (!(mf->mf_fsflags & FS_DIRECTORY))
|
||
|
+ /*
|
||
|
+ * When shutting down this had better
|
||
|
+ * look like a directory, otherwise it
|
||
|
+ * can't be unmounted!
|
||
|
+ */
|
||
|
+ mk_fattr(&mp->am_fattr, NFDIR);
|
||
|
+
|
||
|
+ if ((--immediate_abort < 0 &&
|
||
|
+ !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
|
||
|
+ (mf->mf_flags & MFF_RESTART)) {
|
||
|
+
|
||
|
+ work_done++;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Just throw this node away without bothering to unmount it. If
|
||
|
+ * the server is not known to be up then don't discard the mounted
|
||
|
+ * on directory or Amd might hang...
|
||
|
+ */
|
||
|
+ if (mf->mf_server &&
|
||
|
(mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID)
|
||
|
mf->mf_flags &= ~MFF_MKMNT;
|
||
|
- if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) {
|
||
|
- plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount);
|
||
|
- /*
|
||
|
- * use unmount_mp, not unmount_node, so that unmounts be
|
||
|
- * backgrounded as needed.
|
||
|
- */
|
||
|
- unmount_mp((opaque_t) mp);
|
||
|
- } else {
|
||
|
- am_unmounted(mp);
|
||
|
- }
|
||
|
- exported_ap[i] = 0;
|
||
|
- } else {
|
||
|
- /*
|
||
|
- * Any other node gets forcibly timed out.
|
||
|
- */
|
||
|
- mp->am_flags &= ~AMF_NOTIMEOUT;
|
||
|
- mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
|
||
|
- mp->am_ttl = 0;
|
||
|
- mp->am_timeo = 1;
|
||
|
- mp->am_timeo_w = 0;
|
||
|
- }
|
||
|
- }
|
||
|
+ if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) {
|
||
|
+ plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount);
|
||
|
+ /*
|
||
|
+ * use unmount_mp, not unmount_node, so that unmounts be
|
||
|
+ * backgrounded as needed.
|
||
|
+ */
|
||
|
+ unmount_mp((opaque_t) mp);
|
||
|
+ } else {
|
||
|
+ am_unmounted(mp);
|
||
|
+ }
|
||
|
+ exported_ap[i] = NULL;
|
||
|
+ } else {
|
||
|
+ /*
|
||
|
+ * Any other node gets forcibly timed out.
|
||
|
+ */
|
||
|
+ mp->am_flags &= ~AMF_NOTIMEOUT;
|
||
|
+ mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
|
||
|
+ mp->am_ttl = 0;
|
||
|
+ mp->am_timeo = 1;
|
||
|
+ mp->am_timeo_w = 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ } while (work_done);
|
||
|
}
|
||
|
|
||
|
|
||
|
diff -U0 am-utils-6.1.5/ChangeLog.orig am-utils-6.1.5/ChangeLog
|
||
|
--- am-utils-6.1.5/ChangeLog.orig 2006-05-12 01:25:47.000000000 +0800
|
||
|
+++ am-utils-6.1.5/ChangeLog 2014-03-19 19:36:27.335598581 +0800
|
||
|
@@ -0,0 +1,12 @@
|
||
|
+2009-12-10 Christos Zoulas <christos@zoulas.com>
|
||
|
+
|
||
|
+ * Make sure to remove nodes in the proper order when going
|
||
|
+ down. Depending on what order the nodes got created it's
|
||
|
+ possible that the parent of a node has a bigger am_mapno
|
||
|
+ (index in exported_ap[]) so that it gets freed before
|
||
|
+ its child while the child's am_parent pointer is still
|
||
|
+ pointing to the already freed block of memory.
|
||
|
+ This change makes sure that umount_exported() cleans up
|
||
|
+ all children of a node first before freeing the node.
|
||
|
+ From: Krisztian Kovacs <Kris.Kovacs@morganstanley.com>
|
||
|
+
|