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

📄 nfs_subr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
字号:
/*      @(#)nfs_subr.c 1.1 92/07/30 SMI      */#include <sys/param.h>#include "boot/systm.h"#include <sys/user.h>#include <sys/kernel.h>#include <sys/buf.h>#include <sys/vfs.h>#include "boot/vnode.h"#include <sys/proc.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/stat.h>#include <sys/uio.h>#include <net/if.h>#include <netinet/in.h>#include <rpc/types.h>#include <rpc/xdr.h>#include <rpc/auth.h>#include <rpc/clnt.h>#include "boot/nfs.h"#include <nfs/nfs_clnt.h>#include <nfs/rnode.h>#include <sun/consdev.h>#include <mon/sunromvec.h>#ifdef NFSDEBUGstatic int nfsdebug = 0;#endifextern struct vnodeops nfs_vnodeops;struct inode *iget();struct rnode *rfind();#undef uextern struct user u;/* * Client side utilities *//* * client side statistics */struct {	int	nclsleeps;		/* client handle waits */	int	nclgets;		/* client handle gets */	int	ncalls;			/* client requests */	int	nbadcalls;		/* rpc failures */	int	reqs[32];		/* count of each request */} clstat;#define MAXCLIENTS	6struct chtab {	int	ch_timesused;	bool_t	ch_inuse;	CLIENT	*ch_client;} chtable[MAXCLIENTS];int	clwanted = 0;CLIENT *clget(mi, cred)	struct mntinfo *mi;	struct ucred *cred;{	register struct chtab *ch;	int retrans;	/*	 * If soft mount and server is down just try once	 */	if (!mi->mi_hard && mi->mi_down) {		retrans = 1;	} else {		retrans = mi->mi_retrans;	}	/*	 * Find an unused handle or create one if not at limit yet.	 */	for (;;) {		clstat.nclgets++;		for (ch = chtable; ch < &chtable[MAXCLIENTS]; ch++) {			if (!ch->ch_inuse) {				ch->ch_inuse = TRUE;				if (ch->ch_client == NULL) {					ch->ch_client =					    clntkudp_create(&mi->mi_addr,					    NFS_PROGRAM, NFS_VERSION,					    retrans, cred);				} else {					clntkudp_init(ch->ch_client,					    &mi->mi_addr, retrans, cred);				}				if (ch->ch_client == NULL) {					panic("clget: null client");				}				ch->ch_timesused++;				return (ch->ch_client);			}		}		/*		 * If we got here there are no available handles		 */		clwanted++;		clstat.nclsleeps++;		(void) sleep((caddr_t)chtable, PRIBIO);	}}clfree(cl)	CLIENT *cl;{	register struct chtab *ch;	for (ch = chtable; ch < &chtable[MAXCLIENTS]; ch++) {		if (ch->ch_client == cl) {			ch->ch_inuse = FALSE;			break;		}	}	if (clwanted) {		clwanted = 0;		printf("clfree: wakeup\n");		wakeup((caddr_t)chtable);	}}#define	RPC_INTR	18char *rfsnames[] = {	"null", "getattr", "setattr", "unused", "lookup", "readlink", "read",	"unused", "write", "create", "remove", "rename", "link", "symlink",	"mkdir", "rmdir", "readdir", "fsstat" };/* * Back off for retransmission timeout, MAXTIMO is in 10ths of a sec */#define MAXTIMO	300#define backoff(tim)	((((tim) << 2) > MAXTIMO) ? MAXTIMO : ((tim) << 2))intrfscall(mi, which, xdrargs, argsp, xdrres, resp, cred)	register struct mntinfo *mi;	int	 which;	xdrproc_t xdrargs;	caddr_t	argsp;	xdrproc_t xdrres;	caddr_t	resp;	struct ucred *cred;{	CLIENT *client;	register enum clnt_stat status;	struct rpc_err rpcerr;	struct timeval wait;	struct ucred *newcred;	int timeo;	int user_told;	bool_t tryagain;#ifdef NFSDEBUG	dprint(nfsdebug, 6, "rfscall: %x, %d, %x, %x, %x, %x\n",	    mi, which, xdrargs, argsp, xdrres, resp);#endif	clstat.ncalls++;	clstat.reqs[which]++;	rpcerr.re_errno = 0;	newcred = NULL;	timeo = mi->mi_timeo;	user_told = 0;retry:	client = clget(mi, cred);	/*	 * If hard mounted fs, retry call forever unless hard error occurs	 */	do {		tryagain = FALSE;		wait.tv_sec = timeo / 10;		wait.tv_usec = 100000 * (timeo % 10);		status = CLNT_CALL(client, which, xdrargs, argsp,		    xdrres, resp, wait);		switch (status) {		case RPC_SUCCESS:			break;		/*		 * Unrecoverable errors: give up immediately		 */		case RPC_AUTHERROR:		case RPC_CANTENCODEARGS:		case RPC_CANTDECODERES:		case RPC_VERSMISMATCH:		case RPC_PROGVERSMISMATCH:		case RPC_CANTDECODEARGS:			break;		default:			if (mi->mi_hard) {				if (mi->mi_int && interrupted()) {					status = RPC_INTR;					rpcerr.re_status = RPC_SYSTEMERROR;					rpcerr.re_errno = EINTR;					tryagain = FALSE;					break;				} else {					tryagain = TRUE;					timeo = backoff(timeo);					if (!mi->mi_printed) {						mi->mi_printed = 1;	printf("status 0x%x\n", status);	printf("NFS server %s not responding still trying\n", mi->mi_hostname);					}#ifdef notdef					if (!user_told && u.u_ttyp &&					    u.u_ttyd != consdev &&					    u.u_ttyd != rconsdev) {						user_told = 1;	printf("status 0x%x\n", status);	printf("NFS server %s not responding still trying\n", mi->mi_hostname);					}#endif notdef				}			}		}	} while (tryagain);	if (status != RPC_SUCCESS) {		CLNT_GETERR(client, &rpcerr);		clstat.nbadcalls++;		mi->mi_down = 1;		printf("NFS %s failed for server %s: %s\n", rfsnames[which],			mi->mi_hostname, clnt_sperrno(status));#ifdef notdef		if (u.u_ttyp && u.u_ttyd != consdev && u.u_ttyd != rconsdev) {			printf("NFS %s failed for server %s: %s\n",				rfsnames[which], mi->mi_hostname,			  	clnt_sperrno(status)); 		}#endif notdef	} else if (resp && *(int *)resp == EACCES &&	    newcred == NULL && cred->cr_uid == 0 && cred->cr_ruid != 0) {		/*		 * Boy is this a kludge!  If the reply status is EACCES		 * it may be because we are root (no root net access).		 * Check the real uid, if it isn't root make that		 * the uid instead and retry the call.		 */		newcred = crdup(cred);		cred = newcred;		cred->cr_uid = cred->cr_ruid;		clfree(client);		goto retry;	} else if (mi->mi_hard) {		if (mi->mi_printed) {			printf("NFS server %s ok\n", mi->mi_hostname);			mi->mi_printed = 0;		}		if (user_told) {			printf("NFS server %s ok\n", mi->mi_hostname);		}	} else {		mi->mi_down = 0;	}	clfree(client);#ifdef NFSDEBUG	dprint(nfsdebug, 7, "rfscall: returning %d\n", rpcerr.re_errno);#endif	if (newcred) {		crfree(newcred);	}	return (rpcerr.re_errno);}/* * Check if this process got an interrupt from the keyboard while sleeping */intinterrupted() {	return(0);}nattr_to_vattr(na, vap)	register struct nfsfattr *na;	register struct vattr *vap;{	vap->va_type = (enum vtype)na->na_type;	vap->va_mode = na->na_mode;	vap->va_uid = na->na_uid;	vap->va_gid = na->na_gid;	vap->va_fsid = na->na_fsid;	vap->va_nodeid = na->na_nodeid;	vap->va_nlink = na->na_nlink;	vap->va_size = na->na_size;	vap->va_atime.tv_sec  = na->na_atime.tv_sec;	vap->va_atime.tv_usec = na->na_atime.tv_usec;	vap->va_mtime.tv_sec  = na->na_mtime.tv_sec;	vap->va_mtime.tv_usec = na->na_mtime.tv_usec;	vap->va_ctime.tv_sec  = na->na_ctime.tv_sec;	vap->va_ctime.tv_usec = na->na_ctime.tv_usec;	vap->va_rdev = na->na_rdev;	vap->va_blocks = na->na_blocks;	switch(na->na_type) {	case NFBLK:		vap->va_blocksize = BLKDEV_IOSIZE;		break;	case NFCHR:		vap->va_blocksize = MAXBSIZE;		break;	default:		vap->va_blocksize = na->na_blocksize;		break;	}	/*	 * This bit of ugliness is a *TEMPORARY* hack to preserve the	 * over-the-wire protocols for named-pipe vnodes.  It remaps the	 * special over-the-wire type to the VFIFO type. (see note in nfs.h)	 *	 * BUYER BEWARE:	 *  If you are porting the NFS to a non-SUN server, you probably	 *  don't want to include the following block of code.  The	 *  over-the-wire special file types will be changing with the	 *  NFS Protocol Revision.	 */	if (NA_ISFIFO(na)) {		vap->va_type = VFIFO;		vap->va_mode = (vap->va_mode & ~S_IFMT) | S_IFIFO;		vap->va_rdev = 0;		vap->va_blocksize = na->na_blocksize;	}}setdiropargs(da, nm, dvp)	struct nfsdiropargs *da;	char *nm;	struct vnode *dvp;{#ifdef NFSDEBUG	dprint(nfsdebug, 7,		 "setdiropargs(da 0x%x nm 0x%x dvp 0x%x)\n", da, nm, dvp);#endif	/* NFSDEBUG */	da->da_fhandle = *vtofh(dvp);	da->da_name = nm;}struct rnode *rpfreelist = NULL;int rreuse, rnew, ractive;/* * return a vnode for the given fhandle. * If no rnode exists for this fhandle create one and put it * in a table hashed by fh_fsid and fs_fid.  If the rnode for * this fhandle is already in the table return it (ref count is * incremented by rfind.  The rnode will be flushed from the * table when nfs_inactive calls runsave. */struct vnode *makenfsnode(fh, attr, vfsp)	fhandle_t *fh;	struct nfsfattr *attr;	struct vfs *vfsp;{	register struct rnode *rp;	char newnode = 0;#ifdef NFSDEBUG	dprint(nfsdebug, 3, "makenfsnode(fh 0x%x attr 0x%x vfsp 0x%x)\n",		fh, attr, vfsp);#endif	/* NFSDEBUG */	if ((rp = rfind(fh, vfsp)) == NULL) {		if (rpfreelist) {			rp = rpfreelist;			rpfreelist = rp->r_freef;			rreuse++;		} else {			rp = (struct rnode *)kmem_alloc((u_int)sizeof(*rp));			rnew++;		}		bzero((caddr_t)rp, sizeof(*rp));		rp->r_fh = *fh;		rtov(rp)->v_count = 1;		rtov(rp)->v_op = &nfs_vnodeops;		if (attr) {			rtov(rp)->v_type = n2v_type(attr);			rtov(rp)->v_rdev = n2v_rdev(attr);		}		rtov(rp)->v_data = (caddr_t)rp;		rtov(rp)->v_vfsp = vfsp;		rsave(rp);		((struct mntinfo *)(vfsp->vfs_data))->mi_refct++;		newnode++;	}	if (attr) {		nfs_attrcache(rtov(rp), attr);	}	return (rtov(rp));}/* * Rnode lookup stuff. * These routines maintain a table of rnodes hashed by fhandle so * that the rnode for an fhandle can be found if it already exists. * NOTE: RTABLESIZE must be a power of 2 for rtablehash to work! */#define	RTABLESIZE	16#define	rtablehash(fh) \    ((fh->fh_data[2] ^ fh->fh_data[5] ^ fh->fh_data[15]) & (RTABLESIZE-1))struct rnode *rtable[RTABLESIZE];/* * Put a rnode in the hash table */rsave(rp)	struct rnode *rp;{	rp->r_freef = rtable[rtablehash(rtofh(rp))];	rtable[rtablehash(rtofh(rp))] = rp;}/* * Remove a rnode from the hash table */runsave(rp)	struct rnode *rp;{	struct rnode *rt;	struct rnode *rtprev = NULL;	 	rt = rtable[rtablehash(rtofh(rp))]; 	while (rt != NULL) { 		if (rt == rp) { 			if (rtprev == NULL) {				rtable[rtablehash(rtofh(rp))] = rt->r_freef;			} else {				rtprev->r_freef = rt->r_freef;			}			return; 		}			rtprev = rt;		rt = rt->r_freef;	}	}/* * Put an rnode on the free list and take it out if * the hash table. */rfree(rp)	register struct rnode *rp;{	runsave(rp);	rp->r_freef = rpfreelist;	rpfreelist = rp;}/* * Lookup a rnode by fhandle */struct rnode *rfind(fh, vfsp)	fhandle_t *fh;	struct vfs *vfsp;{	register struct rnode *rt;#ifdef NFSDEBUG	dprint(nfsdebug, 3, "rfind(fh 0x%x vfsp 0x%x)\n", fh, vfsp);#endif	/* NFSDEBUG */	 	rt = rtable[rtablehash(fh)]; 	while (rt != NULL) { 		if (bcmp((caddr_t)rtofh(rt), (caddr_t)fh, sizeof(*fh)) == 0 &&		    vfsp == rtov(rt)->v_vfsp) { 			rtov(rt)->v_count++; 			ractive++;			return (rt); 		}			rt = rt->r_freef;	}	#ifdef NFSDEBUG	dprint(nfsdebug, 3, "rfind: NULL\n");#endif	/* NFSDEBUG */	return (NULL);}/* * General utilities *//* * Returns the prefered transfer size in bytes based on * what network interfaces are available. */nfstsize(){	register struct ifnet *ifp;	for (ifp = ifnet; ifp; ifp = ifp->if_next) {		if (ifp->if_name[0] == 'e' && ifp->if_name[1] == 'c') {			return (ECTSIZE);		}	}#ifdef NFSDEBUG	dprint(nfsdebug, 3, "nfstsize: %d\n", IETSIZE);#endif	return (IETSIZE);}vattr_to_nattr(vap, na)        register struct vattr *vap;        register struct nfsfattr *na;{#ifdef NFSDEBUG	dprint(nfsdebug, 3, "vattr_to_nattr(vap 0x%x na 0x%x)\n",		vap, na);#endif	/* NFSDEBUG */        na->na_type = (enum nfsftype)vap->va_type;        na->na_mode = vap->va_mode;        na->na_uid = vap->va_uid;        na->na_gid = vap->va_gid;        na->na_fsid = vap->va_fsid;        na->na_nodeid = vap->va_nodeid;        na->na_nlink = vap->va_nlink;        na->na_size = vap->va_size;        na->na_atime.tv_sec  = vap->va_atime.tv_sec;        na->na_atime.tv_usec = vap->va_atime.tv_usec;        na->na_mtime.tv_sec  = vap->va_mtime.tv_sec;        na->na_mtime.tv_usec = vap->va_mtime.tv_usec;        na->na_ctime.tv_sec  = vap->va_ctime.tv_sec;        na->na_ctime.tv_usec = vap->va_ctime.tv_usec;        na->na_rdev = vap->va_rdev;        na->na_blocks = vap->va_blocks;        na->na_blocksize = vap->va_blocksize;}

⌨️ 快捷键说明

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