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*40113Smckusick * @(#)nfs_vnops.c 7.27 (Berkeley) 02/16/90 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(), 6339459Smckusick nfs_mknod(), 6438414Smckusick nfs_open(), 6538414Smckusick nfs_close(), 6638414Smckusick nfs_access(), 6738414Smckusick nfs_getattr(), 6838414Smckusick nfs_setattr(), 6938414Smckusick nfs_read(), 7038414Smckusick nfs_write(), 7138414Smckusick vfs_noop(), 7238414Smckusick vfs_nullop(), 7338414Smckusick nfs_remove(), 7438414Smckusick nfs_link(), 7538414Smckusick nfs_rename(), 7638414Smckusick nfs_mkdir(), 7738414Smckusick nfs_rmdir(), 7838414Smckusick nfs_symlink(), 7938414Smckusick nfs_readdir(), 8038414Smckusick nfs_readlink(), 8138414Smckusick nfs_abortop(), 8238414Smckusick nfs_lock(), 8338414Smckusick nfs_unlock(), 8438414Smckusick nfs_bmap(), 8538414Smckusick nfs_strategy(), 8638884Smacklem nfs_fsync(), 8739394Smckusick nfs_inactive(), 8839672Smckusick nfs_reclaim(), 8939906Smckusick nfs_print(), 9039906Smckusick nfs_islocked(); 9138414Smckusick 9238414Smckusick struct vnodeops nfsv2_vnodeops = { 9339672Smckusick nfs_lookup, /* lookup */ 9439672Smckusick nfs_create, /* create */ 9539672Smckusick nfs_mknod, /* mknod */ 9639672Smckusick nfs_open, /* open */ 9739672Smckusick nfs_close, /* close */ 9839672Smckusick nfs_access, /* access */ 9939672Smckusick nfs_getattr, /* getattr */ 10039672Smckusick nfs_setattr, /* setattr */ 10139672Smckusick nfs_read, /* read */ 10239672Smckusick nfs_write, /* write */ 10339672Smckusick vfs_noop, /* ioctl */ 10439672Smckusick vfs_noop, /* select */ 10539672Smckusick vfs_noop, /* mmap */ 10639672Smckusick nfs_fsync, /* fsync */ 10739672Smckusick vfs_nullop, /* seek */ 10839672Smckusick nfs_remove, /* remove */ 10939672Smckusick nfs_link, /* link */ 11039672Smckusick nfs_rename, /* rename */ 11139672Smckusick nfs_mkdir, /* mkdir */ 11239672Smckusick nfs_rmdir, /* rmdir */ 11339672Smckusick nfs_symlink, /* symlink */ 11439672Smckusick nfs_readdir, /* readdir */ 11539672Smckusick nfs_readlink, /* readlink */ 11639672Smckusick nfs_abortop, /* abortop */ 11739672Smckusick nfs_inactive, /* inactive */ 11839672Smckusick nfs_reclaim, /* reclaim */ 11939672Smckusick nfs_lock, /* lock */ 12039672Smckusick nfs_unlock, /* unlock */ 12139672Smckusick nfs_bmap, /* bmap */ 12239672Smckusick nfs_strategy, /* strategy */ 12339672Smckusick nfs_print, /* print */ 12439906Smckusick nfs_islocked, /* islocked */ 12538414Smckusick }; 12638414Smckusick 12738414Smckusick /* Special device vnode ops */ 12839441Smckusick int spec_lookup(), 12939441Smckusick spec_open(), 13039441Smckusick spec_read(), 13139441Smckusick spec_write(), 13239441Smckusick spec_strategy(), 13339672Smckusick spec_bmap(), 13439441Smckusick spec_ioctl(), 13539441Smckusick spec_select(), 13639441Smckusick spec_close(), 13739441Smckusick spec_badop(), 13839441Smckusick spec_nullop(); 13938414Smckusick 14039441Smckusick struct vnodeops spec_nfsv2nodeops = { 14139599Smckusick spec_lookup, /* lookup */ 14239599Smckusick spec_badop, /* create */ 14339599Smckusick spec_badop, /* mknod */ 14439599Smckusick spec_open, /* open */ 14539599Smckusick spec_close, /* close */ 14639599Smckusick nfs_access, /* access */ 14739599Smckusick nfs_getattr, /* getattr */ 14839599Smckusick nfs_setattr, /* setattr */ 14939599Smckusick spec_read, /* read */ 15039599Smckusick spec_write, /* write */ 15139599Smckusick spec_ioctl, /* ioctl */ 15239599Smckusick spec_select, /* select */ 15339599Smckusick spec_badop, /* mmap */ 15439599Smckusick spec_nullop, /* fsync */ 15539599Smckusick spec_badop, /* seek */ 15639599Smckusick spec_badop, /* remove */ 15739599Smckusick spec_badop, /* link */ 15839599Smckusick spec_badop, /* rename */ 15939599Smckusick spec_badop, /* mkdir */ 16039599Smckusick spec_badop, /* rmdir */ 16139599Smckusick spec_badop, /* symlink */ 16239599Smckusick spec_badop, /* readdir */ 16339599Smckusick spec_badop, /* readlink */ 16439599Smckusick spec_badop, /* abortop */ 16539599Smckusick nfs_inactive, /* inactive */ 16639599Smckusick nfs_reclaim, /* reclaim */ 16739599Smckusick nfs_lock, /* lock */ 16839599Smckusick nfs_unlock, /* unlock */ 16939672Smckusick spec_bmap, /* bmap */ 17039599Smckusick spec_strategy, /* strategy */ 17139672Smckusick nfs_print, /* print */ 17239906Smckusick nfs_islocked, /* islocked */ 17338414Smckusick }; 17438414Smckusick 17538414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 17638414Smckusick extern u_long nfs_prog, nfs_vers; 17738414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 17840112Smckusick extern int nonidempotent[NFS_NPROCS]; 17938884Smacklem struct map nfsmap[NFS_MSIZ]; 18038414Smckusick enum vtype v_type[NFLNK+1]; 18138884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 18239341Smckusick int nfs_asyncdaemons = 0; 18339341Smckusick struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 18438884Smacklem static int nfsmap_want = 0; 18538414Smckusick 18638414Smckusick /* 18738414Smckusick * nfs null call from vfs. 18838414Smckusick */ 18938414Smckusick nfs_null(vp, cred) 19038414Smckusick struct vnode *vp; 19138414Smckusick struct ucred *cred; 19238414Smckusick { 19339488Smckusick caddr_t bpos, dpos; 19439488Smckusick u_long xid; 19539488Smckusick int error = 0; 19639488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 19738414Smckusick 19838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 19940112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_NULL]); 20038414Smckusick nfsm_reqdone; 20138414Smckusick return (error); 20238414Smckusick } 20338414Smckusick 20438414Smckusick /* 20538414Smckusick * nfs access vnode op. 20638414Smckusick * Essentially just get vattr and then imitate iaccess() 20738414Smckusick */ 20838414Smckusick nfs_access(vp, mode, cred) 20938414Smckusick struct vnode *vp; 21038414Smckusick int mode; 21138414Smckusick register struct ucred *cred; 21238414Smckusick { 21338414Smckusick register struct vattr *vap; 21438414Smckusick register gid_t *gp; 21538414Smckusick struct vattr vattr; 21638414Smckusick register int i; 21738414Smckusick int error; 21838414Smckusick 21938414Smckusick /* 22038414Smckusick * If you're the super-user, 22138414Smckusick * you always get access. 22238414Smckusick */ 22338414Smckusick if (cred->cr_uid == 0) 22438414Smckusick return (0); 22538414Smckusick vap = &vattr; 22638884Smacklem if (error = nfs_getattr(vp, vap, cred)) 22738884Smacklem return (error); 22838414Smckusick /* 22938414Smckusick * Access check is based on only one of owner, group, public. 23038414Smckusick * If not owner, then check group. If not a member of the 23138414Smckusick * group, then check public access. 23238414Smckusick */ 23338414Smckusick if (cred->cr_uid != vap->va_uid) { 23438414Smckusick mode >>= 3; 23538414Smckusick gp = cred->cr_groups; 23638414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 23738414Smckusick if (vap->va_gid == *gp) 23838414Smckusick goto found; 23938414Smckusick mode >>= 3; 24038414Smckusick found: 24138414Smckusick ; 24238414Smckusick } 24338414Smckusick if ((vap->va_mode & mode) != 0) 24438414Smckusick return (0); 24538414Smckusick return (EACCES); 24638414Smckusick } 24738414Smckusick 24838414Smckusick /* 24938414Smckusick * nfs open vnode op 25038414Smckusick * Just check to see if the type is ok 25138414Smckusick */ 25239488Smckusick /* ARGSUSED */ 25338414Smckusick nfs_open(vp, mode, cred) 25438414Smckusick struct vnode *vp; 25538414Smckusick int mode; 25638414Smckusick struct ucred *cred; 25738414Smckusick { 25838414Smckusick register enum vtype vtyp; 25938414Smckusick 26038414Smckusick vtyp = vp->v_type; 26138414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 26238414Smckusick return (0); 26338414Smckusick else 26438414Smckusick return (EACCES); 26538414Smckusick } 26638414Smckusick 26738414Smckusick /* 26838414Smckusick * nfs close vnode op 26938884Smacklem * For reg files, invalidate any buffer cache entries. 27038414Smckusick */ 27139488Smckusick /* ARGSUSED */ 27238414Smckusick nfs_close(vp, fflags, cred) 27338414Smckusick register struct vnode *vp; 27438414Smckusick int fflags; 27538414Smckusick struct ucred *cred; 27638414Smckusick { 27739488Smckusick register struct nfsnode *np = VTONFS(vp); 27839341Smckusick int error = 0; 27938414Smckusick 28039874Smckusick if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) || 28139341Smckusick ((np->n_flag & NBUFFERED) && np->n_sillyrename))) { 28239441Smckusick nfs_lock(vp); 28339341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 28439751Smckusick vinvalbuf(vp, TRUE); 28539341Smckusick if (np->n_flag & NWRITEERR) { 28639341Smckusick np->n_flag &= ~NWRITEERR; 28739751Smckusick error = np->n_error; 28839341Smckusick } 28939441Smckusick nfs_unlock(vp); 29038884Smacklem } 29138414Smckusick return (error); 29238414Smckusick } 29338414Smckusick 29438414Smckusick /* 29538414Smckusick * nfs getattr call from vfs. 29638414Smckusick */ 29738414Smckusick nfs_getattr(vp, vap, cred) 29839488Smckusick register struct vnode *vp; 29939488Smckusick struct vattr *vap; 30038414Smckusick struct ucred *cred; 30138414Smckusick { 30239488Smckusick register caddr_t cp; 30339488Smckusick register long t1; 30439488Smckusick caddr_t bpos, dpos; 30539488Smckusick u_long xid; 30639488Smckusick int error = 0; 30739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 30838414Smckusick 30938414Smckusick /* First look in the cache.. */ 31038414Smckusick if (nfs_getattrcache(vp, vap) == 0) 31138414Smckusick return (0); 31238414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 31338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH); 31438414Smckusick nfsm_fhtom(vp); 31540112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_GETATTR]); 31638414Smckusick nfsm_loadattr(vp, vap); 31738414Smckusick nfsm_reqdone; 31838414Smckusick return (error); 31938414Smckusick } 32038414Smckusick 32138414Smckusick /* 32238414Smckusick * nfs setattr call. 32338414Smckusick */ 32438414Smckusick nfs_setattr(vp, vap, cred) 32539488Smckusick register struct vnode *vp; 32638414Smckusick register struct vattr *vap; 32738414Smckusick struct ucred *cred; 32838414Smckusick { 32938884Smacklem register struct nfsv2_sattr *sp; 33039488Smckusick register caddr_t cp; 33139488Smckusick register long t1; 33239488Smckusick caddr_t bpos, dpos; 33339488Smckusick u_long xid; 33439488Smckusick int error = 0; 33539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 33639359Smckusick struct nfsnode *np; 33738414Smckusick 33838414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 33938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 34038414Smckusick nfsm_fhtom(vp); 34138884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 34238414Smckusick if (vap->va_mode == 0xffff) 34338884Smacklem sp->sa_mode = VNOVAL; 34438414Smckusick else 34538884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 34638414Smckusick if (vap->va_uid == 0xffff) 34738884Smacklem sp->sa_uid = VNOVAL; 34838414Smckusick else 34938884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 35038414Smckusick if (vap->va_gid == 0xffff) 35138884Smacklem sp->sa_gid = VNOVAL; 35238414Smckusick else 35338884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 35438884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 35539359Smckusick if (vap->va_size != VNOVAL) { 35639359Smckusick np = VTONFS(vp); 35739359Smckusick if (np->n_flag & NMODIFIED) { 35839359Smckusick np->n_flag &= ~NMODIFIED; 35939874Smckusick vinvalbuf(vp, TRUE); 36039359Smckusick } 36139359Smckusick } 36239751Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec); 36339751Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 36438884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 36540112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_SETATTR]); 36638414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 36738414Smckusick /* should we fill in any vap fields ?? */ 36838414Smckusick nfsm_reqdone; 36938414Smckusick return (error); 37038414Smckusick } 37138414Smckusick 37238414Smckusick /* 37338414Smckusick * nfs lookup call, one step at a time... 37438414Smckusick * First look in cache 37538414Smckusick * If not found, unlock the directory nfsnode and do the rpc 37638414Smckusick */ 37738414Smckusick nfs_lookup(vp, ndp) 37838414Smckusick register struct vnode *vp; 37938414Smckusick register struct nameidata *ndp; 38038414Smckusick { 38138414Smckusick register struct vnode *vdp; 38239488Smckusick register u_long *p; 38339488Smckusick register caddr_t cp; 38439488Smckusick register long t1, t2; 38539488Smckusick caddr_t bpos, dpos, cp2; 38639488Smckusick u_long xid; 38739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 38838414Smckusick struct vnode *newvp; 38938414Smckusick long len; 39038414Smckusick nfsv2fh_t *fhp; 39138414Smckusick struct nfsnode *np; 39239488Smckusick int lockparent, wantparent, flag, error = 0; 39338414Smckusick 39438414Smckusick ndp->ni_dvp = vp; 39538414Smckusick ndp->ni_vp = NULL; 39638414Smckusick if (vp->v_type != VDIR) 39738414Smckusick return (ENOTDIR); 39838414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 39938414Smckusick flag = ndp->ni_nameiop & OPFLAG; 40038414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 40139341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 40238884Smacklem struct vattr vattr; 40338884Smacklem int vpid; 40438884Smacklem 40539441Smckusick if (vp == ndp->ni_rdir && ndp->ni_isdotdot) 40639441Smckusick panic("nfs_lookup: .. through root"); 40739441Smckusick vdp = ndp->ni_vp; 40838884Smacklem vpid = vdp->v_id; 40938414Smckusick /* 41038884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 41138884Smacklem * for an explanation of the locking protocol 41238414Smckusick */ 41338414Smckusick if (vp == vdp) { 41438425Smckusick VREF(vdp); 41539441Smckusick error = 0; 41638414Smckusick } else if (ndp->ni_isdotdot) { 41738414Smckusick nfs_unlock(vp); 41839441Smckusick error = vget(vdp); 41938414Smckusick } else { 42039441Smckusick error = vget(vdp); 42138414Smckusick nfs_unlock(vp); 42238414Smckusick } 42339441Smckusick if (!error) { 42439441Smckusick if (vpid == vdp->v_id && 42539441Smckusick !nfs_getattr(vdp, &vattr, ndp->ni_cred)) { 42639441Smckusick nfsstats.lookupcache_hits++; 42739441Smckusick return (0); 42839441Smckusick } else { 42939441Smckusick nfs_nput(vdp); 43039441Smckusick } 43138884Smacklem } 43238884Smacklem ndp->ni_vp = (struct vnode *)0; 43339751Smckusick } else 43439751Smckusick nfs_unlock(vp); 43539341Smckusick error = 0; 43638414Smckusick nfsstats.lookupcache_misses++; 43738414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 43838414Smckusick len = ndp->ni_namelen; 43938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 44038414Smckusick nfsm_fhtom(vp); 44138414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 44240112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]); 44338414Smckusick nfsmout: 44438414Smckusick if (error) { 44539751Smckusick if (lockparent || (flag != CREATE && flag != RENAME) || 44639751Smckusick *ndp->ni_next != 0) 44739751Smckusick nfs_lock(vp); 44838414Smckusick return (ENOENT); 44938414Smckusick } 45038414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 45138414Smckusick 45238414Smckusick /* 45338414Smckusick * Handle DELETE and RENAME cases... 45438414Smckusick */ 45538414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 45638414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 45738425Smckusick VREF(vp); 45838414Smckusick newvp = vp; 45938414Smckusick np = VTONFS(vp); 46038414Smckusick } else { 46138414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 46239751Smckusick nfs_lock(vp); 46338414Smckusick m_freem(mrep); 46438414Smckusick return (error); 46538414Smckusick } 46638414Smckusick newvp = NFSTOV(np); 46738414Smckusick } 46839459Smckusick if (error = 46939459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 47039751Smckusick nfs_lock(vp); 47138414Smckusick if (newvp != vp) 47238414Smckusick nfs_nput(newvp); 47338414Smckusick else 47438425Smckusick vrele(vp); 47538414Smckusick m_freem(mrep); 47638414Smckusick return (error); 47738414Smckusick } 47838414Smckusick ndp->ni_vp = newvp; 47939751Smckusick if (lockparent || vp == newvp) 48039751Smckusick nfs_lock(vp); 48138414Smckusick m_freem(mrep); 48238414Smckusick return (0); 48338414Smckusick } 48438414Smckusick 48538414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 48638414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 48739751Smckusick nfs_lock(vp); 48838414Smckusick m_freem(mrep); 48938414Smckusick return (EISDIR); 49038414Smckusick } 49138414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 49239751Smckusick nfs_lock(vp); 49338414Smckusick m_freem(mrep); 49438414Smckusick return (error); 49538414Smckusick } 49638414Smckusick newvp = NFSTOV(np); 49739459Smckusick if (error = 49839459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 49939751Smckusick nfs_lock(vp); 50038425Smckusick nfs_nput(newvp); 50138414Smckusick m_freem(mrep); 50238414Smckusick return (error); 50338414Smckusick } 50438414Smckusick ndp->ni_vp = newvp; 50539751Smckusick if (lockparent) 50639751Smckusick nfs_lock(vp); 50738414Smckusick return (0); 50838414Smckusick } 50938414Smckusick 51038414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 51138425Smckusick VREF(vp); 51238414Smckusick newvp = vp; 51338414Smckusick np = VTONFS(vp); 51438414Smckusick } else if (ndp->ni_isdotdot) { 51538414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 51638414Smckusick nfs_lock(vp); 51738414Smckusick m_freem(mrep); 51838414Smckusick return (error); 51938414Smckusick } 52038414Smckusick newvp = NFSTOV(np); 52138414Smckusick } else { 52238414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 52339751Smckusick nfs_lock(vp); 52438414Smckusick m_freem(mrep); 52538414Smckusick return (error); 52638414Smckusick } 52738414Smckusick newvp = NFSTOV(np); 52838414Smckusick } 52939459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 53039751Smckusick nfs_lock(vp); 53138414Smckusick if (newvp != vp) 53238414Smckusick nfs_nput(newvp); 53338414Smckusick else 53438425Smckusick vrele(vp); 53538414Smckusick m_freem(mrep); 53638414Smckusick return (error); 53738414Smckusick } 53838414Smckusick m_freem(mrep); 53938414Smckusick 54039751Smckusick if (vp == newvp || (lockparent && *ndp->ni_next == '\0')) 54139751Smckusick nfs_lock(vp); 54238414Smckusick ndp->ni_vp = newvp; 54338414Smckusick if (error == 0 && ndp->ni_makeentry) 54438414Smckusick cache_enter(ndp); 54538414Smckusick return (error); 54638414Smckusick } 54738414Smckusick 54838414Smckusick /* 54938414Smckusick * nfs readlink call 55038414Smckusick */ 55138414Smckusick nfs_readlink(vp, uiop, cred) 55239488Smckusick register struct vnode *vp; 55338414Smckusick struct uio *uiop; 55438414Smckusick struct ucred *cred; 55538414Smckusick { 55639488Smckusick register u_long *p; 55739488Smckusick register caddr_t cp; 55839488Smckusick register long t1; 55939488Smckusick caddr_t bpos, dpos, cp2; 56039488Smckusick u_long xid; 56139488Smckusick int error = 0; 56239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 56338414Smckusick long len; 56438414Smckusick 56538414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 56638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 56738414Smckusick nfsm_fhtom(vp); 56840112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_READLINK]); 56938414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 57038414Smckusick nfsm_mtouio(uiop, len); 57138414Smckusick nfsm_reqdone; 57238414Smckusick return (error); 57338414Smckusick } 57438414Smckusick 57538414Smckusick /* 57638414Smckusick * nfs read call 57738414Smckusick */ 57839587Smckusick nfs_readrpc(vp, uiop, cred) 57939488Smckusick register struct vnode *vp; 58038414Smckusick struct uio *uiop; 58138414Smckusick struct ucred *cred; 58238414Smckusick { 58339488Smckusick register u_long *p; 58439488Smckusick register caddr_t cp; 58539488Smckusick register long t1; 58639488Smckusick caddr_t bpos, dpos, cp2; 58739488Smckusick u_long xid; 58839488Smckusick int error = 0; 58939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 59038414Smckusick struct nfsmount *nmp; 59138414Smckusick long len, retlen, tsiz; 59238414Smckusick 59338414Smckusick nmp = vfs_to_nfs(vp->v_mount); 59438414Smckusick tsiz = uiop->uio_resid; 59538414Smckusick while (tsiz > 0) { 59638414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 59738414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 59838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 59938414Smckusick nfsm_fhtom(vp); 60038414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*3); 60139587Smckusick *p++ = txdr_unsigned(uiop->uio_offset); 60238414Smckusick *p++ = txdr_unsigned(len); 60338414Smckusick *p = 0; 60440112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_READ]); 60538414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 60638414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 60738414Smckusick nfsm_mtouio(uiop, retlen); 60838414Smckusick m_freem(mrep); 60938414Smckusick if (retlen < len) 61038414Smckusick tsiz = 0; 61138414Smckusick else 61238414Smckusick tsiz -= len; 61338414Smckusick } 61438414Smckusick nfsmout: 61538414Smckusick return (error); 61638414Smckusick } 61738414Smckusick 61838414Smckusick /* 61938414Smckusick * nfs write call 62038414Smckusick */ 62139587Smckusick nfs_writerpc(vp, uiop, cred) 62239488Smckusick register struct vnode *vp; 62338414Smckusick struct uio *uiop; 62438414Smckusick struct ucred *cred; 62538414Smckusick { 62639488Smckusick register u_long *p; 62739488Smckusick register caddr_t cp; 62839488Smckusick register long t1; 62939488Smckusick caddr_t bpos, dpos; 63039488Smckusick u_long xid; 63139488Smckusick int error = 0; 63239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 63338414Smckusick struct nfsmount *nmp; 63438414Smckusick long len, tsiz; 63538414Smckusick 63638414Smckusick nmp = vfs_to_nfs(vp->v_mount); 63738414Smckusick tsiz = uiop->uio_resid; 63838414Smckusick while (tsiz > 0) { 63938414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 64038414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 64138414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 64238414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 64338414Smckusick nfsm_fhtom(vp); 64438414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*4); 64539587Smckusick *(p+1) = txdr_unsigned(uiop->uio_offset); 64638414Smckusick *(p+3) = txdr_unsigned(len); 64738414Smckusick nfsm_uiotom(uiop, len); 64840112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_WRITE]); 64938414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 65038414Smckusick m_freem(mrep); 65138414Smckusick tsiz -= len; 65238414Smckusick } 65338414Smckusick nfsmout: 65438414Smckusick return (error); 65538414Smckusick } 65638414Smckusick 65738414Smckusick /* 65839459Smckusick * nfs mknod call 65939459Smckusick * This call is currently not supported. 66039459Smckusick */ 66139459Smckusick /* ARGSUSED */ 66239459Smckusick nfs_mknod(ndp, vap, cred) 66339459Smckusick struct nameidata *ndp; 66439459Smckusick struct ucred *cred; 66539459Smckusick struct vattr *vap; 66639459Smckusick { 66739459Smckusick 66839459Smckusick nfs_abortop(ndp); 66939459Smckusick return (EOPNOTSUPP); 67039459Smckusick } 67139459Smckusick 67239459Smckusick /* 67338414Smckusick * nfs file create call 67438414Smckusick */ 67538414Smckusick nfs_create(ndp, vap) 67638414Smckusick register struct nameidata *ndp; 67738414Smckusick register struct vattr *vap; 67838414Smckusick { 67938884Smacklem register struct nfsv2_sattr *sp; 68039488Smckusick register u_long *p; 68139488Smckusick register caddr_t cp; 68239488Smckusick register long t1, t2; 68339488Smckusick caddr_t bpos, dpos, cp2; 68439488Smckusick u_long xid; 68539488Smckusick int error = 0; 68639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 68738414Smckusick 68838414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 68938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 69038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 69138414Smckusick nfsm_fhtom(ndp->ni_dvp); 69238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 69338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 69438884Smacklem sp->sa_mode = vtonfs_mode(VREG, vap->va_mode); 69538884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 69638884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 69738884Smacklem sp->sa_size = txdr_unsigned(0); 69838414Smckusick /* or should these be VNOVAL ?? */ 69938884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 70038884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 70140112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_CREATE]); 70238414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 70338414Smckusick nfsm_reqdone; 70438414Smckusick nfs_nput(ndp->ni_dvp); 70538414Smckusick return (error); 70638414Smckusick } 70738414Smckusick 70838414Smckusick /* 70938414Smckusick * nfs file remove call 71039341Smckusick * To try and make nfs semantics closer to vfs semantics, a file that has 71139341Smckusick * other references to the vnode is renamed instead of removed and then 71239341Smckusick * removed later on the last close. 71339341Smckusick * Unfortunately you must flush the buffer cache and cmap to get rid of 71439341Smckusick * all extraneous vnode references before you check the reference cnt. 71539341Smckusick * 1 - If the file could have blocks in the buffer cache 71639341Smckusick * flush them out and invalidate them 71739341Smckusick * mpurge the vnode to flush out cmap references 71839341Smckusick * (This is necessary to update the vnode ref cnt as well as sensible 71939341Smckusick * for actual removes, to free up the buffers) 72039810Smckusick * 2 - If v_usecount > 1 72139341Smckusick * If a rename is not already in the works 72239341Smckusick * call nfs_sillyrename() to set it up 72339341Smckusick * else 72439341Smckusick * do the remove rpc 72538414Smckusick */ 72638414Smckusick nfs_remove(ndp) 72738414Smckusick register struct nameidata *ndp; 72838414Smckusick { 72939341Smckusick register struct vnode *vp = ndp->ni_vp; 73039341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 73139488Smckusick register u_long *p; 73239488Smckusick register caddr_t cp; 73339488Smckusick register long t1, t2; 73439488Smckusick caddr_t bpos, dpos; 73539488Smckusick u_long xid; 73639488Smckusick int error = 0; 73739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73838414Smckusick 73939341Smckusick if (vp->v_type == VREG) { 74039341Smckusick if (np->n_flag & (NMODIFIED|NBUFFERED)) { 74139341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 74239874Smckusick vinvalbuf(vp, TRUE); 74339341Smckusick } 74439751Smckusick if (np->n_flag & NPAGEDON) { 74539751Smckusick np->n_flag &= ~NPAGEDON; 74639341Smckusick mpurge(vp); /* In case cmap entries still ref it */ 74739751Smckusick } 74839341Smckusick } 74939810Smckusick if (vp->v_usecount > 1) { 75039341Smckusick if (!np->n_sillyrename) 75139341Smckusick error = nfs_sillyrename(ndp, REMOVE); 75239341Smckusick } else { 75338414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 75438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 75538414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 75638414Smckusick nfsm_fhtom(ndp->ni_dvp); 75738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 75840112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]); 75938414Smckusick nfsm_reqdone; 76039751Smckusick /* 76139751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 76239751Smckusick * the reply to the retransmitted request will be ENOENT 76339751Smckusick * since the file was in fact removed 76439751Smckusick * Therefore, we cheat and return success. 76539751Smckusick */ 76639751Smckusick if (error == ENOENT) 76739751Smckusick error = 0; 76838414Smckusick } 76940042Smckusick np->n_attrstamp = 0; 77040112Smckusick if (ndp->ni_dvp == vp) 77140112Smckusick vrele(vp); 77238414Smckusick else 77340112Smckusick nfs_nput(ndp->ni_dvp); 77440112Smckusick nfs_nput(vp); 77538414Smckusick return (error); 77638414Smckusick } 77738414Smckusick 77838414Smckusick /* 77938414Smckusick * nfs file remove rpc called from nfs_inactive 78038414Smckusick */ 78138414Smckusick nfs_removeit(ndp) 78238414Smckusick register struct nameidata *ndp; 78338414Smckusick { 78439488Smckusick register u_long *p; 78539488Smckusick register caddr_t cp; 78639488Smckusick register long t1, t2; 78739488Smckusick caddr_t bpos, dpos; 78839488Smckusick u_long xid; 78939488Smckusick int error = 0; 79039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 79138414Smckusick 79238414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 79338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 79438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 79538414Smckusick nfsm_fhtom(ndp->ni_dvp); 79638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 79740112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]); 79838414Smckusick nfsm_reqdone; 79938414Smckusick return (error); 80038414Smckusick } 80138414Smckusick 80238414Smckusick /* 80338414Smckusick * nfs file rename call 80438414Smckusick */ 80538414Smckusick nfs_rename(sndp, tndp) 80638414Smckusick register struct nameidata *sndp, *tndp; 80738414Smckusick { 80839488Smckusick register u_long *p; 80939488Smckusick register caddr_t cp; 81039488Smckusick register long t1, t2; 81139488Smckusick caddr_t bpos, dpos; 81239488Smckusick u_long xid; 81339488Smckusick int error = 0; 81439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 81538414Smckusick 81638414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 81738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 81838414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 81938414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 82038414Smckusick nfsm_fhtom(sndp->ni_dvp); 82138414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 82238414Smckusick nfsm_fhtom(tndp->ni_dvp); 82338414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 82440112Smckusick nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]); 82538414Smckusick nfsm_reqdone; 82638414Smckusick if (sndp->ni_vp->v_type == VDIR) { 82738414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 82838414Smckusick cache_purge(tndp->ni_dvp); 82938414Smckusick cache_purge(sndp->ni_dvp); 83038414Smckusick } 83138414Smckusick nfs_abortop(sndp); 83238414Smckusick nfs_abortop(tndp); 83340112Smckusick /* 83440112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 83540112Smckusick */ 83640112Smckusick if (error == ENOENT) 83740112Smckusick error = 0; 83838414Smckusick return (error); 83938414Smckusick } 84038414Smckusick 84138414Smckusick /* 84238414Smckusick * nfs file rename rpc called from above 84338414Smckusick */ 84438414Smckusick nfs_renameit(sndp, tndp) 84538414Smckusick register struct nameidata *sndp, *tndp; 84638414Smckusick { 84739488Smckusick register u_long *p; 84839488Smckusick register caddr_t cp; 84939488Smckusick register long t1, t2; 85039488Smckusick caddr_t bpos, dpos; 85139488Smckusick u_long xid; 85239488Smckusick int error = 0; 85339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 85438414Smckusick 85538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 85638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 85738414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 85838414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 85938414Smckusick nfsm_fhtom(sndp->ni_dvp); 86038414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 86138414Smckusick nfsm_fhtom(tndp->ni_dvp); 86238414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 86340112Smckusick nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]); 86438414Smckusick nfsm_reqdone; 86538414Smckusick return (error); 86638414Smckusick } 86738414Smckusick 86838414Smckusick /* 86938414Smckusick * nfs hard link create call 87038414Smckusick */ 87138414Smckusick nfs_link(vp, ndp) 87239488Smckusick register struct vnode *vp; 87338414Smckusick register struct nameidata *ndp; 87438414Smckusick { 87539488Smckusick register u_long *p; 87639488Smckusick register caddr_t cp; 87739488Smckusick register long t1, t2; 87839488Smckusick caddr_t bpos, dpos; 87939488Smckusick u_long xid; 88039488Smckusick int error = 0; 88139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 88238414Smckusick 88338425Smckusick if (ndp->ni_dvp != vp) 88438425Smckusick nfs_lock(vp); 88538414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 88638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 88738414Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 88838414Smckusick nfsm_fhtom(vp); 88938414Smckusick nfsm_fhtom(ndp->ni_dvp); 89038414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 89140112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_LINK]); 89238414Smckusick nfsm_reqdone; 89340042Smckusick VTONFS(vp)->n_attrstamp = 0; 89438425Smckusick if (ndp->ni_dvp != vp) 89538425Smckusick nfs_unlock(vp); 89638414Smckusick nfs_nput(ndp->ni_dvp); 89740112Smckusick /* 89840112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 89940112Smckusick */ 90040112Smckusick if (error == EEXIST) 90140112Smckusick error = 0; 90238414Smckusick return (error); 90338414Smckusick } 90438414Smckusick 90538414Smckusick /* 90638414Smckusick * nfs symbolic link create call 90738414Smckusick */ 90838414Smckusick nfs_symlink(ndp, vap, nm) 90938414Smckusick struct nameidata *ndp; 91038414Smckusick struct vattr *vap; 91138414Smckusick char *nm; /* is this the path ?? */ 91238414Smckusick { 91338884Smacklem register struct nfsv2_sattr *sp; 91439488Smckusick register u_long *p; 91539488Smckusick register caddr_t cp; 91639488Smckusick register long t1, t2; 91739488Smckusick caddr_t bpos, dpos; 91839488Smckusick u_long xid; 91939488Smckusick int error = 0; 92039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92138414Smckusick 92238414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 92338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 92438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED); 92538414Smckusick nfsm_fhtom(ndp->ni_dvp); 92638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 92738414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 92838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 92938884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 93038884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 93138884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 93238884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 93340112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 93438884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 93540112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]); 93638414Smckusick nfsm_reqdone; 93738414Smckusick nfs_nput(ndp->ni_dvp); 93840112Smckusick /* 93940112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 94040112Smckusick */ 94140112Smckusick if (error == EEXIST) 94240112Smckusick error = 0; 94338414Smckusick return (error); 94438414Smckusick } 94538414Smckusick 94638414Smckusick /* 94738414Smckusick * nfs make dir call 94838414Smckusick */ 94938414Smckusick nfs_mkdir(ndp, vap) 95039488Smckusick register struct nameidata *ndp; 95138414Smckusick struct vattr *vap; 95238414Smckusick { 95338884Smacklem register struct nfsv2_sattr *sp; 95439488Smckusick register u_long *p; 95539488Smckusick register caddr_t cp; 95639488Smckusick register long t1, t2; 95739488Smckusick caddr_t bpos, dpos, cp2; 95839488Smckusick u_long xid; 95939488Smckusick int error = 0; 96039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 96138414Smckusick 96238414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 96338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 96438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 96538414Smckusick nfsm_fhtom(ndp->ni_dvp); 96638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 96738884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 96838884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 96938884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 97038884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 97138884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 97240112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 97338884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 97440112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_MKDIR]); 97538414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 97638414Smckusick nfsm_reqdone; 97738414Smckusick nfs_nput(ndp->ni_dvp); 97840112Smckusick /* 97940112Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry. 98040112Smckusick */ 98140112Smckusick if (error == EEXIST) 98240112Smckusick error = 0; 98338414Smckusick return (error); 98438414Smckusick } 98538414Smckusick 98638414Smckusick /* 98738414Smckusick * nfs remove directory call 98838414Smckusick */ 98938414Smckusick nfs_rmdir(ndp) 99038414Smckusick register struct nameidata *ndp; 99138414Smckusick { 99239488Smckusick register u_long *p; 99339488Smckusick register caddr_t cp; 99439488Smckusick register long t1, t2; 99539488Smckusick caddr_t bpos, dpos; 99639488Smckusick u_long xid; 99739488Smckusick int error = 0; 99839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 99938414Smckusick 100038414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 100138414Smckusick vrele(ndp->ni_dvp); 100238414Smckusick nfs_nput(ndp->ni_dvp); 100338414Smckusick return (EINVAL); 100438414Smckusick } 100538414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 100638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 100738414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 100838414Smckusick nfsm_fhtom(ndp->ni_dvp); 100938414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 101040112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_RMDIR]); 101138414Smckusick nfsm_reqdone; 101238884Smacklem cache_purge(ndp->ni_dvp); 101338884Smacklem cache_purge(ndp->ni_vp); 101438884Smacklem nfs_nput(ndp->ni_vp); 101538884Smacklem nfs_nput(ndp->ni_dvp); 101640112Smckusick /* 101740112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 101840112Smckusick */ 101940112Smckusick if (error == ENOENT) 102040112Smckusick error = 0; 102138414Smckusick return (error); 102238414Smckusick } 102338414Smckusick 102438414Smckusick /* 102538414Smckusick * nfs readdir call 102638414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 102738414Smckusick * order so that it looks more sensible. This appears consistent with the 102838414Smckusick * Ultrix implementation of NFS. 102938414Smckusick */ 103039587Smckusick nfs_readdir(vp, uiop, cred) 103139488Smckusick register struct vnode *vp; 103238414Smckusick struct uio *uiop; 103338414Smckusick struct ucred *cred; 103438414Smckusick { 103538414Smckusick register long len; 103638414Smckusick register struct direct *dp; 103739488Smckusick register u_long *p; 103839488Smckusick register caddr_t cp; 103939488Smckusick register long t1; 1040*40113Smckusick long tlen; 104139488Smckusick caddr_t bpos, dpos, cp2; 104239488Smckusick u_long xid; 104339488Smckusick int error = 0; 104439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 104538414Smckusick struct mbuf *md2; 104638414Smckusick caddr_t dpos2; 104738414Smckusick int siz; 104839495Smckusick int more_dirs; 104938414Smckusick off_t off, savoff; 105038414Smckusick struct direct *savdp; 105138414Smckusick 105238414Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 105338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 105438414Smckusick nfsm_fhtom(vp); 105538414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 105639587Smckusick *p++ = txdr_unsigned(uiop->uio_offset); 105738414Smckusick *p = txdr_unsigned(uiop->uio_resid); 105840112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_READDIR]); 105938414Smckusick siz = 0; 106038414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 106138414Smckusick more_dirs = fxdr_unsigned(int, *p); 106238414Smckusick 106338414Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 106438414Smckusick dpos2 = dpos; 106538414Smckusick md2 = md; 106638414Smckusick 106738414Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 106839488Smckusick savoff = off = 0; 106939488Smckusick savdp = dp = NULL; 107038414Smckusick while (more_dirs && siz < uiop->uio_resid) { 107138414Smckusick savoff = off; /* Hold onto offset and dp */ 107238414Smckusick savdp = dp; 107338414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 107438414Smckusick dp = (struct direct *)p; 107538414Smckusick dp->d_ino = fxdr_unsigned(u_long, *p++); 107638414Smckusick len = fxdr_unsigned(int, *p); 107738414Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 107838414Smckusick error = EBADRPC; 107938414Smckusick m_freem(mrep); 108038414Smckusick goto nfsmout; 108138414Smckusick } 108238414Smckusick dp->d_namlen = (u_short)len; 1083*40113Smckusick nfsm_adv(len); /* Point past name */ 1084*40113Smckusick tlen = nfsm_rndup(len); 1085*40113Smckusick if (tlen != len) { /* If name not on rounded boundary */ 1086*40113Smckusick *dpos = '\0'; /* Null-terminate */ 1087*40113Smckusick nfsm_adv(tlen - len); 1088*40113Smckusick len = tlen; 1089*40113Smckusick } 109038414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 109138414Smckusick off = fxdr_unsigned(off_t, *p); 109238414Smckusick *p++ = 0; /* Ensures null termination of name */ 109338414Smckusick more_dirs = fxdr_unsigned(int, *p); 109438414Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 109538414Smckusick siz += dp->d_reclen; 109638414Smckusick } 109738414Smckusick /* 109838414Smckusick * If at end of rpc data, get the eof boolean 109938414Smckusick */ 110039495Smckusick if (!more_dirs) 110138414Smckusick nfsm_disecton(p, u_long *, NFSX_UNSIGNED); 110238414Smckusick /* 110338414Smckusick * If there is too much to fit in the data buffer, use savoff and 110438414Smckusick * savdp to trim off the last record. 110538414Smckusick * --> we are not at eof 110638414Smckusick */ 110738414Smckusick if (siz > uiop->uio_resid) { 110838414Smckusick off = savoff; 110938414Smckusick siz -= dp->d_reclen; 111038414Smckusick dp = savdp; 111138414Smckusick } 111238414Smckusick if (siz > 0) { 111338414Smckusick md = md2; 111438414Smckusick dpos = dpos2; 111538414Smckusick nfsm_mtouio(uiop, siz); 111639587Smckusick uiop->uio_offset = off; 111738414Smckusick } 111838414Smckusick nfsm_reqdone; 111938414Smckusick return (error); 112038414Smckusick } 112138414Smckusick 112238414Smckusick /* 112338414Smckusick * nfs statfs call 112438414Smckusick * (Actually a vfsop, not a vnode op) 112538414Smckusick */ 112638414Smckusick nfs_statfs(mp, sbp) 112738414Smckusick struct mount *mp; 112838414Smckusick register struct statfs *sbp; 112938414Smckusick { 113039488Smckusick register struct vnode *vp; 113138884Smacklem register struct nfsv2_statfs *sfp; 113239488Smckusick register caddr_t cp; 113339488Smckusick register long t1; 113439488Smckusick caddr_t bpos, dpos, cp2; 113539488Smckusick u_long xid; 113639488Smckusick int error = 0; 113739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 113838884Smacklem struct nfsmount *nmp; 113938414Smckusick struct ucred *cred; 114038414Smckusick struct nfsnode *np; 114138414Smckusick 114238414Smckusick nmp = vfs_to_nfs(mp); 114338414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 114438414Smckusick return (error); 114538414Smckusick vp = NFSTOV(np); 114638414Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 114738414Smckusick cred = crget(); 114838414Smckusick cred->cr_ngroups = 1; 114938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 115038414Smckusick nfsm_fhtom(vp); 115140112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_STATFS]); 115238884Smacklem nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 115338414Smckusick sbp->f_type = MOUNT_NFS; 115439751Smckusick sbp->f_flags = nmp->nm_flag; 115538884Smacklem sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 115638884Smacklem sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 115738884Smacklem sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 115838884Smacklem sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 115938884Smacklem sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 116038739Smckusick sbp->f_files = 0; 116138739Smckusick sbp->f_ffree = 0; 116239751Smckusick sbp->f_fsid.val[0] = mp->m_fsid.val[0]; 116339751Smckusick sbp->f_fsid.val[1] = mp->m_fsid.val[1]; 116438414Smckusick bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN); 116538414Smckusick bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN); 116638414Smckusick nfsm_reqdone; 116738414Smckusick nfs_nput(vp); 116838414Smckusick crfree(cred); 116938414Smckusick return (error); 117038414Smckusick } 117138414Smckusick 117239488Smckusick static char hextoasc[] = "0123456789abcdef"; 117338414Smckusick 117438414Smckusick /* 117538414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 117638414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 117738414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 117838414Smckusick * nfsnode. There is the potential for another process on a different client 117938414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 118038414Smckusick * nfs_rename() completes, but... 118138414Smckusick */ 118238414Smckusick nfs_sillyrename(ndp, flag) 118339488Smckusick register struct nameidata *ndp; 118438414Smckusick int flag; 118538414Smckusick { 118638414Smckusick register struct nfsnode *np; 118738414Smckusick register struct sillyrename *sp; 118838414Smckusick register struct nameidata *tndp; 118938414Smckusick int error; 119038414Smckusick short pid; 119138414Smckusick 119238414Smckusick np = VTONFS(ndp->ni_dvp); 119339341Smckusick cache_purge(ndp->ni_dvp); 119438414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 119538884Smacklem M_TEMP, M_WAITOK); 119638414Smckusick sp->s_flag = flag; 119738414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 119838414Smckusick np = VTONFS(ndp->ni_vp); 119938414Smckusick tndp = &sp->s_namei; 120038414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 120138414Smckusick 120238414Smckusick /* Fudge together a funny name */ 120338414Smckusick pid = u.u_procp->p_pid; 120438414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 120538414Smckusick tndp->ni_dent.d_namlen = 12; 120639488Smckusick tndp->ni_dent.d_name[8] = hextoasc[pid & 0xf]; 120739488Smckusick tndp->ni_dent.d_name[7] = hextoasc[(pid >> 4) & 0xf]; 120839488Smckusick tndp->ni_dent.d_name[6] = hextoasc[(pid >> 8) & 0xf]; 120939488Smckusick tndp->ni_dent.d_name[5] = hextoasc[(pid >> 12) & 0xf]; 121038414Smckusick 121138414Smckusick /* Try lookitups until we get one that isn't there */ 121238414Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) { 121338414Smckusick tndp->ni_dent.d_name[4]++; 121438414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 121538414Smckusick error = EINVAL; 121638414Smckusick goto bad; 121738414Smckusick } 121838414Smckusick } 121938414Smckusick if (error = nfs_renameit(ndp, tndp)) 122038414Smckusick goto bad; 122138414Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh); 122238414Smckusick np->n_sillyrename = sp; 122338414Smckusick return (0); 122438414Smckusick bad: 122538884Smacklem crfree(tndp->ni_cred); 122638414Smckusick free((caddr_t)sp, M_TEMP); 122738414Smckusick return (error); 122838414Smckusick } 122938414Smckusick 123038414Smckusick /* 123138414Smckusick * Look up a file name for silly rename stuff. 123238414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 123338414Smckusick * into the nfsnode table. 123438414Smckusick * If fhp != NULL it copies the returned file handle out 123538414Smckusick */ 123638414Smckusick nfs_lookitup(vp, ndp, fhp) 123738414Smckusick register struct vnode *vp; 123838414Smckusick register struct nameidata *ndp; 123938414Smckusick nfsv2fh_t *fhp; 124038414Smckusick { 124139488Smckusick register u_long *p; 124239488Smckusick register caddr_t cp; 124339488Smckusick register long t1, t2; 124439488Smckusick caddr_t bpos, dpos, cp2; 124539488Smckusick u_long xid; 124639488Smckusick int error = 0; 124739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 124838414Smckusick long len; 124938414Smckusick 125038414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 125138414Smckusick ndp->ni_dvp = vp; 125238414Smckusick ndp->ni_vp = NULL; 125338414Smckusick len = ndp->ni_dent.d_namlen; 125438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 125538414Smckusick nfsm_fhtom(vp); 125638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 125740112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]); 125838414Smckusick if (fhp != NULL) { 125938414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 126038414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 126138414Smckusick } 126238414Smckusick nfsm_reqdone; 126338414Smckusick return (error); 126438414Smckusick } 126538414Smckusick 126638414Smckusick /* 126738414Smckusick * Kludge City.. 126838414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 126938414Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit 127038414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 127138414Smckusick * nfsiobuf area. 127238414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 127338414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 127438414Smckusick * a lot more work than bcopy() and also it currently happens in the 127538414Smckusick * context of the swapper process (2). 127638414Smckusick */ 127738414Smckusick nfs_bmap(vp, bn, vpp, bnp) 127838414Smckusick struct vnode *vp; 127938414Smckusick daddr_t bn; 128038414Smckusick struct vnode **vpp; 128138414Smckusick daddr_t *bnp; 128238414Smckusick { 128338414Smckusick if (vpp != NULL) 128438414Smckusick *vpp = vp; 128538414Smckusick if (bnp != NULL) 128638414Smckusick *bnp = bn * btodb(vp->v_mount->m_bsize); 128738414Smckusick return (0); 128838414Smckusick } 128938414Smckusick 129038414Smckusick /* 129138884Smacklem * Strategy routine for phys. i/o 129238884Smacklem * If the biod's are running, queue a request 129338884Smacklem * otherwise just call nfs_doio() to get it done 129438414Smckusick */ 129538414Smckusick nfs_strategy(bp) 129638414Smckusick register struct buf *bp; 129738414Smckusick { 129838884Smacklem register struct buf *dp; 129939341Smckusick register int i; 130038884Smacklem struct proc *rp; 130138884Smacklem int error = 0; 130239341Smckusick int fnd = 0; 130338884Smacklem 130438884Smacklem /* 130538884Smacklem * If an i/o daemon is waiting 130638884Smacklem * queue the request, wake it up and wait for completion 130738884Smacklem * otherwise just do it ourselves 130838884Smacklem */ 130939341Smckusick for (i = 0; i < nfs_asyncdaemons; i++) { 131039341Smckusick if (rp = nfs_iodwant[i]) { 131139341Smckusick /* 131239341Smckusick * Ensure that the async_daemon is still waiting here 131339341Smckusick */ 131439341Smckusick if (rp->p_stat != SSLEEP || 131539341Smckusick rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) { 131639341Smckusick nfs_iodwant[i] = (struct proc *)0; 131739341Smckusick continue; 131839341Smckusick } 131939341Smckusick dp = &nfs_bqueue; 132039341Smckusick if (dp->b_actf == NULL) { 132139341Smckusick dp->b_actl = bp; 132239341Smckusick bp->b_actf = dp; 132339341Smckusick } else { 132439341Smckusick dp->b_actf->b_actl = bp; 132539341Smckusick bp->b_actf = dp->b_actf; 132639341Smckusick } 132739341Smckusick dp->b_actf = bp; 132839341Smckusick bp->b_actl = dp; 132939341Smckusick fnd++; 133039341Smckusick nfs_iodwant[i] = (struct proc *)0; 133139341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 133239341Smckusick break; 133338884Smacklem } 133439341Smckusick } 133539341Smckusick if (!fnd) 133638884Smacklem error = nfs_doio(bp); 133738884Smacklem return (error); 133838884Smacklem } 133938884Smacklem 134038884Smacklem /* 134138884Smacklem * Fun and games with i/o 134238884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 134338884Smacklem * mapping the data buffer into kernel virtual space and doing the 134438884Smacklem * nfs read or write rpc's from it. 134538884Smacklem * If the biod's are not running, this is just called from nfs_strategy(), 134638884Smacklem * otherwise it is called by the biod's to do what would normally be 134738884Smacklem * partially disk interrupt driven. 134838884Smacklem */ 134938884Smacklem nfs_doio(bp) 135038884Smacklem register struct buf *bp; 135138884Smacklem { 135238414Smckusick register struct pte *pte, *ppte; 135338414Smckusick register caddr_t vaddr; 135438414Smckusick register struct uio *uiop; 135538414Smckusick register struct vnode *vp; 135639341Smckusick struct nfsnode *np; 135738884Smacklem struct ucred *cr; 135838884Smacklem int npf, npf2; 135938884Smacklem int reg; 136038884Smacklem caddr_t vbase; 136138414Smckusick unsigned v; 136238414Smckusick struct proc *rp; 136338414Smckusick int o, error; 136438414Smckusick struct uio uio; 136538414Smckusick struct iovec io; 136638414Smckusick 136738414Smckusick vp = bp->b_vp; 136838414Smckusick uiop = &uio; 136938414Smckusick uiop->uio_iov = &io; 137038414Smckusick uiop->uio_iovcnt = 1; 137138414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 137239751Smckusick 137338414Smckusick /* 137438884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 137538884Smacklem * the Nfsiomap pte's 137638884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 137738884Smacklem * and a guess at a group 137838414Smckusick */ 137938884Smacklem if (bp->b_flags & B_PHYS) { 138039341Smckusick VTONFS(vp)->n_flag |= NPAGEDON; 138138884Smacklem bp->b_rcred = cr = crget(); 138238884Smacklem rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc; 138338884Smacklem cr->cr_uid = rp->p_uid; 138438884Smacklem cr->cr_gid = 0; /* Anything ?? */ 138538884Smacklem cr->cr_ngroups = 1; 138639751Smckusick o = (int)bp->b_un.b_addr & PGOFSET; 138739751Smckusick npf2 = npf = btoc(bp->b_bcount + o); 138839751Smckusick 138938884Smacklem /* 139038884Smacklem * Get some mapping page table entries 139138884Smacklem */ 139238884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 139338884Smacklem nfsmap_want++; 139438884Smacklem sleep((caddr_t)&nfsmap_want, PZERO-1); 139538884Smacklem } 139638884Smacklem reg--; 139739751Smckusick if (bp->b_flags & B_PAGET) 139839751Smckusick pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 139938884Smacklem else { 140039751Smckusick v = btop(bp->b_un.b_addr); 140138884Smacklem if (bp->b_flags & B_UAREA) 140238884Smacklem pte = &rp->p_addr[v]; 140338884Smacklem else 140438884Smacklem pte = vtopte(rp, v); 140538884Smacklem } 140639751Smckusick 140738884Smacklem /* 140838884Smacklem * Play vmaccess() but with the Nfsiomap page table 140938884Smacklem */ 141038884Smacklem ppte = &Nfsiomap[reg]; 141138884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 141238884Smacklem while (npf != 0) { 141338884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 141438414Smckusick #if defined(tahoe) 141538884Smacklem mtpr(P1DC, vaddr); 141638414Smckusick #endif 141738884Smacklem ppte++; 141838884Smacklem pte++; 141938884Smacklem vaddr += NBPG; 142038884Smacklem --npf; 142138884Smacklem } 142239751Smckusick 142339751Smckusick /* 142439751Smckusick * And do the i/o rpc 142539751Smckusick */ 142638884Smacklem io.iov_base = vbase+o; 142739751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 142839823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 142939751Smckusick if (bp->b_flags & B_READ) { 143039751Smckusick uiop->uio_rw = UIO_READ; 143139751Smckusick nfsstats.read_physios++; 143239751Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred); 143339751Smckusick } else { 143439751Smckusick uiop->uio_rw = UIO_WRITE; 143539751Smckusick nfsstats.write_physios++; 143639751Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred); 143739341Smckusick } 143839751Smckusick 143939751Smckusick /* 144039751Smckusick * Finally, release pte's used by physical i/o 144139751Smckusick */ 144238884Smacklem crfree(cr); 144338884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 144438884Smacklem if (nfsmap_want) { 144538884Smacklem nfsmap_want = 0; 144638884Smacklem wakeup((caddr_t)&nfsmap_want); 144738884Smacklem } 144839751Smckusick } else { 144939751Smckusick if (bp->b_flags & B_READ) { 145039751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 145139823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 145239751Smckusick io.iov_base = bp->b_un.b_addr; 145339751Smckusick uiop->uio_rw = UIO_READ; 145439751Smckusick nfsstats.read_bios++; 145539751Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred); 145639751Smckusick } else { 145739751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 145839751Smckusick - bp->b_dirtyoff; 145939823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 146039751Smckusick + bp->b_dirtyoff; 146139751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 146239751Smckusick uiop->uio_rw = UIO_WRITE; 146339751Smckusick nfsstats.write_bios++; 146439751Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred); 146539751Smckusick if (error) { 146639751Smckusick np = VTONFS(vp); 146739751Smckusick np->n_error = error; 146839751Smckusick np->n_flag |= NWRITEERR; 146939751Smckusick } 147039751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 147139751Smckusick } 147238884Smacklem } 147339751Smckusick if (error) 147439751Smckusick bp->b_flags |= B_ERROR; 147539751Smckusick bp->b_resid = uiop->uio_resid; 147638414Smckusick biodone(bp); 147738414Smckusick return (error); 147838414Smckusick } 147938884Smacklem 148038884Smacklem /* 148138884Smacklem * Flush all the blocks associated with a vnode. 148238884Smacklem * Walk through the buffer pool and push any dirty pages 148338884Smacklem * associated with the vnode. 148438884Smacklem */ 148539488Smckusick /* ARGSUSED */ 148639587Smckusick nfs_fsync(vp, fflags, cred, waitfor) 148738884Smacklem register struct vnode *vp; 148838884Smacklem int fflags; 148938884Smacklem struct ucred *cred; 149039587Smckusick int waitfor; 149138884Smacklem { 149238884Smacklem register struct nfsnode *np = VTONFS(vp); 149339751Smckusick int error = 0; 149438884Smacklem 149538884Smacklem if (np->n_flag & NMODIFIED) { 149638884Smacklem np->n_flag &= ~NMODIFIED; 149739751Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 149838884Smacklem } 149939751Smckusick if (!error && (np->n_flag & NWRITEERR)) 150039751Smckusick error = np->n_error; 150138884Smacklem return (error); 150238884Smacklem } 150339672Smckusick 150439672Smckusick /* 150539672Smckusick * Print out the contents of an nfsnode. 150639672Smckusick */ 150739672Smckusick nfs_print(vp) 150839672Smckusick struct vnode *vp; 150939672Smckusick { 151039672Smckusick register struct nfsnode *np = VTONFS(vp); 151139672Smckusick 151239672Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x%s\n", 151339672Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid, 151439672Smckusick (np->n_flag & NLOCKED) ? " (LOCKED)" : ""); 151539914Smckusick if (np->n_lockholder == 0) 151639914Smckusick return; 151739914Smckusick printf("\towner pid %d", np->n_lockholder); 151839914Smckusick if (np->n_lockwaiter) 151939914Smckusick printf(" waiting pid %d", np->n_lockwaiter); 152039914Smckusick printf("\n"); 152139672Smckusick } 1522