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

📄 afs_ops.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry at Imperial College, London. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)afs_ops.c	8.1 (Berkeley) 6/6/93 * * $Id: afs_ops.c,v 5.2.2.4 1992/05/31 16:36:36 jsp Exp $ * */#include "am.h"#define NFS#define NFSCLIENT#include <sys/stat.h>#ifdef NFS_3typedef nfs_fh fhandle_t;#endif /* NFS_3 */#ifdef NFS_HDR#include NFS_HDR#endif /* NFS_HDR */#include <sys/mount.h>#include "mount.h"/* * Automount file system * Direct file system * Root file system * Top-level file system *//* * Interval between forced retries of a mount. */#define RETRY_INTERVAL	2/* * AFS needs nothing in particular. */static char *afs_match P((am_opts *fo));static char *afs_match(fo)am_opts *fo;{	char *p = fo->opt_rfs;	if (!fo->opt_rfs) {		plog(XLOG_USER, "auto: no mount point named (rfs:=)");		return 0;	}	if (!fo->opt_fs) {		plog(XLOG_USER, "auto: no map named (fs:=)");		return 0;	}	/*	 * Swap round fs:= and rfs:= options	 * ... historical (jsp)	 */	fo->opt_rfs = fo->opt_fs;	fo->opt_fs = p;	/*	 * mtab entry turns out to be the name of the mount map	 */	return strdup(fo->opt_rfs ? fo->opt_rfs : ".");}/* * Mount an automounter directory. * The automounter is connected into the system * as a user-level NFS server.  mount_toplvl constructs * the necessary NFS parameters to be given to the * kernel so that it will talk back to us. */static int mount_toplvl P((char *dir, char *opts));static int mount_toplvl(dir, opts)char *dir;char *opts;{	struct nfs_args nfs_args;	struct mntent mnt;	int retry;	struct sockaddr_in sin;	unsigned short port;	int flags;	extern nfs_fh *root_fh();	nfs_fh *fhp;	char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];	MTYPE_TYPE type = MOUNT_TYPE_NFS;	bzero((voidp) &nfs_args, sizeof(nfs_args));	/* Paranoid */	mnt.mnt_dir = dir;	mnt.mnt_fsname = pid_fsname;	mnt.mnt_type = MNTTYPE_AUTO;	mnt.mnt_opts = opts;	mnt.mnt_freq = 0;	mnt.mnt_passno = 0;	retry = hasmntval(&mnt, "retry");	if (retry <= 0)		retry = 2;	/* XXX */	/*	 * get fhandle of remote path for automount point	 */		fhp = root_fh(dir);	if (!fhp) {		plog(XLOG_FATAL, "Can't find root file handle for %s", dir);		return EINVAL;	}	NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp);	/*	 * Create sockaddr to point to the local machine.  127.0.0.1	 * is not used since that will not work in HP-UX clusters and	 * this is no more expensive.	 */	bzero((voidp) &sin, sizeof(sin));	sin.sin_family = AF_INET;	sin.sin_addr = myipaddr;	if (port = hasmntval(&mnt, "port")) {		sin.sin_port = htons(port);	} else {		plog(XLOG_ERROR, "no port number specified for %s", dir);		return EINVAL;	}	/*	 * set mount args	 */	NFS_SA_DREF(nfs_args, &sin);	/*	 * Make a ``hostname'' string for the kernel	 */#ifndef HOSTNAMESZ#define	SHORT_MOUNT_NAME#endif /* HOSTNAMESZ */#ifdef SHORT_MOUNT_NAME	sprintf(fs_hostname, "amd:%d", foreground ? mypid : getppid());#else	sprintf(fs_hostname, "pid%d@%s:%s", foreground ? mypid : getppid(), hostname, dir);#endif /* SHORT_MOUNT_NAME */	nfs_args.hostname = fs_hostname;	nfs_args.flags |= NFSMNT_HOSTNAME;#ifdef HOSTNAMESZ	/*	 * Most kernels have a name length restriction.	 */	if (strlen(fs_hostname) >= HOSTNAMESZ)		strcpy(fs_hostname + HOSTNAMESZ - 3, "..");#endif /* HOSTNAMESZ */#ifdef NFSMNT_DUMBTIMR	nfs_args.flags |= NFSMNT_DUMBTIMR;	plog(XLOG_INFO, "defeating nfs window computation");#endif	/*	 * Parse a subset of the standard nfs options.  The	 * others are probably irrelevant for this application	 */	if (nfs_args.timeo = hasmntval(&mnt, "timeo"))		nfs_args.flags |= NFSMNT_TIMEO;	if (nfs_args.retrans = hasmntval(&mnt, "retrans"))		nfs_args.flags |= NFSMNT_RETRANS;#ifdef NFSMNT_BIODS	if (nfs_args.biods = hasmntval(&mnt, "biods"))		nfs_args.flags |= NFSMNT_BIODS;#endif /* NFSMNT_BIODS */#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)	/*	 * Don't cache attributes - they are changing under	 * the kernel's feet...	 */	nfs_args.acregmin = nfs_args.acregmax = 1;	nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;#endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */	/*	 * These two are constructed internally by the calling routine	 */	if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)		nfs_args.flags |= NFSMNT_SOFT;#ifdef MNTOPT_INTR	if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)		nfs_args.flags |= NFSMNT_INT;#endif /* MNTOPT_INTR */	flags = compute_mount_flags(&mnt);#ifdef ULTRIX_HACK	nfs_args.gfs_flags = flags;	flags &= M_RDONLY;	if (flags & M_RDONLY)		nfs_args.flags |= NFSMNT_RONLY;#endif /* ULTRIX_HACK */	return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);}static void afs_mkcacheref P((mntfs *mf));static void afs_mkcacheref(mf)mntfs *mf;{	/*	 * Build a new map cache for this node, or re-use	 * an existing cache for the same map.	 */	char *cache;	if (mf->mf_fo && mf->mf_fo->opt_cache)	  	cache = mf->mf_fo->opt_cache;	else	  	cache = "none";	mf->mf_private = (voidp) mapc_find(mf->mf_info, cache);	mf->mf_prfree = mapc_free;}/* * Mount the root... */static int root_mount P((am_node *mp));static int root_mount(mp)am_node *mp;{	mntfs *mf = mp->am_mnt;	mf->mf_mount = strealloc(mf->mf_mount, pid_fsname);	mf->mf_private = (voidp) mapc_find(mf->mf_info, "");	mf->mf_prfree = mapc_free;	return 0;}/* * Mount a sub-mount */static int afs_mount P((am_node *mp));static int afs_mount(mp)am_node *mp;{	mntfs *mf = mp->am_mnt;	/*	 * Pseudo-directories are used to provide some structure	 * to the automounted directories instead	 * of putting them all in the top-level automount directory.	 *	 * Here, just increment the parent's link count.	 */	mp->am_parent->am_fattr.nlink++;	/*	 * Info field of . means use parent's info field.	 * Historical - not documented.	 */	if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')		mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);	/*	 * Compute prefix:	 *	 * If there is an option prefix then use that else	 * If the parent had a prefix then use that with name	 *	of this node appended else	 * Use the name of this node.	 *	 * That means if you want no prefix you must say so	 * in the map.	 */	if (mf->mf_fo->opt_pref) {		/*		 * the prefix specified as an option		 */		mp->am_pref = strdup(mf->mf_fo->opt_pref);	} else {		/*		 * else the parent's prefix		 * followed by the name		 * followed by /		 */		char *ppref = mp->am_parent->am_pref;		if (ppref == 0)			ppref = "";		mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");	}	/*	 * Attach a map cache	 */	afs_mkcacheref(mf);	return 0;}/* * Mount the top-level */static int toplvl_mount P((am_node *mp));static int toplvl_mount(mp)am_node *mp;{	mntfs *mf = mp->am_mnt;	struct stat stb;	char opts[256];	int error;	char *mnttype;	/*	 * Mounting the automounter.	 * Make sure the mount directory exists, construct	 * the mount options and call the mount_toplvl routine.	 */	if (stat(mp->am_path, &stb) < 0) {		return errno;	} else if ((stb.st_mode & S_IFMT) != S_IFDIR) {		plog(XLOG_WARNING, "%s is not a directory", mp->am_path);		return ENOTDIR;	}	if (mf->mf_ops == &toplvl_ops) mnttype = "indirect";	else if (mf->mf_ops == &dfs_ops) mnttype = "direct";#ifdef HAS_UNION_FS	else if (mf->mf_ops == &union_ops) mnttype = "union";#endif	else mnttype = "auto";	/*	 * Construct some mount options	 */	sprintf(opts,#ifdef MNTOPT_INTR		"%s,%s,%s=%d,%s=%d,%s=%d,%s",		MNTOPT_INTR,#else		"%s,%s=%d,%s=%d,%s=%d,%s",#endif /* MNTOPT_INTR */		"rw",		"port", nfs_port,		"timeo", afs_timeo,		"retrans", afs_retrans,		mnttype);	error = mount_toplvl(mf->mf_mount, opts);	if (error) {		errno = error;		plog(XLOG_FATAL, "mount_toplvl: %m");		return error;	}	return 0;}static void toplvl_mounted P((mntfs *mf));static void toplvl_mounted(mf)mntfs *mf;{	afs_mkcacheref(mf);}#ifdef HAS_UNION_FS/* * Create a reference to a union'ed entry */static int create_union_node P((char *dir, voidp arg));static int create_union_node(dir, arg)char *dir;voidp arg;{	if (strcmp(dir, "/defaults") != 0) {		int error = 0;		(void) toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE);		if (error > 0) {			errno = error; /* XXX */			plog(XLOG_ERROR, "Could not mount %s: %m", dir);		}		return error;	}	return 0;}static void union_mounted P((mntfs *mf));static void union_mounted(mf)mntfs *mf;{	int i;		afs_mkcacheref(mf);	/*	 * Having made the union mount point,	 * populate all the entries...	 */	for (i = 0; i <= last_used_map; i++) {		am_node *mp = exported_ap[i];		if (mp && mp->am_mnt == mf) {			/* return value from create_union_node is ignored by mapc_keyiter */			(void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private,				(void (*)P((char*,void*))) create_union_node, mp);			break;		}	}#ifdef notdef	/*	 * would be nice to flush most of the cache, but we need to	 * keep the wildcard and /defaults entries...	 */	mapc_free(mf->mf_private);	mf->mf_private = (voidp) mapc_find(mf->mf_info, "inc");/*	mapc_add_kv(mf->mf_private, strdup("/defaults"),		strdup("type:=link;opts:=nounmount;sublink:=${key}")); */#endif}#endif /* HAS_UNION_FS *//* * Unmount an automount sub-node */static int afs_umount P((am_node *mp));static int afs_umount(mp)am_node *mp;{	return 0;}/* * Unmount a top-level automount node */static int toplvl_umount P((am_node *mp));static int toplvl_umount(mp)am_node *mp;{	int error;	struct stat stb;again:	/*	 * The lstat is needed if this mount is type=direct.	 * When that happens, the kernel cache gets confused	 * between the underlying type (dir) and the mounted	 * type (link) and so needs to be re-synced before	 * the unmount.  This is all because the unmount system	 * call follows links and so can't actually unmount	 * a link (stupid!).  It was noted that doing an ls -ld	 * of the mount point to see why things were not working	 * actually fixed the problem - so simulate an ls -ld here.	 */	if (lstat(mp->am_path, &stb) < 0) {#ifdef DEBUG		dlog("lstat(%s): %m", mp->am_path);#endif /* DEBUG */	}	error = UMOUNT_FS(mp->am_path);	if (error == EBUSY) {		plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);		sleep(1);	/* XXX */		goto again;	}	return error;}/* * Unmount an automount node */static void afs_umounted P((am_node *mp));static void afs_umounted(mp)am_node *mp;{	/*	 * If this is a pseudo-directory then just adjust the link count	 * in the parent, otherwise call the generic unmount routine	 */	if (mp->am_parent && mp->am_parent->am_parent)		--mp->am_parent->am_fattr.nlink;}/* * Mounting a file system may take a significant period of time.  The * problem is that if this is done in the main process thread then * the entire automounter could be blocked, possibly hanging lots of * processes on the system.  Instead we use a continuation scheme to * allow mounts to be attempted in a sub-process.  When the sub-process * exits we pick up the exit status (by convention a UN*X error number) * and continue in a notifier.  The notifier gets handed a data structure * and can then determine whether the mount was successful or not.  If * not, it updates the data structure and tries again until there are no * more ways to try the mount, or some other permanent error occurs. * In the mean time no RPC reply is sent, even after the mount is succesful. * We rely on the RPC retry mechanism to resend the lookup request which * can then be handled. */struct continuation {	char **ivec;		/* Current mount info */	am_node *mp;		/* Node we are trying to mount */	char *key;		/* Map key */	char *info;		/* Info string */	char **xivec;		/* Saved strsplit vector */	char *auto_opts;	/* Automount options */	am_opts fs_opts;	/* Filesystem options */	char *def_opts;		/* Default automount options */	int retry;		/* Try again? */	int tried;		/* Have we tried any yet? */	time_t start;		/* Time we started this mount */	int callout;		/* Callout identifier */};#define	IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING)/* * Discard an old continuation */static void free_continuation P((struct continuation *cp));static void free_continuation(cp)struct continuation *cp;{	if (cp->callout)		untimeout(cp->callout);	free((voidp) cp->key);	free((voidp) cp->xivec);	free((voidp) cp->info);	free((voidp) cp->auto_opts);	free((voidp) cp->def_opts);	free_opts(&cp->fs_opts);	free((voidp) cp);}static int afs_bgmount P((struct continuation*, int));/* * Discard the underlying mount point and replace * with a reference to an error filesystem. */static void assign_error_mntfs P((am_node *mp));static void assign_error_mntfs(mp)am_node *mp;{	if (mp->am_error > 0) {		/*		 * Save the old error code		 */		int error = mp->am_error;		if (error <= 0)			error = mp->am_mnt->mf_error;		/*		 * Discard the old filesystem		 */		free_mntfs(mp->am_mnt);		/*		 * Allocate a new error reference		 */		mp->am_mnt = new_mntfs();		/*		 * Put back the error code		 */		mp->am_mnt->mf_error = error;		mp->am_mnt->mf_flags |= MFF_ERROR;		/*		 * Zero the error in the mount point		 */		mp->am_error = 0;	}}/* * The continuation function.  This is called by * the task notifier when a background mount attempt

⌨️ 快捷键说明

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