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 * 844514Sbostic * %sccs.include.redist.c% 938414Smckusick * 10*48054Smckusick * @(#)nfs_vnops.c 7.57 (Berkeley) 04/16/91 1138414Smckusick */ 1238414Smckusick 1338414Smckusick /* 1438414Smckusick * vnode op calls for sun nfs version 2 1538414Smckusick */ 1638414Smckusick 1738414Smckusick #include "param.h" 1838414Smckusick #include "proc.h" 1940296Smckusick #include "kernel.h" 2046981Skarels #include "systm.h" 2138414Smckusick #include "mount.h" 2238414Smckusick #include "buf.h" 2338414Smckusick #include "malloc.h" 2438414Smckusick #include "mbuf.h" 2538414Smckusick #include "conf.h" 26*48054Smckusick #include "namei.h" 2738414Smckusick #include "vnode.h" 28*48054Smckusick #include "specdev.h" 29*48054Smckusick #include "fifo.h" 3038884Smacklem #include "map.h" 3147573Skarels 3242246Smckusick #include "../ufs/quota.h" 3342246Smckusick #include "../ufs/inode.h" 3447573Skarels 3538414Smckusick #include "nfsv2.h" 3638414Smckusick #include "nfs.h" 3738414Smckusick #include "nfsnode.h" 3838414Smckusick #include "nfsmount.h" 3938414Smckusick #include "xdr_subs.h" 4038414Smckusick #include "nfsm_subs.h" 4138884Smacklem #include "nfsiom.h" 4238414Smckusick 4347573Skarels #include "machine/mtpr.h" 4447573Skarels 4538414Smckusick /* Defs */ 4638414Smckusick #define TRUE 1 4738414Smckusick #define FALSE 0 4838414Smckusick 49*48054Smckusick /* 50*48054Smckusick * Global vfs data structures for nfs 51*48054Smckusick */ 5238414Smckusick struct vnodeops nfsv2_vnodeops = { 5339672Smckusick nfs_lookup, /* lookup */ 5439672Smckusick nfs_create, /* create */ 5539672Smckusick nfs_mknod, /* mknod */ 5639672Smckusick nfs_open, /* open */ 5739672Smckusick nfs_close, /* close */ 5839672Smckusick nfs_access, /* access */ 5939672Smckusick nfs_getattr, /* getattr */ 6039672Smckusick nfs_setattr, /* setattr */ 6139672Smckusick nfs_read, /* read */ 6239672Smckusick nfs_write, /* write */ 63*48054Smckusick nfs_ioctl, /* ioctl */ 64*48054Smckusick nfs_select, /* select */ 65*48054Smckusick nfs_mmap, /* mmap */ 6639672Smckusick nfs_fsync, /* fsync */ 67*48054Smckusick nfs_seek, /* seek */ 6839672Smckusick nfs_remove, /* remove */ 6939672Smckusick nfs_link, /* link */ 7039672Smckusick nfs_rename, /* rename */ 7139672Smckusick nfs_mkdir, /* mkdir */ 7239672Smckusick nfs_rmdir, /* rmdir */ 7339672Smckusick nfs_symlink, /* symlink */ 7439672Smckusick nfs_readdir, /* readdir */ 7539672Smckusick nfs_readlink, /* readlink */ 7639672Smckusick nfs_abortop, /* abortop */ 7739672Smckusick nfs_inactive, /* inactive */ 7839672Smckusick nfs_reclaim, /* reclaim */ 7939672Smckusick nfs_lock, /* lock */ 8039672Smckusick nfs_unlock, /* unlock */ 8139672Smckusick nfs_bmap, /* bmap */ 8239672Smckusick nfs_strategy, /* strategy */ 8339672Smckusick nfs_print, /* print */ 8439906Smckusick nfs_islocked, /* islocked */ 8546201Smckusick nfs_advlock, /* advlock */ 8638414Smckusick }; 8738414Smckusick 88*48054Smckusick /* 89*48054Smckusick * Special device vnode ops 90*48054Smckusick */ 9139441Smckusick struct vnodeops spec_nfsv2nodeops = { 9239599Smckusick spec_lookup, /* lookup */ 93*48054Smckusick spec_create, /* create */ 94*48054Smckusick spec_mknod, /* mknod */ 9539599Smckusick spec_open, /* open */ 9639599Smckusick spec_close, /* close */ 9739599Smckusick nfs_access, /* access */ 9839599Smckusick nfs_getattr, /* getattr */ 9939599Smckusick nfs_setattr, /* setattr */ 10039599Smckusick spec_read, /* read */ 10139599Smckusick spec_write, /* write */ 10239599Smckusick spec_ioctl, /* ioctl */ 10339599Smckusick spec_select, /* select */ 104*48054Smckusick spec_mmap, /* mmap */ 105*48054Smckusick spec_fsync, /* fsync */ 106*48054Smckusick spec_seek, /* seek */ 107*48054Smckusick spec_remove, /* remove */ 108*48054Smckusick spec_link, /* link */ 109*48054Smckusick spec_rename, /* rename */ 110*48054Smckusick spec_mkdir, /* mkdir */ 111*48054Smckusick spec_rmdir, /* rmdir */ 112*48054Smckusick spec_symlink, /* symlink */ 113*48054Smckusick spec_readdir, /* readdir */ 114*48054Smckusick spec_readlink, /* readlink */ 115*48054Smckusick spec_abortop, /* abortop */ 11639599Smckusick nfs_inactive, /* inactive */ 11739599Smckusick nfs_reclaim, /* reclaim */ 11839599Smckusick nfs_lock, /* lock */ 11939599Smckusick nfs_unlock, /* unlock */ 12039672Smckusick spec_bmap, /* bmap */ 12139599Smckusick spec_strategy, /* strategy */ 12239672Smckusick nfs_print, /* print */ 12339906Smckusick nfs_islocked, /* islocked */ 12446201Smckusick spec_advlock, /* advlock */ 12538414Smckusick }; 12638414Smckusick 12740294Smckusick #ifdef FIFO 12840294Smckusick struct vnodeops fifo_nfsv2nodeops = { 12940294Smckusick fifo_lookup, /* lookup */ 130*48054Smckusick fifo_create, /* create */ 131*48054Smckusick fifo_mknod, /* mknod */ 13240294Smckusick fifo_open, /* open */ 13340294Smckusick fifo_close, /* close */ 13440294Smckusick nfs_access, /* access */ 13540294Smckusick nfs_getattr, /* getattr */ 13640294Smckusick nfs_setattr, /* setattr */ 13740294Smckusick fifo_read, /* read */ 13840294Smckusick fifo_write, /* write */ 13940294Smckusick fifo_ioctl, /* ioctl */ 14040294Smckusick fifo_select, /* select */ 141*48054Smckusick fifo_mmap, /* mmap */ 142*48054Smckusick fifo_fsync, /* fsync */ 143*48054Smckusick fifo_seek, /* seek */ 144*48054Smckusick fifo_remove, /* remove */ 145*48054Smckusick fifo_link, /* link */ 146*48054Smckusick fifo_rename, /* rename */ 147*48054Smckusick fifo_mkdir, /* mkdir */ 148*48054Smckusick fifo_rmdir, /* rmdir */ 149*48054Smckusick fifo_symlink, /* symlink */ 150*48054Smckusick fifo_readdir, /* readdir */ 151*48054Smckusick fifo_readlink, /* readlink */ 152*48054Smckusick fifo_abortop, /* abortop */ 15340294Smckusick nfs_inactive, /* inactive */ 15440294Smckusick nfs_reclaim, /* reclaim */ 15540294Smckusick nfs_lock, /* lock */ 15640294Smckusick nfs_unlock, /* unlock */ 15740294Smckusick fifo_bmap, /* bmap */ 15840294Smckusick fifo_badop, /* strategy */ 15940294Smckusick nfs_print, /* print */ 16040294Smckusick nfs_islocked, /* islocked */ 16146201Smckusick fifo_advlock, /* advlock */ 16240294Smckusick }; 16340294Smckusick #endif /* FIFO */ 16440294Smckusick 165*48054Smckusick /* 166*48054Smckusick * Global vars 167*48054Smckusick */ 16838414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 16938414Smckusick extern u_long nfs_prog, nfs_vers; 17038414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 17138884Smacklem struct map nfsmap[NFS_MSIZ]; 17238884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 17341905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 17446988Smckusick int nfs_numasync = 0; 17538884Smacklem static int nfsmap_want = 0; 17638414Smckusick 17738414Smckusick /* 17838414Smckusick * nfs null call from vfs. 17938414Smckusick */ 180*48054Smckusick nfs_null(vp, cred, p) 18138414Smckusick struct vnode *vp; 18238414Smckusick struct ucred *cred; 183*48054Smckusick struct proc *p; 18438414Smckusick { 18539488Smckusick caddr_t bpos, dpos; 18639488Smckusick u_long xid; 18739488Smckusick int error = 0; 18839488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 18938414Smckusick 19038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 191*48054Smckusick nfsm_request(vp, NFSPROC_NULL, p, 0); 19238414Smckusick nfsm_reqdone; 19338414Smckusick return (error); 19438414Smckusick } 19538414Smckusick 19638414Smckusick /* 19738414Smckusick * nfs access vnode op. 19838414Smckusick * Essentially just get vattr and then imitate iaccess() 19938414Smckusick */ 200*48054Smckusick nfs_access(vp, mode, cred, p) 20138414Smckusick struct vnode *vp; 20238414Smckusick int mode; 20338414Smckusick register struct ucred *cred; 204*48054Smckusick struct proc *p; 20538414Smckusick { 20638414Smckusick register struct vattr *vap; 20738414Smckusick register gid_t *gp; 20838414Smckusick struct vattr vattr; 20938414Smckusick register int i; 21038414Smckusick int error; 21138414Smckusick 21238414Smckusick /* 21338414Smckusick * If you're the super-user, 21438414Smckusick * you always get access. 21538414Smckusick */ 21638414Smckusick if (cred->cr_uid == 0) 21738414Smckusick return (0); 21838414Smckusick vap = &vattr; 219*48054Smckusick if (error = nfs_dogetattr(vp, vap, cred, 0, p)) 22038884Smacklem return (error); 22138414Smckusick /* 22238414Smckusick * Access check is based on only one of owner, group, public. 22338414Smckusick * If not owner, then check group. If not a member of the 22438414Smckusick * group, then check public access. 22538414Smckusick */ 22638414Smckusick if (cred->cr_uid != vap->va_uid) { 22738414Smckusick mode >>= 3; 22838414Smckusick gp = cred->cr_groups; 22938414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 23038414Smckusick if (vap->va_gid == *gp) 23138414Smckusick goto found; 23238414Smckusick mode >>= 3; 23338414Smckusick found: 23438414Smckusick ; 23538414Smckusick } 23638414Smckusick if ((vap->va_mode & mode) != 0) 23738414Smckusick return (0); 23838414Smckusick return (EACCES); 23938414Smckusick } 24038414Smckusick 24138414Smckusick /* 24238414Smckusick * nfs open vnode op 24338414Smckusick * Just check to see if the type is ok 24438414Smckusick */ 24539488Smckusick /* ARGSUSED */ 246*48054Smckusick nfs_open(vp, mode, cred, p) 24738414Smckusick struct vnode *vp; 24838414Smckusick int mode; 24938414Smckusick struct ucred *cred; 250*48054Smckusick struct proc *p; 25138414Smckusick { 25238414Smckusick register enum vtype vtyp; 25338414Smckusick 25438414Smckusick vtyp = vp->v_type; 25538414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 25638414Smckusick return (0); 25738414Smckusick else 25838414Smckusick return (EACCES); 25938414Smckusick } 26038414Smckusick 26138414Smckusick /* 26238414Smckusick * nfs close vnode op 26338884Smacklem * For reg files, invalidate any buffer cache entries. 26438414Smckusick */ 26539488Smckusick /* ARGSUSED */ 266*48054Smckusick nfs_close(vp, fflags, cred, p) 26738414Smckusick register struct vnode *vp; 26838414Smckusick int fflags; 26938414Smckusick struct ucred *cred; 270*48054Smckusick struct proc *p; 27138414Smckusick { 27239488Smckusick register struct nfsnode *np = VTONFS(vp); 27339341Smckusick int error = 0; 27438414Smckusick 27541905Smckusick if (vp->v_type == VREG && (np->n_flag & NMODIFIED)) { 27639441Smckusick nfs_lock(vp); 27741905Smckusick np->n_flag &= ~NMODIFIED; 27839751Smckusick vinvalbuf(vp, TRUE); 27941905Smckusick np->n_attrstamp = 0; 28039341Smckusick if (np->n_flag & NWRITEERR) { 28139341Smckusick np->n_flag &= ~NWRITEERR; 28239751Smckusick error = np->n_error; 28339341Smckusick } 28439441Smckusick nfs_unlock(vp); 28538884Smacklem } 28638414Smckusick return (error); 28738414Smckusick } 28838414Smckusick 28938414Smckusick /* 29038414Smckusick * nfs getattr call from vfs. 29138414Smckusick */ 292*48054Smckusick nfs_getattr(vp, vap, cred, p) 29339488Smckusick register struct vnode *vp; 29439488Smckusick struct vattr *vap; 29538414Smckusick struct ucred *cred; 296*48054Smckusick struct proc *p; 29738414Smckusick { 298*48054Smckusick return (nfs_dogetattr(vp, vap, cred, 0, p)); 29943356Smckusick } 30043356Smckusick 301*48054Smckusick nfs_dogetattr(vp, vap, cred, tryhard, p) 30243356Smckusick register struct vnode *vp; 30343356Smckusick struct vattr *vap; 30443356Smckusick struct ucred *cred; 30543356Smckusick int tryhard; 306*48054Smckusick struct proc *p; 30743356Smckusick { 30839488Smckusick register caddr_t cp; 30939488Smckusick register long t1; 31039488Smckusick caddr_t bpos, dpos; 31139488Smckusick u_long xid; 31239488Smckusick int error = 0; 31339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 31438414Smckusick 31538414Smckusick /* First look in the cache.. */ 31638414Smckusick if (nfs_getattrcache(vp, vap) == 0) 31738414Smckusick return (0); 31838414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 31938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH); 32038414Smckusick nfsm_fhtom(vp); 321*48054Smckusick nfsm_request(vp, NFSPROC_GETATTR, p, tryhard); 32238414Smckusick nfsm_loadattr(vp, vap); 32338414Smckusick nfsm_reqdone; 32438414Smckusick return (error); 32538414Smckusick } 32638414Smckusick 32738414Smckusick /* 32838414Smckusick * nfs setattr call. 32938414Smckusick */ 330*48054Smckusick nfs_setattr(vp, vap, cred, p) 33139488Smckusick register struct vnode *vp; 33238414Smckusick register struct vattr *vap; 33338414Smckusick struct ucred *cred; 334*48054Smckusick struct proc *p; 33538414Smckusick { 33638884Smacklem register struct nfsv2_sattr *sp; 33739488Smckusick register caddr_t cp; 33839488Smckusick register long t1; 33939488Smckusick caddr_t bpos, dpos; 34039488Smckusick u_long xid; 34139488Smckusick int error = 0; 34239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 34339359Smckusick struct nfsnode *np; 34438414Smckusick 34538414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 34638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 34738414Smckusick nfsm_fhtom(vp); 34838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 34938414Smckusick if (vap->va_mode == 0xffff) 35038884Smacklem sp->sa_mode = VNOVAL; 35138414Smckusick else 35238884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 35338414Smckusick if (vap->va_uid == 0xffff) 35438884Smacklem sp->sa_uid = VNOVAL; 35538414Smckusick else 35638884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 35738414Smckusick if (vap->va_gid == 0xffff) 35838884Smacklem sp->sa_gid = VNOVAL; 35938414Smckusick else 36038884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 36138884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 36244988Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec); 36344988Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 36444988Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 36544988Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 36644988Smckusick vap->va_atime.tv_sec != VNOVAL) { 36739359Smckusick np = VTONFS(vp); 36839359Smckusick if (np->n_flag & NMODIFIED) { 36939359Smckusick np->n_flag &= ~NMODIFIED; 37046988Smckusick if (vap->va_size == 0) 37146988Smckusick vinvalbuf(vp, FALSE); 37246988Smckusick else 37346988Smckusick vinvalbuf(vp, TRUE); 37441905Smckusick np->n_attrstamp = 0; 37539359Smckusick } 37639359Smckusick } 377*48054Smckusick nfsm_request(vp, NFSPROC_SETATTR, p, 1); 37838414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 37938414Smckusick /* should we fill in any vap fields ?? */ 38038414Smckusick nfsm_reqdone; 38138414Smckusick return (error); 38238414Smckusick } 38338414Smckusick 38438414Smckusick /* 38538414Smckusick * nfs lookup call, one step at a time... 38638414Smckusick * First look in cache 38738414Smckusick * If not found, unlock the directory nfsnode and do the rpc 38838414Smckusick */ 389*48054Smckusick nfs_lookup(vp, ndp, p) 39038414Smckusick register struct vnode *vp; 39138414Smckusick register struct nameidata *ndp; 392*48054Smckusick struct proc *p; 39338414Smckusick { 39438414Smckusick register struct vnode *vdp; 395*48054Smckusick register u_long *tl; 39639488Smckusick register caddr_t cp; 39739488Smckusick register long t1, t2; 39839488Smckusick caddr_t bpos, dpos, cp2; 39939488Smckusick u_long xid; 40039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 40138414Smckusick struct vnode *newvp; 40238414Smckusick long len; 40338414Smckusick nfsv2fh_t *fhp; 40438414Smckusick struct nfsnode *np; 40539488Smckusick int lockparent, wantparent, flag, error = 0; 40638414Smckusick 40738414Smckusick ndp->ni_dvp = vp; 40838414Smckusick ndp->ni_vp = NULL; 40938414Smckusick if (vp->v_type != VDIR) 41038414Smckusick return (ENOTDIR); 41138414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 41246510Smckusick flag = ndp->ni_nameiop & OPMASK; 41338414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 41439341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 41538884Smacklem struct vattr vattr; 41638884Smacklem int vpid; 41738884Smacklem 41845920Smckusick #ifdef PARANOID 41939441Smckusick if (vp == ndp->ni_rdir && ndp->ni_isdotdot) 42039441Smckusick panic("nfs_lookup: .. through root"); 42145920Smckusick #endif 42239441Smckusick vdp = ndp->ni_vp; 42338884Smacklem vpid = vdp->v_id; 42438414Smckusick /* 42538884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 42638884Smacklem * for an explanation of the locking protocol 42738414Smckusick */ 42838414Smckusick if (vp == vdp) { 42938425Smckusick VREF(vdp); 43039441Smckusick error = 0; 43138414Smckusick } else if (ndp->ni_isdotdot) { 43238414Smckusick nfs_unlock(vp); 43339441Smckusick error = vget(vdp); 43447289Smckusick if (!error && lockparent && *ndp->ni_next == '\0') 43547289Smckusick nfs_lock(vp); 43638414Smckusick } else { 43739441Smckusick error = vget(vdp); 43847289Smckusick if (!lockparent || error || *ndp->ni_next != '\0') 43947289Smckusick nfs_unlock(vp); 44038414Smckusick } 44139441Smckusick if (!error) { 44240251Smckusick if (vpid == vdp->v_id) { 443*48054Smckusick if (!nfs_dogetattr(vdp, &vattr, ndp->ni_cred, 0, p)&& 44440251Smckusick vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) { 44539441Smckusick nfsstats.lookupcache_hits++; 44639441Smckusick return (0); 44740251Smckusick } 44847289Smckusick cache_purge(vdp); 44939441Smckusick } 45047289Smckusick nfs_nput(vdp); 45147289Smckusick if (lockparent && vdp != vp && *ndp->ni_next == '\0') 45247289Smckusick nfs_unlock(vp); 45338884Smacklem } 45441398Smckusick ndp->ni_vp = NULLVP; 45539751Smckusick } else 45639751Smckusick nfs_unlock(vp); 45739341Smckusick error = 0; 45838414Smckusick nfsstats.lookupcache_misses++; 45938414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 46038414Smckusick len = ndp->ni_namelen; 46138414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 46238414Smckusick nfsm_fhtom(vp); 46338414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 464*48054Smckusick nfsm_request(vp, NFSPROC_LOOKUP, p, 0); 46538414Smckusick nfsmout: 46638414Smckusick if (error) { 46739751Smckusick if (lockparent || (flag != CREATE && flag != RENAME) || 46839751Smckusick *ndp->ni_next != 0) 46939751Smckusick nfs_lock(vp); 47040483Smckusick return (error); 47138414Smckusick } 47238414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 47338414Smckusick 47438414Smckusick /* 47538414Smckusick * Handle DELETE and RENAME cases... 47638414Smckusick */ 47738414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 47838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 47938425Smckusick VREF(vp); 48038414Smckusick newvp = vp; 48138414Smckusick np = VTONFS(vp); 48238414Smckusick } else { 48338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 48439751Smckusick nfs_lock(vp); 48538414Smckusick m_freem(mrep); 48638414Smckusick return (error); 48738414Smckusick } 48838414Smckusick newvp = NFSTOV(np); 48938414Smckusick } 49039459Smckusick if (error = 49139459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 49239751Smckusick nfs_lock(vp); 49338414Smckusick if (newvp != vp) 49438414Smckusick nfs_nput(newvp); 49538414Smckusick else 49638425Smckusick vrele(vp); 49738414Smckusick m_freem(mrep); 49838414Smckusick return (error); 49938414Smckusick } 50038414Smckusick ndp->ni_vp = newvp; 50139751Smckusick if (lockparent || vp == newvp) 50239751Smckusick nfs_lock(vp); 50338414Smckusick m_freem(mrep); 50438414Smckusick return (0); 50538414Smckusick } 50638414Smckusick 50738414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 50838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 50939751Smckusick nfs_lock(vp); 51038414Smckusick m_freem(mrep); 51138414Smckusick return (EISDIR); 51238414Smckusick } 51338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 51439751Smckusick nfs_lock(vp); 51538414Smckusick m_freem(mrep); 51638414Smckusick return (error); 51738414Smckusick } 51838414Smckusick newvp = NFSTOV(np); 51939459Smckusick if (error = 52039459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 52139751Smckusick nfs_lock(vp); 52238425Smckusick nfs_nput(newvp); 52338414Smckusick m_freem(mrep); 52438414Smckusick return (error); 52538414Smckusick } 52638414Smckusick ndp->ni_vp = newvp; 52739751Smckusick if (lockparent) 52839751Smckusick nfs_lock(vp); 52945037Smckusick m_freem(mrep); 53038414Smckusick return (0); 53138414Smckusick } 53238414Smckusick 53338414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 53438425Smckusick VREF(vp); 53538414Smckusick newvp = vp; 53638414Smckusick np = VTONFS(vp); 53738414Smckusick } else if (ndp->ni_isdotdot) { 53838414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 53938414Smckusick nfs_lock(vp); 54038414Smckusick m_freem(mrep); 54138414Smckusick return (error); 54238414Smckusick } 54338414Smckusick newvp = NFSTOV(np); 54438414Smckusick } else { 54538414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 54639751Smckusick nfs_lock(vp); 54738414Smckusick m_freem(mrep); 54838414Smckusick return (error); 54938414Smckusick } 55038414Smckusick newvp = NFSTOV(np); 55138414Smckusick } 55239459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 55339751Smckusick nfs_lock(vp); 55438414Smckusick if (newvp != vp) 55538414Smckusick nfs_nput(newvp); 55638414Smckusick else 55738425Smckusick vrele(vp); 55838414Smckusick m_freem(mrep); 55938414Smckusick return (error); 56038414Smckusick } 56138414Smckusick m_freem(mrep); 56238414Smckusick 56339751Smckusick if (vp == newvp || (lockparent && *ndp->ni_next == '\0')) 56439751Smckusick nfs_lock(vp); 56538414Smckusick ndp->ni_vp = newvp; 56640251Smckusick if (error == 0 && ndp->ni_makeentry) { 56740251Smckusick np->n_ctime = np->n_vattr.va_ctime.tv_sec; 56838414Smckusick cache_enter(ndp); 56940251Smckusick } 57038414Smckusick return (error); 57138414Smckusick } 57238414Smckusick 57338414Smckusick /* 57441905Smckusick * nfs read call. 57541905Smckusick * Just call nfs_bioread() to do the work. 57641905Smckusick */ 57741905Smckusick nfs_read(vp, uiop, ioflag, cred) 57841905Smckusick register struct vnode *vp; 57941905Smckusick struct uio *uiop; 58041905Smckusick int ioflag; 58141905Smckusick struct ucred *cred; 58241905Smckusick { 58341905Smckusick if (vp->v_type != VREG) 58441905Smckusick return (EPERM); 58541905Smckusick return (nfs_bioread(vp, uiop, ioflag, cred)); 58641905Smckusick } 58741905Smckusick 58841905Smckusick /* 58938414Smckusick * nfs readlink call 59038414Smckusick */ 59138414Smckusick nfs_readlink(vp, uiop, cred) 59241905Smckusick struct vnode *vp; 59341905Smckusick struct uio *uiop; 59441905Smckusick struct ucred *cred; 59541905Smckusick { 59641905Smckusick if (vp->v_type != VLNK) 59741905Smckusick return (EPERM); 59841905Smckusick return (nfs_bioread(vp, uiop, 0, cred)); 59941905Smckusick } 60041905Smckusick 60141905Smckusick /* 60241905Smckusick * Do a readlink rpc. 60341905Smckusick * Called by nfs_doio() from below the buffer cache. 60441905Smckusick */ 605*48054Smckusick nfs_readlinkrpc(vp, uiop, cred) 60639488Smckusick register struct vnode *vp; 60738414Smckusick struct uio *uiop; 60838414Smckusick struct ucred *cred; 60938414Smckusick { 610*48054Smckusick register u_long *tl; 61139488Smckusick register caddr_t cp; 61239488Smckusick register long t1; 61339488Smckusick caddr_t bpos, dpos, cp2; 61439488Smckusick u_long xid; 61539488Smckusick int error = 0; 61639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 61738414Smckusick long len; 61838414Smckusick 61938414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 62038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 62138414Smckusick nfsm_fhtom(vp); 622*48054Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, 0); 62338414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 62438414Smckusick nfsm_mtouio(uiop, len); 62538414Smckusick nfsm_reqdone; 62638414Smckusick return (error); 62738414Smckusick } 62838414Smckusick 62938414Smckusick /* 63041905Smckusick * nfs read rpc call 63141905Smckusick * Ditto above 63238414Smckusick */ 633*48054Smckusick nfs_readrpc(vp, uiop, cred) 63439488Smckusick register struct vnode *vp; 63538414Smckusick struct uio *uiop; 63638414Smckusick struct ucred *cred; 63738414Smckusick { 638*48054Smckusick register u_long *tl; 63939488Smckusick register caddr_t cp; 64039488Smckusick register long t1; 64139488Smckusick caddr_t bpos, dpos, cp2; 64239488Smckusick u_long xid; 64339488Smckusick int error = 0; 64439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 64538414Smckusick struct nfsmount *nmp; 64638414Smckusick long len, retlen, tsiz; 64738414Smckusick 64841398Smckusick nmp = VFSTONFS(vp->v_mount); 64938414Smckusick tsiz = uiop->uio_resid; 65038414Smckusick while (tsiz > 0) { 65138414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 65238414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 65338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 65438414Smckusick nfsm_fhtom(vp); 655*48054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 656*48054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 657*48054Smckusick *tl++ = txdr_unsigned(len); 658*48054Smckusick *tl = 0; 659*48054Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, 1); 66038414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 66138414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 66238414Smckusick nfsm_mtouio(uiop, retlen); 66338414Smckusick m_freem(mrep); 66438414Smckusick if (retlen < len) 66538414Smckusick tsiz = 0; 66638414Smckusick else 66738414Smckusick tsiz -= len; 66838414Smckusick } 66938414Smckusick nfsmout: 67038414Smckusick return (error); 67138414Smckusick } 67238414Smckusick 67338414Smckusick /* 67438414Smckusick * nfs write call 67538414Smckusick */ 676*48054Smckusick nfs_writerpc(vp, uiop, cred) 67739488Smckusick register struct vnode *vp; 67838414Smckusick struct uio *uiop; 67938414Smckusick struct ucred *cred; 68038414Smckusick { 681*48054Smckusick register u_long *tl; 68239488Smckusick register caddr_t cp; 68339488Smckusick register long t1; 68439488Smckusick caddr_t bpos, dpos; 68539488Smckusick u_long xid; 68639488Smckusick int error = 0; 68739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 68838414Smckusick struct nfsmount *nmp; 68938414Smckusick long len, tsiz; 69038414Smckusick 69141398Smckusick nmp = VFSTONFS(vp->v_mount); 69238414Smckusick tsiz = uiop->uio_resid; 69338414Smckusick while (tsiz > 0) { 69438414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 69538414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 69638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 69738414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 69838414Smckusick nfsm_fhtom(vp); 699*48054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 700*48054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 701*48054Smckusick *(tl+3) = txdr_unsigned(len); 70238414Smckusick nfsm_uiotom(uiop, len); 703*48054Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, 1); 70438414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 70538414Smckusick m_freem(mrep); 70638414Smckusick tsiz -= len; 70738414Smckusick } 70838414Smckusick nfsmout: 70938414Smckusick return (error); 71038414Smckusick } 71138414Smckusick 71238414Smckusick /* 71339459Smckusick * nfs mknod call 71442246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 71542246Smckusick * set to specify the file type and the size field for rdev. 71639459Smckusick */ 71739459Smckusick /* ARGSUSED */ 718*48054Smckusick nfs_mknod(ndp, vap, cred, p) 71939459Smckusick struct nameidata *ndp; 72039459Smckusick struct ucred *cred; 72142246Smckusick register struct vattr *vap; 722*48054Smckusick struct proc *p; 72339459Smckusick { 72442246Smckusick register struct nfsv2_sattr *sp; 725*48054Smckusick register u_long *tl; 72642246Smckusick register caddr_t cp; 72742246Smckusick register long t1, t2; 72842246Smckusick caddr_t bpos, dpos; 72942246Smckusick u_long xid; 73042246Smckusick int error = 0; 73142246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73242246Smckusick u_long rdev; 73339459Smckusick 73442246Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 73542246Smckusick rdev = txdr_unsigned(vap->va_rdev); 73642246Smckusick #ifdef FIFO 73742246Smckusick else if (vap->va_type == VFIFO) 73842246Smckusick rdev = 0xffffffff; 73942246Smckusick #endif /* FIFO */ 74042246Smckusick else { 74142246Smckusick VOP_ABORTOP(ndp); 74242467Smckusick vput(ndp->ni_dvp); 74342246Smckusick return (EOPNOTSUPP); 74442246Smckusick } 74542246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 74642246Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 74742246Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 74842246Smckusick nfsm_fhtom(ndp->ni_dvp); 74942246Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 75042246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 75142246Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 75242246Smckusick sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 75342246Smckusick sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 75442246Smckusick sp->sa_size = rdev; 75542246Smckusick /* or should these be VNOVAL ?? */ 75642246Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 75742246Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 758*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1); 75942246Smckusick nfsm_reqdone; 76042246Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 76142246Smckusick nfs_nput(ndp->ni_dvp); 76242246Smckusick return (error); 76339459Smckusick } 76439459Smckusick 76539459Smckusick /* 76638414Smckusick * nfs file create call 76738414Smckusick */ 768*48054Smckusick nfs_create(ndp, vap, p) 76938414Smckusick register struct nameidata *ndp; 77038414Smckusick register struct vattr *vap; 771*48054Smckusick struct proc *p; 77238414Smckusick { 77338884Smacklem register struct nfsv2_sattr *sp; 774*48054Smckusick register u_long *tl; 77539488Smckusick register caddr_t cp; 77639488Smckusick register long t1, t2; 77739488Smckusick caddr_t bpos, dpos, cp2; 77839488Smckusick u_long xid; 77939488Smckusick int error = 0; 78039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 78138414Smckusick 78238414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 78338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 78438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 78538414Smckusick nfsm_fhtom(ndp->ni_dvp); 78638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 78738884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 78846988Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 78938884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 79038884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 79138884Smacklem sp->sa_size = txdr_unsigned(0); 79238414Smckusick /* or should these be VNOVAL ?? */ 79338884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 79438884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 795*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1); 79638414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 79738414Smckusick nfsm_reqdone; 79841905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 79938414Smckusick nfs_nput(ndp->ni_dvp); 80038414Smckusick return (error); 80138414Smckusick } 80238414Smckusick 80338414Smckusick /* 80438414Smckusick * nfs file remove call 80541905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 80641905Smckusick * other processes using the vnode is renamed instead of removed and then 80739341Smckusick * removed later on the last close. 80841905Smckusick * - If v_usecount > 1 80939341Smckusick * If a rename is not already in the works 81039341Smckusick * call nfs_sillyrename() to set it up 81139341Smckusick * else 81239341Smckusick * do the remove rpc 81338414Smckusick */ 814*48054Smckusick nfs_remove(ndp, p) 81538414Smckusick register struct nameidata *ndp; 816*48054Smckusick struct proc *p; 81738414Smckusick { 81839341Smckusick register struct vnode *vp = ndp->ni_vp; 81939341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 820*48054Smckusick register u_long *tl; 82139488Smckusick register caddr_t cp; 82239488Smckusick register long t1, t2; 82339488Smckusick caddr_t bpos, dpos; 82439488Smckusick u_long xid; 82539488Smckusick int error = 0; 82639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 82738414Smckusick 82839810Smckusick if (vp->v_usecount > 1) { 82939341Smckusick if (!np->n_sillyrename) 830*48054Smckusick error = nfs_sillyrename(ndp, REMOVE, p); 83139341Smckusick } else { 83238414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 83338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 83438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 83538414Smckusick nfsm_fhtom(ndp->ni_dvp); 83638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 837*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, p, 1); 83838414Smckusick nfsm_reqdone; 83941905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 84039751Smckusick /* 84139751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 84239751Smckusick * the reply to the retransmitted request will be ENOENT 84339751Smckusick * since the file was in fact removed 84439751Smckusick * Therefore, we cheat and return success. 84539751Smckusick */ 84639751Smckusick if (error == ENOENT) 84739751Smckusick error = 0; 84838414Smckusick } 84940042Smckusick np->n_attrstamp = 0; 85040112Smckusick if (ndp->ni_dvp == vp) 85140112Smckusick vrele(vp); 85238414Smckusick else 85340112Smckusick nfs_nput(ndp->ni_dvp); 85440112Smckusick nfs_nput(vp); 85538414Smckusick return (error); 85638414Smckusick } 85738414Smckusick 85838414Smckusick /* 85938414Smckusick * nfs file remove rpc called from nfs_inactive 86038414Smckusick */ 861*48054Smckusick nfs_removeit(ndp, p) 86238414Smckusick register struct nameidata *ndp; 863*48054Smckusick struct proc *p; 86438414Smckusick { 865*48054Smckusick register u_long *tl; 86639488Smckusick register caddr_t cp; 86739488Smckusick register long t1, t2; 86839488Smckusick caddr_t bpos, dpos; 86939488Smckusick u_long xid; 87039488Smckusick int error = 0; 87139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 87238414Smckusick 87338414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 87438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 87538414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 87638414Smckusick nfsm_fhtom(ndp->ni_dvp); 87738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 878*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, p, 1); 87938414Smckusick nfsm_reqdone; 88041905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 88138414Smckusick return (error); 88238414Smckusick } 88338414Smckusick 88438414Smckusick /* 88538414Smckusick * nfs file rename call 88638414Smckusick */ 887*48054Smckusick nfs_rename(sndp, tndp, p) 88838414Smckusick register struct nameidata *sndp, *tndp; 889*48054Smckusick struct proc *p; 89038414Smckusick { 891*48054Smckusick register u_long *tl; 89239488Smckusick register caddr_t cp; 89339488Smckusick register long t1, t2; 89439488Smckusick caddr_t bpos, dpos; 89539488Smckusick u_long xid; 89639488Smckusick int error = 0; 89739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 89838414Smckusick 89938414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 90038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 90138414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 90238414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 90338414Smckusick nfsm_fhtom(sndp->ni_dvp); 90438414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 90538414Smckusick nfsm_fhtom(tndp->ni_dvp); 90638414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 907*48054Smckusick nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1); 90838414Smckusick nfsm_reqdone; 90941905Smckusick VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED; 91041905Smckusick VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED; 91138414Smckusick if (sndp->ni_vp->v_type == VDIR) { 91238414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 91338414Smckusick cache_purge(tndp->ni_dvp); 91438414Smckusick cache_purge(sndp->ni_dvp); 91538414Smckusick } 91642467Smckusick VOP_ABORTOP(tndp); 91743360Smckusick if (tndp->ni_dvp == tndp->ni_vp) 91843360Smckusick vrele(tndp->ni_dvp); 91943360Smckusick else 92043360Smckusick vput(tndp->ni_dvp); 92142467Smckusick if (tndp->ni_vp) 92242467Smckusick vput(tndp->ni_vp); 92342467Smckusick VOP_ABORTOP(sndp); 92442467Smckusick vrele(sndp->ni_dvp); 92542467Smckusick vrele(sndp->ni_vp); 92640112Smckusick /* 92740112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 92840112Smckusick */ 92940112Smckusick if (error == ENOENT) 93040112Smckusick error = 0; 93138414Smckusick return (error); 93238414Smckusick } 93338414Smckusick 93438414Smckusick /* 93541905Smckusick * nfs file rename rpc called from nfs_remove() above 93638414Smckusick */ 937*48054Smckusick nfs_renameit(sndp, tndp, p) 93838414Smckusick register struct nameidata *sndp, *tndp; 939*48054Smckusick struct proc *p; 94038414Smckusick { 941*48054Smckusick register u_long *tl; 94239488Smckusick register caddr_t cp; 94339488Smckusick register long t1, t2; 94439488Smckusick caddr_t bpos, dpos; 94539488Smckusick u_long xid; 94639488Smckusick int error = 0; 94739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 94838414Smckusick 94938414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 95038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 95138414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 95238414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 95338414Smckusick nfsm_fhtom(sndp->ni_dvp); 95438414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 95538414Smckusick nfsm_fhtom(tndp->ni_dvp); 95638414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 957*48054Smckusick nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1); 95838414Smckusick nfsm_reqdone; 95941905Smckusick VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED; 96041905Smckusick VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED; 96138414Smckusick return (error); 96238414Smckusick } 96338414Smckusick 96438414Smckusick /* 96538414Smckusick * nfs hard link create call 96638414Smckusick */ 967*48054Smckusick nfs_link(vp, ndp, p) 96839488Smckusick register struct vnode *vp; 96938414Smckusick register struct nameidata *ndp; 970*48054Smckusick struct proc *p; 97138414Smckusick { 972*48054Smckusick register u_long *tl; 97339488Smckusick register caddr_t cp; 97439488Smckusick register long t1, t2; 97539488Smckusick caddr_t bpos, dpos; 97639488Smckusick u_long xid; 97739488Smckusick int error = 0; 97839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97938414Smckusick 98038425Smckusick if (ndp->ni_dvp != vp) 98138425Smckusick nfs_lock(vp); 98238414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 98338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 98438414Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 98538414Smckusick nfsm_fhtom(vp); 98638414Smckusick nfsm_fhtom(ndp->ni_dvp); 98738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 988*48054Smckusick nfsm_request(vp, NFSPROC_LINK, p, 1); 98938414Smckusick nfsm_reqdone; 99040042Smckusick VTONFS(vp)->n_attrstamp = 0; 99141905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 99238425Smckusick if (ndp->ni_dvp != vp) 99338425Smckusick nfs_unlock(vp); 99438414Smckusick nfs_nput(ndp->ni_dvp); 99540112Smckusick /* 99640112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 99740112Smckusick */ 99840112Smckusick if (error == EEXIST) 99940112Smckusick error = 0; 100038414Smckusick return (error); 100138414Smckusick } 100238414Smckusick 100338414Smckusick /* 100438414Smckusick * nfs symbolic link create call 100538414Smckusick */ 1006*48054Smckusick nfs_symlink(ndp, vap, nm, p) 100738414Smckusick struct nameidata *ndp; 100838414Smckusick struct vattr *vap; 100938414Smckusick char *nm; /* is this the path ?? */ 1010*48054Smckusick struct proc *p; 101138414Smckusick { 101238884Smacklem register struct nfsv2_sattr *sp; 1013*48054Smckusick register u_long *tl; 101439488Smckusick register caddr_t cp; 101539488Smckusick register long t1, t2; 101639488Smckusick caddr_t bpos, dpos; 101739488Smckusick u_long xid; 101839488Smckusick int error = 0; 101939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 102038414Smckusick 102138414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 102238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 102338414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED); 102438414Smckusick nfsm_fhtom(ndp->ni_dvp); 102538414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 102638414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 102738884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 102838884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 102938884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 103038884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 103138884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 103240112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 103338884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 1034*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_SYMLINK, p, 1); 103538414Smckusick nfsm_reqdone; 103641905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 103738414Smckusick nfs_nput(ndp->ni_dvp); 103840112Smckusick /* 103940112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 104040112Smckusick */ 104140112Smckusick if (error == EEXIST) 104240112Smckusick error = 0; 104338414Smckusick return (error); 104438414Smckusick } 104538414Smckusick 104638414Smckusick /* 104738414Smckusick * nfs make dir call 104838414Smckusick */ 1049*48054Smckusick nfs_mkdir(ndp, vap, p) 105039488Smckusick register struct nameidata *ndp; 105138414Smckusick struct vattr *vap; 1052*48054Smckusick struct proc *p; 105338414Smckusick { 105438884Smacklem register struct nfsv2_sattr *sp; 1055*48054Smckusick register u_long *tl; 105639488Smckusick register caddr_t cp; 105739488Smckusick register long t1, t2; 105841905Smckusick register int len; 105939488Smckusick caddr_t bpos, dpos, cp2; 106039488Smckusick u_long xid; 106141905Smckusick int error = 0, firsttry = 1; 106239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 106338414Smckusick 106441905Smckusick len = ndp->ni_dent.d_namlen; 106538414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 106638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 106741905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 106838414Smckusick nfsm_fhtom(ndp->ni_dvp); 106941905Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 107038884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 107138884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 107238884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 107338884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 107438884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 107540112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 107638884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 1077*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_MKDIR, p, 1); 107838414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 107938414Smckusick nfsm_reqdone; 108041905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 108140112Smckusick /* 108241905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 108341905Smckusick * if we can succeed in looking up the directory. 108441905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 108541905Smckusick * is above the if on errors. (Ugh) 108640112Smckusick */ 108741905Smckusick if (error == EEXIST && firsttry) { 108841905Smckusick firsttry = 0; 108940112Smckusick error = 0; 109041905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 109141905Smckusick ndp->ni_vp = NULL; 109241905Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, 109341905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 109441905Smckusick nfsm_fhtom(ndp->ni_dvp); 109541905Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 1096*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_LOOKUP, p, 1); 109741905Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 109841905Smckusick if (ndp->ni_vp->v_type != VDIR) { 109941905Smckusick vput(ndp->ni_vp); 110041905Smckusick error = EEXIST; 110141905Smckusick } 110241905Smckusick m_freem(mrep); 110341905Smckusick } 110441905Smckusick nfs_nput(ndp->ni_dvp); 110538414Smckusick return (error); 110638414Smckusick } 110738414Smckusick 110838414Smckusick /* 110938414Smckusick * nfs remove directory call 111038414Smckusick */ 1111*48054Smckusick nfs_rmdir(ndp, p) 111238414Smckusick register struct nameidata *ndp; 1113*48054Smckusick struct proc *p; 111438414Smckusick { 1115*48054Smckusick register u_long *tl; 111639488Smckusick register caddr_t cp; 111739488Smckusick register long t1, t2; 111839488Smckusick caddr_t bpos, dpos; 111939488Smckusick u_long xid; 112039488Smckusick int error = 0; 112139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 112238414Smckusick 112338414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 112438414Smckusick vrele(ndp->ni_dvp); 112538414Smckusick nfs_nput(ndp->ni_dvp); 112638414Smckusick return (EINVAL); 112738414Smckusick } 112838414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 112938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 113038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 113138414Smckusick nfsm_fhtom(ndp->ni_dvp); 113238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 1133*48054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_RMDIR, p, 1); 113438414Smckusick nfsm_reqdone; 113541905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 113638884Smacklem cache_purge(ndp->ni_dvp); 113738884Smacklem cache_purge(ndp->ni_vp); 113838884Smacklem nfs_nput(ndp->ni_vp); 113938884Smacklem nfs_nput(ndp->ni_dvp); 114040112Smckusick /* 114140112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 114240112Smckusick */ 114340112Smckusick if (error == ENOENT) 114440112Smckusick error = 0; 114538414Smckusick return (error); 114638414Smckusick } 114738414Smckusick 114838414Smckusick /* 114938414Smckusick * nfs readdir call 115038414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 115138414Smckusick * order so that it looks more sensible. This appears consistent with the 115238414Smckusick * Ultrix implementation of NFS. 115338414Smckusick */ 115440296Smckusick nfs_readdir(vp, uiop, cred, eofflagp) 115539488Smckusick register struct vnode *vp; 115638414Smckusick struct uio *uiop; 115738414Smckusick struct ucred *cred; 115840296Smckusick int *eofflagp; 115938414Smckusick { 116041905Smckusick register struct nfsnode *np = VTONFS(vp); 116141905Smckusick int tresid, error; 116241905Smckusick struct vattr vattr; 116341905Smckusick 116441905Smckusick if (vp->v_type != VDIR) 116541905Smckusick return (EPERM); 116641905Smckusick /* 116741905Smckusick * First, check for hit on the EOF offset cache 116841905Smckusick */ 116941905Smckusick if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset && 117041905Smckusick (np->n_flag & NMODIFIED) == 0 && 1171*48054Smckusick nfs_dogetattr(vp, &vattr, cred, 0, uiop->uio_procp) == 0 && 117241905Smckusick np->n_mtime == vattr.va_mtime.tv_sec) { 117341905Smckusick *eofflagp = 1; 117441905Smckusick nfsstats.direofcache_hits++; 117541905Smckusick return (0); 117641905Smckusick } 117741905Smckusick 117841905Smckusick /* 117941905Smckusick * Call nfs_bioread() to do the real work. 118041905Smckusick */ 118141905Smckusick tresid = uiop->uio_resid; 118241905Smckusick error = nfs_bioread(vp, uiop, 0, cred); 118341905Smckusick 118441905Smckusick if (!error && uiop->uio_resid == tresid) { 118541905Smckusick *eofflagp = 1; 118641905Smckusick nfsstats.direofcache_misses++; 118741905Smckusick } else 118841905Smckusick *eofflagp = 0; 118941905Smckusick return (error); 119041905Smckusick } 119141905Smckusick 119241905Smckusick /* 119341905Smckusick * Readdir rpc call. 119441905Smckusick * Called from below the buffer cache by nfs_doio(). 119541905Smckusick */ 1196*48054Smckusick nfs_readdirrpc(vp, uiop, cred) 119741905Smckusick register struct vnode *vp; 119841905Smckusick struct uio *uiop; 119941905Smckusick struct ucred *cred; 120041905Smckusick { 120138414Smckusick register long len; 120238414Smckusick register struct direct *dp; 1203*48054Smckusick register u_long *tl; 120439488Smckusick register caddr_t cp; 120539488Smckusick register long t1; 120641905Smckusick long tlen, lastlen; 120739488Smckusick caddr_t bpos, dpos, cp2; 120839488Smckusick u_long xid; 120939488Smckusick int error = 0; 121039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 121138414Smckusick struct mbuf *md2; 121238414Smckusick caddr_t dpos2; 121338414Smckusick int siz; 121440296Smckusick int more_dirs = 1; 121538414Smckusick off_t off, savoff; 121638414Smckusick struct direct *savdp; 121740296Smckusick struct nfsmount *nmp; 121840296Smckusick struct nfsnode *np = VTONFS(vp); 121940296Smckusick long tresid; 122038414Smckusick 122141398Smckusick nmp = VFSTONFS(vp->v_mount); 122240296Smckusick tresid = uiop->uio_resid; 122340296Smckusick /* 122440296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 1225*48054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 122641905Smckusick * The stopping criteria is EOF or buffer full. 122740296Smckusick */ 1228*48054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 122940296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 123040296Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 123140296Smckusick nfsm_fhtom(vp); 1232*48054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 1233*48054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 1234*48054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 1235*48054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 1236*48054Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, 0); 123740296Smckusick siz = 0; 1238*48054Smckusick nfsm_disect(tl, u_long *, NFSX_UNSIGNED); 1239*48054Smckusick more_dirs = fxdr_unsigned(int, *tl); 124040296Smckusick 124140296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 124240296Smckusick dpos2 = dpos; 124340296Smckusick md2 = md; 124440296Smckusick 124540296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 124641905Smckusick off = uiop->uio_offset; 124742246Smckusick #ifdef lint 124842246Smckusick dp = (struct direct *)0; 124942246Smckusick #endif /* lint */ 125040296Smckusick while (more_dirs && siz < uiop->uio_resid) { 125140296Smckusick savoff = off; /* Hold onto offset and dp */ 125240296Smckusick savdp = dp; 1253*48054Smckusick nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED); 1254*48054Smckusick dp = (struct direct *)tl; 1255*48054Smckusick dp->d_ino = fxdr_unsigned(u_long, *tl++); 1256*48054Smckusick len = fxdr_unsigned(int, *tl); 125740296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 125840296Smckusick error = EBADRPC; 125940296Smckusick m_freem(mrep); 126040296Smckusick goto nfsmout; 126140296Smckusick } 126240296Smckusick dp->d_namlen = (u_short)len; 126340296Smckusick nfsm_adv(len); /* Point past name */ 126440296Smckusick tlen = nfsm_rndup(len); 126540296Smckusick /* 126640296Smckusick * This should not be necessary, but some servers have 126740296Smckusick * broken XDR such that these bytes are not null filled. 126840296Smckusick */ 126940296Smckusick if (tlen != len) { 127040296Smckusick *dpos = '\0'; /* Null-terminate */ 127140296Smckusick nfsm_adv(tlen - len); 127240296Smckusick len = tlen; 127340296Smckusick } 1274*48054Smckusick nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED); 1275*48054Smckusick off = fxdr_unsigned(off_t, *tl); 1276*48054Smckusick *tl++ = 0; /* Ensures null termination of name */ 1277*48054Smckusick more_dirs = fxdr_unsigned(int, *tl); 127840296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 127940296Smckusick siz += dp->d_reclen; 128040296Smckusick } 128140296Smckusick /* 128240296Smckusick * If at end of rpc data, get the eof boolean 128340296Smckusick */ 128440296Smckusick if (!more_dirs) { 1285*48054Smckusick nfsm_disecton(tl, u_long *, NFSX_UNSIGNED); 1286*48054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 128738414Smckusick 128840296Smckusick /* 128940296Smckusick * If at EOF, cache directory offset 129040296Smckusick */ 129141905Smckusick if (!more_dirs) 129240296Smckusick np->n_direofoffset = off; 129338414Smckusick } 129440296Smckusick /* 129540296Smckusick * If there is too much to fit in the data buffer, use savoff and 129640296Smckusick * savdp to trim off the last record. 129740296Smckusick * --> we are not at eof 129840296Smckusick */ 129940296Smckusick if (siz > uiop->uio_resid) { 130040296Smckusick off = savoff; 130140296Smckusick siz -= dp->d_reclen; 130240296Smckusick dp = savdp; 130340296Smckusick more_dirs = 0; /* Paranoia */ 130440113Smckusick } 130540296Smckusick if (siz > 0) { 130641905Smckusick lastlen = dp->d_reclen; 130740296Smckusick md = md2; 130840296Smckusick dpos = dpos2; 130940296Smckusick nfsm_mtouio(uiop, siz); 131040296Smckusick uiop->uio_offset = off; 131140296Smckusick } else 131240296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 131340296Smckusick m_freem(mrep); 131438414Smckusick } 131541905Smckusick /* 1316*48054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 131741905Smckusick * by increasing d_reclen for the last record. 131841905Smckusick */ 131941905Smckusick if (uiop->uio_resid < tresid) { 1320*48054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 132141905Smckusick if (len > 0) { 132241905Smckusick dp = (struct direct *) 132341905Smckusick (uiop->uio_iov->iov_base - lastlen); 132441905Smckusick dp->d_reclen += len; 132541905Smckusick uiop->uio_iov->iov_base += len; 132641905Smckusick uiop->uio_iov->iov_len -= len; 132741905Smckusick uiop->uio_resid -= len; 132841905Smckusick } 132941905Smckusick } 133040296Smckusick nfsmout: 133138414Smckusick return (error); 133238414Smckusick } 133338414Smckusick 133439488Smckusick static char hextoasc[] = "0123456789abcdef"; 133538414Smckusick 133638414Smckusick /* 133738414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 133838414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 133938414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 134038414Smckusick * nfsnode. There is the potential for another process on a different client 134138414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 134238414Smckusick * nfs_rename() completes, but... 134338414Smckusick */ 1344*48054Smckusick nfs_sillyrename(ndp, flag, p) 134539488Smckusick register struct nameidata *ndp; 134638414Smckusick int flag; 1347*48054Smckusick struct proc *p; 134838414Smckusick { 134938414Smckusick register struct nfsnode *np; 135038414Smckusick register struct sillyrename *sp; 135138414Smckusick register struct nameidata *tndp; 135238414Smckusick int error; 135338414Smckusick short pid; 135438414Smckusick 135538414Smckusick np = VTONFS(ndp->ni_dvp); 135639341Smckusick cache_purge(ndp->ni_dvp); 135738414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 135838884Smacklem M_TEMP, M_WAITOK); 135938414Smckusick sp->s_flag = flag; 136038414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 136138414Smckusick np = VTONFS(ndp->ni_vp); 136238414Smckusick tndp = &sp->s_namei; 136338414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 136438414Smckusick 136538414Smckusick /* Fudge together a funny name */ 1366*48054Smckusick pid = p->p_pid; 136738414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 136838414Smckusick tndp->ni_dent.d_namlen = 12; 136939488Smckusick tndp->ni_dent.d_name[8] = hextoasc[pid & 0xf]; 137039488Smckusick tndp->ni_dent.d_name[7] = hextoasc[(pid >> 4) & 0xf]; 137139488Smckusick tndp->ni_dent.d_name[6] = hextoasc[(pid >> 8) & 0xf]; 137239488Smckusick tndp->ni_dent.d_name[5] = hextoasc[(pid >> 12) & 0xf]; 137338414Smckusick 137438414Smckusick /* Try lookitups until we get one that isn't there */ 1375*48054Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0, p) == 0) { 137638414Smckusick tndp->ni_dent.d_name[4]++; 137738414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 137838414Smckusick error = EINVAL; 137938414Smckusick goto bad; 138038414Smckusick } 138138414Smckusick } 1382*48054Smckusick if (error = nfs_renameit(ndp, tndp, p)) 138338414Smckusick goto bad; 1384*48054Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh, p); 138538414Smckusick np->n_sillyrename = sp; 138638414Smckusick return (0); 138738414Smckusick bad: 138838884Smacklem crfree(tndp->ni_cred); 138938414Smckusick free((caddr_t)sp, M_TEMP); 139038414Smckusick return (error); 139138414Smckusick } 139238414Smckusick 139338414Smckusick /* 139438414Smckusick * Look up a file name for silly rename stuff. 139538414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 139638414Smckusick * into the nfsnode table. 139738414Smckusick * If fhp != NULL it copies the returned file handle out 139838414Smckusick */ 1399*48054Smckusick nfs_lookitup(vp, ndp, fhp, p) 140038414Smckusick register struct vnode *vp; 140138414Smckusick register struct nameidata *ndp; 140238414Smckusick nfsv2fh_t *fhp; 1403*48054Smckusick struct proc *p; 140438414Smckusick { 1405*48054Smckusick register u_long *tl; 140639488Smckusick register caddr_t cp; 140739488Smckusick register long t1, t2; 140839488Smckusick caddr_t bpos, dpos, cp2; 140939488Smckusick u_long xid; 141039488Smckusick int error = 0; 141139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 141238414Smckusick long len; 141338414Smckusick 141438414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 141538414Smckusick ndp->ni_dvp = vp; 141638414Smckusick ndp->ni_vp = NULL; 141738414Smckusick len = ndp->ni_dent.d_namlen; 141838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 141938414Smckusick nfsm_fhtom(vp); 142038414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 1421*48054Smckusick nfsm_request(vp, NFSPROC_LOOKUP, p, 1); 142238414Smckusick if (fhp != NULL) { 142338414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 142438414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 142538414Smckusick } 142638414Smckusick nfsm_reqdone; 142738414Smckusick return (error); 142838414Smckusick } 142938414Smckusick 143038414Smckusick /* 143138414Smckusick * Kludge City.. 143238414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 143341905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 143438414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 143538414Smckusick * nfsiobuf area. 143638414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 143738414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 143838414Smckusick * a lot more work than bcopy() and also it currently happens in the 143938414Smckusick * context of the swapper process (2). 144038414Smckusick */ 144138414Smckusick nfs_bmap(vp, bn, vpp, bnp) 144238414Smckusick struct vnode *vp; 144338414Smckusick daddr_t bn; 144438414Smckusick struct vnode **vpp; 144538414Smckusick daddr_t *bnp; 144638414Smckusick { 144738414Smckusick if (vpp != NULL) 144838414Smckusick *vpp = vp; 144938414Smckusick if (bnp != NULL) 145041398Smckusick *bnp = bn * btodb(vp->v_mount->mnt_stat.f_bsize); 145138414Smckusick return (0); 145238414Smckusick } 145338414Smckusick 145438414Smckusick /* 145538884Smacklem * Strategy routine for phys. i/o 145638884Smacklem * If the biod's are running, queue a request 145738884Smacklem * otherwise just call nfs_doio() to get it done 145838414Smckusick */ 145938414Smckusick nfs_strategy(bp) 146038414Smckusick register struct buf *bp; 146138414Smckusick { 146238884Smacklem register struct buf *dp; 146339341Smckusick register int i; 146438884Smacklem int error = 0; 146539341Smckusick int fnd = 0; 146638884Smacklem 146738884Smacklem /* 146841905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 146941905Smckusick * doesn't set it, I will. 147046450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 147141905Smckusick * be hanging about after the process terminates. 147241905Smckusick */ 147346988Smckusick if ((bp->b_flags & B_PHYS) == 0) { 147446988Smckusick if (bp->b_flags & B_ASYNC) 147546988Smckusick bp->b_proc = (struct proc *)0; 147646988Smckusick else 147747573Skarels bp->b_proc = curproc; 147846988Smckusick } 147941905Smckusick /* 148046450Skarels * If the op is asynchronous and an i/o daemon is waiting 148138884Smacklem * queue the request, wake it up and wait for completion 148246450Skarels * otherwise just do it ourselves. 148338884Smacklem */ 148446988Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 148546988Smckusick return (nfs_doio(bp)); 148646988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 148746988Smckusick if (nfs_iodwant[i]) { 148839341Smckusick dp = &nfs_bqueue; 148939341Smckusick if (dp->b_actf == NULL) { 149039341Smckusick dp->b_actl = bp; 149139341Smckusick bp->b_actf = dp; 149239341Smckusick } else { 149339341Smckusick dp->b_actf->b_actl = bp; 149439341Smckusick bp->b_actf = dp->b_actf; 149539341Smckusick } 149639341Smckusick dp->b_actf = bp; 149739341Smckusick bp->b_actl = dp; 149839341Smckusick fnd++; 149939341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 150039341Smckusick break; 150138884Smacklem } 150239341Smckusick } 150339341Smckusick if (!fnd) 150438884Smacklem error = nfs_doio(bp); 150538884Smacklem return (error); 150638884Smacklem } 150738884Smacklem 150838884Smacklem /* 150938884Smacklem * Fun and games with i/o 151038884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 151138884Smacklem * mapping the data buffer into kernel virtual space and doing the 151238884Smacklem * nfs read or write rpc's from it. 151341905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 151441905Smckusick * otherwise it is called by the nfsiods to do what would normally be 151538884Smacklem * partially disk interrupt driven. 151638884Smacklem */ 151738884Smacklem nfs_doio(bp) 151838884Smacklem register struct buf *bp; 151938884Smacklem { 152038414Smckusick register struct uio *uiop; 152138414Smckusick register struct vnode *vp; 152239341Smckusick struct nfsnode *np; 152338884Smacklem struct ucred *cr; 152441539Smckusick int error; 152541539Smckusick struct uio uio; 152641539Smckusick struct iovec io; 152744885Swilliam #if !defined(hp300) && !defined(i386) 152841539Smckusick register struct pte *pte, *ppte; 152941539Smckusick register caddr_t vaddr; 153038884Smacklem int npf, npf2; 153141539Smckusick int reg, o; 153238884Smacklem caddr_t vbase; 153338414Smckusick unsigned v; 153441539Smckusick #endif 153538414Smckusick 153638414Smckusick vp = bp->b_vp; 153740251Smckusick np = VTONFS(vp); 153838414Smckusick uiop = &uio; 153938414Smckusick uiop->uio_iov = &io; 154038414Smckusick uiop->uio_iovcnt = 1; 154138414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 1542*48054Smckusick uiop->uio_procp = (struct proc *)0; 154339751Smckusick 154438414Smckusick /* 154538884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 154638884Smacklem * the Nfsiomap pte's 154738884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 154838884Smacklem * and a guess at a group 154938414Smckusick */ 155038884Smacklem if (bp->b_flags & B_PHYS) { 1551*48054Smckusick if (bp->b_flags & B_DIRTY) 1552*48054Smckusick uiop->uio_procp = pageproc; 1553*48054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 155444885Swilliam #if defined(hp300) || defined(i386) 155541539Smckusick /* mapping was already done by vmapbuf */ 155641539Smckusick io.iov_base = bp->b_un.b_addr; 155741539Smckusick #else 155839751Smckusick o = (int)bp->b_un.b_addr & PGOFSET; 155939751Smckusick npf2 = npf = btoc(bp->b_bcount + o); 156039751Smckusick 156138884Smacklem /* 156238884Smacklem * Get some mapping page table entries 156338884Smacklem */ 156438884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 156538884Smacklem nfsmap_want++; 156643356Smckusick (void) tsleep((caddr_t)&nfsmap_want, PZERO-1, "nfsmap", 156743356Smckusick 0); 156838884Smacklem } 156938884Smacklem reg--; 157039751Smckusick if (bp->b_flags & B_PAGET) 157139751Smckusick pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 157238884Smacklem else { 157339751Smckusick v = btop(bp->b_un.b_addr); 157438884Smacklem if (bp->b_flags & B_UAREA) 1575*48054Smckusick pte = &uiop->uio_procp->p_addr[v]; 157638884Smacklem else 1577*48054Smckusick pte = vtopte(uiop->uio_procp, v); 157838884Smacklem } 157939751Smckusick 158038884Smacklem /* 158138884Smacklem * Play vmaccess() but with the Nfsiomap page table 158238884Smacklem */ 158338884Smacklem ppte = &Nfsiomap[reg]; 158438884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 158538884Smacklem while (npf != 0) { 158638884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 158738414Smckusick #if defined(tahoe) 158838884Smacklem mtpr(P1DC, vaddr); 158938414Smckusick #endif 159038884Smacklem ppte++; 159138884Smacklem pte++; 159238884Smacklem vaddr += NBPG; 159338884Smacklem --npf; 159438884Smacklem } 159541539Smckusick io.iov_base = vbase+o; 159641539Smckusick #endif /* !defined(hp300) */ 159739751Smckusick 159839751Smckusick /* 159939751Smckusick * And do the i/o rpc 160039751Smckusick */ 160139751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 160239823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 160339751Smckusick if (bp->b_flags & B_READ) { 160439751Smckusick uiop->uio_rw = UIO_READ; 160539751Smckusick nfsstats.read_physios++; 1606*48054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 160745717Smckusick (void) vnode_pager_uncache(vp); 160839751Smckusick } else { 160939751Smckusick uiop->uio_rw = UIO_WRITE; 161039751Smckusick nfsstats.write_physios++; 1611*48054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 161239341Smckusick } 161339751Smckusick 161439751Smckusick /* 161539751Smckusick * Finally, release pte's used by physical i/o 161639751Smckusick */ 161738884Smacklem crfree(cr); 161844885Swilliam #if !defined(hp300) && !defined(i386) 161938884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 162038884Smacklem if (nfsmap_want) { 162138884Smacklem nfsmap_want = 0; 162238884Smacklem wakeup((caddr_t)&nfsmap_want); 162338884Smacklem } 162441539Smckusick #endif 162539751Smckusick } else { 162639751Smckusick if (bp->b_flags & B_READ) { 162739751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 162839751Smckusick io.iov_base = bp->b_un.b_addr; 162939751Smckusick uiop->uio_rw = UIO_READ; 163041905Smckusick switch (vp->v_type) { 163141905Smckusick case VREG: 163241905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 163341905Smckusick nfsstats.read_bios++; 1634*48054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 163541905Smckusick break; 163641905Smckusick case VLNK: 163741905Smckusick uiop->uio_offset = 0; 163841905Smckusick nfsstats.readlink_bios++; 1639*48054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 164041905Smckusick break; 164141905Smckusick case VDIR: 164241905Smckusick uiop->uio_offset = bp->b_lblkno; 164341905Smckusick nfsstats.readdir_bios++; 1644*48054Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 164541905Smckusick /* 164641905Smckusick * Save offset cookie in b_blkno. 164741905Smckusick */ 164841905Smckusick bp->b_blkno = uiop->uio_offset; 164941905Smckusick break; 165041905Smckusick }; 165141905Smckusick bp->b_error = error; 165239751Smckusick } else { 165339751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 165439751Smckusick - bp->b_dirtyoff; 165539823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 165639751Smckusick + bp->b_dirtyoff; 165739751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 165839751Smckusick uiop->uio_rw = UIO_WRITE; 165939751Smckusick nfsstats.write_bios++; 166041905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 1661*48054Smckusick bp->b_wcred); 166239751Smckusick if (error) { 166339751Smckusick np->n_error = error; 166439751Smckusick np->n_flag |= NWRITEERR; 166539751Smckusick } 166639751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 166739751Smckusick } 166838884Smacklem } 166939751Smckusick if (error) 167039751Smckusick bp->b_flags |= B_ERROR; 167139751Smckusick bp->b_resid = uiop->uio_resid; 167238414Smckusick biodone(bp); 167338414Smckusick return (error); 167438414Smckusick } 167538884Smacklem 167638884Smacklem /* 1677*48054Smckusick * Mmap a file 1678*48054Smckusick * 1679*48054Smckusick * NB Currently unsupported. 1680*48054Smckusick */ 1681*48054Smckusick /* ARGSUSED */ 1682*48054Smckusick nfs_mmap(vp, fflags, cred, p) 1683*48054Smckusick struct vnode *vp; 1684*48054Smckusick int fflags; 1685*48054Smckusick struct ucred *cred; 1686*48054Smckusick struct proc *p; 1687*48054Smckusick { 1688*48054Smckusick 1689*48054Smckusick return (EINVAL); 1690*48054Smckusick } 1691*48054Smckusick 1692*48054Smckusick /* 169338884Smacklem * Flush all the blocks associated with a vnode. 169438884Smacklem * Walk through the buffer pool and push any dirty pages 169538884Smacklem * associated with the vnode. 169638884Smacklem */ 169739488Smckusick /* ARGSUSED */ 1698*48054Smckusick nfs_fsync(vp, fflags, cred, waitfor, p) 169938884Smacklem register struct vnode *vp; 170038884Smacklem int fflags; 170138884Smacklem struct ucred *cred; 170239587Smckusick int waitfor; 1703*48054Smckusick struct proc *p; 170438884Smacklem { 170538884Smacklem register struct nfsnode *np = VTONFS(vp); 170639751Smckusick int error = 0; 170738884Smacklem 170838884Smacklem if (np->n_flag & NMODIFIED) { 170938884Smacklem np->n_flag &= ~NMODIFIED; 171039751Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 171138884Smacklem } 171239751Smckusick if (!error && (np->n_flag & NWRITEERR)) 171339751Smckusick error = np->n_error; 171438884Smacklem return (error); 171538884Smacklem } 171639672Smckusick 171739672Smckusick /* 171846201Smckusick * NFS advisory byte-level locks. 171946201Smckusick * Currently unsupported. 172046201Smckusick */ 172146201Smckusick nfs_advlock(vp, id, op, fl, flags) 172246201Smckusick struct vnode *vp; 172346201Smckusick caddr_t id; 172446201Smckusick int op; 172546201Smckusick struct flock *fl; 172646201Smckusick int flags; 172746201Smckusick { 172846201Smckusick 172946201Smckusick return (EOPNOTSUPP); 173046201Smckusick } 173146201Smckusick 173246201Smckusick /* 173339672Smckusick * Print out the contents of an nfsnode. 173439672Smckusick */ 173539672Smckusick nfs_print(vp) 173639672Smckusick struct vnode *vp; 173739672Smckusick { 173839672Smckusick register struct nfsnode *np = VTONFS(vp); 173939672Smckusick 174040294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 174140294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 174240294Smckusick #ifdef FIFO 174340294Smckusick if (vp->v_type == VFIFO) 174440294Smckusick fifo_printinfo(vp); 174540294Smckusick #endif /* FIFO */ 174640294Smckusick printf("%s\n", (np->n_flag & NLOCKED) ? " (LOCKED)" : ""); 174739914Smckusick if (np->n_lockholder == 0) 174839914Smckusick return; 174939914Smckusick printf("\towner pid %d", np->n_lockholder); 175039914Smckusick if (np->n_lockwaiter) 175139914Smckusick printf(" waiting pid %d", np->n_lockwaiter); 175239914Smckusick printf("\n"); 175339672Smckusick } 1754