void am_unmounted(am_node *mp) { mntfs *mf = mp->am_mnt; if (!foreground) /* firewall - should never happen */ return; /* * Do unmounted callback */ if (mf->mf_ops->umounted) mf->mf_ops->umounted(mf); /* * This is ugly, but essentially unavoidable. * Sublinks must be treated separately as type==link * when the base type is different. */ if (mp->am_link && mp->am_mnt->mf_ops != &amfs_link_ops) amfs_link_ops.umount_fs(mp, mp->am_mnt); #ifdef HAVE_FS_AUTOFS if (mp->am_flags & AMF_AUTOFS) autofs_umount_succeeded(mp); #endif /* HAVE_FS_AUTOFS */ /* * Clean up any directories that were made * * If we remove the mount point of a pending mount, any queued access * to it will fail. So don't do it in that case. */ if (mf->mf_flags & MFF_MKMNT && !(mp->am_flags & AMF_REMOUNT)) { plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_real_mount); rmdirs(mf->mf_real_mount); } /* * If this is a pseudo-directory then adjust the link count * in the parent */ if (mp->am_parent && mp->am_fattr.na_type == NFDIR) --mp->am_parent->am_fattr.na_nlink; /* * Update mtime of parent node */ if (mp->am_parent && mp->am_parent->am_mnt) mp->am_parent->am_fattr.na_mtime.nt_seconds = clocktime(); if (mp->am_flags & AMF_REMOUNT) { char *fname = strdup(mp->am_name); am_node *mp_parent = mp->am_parent; int error = 0; free_map(mp); plog(XLOG_INFO, "am_unmounted: remounting %s", fname); mp = amfs_auto_lookup_child(mp_parent, fname, &error, VLOOK_CREATE); if (mp && error < 0) mp = amfs_auto_mount_child(mp, &error); if (error > 0) { errno = error; plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname); } XFREE(fname); } else free_map(mp); }
void am_unmounted(am_node *mp) { mntfs *mf = mp->am_al->al_mnt; if (!foreground) { /* firewall - should never happen */ /* * This is a coding error. Make sure we hear about it! */ plog(XLOG_FATAL, "am_unmounted: illegal use in background (%s)", mp->am_name); notify_child(mp, AMQ_UMNT_OK, 0, 0); /* XXX - be safe? */ return; } /* * Do unmounted callback */ if (mf->mf_ops->umounted) mf->mf_ops->umounted(mf); /* * This is ugly, but essentially unavoidable. * Sublinks must be treated separately as type==link * when the base type is different. */ if (mp->am_link && mf->mf_ops != &amfs_link_ops) amfs_link_ops.umount_fs(mp, mf); #ifdef HAVE_FS_AUTOFS if (mf->mf_flags & MFF_IS_AUTOFS) autofs_release_fh(mp); if (mp->am_flags & AMF_AUTOFS) autofs_umount_succeeded(mp); #endif /* HAVE_FS_AUTOFS */ /* * Clean up any directories that were made * * If we remove the mount point of a pending mount, any queued access * to it will fail. So don't do it in that case. * Also don't do it if the refcount is > 1. */ if (mf->mf_flags & MFF_MKMNT && mf->mf_refc == 1 && !(mp->am_flags & AMF_REMOUNT)) { plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount); rmdirs(mf->mf_mount); mf->mf_flags &= ~MFF_MKMNT; } /* * If this is a pseudo-directory then adjust the link count * in the parent */ if (mp->am_parent && mp->am_fattr.na_type == NFDIR) --mp->am_parent->am_fattr.na_nlink; /* * Update mtime of parent node */ if (mp->am_parent && mp->am_parent->am_al->al_mnt) clocktime(&mp->am_parent->am_fattr.na_mtime); if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) { char *fname = xstrdup(mp->am_name); am_node *mp_parent = mp->am_parent; mntfs *mf_parent = mp_parent->am_al->al_mnt; am_node fake_mp; int error = 0; /* * We need to use notify_child() after free_map(), so save enough * to do that in fake_mp. */ fake_mp.am_fd[1] = mp->am_fd[1]; mp->am_fd[1] = -1; free_map(mp); plog(XLOG_INFO, "am_unmounted: remounting %s", fname); mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE); if (mp && error < 0) (void)mf_parent->mf_ops->mount_child(mp, &error); if (error > 0) { errno = error; plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname); notify_child(&fake_mp, AMQ_UMNT_OK, 0, 0); } else { notify_child(&fake_mp, AMQ_UMNT_FAILED, EBUSY, 0); } XFREE(fname); } else { /* * We have a race here. * If this node has a pending mount and amd is going down (unmounting * everything in the process), then we could potentially free it here * while a struct continuation still has a reference to it. So when * amfs_cont is called, it blows up. * We avoid the race by refusing to free any nodes that have * pending mounts (defined as having a non-NULL am_alarray). */ notify_child(mp, AMQ_UMNT_OK, 0, 0); /* do this regardless */ if (!mp->am_alarray) free_map(mp); } }