138414Smckusick /* 238414Smckusick * Copyright (c) 1989 The Regents of the University of California. 338414Smckusick * All rights reserved. 438414Smckusick * 538414Smckusick * This code is derived from software contributed to Berkeley by 638414Smckusick * Rick Macklem at The University of Guelph. 738414Smckusick * 838414Smckusick * Redistribution and use in source and binary forms are permitted 938414Smckusick * provided that the above copyright notice and this paragraph are 1038414Smckusick * duplicated in all such forms and that any documentation, 1138414Smckusick * advertising materials, and other materials related to such 1238414Smckusick * distribution and use acknowledge that the software was developed 1338414Smckusick * by the University of California, Berkeley. The name of the 1438414Smckusick * University may not be used to endorse or promote products derived 1538414Smckusick * from this software without specific prior written permission. 1638414Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738414Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838414Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938414Smckusick * 20*39441Smckusick * @(#)nfs_vnops.c 7.10 (Berkeley) 10/29/89 2138414Smckusick */ 2238414Smckusick 2338414Smckusick /* 2438414Smckusick * vnode op calls for sun nfs version 2 2538414Smckusick */ 2638414Smckusick 2738414Smckusick #include "machine/pte.h" 2838414Smckusick #include "machine/mtpr.h" 2938414Smckusick #include "strings.h" 3038414Smckusick #include "param.h" 3138414Smckusick #include "user.h" 3238414Smckusick #include "proc.h" 3338414Smckusick #include "mount.h" 3438414Smckusick #include "buf.h" 3538414Smckusick #include "vm.h" 3638425Smckusick #include "../ufs/dir.h" 3738414Smckusick #include "malloc.h" 3838414Smckusick #include "mbuf.h" 3938414Smckusick #include "uio.h" 4038414Smckusick #include "ucred.h" 4138414Smckusick #include "namei.h" 4238414Smckusick #include "errno.h" 4338414Smckusick #include "file.h" 4438414Smckusick #include "conf.h" 4538414Smckusick #include "vnode.h" 4638414Smckusick #include "../ufs/inode.h" 4738884Smacklem #include "map.h" 4838414Smckusick #include "nfsv2.h" 4938414Smckusick #include "nfs.h" 5038414Smckusick #include "nfsnode.h" 5138414Smckusick #include "nfsmount.h" 5238414Smckusick #include "xdr_subs.h" 5338414Smckusick #include "nfsm_subs.h" 5438884Smacklem #include "nfsiom.h" 5538414Smckusick 5638414Smckusick /* Defs */ 5738414Smckusick #define TRUE 1 5838414Smckusick #define FALSE 0 5938414Smckusick 6038414Smckusick /* Global vars */ 6138414Smckusick int nfs_lookup(), 6238414Smckusick nfs_create(), 6338414Smckusick nfs_open(), 6438414Smckusick nfs_close(), 6538414Smckusick nfs_access(), 6638414Smckusick nfs_getattr(), 6738414Smckusick nfs_setattr(), 6838414Smckusick nfs_read(), 6938414Smckusick nfs_write(), 7038414Smckusick vfs_noop(), 7138414Smckusick vfs_nullop(), 7238414Smckusick nfs_remove(), 7338414Smckusick nfs_link(), 7438414Smckusick nfs_rename(), 7538414Smckusick nfs_mkdir(), 7638414Smckusick nfs_rmdir(), 7738414Smckusick nfs_symlink(), 7838414Smckusick nfs_readdir(), 7938414Smckusick nfs_readlink(), 8038414Smckusick nfs_abortop(), 8138414Smckusick nfs_lock(), 8238414Smckusick nfs_unlock(), 8338414Smckusick nfs_bmap(), 8438414Smckusick nfs_strategy(), 8538884Smacklem nfs_fsync(), 8639394Smckusick nfs_inactive(), 8739394Smckusick nfs_reclaim(); 8838414Smckusick 8938414Smckusick struct vnodeops nfsv2_vnodeops = { 9038414Smckusick nfs_lookup, 9138414Smckusick nfs_create, 9238414Smckusick vfs_noop, 9338414Smckusick nfs_open, 9438414Smckusick nfs_close, 9538414Smckusick nfs_access, 9638414Smckusick nfs_getattr, 9738414Smckusick nfs_setattr, 9838414Smckusick nfs_read, 9938414Smckusick nfs_write, 10038414Smckusick vfs_noop, 10138414Smckusick vfs_noop, 10238414Smckusick vfs_noop, 10338884Smacklem nfs_fsync, 10438414Smckusick vfs_noop, 10538414Smckusick nfs_remove, 10638414Smckusick nfs_link, 10738414Smckusick nfs_rename, 10838414Smckusick nfs_mkdir, 10938414Smckusick nfs_rmdir, 11038414Smckusick nfs_symlink, 11138414Smckusick nfs_readdir, 11238414Smckusick nfs_readlink, 11338414Smckusick nfs_abortop, 11438414Smckusick nfs_inactive, 11539394Smckusick nfs_reclaim, 11638414Smckusick nfs_lock, 11738414Smckusick nfs_unlock, 11838414Smckusick nfs_bmap, 11938414Smckusick nfs_strategy, 12038414Smckusick }; 12138414Smckusick 12238414Smckusick /* Special device vnode ops */ 123*39441Smckusick int spec_lookup(), 124*39441Smckusick spec_open(), 125*39441Smckusick spec_read(), 126*39441Smckusick spec_write(), 127*39441Smckusick spec_strategy(), 128*39441Smckusick spec_ioctl(), 129*39441Smckusick spec_select(), 130*39441Smckusick spec_close(), 131*39441Smckusick spec_badop(), 132*39441Smckusick spec_nullop(); 13338414Smckusick 134*39441Smckusick struct vnodeops spec_nfsv2nodeops = { 135*39441Smckusick spec_lookup, 136*39441Smckusick spec_badop, 137*39441Smckusick spec_badop, 138*39441Smckusick spec_open, 139*39441Smckusick spec_close, 14038414Smckusick nfs_access, 14138414Smckusick nfs_getattr, 14238414Smckusick nfs_setattr, 143*39441Smckusick spec_read, 144*39441Smckusick spec_write, 145*39441Smckusick spec_ioctl, 146*39441Smckusick spec_select, 147*39441Smckusick spec_badop, 148*39441Smckusick spec_nullop, 149*39441Smckusick spec_badop, 150*39441Smckusick spec_badop, 151*39441Smckusick spec_badop, 152*39441Smckusick spec_badop, 153*39441Smckusick spec_badop, 154*39441Smckusick spec_badop, 155*39441Smckusick spec_badop, 156*39441Smckusick spec_badop, 157*39441Smckusick spec_badop, 158*39441Smckusick spec_badop, 15938414Smckusick nfs_inactive, 16039394Smckusick nfs_reclaim, 16138414Smckusick nfs_lock, 16238414Smckusick nfs_unlock, 163*39441Smckusick spec_badop, 164*39441Smckusick spec_strategy, 16538414Smckusick }; 16638414Smckusick 16738414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 16838414Smckusick extern u_long nfs_prog, nfs_vers; 16938414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 17038884Smacklem struct map nfsmap[NFS_MSIZ]; 17138414Smckusick enum vtype v_type[NFLNK+1]; 17238884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 17339341Smckusick int nfs_asyncdaemons = 0; 17439341Smckusick struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 17538884Smacklem static int nfsmap_want = 0; 17638414Smckusick 17738414Smckusick /* 17838414Smckusick * nfs null call from vfs. 17938414Smckusick */ 18038414Smckusick nfs_null(vp, cred) 18138414Smckusick struct vnode *vp; 18238414Smckusick struct ucred *cred; 18338414Smckusick { 18438414Smckusick nfsm_vars; 18538414Smckusick 18638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 18738414Smckusick nfsm_request(vp); 18838414Smckusick nfsm_reqdone; 18938414Smckusick return (error); 19038414Smckusick } 19138414Smckusick 19238414Smckusick /* 19338414Smckusick * nfs access vnode op. 19438414Smckusick * Essentially just get vattr and then imitate iaccess() 19538414Smckusick */ 19638414Smckusick nfs_access(vp, mode, cred) 19738414Smckusick struct vnode *vp; 19838414Smckusick int mode; 19938414Smckusick register struct ucred *cred; 20038414Smckusick { 20138414Smckusick register struct vattr *vap; 20238414Smckusick register gid_t *gp; 20338414Smckusick struct vattr vattr; 20438414Smckusick register int i; 20538414Smckusick int error; 20638414Smckusick 20738414Smckusick /* 20838414Smckusick * If you're the super-user, 20938414Smckusick * you always get access. 21038414Smckusick */ 21138414Smckusick if (cred->cr_uid == 0) 21238414Smckusick return (0); 21338414Smckusick vap = &vattr; 21438884Smacklem if (error = nfs_getattr(vp, vap, cred)) 21538884Smacklem return (error); 21638414Smckusick /* 21738414Smckusick * Access check is based on only one of owner, group, public. 21838414Smckusick * If not owner, then check group. If not a member of the 21938414Smckusick * group, then check public access. 22038414Smckusick */ 22138414Smckusick if (cred->cr_uid != vap->va_uid) { 22238414Smckusick mode >>= 3; 22338414Smckusick gp = cred->cr_groups; 22438414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 22538414Smckusick if (vap->va_gid == *gp) 22638414Smckusick goto found; 22738414Smckusick mode >>= 3; 22838414Smckusick found: 22938414Smckusick ; 23038414Smckusick } 23138414Smckusick if ((vap->va_mode & mode) != 0) 23238414Smckusick return (0); 23338414Smckusick return (EACCES); 23438414Smckusick } 23538414Smckusick 23638414Smckusick /* 23738414Smckusick * nfs open vnode op 23838414Smckusick * Just check to see if the type is ok 23938414Smckusick */ 24038414Smckusick nfs_open(vp, mode, cred) 24138414Smckusick struct vnode *vp; 24238414Smckusick int mode; 24338414Smckusick struct ucred *cred; 24438414Smckusick { 24538414Smckusick register enum vtype vtyp; 24638414Smckusick 24738414Smckusick vtyp = vp->v_type; 24838414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 24938414Smckusick return (0); 25038414Smckusick else 25138414Smckusick return (EACCES); 25238414Smckusick } 25338414Smckusick 25438414Smckusick /* 25538414Smckusick * nfs close vnode op 25638884Smacklem * For reg files, invalidate any buffer cache entries. 25738414Smckusick */ 25838414Smckusick nfs_close(vp, fflags, cred) 25938414Smckusick register struct vnode *vp; 26038414Smckusick int fflags; 26138414Smckusick struct ucred *cred; 26238414Smckusick { 26338884Smacklem struct nfsnode *np = VTONFS(vp); 26438414Smckusick dev_t dev; 26539341Smckusick int error = 0; 26638414Smckusick 26739341Smckusick if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) || 26839341Smckusick ((np->n_flag & NBUFFERED) && np->n_sillyrename))) { 269*39441Smckusick nfs_lock(vp); 27039341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 27139341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 27239341Smckusick if (np->n_flag & NWRITEERR) { 27339341Smckusick np->n_flag &= ~NWRITEERR; 27439341Smckusick if (!error) 27539341Smckusick error = np->n_error ? np->n_error : EIO; 27639341Smckusick } 277*39441Smckusick nfs_unlock(vp); 27838884Smacklem } 27938414Smckusick return (error); 28038414Smckusick } 28138414Smckusick 28238414Smckusick /* 28338414Smckusick * nfs getattr call from vfs. 28438414Smckusick */ 28538414Smckusick nfs_getattr(vp, vap, cred) 28638414Smckusick struct vnode *vp; 28738414Smckusick register struct vattr *vap; 28838414Smckusick struct ucred *cred; 28938414Smckusick { 29038414Smckusick nfsm_vars; 29138414Smckusick 29238414Smckusick /* First look in the cache.. */ 29338414Smckusick if (nfs_getattrcache(vp, vap) == 0) 29438414Smckusick return (0); 29538414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 29638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH); 29738414Smckusick nfsm_fhtom(vp); 29838414Smckusick nfsm_request(vp); 29938414Smckusick nfsm_loadattr(vp, vap); 30038414Smckusick nfsm_reqdone; 30138414Smckusick return (error); 30238414Smckusick } 30338414Smckusick 30438414Smckusick /* 30538414Smckusick * nfs setattr call. 30638414Smckusick */ 30738414Smckusick nfs_setattr(vp, vap, cred) 30838414Smckusick struct vnode *vp; 30938414Smckusick register struct vattr *vap; 31038414Smckusick struct ucred *cred; 31138414Smckusick { 31238884Smacklem register struct nfsv2_sattr *sp; 31338414Smckusick nfsm_vars; 31439359Smckusick struct nfsnode *np; 31538414Smckusick 31638414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 31738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 31838414Smckusick nfsm_fhtom(vp); 31938884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 32038414Smckusick if (vap->va_mode == 0xffff) 32138884Smacklem sp->sa_mode = VNOVAL; 32238414Smckusick else 32338884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 32438414Smckusick if (vap->va_uid == 0xffff) 32538884Smacklem sp->sa_uid = VNOVAL; 32638414Smckusick else 32738884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 32838414Smckusick if (vap->va_gid == 0xffff) 32938884Smacklem sp->sa_gid = VNOVAL; 33038414Smckusick else 33138884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 33238884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 33339359Smckusick if (vap->va_size != VNOVAL) { 33439359Smckusick np = VTONFS(vp); 33539359Smckusick if (np->n_flag & NMODIFIED) { 33639359Smckusick np->n_flag &= ~NMODIFIED; 33739359Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 33839359Smckusick } 33939359Smckusick } 34038884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 34138884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 34238414Smckusick nfsm_request(vp); 34338414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 34438414Smckusick /* should we fill in any vap fields ?? */ 34538414Smckusick nfsm_reqdone; 34638414Smckusick return (error); 34738414Smckusick } 34838414Smckusick 34938414Smckusick /* 35038414Smckusick * nfs lookup call, one step at a time... 35138414Smckusick * First look in cache 35238414Smckusick * If not found, unlock the directory nfsnode and do the rpc 35338414Smckusick */ 35438414Smckusick nfs_lookup(vp, ndp) 35538414Smckusick register struct vnode *vp; 35638414Smckusick register struct nameidata *ndp; 35738414Smckusick { 35838414Smckusick register struct vnode *vdp; 35938414Smckusick nfsm_vars; 36038414Smckusick struct vnode *newvp; 36138414Smckusick long len; 36238414Smckusick nfsv2fh_t *fhp; 36338414Smckusick struct nfsnode *np; 36438414Smckusick int lockparent, wantparent, flag; 36538414Smckusick dev_t rdev; 36638414Smckusick 36738414Smckusick ndp->ni_dvp = vp; 36838414Smckusick ndp->ni_vp = NULL; 36938414Smckusick if (vp->v_type != VDIR) 37038414Smckusick return (ENOTDIR); 37138414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 37238414Smckusick flag = ndp->ni_nameiop & OPFLAG; 37338414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 37439341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 37538884Smacklem struct vattr vattr; 37638884Smacklem int vpid; 37738884Smacklem 378*39441Smckusick if (vp == ndp->ni_rdir && ndp->ni_isdotdot) 379*39441Smckusick panic("nfs_lookup: .. through root"); 380*39441Smckusick vdp = ndp->ni_vp; 38138884Smacklem vpid = vdp->v_id; 38238414Smckusick /* 38338884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 38438884Smacklem * for an explanation of the locking protocol 38538414Smckusick */ 38638414Smckusick if (vp == vdp) { 38738425Smckusick VREF(vdp); 388*39441Smckusick error = 0; 38938414Smckusick } else if (ndp->ni_isdotdot) { 39038414Smckusick nfs_unlock(vp); 391*39441Smckusick error = vget(vdp); 39238414Smckusick } else { 393*39441Smckusick error = vget(vdp); 39438414Smckusick nfs_unlock(vp); 39538414Smckusick } 396*39441Smckusick if (!error) { 397*39441Smckusick if (vpid == vdp->v_id && 398*39441Smckusick !nfs_getattr(vdp, &vattr, ndp->ni_cred)) { 399*39441Smckusick nfsstats.lookupcache_hits++; 400*39441Smckusick return (0); 401*39441Smckusick } else { 402*39441Smckusick nfs_nput(vdp); 403*39441Smckusick } 40438884Smacklem } 40538884Smacklem nfs_lock(vp); 40638884Smacklem ndp->ni_vp = (struct vnode *)0; 40738414Smckusick } 40839341Smckusick error = 0; 40938414Smckusick nfsstats.lookupcache_misses++; 41038414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 41138414Smckusick len = ndp->ni_namelen; 41238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 41338414Smckusick nfsm_fhtom(vp); 41438414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 41538414Smckusick nfsm_request(vp); 41638414Smckusick nfsmout: 41738414Smckusick if (error) { 41838414Smckusick if ((flag == CREATE || flag == RENAME) && 41938414Smckusick *ndp->ni_next == 0) { 42038414Smckusick if (!lockparent) 42138414Smckusick nfs_unlock(vp); 42238414Smckusick } 42338414Smckusick return (ENOENT); 42438414Smckusick } 42538414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 42638414Smckusick 42738414Smckusick /* 42838414Smckusick * Handle DELETE and RENAME cases... 42938414Smckusick */ 43038414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 43138414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 43238425Smckusick VREF(vp); 43338414Smckusick newvp = vp; 43438414Smckusick np = VTONFS(vp); 43538414Smckusick } else { 43638414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 43738414Smckusick m_freem(mrep); 43838414Smckusick return (error); 43938414Smckusick } 44038414Smckusick newvp = NFSTOV(np); 44138414Smckusick } 44238414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 44338414Smckusick if (newvp != vp) 44438414Smckusick nfs_nput(newvp); 44538414Smckusick else 44638425Smckusick vrele(vp); 44738414Smckusick m_freem(mrep); 44838414Smckusick return (error); 44938414Smckusick } 45038414Smckusick ndp->ni_vp = newvp; 45138414Smckusick if (!lockparent) 45238414Smckusick nfs_unlock(vp); 45338414Smckusick m_freem(mrep); 45438414Smckusick return (0); 45538414Smckusick } 45638414Smckusick 45738414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 45838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 45938414Smckusick m_freem(mrep); 46038414Smckusick return (EISDIR); 46138414Smckusick } 46238414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 46338414Smckusick m_freem(mrep); 46438414Smckusick return (error); 46538414Smckusick } 46638414Smckusick newvp = NFSTOV(np); 46738414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 46838425Smckusick nfs_nput(newvp); 46938414Smckusick m_freem(mrep); 47038414Smckusick return (error); 47138414Smckusick } 47238414Smckusick ndp->ni_vp = newvp; 47338414Smckusick if (!lockparent) 47438414Smckusick nfs_unlock(vp); 47538414Smckusick return (0); 47638414Smckusick } 47738414Smckusick 47838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 47938425Smckusick VREF(vp); 48038414Smckusick newvp = vp; 48138414Smckusick np = VTONFS(vp); 48238414Smckusick } else if (ndp->ni_isdotdot) { 48338414Smckusick nfs_unlock(vp); 48438414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 48538414Smckusick nfs_lock(vp); 48638414Smckusick m_freem(mrep); 48738414Smckusick return (error); 48838414Smckusick } 48938414Smckusick nfs_lock(vp); 49038414Smckusick newvp = NFSTOV(np); 49138414Smckusick } else { 49238414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 49338414Smckusick m_freem(mrep); 49438414Smckusick return (error); 49538414Smckusick } 49638414Smckusick newvp = NFSTOV(np); 49738414Smckusick } 49838414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 49938414Smckusick if (newvp != vp) 50038414Smckusick nfs_nput(newvp); 50138414Smckusick else 50238425Smckusick vrele(vp); 50338414Smckusick m_freem(mrep); 50438414Smckusick return (error); 50538414Smckusick } 50638414Smckusick m_freem(mrep); 50738414Smckusick 50838414Smckusick if (vp != newvp && (!lockparent || *ndp->ni_next != '\0')) 50938414Smckusick nfs_unlock(vp); 51038414Smckusick ndp->ni_vp = newvp; 51138414Smckusick if (error == 0 && ndp->ni_makeentry) 51238414Smckusick cache_enter(ndp); 51338414Smckusick return (error); 51438414Smckusick } 51538414Smckusick 51638414Smckusick /* 51738414Smckusick * nfs readlink call 51838414Smckusick */ 51938414Smckusick nfs_readlink(vp, uiop, cred) 52038414Smckusick struct vnode *vp; 52138414Smckusick struct uio *uiop; 52238414Smckusick struct ucred *cred; 52338414Smckusick { 52438414Smckusick nfsm_vars; 52538414Smckusick long len; 52638414Smckusick 52738414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 52838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 52938414Smckusick nfsm_fhtom(vp); 53038414Smckusick nfsm_request(vp); 53138414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 53238414Smckusick nfsm_mtouio(uiop, len); 53338414Smckusick nfsm_reqdone; 53438414Smckusick return (error); 53538414Smckusick } 53638414Smckusick 53738414Smckusick /* 53838414Smckusick * nfs read call 53938414Smckusick */ 54038884Smacklem nfs_readrpc(vp, uiop, offp, cred) 54138414Smckusick struct vnode *vp; 54238414Smckusick struct uio *uiop; 54338414Smckusick off_t *offp; 54438414Smckusick struct ucred *cred; 54538414Smckusick { 54638414Smckusick nfsm_vars; 54738414Smckusick struct nfsmount *nmp; 54838414Smckusick long len, retlen, tsiz; 54938414Smckusick 55038414Smckusick nmp = vfs_to_nfs(vp->v_mount); 55138414Smckusick tsiz = uiop->uio_resid; 55238414Smckusick while (tsiz > 0) { 55338414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 55438414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 55538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 55638414Smckusick nfsm_fhtom(vp); 55738414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*3); 55838414Smckusick *p++ = txdr_unsigned(*offp); 55938414Smckusick *p++ = txdr_unsigned(len); 56038414Smckusick *p = 0; 56138414Smckusick nfsm_request(vp); 56238414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 56338414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 56438414Smckusick nfsm_mtouio(uiop, retlen); 56538414Smckusick m_freem(mrep); 56638414Smckusick *offp += retlen; 56738414Smckusick if (retlen < len) 56838414Smckusick tsiz = 0; 56938414Smckusick else 57038414Smckusick tsiz -= len; 57138414Smckusick } 57238414Smckusick nfsmout: 57338414Smckusick return (error); 57438414Smckusick } 57538414Smckusick 57638414Smckusick /* 57738414Smckusick * nfs write call 57838414Smckusick */ 57938884Smacklem nfs_writerpc(vp, uiop, offp, cred) 58038414Smckusick struct vnode *vp; 58138414Smckusick struct uio *uiop; 58238414Smckusick off_t *offp; 58338414Smckusick struct ucred *cred; 58438414Smckusick { 58538414Smckusick nfsm_vars; 58638414Smckusick struct nfsmount *nmp; 58738414Smckusick long len, tsiz; 58838414Smckusick 58938414Smckusick nmp = vfs_to_nfs(vp->v_mount); 59038414Smckusick tsiz = uiop->uio_resid; 59138414Smckusick while (tsiz > 0) { 59238414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 59338414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 59438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 59538414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 59638414Smckusick nfsm_fhtom(vp); 59738414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*4); 59838414Smckusick *(p+1) = txdr_unsigned(*offp); 59938414Smckusick *(p+3) = txdr_unsigned(len); 60038414Smckusick nfsm_uiotom(uiop, len); 60138414Smckusick nfsm_request(vp); 60238414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 60338414Smckusick m_freem(mrep); 60438414Smckusick tsiz -= len; 60538414Smckusick *offp += len; 60638414Smckusick } 60738414Smckusick nfsmout: 60838414Smckusick return (error); 60938414Smckusick } 61038414Smckusick 61138414Smckusick /* 61238414Smckusick * nfs file create call 61338414Smckusick */ 61438414Smckusick nfs_create(ndp, vap) 61538414Smckusick register struct nameidata *ndp; 61638414Smckusick register struct vattr *vap; 61738414Smckusick { 61838884Smacklem register struct nfsv2_sattr *sp; 61938414Smckusick nfsm_vars; 62038414Smckusick 62138414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 62238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 62338414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 62438414Smckusick nfsm_fhtom(ndp->ni_dvp); 62538414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 62638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 62738884Smacklem sp->sa_mode = vtonfs_mode(VREG, vap->va_mode); 62838884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 62938884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 63038884Smacklem sp->sa_size = txdr_unsigned(0); 63138414Smckusick /* or should these be VNOVAL ?? */ 63238884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 63338884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 63438414Smckusick nfsm_request(ndp->ni_dvp); 63538414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 63638414Smckusick nfsm_reqdone; 63738414Smckusick nfs_nput(ndp->ni_dvp); 63838414Smckusick return (error); 63938414Smckusick } 64038414Smckusick 64138414Smckusick /* 64238414Smckusick * nfs file remove call 64339341Smckusick * To try and make nfs semantics closer to vfs semantics, a file that has 64439341Smckusick * other references to the vnode is renamed instead of removed and then 64539341Smckusick * removed later on the last close. 64639341Smckusick * Unfortunately you must flush the buffer cache and cmap to get rid of 64739341Smckusick * all extraneous vnode references before you check the reference cnt. 64839341Smckusick * 1 - If the file could have blocks in the buffer cache 64939341Smckusick * flush them out and invalidate them 65039341Smckusick * mpurge the vnode to flush out cmap references 65139341Smckusick * (This is necessary to update the vnode ref cnt as well as sensible 65239341Smckusick * for actual removes, to free up the buffers) 65339341Smckusick * 2 - If v_count > 1 65439341Smckusick * If a rename is not already in the works 65539341Smckusick * call nfs_sillyrename() to set it up 65639341Smckusick * else 65739341Smckusick * do the remove rpc 65838414Smckusick */ 65938414Smckusick nfs_remove(ndp) 66038414Smckusick register struct nameidata *ndp; 66138414Smckusick { 66239341Smckusick register struct vnode *vp = ndp->ni_vp; 66339341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 66438414Smckusick nfsm_vars; 66538414Smckusick 66639341Smckusick if (vp->v_type == VREG) { 66739341Smckusick if (np->n_flag & (NMODIFIED|NBUFFERED)) { 66839341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 66939341Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 67039341Smckusick } 67139341Smckusick if (np->n_flag & NPAGEDON) 67239341Smckusick mpurge(vp); /* In case cmap entries still ref it */ 67339341Smckusick } 67439341Smckusick if (vp->v_count > 1) { 67539341Smckusick if (!np->n_sillyrename) 67639341Smckusick error = nfs_sillyrename(ndp, REMOVE); 67739341Smckusick } else { 67838414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 67938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 68038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 68138414Smckusick nfsm_fhtom(ndp->ni_dvp); 68238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 68338414Smckusick nfsm_request(ndp->ni_dvp); 68438414Smckusick nfsm_reqdone; 68538414Smckusick } 68638414Smckusick if (ndp->ni_dvp == ndp->ni_vp) 68738425Smckusick vrele(ndp->ni_vp); 68838414Smckusick else 68938425Smckusick nfs_nput(ndp->ni_vp); 69038425Smckusick nfs_nput(ndp->ni_dvp); 69138414Smckusick return (error); 69238414Smckusick } 69338414Smckusick 69438414Smckusick /* 69538414Smckusick * nfs file remove rpc called from nfs_inactive 69638414Smckusick */ 69738414Smckusick nfs_removeit(ndp) 69838414Smckusick register struct nameidata *ndp; 69938414Smckusick { 70038414Smckusick nfsm_vars; 70138414Smckusick 70238414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 70338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 70438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 70538414Smckusick nfsm_fhtom(ndp->ni_dvp); 70638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 70738414Smckusick nfsm_request(ndp->ni_dvp); 70838414Smckusick nfsm_reqdone; 70938414Smckusick return (error); 71038414Smckusick } 71138414Smckusick 71238414Smckusick /* 71338414Smckusick * nfs file rename call 71438414Smckusick */ 71538414Smckusick nfs_rename(sndp, tndp) 71638414Smckusick register struct nameidata *sndp, *tndp; 71738414Smckusick { 71838414Smckusick nfsm_vars; 71938414Smckusick 72038414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 72138414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 72238414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 72338414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 72438414Smckusick nfsm_fhtom(sndp->ni_dvp); 72538414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 72638414Smckusick nfsm_fhtom(tndp->ni_dvp); 72738414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 72838414Smckusick nfsm_request(sndp->ni_dvp); 72938414Smckusick nfsm_reqdone; 73038414Smckusick if (sndp->ni_vp->v_type == VDIR) { 73138414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 73238414Smckusick cache_purge(tndp->ni_dvp); 73338414Smckusick cache_purge(sndp->ni_dvp); 73438414Smckusick } 73538414Smckusick nfs_abortop(sndp); 73638414Smckusick nfs_abortop(tndp); 73738414Smckusick return (error); 73838414Smckusick } 73938414Smckusick 74038414Smckusick /* 74138414Smckusick * nfs file rename rpc called from above 74238414Smckusick */ 74338414Smckusick nfs_renameit(sndp, tndp) 74438414Smckusick register struct nameidata *sndp, *tndp; 74538414Smckusick { 74638414Smckusick nfsm_vars; 74738414Smckusick 74838414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 74938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 75038414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 75138414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 75238414Smckusick nfsm_fhtom(sndp->ni_dvp); 75338414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 75438414Smckusick nfsm_fhtom(tndp->ni_dvp); 75538414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 75638414Smckusick nfsm_request(sndp->ni_dvp); 75738414Smckusick nfsm_reqdone; 75838414Smckusick return (error); 75938414Smckusick } 76038414Smckusick 76138414Smckusick /* 76238414Smckusick * nfs hard link create call 76338414Smckusick */ 76438414Smckusick nfs_link(vp, ndp) 76538414Smckusick struct vnode *vp; 76638414Smckusick register struct nameidata *ndp; 76738414Smckusick { 76838414Smckusick nfsm_vars; 76938414Smckusick 77038425Smckusick if (ndp->ni_dvp != vp) 77138425Smckusick nfs_lock(vp); 77238414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 77338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 77438414Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 77538414Smckusick nfsm_fhtom(vp); 77638414Smckusick nfsm_fhtom(ndp->ni_dvp); 77738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 77838414Smckusick nfsm_request(vp); 77938414Smckusick nfsm_reqdone; 78038425Smckusick if (ndp->ni_dvp != vp) 78138425Smckusick nfs_unlock(vp); 78238414Smckusick nfs_nput(ndp->ni_dvp); 78338414Smckusick return (error); 78438414Smckusick } 78538414Smckusick 78638414Smckusick /* 78738414Smckusick * nfs symbolic link create call 78838414Smckusick */ 78938414Smckusick nfs_symlink(ndp, vap, nm) 79038414Smckusick struct nameidata *ndp; 79138414Smckusick struct vattr *vap; 79238414Smckusick char *nm; /* is this the path ?? */ 79338414Smckusick { 79438884Smacklem register struct nfsv2_sattr *sp; 79538414Smckusick nfsm_vars; 79638414Smckusick 79738414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 79838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 79938414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED); 80038414Smckusick nfsm_fhtom(ndp->ni_dvp); 80138414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 80238414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 80338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 80438884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 80538884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 80638884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 80738884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 80838884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 80938884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 81038414Smckusick nfsm_request(ndp->ni_dvp); 81138414Smckusick nfsm_reqdone; 81238414Smckusick nfs_nput(ndp->ni_dvp); 81338414Smckusick return (error); 81438414Smckusick } 81538414Smckusick 81638414Smckusick /* 81738414Smckusick * nfs make dir call 81838414Smckusick */ 81938414Smckusick nfs_mkdir(ndp, vap) 82038414Smckusick struct nameidata *ndp; 82138414Smckusick struct vattr *vap; 82238414Smckusick { 82338884Smacklem register struct nfsv2_sattr *sp; 82438414Smckusick nfsm_vars; 82538414Smckusick 82638414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 82738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 82838414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 82938414Smckusick nfsm_fhtom(ndp->ni_dvp); 83038414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 83138884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 83238884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 83338884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 83438884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 83538884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 83638884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 83738884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 83838414Smckusick nfsm_request(ndp->ni_dvp); 83938414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 84038414Smckusick nfsm_reqdone; 84138414Smckusick nfs_nput(ndp->ni_dvp); 84238414Smckusick return (error); 84338414Smckusick } 84438414Smckusick 84538414Smckusick /* 84638414Smckusick * nfs remove directory call 84738414Smckusick */ 84838414Smckusick nfs_rmdir(ndp) 84938414Smckusick register struct nameidata *ndp; 85038414Smckusick { 85138414Smckusick nfsm_vars; 85238414Smckusick 85338414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 85438414Smckusick vrele(ndp->ni_dvp); 85538414Smckusick nfs_nput(ndp->ni_dvp); 85638414Smckusick return (EINVAL); 85738414Smckusick } 85838414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 85938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 86038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 86138414Smckusick nfsm_fhtom(ndp->ni_dvp); 86238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 86338414Smckusick nfsm_request(ndp->ni_dvp); 86438414Smckusick nfsm_reqdone; 86538884Smacklem cache_purge(ndp->ni_dvp); 86638884Smacklem cache_purge(ndp->ni_vp); 86738884Smacklem nfs_nput(ndp->ni_vp); 86838884Smacklem nfs_nput(ndp->ni_dvp); 86938414Smckusick return (error); 87038414Smckusick } 87138414Smckusick 87238414Smckusick /* 87338414Smckusick * nfs readdir call 87438414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 87538414Smckusick * order so that it looks more sensible. This appears consistent with the 87638414Smckusick * Ultrix implementation of NFS. 87738414Smckusick */ 87838414Smckusick nfs_readdir(vp, uiop, offp, cred) 87938414Smckusick struct vnode *vp; 88038414Smckusick struct uio *uiop; 88138414Smckusick off_t *offp; 88238414Smckusick struct ucred *cred; 88338414Smckusick { 88438414Smckusick register long len; 88538414Smckusick register struct direct *dp; 88638414Smckusick nfsm_vars; 88738414Smckusick struct mbuf *md2; 88838414Smckusick caddr_t dpos2; 88938414Smckusick int siz; 89038414Smckusick int more_dirs, eofflg; 89138414Smckusick off_t off, savoff; 89238414Smckusick struct direct *savdp; 89338414Smckusick 89438414Smckusick nfs_lock(vp); 89538414Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 89638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 89738414Smckusick nfsm_fhtom(vp); 89838414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 89938414Smckusick off = *offp; 90038414Smckusick *p++ = txdr_unsigned(off); 90138414Smckusick *p = txdr_unsigned(uiop->uio_resid); 90238414Smckusick nfsm_request(vp); 90338414Smckusick siz = 0; 90438414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 90538414Smckusick more_dirs = fxdr_unsigned(int, *p); 90638414Smckusick 90738414Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 90838414Smckusick dpos2 = dpos; 90938414Smckusick md2 = md; 91038414Smckusick 91138414Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 91238414Smckusick while (more_dirs && siz < uiop->uio_resid) { 91338414Smckusick savoff = off; /* Hold onto offset and dp */ 91438414Smckusick savdp = dp; 91538414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 91638414Smckusick dp = (struct direct *)p; 91738414Smckusick dp->d_ino = fxdr_unsigned(u_long, *p++); 91838414Smckusick len = fxdr_unsigned(int, *p); 91938414Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 92038414Smckusick error = EBADRPC; 92138414Smckusick m_freem(mrep); 92238414Smckusick goto nfsmout; 92338414Smckusick } 92438414Smckusick dp->d_namlen = (u_short)len; 92538414Smckusick len = nfsm_rndup(len); 92638414Smckusick nfsm_adv(len); 92738414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 92838414Smckusick off = fxdr_unsigned(off_t, *p); 92938414Smckusick *p++ = 0; /* Ensures null termination of name */ 93038414Smckusick more_dirs = fxdr_unsigned(int, *p); 93138414Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 93238414Smckusick siz += dp->d_reclen; 93338414Smckusick } 93438414Smckusick /* 93538414Smckusick * If at end of rpc data, get the eof boolean 93638414Smckusick */ 93738414Smckusick if (!more_dirs) { 93838414Smckusick nfsm_disecton(p, u_long *, NFSX_UNSIGNED); 93938414Smckusick eofflg = fxdr_unsigned(long, *p); 94038414Smckusick } 94138414Smckusick /* 94238414Smckusick * If there is too much to fit in the data buffer, use savoff and 94338414Smckusick * savdp to trim off the last record. 94438414Smckusick * --> we are not at eof 94538414Smckusick */ 94638414Smckusick if (siz > uiop->uio_resid) { 94738414Smckusick eofflg = FALSE; 94838414Smckusick off = savoff; 94938414Smckusick siz -= dp->d_reclen; 95038414Smckusick dp = savdp; 95138414Smckusick } 95238414Smckusick if (siz > 0) { 95338414Smckusick #ifdef notdef 95438414Smckusick if (!eofflg) 95538414Smckusick dp->d_reclen += (uiop->uio_resid-siz); 95638414Smckusick #endif 95738414Smckusick md = md2; 95838414Smckusick dpos = dpos2; 95938414Smckusick nfsm_mtouio(uiop, siz); 96038414Smckusick #ifdef notdef 96138414Smckusick if (!eofflg) 96238414Smckusick uiop->uio_resid = 0; 96338414Smckusick #endif 96438414Smckusick *offp = off; 96538414Smckusick } 96638414Smckusick nfsm_reqdone; 96738414Smckusick nfs_unlock(vp); 96838414Smckusick return (error); 96938414Smckusick } 97038414Smckusick 97138414Smckusick /* 97238414Smckusick * nfs statfs call 97338414Smckusick * (Actually a vfsop, not a vnode op) 97438414Smckusick */ 97538414Smckusick nfs_statfs(mp, sbp) 97638414Smckusick struct mount *mp; 97738414Smckusick register struct statfs *sbp; 97838414Smckusick { 97938884Smacklem register struct nfsv2_statfs *sfp; 98038414Smckusick nfsm_vars; 98138884Smacklem struct nfsmount *nmp; 98238414Smckusick struct ucred *cred; 98338414Smckusick struct nfsnode *np; 98438414Smckusick struct vnode *vp; 98538414Smckusick 98638414Smckusick nmp = vfs_to_nfs(mp); 98738414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 98838414Smckusick return (error); 98938414Smckusick vp = NFSTOV(np); 99038414Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 99138414Smckusick cred = crget(); 99238414Smckusick cred->cr_ngroups = 1; 99338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 99438414Smckusick nfsm_fhtom(vp); 99538414Smckusick nfsm_request(vp); 99638884Smacklem nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 99738414Smckusick sbp->f_type = MOUNT_NFS; 99838414Smckusick sbp->f_flags = nmp->nm_flag; 99938884Smacklem sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 100038884Smacklem sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 100138884Smacklem sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 100238884Smacklem sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 100338884Smacklem sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 100438739Smckusick sbp->f_files = 0; 100538739Smckusick sbp->f_ffree = 0; 100638414Smckusick sbp->f_fsid.val[0] = mp->m_fsid.val[0]; 100738414Smckusick sbp->f_fsid.val[1] = mp->m_fsid.val[1]; 100838414Smckusick bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN); 100938414Smckusick bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN); 101038414Smckusick nfsm_reqdone; 101138414Smckusick nfs_nput(vp); 101238414Smckusick crfree(cred); 101338414Smckusick return (error); 101438414Smckusick } 101538414Smckusick 101638414Smckusick #define HEXTOASC(x) "0123456789abcdef"[x] 101738414Smckusick 101838414Smckusick /* 101938414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 102038414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 102138414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 102238414Smckusick * nfsnode. There is the potential for another process on a different client 102338414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 102438414Smckusick * nfs_rename() completes, but... 102538414Smckusick */ 102638414Smckusick nfs_sillyrename(ndp, flag) 102738414Smckusick struct nameidata *ndp; 102838414Smckusick int flag; 102938414Smckusick { 103038414Smckusick register struct nfsnode *np; 103138414Smckusick register struct sillyrename *sp; 103238414Smckusick register struct nameidata *tndp; 103338414Smckusick int error; 103438414Smckusick short pid; 103538414Smckusick 103638414Smckusick np = VTONFS(ndp->ni_dvp); 103739341Smckusick cache_purge(ndp->ni_dvp); 103838414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 103938884Smacklem M_TEMP, M_WAITOK); 104038414Smckusick sp->s_flag = flag; 104138414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 104238414Smckusick np = VTONFS(ndp->ni_vp); 104338414Smckusick tndp = &sp->s_namei; 104438414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 104538414Smckusick 104638414Smckusick /* Fudge together a funny name */ 104738414Smckusick pid = u.u_procp->p_pid; 104838414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 104938414Smckusick tndp->ni_dent.d_namlen = 12; 105038414Smckusick tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf); 105138414Smckusick tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf); 105238414Smckusick tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf); 105338414Smckusick tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf); 105438414Smckusick 105538414Smckusick /* Try lookitups until we get one that isn't there */ 105638414Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) { 105738414Smckusick tndp->ni_dent.d_name[4]++; 105838414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 105938414Smckusick error = EINVAL; 106038414Smckusick goto bad; 106138414Smckusick } 106238414Smckusick } 106338414Smckusick if (error = nfs_renameit(ndp, tndp)) 106438414Smckusick goto bad; 106538414Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh); 106638414Smckusick np->n_sillyrename = sp; 106738414Smckusick return (0); 106838414Smckusick bad: 106938884Smacklem crfree(tndp->ni_cred); 107038414Smckusick free((caddr_t)sp, M_TEMP); 107138414Smckusick return (error); 107238414Smckusick } 107338414Smckusick 107438414Smckusick /* 107538414Smckusick * Look up a file name for silly rename stuff. 107638414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 107738414Smckusick * into the nfsnode table. 107838414Smckusick * If fhp != NULL it copies the returned file handle out 107938414Smckusick */ 108038414Smckusick nfs_lookitup(vp, ndp, fhp) 108138414Smckusick register struct vnode *vp; 108238414Smckusick register struct nameidata *ndp; 108338414Smckusick nfsv2fh_t *fhp; 108438414Smckusick { 108538414Smckusick nfsm_vars; 108638414Smckusick long len; 108738414Smckusick 108838414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 108938414Smckusick ndp->ni_dvp = vp; 109038414Smckusick ndp->ni_vp = NULL; 109138414Smckusick len = ndp->ni_dent.d_namlen; 109238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 109338414Smckusick nfsm_fhtom(vp); 109438414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 109538414Smckusick nfsm_request(vp); 109638414Smckusick if (fhp != NULL) { 109738414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 109838414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 109938414Smckusick } 110038414Smckusick nfsm_reqdone; 110138414Smckusick return (error); 110238414Smckusick } 110338414Smckusick 110438414Smckusick /* 110538414Smckusick * Kludge City.. 110638414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 110738414Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit 110838414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 110938414Smckusick * nfsiobuf area. 111038414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 111138414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 111238414Smckusick * a lot more work than bcopy() and also it currently happens in the 111338414Smckusick * context of the swapper process (2). 111438414Smckusick */ 111538414Smckusick nfs_bmap(vp, bn, vpp, bnp) 111638414Smckusick struct vnode *vp; 111738414Smckusick daddr_t bn; 111838414Smckusick struct vnode **vpp; 111938414Smckusick daddr_t *bnp; 112038414Smckusick { 112138414Smckusick if (vpp != NULL) 112238414Smckusick *vpp = vp; 112338414Smckusick if (bnp != NULL) 112438414Smckusick *bnp = bn * btodb(vp->v_mount->m_bsize); 112538414Smckusick return (0); 112638414Smckusick } 112738414Smckusick 112838414Smckusick /* 112938884Smacklem * Strategy routine for phys. i/o 113038884Smacklem * If the biod's are running, queue a request 113138884Smacklem * otherwise just call nfs_doio() to get it done 113238414Smckusick */ 113338414Smckusick nfs_strategy(bp) 113438414Smckusick register struct buf *bp; 113538414Smckusick { 113638884Smacklem register struct buf *dp; 113739341Smckusick register int i; 113838884Smacklem struct proc *rp; 113938884Smacklem int error = 0; 114039341Smckusick int fnd = 0; 114138884Smacklem 114238884Smacklem /* 114338884Smacklem * If an i/o daemon is waiting 114438884Smacklem * queue the request, wake it up and wait for completion 114538884Smacklem * otherwise just do it ourselves 114638884Smacklem */ 114739341Smckusick for (i = 0; i < nfs_asyncdaemons; i++) { 114839341Smckusick if (rp = nfs_iodwant[i]) { 114939341Smckusick /* 115039341Smckusick * Ensure that the async_daemon is still waiting here 115139341Smckusick */ 115239341Smckusick if (rp->p_stat != SSLEEP || 115339341Smckusick rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) { 115439341Smckusick nfs_iodwant[i] = (struct proc *)0; 115539341Smckusick continue; 115639341Smckusick } 115739341Smckusick dp = &nfs_bqueue; 115839341Smckusick if (dp->b_actf == NULL) { 115939341Smckusick dp->b_actl = bp; 116039341Smckusick bp->b_actf = dp; 116139341Smckusick } else { 116239341Smckusick dp->b_actf->b_actl = bp; 116339341Smckusick bp->b_actf = dp->b_actf; 116439341Smckusick } 116539341Smckusick dp->b_actf = bp; 116639341Smckusick bp->b_actl = dp; 116739341Smckusick fnd++; 116839341Smckusick nfs_iodwant[i] = (struct proc *)0; 116939341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 117039341Smckusick break; 117138884Smacklem } 117239341Smckusick } 117339341Smckusick if (!fnd) 117438884Smacklem error = nfs_doio(bp); 117538884Smacklem return (error); 117638884Smacklem } 117738884Smacklem 117838884Smacklem /* 117938884Smacklem * Fun and games with i/o 118038884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 118138884Smacklem * mapping the data buffer into kernel virtual space and doing the 118238884Smacklem * nfs read or write rpc's from it. 118338884Smacklem * If the biod's are not running, this is just called from nfs_strategy(), 118438884Smacklem * otherwise it is called by the biod's to do what would normally be 118538884Smacklem * partially disk interrupt driven. 118638884Smacklem */ 118738884Smacklem nfs_doio(bp) 118838884Smacklem register struct buf *bp; 118938884Smacklem { 119038414Smckusick register struct pte *pte, *ppte; 119138414Smckusick register caddr_t vaddr; 119238414Smckusick register struct uio *uiop; 119338414Smckusick register struct vnode *vp; 119439341Smckusick struct nfsnode *np; 119538884Smacklem struct ucred *cr; 119638884Smacklem int npf, npf2; 119738884Smacklem int reg; 119838884Smacklem caddr_t vbase; 119938884Smacklem caddr_t addr; 120038414Smckusick unsigned v; 120138414Smckusick struct proc *rp; 120238414Smckusick int o, error; 120338884Smacklem int bcnt; 120438414Smckusick off_t off; 120538414Smckusick struct uio uio; 120638414Smckusick struct iovec io; 120738414Smckusick 120838414Smckusick vp = bp->b_vp; 120938414Smckusick uiop = &uio; 121038414Smckusick uiop->uio_iov = &io; 121138414Smckusick uiop->uio_iovcnt = 1; 121238414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 121338884Smacklem if (bp->b_flags & B_READ) { 121438884Smacklem io.iov_len = uiop->uio_resid = bp->b_bcount; 121538884Smacklem uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE; 121638884Smacklem addr = bp->b_un.b_addr; 121738884Smacklem bcnt = bp->b_bcount; 121838884Smacklem } else { 121938884Smacklem io.iov_len = uiop->uio_resid = bp->b_dirtyend-bp->b_dirtyoff; 122038884Smacklem uiop->uio_offset = off = (bp->b_blkno*DEV_BSIZE)+bp->b_dirtyoff; 122138884Smacklem addr = bp->b_un.b_addr+bp->b_dirtyoff; 122238884Smacklem bcnt = bp->b_dirtyend-bp->b_dirtyoff; 122338414Smckusick } 122438414Smckusick /* 122538884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 122638884Smacklem * the Nfsiomap pte's 122738884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 122838884Smacklem * and a guess at a group 122938414Smckusick */ 123038884Smacklem if (bp->b_flags & B_PHYS) { 123139341Smckusick VTONFS(vp)->n_flag |= NPAGEDON; 123238884Smacklem bp->b_rcred = cr = crget(); 123338884Smacklem rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc; 123438884Smacklem cr->cr_uid = rp->p_uid; 123538884Smacklem cr->cr_gid = 0; /* Anything ?? */ 123638884Smacklem cr->cr_ngroups = 1; 123738884Smacklem o = (int)addr & PGOFSET; 123838884Smacklem npf2 = npf = btoc(bcnt + o); 123938884Smacklem /* 124038884Smacklem * Get some mapping page table entries 124138884Smacklem */ 124238884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 124338884Smacklem nfsmap_want++; 124438884Smacklem sleep((caddr_t)&nfsmap_want, PZERO-1); 124538884Smacklem } 124638884Smacklem reg--; 124738884Smacklem /* I know it is always the else, but that may change someday */ 124838884Smacklem if ((bp->b_flags & B_PHYS) == 0) 124938884Smacklem pte = kvtopte(bp->b_un.b_addr); 125038884Smacklem else if (bp->b_flags & B_PAGET) 125138884Smacklem pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 125238884Smacklem else { 125338884Smacklem v = btop(bp->b_un.b_addr); 125438884Smacklem if (bp->b_flags & B_UAREA) 125538884Smacklem pte = &rp->p_addr[v]; 125638884Smacklem else 125738884Smacklem pte = vtopte(rp, v); 125838884Smacklem } 125938884Smacklem /* 126038884Smacklem * Play vmaccess() but with the Nfsiomap page table 126138884Smacklem */ 126238884Smacklem ppte = &Nfsiomap[reg]; 126338884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 126438884Smacklem while (npf != 0) { 126538884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 126638414Smckusick #if defined(tahoe) 126738884Smacklem mtpr(P1DC, vaddr); 126838414Smckusick #endif 126938884Smacklem ppte++; 127038884Smacklem pte++; 127138884Smacklem vaddr += NBPG; 127238884Smacklem --npf; 127338884Smacklem } 127438884Smacklem io.iov_base = vbase+o; 127538884Smacklem } else { 127638884Smacklem io.iov_base = addr; 127738414Smckusick } 127838414Smckusick if (bp->b_flags & B_READ) { 127938414Smckusick uiop->uio_rw = UIO_READ; 128038884Smacklem bp->b_error = error = nfs_readrpc(vp, uiop, &off, bp->b_rcred); 128138414Smckusick } else { 128238414Smckusick uiop->uio_rw = UIO_WRITE; 128338884Smacklem bp->b_error = error = nfs_writerpc(vp, uiop, &off, bp->b_wcred); 128439341Smckusick if (error) { 128539341Smckusick np = VTONFS(vp); 128639341Smckusick np->n_error = error; 128739341Smckusick np->n_flag |= NWRITEERR; 128839341Smckusick } 128938884Smacklem bp->b_dirtyoff = bp->b_dirtyend = 0; 129038414Smckusick } 129138884Smacklem if (error) 129238884Smacklem bp->b_flags |= B_ERROR; 129338414Smckusick bp->b_resid = uiop->uio_resid; 129438884Smacklem /* 129538884Smacklem * Release pte's used by physical i/o 129638884Smacklem */ 129738884Smacklem if (bp->b_flags & B_PHYS) { 129838884Smacklem crfree(cr); 129938884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 130038884Smacklem if (nfsmap_want) { 130138884Smacklem nfsmap_want = 0; 130238884Smacklem wakeup((caddr_t)&nfsmap_want); 130338884Smacklem } 130438884Smacklem } 130538414Smckusick biodone(bp); 130638414Smckusick return (error); 130738414Smckusick } 130838884Smacklem 130938884Smacklem /* 131038884Smacklem * Flush all the blocks associated with a vnode. 131138884Smacklem * Walk through the buffer pool and push any dirty pages 131238884Smacklem * associated with the vnode. 131338884Smacklem */ 131438884Smacklem nfs_fsync(vp, fflags, cred) 131538884Smacklem register struct vnode *vp; 131638884Smacklem int fflags; 131738884Smacklem struct ucred *cred; 131838884Smacklem { 131938884Smacklem register struct nfsnode *np = VTONFS(vp); 132038884Smacklem int error; 132138884Smacklem 132238884Smacklem nfs_lock(vp); 132338884Smacklem if (np->n_flag & NMODIFIED) { 132438884Smacklem np->n_flag &= ~NMODIFIED; 132539341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, FALSE); 132638884Smacklem } 132738884Smacklem nfs_unlock(vp); 132838884Smacklem return (error); 132938884Smacklem } 1330