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*40112Smckusick * @(#)nfs_vnops.c 7.26 (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]; 178*40112Smckusick 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); 199*40112Smckusick 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); 315*40112Smckusick 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); 365*40112Smckusick 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); 442*40112Smckusick 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); 568*40112Smckusick 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; 604*40112Smckusick 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); 648*40112Smckusick 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); 701*40112Smckusick 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); 758*40112Smckusick 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; 770*40112Smckusick if (ndp->ni_dvp == vp) 771*40112Smckusick vrele(vp); 77238414Smckusick else 773*40112Smckusick nfs_nput(ndp->ni_dvp); 774*40112Smckusick 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); 797*40112Smckusick 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); 824*40112Smckusick 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); 833*40112Smckusick /* 834*40112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 835*40112Smckusick */ 836*40112Smckusick if (error == ENOENT) 837*40112Smckusick 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); 863*40112Smckusick 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); 891*40112Smckusick 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); 897*40112Smckusick /* 898*40112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 899*40112Smckusick */ 900*40112Smckusick if (error == EEXIST) 901*40112Smckusick 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); 933*40112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 93438884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 935*40112Smckusick nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]); 93638414Smckusick nfsm_reqdone; 93738414Smckusick nfs_nput(ndp->ni_dvp); 938*40112Smckusick /* 939*40112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 940*40112Smckusick */ 941*40112Smckusick if (error == EEXIST) 942*40112Smckusick 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); 972*40112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 97338884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 974*40112Smckusick 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); 978*40112Smckusick /* 979*40112Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry. 980*40112Smckusick */ 981*40112Smckusick if (error == EEXIST) 982*40112Smckusick 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); 1010*40112Smckusick 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); 1016*40112Smckusick /* 1017*40112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 1018*40112Smckusick */ 1019*40112Smckusick if (error == ENOENT) 1020*40112Smckusick 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; 104039488Smckusick caddr_t bpos, dpos, cp2; 104139488Smckusick u_long xid; 104239488Smckusick int error = 0; 104339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 104438414Smckusick struct mbuf *md2; 104538414Smckusick caddr_t dpos2; 104638414Smckusick int siz; 104739495Smckusick int more_dirs; 104838414Smckusick off_t off, savoff; 104938414Smckusick struct direct *savdp; 105038414Smckusick 105138414Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 105238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 105338414Smckusick nfsm_fhtom(vp); 105438414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 105539587Smckusick *p++ = txdr_unsigned(uiop->uio_offset); 105638414Smckusick *p = txdr_unsigned(uiop->uio_resid); 1057*40112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_READDIR]); 105838414Smckusick siz = 0; 105938414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 106038414Smckusick more_dirs = fxdr_unsigned(int, *p); 106138414Smckusick 106238414Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 106338414Smckusick dpos2 = dpos; 106438414Smckusick md2 = md; 106538414Smckusick 106638414Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 106739488Smckusick savoff = off = 0; 106839488Smckusick savdp = dp = NULL; 106938414Smckusick while (more_dirs && siz < uiop->uio_resid) { 107038414Smckusick savoff = off; /* Hold onto offset and dp */ 107138414Smckusick savdp = dp; 107238414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 107338414Smckusick dp = (struct direct *)p; 107438414Smckusick dp->d_ino = fxdr_unsigned(u_long, *p++); 107538414Smckusick len = fxdr_unsigned(int, *p); 107638414Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 107738414Smckusick error = EBADRPC; 107838414Smckusick m_freem(mrep); 107938414Smckusick goto nfsmout; 108038414Smckusick } 108138414Smckusick dp->d_namlen = (u_short)len; 108238414Smckusick len = nfsm_rndup(len); 108338414Smckusick nfsm_adv(len); 108438414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 108538414Smckusick off = fxdr_unsigned(off_t, *p); 108638414Smckusick *p++ = 0; /* Ensures null termination of name */ 108738414Smckusick more_dirs = fxdr_unsigned(int, *p); 108838414Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 108938414Smckusick siz += dp->d_reclen; 109038414Smckusick } 109138414Smckusick /* 109238414Smckusick * If at end of rpc data, get the eof boolean 109338414Smckusick */ 109439495Smckusick if (!more_dirs) 109538414Smckusick nfsm_disecton(p, u_long *, NFSX_UNSIGNED); 109638414Smckusick /* 109738414Smckusick * If there is too much to fit in the data buffer, use savoff and 109838414Smckusick * savdp to trim off the last record. 109938414Smckusick * --> we are not at eof 110038414Smckusick */ 110138414Smckusick if (siz > uiop->uio_resid) { 110238414Smckusick off = savoff; 110338414Smckusick siz -= dp->d_reclen; 110438414Smckusick dp = savdp; 110538414Smckusick } 110638414Smckusick if (siz > 0) { 110738414Smckusick md = md2; 110838414Smckusick dpos = dpos2; 110938414Smckusick nfsm_mtouio(uiop, siz); 111039587Smckusick uiop->uio_offset = off; 111138414Smckusick } 111238414Smckusick nfsm_reqdone; 111338414Smckusick return (error); 111438414Smckusick } 111538414Smckusick 111638414Smckusick /* 111738414Smckusick * nfs statfs call 111838414Smckusick * (Actually a vfsop, not a vnode op) 111938414Smckusick */ 112038414Smckusick nfs_statfs(mp, sbp) 112138414Smckusick struct mount *mp; 112238414Smckusick register struct statfs *sbp; 112338414Smckusick { 112439488Smckusick register struct vnode *vp; 112538884Smacklem register struct nfsv2_statfs *sfp; 112639488Smckusick register caddr_t cp; 112739488Smckusick register long t1; 112839488Smckusick caddr_t bpos, dpos, cp2; 112939488Smckusick u_long xid; 113039488Smckusick int error = 0; 113139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 113238884Smacklem struct nfsmount *nmp; 113338414Smckusick struct ucred *cred; 113438414Smckusick struct nfsnode *np; 113538414Smckusick 113638414Smckusick nmp = vfs_to_nfs(mp); 113738414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 113838414Smckusick return (error); 113938414Smckusick vp = NFSTOV(np); 114038414Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 114138414Smckusick cred = crget(); 114238414Smckusick cred->cr_ngroups = 1; 114338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 114438414Smckusick nfsm_fhtom(vp); 1145*40112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_STATFS]); 114638884Smacklem nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 114738414Smckusick sbp->f_type = MOUNT_NFS; 114839751Smckusick sbp->f_flags = nmp->nm_flag; 114938884Smacklem sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 115038884Smacklem sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 115138884Smacklem sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 115238884Smacklem sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 115338884Smacklem sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 115438739Smckusick sbp->f_files = 0; 115538739Smckusick sbp->f_ffree = 0; 115639751Smckusick sbp->f_fsid.val[0] = mp->m_fsid.val[0]; 115739751Smckusick sbp->f_fsid.val[1] = mp->m_fsid.val[1]; 115838414Smckusick bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN); 115938414Smckusick bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN); 116038414Smckusick nfsm_reqdone; 116138414Smckusick nfs_nput(vp); 116238414Smckusick crfree(cred); 116338414Smckusick return (error); 116438414Smckusick } 116538414Smckusick 116639488Smckusick static char hextoasc[] = "0123456789abcdef"; 116738414Smckusick 116838414Smckusick /* 116938414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 117038414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 117138414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 117238414Smckusick * nfsnode. There is the potential for another process on a different client 117338414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 117438414Smckusick * nfs_rename() completes, but... 117538414Smckusick */ 117638414Smckusick nfs_sillyrename(ndp, flag) 117739488Smckusick register struct nameidata *ndp; 117838414Smckusick int flag; 117938414Smckusick { 118038414Smckusick register struct nfsnode *np; 118138414Smckusick register struct sillyrename *sp; 118238414Smckusick register struct nameidata *tndp; 118338414Smckusick int error; 118438414Smckusick short pid; 118538414Smckusick 118638414Smckusick np = VTONFS(ndp->ni_dvp); 118739341Smckusick cache_purge(ndp->ni_dvp); 118838414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 118938884Smacklem M_TEMP, M_WAITOK); 119038414Smckusick sp->s_flag = flag; 119138414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 119238414Smckusick np = VTONFS(ndp->ni_vp); 119338414Smckusick tndp = &sp->s_namei; 119438414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 119538414Smckusick 119638414Smckusick /* Fudge together a funny name */ 119738414Smckusick pid = u.u_procp->p_pid; 119838414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 119938414Smckusick tndp->ni_dent.d_namlen = 12; 120039488Smckusick tndp->ni_dent.d_name[8] = hextoasc[pid & 0xf]; 120139488Smckusick tndp->ni_dent.d_name[7] = hextoasc[(pid >> 4) & 0xf]; 120239488Smckusick tndp->ni_dent.d_name[6] = hextoasc[(pid >> 8) & 0xf]; 120339488Smckusick tndp->ni_dent.d_name[5] = hextoasc[(pid >> 12) & 0xf]; 120438414Smckusick 120538414Smckusick /* Try lookitups until we get one that isn't there */ 120638414Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) { 120738414Smckusick tndp->ni_dent.d_name[4]++; 120838414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 120938414Smckusick error = EINVAL; 121038414Smckusick goto bad; 121138414Smckusick } 121238414Smckusick } 121338414Smckusick if (error = nfs_renameit(ndp, tndp)) 121438414Smckusick goto bad; 121538414Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh); 121638414Smckusick np->n_sillyrename = sp; 121738414Smckusick return (0); 121838414Smckusick bad: 121938884Smacklem crfree(tndp->ni_cred); 122038414Smckusick free((caddr_t)sp, M_TEMP); 122138414Smckusick return (error); 122238414Smckusick } 122338414Smckusick 122438414Smckusick /* 122538414Smckusick * Look up a file name for silly rename stuff. 122638414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 122738414Smckusick * into the nfsnode table. 122838414Smckusick * If fhp != NULL it copies the returned file handle out 122938414Smckusick */ 123038414Smckusick nfs_lookitup(vp, ndp, fhp) 123138414Smckusick register struct vnode *vp; 123238414Smckusick register struct nameidata *ndp; 123338414Smckusick nfsv2fh_t *fhp; 123438414Smckusick { 123539488Smckusick register u_long *p; 123639488Smckusick register caddr_t cp; 123739488Smckusick register long t1, t2; 123839488Smckusick caddr_t bpos, dpos, cp2; 123939488Smckusick u_long xid; 124039488Smckusick int error = 0; 124139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 124238414Smckusick long len; 124338414Smckusick 124438414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 124538414Smckusick ndp->ni_dvp = vp; 124638414Smckusick ndp->ni_vp = NULL; 124738414Smckusick len = ndp->ni_dent.d_namlen; 124838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 124938414Smckusick nfsm_fhtom(vp); 125038414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 1251*40112Smckusick nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]); 125238414Smckusick if (fhp != NULL) { 125338414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 125438414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 125538414Smckusick } 125638414Smckusick nfsm_reqdone; 125738414Smckusick return (error); 125838414Smckusick } 125938414Smckusick 126038414Smckusick /* 126138414Smckusick * Kludge City.. 126238414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 126338414Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit 126438414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 126538414Smckusick * nfsiobuf area. 126638414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 126738414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 126838414Smckusick * a lot more work than bcopy() and also it currently happens in the 126938414Smckusick * context of the swapper process (2). 127038414Smckusick */ 127138414Smckusick nfs_bmap(vp, bn, vpp, bnp) 127238414Smckusick struct vnode *vp; 127338414Smckusick daddr_t bn; 127438414Smckusick struct vnode **vpp; 127538414Smckusick daddr_t *bnp; 127638414Smckusick { 127738414Smckusick if (vpp != NULL) 127838414Smckusick *vpp = vp; 127938414Smckusick if (bnp != NULL) 128038414Smckusick *bnp = bn * btodb(vp->v_mount->m_bsize); 128138414Smckusick return (0); 128238414Smckusick } 128338414Smckusick 128438414Smckusick /* 128538884Smacklem * Strategy routine for phys. i/o 128638884Smacklem * If the biod's are running, queue a request 128738884Smacklem * otherwise just call nfs_doio() to get it done 128838414Smckusick */ 128938414Smckusick nfs_strategy(bp) 129038414Smckusick register struct buf *bp; 129138414Smckusick { 129238884Smacklem register struct buf *dp; 129339341Smckusick register int i; 129438884Smacklem struct proc *rp; 129538884Smacklem int error = 0; 129639341Smckusick int fnd = 0; 129738884Smacklem 129838884Smacklem /* 129938884Smacklem * If an i/o daemon is waiting 130038884Smacklem * queue the request, wake it up and wait for completion 130138884Smacklem * otherwise just do it ourselves 130238884Smacklem */ 130339341Smckusick for (i = 0; i < nfs_asyncdaemons; i++) { 130439341Smckusick if (rp = nfs_iodwant[i]) { 130539341Smckusick /* 130639341Smckusick * Ensure that the async_daemon is still waiting here 130739341Smckusick */ 130839341Smckusick if (rp->p_stat != SSLEEP || 130939341Smckusick rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) { 131039341Smckusick nfs_iodwant[i] = (struct proc *)0; 131139341Smckusick continue; 131239341Smckusick } 131339341Smckusick dp = &nfs_bqueue; 131439341Smckusick if (dp->b_actf == NULL) { 131539341Smckusick dp->b_actl = bp; 131639341Smckusick bp->b_actf = dp; 131739341Smckusick } else { 131839341Smckusick dp->b_actf->b_actl = bp; 131939341Smckusick bp->b_actf = dp->b_actf; 132039341Smckusick } 132139341Smckusick dp->b_actf = bp; 132239341Smckusick bp->b_actl = dp; 132339341Smckusick fnd++; 132439341Smckusick nfs_iodwant[i] = (struct proc *)0; 132539341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 132639341Smckusick break; 132738884Smacklem } 132839341Smckusick } 132939341Smckusick if (!fnd) 133038884Smacklem error = nfs_doio(bp); 133138884Smacklem return (error); 133238884Smacklem } 133338884Smacklem 133438884Smacklem /* 133538884Smacklem * Fun and games with i/o 133638884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 133738884Smacklem * mapping the data buffer into kernel virtual space and doing the 133838884Smacklem * nfs read or write rpc's from it. 133938884Smacklem * If the biod's are not running, this is just called from nfs_strategy(), 134038884Smacklem * otherwise it is called by the biod's to do what would normally be 134138884Smacklem * partially disk interrupt driven. 134238884Smacklem */ 134338884Smacklem nfs_doio(bp) 134438884Smacklem register struct buf *bp; 134538884Smacklem { 134638414Smckusick register struct pte *pte, *ppte; 134738414Smckusick register caddr_t vaddr; 134838414Smckusick register struct uio *uiop; 134938414Smckusick register struct vnode *vp; 135039341Smckusick struct nfsnode *np; 135138884Smacklem struct ucred *cr; 135238884Smacklem int npf, npf2; 135338884Smacklem int reg; 135438884Smacklem caddr_t vbase; 135538414Smckusick unsigned v; 135638414Smckusick struct proc *rp; 135738414Smckusick int o, error; 135838414Smckusick struct uio uio; 135938414Smckusick struct iovec io; 136038414Smckusick 136138414Smckusick vp = bp->b_vp; 136238414Smckusick uiop = &uio; 136338414Smckusick uiop->uio_iov = &io; 136438414Smckusick uiop->uio_iovcnt = 1; 136538414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 136639751Smckusick 136738414Smckusick /* 136838884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 136938884Smacklem * the Nfsiomap pte's 137038884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 137138884Smacklem * and a guess at a group 137238414Smckusick */ 137338884Smacklem if (bp->b_flags & B_PHYS) { 137439341Smckusick VTONFS(vp)->n_flag |= NPAGEDON; 137538884Smacklem bp->b_rcred = cr = crget(); 137638884Smacklem rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc; 137738884Smacklem cr->cr_uid = rp->p_uid; 137838884Smacklem cr->cr_gid = 0; /* Anything ?? */ 137938884Smacklem cr->cr_ngroups = 1; 138039751Smckusick o = (int)bp->b_un.b_addr & PGOFSET; 138139751Smckusick npf2 = npf = btoc(bp->b_bcount + o); 138239751Smckusick 138338884Smacklem /* 138438884Smacklem * Get some mapping page table entries 138538884Smacklem */ 138638884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 138738884Smacklem nfsmap_want++; 138838884Smacklem sleep((caddr_t)&nfsmap_want, PZERO-1); 138938884Smacklem } 139038884Smacklem reg--; 139139751Smckusick if (bp->b_flags & B_PAGET) 139239751Smckusick pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 139338884Smacklem else { 139439751Smckusick v = btop(bp->b_un.b_addr); 139538884Smacklem if (bp->b_flags & B_UAREA) 139638884Smacklem pte = &rp->p_addr[v]; 139738884Smacklem else 139838884Smacklem pte = vtopte(rp, v); 139938884Smacklem } 140039751Smckusick 140138884Smacklem /* 140238884Smacklem * Play vmaccess() but with the Nfsiomap page table 140338884Smacklem */ 140438884Smacklem ppte = &Nfsiomap[reg]; 140538884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 140638884Smacklem while (npf != 0) { 140738884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 140838414Smckusick #if defined(tahoe) 140938884Smacklem mtpr(P1DC, vaddr); 141038414Smckusick #endif 141138884Smacklem ppte++; 141238884Smacklem pte++; 141338884Smacklem vaddr += NBPG; 141438884Smacklem --npf; 141538884Smacklem } 141639751Smckusick 141739751Smckusick /* 141839751Smckusick * And do the i/o rpc 141939751Smckusick */ 142038884Smacklem io.iov_base = vbase+o; 142139751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 142239823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 142339751Smckusick if (bp->b_flags & B_READ) { 142439751Smckusick uiop->uio_rw = UIO_READ; 142539751Smckusick nfsstats.read_physios++; 142639751Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred); 142739751Smckusick } else { 142839751Smckusick uiop->uio_rw = UIO_WRITE; 142939751Smckusick nfsstats.write_physios++; 143039751Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred); 143139341Smckusick } 143239751Smckusick 143339751Smckusick /* 143439751Smckusick * Finally, release pte's used by physical i/o 143539751Smckusick */ 143638884Smacklem crfree(cr); 143738884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 143838884Smacklem if (nfsmap_want) { 143938884Smacklem nfsmap_want = 0; 144038884Smacklem wakeup((caddr_t)&nfsmap_want); 144138884Smacklem } 144239751Smckusick } else { 144339751Smckusick if (bp->b_flags & B_READ) { 144439751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 144539823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 144639751Smckusick io.iov_base = bp->b_un.b_addr; 144739751Smckusick uiop->uio_rw = UIO_READ; 144839751Smckusick nfsstats.read_bios++; 144939751Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred); 145039751Smckusick } else { 145139751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 145239751Smckusick - bp->b_dirtyoff; 145339823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 145439751Smckusick + bp->b_dirtyoff; 145539751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 145639751Smckusick uiop->uio_rw = UIO_WRITE; 145739751Smckusick nfsstats.write_bios++; 145839751Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred); 145939751Smckusick if (error) { 146039751Smckusick np = VTONFS(vp); 146139751Smckusick np->n_error = error; 146239751Smckusick np->n_flag |= NWRITEERR; 146339751Smckusick } 146439751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 146539751Smckusick } 146638884Smacklem } 146739751Smckusick if (error) 146839751Smckusick bp->b_flags |= B_ERROR; 146939751Smckusick bp->b_resid = uiop->uio_resid; 147038414Smckusick biodone(bp); 147138414Smckusick return (error); 147238414Smckusick } 147338884Smacklem 147438884Smacklem /* 147538884Smacklem * Flush all the blocks associated with a vnode. 147638884Smacklem * Walk through the buffer pool and push any dirty pages 147738884Smacklem * associated with the vnode. 147838884Smacklem */ 147939488Smckusick /* ARGSUSED */ 148039587Smckusick nfs_fsync(vp, fflags, cred, waitfor) 148138884Smacklem register struct vnode *vp; 148238884Smacklem int fflags; 148338884Smacklem struct ucred *cred; 148439587Smckusick int waitfor; 148538884Smacklem { 148638884Smacklem register struct nfsnode *np = VTONFS(vp); 148739751Smckusick int error = 0; 148838884Smacklem 148938884Smacklem if (np->n_flag & NMODIFIED) { 149038884Smacklem np->n_flag &= ~NMODIFIED; 149139751Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 149238884Smacklem } 149339751Smckusick if (!error && (np->n_flag & NWRITEERR)) 149439751Smckusick error = np->n_error; 149538884Smacklem return (error); 149638884Smacklem } 149739672Smckusick 149839672Smckusick /* 149939672Smckusick * Print out the contents of an nfsnode. 150039672Smckusick */ 150139672Smckusick nfs_print(vp) 150239672Smckusick struct vnode *vp; 150339672Smckusick { 150439672Smckusick register struct nfsnode *np = VTONFS(vp); 150539672Smckusick 150639672Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x%s\n", 150739672Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid, 150839672Smckusick (np->n_flag & NLOCKED) ? " (LOCKED)" : ""); 150939914Smckusick if (np->n_lockholder == 0) 151039914Smckusick return; 151139914Smckusick printf("\towner pid %d", np->n_lockholder); 151239914Smckusick if (np->n_lockwaiter) 151339914Smckusick printf(" waiting pid %d", np->n_lockwaiter); 151439914Smckusick printf("\n"); 151539672Smckusick } 1516