⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 map.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
am_node *find_ap(dir)char *dir;{	int i;	for (i = last_used_map; i >= 0; --i) {		am_node *mp = exported_ap[i];		if (mp && (mp->am_flags & AMF_ROOT)) {			mp = find_ap2(dir, exported_ap[i]);			if (mp)				return mp;		}	}	return 0;}/* * Find the mount node corresponding * to the mntfs structure. */am_node *find_mf P((mntfs *mf));am_node *find_mf(mf)mntfs *mf;{	int i;	for (i = last_used_map; i >= 0; --i) {		am_node *mp = exported_ap[i];		if (mp && mp->am_mnt == mf)			return mp;	}	return 0;}/* * Get the filehandle for a particular named directory. * This is used during the bootstrap to tell the kernel * the filehandles of the initial automount points. */nfs_fh *root_fh(dir)char *dir;{	static nfs_fh nfh;	am_node *mp = root_ap(dir, TRUE);	if (mp) {		mp_to_fh(mp, &nfh);		/*		 * Patch up PID to match main server...		 */		if (!foreground) {			long pid = getppid();			((struct am_fh *) &nfh)->fhh_pid = pid;#ifdef DEBUG			dlog("root_fh substitutes pid %d", pid);#endif		}		return &nfh;	}	/*	 * Should never get here...	 */	plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);	return 0;}am_node *root_ap(dir, path)char *dir;int path;{	am_node *mp = find_ap(dir);	if (mp && mp->am_parent == root_node)		return mp;	return 0;}/* * Timeout all nodes waiting on * a given Fserver. */void map_flush_srvr P((fserver *fs));void map_flush_srvr(fs)fserver *fs;{	int i;	int done = 0;	for (i = last_used_map; i >= 0; --i) {		am_node *mp = exported_ap[i];		if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) {			plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host);			mp->am_ttl = clocktime();			done = 1;		}	}	if (done)		reschedule_timeout_mp();}/* * Mount a top level automount node * by calling lookup in the parent * (root) node which will cause the * automount node to be automounted. */int mount_auto_node P((char *dir, voidp arg));int mount_auto_node(dir, arg)char *dir;voidp arg;{	int error = 0;	(void) afs_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE);	if (error > 0) {		errno = error; /* XXX */		plog(XLOG_ERROR, "Could not mount %s: %m", dir);	}	return error;}/* * Cause all the top-level mount nodes * to be automounted */int mount_exported P((void));int mount_exported(){	/*	 * Iterate over all the nodes to be started	 */	return root_keyiter((void (*)P((char*,void*))) mount_auto_node, root_node);}/* * Construct top-level node */void make_root_node P((void));void make_root_node(){	mntfs *root_mnt;	char *rootmap = ROOT_MAP;	root_node = exported_ap_alloc();	/*	 * Allocate a new map	 */	init_map(root_node, "");	/*	 * Allocate a new mounted filesystem	 */	root_mnt = find_mntfs(&root_ops, (am_opts *) 0, "", rootmap, "", "", "");	/*	 * Replace the initial null reference	 */	free_mntfs(root_node->am_mnt);	root_node->am_mnt = root_mnt;	/*	 * Initialise the root	 */	if (root_mnt->mf_ops->fs_init)		(*root_mnt->mf_ops->fs_init)(root_mnt);	/*	 * Mount the root	 */	root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs)(root_node);}/* * Cause all the nodes to be unmounted by timing * them out. */void umount_exported(P_void){	int i;	for (i = last_used_map; i >= 0; --i) {		am_node *mp = exported_ap[i];		if (mp) {			mntfs *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 (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) {				/*				 * When shutting down this had better				 * look like a directory, otherwise it				 * can't be unmounted!				 */				mk_fattr(mp, NFDIR);			}			if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||			    (mf->mf_flags & MFF_RESTART)) {				/*				 * 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;				am_unmounted(mp);			} 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;			}		}	}}static int unmount_node P((am_node *mp));static int unmount_node(mp)am_node *mp;{	mntfs *mf = mp->am_mnt;	int error;	if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {		/*		 * Just unlink		 */#ifdef DEBUG		if (mf->mf_flags & MFF_ERROR)			dlog("No-op unmount of error node %s", mf->mf_info);#endif /* DEBUG */		error = 0;	} else {#ifdef DEBUG		dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);#endif /* DEBUG */		error = (*mf->mf_ops->umount_fs)(mp);	}	if (error) {#ifdef DEBUG		errno = error; /* XXX */		dlog("%s: unmount: %m", mf->mf_mount);#endif /* DEBUG */	}	return error;}#ifdef FLUSH_KERNEL_NAME_CACHEstatic void flush_kernel_name_cache P((am_node*));static void flush_kernel_name_cache(mp)am_node *mp;{	int islink = (mp->am_mnt->mf_fattr.type == NFLNK);	int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);	int elog = 0;	if (islink) {		if (unlink(mp->am_path) < 0)			elog = 1;	} else if (isdir) {		if (rmdir(mp->am_path) < 0)			elog = 1;	}	if (elog)		plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path);}#endif /* FLUSH_KERNEL_NAME_CACHE */static int unmount_node_wrap P((voidp vp));static int unmount_node_wrap(vp)voidp vp;{#ifndef FLUSH_KERNEL_NAME_CACHE	return unmount_node((am_node*) vp);#else /* FLUSH_KERNEL_NAME_CACHE */	/*	 * This code should just say:	 * return unmount_node((am_node *) vp);	 *	 * However...	 * The kernel keeps a cached copy of filehandles,	 * and doesn't ever uncache them (apparently).  So	 * when Amd times out a node the kernel will have a	 * stale filehandle.  When the kernel next uses the	 * filehandle it gets ESTALE.	 *	 * The workaround:	 * Arrange that when a node is removed an unlink or	 * rmdir is done on that path so that the kernel	 * cache is done.  Yes - yuck.	 *	 * This can all be removed (and the background	 * unmount flag in sfs_ops) if/when the kernel does	 * something smarter.	 *	 * If the unlink or rmdir failed then just log a warning,	 * don't fail the unmount.  This can occur if the kernel	 * client code decides that the object is still referenced	 * and should be renamed rather than discarded.	 *	 * There is still a race condition here...	 * if another process is trying to access the same	 * filesystem at the time we get here, then	 * it will block, since the MF_UNMOUNTING flag will	 * be set.  That may, or may not, cause the entire	 * system to deadlock.  Hmmm...	 */	am_node *mp = (am_node *) vp;	int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);	int error = unmount_node(mp);	if (error)		return error;	if (isauto && (int)amd_state < (int)Finishing)		flush_kernel_name_cache(mp);	return 0;#endif /* FLUSH_KERNEL_NAME_CACHE */}static void free_map_if_success(rc, term, closure)int rc;int term;voidp closure;{	am_node *mp = (am_node *) closure;	mntfs *mf = mp->am_mnt;	/*	 * Not unmounting any more	 */	mf->mf_flags &= ~MFF_UNMOUNTING;	/*	 * If a timeout was defered because the underlying filesystem	 * was busy then arrange for a timeout as soon as possible.	 */	if (mf->mf_flags & MFF_WANTTIMO) {		mf->mf_flags &= ~MFF_WANTTIMO;		reschedule_timeout_mp();	}	if (term) {		plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);#if defined(DEBUG) && defined(SIGTRAP)		/*		 * dbx likes to put a trap on exit().		 * Pretend it succeeded for now...		 */		if (term == SIGTRAP) {			am_unmounted(mp);		}#endif /* DEBUG */		amd_stats.d_uerr++;	} else if (rc) {		if (rc == EBUSY) {			plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);		} else {			errno = rc;	/* XXX */			plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);		}		amd_stats.d_uerr++;	} else {		am_unmounted(mp);	}	/*	 * Wakeup anything waiting for this mount	 */	wakeup((voidp) mf);}static int unmount_mp(mp)am_node *mp;{	int was_backgrounded = 0;	mntfs *mf = mp->am_mnt;#ifdef notdef	plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);#endif /* notdef */	if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&			(mf->mf_flags & MFF_MOUNTED)) {		if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {			/*			 * Don't try to unmount from a server that is known to be down			 */			if (!(mf->mf_flags & MFF_LOGDOWN)) {				/* Only log this once, otherwise gets a bit boring */				plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);				mf->mf_flags |= MFF_LOGDOWN;			}		} else {			/* Clear logdown flag - since the server must be up */			mf->mf_flags &= ~MFF_LOGDOWN;#ifdef DEBUG			dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);			/*dlog("Will background the unmount attempt");*/#endif /* DEBUG */			/*			 * Note that we are unmounting this node			 */			mf->mf_flags |= MFF_UNMOUNTING;			run_task(unmount_node_wrap, (voidp) mp,				 free_map_if_success, (voidp) mp);			was_backgrounded = 1;#ifdef DEBUG			dlog("unmount attempt backgrounded");#endif /* DEBUG */		}	} else {#ifdef DEBUG		dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);		dlog("Trying unmount in foreground");#endif		mf->mf_flags |= MFF_UNMOUNTING;		free_map_if_success(unmount_node(mp), 0, (voidp) mp);#ifdef DEBUG		dlog("unmount attempt done");#endif /* DEBUG */	}	return was_backgrounded;}void timeout_mp(){#define NEVER (time_t) 0#define	smallest_t(t1, t2) \	(t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)	int i;	time_t t = NEVER;	time_t now = clocktime();	int backoff = 0;#ifdef DEBUG	dlog("Timing out automount points...");#endif /* DEBUG */	for (i = last_used_map; i >= 0; --i) {		am_node *mp = exported_ap[i];		mntfs *mf;		/*		 * Just continue if nothing mounted, or can't be timed out.		 */		if (!mp || (mp->am_flags & AMF_NOTIMEOUT))			continue;		/*		 * Pick up mounted filesystem		 */		mf = mp->am_mnt;		if (!mf)			continue;		/*		 * Don't delete last reference to a restarted filesystem.		 */		if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)			continue;		/*		 * If there is action on this filesystem then ignore it		 */		if (!(mf->mf_flags & IGNORE_FLAGS)) {			int expired = 0;			mf->mf_flags &= ~MFF_WANTTIMO;#ifdef DEBUG			/*dlog("t is initially @%d, zero in %d secs", t, t - now);*/#endif /* DEBUG */			if (now >= mp->am_ttl) {				if (!backoff) {					expired = 1;					/*					 * Move the ttl forward to avoid thrashing effects					 * on the next call to timeout!					 */					/* sun's -tw option */					if (mp->am_timeo_w < 4 * am_timeo_w)						mp->am_timeo_w += am_timeo_w;					mp->am_ttl = now + mp->am_timeo_w;				} else {					/*					 * Just backoff this unmount for					 * a couple of seconds to avoid					 * many multiple unmounts being					 * started in parallel.					 */					mp->am_ttl = now + backoff + 1;				}			}			/*			 * If the next ttl is smallest, use that			 */			t = smallest_t(t, mp->am_ttl);#ifdef DEBUG			/*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/#endif /* DEBUG */			if (!mp->am_child && mf->mf_error >= 0 && expired) {				/*				 * If the unmount was backgrounded then				 * bump the backoff counter.				 */				if (unmount_mp(mp)) {					backoff = 2;#ifdef DEBUG					/*dlog("backing off subsequent unmounts by at least %d seconds", backoff);*/#endif				}			}		} else if (mf->mf_flags & MFF_UNMOUNTING) {			mf->mf_flags |= MFF_WANTTIMO;		}	}	if (t == NEVER) {#ifdef DEBUG		dlog("No further timeouts");#endif /* DEBUG */		t = now + ONE_HOUR;	}	/*	 * Sanity check to avoid runaways.	 * Absolutely should never get this but	 * if you do without this trap amd will thrash.	 */	if (t <= now) {		t = now + 6;	/* XXX */		plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");	}	/*	 * XXX - when shutting down, make things happen faster	 */	if ((int)amd_state >= (int)Finishing)		t = now + 1;#ifdef DEBUG	dlog("Next mount timeout in %ds", t - now);#endif /* DEBUG */	timeout_mp_id = timeout(t - now, timeout_mp, 0);#undef NEVER#undef smallest_t#undef IGNORE_FLAGS}/* * Cause timeout_mp to be called soonest */void reschedule_timeout_mp(){	if (timeout_mp_id)		untimeout(timeout_mp_id);	timeout_mp_id = timeout(0, timeout_mp, 0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -