Annotation of sys/nfs/nfs_serv.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: nfs_serv.c,v 1.40 2006/04/02 18:35:11 otto Exp $ */
! 2: /* $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to Berkeley by
! 9: * Rick Macklem at The University of Guelph.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
! 36: */
! 37:
! 38: /*
! 39: * nfs version 2 and 3 server calls to vnode ops
! 40: * - these routines generally have 3 phases
! 41: * 1 - break down and validate rpc request in mbuf list
! 42: * 2 - do the vnode ops for the request
! 43: * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
! 44: * 3 - build the rpc reply in an mbuf list
! 45: * nb:
! 46: * - do not mix the phases, since the nfsm_?? macros can return failures
! 47: * on a bad rpc or similar and do not do any vrele() or vput()'s
! 48: *
! 49: * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
! 50: * error number iff error != 0 whereas
! 51: * returning an error from the server function implies a fatal error
! 52: * such as a badly constructed rpc request that should be dropped without
! 53: * a reply.
! 54: * For Version 3, nfsm_reply() does not return for the error case, since
! 55: * most version 3 rpcs return more than the status for error cases.
! 56: */
! 57:
! 58: #include <sys/param.h>
! 59: #include <sys/systm.h>
! 60: #include <sys/proc.h>
! 61: #include <sys/file.h>
! 62: #include <sys/namei.h>
! 63: #include <sys/vnode.h>
! 64: #include <sys/mount.h>
! 65: #include <sys/socket.h>
! 66: #include <sys/socketvar.h>
! 67: #include <sys/mbuf.h>
! 68: #include <sys/dirent.h>
! 69: #include <sys/stat.h>
! 70: #include <sys/kernel.h>
! 71: #include <sys/pool.h>
! 72: #include <ufs/ufs/dir.h>
! 73:
! 74: #include <uvm/uvm_extern.h>
! 75:
! 76: #include <nfs/nfsproto.h>
! 77: #include <nfs/rpcv2.h>
! 78: #include <nfs/nfs.h>
! 79: #include <nfs/xdr_subs.h>
! 80: #include <nfs/nfsm_subs.h>
! 81: #include <nfs/nfs_var.h>
! 82:
! 83: /* Global vars */
! 84: extern u_int32_t nfs_xdrneg1;
! 85: extern u_int32_t nfs_false, nfs_true;
! 86: extern enum vtype nv3tov_type[8];
! 87: extern struct nfsstats nfsstats;
! 88: extern nfstype nfsv2_type[9];
! 89: extern nfstype nfsv3_type[9];
! 90: int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
! 91:
! 92: /*
! 93: * nfs v3 access service
! 94: */
! 95: int
! 96: nfsrv3_access(nfsd, slp, procp, mrq)
! 97: struct nfsrv_descript *nfsd;
! 98: struct nfssvc_sock *slp;
! 99: struct proc *procp;
! 100: struct mbuf **mrq;
! 101: {
! 102: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 103: struct mbuf *nam = nfsd->nd_nam;
! 104: caddr_t dpos = nfsd->nd_dpos;
! 105: struct ucred *cred = &nfsd->nd_cr;
! 106: struct vnode *vp;
! 107: nfsfh_t nfh;
! 108: fhandle_t *fhp;
! 109: u_int32_t *tl;
! 110: int32_t t1;
! 111: caddr_t bpos;
! 112: int error = 0, rdonly, getret;
! 113: char *cp2;
! 114: struct mbuf *mb, *mreq, *mb2;
! 115: struct vattr va;
! 116: u_long testmode, nfsmode;
! 117: u_quad_t frev;
! 118:
! 119: fhp = &nfh.fh_generic;
! 120: nfsm_srvmtofh(fhp);
! 121: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 122: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
! 123: (nfsd->nd_flag & ND_KERBAUTH));
! 124: if (error) {
! 125: nfsm_reply(NFSX_UNSIGNED);
! 126: nfsm_srvpostop_attr(1, (struct vattr *)0);
! 127: return (0);
! 128: }
! 129: nfsmode = fxdr_unsigned(u_int32_t, *tl);
! 130: if ((nfsmode & NFSV3ACCESS_READ) &&
! 131: nfsrv_access(vp, VREAD, cred, rdonly, procp, 0))
! 132: nfsmode &= ~NFSV3ACCESS_READ;
! 133: if (vp->v_type == VDIR)
! 134: testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
! 135: NFSV3ACCESS_DELETE);
! 136: else
! 137: testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
! 138: if ((nfsmode & testmode) &&
! 139: nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0))
! 140: nfsmode &= ~testmode;
! 141: if (vp->v_type == VDIR)
! 142: testmode = NFSV3ACCESS_LOOKUP;
! 143: else
! 144: testmode = NFSV3ACCESS_EXECUTE;
! 145: if ((nfsmode & testmode) &&
! 146: nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0))
! 147: nfsmode &= ~testmode;
! 148: getret = VOP_GETATTR(vp, &va, cred, procp);
! 149: vput(vp);
! 150: nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
! 151: nfsm_srvpostop_attr(getret, &va);
! 152: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 153: *tl = txdr_unsigned(nfsmode);
! 154: nfsm_srvdone;
! 155: }
! 156:
! 157: /*
! 158: * nfs getattr service
! 159: */
! 160: int
! 161: nfsrv_getattr(nfsd, slp, procp, mrq)
! 162: struct nfsrv_descript *nfsd;
! 163: struct nfssvc_sock *slp;
! 164: struct proc *procp;
! 165: struct mbuf **mrq;
! 166: {
! 167: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 168: struct mbuf *nam = nfsd->nd_nam;
! 169: caddr_t dpos = nfsd->nd_dpos;
! 170: struct ucred *cred = &nfsd->nd_cr;
! 171: struct nfs_fattr *fp;
! 172: struct vattr va;
! 173: struct vnode *vp;
! 174: nfsfh_t nfh;
! 175: fhandle_t *fhp;
! 176: u_int32_t *tl;
! 177: int32_t t1;
! 178: caddr_t bpos;
! 179: int error = 0, rdonly;
! 180: char *cp2;
! 181: struct mbuf *mb, *mb2, *mreq;
! 182: u_quad_t frev;
! 183:
! 184: fhp = &nfh.fh_generic;
! 185: nfsm_srvmtofh(fhp);
! 186: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
! 187: (nfsd->nd_flag & ND_KERBAUTH));
! 188: if (error) {
! 189: nfsm_reply(0);
! 190: return (0);
! 191: }
! 192: error = VOP_GETATTR(vp, &va, cred, procp);
! 193: vput(vp);
! 194: nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
! 195: if (error)
! 196: return (0);
! 197: nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
! 198: nfsm_srvfillattr(&va, fp);
! 199: nfsm_srvdone;
! 200: }
! 201:
! 202: /*
! 203: * nfs setattr service
! 204: */
! 205: int
! 206: nfsrv_setattr(nfsd, slp, procp, mrq)
! 207: struct nfsrv_descript *nfsd;
! 208: struct nfssvc_sock *slp;
! 209: struct proc *procp;
! 210: struct mbuf **mrq;
! 211: {
! 212: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 213: struct mbuf *nam = nfsd->nd_nam;
! 214: caddr_t dpos = nfsd->nd_dpos;
! 215: struct ucred *cred = &nfsd->nd_cr;
! 216: struct vattr va, preat;
! 217: struct nfsv2_sattr *sp;
! 218: struct nfs_fattr *fp;
! 219: struct vnode *vp;
! 220: nfsfh_t nfh;
! 221: fhandle_t *fhp;
! 222: u_int32_t *tl;
! 223: int32_t t1;
! 224: caddr_t bpos;
! 225: int error = 0, rdonly, preat_ret = 1, postat_ret = 1;
! 226: int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
! 227: char *cp2;
! 228: struct mbuf *mb, *mb2, *mreq;
! 229: u_quad_t frev;
! 230: struct timespec guard;
! 231:
! 232: fhp = &nfh.fh_generic;
! 233: nfsm_srvmtofh(fhp);
! 234: VATTR_NULL(&va);
! 235: if (v3) {
! 236: va.va_vaflags |= VA_UTIMES_NULL;
! 237: nfsm_srvsattr(&va);
! 238: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 239: gcheck = fxdr_unsigned(int, *tl);
! 240: if (gcheck) {
! 241: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 242: fxdr_nfsv3time(tl, &guard);
! 243: }
! 244: } else {
! 245: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 246: /*
! 247: * Nah nah nah nah na nah
! 248: * There is a bug in the Sun client that puts 0xffff in the mode
! 249: * field of sattr when it should put in 0xffffffff. The u_short
! 250: * doesn't sign extend.
! 251: * --> check the low order 2 bytes for 0xffff
! 252: */
! 253: if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
! 254: va.va_mode = nfstov_mode(sp->sa_mode);
! 255: if (sp->sa_uid != nfs_xdrneg1)
! 256: va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
! 257: if (sp->sa_gid != nfs_xdrneg1)
! 258: va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
! 259: if (sp->sa_size != nfs_xdrneg1)
! 260: va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
! 261: if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
! 262: #ifdef notyet
! 263: fxdr_nfsv2time(&sp->sa_atime, &va.va_atime);
! 264: #else
! 265: va.va_atime.tv_sec =
! 266: fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
! 267: va.va_atime.tv_nsec = 0;
! 268: #endif
! 269: }
! 270: if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
! 271: fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime);
! 272:
! 273: }
! 274:
! 275: /*
! 276: * Now that we have all the fields, lets do it.
! 277: */
! 278: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
! 279: (nfsd->nd_flag & ND_KERBAUTH));
! 280: if (error) {
! 281: nfsm_reply(2 * NFSX_UNSIGNED);
! 282: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
! 283: return (0);
! 284: }
! 285: if (v3) {
! 286: error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
! 287: if (!error && gcheck &&
! 288: (preat.va_ctime.tv_sec != guard.tv_sec ||
! 289: preat.va_ctime.tv_nsec != guard.tv_nsec))
! 290: error = NFSERR_NOT_SYNC;
! 291: if (error) {
! 292: vput(vp);
! 293: nfsm_reply(NFSX_WCCDATA(v3));
! 294: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
! 295: return (0);
! 296: }
! 297: }
! 298:
! 299: /*
! 300: * If the size is being changed write acces is required, otherwise
! 301: * just check for a read only file system.
! 302: */
! 303: if (va.va_size == ((u_quad_t)((quad_t) -1))) {
! 304: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
! 305: error = EROFS;
! 306: goto out;
! 307: }
! 308: } else {
! 309: if (vp->v_type == VDIR) {
! 310: error = EISDIR;
! 311: goto out;
! 312: } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
! 313: procp, 0)) != 0)
! 314: goto out;
! 315: }
! 316: error = VOP_SETATTR(vp, &va, cred, procp);
! 317: postat_ret = VOP_GETATTR(vp, &va, cred, procp);
! 318: if (!error)
! 319: error = postat_ret;
! 320: out:
! 321: vput(vp);
! 322: nfsm_reply(NFSX_WCCORFATTR(v3));
! 323: if (v3) {
! 324: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
! 325: return (0);
! 326: } else {
! 327: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
! 328: nfsm_srvfillattr(&va, fp);
! 329: }
! 330: nfsm_srvdone;
! 331: }
! 332:
! 333: /*
! 334: * nfs lookup rpc
! 335: */
! 336: int
! 337: nfsrv_lookup(nfsd, slp, procp, mrq)
! 338: struct nfsrv_descript *nfsd;
! 339: struct nfssvc_sock *slp;
! 340: struct proc *procp;
! 341: struct mbuf **mrq;
! 342: {
! 343: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 344: struct mbuf *nam = nfsd->nd_nam;
! 345: caddr_t dpos = nfsd->nd_dpos;
! 346: struct ucred *cred = &nfsd->nd_cr;
! 347: struct nfs_fattr *fp;
! 348: struct nameidata nd;
! 349: struct vnode *vp, *dirp;
! 350: nfsfh_t nfh;
! 351: fhandle_t *fhp;
! 352: caddr_t cp;
! 353: u_int32_t *tl;
! 354: int32_t t1;
! 355: caddr_t bpos;
! 356: int error = 0, len, dirattr_ret = 1;
! 357: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 358: char *cp2;
! 359: struct mbuf *mb, *mb2, *mreq;
! 360: struct vattr va, dirattr;
! 361: u_quad_t frev;
! 362:
! 363: fhp = &nfh.fh_generic;
! 364: nfsm_srvmtofh(fhp);
! 365: nfsm_srvnamesiz(len);
! 366: nd.ni_cnd.cn_cred = cred;
! 367: nd.ni_cnd.cn_nameiop = LOOKUP;
! 368: nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
! 369: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 370: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 371: if (dirp) {
! 372: if (v3)
! 373: dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
! 374: procp);
! 375: vrele(dirp);
! 376: }
! 377: if (error) {
! 378: nfsm_reply(NFSX_POSTOPATTR(v3));
! 379: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
! 380: return (0);
! 381: }
! 382: vrele(nd.ni_startdir);
! 383: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 384: vp = nd.ni_vp;
! 385: bzero((caddr_t)fhp, sizeof(nfh));
! 386: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
! 387: error = VFS_VPTOFH(vp, &fhp->fh_fid);
! 388: if (!error)
! 389: error = VOP_GETATTR(vp, &va, cred, procp);
! 390: vput(vp);
! 391: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
! 392: if (error) {
! 393: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
! 394: return (0);
! 395: }
! 396: nfsm_srvfhtom(fhp, v3);
! 397: if (v3) {
! 398: nfsm_srvpostop_attr(0, &va);
! 399: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
! 400: } else {
! 401: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
! 402: nfsm_srvfillattr(&va, fp);
! 403: }
! 404: nfsm_srvdone;
! 405: }
! 406:
! 407: /*
! 408: * nfs readlink service
! 409: */
! 410: int
! 411: nfsrv_readlink(nfsd, slp, procp, mrq)
! 412: struct nfsrv_descript *nfsd;
! 413: struct nfssvc_sock *slp;
! 414: struct proc *procp;
! 415: struct mbuf **mrq;
! 416: {
! 417: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 418: struct mbuf *nam = nfsd->nd_nam;
! 419: caddr_t dpos = nfsd->nd_dpos;
! 420: struct ucred *cred = &nfsd->nd_cr;
! 421: struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
! 422: struct iovec *ivp = iv;
! 423: struct mbuf *mp;
! 424: u_int32_t *tl;
! 425: int32_t t1;
! 426: caddr_t bpos;
! 427: int error = 0, rdonly, i, tlen, len, getret;
! 428: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 429: char *cp2;
! 430: struct mbuf *mb, *mb2, *mp2 = NULL, *mp3 = NULL, *mreq;
! 431: struct vnode *vp;
! 432: struct vattr attr;
! 433: nfsfh_t nfh;
! 434: fhandle_t *fhp;
! 435: struct uio io, *uiop = &io;
! 436: u_quad_t frev;
! 437:
! 438: fhp = &nfh.fh_generic;
! 439: nfsm_srvmtofh(fhp);
! 440: len = 0;
! 441: i = 0;
! 442: while (len < NFS_MAXPATHLEN) {
! 443: MGET(mp, M_WAIT, MT_DATA);
! 444: MCLGET(mp, M_WAIT);
! 445: mp->m_len = NFSMSIZ(mp);
! 446: if (len == 0)
! 447: mp3 = mp2 = mp;
! 448: else {
! 449: mp2->m_next = mp;
! 450: mp2 = mp;
! 451: }
! 452: if ((len+mp->m_len) > NFS_MAXPATHLEN) {
! 453: mp->m_len = NFS_MAXPATHLEN-len;
! 454: len = NFS_MAXPATHLEN;
! 455: } else
! 456: len += mp->m_len;
! 457: ivp->iov_base = mtod(mp, caddr_t);
! 458: ivp->iov_len = mp->m_len;
! 459: i++;
! 460: ivp++;
! 461: }
! 462: uiop->uio_iov = iv;
! 463: uiop->uio_iovcnt = i;
! 464: uiop->uio_offset = 0;
! 465: uiop->uio_resid = len;
! 466: uiop->uio_rw = UIO_READ;
! 467: uiop->uio_segflg = UIO_SYSSPACE;
! 468: uiop->uio_procp = (struct proc *)0;
! 469: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 470: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 471: if (error) {
! 472: m_freem(mp3);
! 473: nfsm_reply(2 * NFSX_UNSIGNED);
! 474: nfsm_srvpostop_attr(1, (struct vattr *)0);
! 475: return (0);
! 476: }
! 477: if (vp->v_type != VLNK) {
! 478: if (v3)
! 479: error = EINVAL;
! 480: else
! 481: error = ENXIO;
! 482: goto out;
! 483: }
! 484: error = VOP_READLINK(vp, uiop, cred);
! 485: out:
! 486: getret = VOP_GETATTR(vp, &attr, cred, procp);
! 487: vput(vp);
! 488: if (error)
! 489: m_freem(mp3);
! 490: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
! 491: if (v3) {
! 492: nfsm_srvpostop_attr(getret, &attr);
! 493: if (error)
! 494: return (0);
! 495: }
! 496: if (uiop->uio_resid > 0) {
! 497: len -= uiop->uio_resid;
! 498: tlen = nfsm_rndup(len);
! 499: nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
! 500: }
! 501: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 502: *tl = txdr_unsigned(len);
! 503: mb->m_next = mp3;
! 504: nfsm_srvdone;
! 505: }
! 506:
! 507: /*
! 508: * nfs read service
! 509: */
! 510: int
! 511: nfsrv_read(nfsd, slp, procp, mrq)
! 512: struct nfsrv_descript *nfsd;
! 513: struct nfssvc_sock *slp;
! 514: struct proc *procp;
! 515: struct mbuf **mrq;
! 516: {
! 517: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 518: struct mbuf *nam = nfsd->nd_nam;
! 519: caddr_t dpos = nfsd->nd_dpos;
! 520: struct ucred *cred = &nfsd->nd_cr;
! 521: struct iovec *iv;
! 522: struct iovec *iv2;
! 523: struct mbuf *m;
! 524: struct nfs_fattr *fp;
! 525: u_int32_t *tl;
! 526: int32_t t1;
! 527: int i;
! 528: caddr_t bpos;
! 529: int error = 0, rdonly, cnt, len, left, siz, tlen, getret;
! 530: int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
! 531: char *cp2;
! 532: struct mbuf *mb, *mb2, *mreq;
! 533: struct mbuf *m2;
! 534: struct vnode *vp;
! 535: nfsfh_t nfh;
! 536: fhandle_t *fhp;
! 537: struct uio io, *uiop = &io;
! 538: struct vattr va;
! 539: off_t off;
! 540: u_quad_t frev;
! 541:
! 542: fhp = &nfh.fh_generic;
! 543: nfsm_srvmtofh(fhp);
! 544: if (v3) {
! 545: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 546: off = fxdr_hyper(tl);
! 547: } else {
! 548: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 549: off = (off_t)fxdr_unsigned(u_int32_t, *tl);
! 550: }
! 551: nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
! 552: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 553: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 554: if (error) {
! 555: nfsm_reply(2 * NFSX_UNSIGNED);
! 556: nfsm_srvpostop_attr(1, (struct vattr *)0);
! 557: return (0);
! 558: }
! 559: if (vp->v_type != VREG) {
! 560: if (v3)
! 561: error = EINVAL;
! 562: else
! 563: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
! 564: }
! 565: if (!error) {
! 566: if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0)
! 567: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1);
! 568: }
! 569: getret = VOP_GETATTR(vp, &va, cred, procp);
! 570: if (!error)
! 571: error = getret;
! 572: if (error) {
! 573: vput(vp);
! 574: nfsm_reply(NFSX_POSTOPATTR(v3));
! 575: nfsm_srvpostop_attr(getret, &va);
! 576: return (0);
! 577: }
! 578: if (off >= va.va_size)
! 579: cnt = 0;
! 580: else if ((off + reqlen) > va.va_size)
! 581: cnt = va.va_size - off;
! 582: else
! 583: cnt = reqlen;
! 584: nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
! 585: if (v3) {
! 586: nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
! 587: *tl++ = nfs_true;
! 588: fp = (struct nfs_fattr *)tl;
! 589: tl += (NFSX_V3FATTR / sizeof (u_int32_t));
! 590: } else {
! 591: nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED);
! 592: fp = (struct nfs_fattr *)tl;
! 593: tl += (NFSX_V2FATTR / sizeof (u_int32_t));
! 594: }
! 595: len = left = nfsm_rndup (cnt);
! 596: if (cnt > 0) {
! 597: /*
! 598: * Generate the mbuf list with the uio_iov ref. to it.
! 599: */
! 600: i = 0;
! 601: m = m2 = mb;
! 602: while (left > 0) {
! 603: siz = min(M_TRAILINGSPACE(m), left);
! 604: if (siz > 0) {
! 605: left -= siz;
! 606: i++;
! 607: }
! 608: if (left > 0) {
! 609: MGET(m, M_WAIT, MT_DATA);
! 610: MCLGET(m, M_WAIT);
! 611: m->m_len = 0;
! 612: m2->m_next = m;
! 613: m2 = m;
! 614: }
! 615: }
! 616: MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
! 617: M_TEMP, M_WAITOK);
! 618: uiop->uio_iov = iv2 = iv;
! 619: m = mb;
! 620: left = len;
! 621: i = 0;
! 622: while (left > 0) {
! 623: if (m == NULL)
! 624: panic("nfsrv_read iov");
! 625: siz = min(M_TRAILINGSPACE(m), left);
! 626: if (siz > 0) {
! 627: iv->iov_base = mtod(m, caddr_t) + m->m_len;
! 628: iv->iov_len = siz;
! 629: m->m_len += siz;
! 630: left -= siz;
! 631: iv++;
! 632: i++;
! 633: }
! 634: m = m->m_next;
! 635: }
! 636: uiop->uio_iovcnt = i;
! 637: uiop->uio_offset = off;
! 638: uiop->uio_resid = len;
! 639: uiop->uio_rw = UIO_READ;
! 640: uiop->uio_segflg = UIO_SYSSPACE;
! 641: error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
! 642: off = uiop->uio_offset;
! 643: FREE((caddr_t)iv2, M_TEMP);
! 644: if (error || (getret = VOP_GETATTR(vp, &va, cred, procp)) != 0){
! 645: if (!error)
! 646: error = getret;
! 647: m_freem(mreq);
! 648: vput(vp);
! 649: nfsm_reply(NFSX_POSTOPATTR(v3));
! 650: nfsm_srvpostop_attr(getret, &va);
! 651: return (0);
! 652: }
! 653: } else
! 654: uiop->uio_resid = 0;
! 655: vput(vp);
! 656: nfsm_srvfillattr(&va, fp);
! 657: tlen = len - uiop->uio_resid;
! 658: cnt = cnt < tlen ? cnt : tlen;
! 659: tlen = nfsm_rndup (cnt);
! 660: if (len != tlen || tlen != cnt)
! 661: nfsm_adj(mb, len - tlen, tlen - cnt);
! 662: if (v3) {
! 663: *tl++ = txdr_unsigned(cnt);
! 664: if (len < reqlen)
! 665: *tl++ = nfs_true;
! 666: else
! 667: *tl++ = nfs_false;
! 668: }
! 669: *tl = txdr_unsigned(cnt);
! 670: nfsm_srvdone;
! 671: }
! 672:
! 673: /*
! 674: * nfs write service
! 675: */
! 676: int
! 677: nfsrv_write(nfsd, slp, procp, mrq)
! 678: struct nfsrv_descript *nfsd;
! 679: struct nfssvc_sock *slp;
! 680: struct proc *procp;
! 681: struct mbuf **mrq;
! 682: {
! 683: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 684: struct mbuf *nam = nfsd->nd_nam;
! 685: caddr_t dpos = nfsd->nd_dpos;
! 686: struct ucred *cred = &nfsd->nd_cr;
! 687: struct iovec *ivp;
! 688: int i, cnt;
! 689: struct mbuf *mp;
! 690: struct nfs_fattr *fp;
! 691: struct iovec *iv;
! 692: struct vattr va, forat;
! 693: u_int32_t *tl;
! 694: int32_t t1;
! 695: caddr_t bpos;
! 696: int error = 0, rdonly, len, forat_ret = 1;
! 697: int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
! 698: int stable = NFSV3WRITE_FILESYNC;
! 699: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 700: char *cp2;
! 701: struct mbuf *mb, *mb2, *mreq;
! 702: struct vnode *vp;
! 703: nfsfh_t nfh;
! 704: fhandle_t *fhp;
! 705: struct uio io, *uiop = &io;
! 706: off_t off;
! 707: u_quad_t frev;
! 708:
! 709: if (mrep == NULL) {
! 710: *mrq = NULL;
! 711: return (0);
! 712: }
! 713: fhp = &nfh.fh_generic;
! 714: nfsm_srvmtofh(fhp);
! 715: if (v3) {
! 716: nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
! 717: off = fxdr_hyper(tl);
! 718: tl += 3;
! 719: stable = fxdr_unsigned(int, *tl++);
! 720: } else {
! 721: nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 722: off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
! 723: tl += 2;
! 724: }
! 725: retlen = len = fxdr_unsigned(int32_t, *tl);
! 726: cnt = i = 0;
! 727:
! 728: /*
! 729: * For NFS Version 2, it is not obvious what a write of zero length
! 730: * should do, but I might as well be consistent with Version 3,
! 731: * which is to return ok so long as there are no permission problems.
! 732: */
! 733: if (len > 0) {
! 734: zeroing = 1;
! 735: mp = mrep;
! 736: while (mp) {
! 737: if (mp == md) {
! 738: zeroing = 0;
! 739: adjust = dpos - mtod(mp, caddr_t);
! 740: mp->m_len -= adjust;
! 741: if (mp->m_len > 0 && adjust > 0)
! 742: NFSMADV(mp, adjust);
! 743: }
! 744: if (zeroing)
! 745: mp->m_len = 0;
! 746: else if (mp->m_len > 0) {
! 747: i += mp->m_len;
! 748: if (i > len) {
! 749: mp->m_len -= (i - len);
! 750: zeroing = 1;
! 751: }
! 752: if (mp->m_len > 0)
! 753: cnt++;
! 754: }
! 755: mp = mp->m_next;
! 756: }
! 757: }
! 758: if (len > NFS_MAXDATA || len < 0 || i < len) {
! 759: error = EIO;
! 760: nfsm_reply(2 * NFSX_UNSIGNED);
! 761: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 762: return (0);
! 763: }
! 764: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 765: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 766: if (error) {
! 767: nfsm_reply(2 * NFSX_UNSIGNED);
! 768: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 769: return (0);
! 770: }
! 771: if (v3)
! 772: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
! 773: if (vp->v_type != VREG) {
! 774: if (v3)
! 775: error = EINVAL;
! 776: else
! 777: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
! 778: }
! 779: if (!error) {
! 780: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1);
! 781: }
! 782: if (error) {
! 783: vput(vp);
! 784: nfsm_reply(NFSX_WCCDATA(v3));
! 785: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 786: return (0);
! 787: }
! 788:
! 789: if (len > 0) {
! 790: MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
! 791: M_WAITOK);
! 792: uiop->uio_iov = iv = ivp;
! 793: uiop->uio_iovcnt = cnt;
! 794: mp = mrep;
! 795: while (mp) {
! 796: if (mp->m_len > 0) {
! 797: ivp->iov_base = mtod(mp, caddr_t);
! 798: ivp->iov_len = mp->m_len;
! 799: ivp++;
! 800: }
! 801: mp = mp->m_next;
! 802: }
! 803:
! 804: /*
! 805: * XXX
! 806: * The IO_METASYNC flag indicates that all metadata (and not just
! 807: * enough to ensure data integrity) mus be written to stable storage
! 808: * synchronously.
! 809: * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
! 810: */
! 811: if (stable == NFSV3WRITE_UNSTABLE)
! 812: ioflags = IO_NODELOCKED;
! 813: else if (stable == NFSV3WRITE_DATASYNC)
! 814: ioflags = (IO_SYNC | IO_NODELOCKED);
! 815: else
! 816: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
! 817: uiop->uio_resid = len;
! 818: uiop->uio_rw = UIO_WRITE;
! 819: uiop->uio_segflg = UIO_SYSSPACE;
! 820: uiop->uio_procp = (struct proc *)0;
! 821: uiop->uio_offset = off;
! 822: error = VOP_WRITE(vp, uiop, ioflags, cred);
! 823: nfsstats.srvvop_writes++;
! 824: FREE((caddr_t)iv, M_TEMP);
! 825: }
! 826: aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
! 827: vput(vp);
! 828: if (!error)
! 829: error = aftat_ret;
! 830: nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
! 831: 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
! 832: if (v3) {
! 833: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 834: if (error)
! 835: return (0);
! 836: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 837: *tl++ = txdr_unsigned(retlen);
! 838: if (stable == NFSV3WRITE_UNSTABLE)
! 839: *tl++ = txdr_unsigned(stable);
! 840: else
! 841: *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
! 842: /*
! 843: * Actually, there is no need to txdr these fields,
! 844: * but it may make the values more human readable,
! 845: * for debugging purposes.
! 846: */
! 847: *tl++ = txdr_unsigned(boottime.tv_sec);
! 848: *tl = txdr_unsigned(boottime.tv_usec);
! 849: } else {
! 850: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
! 851: nfsm_srvfillattr(&va, fp);
! 852: }
! 853: nfsm_srvdone;
! 854: }
! 855:
! 856: /*
! 857: * NFS write service with write gathering support. Called when
! 858: * nfsrvw_procrastinate > 0.
! 859: * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
! 860: * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
! 861: * Jan. 1994.
! 862: */
! 863: int
! 864: nfsrv_writegather(ndp, slp, procp, mrq)
! 865: struct nfsrv_descript **ndp;
! 866: struct nfssvc_sock *slp;
! 867: struct proc *procp;
! 868: struct mbuf **mrq;
! 869: {
! 870: struct iovec *ivp;
! 871: struct mbuf *mp;
! 872: struct nfsrv_descript *wp, *nfsd, *owp, *swp;
! 873: struct nfs_fattr *fp;
! 874: int i = 0;
! 875: struct iovec *iov;
! 876: struct nfsrvw_delayhash *wpp;
! 877: struct ucred *cred;
! 878: struct vattr va, forat;
! 879: u_int32_t *tl;
! 880: int32_t t1;
! 881: caddr_t bpos, dpos;
! 882: int error = 0, rdonly, len = 0, forat_ret = 1;
! 883: int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
! 884: char *cp2;
! 885: struct mbuf *mb, *mb2, *mreq, *mrep, *md;
! 886: struct vnode *vp;
! 887: struct uio io, *uiop = &io;
! 888: u_quad_t frev, cur_usec;
! 889: struct timeval tv;
! 890:
! 891: *mrq = NULL;
! 892: if (*ndp) {
! 893: nfsd = *ndp;
! 894: *ndp = NULL;
! 895: mrep = nfsd->nd_mrep;
! 896: md = nfsd->nd_md;
! 897: dpos = nfsd->nd_dpos;
! 898: cred = &nfsd->nd_cr;
! 899: v3 = (nfsd->nd_flag & ND_NFSV3);
! 900: LIST_INIT(&nfsd->nd_coalesce);
! 901: nfsd->nd_mreq = NULL;
! 902: nfsd->nd_stable = NFSV3WRITE_FILESYNC;
! 903: getmicrotime(&tv);
! 904: cur_usec = (u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec;
! 905: nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
! 906:
! 907: /*
! 908: * Now, get the write header..
! 909: */
! 910: nfsm_srvmtofh(&nfsd->nd_fh);
! 911: if (v3) {
! 912: nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
! 913: nfsd->nd_off = fxdr_hyper(tl);
! 914: tl += 3;
! 915: nfsd->nd_stable = fxdr_unsigned(int, *tl++);
! 916: } else {
! 917: nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 918: nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
! 919: tl += 2;
! 920: }
! 921: len = fxdr_unsigned(int32_t, *tl);
! 922: nfsd->nd_len = len;
! 923: nfsd->nd_eoff = nfsd->nd_off + len;
! 924:
! 925: /*
! 926: * Trim the header out of the mbuf list and trim off any trailing
! 927: * junk so that the mbuf list has only the write data.
! 928: */
! 929: zeroing = 1;
! 930: i = 0;
! 931: mp = mrep;
! 932: while (mp) {
! 933: if (mp == md) {
! 934: zeroing = 0;
! 935: adjust = dpos - mtod(mp, caddr_t);
! 936: mp->m_len -= adjust;
! 937: if (mp->m_len > 0 && adjust > 0)
! 938: NFSMADV(mp, adjust);
! 939: }
! 940: if (zeroing)
! 941: mp->m_len = 0;
! 942: else {
! 943: i += mp->m_len;
! 944: if (i > len) {
! 945: mp->m_len -= (i - len);
! 946: zeroing = 1;
! 947: }
! 948: }
! 949: mp = mp->m_next;
! 950: }
! 951: if (len > NFS_MAXDATA || len < 0 || i < len) {
! 952: m_freem(mrep);
! 953: nfsmout:
! 954: error = EIO;
! 955: nfsm_writereply(2 * NFSX_UNSIGNED, v3);
! 956: if (v3)
! 957: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 958: nfsd->nd_mreq = mreq;
! 959: nfsd->nd_mrep = NULL;
! 960: nfsd->nd_time = 0;
! 961: }
! 962:
! 963: /*
! 964: * Add this entry to the hash and time queues.
! 965: */
! 966: s = splsoftclock();
! 967: owp = NULL;
! 968: wp = LIST_FIRST(&slp->ns_tq);
! 969: while (wp && wp->nd_time < nfsd->nd_time) {
! 970: owp = wp;
! 971: wp = LIST_NEXT(wp, nd_tq);
! 972: }
! 973: if (owp) {
! 974: LIST_INSERT_AFTER(owp, nfsd, nd_tq);
! 975: } else {
! 976: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
! 977: }
! 978: if (nfsd->nd_mrep) {
! 979: wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
! 980: owp = NULL;
! 981: wp = LIST_FIRST(wpp);
! 982: while (wp &&
! 983: bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
! 984: owp = wp;
! 985: wp = LIST_NEXT(wp, nd_hash);
! 986: }
! 987: while (wp && wp->nd_off < nfsd->nd_off &&
! 988: !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
! 989: owp = wp;
! 990: wp = LIST_NEXT(wp, nd_hash);
! 991: }
! 992: if (owp) {
! 993: LIST_INSERT_AFTER(owp, nfsd, nd_hash);
! 994:
! 995: /*
! 996: * Search the hash list for overlapping entries and
! 997: * coalesce.
! 998: */
! 999: for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
! 1000: wp = LIST_NEXT(nfsd, nd_hash);
! 1001: if (NFSW_SAMECRED(owp, nfsd))
! 1002: nfsrvw_coalesce(owp, nfsd);
! 1003: }
! 1004: } else {
! 1005: LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
! 1006: }
! 1007: }
! 1008: splx(s);
! 1009: }
! 1010:
! 1011: /*
! 1012: * Now, do VOP_WRITE()s for any one(s) that need to be done now
! 1013: * and generate the associated reply mbuf list(s).
! 1014: */
! 1015: loop1:
! 1016: getmicrotime(&tv);
! 1017: cur_usec = (u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec;
! 1018: s = splsoftclock();
! 1019: for (nfsd = LIST_FIRST(&slp->ns_tq); nfsd != NULL; nfsd = owp) {
! 1020: owp = LIST_NEXT(nfsd, nd_tq);
! 1021: if (nfsd->nd_time > cur_usec)
! 1022: break;
! 1023: if (nfsd->nd_mreq)
! 1024: continue;
! 1025: LIST_REMOVE(nfsd, nd_tq);
! 1026: LIST_REMOVE(nfsd, nd_hash);
! 1027: splx(s);
! 1028: mrep = nfsd->nd_mrep;
! 1029: nfsd->nd_mrep = NULL;
! 1030: cred = &nfsd->nd_cr;
! 1031: v3 = (nfsd->nd_flag & ND_NFSV3);
! 1032: forat_ret = aftat_ret = 1;
! 1033: error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
! 1034: nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 1035: if (!error) {
! 1036: if (v3)
! 1037: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
! 1038: if (vp->v_type != VREG) {
! 1039: if (v3)
! 1040: error = EINVAL;
! 1041: else
! 1042: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
! 1043: }
! 1044: } else
! 1045: vp = NULL;
! 1046: if (!error) {
! 1047: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1);
! 1048: }
! 1049:
! 1050: if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
! 1051: ioflags = IO_NODELOCKED;
! 1052: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
! 1053: ioflags = (IO_SYNC | IO_NODELOCKED);
! 1054: else
! 1055: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
! 1056: uiop->uio_rw = UIO_WRITE;
! 1057: uiop->uio_segflg = UIO_SYSSPACE;
! 1058: uiop->uio_procp = (struct proc *)0;
! 1059: uiop->uio_offset = nfsd->nd_off;
! 1060: uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
! 1061: if (uiop->uio_resid > 0) {
! 1062: mp = mrep;
! 1063: i = 0;
! 1064: while (mp) {
! 1065: if (mp->m_len > 0)
! 1066: i++;
! 1067: mp = mp->m_next;
! 1068: }
! 1069: uiop->uio_iovcnt = i;
! 1070: MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
! 1071: M_TEMP, M_WAITOK);
! 1072: uiop->uio_iov = ivp = iov;
! 1073: mp = mrep;
! 1074: while (mp) {
! 1075: if (mp->m_len > 0) {
! 1076: ivp->iov_base = mtod(mp, caddr_t);
! 1077: ivp->iov_len = mp->m_len;
! 1078: ivp++;
! 1079: }
! 1080: mp = mp->m_next;
! 1081: }
! 1082: if (!error) {
! 1083: error = VOP_WRITE(vp, uiop, ioflags, cred);
! 1084: nfsstats.srvvop_writes++;
! 1085: }
! 1086: FREE((caddr_t)iov, M_TEMP);
! 1087: }
! 1088: m_freem(mrep);
! 1089: if (vp) {
! 1090: aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
! 1091: vput(vp);
! 1092: }
! 1093:
! 1094: /*
! 1095: * Loop around generating replies for all write rpcs that have
! 1096: * now been completed.
! 1097: */
! 1098: swp = nfsd;
! 1099: do {
! 1100: if (error) {
! 1101: nfsm_writereply(NFSX_WCCDATA(v3), v3);
! 1102: if (v3) {
! 1103: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 1104: }
! 1105: } else {
! 1106: nfsm_writereply(NFSX_PREOPATTR(v3) +
! 1107: NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
! 1108: NFSX_WRITEVERF(v3), v3);
! 1109: if (v3) {
! 1110: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
! 1111: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 1112: *tl++ = txdr_unsigned(nfsd->nd_len);
! 1113: *tl++ = txdr_unsigned(swp->nd_stable);
! 1114: /*
! 1115: * Actually, there is no need to txdr these fields,
! 1116: * but it may make the values more human readable,
! 1117: * for debugging purposes.
! 1118: */
! 1119: *tl++ = txdr_unsigned(boottime.tv_sec);
! 1120: *tl = txdr_unsigned(boottime.tv_usec);
! 1121: } else {
! 1122: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
! 1123: nfsm_srvfillattr(&va, fp);
! 1124: }
! 1125: }
! 1126: nfsd->nd_mreq = mreq;
! 1127: if (nfsd->nd_mrep)
! 1128: panic("nfsrv_write: nd_mrep not free");
! 1129:
! 1130: /*
! 1131: * Done. Put it at the head of the timer queue so that
! 1132: * the final phase can return the reply.
! 1133: */
! 1134: s = splsoftclock();
! 1135: if (nfsd != swp) {
! 1136: nfsd->nd_time = 0;
! 1137: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
! 1138: }
! 1139: nfsd = LIST_FIRST(&swp->nd_coalesce);
! 1140: if (nfsd) {
! 1141: LIST_REMOVE(nfsd, nd_tq);
! 1142: }
! 1143: splx(s);
! 1144: } while (nfsd);
! 1145: s = splsoftclock();
! 1146: swp->nd_time = 0;
! 1147: LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
! 1148: splx(s);
! 1149: goto loop1;
! 1150: }
! 1151: splx(s);
! 1152:
! 1153: /*
! 1154: * Search for a reply to return.
! 1155: */
! 1156: s = splsoftclock();
! 1157: for (nfsd = LIST_FIRST(&slp->ns_tq); nfsd != NULL;
! 1158: nfsd = LIST_NEXT(nfsd, nd_tq)) {
! 1159: if (nfsd->nd_mreq) {
! 1160: LIST_REMOVE(nfsd, nd_tq);
! 1161: *mrq = nfsd->nd_mreq;
! 1162: *ndp = nfsd;
! 1163: break;
! 1164: }
! 1165: }
! 1166: splx(s);
! 1167: return (0);
! 1168: }
! 1169:
! 1170: /*
! 1171: * Coalesce the write request nfsd into owp. To do this we must:
! 1172: * - remove nfsd from the queues
! 1173: * - merge nfsd->nd_mrep into owp->nd_mrep
! 1174: * - update the nd_eoff and nd_stable for owp
! 1175: * - put nfsd on owp's nd_coalesce list
! 1176: * NB: Must be called at splsoftclock().
! 1177: */
! 1178: void
! 1179: nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd)
! 1180: {
! 1181: int overlap;
! 1182: struct mbuf *mp;
! 1183:
! 1184: splassert(IPL_SOFTCLOCK);
! 1185:
! 1186: LIST_REMOVE(nfsd, nd_hash);
! 1187: LIST_REMOVE(nfsd, nd_tq);
! 1188: if (owp->nd_eoff < nfsd->nd_eoff) {
! 1189: overlap = owp->nd_eoff - nfsd->nd_off;
! 1190: if (overlap < 0)
! 1191: panic("nfsrv_coalesce: bad off");
! 1192: if (overlap > 0)
! 1193: m_adj(nfsd->nd_mrep, overlap);
! 1194: mp = owp->nd_mrep;
! 1195: while (mp->m_next)
! 1196: mp = mp->m_next;
! 1197: mp->m_next = nfsd->nd_mrep;
! 1198: owp->nd_eoff = nfsd->nd_eoff;
! 1199: } else
! 1200: m_freem(nfsd->nd_mrep);
! 1201: nfsd->nd_mrep = NULL;
! 1202: if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
! 1203: owp->nd_stable = NFSV3WRITE_FILESYNC;
! 1204: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
! 1205: owp->nd_stable == NFSV3WRITE_UNSTABLE)
! 1206: owp->nd_stable = NFSV3WRITE_DATASYNC;
! 1207: LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
! 1208:
! 1209: /*
! 1210: * nfsd might hold coalesce elements! Move them to owp.
! 1211: * Otherwise, requests may be lost and clients will be stuck.
! 1212: */
! 1213: if (LIST_FIRST(&nfsd->nd_coalesce) != NULL) {
! 1214: struct nfsrv_descript *m;
! 1215:
! 1216: while ((m = LIST_FIRST(&nfsd->nd_coalesce)) != NULL) {
! 1217: LIST_REMOVE(m, nd_tq);
! 1218: LIST_INSERT_HEAD(&owp->nd_coalesce, m, nd_tq);
! 1219: }
! 1220: }
! 1221: }
! 1222:
! 1223: /*
! 1224: * nfs create service
! 1225: * now does a truncate to 0 length via. setattr if it already exists
! 1226: */
! 1227: int
! 1228: nfsrv_create(nfsd, slp, procp, mrq)
! 1229: struct nfsrv_descript *nfsd;
! 1230: struct nfssvc_sock *slp;
! 1231: struct proc *procp;
! 1232: struct mbuf **mrq;
! 1233: {
! 1234: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 1235: struct mbuf *nam = nfsd->nd_nam;
! 1236: caddr_t dpos = nfsd->nd_dpos;
! 1237: struct ucred *cred = &nfsd->nd_cr;
! 1238: struct nfs_fattr *fp;
! 1239: struct vattr va, dirfor, diraft;
! 1240: struct nfsv2_sattr *sp;
! 1241: u_int32_t *tl;
! 1242: struct nameidata nd;
! 1243: caddr_t cp;
! 1244: int32_t t1;
! 1245: caddr_t bpos;
! 1246: int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1;
! 1247: dev_t rdev = 0;
! 1248: int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
! 1249: char *cp2;
! 1250: struct mbuf *mb, *mb2, *mreq;
! 1251: struct vnode *vp = NULL, *dirp = NULL;
! 1252: nfsfh_t nfh;
! 1253: fhandle_t *fhp;
! 1254: u_quad_t frev, tempsize;
! 1255: u_char cverf[NFSX_V3CREATEVERF];
! 1256:
! 1257: nd.ni_cnd.cn_nameiop = 0;
! 1258: fhp = &nfh.fh_generic;
! 1259: nfsm_srvmtofh(fhp);
! 1260: nfsm_srvnamesiz(len);
! 1261: nd.ni_cnd.cn_cred = cred;
! 1262: nd.ni_cnd.cn_nameiop = CREATE;
! 1263: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
! 1264: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 1265: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 1266: if (dirp) {
! 1267: if (v3)
! 1268: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
! 1269: procp);
! 1270: else {
! 1271: vrele(dirp);
! 1272: dirp = (struct vnode *)0;
! 1273: }
! 1274: }
! 1275: if (error) {
! 1276: nfsm_reply(NFSX_WCCDATA(v3));
! 1277: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1278: if (dirp)
! 1279: vrele(dirp);
! 1280: return (0);
! 1281: }
! 1282: VATTR_NULL(&va);
! 1283: if (v3) {
! 1284: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 1285: how = fxdr_unsigned(int, *tl);
! 1286: switch (how) {
! 1287: case NFSV3CREATE_GUARDED:
! 1288: if (nd.ni_vp) {
! 1289: error = EEXIST;
! 1290: break;
! 1291: }
! 1292: case NFSV3CREATE_UNCHECKED:
! 1293: nfsm_srvsattr(&va);
! 1294: break;
! 1295: case NFSV3CREATE_EXCLUSIVE:
! 1296: nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
! 1297: bcopy(cp, cverf, NFSX_V3CREATEVERF);
! 1298: exclusive_flag = 1;
! 1299: if (nd.ni_vp == NULL)
! 1300: va.va_mode = 0;
! 1301: break;
! 1302: };
! 1303: va.va_type = VREG;
! 1304: } else {
! 1305: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 1306: va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
! 1307: if (va.va_type == VNON)
! 1308: va.va_type = VREG;
! 1309: va.va_mode = nfstov_mode(sp->sa_mode);
! 1310: switch (va.va_type) {
! 1311: case VREG:
! 1312: tsize = fxdr_unsigned(int32_t, sp->sa_size);
! 1313: if (tsize != -1)
! 1314: va.va_size = (u_quad_t)tsize;
! 1315: break;
! 1316: case VCHR:
! 1317: case VBLK:
! 1318: case VFIFO:
! 1319: rdev = (dev_t)fxdr_unsigned(int32_t, sp->sa_size);
! 1320: break;
! 1321: default:
! 1322: break;
! 1323: };
! 1324: }
! 1325:
! 1326: /*
! 1327: * Iff doesn't exist, create it
! 1328: * otherwise just truncate to 0 length
! 1329: * should I set the mode too ??
! 1330: */
! 1331: if (nd.ni_vp == NULL) {
! 1332: if (va.va_type == VREG || va.va_type == VSOCK) {
! 1333: vrele(nd.ni_startdir);
! 1334: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
! 1335: if (!error) {
! 1336: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1337: if (exclusive_flag) {
! 1338: exclusive_flag = 0;
! 1339: VATTR_NULL(&va);
! 1340: bcopy(cverf, (caddr_t)&va.va_atime,
! 1341: NFSX_V3CREATEVERF);
! 1342: error = VOP_SETATTR(nd.ni_vp, &va, cred,
! 1343: procp);
! 1344: }
! 1345: }
! 1346: } else if (va.va_type == VCHR || va.va_type == VBLK ||
! 1347: va.va_type == VFIFO) {
! 1348: if (va.va_type == VCHR && rdev == 0xffffffff)
! 1349: va.va_type = VFIFO;
! 1350: if (va.va_type != VFIFO &&
! 1351: (error = suser_ucred(cred))) {
! 1352: vrele(nd.ni_startdir);
! 1353: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1354: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1355: vput(nd.ni_dvp);
! 1356: nfsm_reply(0);
! 1357: return (0);
! 1358: } else
! 1359: va.va_rdev = (dev_t)rdev;
! 1360: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
! 1361: &va);
! 1362: if (error) {
! 1363: vrele(nd.ni_startdir);
! 1364: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1365: nfsm_reply(0);
! 1366: return (0);
! 1367: }
! 1368: nd.ni_cnd.cn_nameiop = LOOKUP;
! 1369: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
! 1370: nd.ni_cnd.cn_proc = procp;
! 1371: nd.ni_cnd.cn_cred = cred;
! 1372: if ((error = lookup(&nd)) != 0) {
! 1373: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1374: nfsm_reply(0);
! 1375: return (0);
! 1376: }
! 1377:
! 1378: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1379: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
! 1380: vrele(nd.ni_dvp);
! 1381: vput(nd.ni_vp);
! 1382: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1383: error = EINVAL;
! 1384: nfsm_reply(0);
! 1385: return (0);
! 1386: }
! 1387: } else {
! 1388: vrele(nd.ni_startdir);
! 1389: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1390: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1391: vput(nd.ni_dvp);
! 1392: error = ENXIO;
! 1393: }
! 1394: vp = nd.ni_vp;
! 1395: } else {
! 1396: vrele(nd.ni_startdir);
! 1397: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1398: vp = nd.ni_vp;
! 1399: if (nd.ni_dvp == vp)
! 1400: vrele(nd.ni_dvp);
! 1401: else
! 1402: vput(nd.ni_dvp);
! 1403: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1404: if (va.va_size != -1) {
! 1405: error = nfsrv_access(vp, VWRITE, cred,
! 1406: (nd.ni_cnd.cn_flags & RDONLY), procp, 0);
! 1407: if (!error) {
! 1408: tempsize = va.va_size;
! 1409: VATTR_NULL(&va);
! 1410: va.va_size = tempsize;
! 1411: error = VOP_SETATTR(vp, &va, cred,
! 1412: procp);
! 1413: }
! 1414: if (error)
! 1415: vput(vp);
! 1416: }
! 1417: }
! 1418: if (!error) {
! 1419: bzero((caddr_t)fhp, sizeof(nfh));
! 1420: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
! 1421: error = VFS_VPTOFH(vp, &fhp->fh_fid);
! 1422: if (!error)
! 1423: error = VOP_GETATTR(vp, &va, cred, procp);
! 1424: vput(vp);
! 1425: }
! 1426: if (v3) {
! 1427: if (exclusive_flag && !error &&
! 1428: bcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF))
! 1429: error = EEXIST;
! 1430: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 1431: vrele(dirp);
! 1432: }
! 1433: nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
! 1434: if (v3) {
! 1435: if (!error) {
! 1436: nfsm_srvpostop_fh(fhp);
! 1437: nfsm_srvpostop_attr(0, &va);
! 1438: }
! 1439: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1440: } else {
! 1441: nfsm_srvfhtom(fhp, v3);
! 1442: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
! 1443: nfsm_srvfillattr(&va, fp);
! 1444: }
! 1445: return (0);
! 1446: nfsmout:
! 1447: if (dirp)
! 1448: vrele(dirp);
! 1449: if (nd.ni_cnd.cn_nameiop) {
! 1450: vrele(nd.ni_startdir);
! 1451: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1452: }
! 1453: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1454: if (nd.ni_dvp == nd.ni_vp)
! 1455: vrele(nd.ni_dvp);
! 1456: else
! 1457: vput(nd.ni_dvp);
! 1458: if (nd.ni_vp)
! 1459: vput(nd.ni_vp);
! 1460: return (error);
! 1461: }
! 1462:
! 1463: /*
! 1464: * nfs v3 mknod service
! 1465: */
! 1466: int
! 1467: nfsrv_mknod(nfsd, slp, procp, mrq)
! 1468: struct nfsrv_descript *nfsd;
! 1469: struct nfssvc_sock *slp;
! 1470: struct proc *procp;
! 1471: struct mbuf **mrq;
! 1472: {
! 1473: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 1474: struct mbuf *nam = nfsd->nd_nam;
! 1475: caddr_t dpos = nfsd->nd_dpos;
! 1476: struct ucred *cred = &nfsd->nd_cr;
! 1477: struct vattr va, dirfor, diraft;
! 1478: u_int32_t *tl;
! 1479: struct nameidata nd;
! 1480: int32_t t1;
! 1481: caddr_t bpos;
! 1482: int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
! 1483: u_int32_t major, minor;
! 1484: enum vtype vtyp;
! 1485: char *cp2;
! 1486: struct mbuf *mb, *mb2, *mreq;
! 1487: struct vnode *vp, *dirp = (struct vnode *)0;
! 1488: nfsfh_t nfh;
! 1489: fhandle_t *fhp;
! 1490: u_quad_t frev;
! 1491:
! 1492: nd.ni_cnd.cn_nameiop = 0;
! 1493: fhp = &nfh.fh_generic;
! 1494: nfsm_srvmtofh(fhp);
! 1495: nfsm_srvnamesiz(len);
! 1496: nd.ni_cnd.cn_cred = cred;
! 1497: nd.ni_cnd.cn_nameiop = CREATE;
! 1498: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
! 1499: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 1500: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 1501: if (dirp)
! 1502: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
! 1503: if (error) {
! 1504: nfsm_reply(NFSX_WCCDATA(1));
! 1505: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1506: if (dirp)
! 1507: vrele(dirp);
! 1508: return (0);
! 1509: }
! 1510: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 1511: vtyp = nfsv3tov_type(*tl);
! 1512: if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
! 1513: vrele(nd.ni_startdir);
! 1514: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1515: error = NFSERR_BADTYPE;
! 1516: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1517: vput(nd.ni_dvp);
! 1518: goto out;
! 1519: }
! 1520: VATTR_NULL(&va);
! 1521: nfsm_srvsattr(&va);
! 1522: if (vtyp == VCHR || vtyp == VBLK) {
! 1523: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 1524: major = fxdr_unsigned(u_int32_t, *tl++);
! 1525: minor = fxdr_unsigned(u_int32_t, *tl);
! 1526: va.va_rdev = makedev(major, minor);
! 1527: }
! 1528:
! 1529: /*
! 1530: * Iff doesn't exist, create it.
! 1531: */
! 1532: if (nd.ni_vp) {
! 1533: vrele(nd.ni_startdir);
! 1534: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1535: error = EEXIST;
! 1536: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1537: vput(nd.ni_dvp);
! 1538: goto out;
! 1539: }
! 1540: va.va_type = vtyp;
! 1541: if (vtyp == VSOCK) {
! 1542: vrele(nd.ni_startdir);
! 1543: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
! 1544: if (!error)
! 1545: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1546: } else {
! 1547: if (va.va_type != VFIFO &&
! 1548: (error = suser_ucred(cred))) {
! 1549: vrele(nd.ni_startdir);
! 1550: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1551: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1552: vput(nd.ni_dvp);
! 1553: goto out;
! 1554: }
! 1555: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
! 1556: if (error) {
! 1557: vrele(nd.ni_startdir);
! 1558: goto out;
! 1559: }
! 1560: nd.ni_cnd.cn_nameiop = LOOKUP;
! 1561: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
! 1562: nd.ni_cnd.cn_proc = procp;
! 1563: nd.ni_cnd.cn_cred = procp->p_ucred;
! 1564: error = lookup(&nd);
! 1565: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1566: if (error)
! 1567: goto out;
! 1568: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
! 1569: vrele(nd.ni_dvp);
! 1570: vput(nd.ni_vp);
! 1571: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1572: error = EINVAL;
! 1573: }
! 1574: }
! 1575: out:
! 1576: vp = nd.ni_vp;
! 1577: if (!error) {
! 1578: bzero((caddr_t)fhp, sizeof(nfh));
! 1579: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
! 1580: error = VFS_VPTOFH(vp, &fhp->fh_fid);
! 1581: if (!error)
! 1582: error = VOP_GETATTR(vp, &va, cred, procp);
! 1583: vput(vp);
! 1584: }
! 1585: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 1586: vrele(dirp);
! 1587: nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
! 1588: if (!error) {
! 1589: nfsm_srvpostop_fh(fhp);
! 1590: nfsm_srvpostop_attr(0, &va);
! 1591: }
! 1592: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1593: return (0);
! 1594: nfsmout:
! 1595: if (dirp)
! 1596: vrele(dirp);
! 1597: if (nd.ni_cnd.cn_nameiop) {
! 1598: vrele(nd.ni_startdir);
! 1599: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 1600: }
! 1601: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1602: if (nd.ni_dvp == nd.ni_vp)
! 1603: vrele(nd.ni_dvp);
! 1604: else
! 1605: vput(nd.ni_dvp);
! 1606: if (nd.ni_vp)
! 1607: vput(nd.ni_vp);
! 1608: return (error);
! 1609: }
! 1610:
! 1611: /*
! 1612: * nfs remove service
! 1613: */
! 1614: int
! 1615: nfsrv_remove(nfsd, slp, procp, mrq)
! 1616: struct nfsrv_descript *nfsd;
! 1617: struct nfssvc_sock *slp;
! 1618: struct proc *procp;
! 1619: struct mbuf **mrq;
! 1620: {
! 1621: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 1622: struct mbuf *nam = nfsd->nd_nam;
! 1623: caddr_t dpos = nfsd->nd_dpos;
! 1624: struct ucred *cred = &nfsd->nd_cr;
! 1625: struct nameidata nd;
! 1626: u_int32_t *tl;
! 1627: int32_t t1;
! 1628: caddr_t bpos;
! 1629: int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
! 1630: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 1631: char *cp2;
! 1632: struct mbuf *mb, *mreq;
! 1633: struct vnode *vp, *dirp;
! 1634: struct vattr dirfor, diraft;
! 1635: nfsfh_t nfh;
! 1636: fhandle_t *fhp;
! 1637: u_quad_t frev;
! 1638:
! 1639: #ifndef nolint
! 1640: vp = (struct vnode *)0;
! 1641: #endif
! 1642: fhp = &nfh.fh_generic;
! 1643: nfsm_srvmtofh(fhp);
! 1644: nfsm_srvnamesiz(len);
! 1645: nd.ni_cnd.cn_cred = cred;
! 1646: nd.ni_cnd.cn_nameiop = DELETE;
! 1647: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
! 1648: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 1649: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 1650: if (dirp) {
! 1651: if (v3)
! 1652: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
! 1653: procp);
! 1654: else
! 1655: vrele(dirp);
! 1656: }
! 1657: if (!error) {
! 1658: vp = nd.ni_vp;
! 1659: if (vp->v_type == VDIR &&
! 1660: (error = suser_ucred(cred)) != 0)
! 1661: goto out;
! 1662: /*
! 1663: * The root of a mounted filesystem cannot be deleted.
! 1664: */
! 1665: if (vp->v_flag & VROOT) {
! 1666: error = EBUSY;
! 1667: goto out;
! 1668: }
! 1669: if (vp->v_flag & VTEXT)
! 1670: uvm_vnp_uncache(vp);
! 1671: out:
! 1672: if (!error) {
! 1673: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
! 1674: } else {
! 1675: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1676: if (nd.ni_dvp == vp)
! 1677: vrele(nd.ni_dvp);
! 1678: else
! 1679: vput(nd.ni_dvp);
! 1680: vput(vp);
! 1681: }
! 1682: }
! 1683: if (dirp && v3) {
! 1684: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 1685: vrele(dirp);
! 1686: }
! 1687: nfsm_reply(NFSX_WCCDATA(v3));
! 1688: if (v3) {
! 1689: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1690: return (0);
! 1691: }
! 1692: nfsm_srvdone;
! 1693: }
! 1694:
! 1695: /*
! 1696: * nfs rename service
! 1697: */
! 1698: int
! 1699: nfsrv_rename(nfsd, slp, procp, mrq)
! 1700: struct nfsrv_descript *nfsd;
! 1701: struct nfssvc_sock *slp;
! 1702: struct proc *procp;
! 1703: struct mbuf **mrq;
! 1704: {
! 1705: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 1706: struct mbuf *nam = nfsd->nd_nam;
! 1707: caddr_t dpos = nfsd->nd_dpos;
! 1708: struct ucred *cred = &nfsd->nd_cr;
! 1709: u_int32_t *tl;
! 1710: int32_t t1;
! 1711: caddr_t bpos;
! 1712: int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
! 1713: int tdirfor_ret = 1, tdiraft_ret = 1;
! 1714: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 1715: char *cp2;
! 1716: struct mbuf *mb, *mreq;
! 1717: struct nameidata fromnd, tond;
! 1718: struct vnode *fvp = NULL, *tvp, *tdvp, *fdirp = NULL;
! 1719: struct vnode *tdirp = NULL;
! 1720: struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
! 1721: nfsfh_t fnfh, tnfh;
! 1722: fhandle_t *ffhp, *tfhp;
! 1723: u_quad_t frev;
! 1724: uid_t saved_uid;
! 1725:
! 1726: ffhp = &fnfh.fh_generic;
! 1727: tfhp = &tnfh.fh_generic;
! 1728: fromnd.ni_cnd.cn_nameiop = 0;
! 1729: tond.ni_cnd.cn_nameiop = 0;
! 1730: nfsm_srvmtofh(ffhp);
! 1731: nfsm_srvnamesiz(len);
! 1732: /*
! 1733: * Remember our original uid so that we can reset cr_uid before
! 1734: * the second nfs_namei() call, in case it is remapped.
! 1735: */
! 1736: saved_uid = cred->cr_uid;
! 1737: fromnd.ni_cnd.cn_cred = cred;
! 1738: fromnd.ni_cnd.cn_nameiop = DELETE;
! 1739: fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
! 1740: error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
! 1741: &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 1742: if (fdirp) {
! 1743: if (v3)
! 1744: fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
! 1745: procp);
! 1746: else {
! 1747: vrele(fdirp);
! 1748: fdirp = (struct vnode *)0;
! 1749: }
! 1750: }
! 1751: if (error) {
! 1752: nfsm_reply(2 * NFSX_WCCDATA(v3));
! 1753: nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
! 1754: nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
! 1755: if (fdirp)
! 1756: vrele(fdirp);
! 1757: return (0);
! 1758: }
! 1759: fvp = fromnd.ni_vp;
! 1760: nfsm_srvmtofh(tfhp);
! 1761: nfsm_strsiz(len2, NFS_MAXNAMLEN);
! 1762: cred->cr_uid = saved_uid;
! 1763: tond.ni_cnd.cn_cred = cred;
! 1764: tond.ni_cnd.cn_nameiop = RENAME;
! 1765: tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
! 1766: error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
! 1767: &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 1768: if (tdirp) {
! 1769: if (v3)
! 1770: tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
! 1771: procp);
! 1772: else {
! 1773: vrele(tdirp);
! 1774: tdirp = (struct vnode *)0;
! 1775: }
! 1776: }
! 1777: if (error) {
! 1778: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
! 1779: vrele(fromnd.ni_dvp);
! 1780: vrele(fvp);
! 1781: goto out1;
! 1782: }
! 1783: tdvp = tond.ni_dvp;
! 1784: tvp = tond.ni_vp;
! 1785: if (tvp != NULL) {
! 1786: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
! 1787: error = v3 ? EEXIST : EISDIR;
! 1788: goto out;
! 1789: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
! 1790: error = v3 ? EEXIST : ENOTDIR;
! 1791: goto out;
! 1792: }
! 1793: if (tvp->v_type == VDIR && tvp->v_mountedhere) {
! 1794: error = v3 ? EXDEV : ENOTEMPTY;
! 1795: goto out;
! 1796: }
! 1797: }
! 1798: if (fvp->v_type == VDIR && fvp->v_mountedhere) {
! 1799: error = v3 ? EXDEV : ENOTEMPTY;
! 1800: goto out;
! 1801: }
! 1802: if (fvp->v_mount != tdvp->v_mount) {
! 1803: error = v3 ? EXDEV : ENOTEMPTY;
! 1804: goto out;
! 1805: }
! 1806: if (fvp == tdvp)
! 1807: error = v3 ? EINVAL : ENOTEMPTY;
! 1808: /*
! 1809: * If source is the same as the destination (that is the
! 1810: * same vnode with the same name in the same directory),
! 1811: * then there is nothing to do.
! 1812: */
! 1813: if (fvp == tvp && fromnd.ni_dvp == tdvp &&
! 1814: fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
! 1815: !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
! 1816: fromnd.ni_cnd.cn_namelen))
! 1817: error = -1;
! 1818: out:
! 1819: if (!error) {
! 1820: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
! 1821: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
! 1822: } else {
! 1823: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
! 1824: if (tdvp == tvp)
! 1825: vrele(tdvp);
! 1826: else
! 1827: vput(tdvp);
! 1828: if (tvp)
! 1829: vput(tvp);
! 1830: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
! 1831: vrele(fromnd.ni_dvp);
! 1832: vrele(fvp);
! 1833: if (error == -1)
! 1834: error = 0;
! 1835: }
! 1836: vrele(tond.ni_startdir);
! 1837: pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
! 1838: out1:
! 1839: if (fdirp) {
! 1840: fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
! 1841: vrele(fdirp);
! 1842: }
! 1843: if (tdirp) {
! 1844: tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
! 1845: vrele(tdirp);
! 1846: }
! 1847: vrele(fromnd.ni_startdir);
! 1848: pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
! 1849: nfsm_reply(2 * NFSX_WCCDATA(v3));
! 1850: if (v3) {
! 1851: nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
! 1852: nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
! 1853: }
! 1854: return (0);
! 1855:
! 1856: nfsmout:
! 1857: if (fdirp)
! 1858: vrele(fdirp);
! 1859: if (tdirp)
! 1860: vrele(tdirp);
! 1861: if (tond.ni_cnd.cn_nameiop) {
! 1862: vrele(tond.ni_startdir);
! 1863: pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
! 1864: }
! 1865: if (fromnd.ni_cnd.cn_nameiop) {
! 1866: vrele(fromnd.ni_startdir);
! 1867: pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
! 1868: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
! 1869: vrele(fromnd.ni_dvp);
! 1870: vrele(fvp);
! 1871: }
! 1872: return (error);
! 1873: }
! 1874:
! 1875: /*
! 1876: * nfs link service
! 1877: */
! 1878: int
! 1879: nfsrv_link(nfsd, slp, procp, mrq)
! 1880: struct nfsrv_descript *nfsd;
! 1881: struct nfssvc_sock *slp;
! 1882: struct proc *procp;
! 1883: struct mbuf **mrq;
! 1884: {
! 1885: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 1886: struct mbuf *nam = nfsd->nd_nam;
! 1887: caddr_t dpos = nfsd->nd_dpos;
! 1888: struct ucred *cred = &nfsd->nd_cr;
! 1889: struct nameidata nd;
! 1890: u_int32_t *tl;
! 1891: int32_t t1;
! 1892: caddr_t bpos;
! 1893: int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1;
! 1894: int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
! 1895: char *cp2;
! 1896: struct mbuf *mb, *mreq;
! 1897: struct vnode *vp, *xp, *dirp = (struct vnode *)0;
! 1898: struct vattr dirfor, diraft, at;
! 1899: nfsfh_t nfh, dnfh;
! 1900: fhandle_t *fhp, *dfhp;
! 1901: u_quad_t frev;
! 1902:
! 1903: fhp = &nfh.fh_generic;
! 1904: dfhp = &dnfh.fh_generic;
! 1905: nfsm_srvmtofh(fhp);
! 1906: nfsm_srvmtofh(dfhp);
! 1907: nfsm_srvnamesiz(len);
! 1908: error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
! 1909: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 1910: if (error) {
! 1911: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
! 1912: nfsm_srvpostop_attr(getret, &at);
! 1913: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1914: return (0);
! 1915: }
! 1916: if (vp->v_type == VDIR && (error = suser_ucred(cred)) != 0)
! 1917: goto out1;
! 1918: nd.ni_cnd.cn_cred = cred;
! 1919: nd.ni_cnd.cn_nameiop = CREATE;
! 1920: nd.ni_cnd.cn_flags = LOCKPARENT;
! 1921: error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
! 1922: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 1923: if (dirp) {
! 1924: if (v3)
! 1925: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
! 1926: procp);
! 1927: else {
! 1928: vrele(dirp);
! 1929: dirp = (struct vnode *)0;
! 1930: }
! 1931: }
! 1932: if (error)
! 1933: goto out1;
! 1934: xp = nd.ni_vp;
! 1935: if (xp != NULL) {
! 1936: error = EEXIST;
! 1937: goto out;
! 1938: }
! 1939: xp = nd.ni_dvp;
! 1940: if (vp->v_mount != xp->v_mount)
! 1941: error = EXDEV;
! 1942: out:
! 1943: if (!error) {
! 1944: error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
! 1945: } else {
! 1946: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1947: if (nd.ni_dvp == nd.ni_vp)
! 1948: vrele(nd.ni_dvp);
! 1949: else
! 1950: vput(nd.ni_dvp);
! 1951: if (nd.ni_vp)
! 1952: vrele(nd.ni_vp);
! 1953: }
! 1954: out1:
! 1955: if (v3)
! 1956: getret = VOP_GETATTR(vp, &at, cred, procp);
! 1957: if (dirp) {
! 1958: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 1959: vrele(dirp);
! 1960: }
! 1961: vrele(vp);
! 1962: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
! 1963: if (v3) {
! 1964: nfsm_srvpostop_attr(getret, &at);
! 1965: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 1966: return (0);
! 1967: }
! 1968: nfsm_srvdone;
! 1969: }
! 1970:
! 1971: /*
! 1972: * nfs symbolic link service
! 1973: */
! 1974: int
! 1975: nfsrv_symlink(nfsd, slp, procp, mrq)
! 1976: struct nfsrv_descript *nfsd;
! 1977: struct nfssvc_sock *slp;
! 1978: struct proc *procp;
! 1979: struct mbuf **mrq;
! 1980: {
! 1981: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 1982: struct mbuf *nam = nfsd->nd_nam;
! 1983: caddr_t dpos = nfsd->nd_dpos;
! 1984: struct ucred *cred = &nfsd->nd_cr;
! 1985: struct vattr va, dirfor, diraft;
! 1986: struct nameidata nd;
! 1987: u_int32_t *tl;
! 1988: int32_t t1;
! 1989: struct nfsv2_sattr *sp;
! 1990: char *bpos, *pathcp = NULL, *cp2;
! 1991: struct uio io;
! 1992: struct iovec iv;
! 1993: int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1;
! 1994: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 1995: struct mbuf *mb, *mreq, *mb2;
! 1996: struct vnode *dirp = (struct vnode *)0;
! 1997: nfsfh_t nfh;
! 1998: fhandle_t *fhp;
! 1999: u_quad_t frev;
! 2000:
! 2001: nd.ni_cnd.cn_nameiop = 0;
! 2002: fhp = &nfh.fh_generic;
! 2003: nfsm_srvmtofh(fhp);
! 2004: nfsm_srvnamesiz(len);
! 2005: nd.ni_cnd.cn_cred = cred;
! 2006: nd.ni_cnd.cn_nameiop = CREATE;
! 2007: nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
! 2008: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 2009: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 2010: if (dirp) {
! 2011: if (v3)
! 2012: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
! 2013: procp);
! 2014: else {
! 2015: vrele(dirp);
! 2016: dirp = (struct vnode *)0;
! 2017: }
! 2018: }
! 2019: if (error)
! 2020: goto out;
! 2021: VATTR_NULL(&va);
! 2022: if (v3)
! 2023: nfsm_srvsattr(&va);
! 2024: nfsm_strsiz(len2, NFS_MAXPATHLEN);
! 2025: MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
! 2026: iv.iov_base = pathcp;
! 2027: iv.iov_len = len2;
! 2028: io.uio_resid = len2;
! 2029: io.uio_offset = 0;
! 2030: io.uio_iov = &iv;
! 2031: io.uio_iovcnt = 1;
! 2032: io.uio_segflg = UIO_SYSSPACE;
! 2033: io.uio_rw = UIO_READ;
! 2034: io.uio_procp = (struct proc *)0;
! 2035: nfsm_mtouio(&io, len2);
! 2036: if (!v3) {
! 2037: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 2038: va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
! 2039: }
! 2040: *(pathcp + len2) = '\0';
! 2041: if (nd.ni_vp) {
! 2042: vrele(nd.ni_startdir);
! 2043: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 2044: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2045: if (nd.ni_dvp == nd.ni_vp)
! 2046: vrele(nd.ni_dvp);
! 2047: else
! 2048: vput(nd.ni_dvp);
! 2049: vrele(nd.ni_vp);
! 2050: error = EEXIST;
! 2051: goto out;
! 2052: }
! 2053: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
! 2054: if (error)
! 2055: vrele(nd.ni_startdir);
! 2056: else {
! 2057: if (v3) {
! 2058: nd.ni_cnd.cn_nameiop = LOOKUP;
! 2059: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
! 2060: nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
! 2061: nd.ni_cnd.cn_proc = procp;
! 2062: nd.ni_cnd.cn_cred = cred;
! 2063: error = lookup(&nd);
! 2064: if (!error) {
! 2065: bzero((caddr_t)fhp, sizeof(nfh));
! 2066: fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
! 2067: error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
! 2068: if (!error)
! 2069: error = VOP_GETATTR(nd.ni_vp, &va, cred,
! 2070: procp);
! 2071: vput(nd.ni_vp);
! 2072: }
! 2073: } else
! 2074: vrele(nd.ni_startdir);
! 2075: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 2076: }
! 2077: out:
! 2078: if (pathcp)
! 2079: FREE(pathcp, M_TEMP);
! 2080: if (dirp) {
! 2081: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 2082: vrele(dirp);
! 2083: }
! 2084: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
! 2085: if (v3) {
! 2086: if (!error) {
! 2087: nfsm_srvpostop_fh(fhp);
! 2088: nfsm_srvpostop_attr(0, &va);
! 2089: }
! 2090: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 2091: }
! 2092: return (0);
! 2093: nfsmout:
! 2094: if (nd.ni_cnd.cn_nameiop) {
! 2095: vrele(nd.ni_startdir);
! 2096: pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
! 2097: }
! 2098: if (dirp)
! 2099: vrele(dirp);
! 2100: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2101: if (nd.ni_dvp == nd.ni_vp)
! 2102: vrele(nd.ni_dvp);
! 2103: else
! 2104: vput(nd.ni_dvp);
! 2105: if (nd.ni_vp)
! 2106: vrele(nd.ni_vp);
! 2107: if (pathcp)
! 2108: FREE(pathcp, M_TEMP);
! 2109: return (error);
! 2110: }
! 2111:
! 2112: /*
! 2113: * nfs mkdir service
! 2114: */
! 2115: int
! 2116: nfsrv_mkdir(nfsd, slp, procp, mrq)
! 2117: struct nfsrv_descript *nfsd;
! 2118: struct nfssvc_sock *slp;
! 2119: struct proc *procp;
! 2120: struct mbuf **mrq;
! 2121: {
! 2122: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 2123: struct mbuf *nam = nfsd->nd_nam;
! 2124: caddr_t dpos = nfsd->nd_dpos;
! 2125: struct ucred *cred = &nfsd->nd_cr;
! 2126: struct vattr va, dirfor, diraft;
! 2127: struct nfs_fattr *fp;
! 2128: struct nameidata nd;
! 2129: caddr_t cp;
! 2130: u_int32_t *tl;
! 2131: int32_t t1;
! 2132: caddr_t bpos;
! 2133: int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
! 2134: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 2135: char *cp2;
! 2136: struct mbuf *mb, *mb2, *mreq;
! 2137: struct vnode *vp, *dirp = (struct vnode *)0;
! 2138: nfsfh_t nfh;
! 2139: fhandle_t *fhp;
! 2140: u_quad_t frev;
! 2141:
! 2142: fhp = &nfh.fh_generic;
! 2143: nfsm_srvmtofh(fhp);
! 2144: nfsm_srvnamesiz(len);
! 2145: nd.ni_cnd.cn_cred = cred;
! 2146: nd.ni_cnd.cn_nameiop = CREATE;
! 2147: nd.ni_cnd.cn_flags = LOCKPARENT;
! 2148: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 2149: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 2150: if (dirp) {
! 2151: if (v3)
! 2152: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
! 2153: procp);
! 2154: else {
! 2155: vrele(dirp);
! 2156: dirp = (struct vnode *)0;
! 2157: }
! 2158: }
! 2159: if (error) {
! 2160: nfsm_reply(NFSX_WCCDATA(v3));
! 2161: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 2162: if (dirp)
! 2163: vrele(dirp);
! 2164: return (0);
! 2165: }
! 2166: VATTR_NULL(&va);
! 2167: if (v3) {
! 2168: nfsm_srvsattr(&va);
! 2169: } else {
! 2170: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2171: va.va_mode = nfstov_mode(*tl++);
! 2172: }
! 2173: va.va_type = VDIR;
! 2174: vp = nd.ni_vp;
! 2175: if (vp != NULL) {
! 2176: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2177: if (nd.ni_dvp == vp)
! 2178: vrele(nd.ni_dvp);
! 2179: else
! 2180: vput(nd.ni_dvp);
! 2181: vrele(vp);
! 2182: error = EEXIST;
! 2183: goto out;
! 2184: }
! 2185: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
! 2186: if (!error) {
! 2187: vp = nd.ni_vp;
! 2188: bzero((caddr_t)fhp, sizeof(nfh));
! 2189: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
! 2190: error = VFS_VPTOFH(vp, &fhp->fh_fid);
! 2191: if (!error)
! 2192: error = VOP_GETATTR(vp, &va, cred, procp);
! 2193: vput(vp);
! 2194: }
! 2195: out:
! 2196: if (dirp) {
! 2197: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 2198: vrele(dirp);
! 2199: }
! 2200: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
! 2201: if (v3) {
! 2202: if (!error) {
! 2203: nfsm_srvpostop_fh(fhp);
! 2204: nfsm_srvpostop_attr(0, &va);
! 2205: }
! 2206: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 2207: } else {
! 2208: nfsm_srvfhtom(fhp, v3);
! 2209: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
! 2210: nfsm_srvfillattr(&va, fp);
! 2211: }
! 2212: return (0);
! 2213: nfsmout:
! 2214: if (dirp)
! 2215: vrele(dirp);
! 2216: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2217: if (nd.ni_dvp == nd.ni_vp)
! 2218: vrele(nd.ni_dvp);
! 2219: else
! 2220: vput(nd.ni_dvp);
! 2221: if (nd.ni_vp)
! 2222: vrele(nd.ni_vp);
! 2223: return (error);
! 2224: }
! 2225:
! 2226: /*
! 2227: * nfs rmdir service
! 2228: */
! 2229: int
! 2230: nfsrv_rmdir(nfsd, slp, procp, mrq)
! 2231: struct nfsrv_descript *nfsd;
! 2232: struct nfssvc_sock *slp;
! 2233: struct proc *procp;
! 2234: struct mbuf **mrq;
! 2235: {
! 2236: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 2237: struct mbuf *nam = nfsd->nd_nam;
! 2238: caddr_t dpos = nfsd->nd_dpos;
! 2239: struct ucred *cred = &nfsd->nd_cr;
! 2240: u_int32_t *tl;
! 2241: int32_t t1;
! 2242: caddr_t bpos;
! 2243: int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
! 2244: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 2245: char *cp2;
! 2246: struct mbuf *mb, *mreq;
! 2247: struct vnode *vp, *dirp = (struct vnode *)0;
! 2248: struct vattr dirfor, diraft;
! 2249: nfsfh_t nfh;
! 2250: fhandle_t *fhp;
! 2251: struct nameidata nd;
! 2252: u_quad_t frev;
! 2253:
! 2254: fhp = &nfh.fh_generic;
! 2255: nfsm_srvmtofh(fhp);
! 2256: nfsm_srvnamesiz(len);
! 2257: nd.ni_cnd.cn_cred = cred;
! 2258: nd.ni_cnd.cn_nameiop = DELETE;
! 2259: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
! 2260: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
! 2261: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
! 2262: if (dirp) {
! 2263: if (v3)
! 2264: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
! 2265: procp);
! 2266: else {
! 2267: vrele(dirp);
! 2268: dirp = (struct vnode *)0;
! 2269: }
! 2270: }
! 2271: if (error) {
! 2272: nfsm_reply(NFSX_WCCDATA(v3));
! 2273: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 2274: if (dirp)
! 2275: vrele(dirp);
! 2276: return (0);
! 2277: }
! 2278: vp = nd.ni_vp;
! 2279: if (vp->v_type != VDIR) {
! 2280: error = ENOTDIR;
! 2281: goto out;
! 2282: }
! 2283: /*
! 2284: * No rmdir "." please.
! 2285: */
! 2286: if (nd.ni_dvp == vp) {
! 2287: error = EINVAL;
! 2288: goto out;
! 2289: }
! 2290: /*
! 2291: * The root of a mounted filesystem cannot be deleted.
! 2292: */
! 2293: if (vp->v_flag & VROOT)
! 2294: error = EBUSY;
! 2295: out:
! 2296: if (!error) {
! 2297: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
! 2298: } else {
! 2299: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2300: if (nd.ni_dvp == nd.ni_vp)
! 2301: vrele(nd.ni_dvp);
! 2302: else
! 2303: vput(nd.ni_dvp);
! 2304: vput(vp);
! 2305: }
! 2306: if (dirp) {
! 2307: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
! 2308: vrele(dirp);
! 2309: }
! 2310: nfsm_reply(NFSX_WCCDATA(v3));
! 2311: if (v3) {
! 2312: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
! 2313: return (0);
! 2314: }
! 2315: nfsm_srvdone;
! 2316: }
! 2317:
! 2318: /*
! 2319: * nfs readdir service
! 2320: * - mallocs what it thinks is enough to read
! 2321: * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
! 2322: * - calls VOP_READDIR()
! 2323: * - loops around building the reply
! 2324: * if the output generated exceeds count break out of loop
! 2325: * The nfsm_clget macro is used here so that the reply will be packed
! 2326: * tightly in mbuf clusters.
! 2327: * - it only knows that it has encountered eof when the VOP_READDIR()
! 2328: * reads nothing
! 2329: * - as such one readdir rpc will return eof false although you are there
! 2330: * and then the next will return eof
! 2331: * - it trims out records with d_fileno == 0
! 2332: * this doesn't matter for Unix clients, but they might confuse clients
! 2333: * for other os'.
! 2334: * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
! 2335: * than requested, but this may not apply to all filesystems. For
! 2336: * example, client NFS does not { although it is never remote mounted
! 2337: * anyhow }
! 2338: * The alternate call nfsrv_readdirplus() does lookups as well.
! 2339: * PS: The NFS protocol spec. does not clarify what the "count" byte
! 2340: * argument is a count of.. just name strings and file id's or the
! 2341: * entire reply rpc or ...
! 2342: * I tried just file name and id sizes and it confused the Sun client,
! 2343: * so I am using the full rpc size now. The "paranoia.." comment refers
! 2344: * to including the status longwords that are not a part of the dir.
! 2345: * "entry" structures, but are in the rpc.
! 2346: */
! 2347: struct flrep {
! 2348: nfsuint64 fl_off;
! 2349: u_int32_t fl_postopok;
! 2350: u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
! 2351: u_int32_t fl_fhok;
! 2352: u_int32_t fl_fhsize;
! 2353: u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
! 2354: };
! 2355:
! 2356: int
! 2357: nfsrv_readdir(nfsd, slp, procp, mrq)
! 2358: struct nfsrv_descript *nfsd;
! 2359: struct nfssvc_sock *slp;
! 2360: struct proc *procp;
! 2361: struct mbuf **mrq;
! 2362: {
! 2363: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 2364: struct mbuf *nam = nfsd->nd_nam;
! 2365: caddr_t dpos = nfsd->nd_dpos;
! 2366: struct ucred *cred = &nfsd->nd_cr;
! 2367: char *bp, *be;
! 2368: struct mbuf *mp;
! 2369: struct dirent *dp;
! 2370: caddr_t cp;
! 2371: u_int32_t *tl;
! 2372: int32_t t1;
! 2373: caddr_t bpos;
! 2374: struct mbuf *mb, *mb2, *mreq, *mp2;
! 2375: char *cpos, *cend, *cp2, *rbuf;
! 2376: struct vnode *vp;
! 2377: struct vattr at;
! 2378: nfsfh_t nfh;
! 2379: fhandle_t *fhp;
! 2380: struct uio io;
! 2381: struct iovec iv;
! 2382: int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
! 2383: int siz, cnt, fullsiz, eofflag, rdonly, ncookies;
! 2384: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 2385: u_quad_t frev, off, toff, verf;
! 2386: u_long *cookies = NULL, *cookiep;
! 2387:
! 2388: fhp = &nfh.fh_generic;
! 2389: nfsm_srvmtofh(fhp);
! 2390: if (v3) {
! 2391: nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
! 2392: toff = fxdr_hyper(tl);
! 2393: tl += 2;
! 2394: verf = fxdr_hyper(tl);
! 2395: tl += 2;
! 2396: } else {
! 2397: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 2398: toff = fxdr_unsigned(u_quad_t, *tl++);
! 2399: }
! 2400: off = toff;
! 2401: cnt = fxdr_unsigned(int, *tl);
! 2402: siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
! 2403: xfer = NFS_SRVMAXDATA(nfsd);
! 2404: if (siz > xfer)
! 2405: siz = xfer;
! 2406: if (cnt > xfer)
! 2407: cnt = xfer;
! 2408: fullsiz = siz;
! 2409: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 2410: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 2411: if (error) {
! 2412: nfsm_reply(NFSX_UNSIGNED);
! 2413: nfsm_srvpostop_attr(getret, &at);
! 2414: return (0);
! 2415: }
! 2416: if (v3) {
! 2417: error = getret = VOP_GETATTR(vp, &at, cred, procp);
! 2418: #ifdef NFS3_STRICTVERF
! 2419: /*
! 2420: * XXX This check is too strict for Solaris 2.5 clients.
! 2421: */
! 2422: if (!error && toff && verf != at.va_filerev)
! 2423: error = NFSERR_BAD_COOKIE;
! 2424: #endif
! 2425: }
! 2426: if (!error)
! 2427: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
! 2428: if (error) {
! 2429: vput(vp);
! 2430: nfsm_reply(NFSX_POSTOPATTR(v3));
! 2431: nfsm_srvpostop_attr(getret, &at);
! 2432: return (0);
! 2433: }
! 2434: VOP_UNLOCK(vp, 0, procp);
! 2435: MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
! 2436: again:
! 2437: iv.iov_base = rbuf;
! 2438: iv.iov_len = fullsiz;
! 2439: io.uio_iov = &iv;
! 2440: io.uio_iovcnt = 1;
! 2441: io.uio_offset = (off_t)off;
! 2442: io.uio_resid = fullsiz;
! 2443: io.uio_segflg = UIO_SYSSPACE;
! 2444: io.uio_rw = UIO_READ;
! 2445: io.uio_procp = (struct proc *)0;
! 2446: eofflag = 0;
! 2447:
! 2448: if (cookies) {
! 2449: free((caddr_t)cookies, M_TEMP);
! 2450: cookies = NULL;
! 2451: }
! 2452:
! 2453: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
! 2454: error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
! 2455:
! 2456: off = (off_t)io.uio_offset;
! 2457: if (!cookies && !error)
! 2458: error = NFSERR_PERM;
! 2459: if (v3) {
! 2460: getret = VOP_GETATTR(vp, &at, cred, procp);
! 2461: if (!error)
! 2462: error = getret;
! 2463: }
! 2464:
! 2465: VOP_UNLOCK(vp, 0, procp);
! 2466: if (error) {
! 2467: vrele(vp);
! 2468: free((caddr_t)rbuf, M_TEMP);
! 2469: if (cookies)
! 2470: free((caddr_t)cookies, M_TEMP);
! 2471: nfsm_reply(NFSX_POSTOPATTR(v3));
! 2472: nfsm_srvpostop_attr(getret, &at);
! 2473: return (0);
! 2474: }
! 2475: if (io.uio_resid) {
! 2476: siz -= io.uio_resid;
! 2477:
! 2478: /*
! 2479: * If nothing read, return eof
! 2480: * rpc reply
! 2481: */
! 2482: if (siz == 0) {
! 2483: vrele(vp);
! 2484: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
! 2485: 2 * NFSX_UNSIGNED);
! 2486: if (v3) {
! 2487: nfsm_srvpostop_attr(getret, &at);
! 2488: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 2489: txdr_hyper(at.va_filerev, tl);
! 2490: tl += 2;
! 2491: } else
! 2492: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 2493: *tl++ = nfs_false;
! 2494: *tl = nfs_true;
! 2495: FREE((caddr_t)rbuf, M_TEMP);
! 2496: FREE((caddr_t)cookies, M_TEMP);
! 2497: return (0);
! 2498: }
! 2499: }
! 2500:
! 2501: /*
! 2502: * Check for degenerate cases of nothing useful read.
! 2503: * If so go try again
! 2504: */
! 2505: cpos = rbuf;
! 2506: cend = rbuf + siz;
! 2507: dp = (struct dirent *)cpos;
! 2508: cookiep = cookies;
! 2509:
! 2510: while (cpos < cend && ncookies > 0 && dp->d_fileno == 0) {
! 2511: cpos += dp->d_reclen;
! 2512: dp = (struct dirent *)cpos;
! 2513: cookiep++;
! 2514: ncookies--;
! 2515: }
! 2516: if (cpos >= cend || ncookies == 0) {
! 2517: toff = off;
! 2518: siz = fullsiz;
! 2519: goto again;
! 2520: }
! 2521:
! 2522: len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
! 2523: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
! 2524: if (v3) {
! 2525: nfsm_srvpostop_attr(getret, &at);
! 2526: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 2527: txdr_hyper(at.va_filerev, tl);
! 2528: }
! 2529: mp = mp2 = mb;
! 2530: bp = bpos;
! 2531: be = bp + M_TRAILINGSPACE(mp);
! 2532:
! 2533: /* Loop through the records and build reply */
! 2534: while (cpos < cend && ncookies > 0) {
! 2535: if (dp->d_fileno != 0) {
! 2536: nlen = dp->d_namlen;
! 2537: rem = nfsm_rndup(nlen)-nlen;
! 2538: len += (4 * NFSX_UNSIGNED + nlen + rem);
! 2539: if (v3)
! 2540: len += 2 * NFSX_UNSIGNED;
! 2541: if (len > cnt) {
! 2542: eofflag = 0;
! 2543: break;
! 2544: }
! 2545: /*
! 2546: * Build the directory record xdr from
! 2547: * the dirent entry.
! 2548: */
! 2549: nfsm_clget;
! 2550: *tl = nfs_true;
! 2551: bp += NFSX_UNSIGNED;
! 2552: if (v3) {
! 2553: nfsm_clget;
! 2554: *tl = 0;
! 2555: bp += NFSX_UNSIGNED;
! 2556: }
! 2557: nfsm_clget;
! 2558: *tl = txdr_unsigned(dp->d_fileno);
! 2559: bp += NFSX_UNSIGNED;
! 2560: nfsm_clget;
! 2561: *tl = txdr_unsigned(nlen);
! 2562: bp += NFSX_UNSIGNED;
! 2563:
! 2564: /* And loop around copying the name */
! 2565: xfer = nlen;
! 2566: cp = dp->d_name;
! 2567: while (xfer > 0) {
! 2568: nfsm_clget;
! 2569: if ((bp+xfer) > be)
! 2570: tsiz = be-bp;
! 2571: else
! 2572: tsiz = xfer;
! 2573: bcopy(cp, bp, tsiz);
! 2574: bp += tsiz;
! 2575: xfer -= tsiz;
! 2576: if (xfer > 0)
! 2577: cp += tsiz;
! 2578: }
! 2579: /* And null pad to an int32_t boundary */
! 2580: for (i = 0; i < rem; i++)
! 2581: *bp++ = '\0';
! 2582: nfsm_clget;
! 2583:
! 2584: /* Finish off the record */
! 2585: if (v3) {
! 2586: *tl = 0;
! 2587: bp += NFSX_UNSIGNED;
! 2588: nfsm_clget;
! 2589: }
! 2590: *tl = txdr_unsigned(*cookiep);
! 2591: bp += NFSX_UNSIGNED;
! 2592: }
! 2593: cpos += dp->d_reclen;
! 2594: dp = (struct dirent *)cpos;
! 2595: cookiep++;
! 2596: ncookies--;
! 2597: }
! 2598: vrele(vp);
! 2599: nfsm_clget;
! 2600: *tl = nfs_false;
! 2601: bp += NFSX_UNSIGNED;
! 2602: nfsm_clget;
! 2603: if (eofflag)
! 2604: *tl = nfs_true;
! 2605: else
! 2606: *tl = nfs_false;
! 2607: bp += NFSX_UNSIGNED;
! 2608: if (mp != mb) {
! 2609: if (bp < be)
! 2610: mp->m_len = bp - mtod(mp, caddr_t);
! 2611: } else
! 2612: mp->m_len += bp - bpos;
! 2613: FREE((caddr_t)rbuf, M_TEMP);
! 2614: FREE((caddr_t)cookies, M_TEMP);
! 2615: nfsm_srvdone;
! 2616: }
! 2617:
! 2618: int
! 2619: nfsrv_readdirplus(nfsd, slp, procp, mrq)
! 2620: struct nfsrv_descript *nfsd;
! 2621: struct nfssvc_sock *slp;
! 2622: struct proc *procp;
! 2623: struct mbuf **mrq;
! 2624: {
! 2625: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 2626: struct mbuf *nam = nfsd->nd_nam;
! 2627: caddr_t dpos = nfsd->nd_dpos;
! 2628: struct ucred *cred = &nfsd->nd_cr;
! 2629: char *bp, *be;
! 2630: struct mbuf *mp;
! 2631: struct dirent *dp;
! 2632: caddr_t cp;
! 2633: u_int32_t *tl;
! 2634: int32_t t1;
! 2635: caddr_t bpos;
! 2636: struct mbuf *mb, *mb2, *mreq, *mp2;
! 2637: char *cpos, *cend, *cp2, *rbuf;
! 2638: struct vnode *vp, *nvp;
! 2639: struct flrep fl;
! 2640: nfsfh_t nfh;
! 2641: fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
! 2642: struct uio io;
! 2643: struct iovec iv;
! 2644: struct vattr va, at, *vap = &va;
! 2645: struct nfs_fattr *fp;
! 2646: int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
! 2647: int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies;
! 2648: u_quad_t frev, off, toff, verf;
! 2649: u_long *cookies = NULL, *cookiep;
! 2650:
! 2651: fhp = &nfh.fh_generic;
! 2652: nfsm_srvmtofh(fhp);
! 2653: nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
! 2654: toff = fxdr_hyper(tl);
! 2655: tl += 2;
! 2656: verf = fxdr_hyper(tl);
! 2657: tl += 2;
! 2658: siz = fxdr_unsigned(int, *tl++);
! 2659: cnt = fxdr_unsigned(int, *tl);
! 2660: off = toff;
! 2661: siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
! 2662: xfer = NFS_SRVMAXDATA(nfsd);
! 2663: if (siz > xfer)
! 2664: siz = xfer;
! 2665: if (cnt > xfer)
! 2666: cnt = xfer;
! 2667: fullsiz = siz;
! 2668: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 2669: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 2670: if (error) {
! 2671: nfsm_reply(NFSX_UNSIGNED);
! 2672: nfsm_srvpostop_attr(getret, &at);
! 2673: return (0);
! 2674: }
! 2675: error = getret = VOP_GETATTR(vp, &at, cred, procp);
! 2676: #ifdef NFS3_STRICTVERF
! 2677: /*
! 2678: * XXX This check is too strict for Solaris 2.5 clients.
! 2679: */
! 2680: if (!error && toff && verf != at.va_filerev)
! 2681: error = NFSERR_BAD_COOKIE;
! 2682: #endif
! 2683: if (!error) {
! 2684: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
! 2685: }
! 2686: if (error) {
! 2687: vput(vp);
! 2688: nfsm_reply(NFSX_V3POSTOPATTR);
! 2689: nfsm_srvpostop_attr(getret, &at);
! 2690: return (0);
! 2691: }
! 2692: VOP_UNLOCK(vp, 0, procp);
! 2693:
! 2694: MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
! 2695: again:
! 2696: iv.iov_base = rbuf;
! 2697: iv.iov_len = fullsiz;
! 2698: io.uio_iov = &iv;
! 2699: io.uio_iovcnt = 1;
! 2700: io.uio_offset = (off_t)off;
! 2701: io.uio_resid = fullsiz;
! 2702: io.uio_segflg = UIO_SYSSPACE;
! 2703: io.uio_rw = UIO_READ;
! 2704: io.uio_procp = (struct proc *)0;
! 2705: eofflag = 0;
! 2706:
! 2707: if (cookies) {
! 2708: free((caddr_t)cookies, M_TEMP);
! 2709: cookies = NULL;
! 2710: }
! 2711:
! 2712: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
! 2713: error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
! 2714:
! 2715: off = (u_quad_t)io.uio_offset;
! 2716: getret = VOP_GETATTR(vp, &at, cred, procp);
! 2717:
! 2718: VOP_UNLOCK(vp, 0, procp);
! 2719:
! 2720: if (!cookies && !error)
! 2721: error = NFSERR_PERM;
! 2722: if (!error)
! 2723: error = getret;
! 2724: if (error) {
! 2725: vrele(vp);
! 2726: if (cookies)
! 2727: free((caddr_t)cookies, M_TEMP);
! 2728: free((caddr_t)rbuf, M_TEMP);
! 2729: nfsm_reply(NFSX_V3POSTOPATTR);
! 2730: nfsm_srvpostop_attr(getret, &at);
! 2731: return (0);
! 2732: }
! 2733: if (io.uio_resid) {
! 2734: siz -= io.uio_resid;
! 2735:
! 2736: /*
! 2737: * If nothing read, return eof
! 2738: * rpc reply
! 2739: */
! 2740: if (siz == 0) {
! 2741: vrele(vp);
! 2742: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
! 2743: 2 * NFSX_UNSIGNED);
! 2744: nfsm_srvpostop_attr(getret, &at);
! 2745: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 2746: txdr_hyper(at.va_filerev, tl);
! 2747: tl += 2;
! 2748: *tl++ = nfs_false;
! 2749: *tl = nfs_true;
! 2750: FREE((caddr_t)cookies, M_TEMP);
! 2751: FREE((caddr_t)rbuf, M_TEMP);
! 2752: return (0);
! 2753: }
! 2754: }
! 2755:
! 2756: /*
! 2757: * Check for degenerate cases of nothing useful read.
! 2758: * If so go try again
! 2759: */
! 2760: cpos = rbuf;
! 2761: cend = rbuf + siz;
! 2762: dp = (struct dirent *)cpos;
! 2763: cookiep = cookies;
! 2764:
! 2765: while (cpos < cend && ncookies > 0 && dp->d_fileno == 0) {
! 2766: cpos += dp->d_reclen;
! 2767: dp = (struct dirent *)cpos;
! 2768: cookiep++;
! 2769: ncookies--;
! 2770: }
! 2771: if (cpos >= cend || ncookies == 0) {
! 2772: toff = off;
! 2773: siz = fullsiz;
! 2774: goto again;
! 2775: }
! 2776:
! 2777: /*
! 2778: * struct READDIRPLUS3resok {
! 2779: * postop_attr dir_attributes;
! 2780: * cookieverf3 cookieverf;
! 2781: * dirlistplus3 reply;
! 2782: * }
! 2783: *
! 2784: * struct dirlistplus3 {
! 2785: * entryplus3 *entries;
! 2786: * bool eof;
! 2787: * }
! 2788: */
! 2789: dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
! 2790: nfsm_reply(cnt);
! 2791: nfsm_srvpostop_attr(getret, &at);
! 2792: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 2793: txdr_hyper(at.va_filerev, tl);
! 2794: mp = mp2 = mb;
! 2795: bp = bpos;
! 2796: be = bp + M_TRAILINGSPACE(mp);
! 2797:
! 2798: /* Loop through the records and build reply */
! 2799: while (cpos < cend && ncookies > 0) {
! 2800: if (dp->d_fileno != 0) {
! 2801: nlen = dp->d_namlen;
! 2802: rem = nfsm_rndup(nlen)-nlen;
! 2803:
! 2804: /*
! 2805: * For readdir_and_lookup get the vnode using
! 2806: * the file number.
! 2807: */
! 2808: if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
! 2809: goto invalid;
! 2810: bzero((caddr_t)nfhp, NFSX_V3FH);
! 2811: nfhp->fh_fsid =
! 2812: nvp->v_mount->mnt_stat.f_fsid;
! 2813: if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
! 2814: vput(nvp);
! 2815: goto invalid;
! 2816: }
! 2817: if (VOP_GETATTR(nvp, vap, cred, procp)) {
! 2818: vput(nvp);
! 2819: goto invalid;
! 2820: }
! 2821: vput(nvp);
! 2822:
! 2823: /*
! 2824: * If either the dircount or maxcount will be
! 2825: * exceeded, get out now. Both of these lengths
! 2826: * are calculated conservatively, including all
! 2827: * XDR overheads.
! 2828: *
! 2829: * Each entry:
! 2830: * 2 * NFSX_UNSIGNED for fileid3
! 2831: * 1 * NFSX_UNSIGNED for length of name
! 2832: * nlen + rem == space the name takes up
! 2833: * 2 * NFSX_UNSIGNED for the cookie
! 2834: * 1 * NFSX_UNSIGNED to indicate if file handle present
! 2835: * 1 * NFSX_UNSIGNED for the file handle length
! 2836: * NFSX_V3FH == space our file handle takes up
! 2837: * NFSX_V3POSTOPATTR == space the attributes take up
! 2838: * 1 * NFSX_UNSIGNED for next pointer
! 2839: */
! 2840: len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
! 2841: NFSX_V3POSTOPATTR);
! 2842: dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
! 2843: if (len > cnt || dirlen > fullsiz) {
! 2844: eofflag = 0;
! 2845: break;
! 2846: }
! 2847:
! 2848: /*
! 2849: * Build the directory record xdr from
! 2850: * the dirent entry.
! 2851: */
! 2852: fp = (struct nfs_fattr *)&fl.fl_fattr;
! 2853: nfsm_srvfillattr(vap, fp);
! 2854: fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
! 2855: fl.fl_fhok = nfs_true;
! 2856: fl.fl_postopok = nfs_true;
! 2857: fl.fl_off.nfsuquad[0] = 0;
! 2858: fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
! 2859:
! 2860: nfsm_clget;
! 2861: *tl = nfs_true;
! 2862: bp += NFSX_UNSIGNED;
! 2863: nfsm_clget;
! 2864: *tl = 0;
! 2865: bp += NFSX_UNSIGNED;
! 2866: nfsm_clget;
! 2867: *tl = txdr_unsigned(dp->d_fileno);
! 2868: bp += NFSX_UNSIGNED;
! 2869: nfsm_clget;
! 2870: *tl = txdr_unsigned(nlen);
! 2871: bp += NFSX_UNSIGNED;
! 2872:
! 2873: /* And loop around copying the name */
! 2874: xfer = nlen;
! 2875: cp = dp->d_name;
! 2876: while (xfer > 0) {
! 2877: nfsm_clget;
! 2878: if ((bp + xfer) > be)
! 2879: tsiz = be - bp;
! 2880: else
! 2881: tsiz = xfer;
! 2882: bcopy(cp, bp, tsiz);
! 2883: bp += tsiz;
! 2884: xfer -= tsiz;
! 2885: if (xfer > 0)
! 2886: cp += tsiz;
! 2887: }
! 2888: /* And null pad to an int32_t boundary */
! 2889: for (i = 0; i < rem; i++)
! 2890: *bp++ = '\0';
! 2891:
! 2892: /*
! 2893: * Now copy the flrep structure out.
! 2894: */
! 2895: xfer = sizeof (struct flrep);
! 2896: cp = (caddr_t)&fl;
! 2897: while (xfer > 0) {
! 2898: nfsm_clget;
! 2899: if ((bp + xfer) > be)
! 2900: tsiz = be - bp;
! 2901: else
! 2902: tsiz = xfer;
! 2903: bcopy(cp, bp, tsiz);
! 2904: bp += tsiz;
! 2905: xfer -= tsiz;
! 2906: if (xfer > 0)
! 2907: cp += tsiz;
! 2908: }
! 2909: }
! 2910: invalid:
! 2911: cpos += dp->d_reclen;
! 2912: dp = (struct dirent *)cpos;
! 2913: cookiep++;
! 2914: ncookies--;
! 2915: }
! 2916: vrele(vp);
! 2917: nfsm_clget;
! 2918: *tl = nfs_false;
! 2919: bp += NFSX_UNSIGNED;
! 2920: nfsm_clget;
! 2921: if (eofflag)
! 2922: *tl = nfs_true;
! 2923: else
! 2924: *tl = nfs_false;
! 2925: bp += NFSX_UNSIGNED;
! 2926: if (mp != mb) {
! 2927: if (bp < be)
! 2928: mp->m_len = bp - mtod(mp, caddr_t);
! 2929: } else
! 2930: mp->m_len += bp - bpos;
! 2931: FREE((caddr_t)cookies, M_TEMP);
! 2932: FREE((caddr_t)rbuf, M_TEMP);
! 2933: nfsm_srvdone;
! 2934: }
! 2935:
! 2936: /*
! 2937: * nfs commit service
! 2938: */
! 2939: int
! 2940: nfsrv_commit(nfsd, slp, procp, mrq)
! 2941: struct nfsrv_descript *nfsd;
! 2942: struct nfssvc_sock *slp;
! 2943: struct proc *procp;
! 2944: struct mbuf **mrq;
! 2945: {
! 2946: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 2947: struct mbuf *nam = nfsd->nd_nam;
! 2948: caddr_t dpos = nfsd->nd_dpos;
! 2949: struct ucred *cred = &nfsd->nd_cr;
! 2950: struct vattr bfor, aft;
! 2951: struct vnode *vp;
! 2952: nfsfh_t nfh;
! 2953: fhandle_t *fhp;
! 2954: u_int32_t *tl;
! 2955: int32_t t1;
! 2956: caddr_t bpos;
! 2957: int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt;
! 2958: char *cp2;
! 2959: struct mbuf *mb, *mb2, *mreq;
! 2960: u_quad_t frev, off;
! 2961:
! 2962: fhp = &nfh.fh_generic;
! 2963: nfsm_srvmtofh(fhp);
! 2964: nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
! 2965:
! 2966: /*
! 2967: * XXX At this time VOP_FSYNC() does not accept offset and byte
! 2968: * count parameters, so these arguments are useless (someday maybe).
! 2969: */
! 2970: off = fxdr_hyper(tl);
! 2971: tl += 2;
! 2972: cnt = fxdr_unsigned(int, *tl);
! 2973: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 2974: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 2975: if (error) {
! 2976: nfsm_reply(2 * NFSX_UNSIGNED);
! 2977: nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
! 2978: return (0);
! 2979: }
! 2980: for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
! 2981: error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
! 2982: aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
! 2983: vput(vp);
! 2984: nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
! 2985: nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
! 2986: if (!error) {
! 2987: nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
! 2988: *tl++ = txdr_unsigned(boottime.tv_sec);
! 2989: *tl = txdr_unsigned(boottime.tv_usec);
! 2990: } else
! 2991: return (0);
! 2992: nfsm_srvdone;
! 2993: }
! 2994:
! 2995: /*
! 2996: * nfs statfs service
! 2997: */
! 2998: int
! 2999: nfsrv_statfs(nfsd, slp, procp, mrq)
! 3000: struct nfsrv_descript *nfsd;
! 3001: struct nfssvc_sock *slp;
! 3002: struct proc *procp;
! 3003: struct mbuf **mrq;
! 3004: {
! 3005: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 3006: struct mbuf *nam = nfsd->nd_nam;
! 3007: caddr_t dpos = nfsd->nd_dpos;
! 3008: struct ucred *cred = &nfsd->nd_cr;
! 3009: struct statfs *sf;
! 3010: struct nfs_statfs *sfp;
! 3011: u_int32_t *tl;
! 3012: int32_t t1;
! 3013: caddr_t bpos;
! 3014: int error = 0, rdonly, getret = 1;
! 3015: int v3 = (nfsd->nd_flag & ND_NFSV3);
! 3016: char *cp2;
! 3017: struct mbuf *mb, *mb2, *mreq;
! 3018: struct vnode *vp;
! 3019: struct vattr at;
! 3020: nfsfh_t nfh;
! 3021: fhandle_t *fhp;
! 3022: struct statfs statfs;
! 3023: u_quad_t frev, tval;
! 3024:
! 3025: fhp = &nfh.fh_generic;
! 3026: nfsm_srvmtofh(fhp);
! 3027: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 3028: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 3029: if (error) {
! 3030: nfsm_reply(NFSX_UNSIGNED);
! 3031: nfsm_srvpostop_attr(getret, &at);
! 3032: return (0);
! 3033: }
! 3034: sf = &statfs;
! 3035: error = VFS_STATFS(vp->v_mount, sf, procp);
! 3036: getret = VOP_GETATTR(vp, &at, cred, procp);
! 3037: vput(vp);
! 3038: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
! 3039: if (v3)
! 3040: nfsm_srvpostop_attr(getret, &at);
! 3041: if (error)
! 3042: return (0);
! 3043: nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
! 3044: if (v3) {
! 3045: tval = (u_quad_t)sf->f_blocks;
! 3046: tval *= (u_quad_t)sf->f_bsize;
! 3047: txdr_hyper(tval, &sfp->sf_tbytes);
! 3048: tval = (u_quad_t)sf->f_bfree;
! 3049: tval *= (u_quad_t)sf->f_bsize;
! 3050: txdr_hyper(tval, &sfp->sf_fbytes);
! 3051: tval = (u_quad_t)sf->f_bavail;
! 3052: tval *= (u_quad_t)sf->f_bsize;
! 3053: txdr_hyper(tval, &sfp->sf_abytes);
! 3054: sfp->sf_tfiles.nfsuquad[0] = 0;
! 3055: sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
! 3056: sfp->sf_ffiles.nfsuquad[0] = 0;
! 3057: sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
! 3058: sfp->sf_afiles.nfsuquad[0] = 0;
! 3059: sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
! 3060: sfp->sf_invarsec = 0;
! 3061: } else {
! 3062: sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
! 3063: sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
! 3064: sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
! 3065: sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
! 3066: sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
! 3067: }
! 3068: nfsm_srvdone;
! 3069: }
! 3070:
! 3071: /*
! 3072: * nfs fsinfo service
! 3073: */
! 3074: int
! 3075: nfsrv_fsinfo(nfsd, slp, procp, mrq)
! 3076: struct nfsrv_descript *nfsd;
! 3077: struct nfssvc_sock *slp;
! 3078: struct proc *procp;
! 3079: struct mbuf **mrq;
! 3080: {
! 3081: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 3082: struct mbuf *nam = nfsd->nd_nam;
! 3083: caddr_t dpos = nfsd->nd_dpos;
! 3084: struct ucred *cred = &nfsd->nd_cr;
! 3085: u_int32_t *tl;
! 3086: struct nfsv3_fsinfo *sip;
! 3087: int32_t t1;
! 3088: caddr_t bpos;
! 3089: int error = 0, rdonly, getret = 1, pref;
! 3090: char *cp2;
! 3091: struct mbuf *mb, *mb2, *mreq;
! 3092: struct vnode *vp;
! 3093: struct vattr at;
! 3094: nfsfh_t nfh;
! 3095: fhandle_t *fhp;
! 3096: u_quad_t frev;
! 3097:
! 3098: fhp = &nfh.fh_generic;
! 3099: nfsm_srvmtofh(fhp);
! 3100: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 3101: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 3102: if (error) {
! 3103: nfsm_reply(NFSX_UNSIGNED);
! 3104: nfsm_srvpostop_attr(getret, &at);
! 3105: return (0);
! 3106: }
! 3107: getret = VOP_GETATTR(vp, &at, cred, procp);
! 3108: vput(vp);
! 3109: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
! 3110: nfsm_srvpostop_attr(getret, &at);
! 3111: nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
! 3112:
! 3113: /*
! 3114: * XXX
! 3115: * There should be file system VFS OP(s) to get this information.
! 3116: * For now, assume ufs.
! 3117: */
! 3118: if (slp->ns_so->so_type == SOCK_DGRAM)
! 3119: pref = NFS_MAXDGRAMDATA;
! 3120: else
! 3121: pref = NFS_MAXDATA;
! 3122: sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
! 3123: sip->fs_rtpref = txdr_unsigned(pref);
! 3124: sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
! 3125: sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
! 3126: sip->fs_wtpref = txdr_unsigned(pref);
! 3127: sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
! 3128: sip->fs_dtpref = txdr_unsigned(pref);
! 3129: sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
! 3130: sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
! 3131: sip->fs_timedelta.nfsv3_sec = 0;
! 3132: sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
! 3133: sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
! 3134: NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
! 3135: NFSV3FSINFO_CANSETTIME);
! 3136: nfsm_srvdone;
! 3137: }
! 3138:
! 3139: /*
! 3140: * nfs pathconf service
! 3141: */
! 3142: int
! 3143: nfsrv_pathconf(nfsd, slp, procp, mrq)
! 3144: struct nfsrv_descript *nfsd;
! 3145: struct nfssvc_sock *slp;
! 3146: struct proc *procp;
! 3147: struct mbuf **mrq;
! 3148: {
! 3149: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
! 3150: struct mbuf *nam = nfsd->nd_nam;
! 3151: caddr_t dpos = nfsd->nd_dpos;
! 3152: struct ucred *cred = &nfsd->nd_cr;
! 3153: u_int32_t *tl;
! 3154: struct nfsv3_pathconf *pc;
! 3155: int32_t t1;
! 3156: caddr_t bpos;
! 3157: int error = 0, rdonly, getret = 1;
! 3158: register_t linkmax, namemax, chownres, notrunc;
! 3159: char *cp2;
! 3160: struct mbuf *mb, *mb2, *mreq;
! 3161: struct vnode *vp;
! 3162: struct vattr at;
! 3163: nfsfh_t nfh;
! 3164: fhandle_t *fhp;
! 3165: u_quad_t frev;
! 3166:
! 3167: fhp = &nfh.fh_generic;
! 3168: nfsm_srvmtofh(fhp);
! 3169: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
! 3170: &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
! 3171: if (error) {
! 3172: nfsm_reply(NFSX_UNSIGNED);
! 3173: nfsm_srvpostop_attr(getret, &at);
! 3174: return (0);
! 3175: }
! 3176: error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
! 3177: if (!error)
! 3178: error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
! 3179: if (!error)
! 3180: error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
! 3181: if (!error)
! 3182: error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
! 3183: getret = VOP_GETATTR(vp, &at, cred, procp);
! 3184: vput(vp);
! 3185: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
! 3186: nfsm_srvpostop_attr(getret, &at);
! 3187: if (error)
! 3188: return (0);
! 3189: nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
! 3190:
! 3191: pc->pc_linkmax = txdr_unsigned(linkmax);
! 3192: pc->pc_namemax = txdr_unsigned(namemax);
! 3193: pc->pc_notrunc = txdr_unsigned(notrunc);
! 3194: pc->pc_chownrestricted = txdr_unsigned(chownres);
! 3195:
! 3196: /*
! 3197: * These should probably be supported by VOP_PATHCONF(), but
! 3198: * until msdosfs is exportable (why would you want to?), the
! 3199: * Unix defaults should be ok.
! 3200: */
! 3201: pc->pc_caseinsensitive = nfs_false;
! 3202: pc->pc_casepreserving = nfs_true;
! 3203: nfsm_srvdone;
! 3204: }
! 3205:
! 3206: /*
! 3207: * Null operation, used by clients to ping server
! 3208: */
! 3209: /* ARGSUSED */
! 3210: int
! 3211: nfsrv_null(nfsd, slp, procp, mrq)
! 3212: struct nfsrv_descript *nfsd;
! 3213: struct nfssvc_sock *slp;
! 3214: struct proc *procp;
! 3215: struct mbuf **mrq;
! 3216: {
! 3217: struct mbuf *mrep = nfsd->nd_mrep;
! 3218: caddr_t bpos;
! 3219: int error = NFSERR_RETVOID;
! 3220: struct mbuf *mb, *mreq;
! 3221: u_quad_t frev;
! 3222:
! 3223: nfsm_reply(0);
! 3224: return (0);
! 3225: }
! 3226:
! 3227: /*
! 3228: * No operation, used for obsolete procedures
! 3229: */
! 3230: /* ARGSUSED */
! 3231: int
! 3232: nfsrv_noop(nfsd, slp, procp, mrq)
! 3233: struct nfsrv_descript *nfsd;
! 3234: struct nfssvc_sock *slp;
! 3235: struct proc *procp;
! 3236: struct mbuf **mrq;
! 3237: {
! 3238: struct mbuf *mrep = nfsd->nd_mrep;
! 3239: caddr_t bpos;
! 3240: int error;
! 3241: struct mbuf *mb, *mreq;
! 3242: u_quad_t frev;
! 3243:
! 3244: if (nfsd->nd_repstat)
! 3245: error = nfsd->nd_repstat;
! 3246: else
! 3247: error = EPROCUNAVAIL;
! 3248: nfsm_reply(0);
! 3249: return (0);
! 3250: }
! 3251:
! 3252: /*
! 3253: * Perform access checking for vnodes obtained from file handles that would
! 3254: * refer to files already opened by a Unix client. You cannot just use
! 3255: * vn_writechk() and VOP_ACCESS() for two reasons.
! 3256: * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
! 3257: * 2 - The owner is to be given access irrespective of mode bits for some
! 3258: * operations, so that processes that chmod after opening a file don't
! 3259: * break. I don't like this because it opens a security hole, but since
! 3260: * the nfs server opens a security hole the size of a barn door anyhow,
! 3261: * what the heck.
! 3262: */
! 3263: int
! 3264: nfsrv_access(vp, flags, cred, rdonly, p, override)
! 3265: struct vnode *vp;
! 3266: int flags;
! 3267: struct ucred *cred;
! 3268: int rdonly;
! 3269: struct proc *p;
! 3270: int override;
! 3271: {
! 3272: struct vattr vattr;
! 3273: int error;
! 3274:
! 3275: if (flags & VWRITE) {
! 3276: /* Just vn_writechk() changed to check rdonly */
! 3277: /*
! 3278: * Disallow write attempts on read-only file systems;
! 3279: * unless the file is a socket or a block or character
! 3280: * device resident on the file system.
! 3281: */
! 3282: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
! 3283: switch (vp->v_type) {
! 3284: case VREG:
! 3285: case VDIR:
! 3286: case VLNK:
! 3287: return (EROFS);
! 3288: default:
! 3289: break;
! 3290: }
! 3291: }
! 3292: /*
! 3293: * If there's shared text associated with
! 3294: * the inode, try to free it up once. If
! 3295: * we fail, we can't allow writing.
! 3296: */
! 3297: if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
! 3298: return (ETXTBSY);
! 3299: }
! 3300: error = VOP_ACCESS(vp, flags, cred, p);
! 3301: /*
! 3302: * Allow certain operations for the owner (reads and writes
! 3303: * on files that are already open).
! 3304: */
! 3305: if (override && (error == EPERM || error == EACCES) &&
! 3306: VOP_GETATTR(vp, &vattr, cred, p) == 0 &&
! 3307: cred->cr_uid == vattr.va_uid)
! 3308: error = 0;
! 3309: return error;
! 3310: }
CVSweb