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

📄 nfs_vnops.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		vrele(dvp);		vrele(dvp);		FREE(cnp->cn_pnbuf, M_NAMEI);		return (EINVAL);	}	nfsstats.rpccnt[NFSPROC_RMDIR]++;	nfsm_reqhead(dvp, NFSPROC_RMDIR,		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));	nfsm_fhtom(dvp);	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);	nfsm_reqdone;	FREE(cnp->cn_pnbuf, M_NAMEI);	VTONFS(dvp)->n_flag |= NMODIFIED;	VTONFS(dvp)->n_attrstamp = 0;	cache_purge(dvp);	cache_purge(vp);	vrele(vp);	vrele(dvp);	/*	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.	 */	if (error == ENOENT)		error = 0;	return (error);}/* * nfs readdir call * Although cookie is defined as opaque, I translate it to/from net byte * order so that it looks more sensible. This appears consistent with the * Ultrix implementation of NFS. */intnfs_readdir(ap)	struct vop_readdir_args /* {		struct vnode *a_vp;		struct uio *a_uio;		struct ucred *a_cred;	} */ *ap;{	register struct vnode *vp = ap->a_vp;	register struct nfsnode *np = VTONFS(vp);	register struct uio *uio = ap->a_uio;	int tresid, error;	struct vattr vattr;	if (vp->v_type != VDIR)		return (EPERM);	/*	 * First, check for hit on the EOF offset cache	 */	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&	    (np->n_flag & NMODIFIED) == 0) {		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {				nfsstats.direofcache_hits++;				return (0);			}		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&			np->n_mtime == vattr.va_mtime.ts_sec) {			nfsstats.direofcache_hits++;			return (0);		}	}	/*	 * Call nfs_bioread() to do the real work.	 */	tresid = uio->uio_resid;	error = nfs_bioread(vp, uio, 0, ap->a_cred);	if (!error && uio->uio_resid == tresid)		nfsstats.direofcache_misses++;	return (error);}/* * Readdir rpc call. * Called from below the buffer cache by nfs_doio(). */intnfs_readdirrpc(vp, uiop, cred)	register struct vnode *vp;	struct uio *uiop;	struct ucred *cred;{	register long len;	register struct dirent *dp;	register u_long *tl;	register caddr_t cp;	register long t1;	long tlen, lastlen;	caddr_t bpos, dpos, cp2;	int error = 0;	struct mbuf *mreq, *mrep, *md, *mb, *mb2;	struct mbuf *md2;	caddr_t dpos2;	int siz;	int more_dirs = 1;	u_long off, savoff;	struct dirent *savdp;	struct nfsmount *nmp;	struct nfsnode *np = VTONFS(vp);	long tresid;	nmp = VFSTONFS(vp->v_mount);	tresid = uiop->uio_resid;	/*	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.	 * The stopping criteria is EOF or buffer full.	 */	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {		nfsstats.rpccnt[NFSPROC_READDIR]++;		nfsm_reqhead(vp, NFSPROC_READDIR,			NFSX_FH + 2 * NFSX_UNSIGNED);		nfsm_fhtom(vp);		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);		off = (u_long)uiop->uio_offset;		*tl++ = txdr_unsigned(off);		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);		siz = 0;		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);		more_dirs = fxdr_unsigned(int, *tl);			/* Save the position so that we can do nfsm_mtouio() later */		dpos2 = dpos;		md2 = md;			/* loop thru the dir entries, doctoring them to 4bsd form */#ifdef lint		dp = (struct dirent *)0;#endif /* lint */		while (more_dirs && siz < uiop->uio_resid) {			savoff = off;		/* Hold onto offset and dp */			savdp = dp;			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);			dp = (struct dirent *)tl;			dp->d_fileno = fxdr_unsigned(u_long, *tl++);			len = fxdr_unsigned(int, *tl);			if (len <= 0 || len > NFS_MAXNAMLEN) {				error = EBADRPC;				m_freem(mrep);				goto nfsmout;			}			dp->d_namlen = (u_char)len;			dp->d_type = DT_UNKNOWN;			nfsm_adv(len);		/* Point past name */			tlen = nfsm_rndup(len);			/*			 * This should not be necessary, but some servers have			 * broken XDR such that these bytes are not null filled.			 */			if (tlen != len) {				*dpos = '\0';	/* Null-terminate */				nfsm_adv(tlen - len);				len = tlen;			}			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);			off = fxdr_unsigned(u_long, *tl);			*tl++ = 0;	/* Ensures null termination of name */			more_dirs = fxdr_unsigned(int, *tl);			dp->d_reclen = len + 4 * NFSX_UNSIGNED;			siz += dp->d_reclen;		}		/*		 * If at end of rpc data, get the eof boolean		 */		if (!more_dirs) {			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);			more_dirs = (fxdr_unsigned(int, *tl) == 0);			/*			 * If at EOF, cache directory offset			 */			if (!more_dirs)				np->n_direofoffset = off;		}		/*		 * If there is too much to fit in the data buffer, use savoff and		 * savdp to trim off the last record.		 * --> we are not at eof		 */		if (siz > uiop->uio_resid) {			off = savoff;			siz -= dp->d_reclen;			dp = savdp;			more_dirs = 0;	/* Paranoia */		}		if (siz > 0) {			lastlen = dp->d_reclen;			md = md2;			dpos = dpos2;			nfsm_mtouio(uiop, siz);			uiop->uio_offset = (off_t)off;		} else			more_dirs = 0;	/* Ugh, never happens, but in case.. */		m_freem(mrep);	}	/*	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ	 * by increasing d_reclen for the last record.	 */	if (uiop->uio_resid < tresid) {		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);		if (len > 0) {			dp = (struct dirent *)				(uiop->uio_iov->iov_base - lastlen);			dp->d_reclen += len;			uiop->uio_iov->iov_base += len;			uiop->uio_iov->iov_len -= len;			uiop->uio_resid -= len;		}	}nfsmout:	return (error);}/* * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc(). */intnfs_readdirlookrpc(vp, uiop, cred)	struct vnode *vp;	register struct uio *uiop;	struct ucred *cred;{	register int len;	register struct dirent *dp;	register u_long *tl;	register caddr_t cp;	register long t1;	caddr_t bpos, dpos, cp2;	struct mbuf *mreq, *mrep, *md, *mb, *mb2;	struct nameidata nami, *ndp = &nami;	struct componentname *cnp = &ndp->ni_cnd;	u_long off, endoff, fileno;	time_t reqtime, ltime;	struct nfsmount *nmp;	struct nfsnode *np;	struct vnode *newvp;	nfsv2fh_t *fhp;	u_quad_t frev;	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;	int cachable;	if (uiop->uio_iovcnt != 1)		panic("nfs rdirlook");	nmp = VFSTONFS(vp->v_mount);	tresid = uiop->uio_resid;	ndp->ni_dvp = vp;	newvp = NULLVP;	/*	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.	 * The stopping criteria is EOF or buffer full.	 */	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,			NFSX_FH + 3 * NFSX_UNSIGNED);		nfsm_fhtom(vp); 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);		off = (u_long)uiop->uio_offset;		*tl++ = txdr_unsigned(off);		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)			*tl = txdr_unsigned(nmp->nm_leaseterm);		else			*tl = 0;		reqtime = time.tv_sec;		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);		more_dirs = fxdr_unsigned(int, *tl);			/* loop thru the dir entries, doctoring them to 4bsd form */		bigenough = 1;		while (more_dirs && bigenough) {			doit = 1;			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {				cachable = fxdr_unsigned(int, *tl++);				ltime = reqtime + fxdr_unsigned(int, *tl++);				fxdr_hyper(tl, &frev);			}			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {				VREF(vp);				newvp = vp;				np = VTONFS(vp);			} else {				if (error = nfs_nget(vp->v_mount, fhp, &np))					doit = 0;				newvp = NFSTOV(np);			}			if (error = nfs_loadattrcache(&newvp, &md, &dpos,				(struct vattr *)0))				doit = 0;			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);			fileno = fxdr_unsigned(u_long, *tl++);			len = fxdr_unsigned(int, *tl);			if (len <= 0 || len > NFS_MAXNAMLEN) {				error = EBADRPC;				m_freem(mrep);				goto nfsmout;			}			tlen = (len + 4) & ~0x3;			if ((tlen + DIRHDSIZ) > uiop->uio_resid)				bigenough = 0;			if (bigenough && doit) {				dp = (struct dirent *)uiop->uio_iov->iov_base;				dp->d_fileno = fileno;				dp->d_namlen = len;				dp->d_reclen = tlen + DIRHDSIZ;				dp->d_type =				    IFTODT(VTTOIF(np->n_vattr.va_type));				uiop->uio_resid -= DIRHDSIZ;				uiop->uio_iov->iov_base += DIRHDSIZ;				uiop->uio_iov->iov_len -= DIRHDSIZ;				cnp->cn_nameptr = uiop->uio_iov->iov_base;				cnp->cn_namelen = len;				ndp->ni_vp = newvp;				nfsm_mtouio(uiop, len);				cp = uiop->uio_iov->iov_base;				tlen -= len;				for (i = 0; i < tlen; i++)					*cp++ = '\0';				uiop->uio_iov->iov_base += tlen;				uiop->uio_iov->iov_len -= tlen;				uiop->uio_resid -= tlen;				cnp->cn_hash = 0;				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)					cnp->cn_hash += (unsigned char)*cp * i;				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&					ltime > time.tv_sec)					nqnfs_clientlease(nmp, np, NQL_READ,						cachable, ltime, frev);				if (cnp->cn_namelen <= NCHNAMLEN)				    cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);			} else {				nfsm_adv(nfsm_rndup(len));			}			if (newvp != NULLVP) {				vrele(newvp);				newvp = NULLVP;			}			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);			if (bigenough)				endoff = off = fxdr_unsigned(u_long, *tl++);			else				endoff = fxdr_unsigned(u_long, *tl++);			more_dirs = fxdr_unsigned(int, *tl);		}		/*		 * If at end of rpc data, get the eof boolean		 */		if (!more_dirs) {			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);			more_dirs = (fxdr_unsigned(int, *tl) == 0);			/*			 * If at EOF, cache directory offset			 */			if (!more_dirs)				VTONFS(vp)->n_direofoffset = endoff;		}		if (uiop->uio_resid < tresid)			uiop->uio_offset = (off_t)off;		else			more_dirs = 0;		m_freem(mrep);	}	/*	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ	 * by increasing d_reclen for the last record.	 */	if (uiop->uio_resid < tresid) {		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);		if (len > 0) {			dp->d_reclen += len;			uiop->uio_iov->iov_base += len;			uiop->uio_iov->iov_len -= len;			uiop->uio_resid -= len;		}	}nfsmout:	if (newvp != NULLVP)		vrele(newvp);	return (error);}static char hextoasc[] = "0123456789abcdef";/* * Silly rename. To make the NFS filesystem that is stateless look a little * more like the "ufs" a remove of an active vnode is translated to a rename * to a funny looking filename that is removed by nfs_inactive on the * nfsnode. There is the potential for another process on a different client * to create the same funny name between the nfs_lookitup() fails and the * nfs_rename() completes, but... */intnfs_sillyrename(dvp, vp, cnp)	struct vnode *dvp, *vp;	struct componentname *cnp;{	register struct nfsnode *np;	register struct sillyrename *sp;	int error;	short pid;	cache_purge(dvp);	np = VTONFS(vp);#ifdef SILLYSEPARATE	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),		M_NFSREQ, M_WAITOK);#else	sp = &np->n_silly;#endif	sp->s_cred = crdup(cnp->cn_cred);	sp->s_dvp = dvp;	VREF(dvp);	/* Fudge together a funny name */	pid = cnp->cn_proc->p_pid;	bcopy(".nfsAxxxx4.4", sp->s_name, 13);	sp->s_namlen = 12;	sp->s_name[8] = hextoasc[pid & 0xf];	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];	/* Try lookitups until we get one that isn't there */	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {		sp->s_name[4]++;		if (sp->s_name[4] > 'z') {			error = EINVAL;			goto bad;		}	}	if (error = nfs_renameit(dvp, cnp, sp))		goto bad;	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);	np->n_sillyrename = sp;	return (0);bad:	vrele(sp->s_dvp);	crfree(sp->s_cred);#ifdef SILLYSEPARATE	free((caddr_t)sp, M_NFSREQ);#endif	return (error);}/* * Look up a file name for silly rename stuff. * Just like nfs_lookup() except that it doesn't load returned values * into the nfsnode table. * If fhp != NULL it copies the returned file handle out */intnfs_lookitup(sp, fhp, procp)	register struct sillyrename *sp;	nfsv2fh_t *fhp;	struct proc *procp;{	register struct vnode *vp = sp->s_dvp;	register u_long *tl;	register caddr_t cp;	register long t1, t2;	caddr_t bpos, dpos, cp2;	int error = 0, isnq;	struct mbuf *mreq, *mrep, *md, *mb, *mb2;	long len;	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);	nfsstats.rpccnt[NFSPROC_LOOKUP]++;	len = sp->s_namlen;	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));	if (isnq) {		nfsm_build(tl, u_long *, NFSX_UNSIGNED);		*tl = 0;	}	nfsm_fhtom(vp);	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);	if (fhp != NULL) {		if (isnq)			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);		nfsm_dissect(cp, caddr_t, NFSX_FH);		bcopy(cp, (caddr_t)fhp, NFSX_FH);	}	nfsm_reqdone;	return (error);}/* * Kludge City..

⌨️ 快捷键说明

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