📄 nfs_vnops.c
字号:
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 + -