138418Smckusick /* 263233Sbostic * Copyright (c) 1989, 1993 363233Sbostic * The Regents of the University of California. All rights reserved. 438418Smckusick * 538418Smckusick * This code is derived from software contributed to Berkeley by 638418Smckusick * Rick Macklem at The University of Guelph. 738418Smckusick * 844510Sbostic * %sccs.include.redist.c% 938418Smckusick * 10*68653Smckusick * @(#)nfs_serv.c 8.6 (Berkeley) 03/30/95 1138418Smckusick */ 1238418Smckusick 1338418Smckusick /* 14*68653Smckusick * nfs version 2 and 3 server calls to vnode ops 1538418Smckusick * - these routines generally have 3 phases 1638418Smckusick * 1 - break down and validate rpc request in mbuf list 1738418Smckusick * 2 - do the vnode ops for the request 1838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 1938418Smckusick * 3 - build the rpc reply in an mbuf list 2038418Smckusick * nb: 2138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 2241899Smckusick * on a bad rpc or similar and do not do any vrele() or vput()'s 2338418Smckusick * 2438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 2538418Smckusick * error number iff error != 0 whereas 2641899Smckusick * returning an error from the server function implies a fatal error 2741899Smckusick * such as a badly constructed rpc request that should be dropped without 2841899Smckusick * a reply. 29*68653Smckusick * For Version 3, nfsm_reply() does not return for the error case, since 30*68653Smckusick * most version 3 rpcs return more than the status for error cases. 3138418Smckusick */ 3238418Smckusick 3353322Smckusick #include <sys/param.h> 3455073Spendry #include <sys/systm.h> 3553322Smckusick #include <sys/proc.h> 3653322Smckusick #include <sys/file.h> 3753322Smckusick #include <sys/namei.h> 3853322Smckusick #include <sys/vnode.h> 3953322Smckusick #include <sys/mount.h> 40*68653Smckusick #include <sys/socket.h> 41*68653Smckusick #include <sys/socketvar.h> 4253322Smckusick #include <sys/mbuf.h> 4353322Smckusick #include <sys/dirent.h> 4454446Smckusick #include <sys/stat.h> 45*68653Smckusick #include <sys/kernel.h> 46*68653Smckusick #include <ufs/ufs/dir.h> 4747573Skarels 4853322Smckusick #include <vm/vm.h> 4947573Skarels 50*68653Smckusick #include <nfs/nfsproto.h> 5153322Smckusick #include <nfs/rpcv2.h> 5253322Smckusick #include <nfs/nfs.h> 5353322Smckusick #include <nfs/xdr_subs.h> 5453322Smckusick #include <nfs/nfsm_subs.h> 5553322Smckusick #include <nfs/nqnfs.h> 5653322Smckusick 5738418Smckusick /* Global vars */ 5838418Smckusick extern u_long nfs_xdrneg1; 5938418Smckusick extern u_long nfs_false, nfs_true; 60*68653Smckusick extern enum vtype nv3tov_type[8]; 61*68653Smckusick extern struct nfsstats nfsstats; 62*68653Smckusick nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 6342242Smckusick NFCHR, NFNON }; 64*68653Smckusick nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 65*68653Smckusick NFFIFO, NFNON }; 66*68653Smckusick int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000; 6738418Smckusick 6838418Smckusick /* 69*68653Smckusick * nfs v3 access service 7056360Smckusick */ 71*68653Smckusick int 72*68653Smckusick nfsrv3_access(nfsd, slp, procp, mrq) 73*68653Smckusick struct nfsrv_descript *nfsd; 74*68653Smckusick struct nfssvc_sock *slp; 75*68653Smckusick struct proc *procp; 76*68653Smckusick struct mbuf **mrq; 7756360Smckusick { 78*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 79*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 80*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 81*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 8256360Smckusick struct vnode *vp; 83*68653Smckusick nfsfh_t nfh; 8456360Smckusick fhandle_t *fhp; 8556360Smckusick register u_long *tl; 8656360Smckusick register long t1; 8756360Smckusick caddr_t bpos; 88*68653Smckusick int error = 0, rdonly, cache, getret; 8956360Smckusick char *cp2; 90*68653Smckusick struct mbuf *mb, *mreq, *mb2; 91*68653Smckusick struct vattr vattr, *vap = &vattr; 92*68653Smckusick u_long testmode, nfsmode; 9356360Smckusick u_quad_t frev; 9456360Smckusick 95*68653Smckusick #ifndef nolint 96*68653Smckusick cache = 0; 97*68653Smckusick #endif 9856360Smckusick fhp = &nfh.fh_generic; 9956360Smckusick nfsm_srvmtofh(fhp); 100*68653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 101*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 102*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 103*68653Smckusick nfsm_reply(NFSX_UNSIGNED); 104*68653Smckusick nfsm_srvpostop_attr(1, (struct vattr *)0); 105*68653Smckusick return (0); 106*68653Smckusick } 107*68653Smckusick nfsmode = fxdr_unsigned(u_long, *tl); 108*68653Smckusick if ((nfsmode & NFSV3ACCESS_READ) && 109*68653Smckusick nfsrv_access(vp, VREAD, cred, rdonly, procp)) 110*68653Smckusick nfsmode &= ~NFSV3ACCESS_READ; 111*68653Smckusick if (vp->v_type == VDIR) 112*68653Smckusick testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 113*68653Smckusick NFSV3ACCESS_DELETE); 114*68653Smckusick else 115*68653Smckusick testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 116*68653Smckusick if ((nfsmode & testmode) && 117*68653Smckusick nfsrv_access(vp, VWRITE, cred, rdonly, procp)) 118*68653Smckusick nfsmode &= ~testmode; 119*68653Smckusick if (vp->v_type == VDIR) 120*68653Smckusick testmode = NFSV3ACCESS_LOOKUP; 121*68653Smckusick else 122*68653Smckusick testmode = NFSV3ACCESS_EXECUTE; 123*68653Smckusick if ((nfsmode & testmode) && 124*68653Smckusick nfsrv_access(vp, VEXEC, cred, rdonly, procp)) 125*68653Smckusick nfsmode &= ~testmode; 126*68653Smckusick getret = VOP_GETATTR(vp, vap, cred, procp); 12756360Smckusick vput(vp); 128*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); 129*68653Smckusick nfsm_srvpostop_attr(getret, vap); 130*68653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 131*68653Smckusick *tl = txdr_unsigned(nfsmode); 13256360Smckusick nfsm_srvdone; 13356360Smckusick } 13456360Smckusick 13556360Smckusick /* 13638418Smckusick * nfs getattr service 13738418Smckusick */ 138*68653Smckusick int 139*68653Smckusick nfsrv_getattr(nfsd, slp, procp, mrq) 140*68653Smckusick struct nfsrv_descript *nfsd; 141*68653Smckusick struct nfssvc_sock *slp; 142*68653Smckusick struct proc *procp; 143*68653Smckusick struct mbuf **mrq; 14438418Smckusick { 145*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 146*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 147*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 148*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 149*68653Smckusick register struct nfs_fattr *fp; 15038418Smckusick struct vattr va; 15138418Smckusick register struct vattr *vap = &va; 15238418Smckusick struct vnode *vp; 153*68653Smckusick nfsfh_t nfh; 15438418Smckusick fhandle_t *fhp; 15548050Smckusick register u_long *tl; 15639494Smckusick register long t1; 15739494Smckusick caddr_t bpos; 15852196Smckusick int error = 0, rdonly, cache; 15939494Smckusick char *cp2; 16039753Smckusick struct mbuf *mb, *mb2, *mreq; 16152196Smckusick u_quad_t frev; 16238418Smckusick 16338418Smckusick fhp = &nfh.fh_generic; 16438418Smckusick nfsm_srvmtofh(fhp); 165*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 166*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 16738418Smckusick nfsm_reply(0); 168*68653Smckusick return (0); 169*68653Smckusick } 170*68653Smckusick nqsrv_getl(vp, ND_READ); 171*68653Smckusick error = VOP_GETATTR(vp, vap, cred, procp); 17238418Smckusick vput(vp); 173*68653Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 174*68653Smckusick if (error) 175*68653Smckusick return (0); 176*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 177*68653Smckusick nfsm_srvfillattr(vap, fp); 17838418Smckusick nfsm_srvdone; 17938418Smckusick } 18038418Smckusick 18138418Smckusick /* 18238418Smckusick * nfs setattr service 18338418Smckusick */ 184*68653Smckusick int 185*68653Smckusick nfsrv_setattr(nfsd, slp, procp, mrq) 186*68653Smckusick struct nfsrv_descript *nfsd; 187*68653Smckusick struct nfssvc_sock *slp; 188*68653Smckusick struct proc *procp; 189*68653Smckusick struct mbuf **mrq; 19038418Smckusick { 191*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 192*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 193*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 194*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 195*68653Smckusick struct vattr va, preat; 19638418Smckusick register struct vattr *vap = &va; 19738884Smacklem register struct nfsv2_sattr *sp; 198*68653Smckusick register struct nfs_fattr *fp; 19938418Smckusick struct vnode *vp; 200*68653Smckusick nfsfh_t nfh; 20138418Smckusick fhandle_t *fhp; 20248050Smckusick register u_long *tl; 20339494Smckusick register long t1; 20439494Smckusick caddr_t bpos; 205*68653Smckusick int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1; 206*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0; 20739494Smckusick char *cp2; 20839753Smckusick struct mbuf *mb, *mb2, *mreq; 209*68653Smckusick u_quad_t frev; 210*68653Smckusick struct timespec guard; 21138418Smckusick 21238418Smckusick fhp = &nfh.fh_generic; 21338418Smckusick nfsm_srvmtofh(fhp); 21441361Smckusick VATTR_NULL(vap); 215*68653Smckusick if (v3) { 216*68653Smckusick nfsm_srvsattr(vap); 217*68653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 218*68653Smckusick gcheck = fxdr_unsigned(int, *tl); 219*68653Smckusick if (gcheck) { 220*68653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 221*68653Smckusick fxdr_nfsv3time(tl, &guard); 222*68653Smckusick } 223*68653Smckusick } else { 224*68653Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 225*68653Smckusick /* 226*68653Smckusick * Nah nah nah nah na nah 227*68653Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 228*68653Smckusick * field of sattr when it should put in 0xffffffff. The u_short 229*68653Smckusick * doesn't sign extend. 230*68653Smckusick * --> check the low order 2 bytes for 0xffff 231*68653Smckusick */ 232*68653Smckusick if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 233*68653Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 234*68653Smckusick if (sp->sa_uid != nfs_xdrneg1) 235*68653Smckusick vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 236*68653Smckusick if (sp->sa_gid != nfs_xdrneg1) 237*68653Smckusick vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 238*68653Smckusick if (sp->sa_size != nfs_xdrneg1) 239*68653Smckusick vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size); 240*68653Smckusick if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { 24158880Smckusick #ifdef notyet 242*68653Smckusick fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime); 24358880Smckusick #else 24458880Smckusick vap->va_atime.ts_sec = 245*68653Smckusick fxdr_unsigned(long, sp->sa_atime.nfsv2_sec); 24656285Smckusick vap->va_atime.ts_nsec = 0; 24758880Smckusick #endif 24856285Smckusick } 249*68653Smckusick if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) 250*68653Smckusick fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime); 251*68653Smckusick 25238425Smckusick } 25359526Smckusick 25459526Smckusick /* 255*68653Smckusick * Now that we have all the fields, lets do it. 256*68653Smckusick */ 257*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 258*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 259*68653Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 260*68653Smckusick nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); 261*68653Smckusick return (0); 262*68653Smckusick } 263*68653Smckusick nqsrv_getl(vp, ND_WRITE); 264*68653Smckusick if (v3) { 265*68653Smckusick error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp); 266*68653Smckusick if (!error && gcheck && 267*68653Smckusick (preat.va_ctime.ts_sec != guard.ts_sec || 268*68653Smckusick preat.va_ctime.ts_nsec != guard.ts_nsec)) 269*68653Smckusick error = NFSERR_NOT_SYNC; 270*68653Smckusick if (error) { 271*68653Smckusick vput(vp); 272*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 273*68653Smckusick nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); 274*68653Smckusick return (0); 275*68653Smckusick } 276*68653Smckusick } 277*68653Smckusick 278*68653Smckusick /* 27959526Smckusick * If the size is being changed write acces is required, otherwise 28059526Smckusick * just check for a read only file system. 28159526Smckusick */ 28259526Smckusick if (vap->va_size == ((u_quad_t)((quad_t) -1))) { 28359526Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 28459526Smckusick error = EROFS; 28559526Smckusick goto out; 28659526Smckusick } 28759526Smckusick } else { 28859526Smckusick if (vp->v_type == VDIR) { 28959526Smckusick error = EISDIR; 29059526Smckusick goto out; 29159526Smckusick } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly, 292*68653Smckusick procp)) 29359526Smckusick goto out; 29459526Smckusick } 295*68653Smckusick error = VOP_SETATTR(vp, vap, cred, procp); 296*68653Smckusick postat_ret = VOP_GETATTR(vp, vap, cred, procp); 297*68653Smckusick if (!error) 298*68653Smckusick error = postat_ret; 29938418Smckusick out: 30038418Smckusick vput(vp); 301*68653Smckusick nfsm_reply(NFSX_WCCORFATTR(v3)); 302*68653Smckusick if (v3) { 303*68653Smckusick nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); 304*68653Smckusick return (0); 305*68653Smckusick } else { 306*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 307*68653Smckusick nfsm_srvfillattr(vap, fp); 30852196Smckusick } 30938418Smckusick nfsm_srvdone; 31038418Smckusick } 31138418Smckusick 31238418Smckusick /* 31338418Smckusick * nfs lookup rpc 31438418Smckusick */ 315*68653Smckusick int 316*68653Smckusick nfsrv_lookup(nfsd, slp, procp, mrq) 317*68653Smckusick struct nfsrv_descript *nfsd; 318*68653Smckusick struct nfssvc_sock *slp; 319*68653Smckusick struct proc *procp; 320*68653Smckusick struct mbuf **mrq; 32138418Smckusick { 322*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 323*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 324*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 325*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 326*68653Smckusick register struct nfs_fattr *fp; 32749742Smckusick struct nameidata nd; 328*68653Smckusick struct vnode *vp, *dirp; 329*68653Smckusick nfsfh_t nfh; 33038418Smckusick fhandle_t *fhp; 33139494Smckusick register caddr_t cp; 33248050Smckusick register u_long *tl; 33339494Smckusick register long t1; 33439494Smckusick caddr_t bpos; 335*68653Smckusick int error = 0, cache, len, dirattr_ret = 1; 336*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 33739494Smckusick char *cp2; 33839753Smckusick struct mbuf *mb, *mb2, *mreq; 339*68653Smckusick struct vattr va, dirattr, *vap = &va; 340*68653Smckusick u_quad_t frev; 34138418Smckusick 34238418Smckusick fhp = &nfh.fh_generic; 34338418Smckusick nfsm_srvmtofh(fhp); 344*68653Smckusick nfsm_srvnamesiz(len); 34552316Sheideman nd.ni_cnd.cn_cred = cred; 34652316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 34752316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 348*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 349*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 350*68653Smckusick if (dirp) { 351*68653Smckusick if (v3) 352*68653Smckusick dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, 353*68653Smckusick procp); 354*68653Smckusick vrele(dirp); 355*68653Smckusick } 356*68653Smckusick if (error) { 357*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3)); 358*68653Smckusick nfsm_srvpostop_attr(dirattr_ret, &dirattr); 359*68653Smckusick return (0); 360*68653Smckusick } 361*68653Smckusick nqsrv_getl(nd.ni_startdir, ND_READ); 36252196Smckusick vrele(nd.ni_startdir); 36352653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 36449742Smckusick vp = nd.ni_vp; 36538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 36641398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 367*68653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid); 368*68653Smckusick if (!error) 369*68653Smckusick error = VOP_GETATTR(vp, vap, cred, procp); 37038418Smckusick vput(vp); 371*68653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3)); 372*68653Smckusick if (error) { 373*68653Smckusick nfsm_srvpostop_attr(dirattr_ret, &dirattr); 374*68653Smckusick return (0); 37552196Smckusick } 376*68653Smckusick nfsm_srvfhtom(fhp, v3); 377*68653Smckusick if (v3) { 378*68653Smckusick nfsm_srvpostop_attr(0, vap); 379*68653Smckusick nfsm_srvpostop_attr(dirattr_ret, &dirattr); 380*68653Smckusick } else { 381*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 382*68653Smckusick nfsm_srvfillattr(vap, fp); 383*68653Smckusick } 38438418Smckusick nfsm_srvdone; 38538418Smckusick } 38638418Smckusick 38738418Smckusick /* 38838418Smckusick * nfs readlink service 38938418Smckusick */ 390*68653Smckusick int 391*68653Smckusick nfsrv_readlink(nfsd, slp, procp, mrq) 392*68653Smckusick struct nfsrv_descript *nfsd; 393*68653Smckusick struct nfssvc_sock *slp; 394*68653Smckusick struct proc *procp; 395*68653Smckusick struct mbuf **mrq; 39638418Smckusick { 397*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 398*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 399*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 400*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 40141899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 40238418Smckusick register struct iovec *ivp = iv; 40338418Smckusick register struct mbuf *mp; 40448050Smckusick register u_long *tl; 40539494Smckusick register long t1; 40639494Smckusick caddr_t bpos; 407*68653Smckusick int error = 0, rdonly, cache, i, tlen, len, getret; 408*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 40939494Smckusick char *cp2; 41039753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 41138418Smckusick struct vnode *vp; 412*68653Smckusick struct vattr attr; 413*68653Smckusick nfsfh_t nfh; 41438418Smckusick fhandle_t *fhp; 41538418Smckusick struct uio io, *uiop = &io; 41652196Smckusick u_quad_t frev; 41738418Smckusick 418*68653Smckusick #ifndef nolint 419*68653Smckusick mp2 = mp3 = (struct mbuf *)0; 420*68653Smckusick #endif 42138418Smckusick fhp = &nfh.fh_generic; 42238418Smckusick nfsm_srvmtofh(fhp); 42338418Smckusick len = 0; 42438418Smckusick i = 0; 42538418Smckusick while (len < NFS_MAXPATHLEN) { 42638418Smckusick MGET(mp, M_WAIT, MT_DATA); 42741899Smckusick MCLGET(mp, M_WAIT); 42838418Smckusick mp->m_len = NFSMSIZ(mp); 42938418Smckusick if (len == 0) 43038418Smckusick mp3 = mp2 = mp; 43141899Smckusick else { 43238418Smckusick mp2->m_next = mp; 43341899Smckusick mp2 = mp; 43441899Smckusick } 43538418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 43638418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 43738418Smckusick len = NFS_MAXPATHLEN; 43838418Smckusick } else 43938418Smckusick len += mp->m_len; 44038418Smckusick ivp->iov_base = mtod(mp, caddr_t); 44138418Smckusick ivp->iov_len = mp->m_len; 44238418Smckusick i++; 44338418Smckusick ivp++; 44438418Smckusick } 44538418Smckusick uiop->uio_iov = iv; 44638418Smckusick uiop->uio_iovcnt = i; 44738418Smckusick uiop->uio_offset = 0; 44838418Smckusick uiop->uio_resid = len; 44938418Smckusick uiop->uio_rw = UIO_READ; 45038418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 45148050Smckusick uiop->uio_procp = (struct proc *)0; 452*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 453*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 45438418Smckusick m_freem(mp3); 455*68653Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 456*68653Smckusick nfsm_srvpostop_attr(1, (struct vattr *)0); 457*68653Smckusick return (0); 45838418Smckusick } 45938418Smckusick if (vp->v_type != VLNK) { 460*68653Smckusick if (v3) 461*68653Smckusick error = EINVAL; 462*68653Smckusick else 463*68653Smckusick error = ENXIO; 46438418Smckusick goto out; 46538418Smckusick } 466*68653Smckusick nqsrv_getl(vp, ND_READ); 46738418Smckusick error = VOP_READLINK(vp, uiop, cred); 46838418Smckusick out: 469*68653Smckusick getret = VOP_GETATTR(vp, &attr, cred, procp); 47038418Smckusick vput(vp); 47138418Smckusick if (error) 47238418Smckusick m_freem(mp3); 473*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); 474*68653Smckusick if (v3) { 475*68653Smckusick nfsm_srvpostop_attr(getret, &attr); 476*68653Smckusick if (error) 477*68653Smckusick return (0); 478*68653Smckusick } 47938418Smckusick if (uiop->uio_resid > 0) { 48038418Smckusick len -= uiop->uio_resid; 48138418Smckusick tlen = nfsm_rndup(len); 48238418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 48338418Smckusick } 48448050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 48548050Smckusick *tl = txdr_unsigned(len); 48638418Smckusick mb->m_next = mp3; 48738418Smckusick nfsm_srvdone; 48838418Smckusick } 48938418Smckusick 49038418Smckusick /* 49138418Smckusick * nfs read service 49238418Smckusick */ 493*68653Smckusick int 494*68653Smckusick nfsrv_read(nfsd, slp, procp, mrq) 495*68653Smckusick struct nfsrv_descript *nfsd; 496*68653Smckusick struct nfssvc_sock *slp; 497*68653Smckusick struct proc *procp; 498*68653Smckusick struct mbuf **mrq; 49938418Smckusick { 500*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 501*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 502*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 503*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 50443350Smckusick register struct iovec *iv; 50543350Smckusick struct iovec *iv2; 50641899Smckusick register struct mbuf *m; 507*68653Smckusick register struct nfs_fattr *fp; 50848050Smckusick register u_long *tl; 50939494Smckusick register long t1; 510*68653Smckusick register int i; 51139494Smckusick caddr_t bpos; 512*68653Smckusick int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret; 513*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen; 51439494Smckusick char *cp2; 51539753Smckusick struct mbuf *mb, *mb2, *mreq; 51652196Smckusick struct mbuf *m2; 51738418Smckusick struct vnode *vp; 518*68653Smckusick nfsfh_t nfh; 51938418Smckusick fhandle_t *fhp; 52038418Smckusick struct uio io, *uiop = &io; 52138418Smckusick struct vattr va, *vap = &va; 52238418Smckusick off_t off; 52352196Smckusick u_quad_t frev; 52438418Smckusick 52538418Smckusick fhp = &nfh.fh_generic; 52638418Smckusick nfsm_srvmtofh(fhp); 527*68653Smckusick if (v3) { 528*68653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 529*68653Smckusick fxdr_hyper(tl, &off); 530*68653Smckusick } else { 53156285Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 53256285Smckusick off = (off_t)fxdr_unsigned(u_long, *tl); 53356285Smckusick } 534*68653Smckusick nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); 535*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 536*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 537*68653Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 538*68653Smckusick nfsm_srvpostop_attr(1, (struct vattr *)0); 539*68653Smckusick return (0); 540*68653Smckusick } 54160186Smckusick if (vp->v_type != VREG) { 542*68653Smckusick if (v3) 543*68653Smckusick error = EINVAL; 544*68653Smckusick else 545*68653Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES; 54660186Smckusick } 547*68653Smckusick if (!error) { 548*68653Smckusick nqsrv_getl(vp, ND_READ); 549*68653Smckusick if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp)) 550*68653Smckusick error = nfsrv_access(vp, VEXEC, cred, rdonly, procp); 55138418Smckusick } 552*68653Smckusick getret = VOP_GETATTR(vp, vap, cred, procp); 553*68653Smckusick if (!error) 554*68653Smckusick error = getret; 555*68653Smckusick if (error) { 55638418Smckusick vput(vp); 557*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3)); 558*68653Smckusick nfsm_srvpostop_attr(getret, vap); 559*68653Smckusick return (0); 56038418Smckusick } 56152196Smckusick if (off >= vap->va_size) 56252196Smckusick cnt = 0; 563*68653Smckusick else if ((off + reqlen) > vap->va_size) 56452196Smckusick cnt = nfsm_rndup(vap->va_size - off); 565*68653Smckusick else 566*68653Smckusick cnt = reqlen; 567*68653Smckusick nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); 568*68653Smckusick if (v3) { 569*68653Smckusick nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); 570*68653Smckusick *tl++ = nfs_true; 571*68653Smckusick fp = (struct nfs_fattr *)tl; 572*68653Smckusick tl += (NFSX_V3FATTR / sizeof (u_long)); 573*68653Smckusick } else { 574*68653Smckusick nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED); 575*68653Smckusick fp = (struct nfs_fattr *)tl; 576*68653Smckusick tl += (NFSX_V2FATTR / sizeof (u_long)); 577*68653Smckusick } 57852196Smckusick len = left = cnt; 57952196Smckusick if (cnt > 0) { 58052196Smckusick /* 58152196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 58252196Smckusick */ 58352196Smckusick i = 0; 58452196Smckusick m = m2 = mb; 58552196Smckusick while (left > 0) { 58655057Spendry siz = min(M_TRAILINGSPACE(m), left); 58752196Smckusick if (siz > 0) { 588*68653Smckusick left -= siz; 58952196Smckusick i++; 59052196Smckusick } 59152196Smckusick if (left > 0) { 59252196Smckusick MGET(m, M_WAIT, MT_DATA); 59352196Smckusick MCLGET(m, M_WAIT); 59452196Smckusick m->m_len = 0; 59552196Smckusick m2->m_next = m; 59652196Smckusick m2 = m; 59752196Smckusick } 59852196Smckusick } 599*68653Smckusick MALLOC(iv, struct iovec *, i * sizeof (struct iovec), 600*68653Smckusick M_TEMP, M_WAITOK); 601*68653Smckusick uiop->uio_iov = iv2 = iv; 602*68653Smckusick m = mb; 603*68653Smckusick left = cnt; 604*68653Smckusick i = 0; 605*68653Smckusick while (left > 0) { 606*68653Smckusick if (m == NULL) 607*68653Smckusick panic("nfsrv_read iov"); 608*68653Smckusick siz = min(M_TRAILINGSPACE(m), left); 609*68653Smckusick if (siz > 0) { 610*68653Smckusick iv->iov_base = mtod(m, caddr_t) + m->m_len; 611*68653Smckusick iv->iov_len = siz; 612*68653Smckusick m->m_len += siz; 613*68653Smckusick left -= siz; 614*68653Smckusick iv++; 615*68653Smckusick i++; 616*68653Smckusick } 617*68653Smckusick m = m->m_next; 618*68653Smckusick } 61952196Smckusick uiop->uio_iovcnt = i; 62052196Smckusick uiop->uio_offset = off; 62152196Smckusick uiop->uio_resid = cnt; 62252196Smckusick uiop->uio_rw = UIO_READ; 62352196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 62452196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 62552196Smckusick off = uiop->uio_offset; 62652196Smckusick FREE((caddr_t)iv2, M_TEMP); 627*68653Smckusick if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) { 628*68653Smckusick if (!error) 629*68653Smckusick error = getret; 63052196Smckusick m_freem(mreq); 63152196Smckusick vput(vp); 632*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3)); 633*68653Smckusick nfsm_srvpostop_attr(getret, vap); 634*68653Smckusick return (0); 63552196Smckusick } 63652196Smckusick } else 63752196Smckusick uiop->uio_resid = 0; 63838418Smckusick vput(vp); 639*68653Smckusick nfsm_srvfillattr(vap, fp); 64045877Smckusick len -= uiop->uio_resid; 64152196Smckusick tlen = nfsm_rndup(len); 64252196Smckusick if (cnt != tlen || tlen != len) 643*68653Smckusick nfsm_adj(mb, cnt - tlen, tlen - len); 644*68653Smckusick if (v3) { 645*68653Smckusick *tl++ = txdr_unsigned(len); 646*68653Smckusick if (len < reqlen) 647*68653Smckusick *tl++ = nfs_true; 648*68653Smckusick else 649*68653Smckusick *tl++ = nfs_false; 650*68653Smckusick } 65148050Smckusick *tl = txdr_unsigned(len); 65238418Smckusick nfsm_srvdone; 65338418Smckusick } 65438418Smckusick 65538418Smckusick /* 65638418Smckusick * nfs write service 65738418Smckusick */ 658*68653Smckusick int 659*68653Smckusick nfsrv_write(nfsd, slp, procp, mrq) 660*68653Smckusick struct nfsrv_descript *nfsd; 661*68653Smckusick struct nfssvc_sock *slp; 662*68653Smckusick struct proc *procp; 663*68653Smckusick struct mbuf **mrq; 66438418Smckusick { 665*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 666*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 667*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 668*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 66938418Smckusick register struct iovec *ivp; 670*68653Smckusick register int i, cnt; 67138418Smckusick register struct mbuf *mp; 672*68653Smckusick register struct nfs_fattr *fp; 673*68653Smckusick struct iovec *iv; 674*68653Smckusick struct vattr va, forat; 67538418Smckusick register struct vattr *vap = &va; 67648050Smckusick register u_long *tl; 67739494Smckusick register long t1; 67839494Smckusick caddr_t bpos; 679*68653Smckusick int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1; 680*68653Smckusick int ioflags, aftat_ret = 1, retlen, zeroing, adjust; 681*68653Smckusick int stable = NFSV3WRITE_FILESYNC; 682*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 68339494Smckusick char *cp2; 68439753Smckusick struct mbuf *mb, *mb2, *mreq; 68538418Smckusick struct vnode *vp; 686*68653Smckusick nfsfh_t nfh; 68738418Smckusick fhandle_t *fhp; 68838418Smckusick struct uio io, *uiop = &io; 68938418Smckusick off_t off; 69052196Smckusick u_quad_t frev; 69138418Smckusick 692*68653Smckusick if (mrep == NULL) { 693*68653Smckusick *mrq = NULL; 694*68653Smckusick return (0); 695*68653Smckusick } 69638418Smckusick fhp = &nfh.fh_generic; 69738418Smckusick nfsm_srvmtofh(fhp); 698*68653Smckusick if (v3) { 699*68653Smckusick nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED); 700*68653Smckusick fxdr_hyper(tl, &off); 701*68653Smckusick tl += 3; 702*68653Smckusick stable = fxdr_unsigned(int, *tl++); 703*68653Smckusick } else { 704*68653Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 70556285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl); 70656285Smckusick tl += 2; 70756285Smckusick } 708*68653Smckusick retlen = len = fxdr_unsigned(long, *tl); 709*68653Smckusick cnt = i = 0; 710*68653Smckusick 711*68653Smckusick /* 712*68653Smckusick * For NFS Version 2, it is not obvious what a write of zero length 713*68653Smckusick * should do, but I might as well be consistent with Version 3, 714*68653Smckusick * which is to return ok so long as there are no permission problems. 715*68653Smckusick */ 716*68653Smckusick if (len > 0) { 717*68653Smckusick zeroing = 1; 718*68653Smckusick mp = mrep; 719*68653Smckusick while (mp) { 720*68653Smckusick if (mp == md) { 721*68653Smckusick zeroing = 0; 722*68653Smckusick adjust = dpos - mtod(mp, caddr_t); 723*68653Smckusick mp->m_len -= adjust; 724*68653Smckusick if (mp->m_len > 0 && adjust > 0) 725*68653Smckusick NFSMADV(mp, adjust); 72638418Smckusick } 727*68653Smckusick if (zeroing) 728*68653Smckusick mp->m_len = 0; 729*68653Smckusick else if (mp->m_len > 0) { 730*68653Smckusick i += mp->m_len; 731*68653Smckusick if (i > len) { 732*68653Smckusick mp->m_len -= (i - len); 733*68653Smckusick zeroing = 1; 734*68653Smckusick } 735*68653Smckusick if (mp->m_len > 0) 736*68653Smckusick cnt++; 737*68653Smckusick } 738*68653Smckusick mp = mp->m_next; 739*68653Smckusick } 74038418Smckusick } 741*68653Smckusick if (len > NFS_MAXDATA || len < 0 || i < len) { 742*68653Smckusick error = EIO; 743*68653Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 744*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); 745*68653Smckusick return (0); 746*68653Smckusick } 747*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 748*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 749*68653Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 750*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); 751*68653Smckusick return (0); 752*68653Smckusick } 753*68653Smckusick if (v3) 754*68653Smckusick forat_ret = VOP_GETATTR(vp, &forat, cred, procp); 75560186Smckusick if (vp->v_type != VREG) { 756*68653Smckusick if (v3) 757*68653Smckusick error = EINVAL; 758*68653Smckusick else 759*68653Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES; 76060186Smckusick } 761*68653Smckusick if (!error) { 762*68653Smckusick nqsrv_getl(vp, ND_WRITE); 763*68653Smckusick error = nfsrv_access(vp, VWRITE, cred, rdonly, procp); 764*68653Smckusick } 765*68653Smckusick if (error) { 76638418Smckusick vput(vp); 767*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 768*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); 769*68653Smckusick return (0); 77038418Smckusick } 771*68653Smckusick 772*68653Smckusick if (len > 0) { 773*68653Smckusick MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, 774*68653Smckusick M_WAITOK); 775*68653Smckusick uiop->uio_iov = iv = ivp; 776*68653Smckusick uiop->uio_iovcnt = cnt; 777*68653Smckusick mp = mrep; 778*68653Smckusick while (mp) { 779*68653Smckusick if (mp->m_len > 0) { 780*68653Smckusick ivp->iov_base = mtod(mp, caddr_t); 781*68653Smckusick ivp->iov_len = mp->m_len; 782*68653Smckusick ivp++; 783*68653Smckusick } 784*68653Smckusick mp = mp->m_next; 785*68653Smckusick } 786*68653Smckusick 787*68653Smckusick /* 788*68653Smckusick * XXX 789*68653Smckusick * The IO_METASYNC flag indicates that all metadata (and not just 790*68653Smckusick * enough to ensure data integrity) mus be written to stable storage 791*68653Smckusick * synchronously. 792*68653Smckusick * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.) 793*68653Smckusick */ 794*68653Smckusick if (stable == NFSV3WRITE_UNSTABLE) 795*68653Smckusick ioflags = IO_NODELOCKED; 796*68653Smckusick else if (stable == NFSV3WRITE_DATASYNC) 797*68653Smckusick ioflags = (IO_SYNC | IO_NODELOCKED); 798*68653Smckusick else 799*68653Smckusick ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); 800*68653Smckusick uiop->uio_resid = len; 801*68653Smckusick uiop->uio_rw = UIO_WRITE; 802*68653Smckusick uiop->uio_segflg = UIO_SYSSPACE; 803*68653Smckusick uiop->uio_procp = (struct proc *)0; 804*68653Smckusick uiop->uio_offset = off; 805*68653Smckusick error = VOP_WRITE(vp, uiop, ioflags, cred); 806*68653Smckusick nfsstats.srvvop_writes++; 807*68653Smckusick FREE((caddr_t)iv, M_TEMP); 808*68653Smckusick } 809*68653Smckusick aftat_ret = VOP_GETATTR(vp, vap, cred, procp); 810*68653Smckusick vput(vp); 811*68653Smckusick if (!error) 812*68653Smckusick error = aftat_ret; 813*68653Smckusick nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + 814*68653Smckusick 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3)); 815*68653Smckusick if (v3) { 816*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); 817*68653Smckusick if (error) 818*68653Smckusick return (0); 819*68653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); 820*68653Smckusick *tl++ = txdr_unsigned(retlen); 821*68653Smckusick if (stable == NFSV3WRITE_UNSTABLE) 822*68653Smckusick *tl++ = txdr_unsigned(stable); 823*68653Smckusick else 824*68653Smckusick *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); 825*68653Smckusick /* 826*68653Smckusick * Actually, there is no need to txdr these fields, 827*68653Smckusick * but it may make the values more human readable, 828*68653Smckusick * for debugging purposes. 829*68653Smckusick */ 830*68653Smckusick *tl++ = txdr_unsigned(boottime.tv_sec); 831*68653Smckusick *tl = txdr_unsigned(boottime.tv_usec); 832*68653Smckusick } else { 833*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 834*68653Smckusick nfsm_srvfillattr(vap, fp); 835*68653Smckusick } 836*68653Smckusick nfsm_srvdone; 837*68653Smckusick } 838*68653Smckusick 839*68653Smckusick /* 840*68653Smckusick * NFS write service with write gathering support. Called when 841*68653Smckusick * nfsrvw_procrastinate > 0. 842*68653Smckusick * See: Chet Juszczak, "Improving the Write Performance of an NFS Server", 843*68653Smckusick * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco, 844*68653Smckusick * Jan. 1994. 845*68653Smckusick */ 846*68653Smckusick int 847*68653Smckusick nfsrv_writegather(ndp, slp, procp, mrq) 848*68653Smckusick struct nfsrv_descript **ndp; 849*68653Smckusick struct nfssvc_sock *slp; 850*68653Smckusick struct proc *procp; 851*68653Smckusick struct mbuf **mrq; 852*68653Smckusick { 853*68653Smckusick register struct iovec *ivp; 854*68653Smckusick register struct mbuf *mp; 855*68653Smckusick register struct nfsrv_descript *wp, *nfsd, *owp, *swp; 856*68653Smckusick register struct nfs_fattr *fp; 857*68653Smckusick register int i; 858*68653Smckusick struct iovec *iov; 859*68653Smckusick struct nfsrvw_delayhash *wpp; 860*68653Smckusick struct ucred *cred; 861*68653Smckusick struct vattr va, forat; 862*68653Smckusick register u_long *tl; 863*68653Smckusick register long t1; 864*68653Smckusick caddr_t bpos, dpos; 865*68653Smckusick int error = 0, rdonly, cache, len, forat_ret = 1; 866*68653Smckusick int ioflags, aftat_ret = 1, s, adjust, v3, zeroing; 867*68653Smckusick char *cp2; 868*68653Smckusick struct mbuf *mb, *mb2, *mreq, *mrep, *md; 869*68653Smckusick struct vnode *vp; 870*68653Smckusick struct uio io, *uiop = &io; 871*68653Smckusick off_t off; 872*68653Smckusick u_quad_t frev, cur_usec; 873*68653Smckusick 874*68653Smckusick #ifndef nolint 875*68653Smckusick i = 0; 876*68653Smckusick len = 0; 877*68653Smckusick #endif 878*68653Smckusick *mrq = NULL; 879*68653Smckusick if (*ndp) { 880*68653Smckusick nfsd = *ndp; 881*68653Smckusick *ndp = NULL; 882*68653Smckusick mrep = nfsd->nd_mrep; 883*68653Smckusick md = nfsd->nd_md; 884*68653Smckusick dpos = nfsd->nd_dpos; 885*68653Smckusick cred = &nfsd->nd_cr; 886*68653Smckusick v3 = (nfsd->nd_flag & ND_NFSV3); 887*68653Smckusick LIST_INIT(&nfsd->nd_coalesce); 888*68653Smckusick nfsd->nd_mreq = NULL; 889*68653Smckusick nfsd->nd_stable = NFSV3WRITE_FILESYNC; 890*68653Smckusick cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; 891*68653Smckusick nfsd->nd_time = cur_usec + nfsrvw_procrastinate; 892*68653Smckusick 893*68653Smckusick /* 894*68653Smckusick * Now, get the write header.. 895*68653Smckusick */ 896*68653Smckusick nfsm_srvmtofh(&nfsd->nd_fh); 897*68653Smckusick if (v3) { 898*68653Smckusick nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED); 899*68653Smckusick fxdr_hyper(tl, &nfsd->nd_off); 900*68653Smckusick tl += 3; 901*68653Smckusick nfsd->nd_stable = fxdr_unsigned(int, *tl++); 902*68653Smckusick } else { 903*68653Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 904*68653Smckusick nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl); 905*68653Smckusick tl += 2; 906*68653Smckusick } 907*68653Smckusick len = fxdr_unsigned(long, *tl); 908*68653Smckusick nfsd->nd_len = len; 909*68653Smckusick nfsd->nd_eoff = nfsd->nd_off + len; 910*68653Smckusick 911*68653Smckusick /* 912*68653Smckusick * Trim the header out of the mbuf list and trim off any trailing 913*68653Smckusick * junk so that the mbuf list has only the write data. 914*68653Smckusick */ 915*68653Smckusick zeroing = 1; 916*68653Smckusick i = 0; 917*68653Smckusick mp = mrep; 918*68653Smckusick while (mp) { 919*68653Smckusick if (mp == md) { 920*68653Smckusick zeroing = 0; 921*68653Smckusick adjust = dpos - mtod(mp, caddr_t); 922*68653Smckusick mp->m_len -= adjust; 923*68653Smckusick if (mp->m_len > 0 && adjust > 0) 924*68653Smckusick NFSMADV(mp, adjust); 925*68653Smckusick } 926*68653Smckusick if (zeroing) 927*68653Smckusick mp->m_len = 0; 928*68653Smckusick else { 929*68653Smckusick i += mp->m_len; 930*68653Smckusick if (i > len) { 931*68653Smckusick mp->m_len -= (i - len); 932*68653Smckusick zeroing = 1; 933*68653Smckusick } 934*68653Smckusick } 935*68653Smckusick mp = mp->m_next; 936*68653Smckusick } 937*68653Smckusick if (len > NFS_MAXDATA || len < 0 || i < len) { 938*68653Smckusick nfsmout: 939*68653Smckusick m_freem(mrep); 940*68653Smckusick error = EIO; 941*68653Smckusick nfsm_writereply(2 * NFSX_UNSIGNED, v3); 942*68653Smckusick if (v3) 943*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 944*68653Smckusick nfsd->nd_mreq = mreq; 945*68653Smckusick nfsd->nd_mrep = NULL; 946*68653Smckusick nfsd->nd_time = 0; 947*68653Smckusick } 948*68653Smckusick 949*68653Smckusick /* 950*68653Smckusick * Add this entry to the hash and time queues. 951*68653Smckusick */ 952*68653Smckusick s = splsoftclock(); 953*68653Smckusick owp = NULL; 954*68653Smckusick wp = slp->ns_tq.lh_first; 955*68653Smckusick while (wp && wp->nd_time < nfsd->nd_time) { 956*68653Smckusick owp = wp; 957*68653Smckusick wp = wp->nd_tq.le_next; 958*68653Smckusick } 959*68653Smckusick if (owp) { 960*68653Smckusick LIST_INSERT_AFTER(owp, nfsd, nd_tq); 961*68653Smckusick } else { 962*68653Smckusick LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); 963*68653Smckusick } 964*68653Smckusick if (nfsd->nd_mrep) { 965*68653Smckusick wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data); 966*68653Smckusick owp = NULL; 967*68653Smckusick wp = wpp->lh_first; 968*68653Smckusick while (wp && 969*68653Smckusick bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { 970*68653Smckusick owp = wp; 971*68653Smckusick wp = wp->nd_hash.le_next; 972*68653Smckusick } 973*68653Smckusick while (wp && wp->nd_off < nfsd->nd_off && 974*68653Smckusick !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { 975*68653Smckusick owp = wp; 976*68653Smckusick wp = wp->nd_hash.le_next; 977*68653Smckusick } 978*68653Smckusick if (owp) { 979*68653Smckusick LIST_INSERT_AFTER(owp, nfsd, nd_hash); 980*68653Smckusick 981*68653Smckusick /* 982*68653Smckusick * Search the hash list for overlapping entries and 983*68653Smckusick * coalesce. 984*68653Smckusick */ 985*68653Smckusick for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) { 986*68653Smckusick wp = nfsd->nd_hash.le_next; 987*68653Smckusick if (NFSW_SAMECRED(owp, nfsd)) 988*68653Smckusick nfsrvw_coalesce(owp, nfsd); 989*68653Smckusick } 990*68653Smckusick } else { 991*68653Smckusick LIST_INSERT_HEAD(wpp, nfsd, nd_hash); 992*68653Smckusick } 993*68653Smckusick } 994*68653Smckusick splx(s); 995*68653Smckusick } 996*68653Smckusick 99738418Smckusick /* 998*68653Smckusick * Now, do VOP_WRITE()s for any one(s) that need to be done now 999*68653Smckusick * and generate the associated reply mbuf list(s). 100038418Smckusick */ 1001*68653Smckusick loop1: 1002*68653Smckusick cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; 1003*68653Smckusick s = splsoftclock(); 1004*68653Smckusick for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) { 1005*68653Smckusick owp = nfsd->nd_tq.le_next; 1006*68653Smckusick if (nfsd->nd_time > cur_usec) 1007*68653Smckusick break; 1008*68653Smckusick if (nfsd->nd_mreq) 1009*68653Smckusick continue; 1010*68653Smckusick LIST_REMOVE(nfsd, nd_tq); 1011*68653Smckusick LIST_REMOVE(nfsd, nd_hash); 1012*68653Smckusick splx(s); 1013*68653Smckusick mrep = nfsd->nd_mrep; 1014*68653Smckusick nfsd->nd_mrep = NULL; 1015*68653Smckusick cred = &nfsd->nd_cr; 1016*68653Smckusick v3 = (nfsd->nd_flag & ND_NFSV3); 1017*68653Smckusick forat_ret = aftat_ret = 1; 1018*68653Smckusick error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, 1019*68653Smckusick nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH)); 1020*68653Smckusick if (!error) { 1021*68653Smckusick if (v3) 1022*68653Smckusick forat_ret = VOP_GETATTR(vp, &forat, cred, procp); 1023*68653Smckusick if (vp->v_type != VREG) { 1024*68653Smckusick if (v3) 1025*68653Smckusick error = EINVAL; 102638418Smckusick else 1027*68653Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES; 1028*68653Smckusick } 1029*68653Smckusick } else 1030*68653Smckusick vp = NULL; 1031*68653Smckusick if (!error) { 1032*68653Smckusick nqsrv_getl(vp, ND_WRITE); 1033*68653Smckusick error = nfsrv_access(vp, VWRITE, cred, rdonly, procp); 1034*68653Smckusick } 1035*68653Smckusick 1036*68653Smckusick if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) 1037*68653Smckusick ioflags = IO_NODELOCKED; 1038*68653Smckusick else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) 1039*68653Smckusick ioflags = (IO_SYNC | IO_NODELOCKED); 1040*68653Smckusick else 1041*68653Smckusick ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); 1042*68653Smckusick uiop->uio_rw = UIO_WRITE; 1043*68653Smckusick uiop->uio_segflg = UIO_SYSSPACE; 1044*68653Smckusick uiop->uio_procp = (struct proc *)0; 1045*68653Smckusick uiop->uio_offset = nfsd->nd_off; 1046*68653Smckusick uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; 1047*68653Smckusick if (uiop->uio_resid > 0) { 1048*68653Smckusick mp = mrep; 1049*68653Smckusick i = 0; 1050*68653Smckusick while (mp) { 1051*68653Smckusick if (mp->m_len > 0) 1052*68653Smckusick i++; 105338418Smckusick mp = mp->m_next; 1054*68653Smckusick } 1055*68653Smckusick uiop->uio_iovcnt = i; 1056*68653Smckusick MALLOC(iov, struct iovec *, i * sizeof (struct iovec), 1057*68653Smckusick M_TEMP, M_WAITOK); 1058*68653Smckusick uiop->uio_iov = ivp = iov; 1059*68653Smckusick mp = mrep; 1060*68653Smckusick while (mp) { 1061*68653Smckusick if (mp->m_len > 0) { 1062*68653Smckusick ivp->iov_base = mtod(mp, caddr_t); 1063*68653Smckusick ivp->iov_len = mp->m_len; 1064*68653Smckusick ivp++; 1065*68653Smckusick } 1066*68653Smckusick mp = mp->m_next; 1067*68653Smckusick } 1068*68653Smckusick if (!error) { 1069*68653Smckusick error = VOP_WRITE(vp, uiop, ioflags, cred); 1070*68653Smckusick nfsstats.srvvop_writes++; 1071*68653Smckusick } 1072*68653Smckusick FREE((caddr_t)iov, M_TEMP); 107338418Smckusick } 1074*68653Smckusick m_freem(mrep); 1075*68653Smckusick if (vp) { 1076*68653Smckusick aftat_ret = VOP_GETATTR(vp, &va, cred, procp); 1077*68653Smckusick vput(vp); 107838418Smckusick } 1079*68653Smckusick 1080*68653Smckusick /* 1081*68653Smckusick * Loop around generating replies for all write rpcs that have 1082*68653Smckusick * now been completed. 1083*68653Smckusick */ 1084*68653Smckusick swp = nfsd; 1085*68653Smckusick do { 1086*68653Smckusick if (error) { 1087*68653Smckusick nfsm_writereply(NFSX_WCCDATA(v3), v3); 1088*68653Smckusick if (v3) { 1089*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 1090*68653Smckusick } 1091*68653Smckusick } else { 1092*68653Smckusick nfsm_writereply(NFSX_PREOPATTR(v3) + 1093*68653Smckusick NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + 1094*68653Smckusick NFSX_WRITEVERF(v3), v3); 1095*68653Smckusick if (v3) { 1096*68653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 1097*68653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); 1098*68653Smckusick *tl++ = txdr_unsigned(nfsd->nd_len); 1099*68653Smckusick *tl++ = txdr_unsigned(swp->nd_stable); 1100*68653Smckusick /* 1101*68653Smckusick * Actually, there is no need to txdr these fields, 1102*68653Smckusick * but it may make the values more human readable, 1103*68653Smckusick * for debugging purposes. 1104*68653Smckusick */ 1105*68653Smckusick *tl++ = txdr_unsigned(boottime.tv_sec); 1106*68653Smckusick *tl = txdr_unsigned(boottime.tv_usec); 1107*68653Smckusick } else { 1108*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 1109*68653Smckusick nfsm_srvfillattr(&va, fp); 1110*68653Smckusick } 1111*68653Smckusick } 1112*68653Smckusick nfsd->nd_mreq = mreq; 1113*68653Smckusick if (nfsd->nd_mrep) 1114*68653Smckusick panic("nfsrv_write: nd_mrep not free"); 1115*68653Smckusick 1116*68653Smckusick /* 1117*68653Smckusick * Done. Put it at the head of the timer queue so that 1118*68653Smckusick * the final phase can return the reply. 1119*68653Smckusick */ 1120*68653Smckusick s = splsoftclock(); 1121*68653Smckusick if (nfsd != swp) { 1122*68653Smckusick nfsd->nd_time = 0; 1123*68653Smckusick LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); 1124*68653Smckusick } 1125*68653Smckusick nfsd = swp->nd_coalesce.lh_first; 1126*68653Smckusick if (nfsd) { 1127*68653Smckusick LIST_REMOVE(nfsd, nd_tq); 1128*68653Smckusick } 1129*68653Smckusick splx(s); 1130*68653Smckusick } while (nfsd); 1131*68653Smckusick s = splsoftclock(); 1132*68653Smckusick swp->nd_time = 0; 1133*68653Smckusick LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq); 1134*68653Smckusick splx(s); 1135*68653Smckusick goto loop1; 1136*68653Smckusick } 1137*68653Smckusick splx(s); 1138*68653Smckusick 1139*68653Smckusick /* 1140*68653Smckusick * Search for a reply to return. 1141*68653Smckusick */ 1142*68653Smckusick s = splsoftclock(); 1143*68653Smckusick for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) 1144*68653Smckusick if (nfsd->nd_mreq) { 1145*68653Smckusick LIST_REMOVE(nfsd, nd_tq); 1146*68653Smckusick *mrq = nfsd->nd_mreq; 1147*68653Smckusick *ndp = nfsd; 1148*68653Smckusick break; 114938418Smckusick } 1150*68653Smckusick splx(s); 1151*68653Smckusick return (0); 1152*68653Smckusick } 1153*68653Smckusick 1154*68653Smckusick /* 1155*68653Smckusick * Coalesce the write request nfsd into owp. To do this we must: 1156*68653Smckusick * - remove nfsd from the queues 1157*68653Smckusick * - merge nfsd->nd_mrep into owp->nd_mrep 1158*68653Smckusick * - update the nd_eoff and nd_stable for owp 1159*68653Smckusick * - put nfsd on owp's nd_coalesce list 1160*68653Smckusick * NB: Must be called at splsoftclock(). 1161*68653Smckusick */ 1162*68653Smckusick void 1163*68653Smckusick nfsrvw_coalesce(owp, nfsd) 1164*68653Smckusick register struct nfsrv_descript *owp; 1165*68653Smckusick register struct nfsrv_descript *nfsd; 1166*68653Smckusick { 1167*68653Smckusick register int overlap; 1168*68653Smckusick register struct mbuf *mp; 1169*68653Smckusick 1170*68653Smckusick LIST_REMOVE(nfsd, nd_hash); 1171*68653Smckusick LIST_REMOVE(nfsd, nd_tq); 1172*68653Smckusick if (owp->nd_eoff < nfsd->nd_eoff) { 1173*68653Smckusick overlap = owp->nd_eoff - nfsd->nd_off; 1174*68653Smckusick if (overlap < 0) 1175*68653Smckusick panic("nfsrv_coalesce: bad off"); 1176*68653Smckusick if (overlap > 0) 1177*68653Smckusick m_adj(nfsd->nd_mrep, overlap); 1178*68653Smckusick mp = owp->nd_mrep; 1179*68653Smckusick while (mp->m_next) 1180*68653Smckusick mp = mp->m_next; 1181*68653Smckusick mp->m_next = nfsd->nd_mrep; 1182*68653Smckusick owp->nd_eoff = nfsd->nd_eoff; 1183*68653Smckusick } else 1184*68653Smckusick m_freem(nfsd->nd_mrep); 1185*68653Smckusick nfsd->nd_mrep = NULL; 1186*68653Smckusick if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) 1187*68653Smckusick owp->nd_stable = NFSV3WRITE_FILESYNC; 1188*68653Smckusick else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && 1189*68653Smckusick owp->nd_stable == NFSV3WRITE_UNSTABLE) 1190*68653Smckusick owp->nd_stable = NFSV3WRITE_DATASYNC; 1191*68653Smckusick LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq); 1192*68653Smckusick } 1193*68653Smckusick 1194*68653Smckusick /* 1195*68653Smckusick * Sort the group list in increasing numerical order. 1196*68653Smckusick * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1197*68653Smckusick * that used to be here.) 1198*68653Smckusick */ 1199*68653Smckusick void 1200*68653Smckusick nfsrvw_sort(list, num) 1201*68653Smckusick register gid_t *list; 1202*68653Smckusick register int num; 1203*68653Smckusick { 1204*68653Smckusick register int i, j; 1205*68653Smckusick gid_t v; 1206*68653Smckusick 1207*68653Smckusick /* Insertion sort. */ 1208*68653Smckusick for (i = 1; i < num; i++) { 1209*68653Smckusick v = list[i]; 1210*68653Smckusick /* find correct slot for value v, moving others up */ 1211*68653Smckusick for (j = i; --j >= 0 && v < list[j];) 1212*68653Smckusick list[j + 1] = list[j]; 1213*68653Smckusick list[j + 1] = v; 121438418Smckusick } 121538418Smckusick } 121638418Smckusick 121738418Smckusick /* 1218*68653Smckusick * copy credentials making sure that the result can be compared with bcmp(). 1219*68653Smckusick */ 1220*68653Smckusick void 1221*68653Smckusick nfsrv_setcred(incred, outcred) 1222*68653Smckusick register struct ucred *incred, *outcred; 1223*68653Smckusick { 1224*68653Smckusick register int i; 1225*68653Smckusick 1226*68653Smckusick bzero((caddr_t)outcred, sizeof (struct ucred)); 1227*68653Smckusick outcred->cr_ref = 1; 1228*68653Smckusick outcred->cr_uid = incred->cr_uid; 1229*68653Smckusick outcred->cr_ngroups = incred->cr_ngroups; 1230*68653Smckusick for (i = 0; i < incred->cr_ngroups; i++) 1231*68653Smckusick outcred->cr_groups[i] = incred->cr_groups[i]; 1232*68653Smckusick nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 1233*68653Smckusick } 1234*68653Smckusick 1235*68653Smckusick /* 123638418Smckusick * nfs create service 123738418Smckusick * now does a truncate to 0 length via. setattr if it already exists 123838418Smckusick */ 1239*68653Smckusick int 1240*68653Smckusick nfsrv_create(nfsd, slp, procp, mrq) 1241*68653Smckusick struct nfsrv_descript *nfsd; 1242*68653Smckusick struct nfssvc_sock *slp; 1243*68653Smckusick struct proc *procp; 1244*68653Smckusick struct mbuf **mrq; 124538418Smckusick { 1246*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1247*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 1248*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 1249*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 1250*68653Smckusick register struct nfs_fattr *fp; 1251*68653Smckusick struct vattr va, dirfor, diraft; 125238418Smckusick register struct vattr *vap = &va; 125356285Smckusick register struct nfsv2_sattr *sp; 125456285Smckusick register u_long *tl; 125549742Smckusick struct nameidata nd; 125639494Smckusick register caddr_t cp; 125739494Smckusick register long t1; 125839494Smckusick caddr_t bpos; 1259*68653Smckusick int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; 1260*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0; 126139494Smckusick char *cp2; 126239753Smckusick struct mbuf *mb, *mb2, *mreq; 1263*68653Smckusick struct vnode *vp, *dirp = (struct vnode *)0; 1264*68653Smckusick nfsfh_t nfh; 126538418Smckusick fhandle_t *fhp; 1266*68653Smckusick u_quad_t frev, tempsize; 1267*68653Smckusick u_char cverf[NFSX_V3CREATEVERF]; 126838418Smckusick 1269*68653Smckusick #ifndef nolint 1270*68653Smckusick rdev = 0; 1271*68653Smckusick #endif 127252316Sheideman nd.ni_cnd.cn_nameiop = 0; 127338418Smckusick fhp = &nfh.fh_generic; 127438418Smckusick nfsm_srvmtofh(fhp); 1275*68653Smckusick nfsm_srvnamesiz(len); 127652316Sheideman nd.ni_cnd.cn_cred = cred; 127752316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 127852316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 1279*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 1280*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 1281*68653Smckusick if (dirp) { 1282*68653Smckusick if (v3) 1283*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1284*68653Smckusick procp); 1285*68653Smckusick else { 1286*68653Smckusick vrele(dirp); 1287*68653Smckusick dirp = (struct vnode *)0; 1288*68653Smckusick } 1289*68653Smckusick } 1290*68653Smckusick if (error) { 1291*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 1292*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1293*68653Smckusick if (dirp) 1294*68653Smckusick vrele(dirp); 1295*68653Smckusick return (0); 1296*68653Smckusick } 129741361Smckusick VATTR_NULL(vap); 1298*68653Smckusick if (v3) { 1299*68653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 1300*68653Smckusick how = fxdr_unsigned(int, *tl); 1301*68653Smckusick switch (how) { 1302*68653Smckusick case NFSV3CREATE_GUARDED: 1303*68653Smckusick if (nd.ni_vp) { 1304*68653Smckusick error = EEXIST; 1305*68653Smckusick break; 1306*68653Smckusick } 1307*68653Smckusick case NFSV3CREATE_UNCHECKED: 1308*68653Smckusick nfsm_srvsattr(vap); 1309*68653Smckusick break; 1310*68653Smckusick case NFSV3CREATE_EXCLUSIVE: 1311*68653Smckusick nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF); 1312*68653Smckusick bcopy(cp, cverf, NFSX_V3CREATEVERF); 1313*68653Smckusick exclusive_flag = 1; 1314*68653Smckusick if (nd.ni_vp == NULL) 1315*68653Smckusick vap->va_mode = 0; 1316*68653Smckusick break; 1317*68653Smckusick }; 1318*68653Smckusick vap->va_type = VREG; 1319*68653Smckusick } else { 1320*68653Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1321*68653Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); 1322*68653Smckusick if (vap->va_type == VNON) 1323*68653Smckusick vap->va_type = VREG; 1324*68653Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 1325*68653Smckusick switch (vap->va_type) { 1326*68653Smckusick case VREG: 1327*68653Smckusick tsize = fxdr_unsigned(long, sp->sa_size); 1328*68653Smckusick if (tsize != -1) 1329*68653Smckusick vap->va_size = (u_quad_t)tsize; 1330*68653Smckusick break; 1331*68653Smckusick case VCHR: 1332*68653Smckusick case VBLK: 1333*68653Smckusick case VFIFO: 1334*68653Smckusick rdev = fxdr_unsigned(long, sp->sa_size); 1335*68653Smckusick break; 1336*68653Smckusick }; 1337*68653Smckusick } 1338*68653Smckusick 133938418Smckusick /* 134038418Smckusick * Iff doesn't exist, create it 134138418Smckusick * otherwise just truncate to 0 length 134238418Smckusick * should I set the mode too ?? 134338418Smckusick */ 134449742Smckusick if (nd.ni_vp == NULL) { 134546988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 134649742Smckusick vrele(nd.ni_startdir); 1347*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 1348*68653Smckusick error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); 1349*68653Smckusick if (!error) { 1350*68653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 1351*68653Smckusick if (exclusive_flag) { 1352*68653Smckusick exclusive_flag = 0; 1353*68653Smckusick VATTR_NULL(vap); 1354*68653Smckusick bcopy(cverf, (caddr_t)&vap->va_atime, 1355*68653Smckusick NFSX_V3CREATEVERF); 1356*68653Smckusick error = VOP_SETATTR(nd.ni_vp, vap, cred, 1357*68653Smckusick procp); 1358*68653Smckusick } 1359*68653Smckusick } 136042242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 136142242Smckusick vap->va_type == VFIFO) { 136242242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 136342242Smckusick vap->va_type = VFIFO; 1364*68653Smckusick if (error = suser(cred, (u_short *)0)) { 1365*68653Smckusick vrele(nd.ni_startdir); 1366*68653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 136752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 136849742Smckusick vput(nd.ni_dvp); 1369*68653Smckusick nfsm_reply(0); 1370*68653Smckusick return (error); 137142242Smckusick } else 137242242Smckusick vap->va_rdev = (dev_t)rdev; 1373*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 137452234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 137549742Smckusick vrele(nd.ni_startdir); 137642242Smckusick nfsm_reply(0); 137749742Smckusick } 137852316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 137952316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1380*68653Smckusick nd.ni_cnd.cn_proc = procp; 1381*68653Smckusick nd.ni_cnd.cn_cred = cred; 138252316Sheideman if (error = lookup(&nd)) { 138352316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 138442242Smckusick nfsm_reply(0); 138549742Smckusick } 138652316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 138752316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 138849742Smckusick vrele(nd.ni_dvp); 138949742Smckusick vput(nd.ni_vp); 139052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 139149742Smckusick error = EINVAL; 139249742Smckusick nfsm_reply(0); 139349742Smckusick } 139442242Smckusick } else { 1395*68653Smckusick vrele(nd.ni_startdir); 1396*68653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 139752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 139849742Smckusick vput(nd.ni_dvp); 139942242Smckusick error = ENXIO; 140042242Smckusick } 140149742Smckusick vp = nd.ni_vp; 140238418Smckusick } else { 140349742Smckusick vrele(nd.ni_startdir); 140452316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 140549742Smckusick vp = nd.ni_vp; 140649742Smckusick if (nd.ni_dvp == vp) 140749742Smckusick vrele(nd.ni_dvp); 140843359Smckusick else 140949742Smckusick vput(nd.ni_dvp); 141052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 141156285Smckusick if (vap->va_size != -1) { 1412*68653Smckusick error = nfsrv_access(vp, VWRITE, cred, 1413*68653Smckusick (nd.ni_cnd.cn_flags & RDONLY), procp); 1414*68653Smckusick if (!error) { 1415*68653Smckusick nqsrv_getl(vp, ND_WRITE); 1416*68653Smckusick tempsize = vap->va_size; 1417*68653Smckusick VATTR_NULL(vap); 1418*68653Smckusick vap->va_size = tempsize; 1419*68653Smckusick error = VOP_SETATTR(vp, vap, cred, 1420*68653Smckusick procp); 142160401Smckusick } 1422*68653Smckusick if (error) 142356285Smckusick vput(vp); 142442506Smckusick } 142538418Smckusick } 1426*68653Smckusick if (!error) { 1427*68653Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 1428*68653Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1429*68653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid); 1430*68653Smckusick if (!error) 1431*68653Smckusick error = VOP_GETATTR(vp, vap, cred, procp); 143238418Smckusick vput(vp); 143338418Smckusick } 1434*68653Smckusick if (v3) { 1435*68653Smckusick if (exclusive_flag && !error && 1436*68653Smckusick bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF)) 1437*68653Smckusick error = EEXIST; 1438*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1439*68653Smckusick vrele(dirp); 1440*68653Smckusick } 1441*68653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); 1442*68653Smckusick if (v3) { 1443*68653Smckusick if (!error) { 1444*68653Smckusick nfsm_srvpostop_fh(fhp); 1445*68653Smckusick nfsm_srvpostop_attr(0, vap); 1446*68653Smckusick } 1447*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1448*68653Smckusick } else { 1449*68653Smckusick nfsm_srvfhtom(fhp, v3); 1450*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 1451*68653Smckusick nfsm_srvfillattr(vap, fp); 1452*68653Smckusick } 1453*68653Smckusick return (0); 145438418Smckusick nfsmout: 1455*68653Smckusick if (dirp) 1456*68653Smckusick vrele(dirp); 1457*68653Smckusick if (nd.ni_cnd.cn_nameiop) { 145851464Sbostic vrele(nd.ni_startdir); 1459*68653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); 1460*68653Smckusick } 146152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 146249742Smckusick if (nd.ni_dvp == nd.ni_vp) 146349742Smckusick vrele(nd.ni_dvp); 146443359Smckusick else 146549742Smckusick vput(nd.ni_dvp); 146649742Smckusick if (nd.ni_vp) 146749742Smckusick vput(nd.ni_vp); 146838418Smckusick return (error); 146938418Smckusick } 147038418Smckusick 147138418Smckusick /* 1472*68653Smckusick * nfs v3 mknod service 147338418Smckusick */ 1474*68653Smckusick int 1475*68653Smckusick nfsrv_mknod(nfsd, slp, procp, mrq) 1476*68653Smckusick struct nfsrv_descript *nfsd; 1477*68653Smckusick struct nfssvc_sock *slp; 1478*68653Smckusick struct proc *procp; 1479*68653Smckusick struct mbuf **mrq; 148038418Smckusick { 1481*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1482*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 1483*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 1484*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 1485*68653Smckusick register struct nfs_fattr *fp; 1486*68653Smckusick struct vattr va, dirfor, diraft; 1487*68653Smckusick register struct vattr *vap = &va; 1488*68653Smckusick register u_long *tl; 148949742Smckusick struct nameidata nd; 1490*68653Smckusick register caddr_t cp; 149139494Smckusick register long t1; 149239494Smckusick caddr_t bpos; 1493*68653Smckusick int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; 1494*68653Smckusick u_long major, minor; 1495*68653Smckusick enum vtype vtyp; 149639494Smckusick char *cp2; 1497*68653Smckusick struct mbuf *mb, *mb2, *mreq; 1498*68653Smckusick struct vnode *vp, *dirp = (struct vnode *)0; 1499*68653Smckusick nfsfh_t nfh; 150038418Smckusick fhandle_t *fhp; 150152196Smckusick u_quad_t frev; 150238418Smckusick 1503*68653Smckusick nd.ni_cnd.cn_nameiop = 0; 150438418Smckusick fhp = &nfh.fh_generic; 150538418Smckusick nfsm_srvmtofh(fhp); 1506*68653Smckusick nfsm_srvnamesiz(len); 150752316Sheideman nd.ni_cnd.cn_cred = cred; 1508*68653Smckusick nd.ni_cnd.cn_nameiop = CREATE; 1509*68653Smckusick nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 1510*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 1511*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 1512*68653Smckusick if (dirp) 1513*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1514*68653Smckusick if (error) { 1515*68653Smckusick nfsm_reply(NFSX_WCCDATA(1)); 1516*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1517*68653Smckusick if (dirp) 1518*68653Smckusick vrele(dirp); 1519*68653Smckusick return (0); 1520*68653Smckusick } 1521*68653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 1522*68653Smckusick vtyp = nfsv3tov_type(*tl); 1523*68653Smckusick if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1524*68653Smckusick vrele(nd.ni_startdir); 1525*68653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); 1526*68653Smckusick error = NFSERR_BADTYPE; 1527*68653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1528*68653Smckusick vput(nd.ni_dvp); 152938418Smckusick goto out; 1530*68653Smckusick } 1531*68653Smckusick VATTR_NULL(vap); 1532*68653Smckusick nfsm_srvsattr(vap); 1533*68653Smckusick if (vtyp == VCHR || vtyp == VBLK) { 1534*68653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 1535*68653Smckusick major = fxdr_unsigned(u_long, *tl++); 1536*68653Smckusick minor = fxdr_unsigned(u_long, *tl); 1537*68653Smckusick vap->va_rdev = makedev(major, minor); 1538*68653Smckusick } 1539*68653Smckusick 154038418Smckusick /* 1541*68653Smckusick * Iff doesn't exist, create it. 154238418Smckusick */ 1543*68653Smckusick if (nd.ni_vp) { 1544*68653Smckusick vrele(nd.ni_startdir); 1545*68653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); 1546*68653Smckusick error = EEXIST; 1547*68653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1548*68653Smckusick vput(nd.ni_dvp); 154938418Smckusick goto out; 155038418Smckusick } 1551*68653Smckusick vap->va_type = vtyp; 1552*68653Smckusick if (vtyp == VSOCK) { 1553*68653Smckusick vrele(nd.ni_startdir); 1554*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 1555*68653Smckusick error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); 1556*68653Smckusick if (!error) 1557*68653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 1558*68653Smckusick } else { 1559*68653Smckusick if (error = suser(cred, (u_short *)0)) { 1560*68653Smckusick vrele(nd.ni_startdir); 1561*68653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); 1562*68653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1563*68653Smckusick vput(nd.ni_dvp); 1564*68653Smckusick goto out; 1565*68653Smckusick } 1566*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 1567*68653Smckusick if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 1568*68653Smckusick vrele(nd.ni_startdir); 1569*68653Smckusick goto out; 1570*68653Smckusick } 1571*68653Smckusick nd.ni_cnd.cn_nameiop = LOOKUP; 1572*68653Smckusick nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1573*68653Smckusick nd.ni_cnd.cn_proc = procp; 1574*68653Smckusick nd.ni_cnd.cn_cred = procp->p_ucred; 1575*68653Smckusick error = lookup(&nd); 1576*68653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 1577*68653Smckusick if (error) 1578*68653Smckusick goto out; 1579*68653Smckusick if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1580*68653Smckusick vrele(nd.ni_dvp); 1581*68653Smckusick vput(nd.ni_vp); 1582*68653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1583*68653Smckusick error = EINVAL; 1584*68653Smckusick } 1585*68653Smckusick } 158638418Smckusick out: 1587*68653Smckusick vp = nd.ni_vp; 158842467Smckusick if (!error) { 1589*68653Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 1590*68653Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1591*68653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid); 1592*68653Smckusick if (!error) 1593*68653Smckusick error = VOP_GETATTR(vp, vap, cred, procp); 159442467Smckusick vput(vp); 159542467Smckusick } 1596*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1597*68653Smckusick vrele(dirp); 1598*68653Smckusick nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); 1599*68653Smckusick if (!error) { 1600*68653Smckusick nfsm_srvpostop_fh(fhp); 1601*68653Smckusick nfsm_srvpostop_attr(0, vap); 1602*68653Smckusick } 1603*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1604*68653Smckusick return (0); 1605*68653Smckusick nfsmout: 1606*68653Smckusick if (dirp) 1607*68653Smckusick vrele(dirp); 1608*68653Smckusick if (nd.ni_cnd.cn_nameiop) { 1609*68653Smckusick vrele(nd.ni_startdir); 1610*68653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); 1611*68653Smckusick } 1612*68653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1613*68653Smckusick if (nd.ni_dvp == nd.ni_vp) 1614*68653Smckusick vrele(nd.ni_dvp); 1615*68653Smckusick else 1616*68653Smckusick vput(nd.ni_dvp); 1617*68653Smckusick if (nd.ni_vp) 1618*68653Smckusick vput(nd.ni_vp); 1619*68653Smckusick return (error); 1620*68653Smckusick } 1621*68653Smckusick 1622*68653Smckusick /* 1623*68653Smckusick * nfs remove service 1624*68653Smckusick */ 1625*68653Smckusick int 1626*68653Smckusick nfsrv_remove(nfsd, slp, procp, mrq) 1627*68653Smckusick struct nfsrv_descript *nfsd; 1628*68653Smckusick struct nfssvc_sock *slp; 1629*68653Smckusick struct proc *procp; 1630*68653Smckusick struct mbuf **mrq; 1631*68653Smckusick { 1632*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1633*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 1634*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 1635*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 1636*68653Smckusick struct nameidata nd; 1637*68653Smckusick register u_long *tl; 1638*68653Smckusick register long t1; 1639*68653Smckusick caddr_t bpos; 1640*68653Smckusick int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 1641*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 1642*68653Smckusick char *cp2; 1643*68653Smckusick struct mbuf *mb, *mreq, *mb2; 1644*68653Smckusick struct vnode *vp, *dirp; 1645*68653Smckusick struct vattr dirfor, diraft; 1646*68653Smckusick nfsfh_t nfh; 1647*68653Smckusick fhandle_t *fhp; 1648*68653Smckusick u_quad_t frev; 1649*68653Smckusick 1650*68653Smckusick #ifndef nolint 1651*68653Smckusick vp = (struct vnode *)0; 1652*68653Smckusick #endif 1653*68653Smckusick fhp = &nfh.fh_generic; 1654*68653Smckusick nfsm_srvmtofh(fhp); 1655*68653Smckusick nfsm_srvnamesiz(len); 1656*68653Smckusick nd.ni_cnd.cn_cred = cred; 1657*68653Smckusick nd.ni_cnd.cn_nameiop = DELETE; 1658*68653Smckusick nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1659*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 1660*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 1661*68653Smckusick if (dirp) { 1662*68653Smckusick if (v3) 1663*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1664*68653Smckusick procp); 1665*68653Smckusick else 1666*68653Smckusick vrele(dirp); 1667*68653Smckusick } 1668*68653Smckusick if (!error) { 1669*68653Smckusick vp = nd.ni_vp; 1670*68653Smckusick if (vp->v_type == VDIR && 1671*68653Smckusick (error = suser(cred, (u_short *)0))) 1672*68653Smckusick goto out; 1673*68653Smckusick /* 1674*68653Smckusick * The root of a mounted filesystem cannot be deleted. 1675*68653Smckusick */ 1676*68653Smckusick if (vp->v_flag & VROOT) { 1677*68653Smckusick error = EBUSY; 1678*68653Smckusick goto out; 1679*68653Smckusick } 1680*68653Smckusick if (vp->v_flag & VTEXT) 1681*68653Smckusick (void) vnode_pager_uncache(vp); 1682*68653Smckusick out: 1683*68653Smckusick if (!error) { 1684*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 1685*68653Smckusick nqsrv_getl(vp, ND_WRITE); 1686*68653Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1687*68653Smckusick } else { 1688*68653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1689*68653Smckusick if (nd.ni_dvp == vp) 1690*68653Smckusick vrele(nd.ni_dvp); 1691*68653Smckusick else 1692*68653Smckusick vput(nd.ni_dvp); 1693*68653Smckusick vput(vp); 1694*68653Smckusick } 1695*68653Smckusick } 1696*68653Smckusick if (dirp && v3) { 1697*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1698*68653Smckusick vrele(dirp); 1699*68653Smckusick } 1700*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 1701*68653Smckusick if (v3) { 1702*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1703*68653Smckusick return (0); 1704*68653Smckusick } 170538418Smckusick nfsm_srvdone; 170638418Smckusick } 170738418Smckusick 170838418Smckusick /* 170938418Smckusick * nfs rename service 171038418Smckusick */ 1711*68653Smckusick int 1712*68653Smckusick nfsrv_rename(nfsd, slp, procp, mrq) 1713*68653Smckusick struct nfsrv_descript *nfsd; 1714*68653Smckusick struct nfssvc_sock *slp; 1715*68653Smckusick struct proc *procp; 1716*68653Smckusick struct mbuf **mrq; 171738418Smckusick { 1718*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1719*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 1720*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 1721*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 172248050Smckusick register u_long *tl; 172339494Smckusick register long t1; 172439494Smckusick caddr_t bpos; 1725*68653Smckusick int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 1726*68653Smckusick int tdirfor_ret = 1, tdiraft_ret = 1; 1727*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 172839494Smckusick char *cp2; 1729*68653Smckusick struct mbuf *mb, *mreq, *mb2; 173049742Smckusick struct nameidata fromnd, tond; 1731*68653Smckusick struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0; 1732*68653Smckusick struct vnode *tdirp = (struct vnode *)0; 1733*68653Smckusick struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 1734*68653Smckusick nfsfh_t fnfh, tnfh; 173538418Smckusick fhandle_t *ffhp, *tfhp; 173652196Smckusick u_quad_t frev; 173752196Smckusick uid_t saved_uid; 173838418Smckusick 1739*68653Smckusick #ifndef nolint 1740*68653Smckusick fvp = (struct vnode *)0; 1741*68653Smckusick #endif 174238418Smckusick ffhp = &fnfh.fh_generic; 174338418Smckusick tfhp = &tnfh.fh_generic; 174452316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 174552316Sheideman tond.ni_cnd.cn_nameiop = 0; 174638418Smckusick nfsm_srvmtofh(ffhp); 1747*68653Smckusick nfsm_srvnamesiz(len); 174838418Smckusick /* 174952196Smckusick * Remember our original uid so that we can reset cr_uid before 175052196Smckusick * the second nfs_namei() call, in case it is remapped. 175138418Smckusick */ 175252196Smckusick saved_uid = cred->cr_uid; 175352316Sheideman fromnd.ni_cnd.cn_cred = cred; 175452316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 175552316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 1756*68653Smckusick error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, 1757*68653Smckusick &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 1758*68653Smckusick if (fdirp) { 1759*68653Smckusick if (v3) 1760*68653Smckusick fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, 1761*68653Smckusick procp); 1762*68653Smckusick else { 1763*68653Smckusick vrele(fdirp); 1764*68653Smckusick fdirp = (struct vnode *)0; 1765*68653Smckusick } 1766*68653Smckusick } 1767*68653Smckusick if (error) { 1768*68653Smckusick nfsm_reply(2 * NFSX_WCCDATA(v3)); 1769*68653Smckusick nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1770*68653Smckusick nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1771*68653Smckusick if (fdirp) 1772*68653Smckusick vrele(fdirp); 1773*68653Smckusick return (0); 1774*68653Smckusick } 177549742Smckusick fvp = fromnd.ni_vp; 177638418Smckusick nfsm_srvmtofh(tfhp); 177741899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 177852196Smckusick cred->cr_uid = saved_uid; 177952316Sheideman tond.ni_cnd.cn_cred = cred; 178052316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 178152316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 1782*68653Smckusick error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, 1783*68653Smckusick &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 1784*68653Smckusick if (tdirp) { 1785*68653Smckusick if (v3) 1786*68653Smckusick tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, 1787*68653Smckusick procp); 1788*68653Smckusick else { 1789*68653Smckusick vrele(tdirp); 1790*68653Smckusick tdirp = (struct vnode *)0; 1791*68653Smckusick } 1792*68653Smckusick } 1793*68653Smckusick if (error) { 179452234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 179549742Smckusick vrele(fromnd.ni_dvp); 179642467Smckusick vrele(fvp); 179742467Smckusick goto out1; 179842467Smckusick } 179938425Smckusick tdvp = tond.ni_dvp; 180038425Smckusick tvp = tond.ni_vp; 180138418Smckusick if (tvp != NULL) { 180238418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1803*68653Smckusick if (v3) 1804*68653Smckusick error = EEXIST; 1805*68653Smckusick else 1806*68653Smckusick error = EISDIR; 180738418Smckusick goto out; 180838418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1809*68653Smckusick if (v3) 1810*68653Smckusick error = EEXIST; 1811*68653Smckusick else 1812*68653Smckusick error = ENOTDIR; 181338418Smckusick goto out; 181438418Smckusick } 181552196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 1816*68653Smckusick if (v3) 1817*68653Smckusick error = EXDEV; 1818*68653Smckusick else 1819*68653Smckusick error = ENOTEMPTY; 182052196Smckusick goto out; 182152196Smckusick } 182238418Smckusick } 182352196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 1824*68653Smckusick if (v3) 1825*68653Smckusick error = EXDEV; 1826*68653Smckusick else 1827*68653Smckusick error = ENOTEMPTY; 182852196Smckusick goto out; 182952196Smckusick } 183038418Smckusick if (fvp->v_mount != tdvp->v_mount) { 1831*68653Smckusick if (v3) 1832*68653Smckusick error = EXDEV; 1833*68653Smckusick else 1834*68653Smckusick error = ENOTEMPTY; 183538418Smckusick goto out; 183638418Smckusick } 183749742Smckusick if (fvp == tdvp) 1838*68653Smckusick if (v3) 1839*68653Smckusick error = EINVAL; 1840*68653Smckusick else 1841*68653Smckusick error = ENOTEMPTY; 184249742Smckusick /* 184349742Smckusick * If source is the same as the destination (that is the 184449742Smckusick * same vnode with the same name in the same directory), 184549742Smckusick * then there is nothing to do. 184649742Smckusick */ 184749742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 184852316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 184952316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 185052316Sheideman fromnd.ni_cnd.cn_namelen)) 185149742Smckusick error = -1; 185238418Smckusick out: 185342467Smckusick if (!error) { 1854*68653Smckusick nqsrv_getl(fromnd.ni_dvp, ND_WRITE); 1855*68653Smckusick nqsrv_getl(tdvp, ND_WRITE); 185652196Smckusick if (tvp) 1857*68653Smckusick nqsrv_getl(tvp, ND_WRITE); 185852234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 185952234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 186042467Smckusick } else { 186152234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 186243359Smckusick if (tdvp == tvp) 186343359Smckusick vrele(tdvp); 186443359Smckusick else 186543359Smckusick vput(tdvp); 186642467Smckusick if (tvp) 186742467Smckusick vput(tvp); 186852234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 186949742Smckusick vrele(fromnd.ni_dvp); 187042467Smckusick vrele(fvp); 1871*68653Smckusick if (error == -1) 1872*68653Smckusick error = 0; 187338418Smckusick } 187446513Smckusick vrele(tond.ni_startdir); 187552316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 187638418Smckusick out1: 1877*68653Smckusick if (fdirp) { 1878*68653Smckusick fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); 1879*68653Smckusick vrele(fdirp); 1880*68653Smckusick } 1881*68653Smckusick if (tdirp) { 1882*68653Smckusick tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); 1883*68653Smckusick vrele(tdirp); 1884*68653Smckusick } 188549742Smckusick vrele(fromnd.ni_startdir); 188652316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 1887*68653Smckusick nfsm_reply(2 * NFSX_WCCDATA(v3)); 1888*68653Smckusick if (v3) { 1889*68653Smckusick nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1890*68653Smckusick nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1891*68653Smckusick } 1892*68653Smckusick return (0); 189349742Smckusick 189438418Smckusick nfsmout: 1895*68653Smckusick if (fdirp) 1896*68653Smckusick vrele(fdirp); 1897*68653Smckusick if (tdirp) 1898*68653Smckusick vrele(tdirp); 1899*68653Smckusick if (tond.ni_cnd.cn_nameiop) { 190049742Smckusick vrele(tond.ni_startdir); 190152316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 190249742Smckusick } 1903*68653Smckusick if (fromnd.ni_cnd.cn_nameiop) { 190449742Smckusick vrele(fromnd.ni_startdir); 190552316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 190652234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 190749742Smckusick vrele(fromnd.ni_dvp); 190849742Smckusick vrele(fvp); 190949742Smckusick } 191038418Smckusick return (error); 191138418Smckusick } 191238418Smckusick 191338418Smckusick /* 191438418Smckusick * nfs link service 191538418Smckusick */ 1916*68653Smckusick int 1917*68653Smckusick nfsrv_link(nfsd, slp, procp, mrq) 1918*68653Smckusick struct nfsrv_descript *nfsd; 1919*68653Smckusick struct nfssvc_sock *slp; 1920*68653Smckusick struct proc *procp; 1921*68653Smckusick struct mbuf **mrq; 192238418Smckusick { 1923*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1924*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 1925*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 1926*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 192749742Smckusick struct nameidata nd; 192848050Smckusick register u_long *tl; 192939494Smckusick register long t1; 193039494Smckusick caddr_t bpos; 1931*68653Smckusick int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1; 1932*68653Smckusick int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3); 193339494Smckusick char *cp2; 1934*68653Smckusick struct mbuf *mb, *mreq, *mb2; 1935*68653Smckusick struct vnode *vp, *xp, *dirp = (struct vnode *)0; 1936*68653Smckusick struct vattr dirfor, diraft, at; 1937*68653Smckusick nfsfh_t nfh, dnfh; 193838418Smckusick fhandle_t *fhp, *dfhp; 193952196Smckusick u_quad_t frev; 194038418Smckusick 194138418Smckusick fhp = &nfh.fh_generic; 194238418Smckusick dfhp = &dnfh.fh_generic; 194338418Smckusick nfsm_srvmtofh(fhp); 194438418Smckusick nfsm_srvmtofh(dfhp); 1945*68653Smckusick nfsm_srvnamesiz(len); 1946*68653Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, 1947*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 1948*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 1949*68653Smckusick nfsm_srvpostop_attr(getret, &at); 1950*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1951*68653Smckusick return (0); 1952*68653Smckusick } 195352196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 195438418Smckusick goto out1; 195552316Sheideman nd.ni_cnd.cn_cred = cred; 195652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 195752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 1958*68653Smckusick error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, 1959*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 1960*68653Smckusick if (dirp) { 1961*68653Smckusick if (v3) 1962*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1963*68653Smckusick procp); 1964*68653Smckusick else { 1965*68653Smckusick vrele(dirp); 1966*68653Smckusick dirp = (struct vnode *)0; 1967*68653Smckusick } 1968*68653Smckusick } 1969*68653Smckusick if (error) 197038418Smckusick goto out1; 197149742Smckusick xp = nd.ni_vp; 197238418Smckusick if (xp != NULL) { 197338418Smckusick error = EEXIST; 197438418Smckusick goto out; 197538418Smckusick } 197649742Smckusick xp = nd.ni_dvp; 197738418Smckusick if (vp->v_mount != xp->v_mount) 197838418Smckusick error = EXDEV; 197938418Smckusick out: 198042467Smckusick if (!error) { 1981*68653Smckusick nqsrv_getl(vp, ND_WRITE); 1982*68653Smckusick nqsrv_getl(xp, ND_WRITE); 198368539Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); 198442467Smckusick } else { 198552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 198649742Smckusick if (nd.ni_dvp == nd.ni_vp) 198749742Smckusick vrele(nd.ni_dvp); 198843359Smckusick else 198949742Smckusick vput(nd.ni_dvp); 199049742Smckusick if (nd.ni_vp) 199149742Smckusick vrele(nd.ni_vp); 199242467Smckusick } 199338418Smckusick out1: 1994*68653Smckusick if (v3) 1995*68653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp); 1996*68653Smckusick if (dirp) { 1997*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1998*68653Smckusick vrele(dirp); 1999*68653Smckusick } 200038418Smckusick vrele(vp); 2001*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2002*68653Smckusick if (v3) { 2003*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2004*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2005*68653Smckusick return (0); 2006*68653Smckusick } 200738418Smckusick nfsm_srvdone; 200838418Smckusick } 200938418Smckusick 201038418Smckusick /* 201138418Smckusick * nfs symbolic link service 201238418Smckusick */ 2013*68653Smckusick int 2014*68653Smckusick nfsrv_symlink(nfsd, slp, procp, mrq) 2015*68653Smckusick struct nfsrv_descript *nfsd; 2016*68653Smckusick struct nfssvc_sock *slp; 2017*68653Smckusick struct proc *procp; 2018*68653Smckusick struct mbuf **mrq; 201938418Smckusick { 2020*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2021*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 2022*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 2023*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 2024*68653Smckusick struct vattr va, dirfor, diraft; 202549742Smckusick struct nameidata nd; 202638418Smckusick register struct vattr *vap = &va; 202748050Smckusick register u_long *tl; 202839494Smckusick register long t1; 202945285Smckusick struct nfsv2_sattr *sp; 2030*68653Smckusick char *bpos, *cp, *pathcp = (char *)0, *cp2; 203141899Smckusick struct uio io; 203241899Smckusick struct iovec iv; 2033*68653Smckusick int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1; 2034*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 2035*68653Smckusick struct mbuf *mb, *mreq, *mb2; 2036*68653Smckusick struct vnode *dirp = (struct vnode *)0; 2037*68653Smckusick nfsfh_t nfh; 203838418Smckusick fhandle_t *fhp; 203952196Smckusick u_quad_t frev; 204038418Smckusick 2041*68653Smckusick nd.ni_cnd.cn_nameiop = 0; 204238418Smckusick fhp = &nfh.fh_generic; 204338418Smckusick nfsm_srvmtofh(fhp); 2044*68653Smckusick nfsm_srvnamesiz(len); 204552316Sheideman nd.ni_cnd.cn_cred = cred; 204652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 2047*68653Smckusick nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; 2048*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 2049*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 2050*68653Smckusick if (dirp) { 2051*68653Smckusick if (v3) 2052*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2053*68653Smckusick procp); 2054*68653Smckusick else { 2055*68653Smckusick vrele(dirp); 2056*68653Smckusick dirp = (struct vnode *)0; 2057*68653Smckusick } 2058*68653Smckusick } 2059*68653Smckusick if (error) 206042467Smckusick goto out; 2061*68653Smckusick VATTR_NULL(vap); 2062*68653Smckusick if (v3) 2063*68653Smckusick nfsm_srvsattr(vap); 206441899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 206541899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 206641899Smckusick iv.iov_base = pathcp; 206741899Smckusick iv.iov_len = len2; 206841899Smckusick io.uio_resid = len2; 206941899Smckusick io.uio_offset = 0; 207041899Smckusick io.uio_iov = &iv; 207141899Smckusick io.uio_iovcnt = 1; 207241899Smckusick io.uio_segflg = UIO_SYSSPACE; 207341899Smckusick io.uio_rw = UIO_READ; 207448050Smckusick io.uio_procp = (struct proc *)0; 207541899Smckusick nfsm_mtouio(&io, len2); 2076*68653Smckusick if (!v3) { 2077*68653Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 2078*68653Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 2079*68653Smckusick } 208041899Smckusick *(pathcp + len2) = '\0'; 208149742Smckusick if (nd.ni_vp) { 2082*68653Smckusick vrele(nd.ni_startdir); 2083*68653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 208452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 208549742Smckusick if (nd.ni_dvp == nd.ni_vp) 208649742Smckusick vrele(nd.ni_dvp); 208743359Smckusick else 208849742Smckusick vput(nd.ni_dvp); 208949742Smckusick vrele(nd.ni_vp); 209038418Smckusick error = EEXIST; 209138418Smckusick goto out; 209238418Smckusick } 2093*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 209452234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 2095*68653Smckusick if (error) 2096*68653Smckusick vrele(nd.ni_startdir); 2097*68653Smckusick else { 2098*68653Smckusick if (v3) { 2099*68653Smckusick nd.ni_cnd.cn_nameiop = LOOKUP; 2100*68653Smckusick nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW); 2101*68653Smckusick nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF); 2102*68653Smckusick nd.ni_cnd.cn_proc = procp; 2103*68653Smckusick nd.ni_cnd.cn_cred = cred; 2104*68653Smckusick error = lookup(&nd); 2105*68653Smckusick if (!error) { 2106*68653Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 2107*68653Smckusick fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; 2108*68653Smckusick error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); 2109*68653Smckusick if (!error) 2110*68653Smckusick error = VOP_GETATTR(nd.ni_vp, vap, cred, 2111*68653Smckusick procp); 2112*68653Smckusick vput(nd.ni_vp); 2113*68653Smckusick } 2114*68653Smckusick } else 2115*68653Smckusick vrele(nd.ni_startdir); 2116*68653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 2117*68653Smckusick } 211838418Smckusick out: 211941899Smckusick if (pathcp) 212041899Smckusick FREE(pathcp, M_TEMP); 2121*68653Smckusick if (dirp) { 2122*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2123*68653Smckusick vrele(dirp); 2124*68653Smckusick } 2125*68653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2126*68653Smckusick if (v3) { 2127*68653Smckusick if (!error) { 2128*68653Smckusick nfsm_srvpostop_fh(fhp); 2129*68653Smckusick nfsm_srvpostop_attr(0, vap); 2130*68653Smckusick } 2131*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2132*68653Smckusick } 2133*68653Smckusick return (0); 213438418Smckusick nfsmout: 2135*68653Smckusick if (nd.ni_cnd.cn_nameiop) { 2136*68653Smckusick vrele(nd.ni_startdir); 2137*68653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 2138*68653Smckusick } 2139*68653Smckusick if (dirp) 2140*68653Smckusick vrele(dirp); 214152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 214249742Smckusick if (nd.ni_dvp == nd.ni_vp) 214349742Smckusick vrele(nd.ni_dvp); 214443359Smckusick else 214549742Smckusick vput(nd.ni_dvp); 214649742Smckusick if (nd.ni_vp) 214749742Smckusick vrele(nd.ni_vp); 214841899Smckusick if (pathcp) 214941899Smckusick FREE(pathcp, M_TEMP); 215038418Smckusick return (error); 215138418Smckusick } 215238418Smckusick 215338418Smckusick /* 215438418Smckusick * nfs mkdir service 215538418Smckusick */ 2156*68653Smckusick int 2157*68653Smckusick nfsrv_mkdir(nfsd, slp, procp, mrq) 2158*68653Smckusick struct nfsrv_descript *nfsd; 2159*68653Smckusick struct nfssvc_sock *slp; 2160*68653Smckusick struct proc *procp; 2161*68653Smckusick struct mbuf **mrq; 216238418Smckusick { 2163*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2164*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 2165*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 2166*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 2167*68653Smckusick struct vattr va, dirfor, diraft; 216838418Smckusick register struct vattr *vap = &va; 2169*68653Smckusick register struct nfs_fattr *fp; 217049742Smckusick struct nameidata nd; 217139494Smckusick register caddr_t cp; 217248050Smckusick register u_long *tl; 217339494Smckusick register long t1; 217439494Smckusick caddr_t bpos; 2175*68653Smckusick int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 2176*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 217739494Smckusick char *cp2; 217839753Smckusick struct mbuf *mb, *mb2, *mreq; 2179*68653Smckusick struct vnode *vp, *dirp = (struct vnode *)0; 2180*68653Smckusick nfsfh_t nfh; 218138418Smckusick fhandle_t *fhp; 218252196Smckusick u_quad_t frev; 218338418Smckusick 218438418Smckusick fhp = &nfh.fh_generic; 218538418Smckusick nfsm_srvmtofh(fhp); 2186*68653Smckusick nfsm_srvnamesiz(len); 218752316Sheideman nd.ni_cnd.cn_cred = cred; 218852316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 218952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 2190*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 2191*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 2192*68653Smckusick if (dirp) { 2193*68653Smckusick if (v3) 2194*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2195*68653Smckusick procp); 2196*68653Smckusick else { 2197*68653Smckusick vrele(dirp); 2198*68653Smckusick dirp = (struct vnode *)0; 2199*68653Smckusick } 2200*68653Smckusick } 2201*68653Smckusick if (error) { 2202*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 2203*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2204*68653Smckusick if (dirp) 2205*68653Smckusick vrele(dirp); 2206*68653Smckusick return (0); 2207*68653Smckusick } 220841361Smckusick VATTR_NULL(vap); 2209*68653Smckusick if (v3) { 2210*68653Smckusick nfsm_srvsattr(vap); 2211*68653Smckusick } else { 2212*68653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 2213*68653Smckusick vap->va_mode = nfstov_mode(*tl++); 2214*68653Smckusick } 221538418Smckusick vap->va_type = VDIR; 221649742Smckusick vp = nd.ni_vp; 221738418Smckusick if (vp != NULL) { 221852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 221949742Smckusick if (nd.ni_dvp == vp) 222049742Smckusick vrele(nd.ni_dvp); 222143359Smckusick else 222249742Smckusick vput(nd.ni_dvp); 222342467Smckusick vrele(vp); 222438418Smckusick error = EEXIST; 2225*68653Smckusick goto out; 222638418Smckusick } 2227*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 2228*68653Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); 2229*68653Smckusick if (!error) { 2230*68653Smckusick vp = nd.ni_vp; 2231*68653Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 2232*68653Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 2233*68653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid); 2234*68653Smckusick if (!error) 2235*68653Smckusick error = VOP_GETATTR(vp, vap, cred, procp); 223638418Smckusick vput(vp); 223738418Smckusick } 2238*68653Smckusick out: 2239*68653Smckusick if (dirp) { 2240*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2241*68653Smckusick vrele(dirp); 2242*68653Smckusick } 2243*68653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2244*68653Smckusick if (v3) { 2245*68653Smckusick if (!error) { 2246*68653Smckusick nfsm_srvpostop_fh(fhp); 2247*68653Smckusick nfsm_srvpostop_attr(0, vap); 2248*68653Smckusick } 2249*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2250*68653Smckusick } else { 2251*68653Smckusick nfsm_srvfhtom(fhp, v3); 2252*68653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 2253*68653Smckusick nfsm_srvfillattr(vap, fp); 2254*68653Smckusick } 2255*68653Smckusick return (0); 225638418Smckusick nfsmout: 2257*68653Smckusick if (dirp) 2258*68653Smckusick vrele(dirp); 225952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 226049742Smckusick if (nd.ni_dvp == nd.ni_vp) 226149742Smckusick vrele(nd.ni_dvp); 226243359Smckusick else 226349742Smckusick vput(nd.ni_dvp); 226449742Smckusick if (nd.ni_vp) 226549742Smckusick vrele(nd.ni_vp); 226638418Smckusick return (error); 226738418Smckusick } 226838418Smckusick 226938418Smckusick /* 227038418Smckusick * nfs rmdir service 227138418Smckusick */ 2272*68653Smckusick int 2273*68653Smckusick nfsrv_rmdir(nfsd, slp, procp, mrq) 2274*68653Smckusick struct nfsrv_descript *nfsd; 2275*68653Smckusick struct nfssvc_sock *slp; 2276*68653Smckusick struct proc *procp; 2277*68653Smckusick struct mbuf **mrq; 227838418Smckusick { 2279*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2280*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 2281*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 2282*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 228348050Smckusick register u_long *tl; 228439494Smckusick register long t1; 228539494Smckusick caddr_t bpos; 2286*68653Smckusick int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 2287*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 228839494Smckusick char *cp2; 2289*68653Smckusick struct mbuf *mb, *mreq, *mb2; 2290*68653Smckusick struct vnode *vp, *dirp = (struct vnode *)0; 2291*68653Smckusick struct vattr dirfor, diraft; 2292*68653Smckusick nfsfh_t nfh; 229338418Smckusick fhandle_t *fhp; 229449742Smckusick struct nameidata nd; 229552196Smckusick u_quad_t frev; 229638418Smckusick 229738418Smckusick fhp = &nfh.fh_generic; 229838418Smckusick nfsm_srvmtofh(fhp); 2299*68653Smckusick nfsm_srvnamesiz(len); 230052316Sheideman nd.ni_cnd.cn_cred = cred; 230152316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 230252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 2303*68653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 2304*68653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); 2305*68653Smckusick if (dirp) { 2306*68653Smckusick if (v3) 2307*68653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2308*68653Smckusick procp); 2309*68653Smckusick else { 2310*68653Smckusick vrele(dirp); 2311*68653Smckusick dirp = (struct vnode *)0; 2312*68653Smckusick } 2313*68653Smckusick } 2314*68653Smckusick if (error) { 2315*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 2316*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2317*68653Smckusick if (dirp) 2318*68653Smckusick vrele(dirp); 2319*68653Smckusick return (0); 2320*68653Smckusick } 232149742Smckusick vp = nd.ni_vp; 232238418Smckusick if (vp->v_type != VDIR) { 232338418Smckusick error = ENOTDIR; 232438418Smckusick goto out; 232538418Smckusick } 232638418Smckusick /* 232738418Smckusick * No rmdir "." please. 232838418Smckusick */ 232949742Smckusick if (nd.ni_dvp == vp) { 233038418Smckusick error = EINVAL; 233138418Smckusick goto out; 233238418Smckusick } 233338418Smckusick /* 233449454Smckusick * The root of a mounted filesystem cannot be deleted. 233538418Smckusick */ 233638418Smckusick if (vp->v_flag & VROOT) 233738418Smckusick error = EBUSY; 233838418Smckusick out: 233942467Smckusick if (!error) { 2340*68653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE); 2341*68653Smckusick nqsrv_getl(vp, ND_WRITE); 234252234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 234342467Smckusick } else { 234452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 234549742Smckusick if (nd.ni_dvp == nd.ni_vp) 234649742Smckusick vrele(nd.ni_dvp); 234743359Smckusick else 234849742Smckusick vput(nd.ni_dvp); 234942467Smckusick vput(vp); 235042467Smckusick } 2351*68653Smckusick if (dirp) { 2352*68653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2353*68653Smckusick vrele(dirp); 2354*68653Smckusick } 2355*68653Smckusick nfsm_reply(NFSX_WCCDATA(v3)); 2356*68653Smckusick if (v3) { 2357*68653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2358*68653Smckusick return (0); 2359*68653Smckusick } 236038418Smckusick nfsm_srvdone; 236138418Smckusick } 236238418Smckusick 236338418Smckusick /* 236438418Smckusick * nfs readdir service 236538418Smckusick * - mallocs what it thinks is enough to read 236648050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 236738418Smckusick * - calls VOP_READDIR() 236840115Smckusick * - loops around building the reply 236938425Smckusick * if the output generated exceeds count break out of loop 237038425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 237138425Smckusick * tightly in mbuf clusters. 237238418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 237338425Smckusick * reads nothing 237438418Smckusick * - as such one readdir rpc will return eof false although you are there 237538425Smckusick * and then the next will return eof 237652441Smckusick * - it trims out records with d_fileno == 0 237738425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 237838425Smckusick * for other os'. 237938418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 238038425Smckusick * than requested, but this may not apply to all filesystems. For 238138425Smckusick * example, client NFS does not { although it is never remote mounted 238238425Smckusick * anyhow } 2383*68653Smckusick * The alternate call nfsrv_readdirplus() does lookups as well. 238438418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 238538425Smckusick * argument is a count of.. just name strings and file id's or the 238638425Smckusick * entire reply rpc or ... 238738425Smckusick * I tried just file name and id sizes and it confused the Sun client, 238838425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 238938425Smckusick * to including the status longwords that are not a part of the dir. 239038425Smckusick * "entry" structures, but are in the rpc. 239138418Smckusick */ 239252196Smckusick struct flrep { 2393*68653Smckusick nfsuint64 fl_off; 2394*68653Smckusick u_long fl_postopok; 2395*68653Smckusick u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)]; 2396*68653Smckusick u_long fl_fhok; 2397*68653Smckusick u_long fl_fhsize; 2398*68653Smckusick u_long fl_nfh[NFSX_V3FH / sizeof (u_long)]; 239952196Smckusick }; 240052196Smckusick 2401*68653Smckusick int 2402*68653Smckusick nfsrv_readdir(nfsd, slp, procp, mrq) 2403*68653Smckusick struct nfsrv_descript *nfsd; 2404*68653Smckusick struct nfssvc_sock *slp; 2405*68653Smckusick struct proc *procp; 2406*68653Smckusick struct mbuf **mrq; 240738418Smckusick { 2408*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2409*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 2410*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 2411*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 241238418Smckusick register char *bp, *be; 241338418Smckusick register struct mbuf *mp; 241452441Smckusick register struct dirent *dp; 241539494Smckusick register caddr_t cp; 241648050Smckusick register u_long *tl; 241739494Smckusick register long t1; 241839494Smckusick caddr_t bpos; 241952196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 242052196Smckusick char *cpos, *cend, *cp2, *rbuf; 242138418Smckusick struct vnode *vp; 2422*68653Smckusick struct vattr at; 2423*68653Smckusick nfsfh_t nfh; 242438418Smckusick fhandle_t *fhp; 242538418Smckusick struct uio io; 242638418Smckusick struct iovec iv; 2427*68653Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2428*68653Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies; 2429*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 2430*68653Smckusick u_quad_t frev, off, toff, verf; 2431*68653Smckusick u_long *cookies = NULL, *cookiep; 243238418Smckusick 243338418Smckusick fhp = &nfh.fh_generic; 243438418Smckusick nfsm_srvmtofh(fhp); 2435*68653Smckusick if (v3) { 2436*68653Smckusick nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED); 2437*68653Smckusick fxdr_hyper(tl, &toff); 2438*68653Smckusick tl += 2; 2439*68653Smckusick fxdr_hyper(tl, &verf); 2440*68653Smckusick tl += 2; 2441*68653Smckusick } else { 2442*68653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 2443*68653Smckusick toff = fxdr_unsigned(u_quad_t, *tl++); 2444*68653Smckusick } 2445*68653Smckusick off = toff; 244648050Smckusick cnt = fxdr_unsigned(int, *tl); 2447*68653Smckusick siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2448*68653Smckusick xfer = NFS_SRVMAXDATA(nfsd); 2449*68653Smckusick if (siz > xfer) 2450*68653Smckusick siz = xfer; 245138418Smckusick fullsiz = siz; 2452*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 2453*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 2454*68653Smckusick nfsm_reply(NFSX_UNSIGNED); 2455*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2456*68653Smckusick return (0); 2457*68653Smckusick } 2458*68653Smckusick nqsrv_getl(vp, ND_READ); 2459*68653Smckusick if (v3) { 2460*68653Smckusick error = getret = VOP_GETATTR(vp, &at, cred, procp); 2461*68653Smckusick if (!error && toff && verf != at.va_filerev) 2462*68653Smckusick error = NFSERR_BAD_COOKIE; 2463*68653Smckusick } 2464*68653Smckusick if (!error) 2465*68653Smckusick error = nfsrv_access(vp, VEXEC, cred, rdonly, procp); 2466*68653Smckusick if (error) { 246738418Smckusick vput(vp); 2468*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3)); 2469*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2470*68653Smckusick return (0); 247138418Smckusick } 247238418Smckusick VOP_UNLOCK(vp); 247338418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 247438418Smckusick again: 247538418Smckusick iv.iov_base = rbuf; 247638418Smckusick iv.iov_len = fullsiz; 247738418Smckusick io.uio_iov = &iv; 247838418Smckusick io.uio_iovcnt = 1; 247956285Smckusick io.uio_offset = (off_t)off; 248038418Smckusick io.uio_resid = fullsiz; 248138418Smckusick io.uio_segflg = UIO_SYSSPACE; 248238418Smckusick io.uio_rw = UIO_READ; 248348050Smckusick io.uio_procp = (struct proc *)0; 2484*68653Smckusick eofflag = 0; 2485*68653Smckusick if (cookies) { 2486*68653Smckusick free((caddr_t)cookies, M_TEMP); 2487*68653Smckusick cookies = NULL; 2488*68653Smckusick } 2489*68653Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 249056285Smckusick off = (off_t)io.uio_offset; 2491*68653Smckusick if (!cookies && !error) 2492*68653Smckusick error = NFSERR_PERM; 2493*68653Smckusick if (v3) { 2494*68653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp); 2495*68653Smckusick if (!error) 2496*68653Smckusick error = getret; 2497*68653Smckusick } 249838418Smckusick if (error) { 249938418Smckusick vrele(vp); 250038418Smckusick free((caddr_t)rbuf, M_TEMP); 2501*68653Smckusick if (cookies) 2502*68653Smckusick free((caddr_t)cookies, M_TEMP); 2503*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3)); 2504*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2505*68653Smckusick return (0); 250638418Smckusick } 250738418Smckusick if (io.uio_resid) { 250838418Smckusick siz -= io.uio_resid; 250938418Smckusick 251038418Smckusick /* 251138418Smckusick * If nothing read, return eof 251238418Smckusick * rpc reply 251338418Smckusick */ 251438418Smckusick if (siz == 0) { 251538418Smckusick vrele(vp); 2516*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + 2517*68653Smckusick 2 * NFSX_UNSIGNED); 2518*68653Smckusick if (v3) { 2519*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2520*68653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); 2521*68653Smckusick txdr_hyper(&at.va_filerev, tl); 2522*68653Smckusick tl += 2; 2523*68653Smckusick } else 2524*68653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 252548050Smckusick *tl++ = nfs_false; 252648050Smckusick *tl = nfs_true; 252738418Smckusick FREE((caddr_t)rbuf, M_TEMP); 2528*68653Smckusick FREE((caddr_t)cookies, M_TEMP); 252938418Smckusick return (0); 253038418Smckusick } 253138418Smckusick } 253240115Smckusick 253338418Smckusick /* 253438418Smckusick * Check for degenerate cases of nothing useful read. 253540115Smckusick * If so go try again 253638418Smckusick */ 253767363Smckusick cpos = rbuf; 253840115Smckusick cend = rbuf + siz; 2539*68653Smckusick dp = (struct dirent *)cpos; 2540*68653Smckusick cookiep = cookies; 2541*68653Smckusick while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) { 2542*68653Smckusick cpos += dp->d_reclen; 254352441Smckusick dp = (struct dirent *)cpos; 2544*68653Smckusick cookiep++; 2545*68653Smckusick ncookies--; 254640115Smckusick } 2547*68653Smckusick if (cpos >= cend || ncookies == 0) { 2548*68653Smckusick toff = off; 254938418Smckusick siz = fullsiz; 255038418Smckusick goto again; 255138418Smckusick } 255240115Smckusick 2553*68653Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 2554*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); 2555*68653Smckusick if (v3) { 2556*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2557*68653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 2558*68653Smckusick txdr_hyper(&at.va_filerev, tl); 2559*68653Smckusick } 256052196Smckusick mp = mp2 = mb; 256152196Smckusick bp = bpos; 256252196Smckusick be = bp + M_TRAILINGSPACE(mp); 256352196Smckusick 256452196Smckusick /* Loop through the records and build reply */ 2565*68653Smckusick while (cpos < cend && ncookies > 0) { 256652441Smckusick if (dp->d_fileno != 0) { 256752196Smckusick nlen = dp->d_namlen; 256852196Smckusick rem = nfsm_rndup(nlen)-nlen; 2569*68653Smckusick len += (4 * NFSX_UNSIGNED + nlen + rem); 2570*68653Smckusick if (v3) 2571*68653Smckusick len += 2 * NFSX_UNSIGNED; 257252196Smckusick if (len > cnt) { 257352196Smckusick eofflag = 0; 257452196Smckusick break; 257552196Smckusick } 257652441Smckusick /* 257752441Smckusick * Build the directory record xdr from 257852441Smckusick * the dirent entry. 257952441Smckusick */ 258052196Smckusick nfsm_clget; 258152196Smckusick *tl = nfs_true; 258252196Smckusick bp += NFSX_UNSIGNED; 2583*68653Smckusick if (v3) { 2584*68653Smckusick nfsm_clget; 2585*68653Smckusick *tl = 0; 2586*68653Smckusick bp += NFSX_UNSIGNED; 2587*68653Smckusick } 258852196Smckusick nfsm_clget; 258952441Smckusick *tl = txdr_unsigned(dp->d_fileno); 259052196Smckusick bp += NFSX_UNSIGNED; 259152196Smckusick nfsm_clget; 259252196Smckusick *tl = txdr_unsigned(nlen); 259352196Smckusick bp += NFSX_UNSIGNED; 259452196Smckusick 259552196Smckusick /* And loop around copying the name */ 259652196Smckusick xfer = nlen; 259752196Smckusick cp = dp->d_name; 259852196Smckusick while (xfer > 0) { 259952196Smckusick nfsm_clget; 260052196Smckusick if ((bp+xfer) > be) 260152196Smckusick tsiz = be-bp; 260252196Smckusick else 260352196Smckusick tsiz = xfer; 260452196Smckusick bcopy(cp, bp, tsiz); 260552196Smckusick bp += tsiz; 260652196Smckusick xfer -= tsiz; 260752196Smckusick if (xfer > 0) 260852196Smckusick cp += tsiz; 260952196Smckusick } 261052196Smckusick /* And null pad to a long boundary */ 261152196Smckusick for (i = 0; i < rem; i++) 261252196Smckusick *bp++ = '\0'; 261352196Smckusick nfsm_clget; 261452196Smckusick 261552196Smckusick /* Finish off the record */ 2616*68653Smckusick if (v3) { 2617*68653Smckusick *tl = 0; 2618*68653Smckusick bp += NFSX_UNSIGNED; 2619*68653Smckusick nfsm_clget; 2620*68653Smckusick } 2621*68653Smckusick *tl = txdr_unsigned(*cookiep); 262252196Smckusick bp += NFSX_UNSIGNED; 262367363Smckusick } 262452196Smckusick cpos += dp->d_reclen; 262552441Smckusick dp = (struct dirent *)cpos; 2626*68653Smckusick cookiep++; 2627*68653Smckusick ncookies--; 262852196Smckusick } 262938418Smckusick vrele(vp); 263052196Smckusick nfsm_clget; 263152196Smckusick *tl = nfs_false; 263252196Smckusick bp += NFSX_UNSIGNED; 263352196Smckusick nfsm_clget; 263452196Smckusick if (eofflag) 263552196Smckusick *tl = nfs_true; 263652196Smckusick else 263752196Smckusick *tl = nfs_false; 263852196Smckusick bp += NFSX_UNSIGNED; 263952196Smckusick if (mp != mb) { 264052196Smckusick if (bp < be) 264152196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 264252196Smckusick } else 264352196Smckusick mp->m_len += bp - bpos; 2644*68653Smckusick FREE((caddr_t)rbuf, M_TEMP); 2645*68653Smckusick FREE((caddr_t)cookies, M_TEMP); 264652196Smckusick nfsm_srvdone; 264752196Smckusick } 264852196Smckusick 2649*68653Smckusick int 2650*68653Smckusick nfsrv_readdirplus(nfsd, slp, procp, mrq) 2651*68653Smckusick struct nfsrv_descript *nfsd; 2652*68653Smckusick struct nfssvc_sock *slp; 2653*68653Smckusick struct proc *procp; 2654*68653Smckusick struct mbuf **mrq; 265552196Smckusick { 2656*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2657*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 2658*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 2659*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 266052196Smckusick register char *bp, *be; 266152196Smckusick register struct mbuf *mp; 266252441Smckusick register struct dirent *dp; 266352196Smckusick register caddr_t cp; 266452196Smckusick register u_long *tl; 266552196Smckusick register long t1; 266652196Smckusick caddr_t bpos; 266752196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 266852196Smckusick char *cpos, *cend, *cp2, *rbuf; 266952196Smckusick struct vnode *vp, *nvp; 267052196Smckusick struct flrep fl; 2671*68653Smckusick nfsfh_t nfh; 2672*68653Smckusick fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 267352196Smckusick struct uio io; 267452196Smckusick struct iovec iv; 2675*68653Smckusick struct vattr va, at, *vap = &va; 2676*68653Smckusick struct nfs_fattr *fp; 2677*68653Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2678*68653Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies; 2679*68653Smckusick u_quad_t frev, off, toff, verf; 2680*68653Smckusick u_long *cookies = NULL, *cookiep; 268152196Smckusick 268252196Smckusick fhp = &nfh.fh_generic; 268352196Smckusick nfsm_srvmtofh(fhp); 2684*68653Smckusick nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED); 2685*68653Smckusick fxdr_hyper(tl, &toff); 2686*68653Smckusick tl += 2; 2687*68653Smckusick fxdr_hyper(tl, &verf); 2688*68653Smckusick tl += 2; 2689*68653Smckusick siz = fxdr_unsigned(int, *tl++); 2690*68653Smckusick cnt = fxdr_unsigned(int, *tl); 2691*68653Smckusick off = toff; 2692*68653Smckusick siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2693*68653Smckusick xfer = NFS_SRVMAXDATA(nfsd); 2694*68653Smckusick if (siz > xfer) 2695*68653Smckusick siz = xfer; 269652196Smckusick fullsiz = siz; 2697*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 2698*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 2699*68653Smckusick nfsm_reply(NFSX_UNSIGNED); 2700*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2701*68653Smckusick return (0); 2702*68653Smckusick } 2703*68653Smckusick error = getret = VOP_GETATTR(vp, &at, cred, procp); 2704*68653Smckusick if (!error && toff && verf != at.va_filerev) 2705*68653Smckusick error = NFSERR_BAD_COOKIE; 2706*68653Smckusick if (!error) { 2707*68653Smckusick nqsrv_getl(vp, ND_READ); 2708*68653Smckusick error = nfsrv_access(vp, VEXEC, cred, rdonly, procp); 2709*68653Smckusick } 2710*68653Smckusick if (error) { 271152196Smckusick vput(vp); 2712*68653Smckusick nfsm_reply(NFSX_V3POSTOPATTR); 2713*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2714*68653Smckusick return (0); 271552196Smckusick } 271652196Smckusick VOP_UNLOCK(vp); 271752196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 271852196Smckusick again: 271952196Smckusick iv.iov_base = rbuf; 272052196Smckusick iv.iov_len = fullsiz; 272152196Smckusick io.uio_iov = &iv; 272252196Smckusick io.uio_iovcnt = 1; 272356285Smckusick io.uio_offset = (off_t)off; 272452196Smckusick io.uio_resid = fullsiz; 272552196Smckusick io.uio_segflg = UIO_SYSSPACE; 272652196Smckusick io.uio_rw = UIO_READ; 272752196Smckusick io.uio_procp = (struct proc *)0; 2728*68653Smckusick eofflag = 0; 2729*68653Smckusick if (cookies) { 2730*68653Smckusick free((caddr_t)cookies, M_TEMP); 2731*68653Smckusick cookies = NULL; 2732*68653Smckusick } 2733*68653Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 2734*68653Smckusick off = (u_quad_t)io.uio_offset; 2735*68653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp); 2736*68653Smckusick if (!cookies && !error) 2737*68653Smckusick error = NFSERR_PERM; 2738*68653Smckusick if (!error) 2739*68653Smckusick error = getret; 274052196Smckusick if (error) { 274152196Smckusick vrele(vp); 2742*68653Smckusick if (cookies) 2743*68653Smckusick free((caddr_t)cookies, M_TEMP); 274452196Smckusick free((caddr_t)rbuf, M_TEMP); 2745*68653Smckusick nfsm_reply(NFSX_V3POSTOPATTR); 2746*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2747*68653Smckusick return (0); 274852196Smckusick } 274952196Smckusick if (io.uio_resid) { 275052196Smckusick siz -= io.uio_resid; 275152196Smckusick 275252196Smckusick /* 275352196Smckusick * If nothing read, return eof 275452196Smckusick * rpc reply 275552196Smckusick */ 275652196Smckusick if (siz == 0) { 275752196Smckusick vrele(vp); 2758*68653Smckusick nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2759*68653Smckusick 2 * NFSX_UNSIGNED); 2760*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2761*68653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); 2762*68653Smckusick txdr_hyper(&at.va_filerev, tl); 2763*68653Smckusick tl += 2; 276452196Smckusick *tl++ = nfs_false; 276552196Smckusick *tl = nfs_true; 2766*68653Smckusick FREE((caddr_t)cookies, M_TEMP); 276752196Smckusick FREE((caddr_t)rbuf, M_TEMP); 276852196Smckusick return (0); 276952196Smckusick } 277052196Smckusick } 277152196Smckusick 277252196Smckusick /* 277352196Smckusick * Check for degenerate cases of nothing useful read. 277452196Smckusick * If so go try again 277552196Smckusick */ 277667363Smckusick cpos = rbuf; 277752196Smckusick cend = rbuf + siz; 2778*68653Smckusick dp = (struct dirent *)cpos; 2779*68653Smckusick cookiep = cookies; 2780*68653Smckusick while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) { 2781*68653Smckusick cpos += dp->d_reclen; 278252441Smckusick dp = (struct dirent *)cpos; 2783*68653Smckusick cookiep++; 2784*68653Smckusick ncookies--; 278552196Smckusick } 2786*68653Smckusick if (cpos >= cend || ncookies == 0) { 2787*68653Smckusick toff = off; 278852196Smckusick siz = fullsiz; 278952196Smckusick goto again; 279052196Smckusick } 279152196Smckusick 2792*68653Smckusick dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; 2793*68653Smckusick nfsm_reply(cnt); 2794*68653Smckusick nfsm_srvpostop_attr(getret, &at); 2795*68653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 2796*68653Smckusick txdr_hyper(&at.va_filerev, tl); 279752196Smckusick mp = mp2 = mb; 279852196Smckusick bp = bpos; 279952196Smckusick be = bp + M_TRAILINGSPACE(mp); 280038418Smckusick 280138418Smckusick /* Loop through the records and build reply */ 2802*68653Smckusick while (cpos < cend && ncookies > 0) { 280352441Smckusick if (dp->d_fileno != 0) { 280438418Smckusick nlen = dp->d_namlen; 280538418Smckusick rem = nfsm_rndup(nlen)-nlen; 280638425Smckusick 280738418Smckusick /* 280852196Smckusick * For readdir_and_lookup get the vnode using 280952196Smckusick * the file number. 281038418Smckusick */ 281154665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 281252196Smckusick goto invalid; 2813*68653Smckusick bzero((caddr_t)nfhp, NFSX_V3FH); 2814*68653Smckusick nfhp->fh_fsid = 281555655Smckusick nvp->v_mount->mnt_stat.f_fsid; 2816*68653Smckusick if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 281755655Smckusick vput(nvp); 281855655Smckusick goto invalid; 281955655Smckusick } 2820*68653Smckusick if (VOP_GETATTR(nvp, vap, cred, procp)) { 282152196Smckusick vput(nvp); 282252196Smckusick goto invalid; 282352196Smckusick } 282452196Smckusick vput(nvp); 2825*68653Smckusick 2826*68653Smckusick /* 2827*68653Smckusick * If either the dircount or maxcount will be 2828*68653Smckusick * exceeded, get out now. Both of these lengths 2829*68653Smckusick * are calculated conservatively, including all 2830*68653Smckusick * XDR overheads. 2831*68653Smckusick */ 2832*68653Smckusick len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + 2833*68653Smckusick NFSX_V3POSTOPATTR); 2834*68653Smckusick dirlen += (6 * NFSX_UNSIGNED + nlen + rem); 2835*68653Smckusick if (len > cnt || dirlen > fullsiz) { 283641899Smckusick eofflag = 0; 283738418Smckusick break; 283841899Smckusick } 2839*68653Smckusick 284052441Smckusick /* 284152441Smckusick * Build the directory record xdr from 284252441Smckusick * the dirent entry. 284352441Smckusick */ 2844*68653Smckusick fp = (struct nfs_fattr *)&fl.fl_fattr; 2845*68653Smckusick nfsm_srvfillattr(vap, fp); 2846*68653Smckusick fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 2847*68653Smckusick fl.fl_fhok = nfs_true; 2848*68653Smckusick fl.fl_postopok = nfs_true; 2849*68653Smckusick fl.fl_off.nfsuquad[0] = 0; 2850*68653Smckusick fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); 2851*68653Smckusick 285238418Smckusick nfsm_clget; 285348050Smckusick *tl = nfs_true; 285438418Smckusick bp += NFSX_UNSIGNED; 285538418Smckusick nfsm_clget; 2856*68653Smckusick *tl = 0; 2857*68653Smckusick bp += NFSX_UNSIGNED; 2858*68653Smckusick nfsm_clget; 285952441Smckusick *tl = txdr_unsigned(dp->d_fileno); 286038418Smckusick bp += NFSX_UNSIGNED; 286138418Smckusick nfsm_clget; 286248050Smckusick *tl = txdr_unsigned(nlen); 286338418Smckusick bp += NFSX_UNSIGNED; 286438425Smckusick 286552196Smckusick /* And loop around copying the name */ 286638418Smckusick xfer = nlen; 286738418Smckusick cp = dp->d_name; 286838418Smckusick while (xfer > 0) { 286938418Smckusick nfsm_clget; 2870*68653Smckusick if ((bp + xfer) > be) 2871*68653Smckusick tsiz = be - bp; 287238418Smckusick else 287338418Smckusick tsiz = xfer; 287438418Smckusick bcopy(cp, bp, tsiz); 287538418Smckusick bp += tsiz; 287638418Smckusick xfer -= tsiz; 287738418Smckusick if (xfer > 0) 287838418Smckusick cp += tsiz; 287938418Smckusick } 288038418Smckusick /* And null pad to a long boundary */ 288138418Smckusick for (i = 0; i < rem; i++) 288238418Smckusick *bp++ = '\0'; 288338425Smckusick 2884*68653Smckusick /* 2885*68653Smckusick * Now copy the flrep structure out. 2886*68653Smckusick */ 2887*68653Smckusick xfer = sizeof (struct flrep); 2888*68653Smckusick cp = (caddr_t)&fl; 2889*68653Smckusick while (xfer > 0) { 2890*68653Smckusick nfsm_clget; 2891*68653Smckusick if ((bp + xfer) > be) 2892*68653Smckusick tsiz = be - bp; 2893*68653Smckusick else 2894*68653Smckusick tsiz = xfer; 2895*68653Smckusick bcopy(cp, bp, tsiz); 2896*68653Smckusick bp += tsiz; 2897*68653Smckusick xfer -= tsiz; 2898*68653Smckusick if (xfer > 0) 2899*68653Smckusick cp += tsiz; 2900*68653Smckusick } 290167363Smckusick } 290252196Smckusick invalid: 290338418Smckusick cpos += dp->d_reclen; 290452441Smckusick dp = (struct dirent *)cpos; 2905*68653Smckusick cookiep++; 2906*68653Smckusick ncookies--; 290738418Smckusick } 290852196Smckusick vrele(vp); 290938418Smckusick nfsm_clget; 291048050Smckusick *tl = nfs_false; 291138418Smckusick bp += NFSX_UNSIGNED; 291238418Smckusick nfsm_clget; 291340296Smckusick if (eofflag) 291448050Smckusick *tl = nfs_true; 291540296Smckusick else 291648050Smckusick *tl = nfs_false; 291738418Smckusick bp += NFSX_UNSIGNED; 291852196Smckusick if (mp != mb) { 291952196Smckusick if (bp < be) 292052196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 292152196Smckusick } else 292252196Smckusick mp->m_len += bp - bpos; 2923*68653Smckusick FREE((caddr_t)cookies, M_TEMP); 2924*68653Smckusick FREE((caddr_t)rbuf, M_TEMP); 292538418Smckusick nfsm_srvdone; 292638418Smckusick } 292738418Smckusick 292838418Smckusick /* 2929*68653Smckusick * nfs commit service 2930*68653Smckusick */ 2931*68653Smckusick int 2932*68653Smckusick nfsrv_commit(nfsd, slp, procp, mrq) 2933*68653Smckusick struct nfsrv_descript *nfsd; 2934*68653Smckusick struct nfssvc_sock *slp; 2935*68653Smckusick struct proc *procp; 2936*68653Smckusick struct mbuf **mrq; 2937*68653Smckusick { 2938*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2939*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 2940*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 2941*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 2942*68653Smckusick struct vattr bfor, aft; 2943*68653Smckusick struct vnode *vp; 2944*68653Smckusick nfsfh_t nfh; 2945*68653Smckusick fhandle_t *fhp; 2946*68653Smckusick register u_long *tl; 2947*68653Smckusick register long t1; 2948*68653Smckusick caddr_t bpos; 2949*68653Smckusick int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache; 2950*68653Smckusick char *cp2; 2951*68653Smckusick struct mbuf *mb, *mb2, *mreq; 2952*68653Smckusick u_quad_t frev, off; 2953*68653Smckusick 2954*68653Smckusick #ifndef nolint 2955*68653Smckusick cache = 0; 2956*68653Smckusick #endif 2957*68653Smckusick fhp = &nfh.fh_generic; 2958*68653Smckusick nfsm_srvmtofh(fhp); 2959*68653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 2960*68653Smckusick 2961*68653Smckusick /* 2962*68653Smckusick * XXX At this time VOP_FSYNC() does not accept offset and byte 2963*68653Smckusick * count parameters, so these arguments are useless (someday maybe). 2964*68653Smckusick */ 2965*68653Smckusick fxdr_hyper(tl, &off); 2966*68653Smckusick tl += 2; 2967*68653Smckusick cnt = fxdr_unsigned(int, *tl); 2968*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 2969*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 2970*68653Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 2971*68653Smckusick nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); 2972*68653Smckusick return (0); 2973*68653Smckusick } 2974*68653Smckusick for_ret = VOP_GETATTR(vp, &bfor, cred, procp); 2975*68653Smckusick error = VOP_FSYNC(vp, cred, MNT_WAIT, procp); 2976*68653Smckusick aft_ret = VOP_GETATTR(vp, &aft, cred, procp); 2977*68653Smckusick vput(vp); 2978*68653Smckusick nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); 2979*68653Smckusick nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); 2980*68653Smckusick if (!error) { 2981*68653Smckusick nfsm_build(tl, u_long *, NFSX_V3WRITEVERF); 2982*68653Smckusick *tl++ = txdr_unsigned(boottime.tv_sec); 2983*68653Smckusick *tl = txdr_unsigned(boottime.tv_usec); 2984*68653Smckusick } else 2985*68653Smckusick return (0); 2986*68653Smckusick nfsm_srvdone; 2987*68653Smckusick } 2988*68653Smckusick 2989*68653Smckusick /* 299038418Smckusick * nfs statfs service 299138418Smckusick */ 2992*68653Smckusick int 2993*68653Smckusick nfsrv_statfs(nfsd, slp, procp, mrq) 2994*68653Smckusick struct nfsrv_descript *nfsd; 2995*68653Smckusick struct nfssvc_sock *slp; 2996*68653Smckusick struct proc *procp; 2997*68653Smckusick struct mbuf **mrq; 299838418Smckusick { 2999*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3000*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 3001*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 3002*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 300338418Smckusick register struct statfs *sf; 3004*68653Smckusick register struct nfs_statfs *sfp; 300548050Smckusick register u_long *tl; 300639494Smckusick register long t1; 300739494Smckusick caddr_t bpos; 3008*68653Smckusick int error = 0, rdonly, cache, getret = 1; 3009*68653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3); 301039494Smckusick char *cp2; 301139753Smckusick struct mbuf *mb, *mb2, *mreq; 301238418Smckusick struct vnode *vp; 3013*68653Smckusick struct vattr at; 3014*68653Smckusick nfsfh_t nfh; 301538418Smckusick fhandle_t *fhp; 301638418Smckusick struct statfs statfs; 3017*68653Smckusick u_quad_t frev, tval; 301838418Smckusick 3019*68653Smckusick #ifndef nolint 3020*68653Smckusick cache = 0; 3021*68653Smckusick #endif 302238418Smckusick fhp = &nfh.fh_generic; 302338418Smckusick nfsm_srvmtofh(fhp); 3024*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3025*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 3026*68653Smckusick nfsm_reply(NFSX_UNSIGNED); 3027*68653Smckusick nfsm_srvpostop_attr(getret, &at); 3028*68653Smckusick return (0); 3029*68653Smckusick } 303038418Smckusick sf = &statfs; 3031*68653Smckusick error = VFS_STATFS(vp->v_mount, sf, procp); 3032*68653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp); 303338418Smckusick vput(vp); 3034*68653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); 3035*68653Smckusick if (v3) 3036*68653Smckusick nfsm_srvpostop_attr(getret, &at); 3037*68653Smckusick if (error) 3038*68653Smckusick return (0); 3039*68653Smckusick nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); 3040*68653Smckusick if (v3) { 3041*68653Smckusick tval = (u_quad_t)sf->f_blocks; 3042*68653Smckusick tval *= (u_quad_t)sf->f_bsize; 3043*68653Smckusick txdr_hyper(&tval, &sfp->sf_tbytes); 3044*68653Smckusick tval = (u_quad_t)sf->f_bfree; 3045*68653Smckusick tval *= (u_quad_t)sf->f_bsize; 3046*68653Smckusick txdr_hyper(&tval, &sfp->sf_fbytes); 3047*68653Smckusick tval = (u_quad_t)sf->f_bavail; 3048*68653Smckusick tval *= (u_quad_t)sf->f_bsize; 3049*68653Smckusick txdr_hyper(&tval, &sfp->sf_abytes); 3050*68653Smckusick sfp->sf_tfiles.nfsuquad[0] = 0; 3051*68653Smckusick sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files); 3052*68653Smckusick sfp->sf_ffiles.nfsuquad[0] = 0; 3053*68653Smckusick sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3054*68653Smckusick sfp->sf_afiles.nfsuquad[0] = 0; 3055*68653Smckusick sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3056*68653Smckusick sfp->sf_invarsec = 0; 3057*68653Smckusick } else { 3058*68653Smckusick sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 3059*68653Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 3060*68653Smckusick sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 3061*68653Smckusick sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 3062*68653Smckusick sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 306356285Smckusick } 306438418Smckusick nfsm_srvdone; 306538418Smckusick } 306638418Smckusick 306738418Smckusick /* 3068*68653Smckusick * nfs fsinfo service 3069*68653Smckusick */ 3070*68653Smckusick int 3071*68653Smckusick nfsrv_fsinfo(nfsd, slp, procp, mrq) 3072*68653Smckusick struct nfsrv_descript *nfsd; 3073*68653Smckusick struct nfssvc_sock *slp; 3074*68653Smckusick struct proc *procp; 3075*68653Smckusick struct mbuf **mrq; 3076*68653Smckusick { 3077*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3078*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 3079*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 3080*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 3081*68653Smckusick register u_long *tl; 3082*68653Smckusick register struct nfsv3_fsinfo *sip; 3083*68653Smckusick register long t1; 3084*68653Smckusick caddr_t bpos; 3085*68653Smckusick int error = 0, rdonly, cache, getret = 1, pref; 3086*68653Smckusick char *cp2; 3087*68653Smckusick struct mbuf *mb, *mb2, *mreq; 3088*68653Smckusick struct vnode *vp; 3089*68653Smckusick struct vattr at; 3090*68653Smckusick nfsfh_t nfh; 3091*68653Smckusick fhandle_t *fhp; 3092*68653Smckusick u_quad_t frev; 3093*68653Smckusick 3094*68653Smckusick #ifndef nolint 3095*68653Smckusick cache = 0; 3096*68653Smckusick #endif 3097*68653Smckusick fhp = &nfh.fh_generic; 3098*68653Smckusick nfsm_srvmtofh(fhp); 3099*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3100*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 3101*68653Smckusick nfsm_reply(NFSX_UNSIGNED); 3102*68653Smckusick nfsm_srvpostop_attr(getret, &at); 3103*68653Smckusick return (0); 3104*68653Smckusick } 3105*68653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp); 3106*68653Smckusick vput(vp); 3107*68653Smckusick nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); 3108*68653Smckusick nfsm_srvpostop_attr(getret, &at); 3109*68653Smckusick nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO); 3110*68653Smckusick 3111*68653Smckusick /* 3112*68653Smckusick * XXX 3113*68653Smckusick * There should be file system VFS OP(s) to get this information. 3114*68653Smckusick * For now, assume ufs. 3115*68653Smckusick */ 3116*68653Smckusick if (slp->ns_so->so_type == SOCK_DGRAM) 3117*68653Smckusick pref = NFS_MAXDGRAMDATA; 3118*68653Smckusick else 3119*68653Smckusick pref = NFS_MAXDATA; 3120*68653Smckusick sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 3121*68653Smckusick sip->fs_rtpref = txdr_unsigned(pref); 3122*68653Smckusick sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3123*68653Smckusick sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 3124*68653Smckusick sip->fs_wtpref = txdr_unsigned(pref); 3125*68653Smckusick sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3126*68653Smckusick sip->fs_dtpref = txdr_unsigned(pref); 3127*68653Smckusick sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff; 3128*68653Smckusick sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff; 3129*68653Smckusick sip->fs_timedelta.nfsv3_sec = 0; 3130*68653Smckusick sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3131*68653Smckusick sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3132*68653Smckusick NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3133*68653Smckusick NFSV3FSINFO_CANSETTIME); 3134*68653Smckusick nfsm_srvdone; 3135*68653Smckusick } 3136*68653Smckusick 3137*68653Smckusick /* 3138*68653Smckusick * nfs pathconf service 3139*68653Smckusick */ 3140*68653Smckusick int 3141*68653Smckusick nfsrv_pathconf(nfsd, slp, procp, mrq) 3142*68653Smckusick struct nfsrv_descript *nfsd; 3143*68653Smckusick struct nfssvc_sock *slp; 3144*68653Smckusick struct proc *procp; 3145*68653Smckusick struct mbuf **mrq; 3146*68653Smckusick { 3147*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3148*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 3149*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 3150*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 3151*68653Smckusick register u_long *tl; 3152*68653Smckusick register struct nfsv3_pathconf *pc; 3153*68653Smckusick register long t1; 3154*68653Smckusick caddr_t bpos; 3155*68653Smckusick int error = 0, rdonly, cache, getret = 1, linkmax, namemax; 3156*68653Smckusick int chownres, notrunc; 3157*68653Smckusick char *cp2; 3158*68653Smckusick struct mbuf *mb, *mb2, *mreq; 3159*68653Smckusick struct vnode *vp; 3160*68653Smckusick struct vattr at; 3161*68653Smckusick nfsfh_t nfh; 3162*68653Smckusick fhandle_t *fhp; 3163*68653Smckusick u_quad_t frev; 3164*68653Smckusick 3165*68653Smckusick #ifndef nolint 3166*68653Smckusick cache = 0; 3167*68653Smckusick #endif 3168*68653Smckusick fhp = &nfh.fh_generic; 3169*68653Smckusick nfsm_srvmtofh(fhp); 3170*68653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3171*68653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { 3172*68653Smckusick nfsm_reply(NFSX_UNSIGNED); 3173*68653Smckusick nfsm_srvpostop_attr(getret, &at); 3174*68653Smckusick return (0); 3175*68653Smckusick } 3176*68653Smckusick error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3177*68653Smckusick if (!error) 3178*68653Smckusick error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3179*68653Smckusick if (!error) 3180*68653Smckusick error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3181*68653Smckusick if (!error) 3182*68653Smckusick error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3183*68653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp); 3184*68653Smckusick vput(vp); 3185*68653Smckusick nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); 3186*68653Smckusick nfsm_srvpostop_attr(getret, &at); 3187*68653Smckusick if (error) 3188*68653Smckusick return (0); 3189*68653Smckusick nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 3190*68653Smckusick 3191*68653Smckusick pc->pc_linkmax = txdr_unsigned(linkmax); 3192*68653Smckusick pc->pc_namemax = txdr_unsigned(namemax); 3193*68653Smckusick pc->pc_notrunc = txdr_unsigned(notrunc); 3194*68653Smckusick pc->pc_chownrestricted = txdr_unsigned(chownres); 3195*68653Smckusick 3196*68653Smckusick /* 3197*68653Smckusick * These should probably be supported by VOP_PATHCONF(), but 3198*68653Smckusick * until msdosfs is exportable (why would you want to?), the 3199*68653Smckusick * Unix defaults should be ok. 3200*68653Smckusick */ 3201*68653Smckusick pc->pc_caseinsensitive = nfs_false; 3202*68653Smckusick pc->pc_casepreserving = nfs_true; 3203*68653Smckusick nfsm_srvdone; 3204*68653Smckusick } 3205*68653Smckusick 3206*68653Smckusick /* 320738418Smckusick * Null operation, used by clients to ping server 320838418Smckusick */ 320939494Smckusick /* ARGSUSED */ 3210*68653Smckusick int 3211*68653Smckusick nfsrv_null(nfsd, slp, procp, mrq) 3212*68653Smckusick struct nfsrv_descript *nfsd; 3213*68653Smckusick struct nfssvc_sock *slp; 3214*68653Smckusick struct proc *procp; 3215*68653Smckusick struct mbuf **mrq; 321638418Smckusick { 3217*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3218*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 3219*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 3220*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 322139494Smckusick caddr_t bpos; 3222*68653Smckusick int error = NFSERR_RETVOID, cache; 322339753Smckusick struct mbuf *mb, *mreq; 322452196Smckusick u_quad_t frev; 322538418Smckusick 3226*68653Smckusick #ifndef nolint 3227*68653Smckusick cache = 0; 3228*68653Smckusick #endif 322938418Smckusick nfsm_reply(0); 3230*68653Smckusick return (0); 323138418Smckusick } 323238418Smckusick 323338418Smckusick /* 323438418Smckusick * No operation, used for obsolete procedures 323538418Smckusick */ 323639494Smckusick /* ARGSUSED */ 3237*68653Smckusick int 3238*68653Smckusick nfsrv_noop(nfsd, slp, procp, mrq) 3239*68653Smckusick struct nfsrv_descript *nfsd; 3240*68653Smckusick struct nfssvc_sock *slp; 3241*68653Smckusick struct proc *procp; 3242*68653Smckusick struct mbuf **mrq; 324338418Smckusick { 3244*68653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3245*68653Smckusick struct mbuf *nam = nfsd->nd_nam; 3246*68653Smckusick caddr_t dpos = nfsd->nd_dpos; 3247*68653Smckusick struct ucred *cred = &nfsd->nd_cr; 324839494Smckusick caddr_t bpos; 324952196Smckusick int error, cache; 325039753Smckusick struct mbuf *mb, *mreq; 325152196Smckusick u_quad_t frev; 325238418Smckusick 3253*68653Smckusick #ifndef nolint 3254*68653Smckusick cache = 0; 3255*68653Smckusick #endif 325652196Smckusick if (nfsd->nd_repstat) 325752196Smckusick error = nfsd->nd_repstat; 325852196Smckusick else 325952196Smckusick error = EPROCUNAVAIL; 326038418Smckusick nfsm_reply(0); 3261*68653Smckusick return (0); 326238418Smckusick } 326338425Smckusick 326438450Smckusick /* 326538450Smckusick * Perform access checking for vnodes obtained from file handles that would 326638450Smckusick * refer to files already opened by a Unix client. You cannot just use 326738450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 326852196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 326938450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 327038450Smckusick * processes that chmod after opening a file don't break. I don't like 327138450Smckusick * this because it opens a security hole, but since the nfs server opens 327238450Smckusick * a security hole the size of a barn door anyhow, what the heck. 327338450Smckusick */ 3274*68653Smckusick int 327552196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 327638450Smckusick register struct vnode *vp; 327738450Smckusick int flags; 327838450Smckusick register struct ucred *cred; 327952196Smckusick int rdonly; 328048050Smckusick struct proc *p; 328138450Smckusick { 328238450Smckusick struct vattr vattr; 328338450Smckusick int error; 328438450Smckusick if (flags & VWRITE) { 328552196Smckusick /* Just vn_writechk() changed to check rdonly */ 328638450Smckusick /* 328738450Smckusick * Disallow write attempts on read-only file systems; 328838450Smckusick * unless the file is a socket or a block or character 328938450Smckusick * device resident on the file system. 329038450Smckusick */ 329152196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 329245059Smckusick switch (vp->v_type) { 329345059Smckusick case VREG: case VDIR: case VLNK: 329438450Smckusick return (EROFS); 329545059Smckusick } 329645059Smckusick } 329738450Smckusick /* 329838450Smckusick * If there's shared text associated with 329938450Smckusick * the inode, try to free it up once. If 330038450Smckusick * we fail, we can't allow writing. 330138450Smckusick */ 330245715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 330338450Smckusick return (ETXTBSY); 330438450Smckusick } 330548050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 330645059Smckusick return (error); 330748050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 330845059Smckusick cred->cr_uid != vattr.va_uid) 330945059Smckusick return (error); 331045059Smckusick return (0); 331138450Smckusick } 3312