📄 nfs_serv.c
字号:
/* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * 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. * * @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94 *//* * nfs version 2 server calls to vnode ops * - these routines generally have 3 phases * 1 - break down and validate rpc request in mbuf list * 2 - do the vnode ops for the request * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) * 3 - build the rpc reply in an mbuf list * nb: * - do not mix the phases, since the nfsm_?? macros can return failures * on a bad rpc or similar and do not do any vrele() or vput()'s * * - the nfsm_reply() macro generates an nfs rpc reply with the nfs * error number iff error != 0 whereas * returning an error from the server function implies a fatal error * such as a badly constructed rpc request that should be dropped without * a reply. */#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/file.h>#include <sys/namei.h>#include <sys/vnode.h>#include <sys/mount.h>#include <sys/mbuf.h>#include <sys/dirent.h>#include <sys/stat.h>#include <vm/vm.h>#include <nfs/nfsv2.h>#include <nfs/rpcv2.h>#include <nfs/nfs.h>#include <nfs/xdr_subs.h>#include <nfs/nfsm_subs.h>#include <nfs/nqnfs.h>/* Defs */#define TRUE 1#define FALSE 0/* Global vars */extern u_long nfs_procids[NFS_NPROCS];extern u_long nfs_xdrneg1;extern u_long nfs_false, nfs_true;nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };/* * nqnfs access service */nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache, mode = 0; char *cp2; struct mbuf *mb, *mreq; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); if (*tl++ == nfs_true) mode |= VREAD; if (*tl++ == nfs_true) mode |= VWRITE; if (*tl == nfs_true) mode |= VEXEC; error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp); vput(vp); nfsm_reply(0); nfsm_srvdone;}/* * nfs getattr service */nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ register struct nfsv2_fattr *fp; struct vattr va; register struct vattr *vap = &va; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache; char *cp2; struct mbuf *mb, *mb2, *mreq; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); nqsrv_getl(vp, NQL_READ); error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); vput(vp); nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_srvfillattr; nfsm_srvdone;}/* * nfs setattr service */nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ struct vattr va; register struct vattr *vap = &va; register struct nfsv2_sattr *sp; register struct nfsv2_fattr *fp; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache; char *cp2; struct mbuf *mb, *mb2, *mreq; u_quad_t frev, frev2; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); nqsrv_getl(vp, NQL_WRITE); VATTR_NULL(vap); /* * Nah nah nah nah na nah * There is a bug in the Sun client that puts 0xffff in the mode * field of sattr when it should put in 0xffffffff. The u_short * doesn't sign extend. * --> check the low order 2 bytes for 0xffff */ if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) vap->va_mode = nfstov_mode(sp->sa_mode); if (sp->sa_uid != nfs_xdrneg1) vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); if (sp->sa_gid != nfs_xdrneg1) vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); if (nfsd->nd_nqlflag == NQL_NOVAL) { if (sp->sa_nfssize != nfs_xdrneg1) vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize); if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) {#ifdef notyet fxdr_nfstime(&sp->sa_nfsatime, &vap->va_atime);#else vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec); vap->va_atime.ts_nsec = 0;#endif } if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1) fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime); } else { fxdr_hyper(&sp->sa_nqsize, &vap->va_size); fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime); fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime); vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags); } /* * If the size is being changed write acces is required, otherwise * just check for a read only file system. */ if (vap->va_size == ((u_quad_t)((quad_t) -1))) { if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { error = EROFS; goto out; } } else { if (vp->v_type == VDIR) { error = EISDIR; goto out; } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) goto out; } if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { vput(vp); nfsm_reply(0); } error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);out: vput(vp); nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED); nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_srvfillattr; if (nfsd->nd_nqlflag != NQL_NOVAL) { nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); txdr_hyper(&frev2, tl); } nfsm_srvdone;}/* * nfs lookup rpc */nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ register struct nfsv2_fattr *fp; struct nameidata nd; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; register caddr_t cp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, cache, duration2, cache2, len; char *cp2; struct mbuf *mb, *mb2, *mreq; struct vattr va, *vap = &va; u_quad_t frev, frev2; fhp = &nfh.fh_generic; duration2 = 0; if (nfsd->nd_nqlflag != NQL_NOVAL) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); duration2 = fxdr_unsigned(int, *tl); } nfsm_srvmtofh(fhp); nfsm_srvstrsiz(len, NFS_MAXNAMLEN); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) nfsm_reply(0); nqsrv_getl(nd.ni_startdir, NQL_READ); vrele(nd.ni_startdir); FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); vp = nd.ni_vp; bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { vput(vp); nfsm_reply(0); } if (duration2) (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd, nam, &cache2, &frev2, cred); error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); vput(vp); nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED); if (nfsd->nd_nqlflag != NQL_NOVAL) { if (duration2) { nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); *tl++ = txdr_unsigned(NQL_READ); *tl++ = txdr_unsigned(cache2); *tl++ = txdr_unsigned(duration2); txdr_hyper(&frev2, tl); } else { nfsm_build(tl, u_long *, NFSX_UNSIGNED); *tl = 0; } } nfsm_srvfhtom(fhp); nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_srvfillattr; nfsm_srvdone;}/* * nfs readlink service */nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; register struct iovec *ivp = iv; register struct mbuf *mp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache, i, tlen, len; char *cp2; struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); len = 0; i = 0; while (len < NFS_MAXPATHLEN) { MGET(mp, M_WAIT, MT_DATA); MCLGET(mp, M_WAIT); mp->m_len = NFSMSIZ(mp); if (len == 0) mp3 = mp2 = mp; else { mp2->m_next = mp; mp2 = mp; } if ((len+mp->m_len) > NFS_MAXPATHLEN) { mp->m_len = NFS_MAXPATHLEN-len; len = NFS_MAXPATHLEN; } else len += mp->m_len; ivp->iov_base = mtod(mp, caddr_t); ivp->iov_len = mp->m_len; i++; ivp++; } uiop->uio_iov = iv; uiop->uio_iovcnt = i; uiop->uio_offset = 0; uiop->uio_resid = len; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_procp = (struct proc *)0; if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { m_freem(mp3); nfsm_reply(0); } if (vp->v_type != VLNK) { error = EINVAL; goto out; } nqsrv_getl(vp, NQL_READ); error = VOP_READLINK(vp, uiop, cred);out: vput(vp); if (error) m_freem(mp3); nfsm_reply(NFSX_UNSIGNED); if (uiop->uio_resid > 0) { len -= uiop->uio_resid; tlen = nfsm_rndup(len); nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); } nfsm_build(tl, u_long *, NFSX_UNSIGNED); *tl = txdr_unsigned(len); mb->m_next = mp3; nfsm_srvdone;}/* * nfs read service */nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ register struct iovec *iv; struct iovec *iv2; register struct mbuf *m; register struct nfsv2_fattr *fp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; char *cp2; struct mbuf *mb, *mb2, *mreq; struct mbuf *m2; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; struct vattr va, *vap = &va; off_t off; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (nfsd->nd_nqlflag == NQL_NOVAL) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); off = (off_t)fxdr_unsigned(u_long, *tl); } else { nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); fxdr_hyper(tl, &off); } nfsm_srvstrsiz(cnt, NFS_MAXDATA); if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); if (vp->v_type != VREG) { error = (vp->v_type == VDIR) ? EISDIR : EACCES; vput(vp); nfsm_reply(0); } nqsrv_getl(vp, NQL_READ); if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) && (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) { vput(vp); nfsm_reply(0); } if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { vput(vp); nfsm_reply(0); } if (off >= vap->va_size) cnt = 0; else if ((off + cnt) > vap->va_size) cnt = nfsm_rndup(vap->va_size - off); nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -