/* 终止线程 */ void thread::stop() { if ( !_run ) { ERROR( "thread::stop:thread not running" ); return; } assert( "thread join zero thread id", 0 != _thread ); _run = false; notify_child( EXIT ); int32 ecode = pthread_join( _thread,NULL ); if ( ecode ) { /* On success, pthread_join() returns 0; on error, it returns an error * number.errno is not use. * not strerror(errno) */ FATAL( "thread join fail:%s",strerror( ecode ) ); } _join = true; if ( _watcher.is_active() ) _watcher.stop(); if ( _fd[0] >= 0 ) { ::close( _fd[0] );_fd[0] = -1; } if ( _fd[1] >= 0 ) { ::close( _fd[1] );_fd[1] = -1; } }
void forcibly_timeout_mp(am_node *mp) { mntfs *mf = mp->am_al->al_mnt; /* * Arrange to timeout this node */ if (mf && ((mp->am_flags & AMF_ROOT) || (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) { /* * We aren't going to schedule a timeout, so we need to notify the * child here unless we are already unmounting, in which case that * process is responsible for notifying the child. */ if (mf->mf_flags & MFF_UNMOUNTING) plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path); else { plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path); notify_child(mp, AMQ_UMNT_FAILED, EBUSY, 0); } } else { plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path); mp->am_flags &= ~AMF_NOTIMEOUT; mp->am_ttl = clocktime(NULL); /* * Force mtime update of parent dir, to prevent DNLC/dcache from caching * the old entry, which could result in ESTALE errors, bad symlinks, and * more. */ clocktime(&mp->am_parent->am_fattr.na_mtime); reschedule_timeout_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); } }