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*52823Smckusick * @(#)nfs_vnops.c 7.69 (Berkeley) 03/03/92 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" 2648054Smckusick #include "namei.h" 2738414Smckusick #include "vnode.h" 2848054Smckusick #include "specdev.h" 2948054Smckusick #include "fifo.h" 3038884Smacklem #include "map.h" 3147573Skarels 3252196Smckusick #include "rpcv2.h" 3338414Smckusick #include "nfsv2.h" 3438414Smckusick #include "nfs.h" 3538414Smckusick #include "nfsnode.h" 3638414Smckusick #include "nfsmount.h" 3738414Smckusick #include "xdr_subs.h" 3838414Smckusick #include "nfsm_subs.h" 3952196Smckusick #include "nqnfs.h" 4038414Smckusick 4138414Smckusick /* Defs */ 4238414Smckusick #define TRUE 1 4338414Smckusick #define FALSE 0 4438414Smckusick 4548054Smckusick /* 4648054Smckusick * Global vfs data structures for nfs 4748054Smckusick */ 4838414Smckusick struct vnodeops nfsv2_vnodeops = { 4939672Smckusick nfs_lookup, /* lookup */ 5039672Smckusick nfs_create, /* create */ 5139672Smckusick nfs_mknod, /* mknod */ 5239672Smckusick nfs_open, /* open */ 5339672Smckusick nfs_close, /* close */ 5439672Smckusick nfs_access, /* access */ 5539672Smckusick nfs_getattr, /* getattr */ 5639672Smckusick nfs_setattr, /* setattr */ 5739672Smckusick nfs_read, /* read */ 5839672Smckusick nfs_write, /* write */ 5948054Smckusick nfs_ioctl, /* ioctl */ 6048054Smckusick nfs_select, /* select */ 6148054Smckusick nfs_mmap, /* mmap */ 6239672Smckusick nfs_fsync, /* fsync */ 6348054Smckusick nfs_seek, /* seek */ 6439672Smckusick nfs_remove, /* remove */ 6539672Smckusick nfs_link, /* link */ 6639672Smckusick nfs_rename, /* rename */ 6739672Smckusick nfs_mkdir, /* mkdir */ 6839672Smckusick nfs_rmdir, /* rmdir */ 6939672Smckusick nfs_symlink, /* symlink */ 7039672Smckusick nfs_readdir, /* readdir */ 7139672Smckusick nfs_readlink, /* readlink */ 7239672Smckusick nfs_abortop, /* abortop */ 7339672Smckusick nfs_inactive, /* inactive */ 7439672Smckusick nfs_reclaim, /* reclaim */ 7539672Smckusick nfs_lock, /* lock */ 7639672Smckusick nfs_unlock, /* unlock */ 7739672Smckusick nfs_bmap, /* bmap */ 7839672Smckusick nfs_strategy, /* strategy */ 7939672Smckusick nfs_print, /* print */ 8039906Smckusick nfs_islocked, /* islocked */ 8146201Smckusick nfs_advlock, /* advlock */ 8251573Smckusick nfs_blkatoff, /* blkatoff */ 8351573Smckusick nfs_vget, /* vget */ 8451573Smckusick nfs_valloc, /* valloc */ 8551573Smckusick nfs_vfree, /* vfree */ 8651573Smckusick nfs_truncate, /* truncate */ 8751573Smckusick nfs_update, /* update */ 8851573Smckusick bwrite, /* bwrite */ 8938414Smckusick }; 9038414Smckusick 9148054Smckusick /* 9248054Smckusick * Special device vnode ops 9348054Smckusick */ 9439441Smckusick struct vnodeops spec_nfsv2nodeops = { 9539599Smckusick spec_lookup, /* lookup */ 9648054Smckusick spec_create, /* create */ 9748054Smckusick spec_mknod, /* mknod */ 9839599Smckusick spec_open, /* open */ 9939599Smckusick spec_close, /* close */ 10039599Smckusick nfs_access, /* access */ 10139599Smckusick nfs_getattr, /* getattr */ 10239599Smckusick nfs_setattr, /* setattr */ 10339599Smckusick spec_read, /* read */ 10439599Smckusick spec_write, /* write */ 10539599Smckusick spec_ioctl, /* ioctl */ 10639599Smckusick spec_select, /* select */ 10748054Smckusick spec_mmap, /* mmap */ 10848054Smckusick spec_fsync, /* fsync */ 10948054Smckusick spec_seek, /* seek */ 11048054Smckusick spec_remove, /* remove */ 11148054Smckusick spec_link, /* link */ 11248054Smckusick spec_rename, /* rename */ 11348054Smckusick spec_mkdir, /* mkdir */ 11448054Smckusick spec_rmdir, /* rmdir */ 11548054Smckusick spec_symlink, /* symlink */ 11648054Smckusick spec_readdir, /* readdir */ 11748054Smckusick spec_readlink, /* readlink */ 11848054Smckusick spec_abortop, /* abortop */ 11939599Smckusick nfs_inactive, /* inactive */ 12039599Smckusick nfs_reclaim, /* reclaim */ 12139599Smckusick nfs_lock, /* lock */ 12239599Smckusick nfs_unlock, /* unlock */ 12339672Smckusick spec_bmap, /* bmap */ 12439599Smckusick spec_strategy, /* strategy */ 12539672Smckusick nfs_print, /* print */ 12639906Smckusick nfs_islocked, /* islocked */ 12746201Smckusick spec_advlock, /* advlock */ 12851573Smckusick spec_blkatoff, /* blkatoff */ 12951573Smckusick spec_vget, /* vget */ 13051573Smckusick spec_valloc, /* valloc */ 13151573Smckusick spec_vfree, /* vfree */ 13251573Smckusick spec_truncate, /* truncate */ 13351573Smckusick nfs_update, /* update */ 13451573Smckusick bwrite, /* bwrite */ 13538414Smckusick }; 13638414Smckusick 13740294Smckusick #ifdef FIFO 13840294Smckusick struct vnodeops fifo_nfsv2nodeops = { 13940294Smckusick fifo_lookup, /* lookup */ 14048054Smckusick fifo_create, /* create */ 14148054Smckusick fifo_mknod, /* mknod */ 14240294Smckusick fifo_open, /* open */ 14340294Smckusick fifo_close, /* close */ 14440294Smckusick nfs_access, /* access */ 14540294Smckusick nfs_getattr, /* getattr */ 14640294Smckusick nfs_setattr, /* setattr */ 14740294Smckusick fifo_read, /* read */ 14840294Smckusick fifo_write, /* write */ 14940294Smckusick fifo_ioctl, /* ioctl */ 15040294Smckusick fifo_select, /* select */ 15148054Smckusick fifo_mmap, /* mmap */ 15248054Smckusick fifo_fsync, /* fsync */ 15348054Smckusick fifo_seek, /* seek */ 15448054Smckusick fifo_remove, /* remove */ 15548054Smckusick fifo_link, /* link */ 15648054Smckusick fifo_rename, /* rename */ 15748054Smckusick fifo_mkdir, /* mkdir */ 15848054Smckusick fifo_rmdir, /* rmdir */ 15948054Smckusick fifo_symlink, /* symlink */ 16048054Smckusick fifo_readdir, /* readdir */ 16148054Smckusick fifo_readlink, /* readlink */ 16248054Smckusick fifo_abortop, /* abortop */ 16340294Smckusick nfs_inactive, /* inactive */ 16440294Smckusick nfs_reclaim, /* reclaim */ 16540294Smckusick nfs_lock, /* lock */ 16640294Smckusick nfs_unlock, /* unlock */ 16740294Smckusick fifo_bmap, /* bmap */ 16840294Smckusick fifo_badop, /* strategy */ 16940294Smckusick nfs_print, /* print */ 17040294Smckusick nfs_islocked, /* islocked */ 17146201Smckusick fifo_advlock, /* advlock */ 17251573Smckusick fifo_blkatoff, /* blkatoff */ 17351573Smckusick fifo_vget, /* vget */ 17451573Smckusick fifo_valloc, /* valloc */ 17551573Smckusick fifo_vfree, /* vfree */ 17651573Smckusick fifo_truncate, /* truncate */ 17751573Smckusick nfs_update, /* update */ 17851573Smckusick bwrite, /* bwrite */ 17940294Smckusick }; 18040294Smckusick #endif /* FIFO */ 18140294Smckusick 18248054Smckusick /* 18352196Smckusick * Global variables 18448054Smckusick */ 18538414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 18638414Smckusick extern u_long nfs_prog, nfs_vers; 18738414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 18838884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 18941905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 19046988Smckusick int nfs_numasync = 0; 19152436Smckusick #define DIRHDSIZ (sizeof (struct readdir) - (MAXNAMLEN + 1)) 19238414Smckusick 19338414Smckusick /* 19438414Smckusick * nfs null call from vfs. 19538414Smckusick */ 19652234Sheideman int 19752196Smckusick nfs_null(vp, cred, procp) 19838414Smckusick struct vnode *vp; 19938414Smckusick struct ucred *cred; 20052196Smckusick struct proc *procp; 20138414Smckusick { 20239488Smckusick caddr_t bpos, dpos; 20339488Smckusick int error = 0; 20439488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 20538414Smckusick 20652196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 20752196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 20838414Smckusick nfsm_reqdone; 20938414Smckusick return (error); 21038414Smckusick } 21138414Smckusick 21238414Smckusick /* 21338414Smckusick * nfs access vnode op. 21438414Smckusick * Essentially just get vattr and then imitate iaccess() 21538414Smckusick */ 21652234Sheideman int 21752196Smckusick nfs_access(vp, mode, cred, procp) 21838414Smckusick struct vnode *vp; 21938414Smckusick int mode; 22038414Smckusick register struct ucred *cred; 22152196Smckusick struct proc *procp; 22238414Smckusick { 22338414Smckusick register struct vattr *vap; 22438414Smckusick register gid_t *gp; 22538414Smckusick struct vattr vattr; 22638414Smckusick register int i; 22738414Smckusick int error; 22838414Smckusick 22938414Smckusick /* 23038414Smckusick * If you're the super-user, 23138414Smckusick * you always get access. 23238414Smckusick */ 23338414Smckusick if (cred->cr_uid == 0) 23438414Smckusick return (0); 23538414Smckusick vap = &vattr; 23652196Smckusick if (error = nfs_getattr(vp, vap, cred, procp)) 23738884Smacklem return (error); 23838414Smckusick /* 23938414Smckusick * Access check is based on only one of owner, group, public. 24038414Smckusick * If not owner, then check group. If not a member of the 24138414Smckusick * group, then check public access. 24238414Smckusick */ 24338414Smckusick if (cred->cr_uid != vap->va_uid) { 24438414Smckusick mode >>= 3; 24538414Smckusick gp = cred->cr_groups; 24638414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 24738414Smckusick if (vap->va_gid == *gp) 24838414Smckusick goto found; 24938414Smckusick mode >>= 3; 25038414Smckusick found: 25138414Smckusick ; 25238414Smckusick } 25338414Smckusick if ((vap->va_mode & mode) != 0) 25438414Smckusick return (0); 25538414Smckusick return (EACCES); 25638414Smckusick } 25738414Smckusick 25838414Smckusick /* 25938414Smckusick * nfs open vnode op 26038414Smckusick * Just check to see if the type is ok 26152196Smckusick * and that deletion is not in progress. 26238414Smckusick */ 26339488Smckusick /* ARGSUSED */ 26452234Sheideman int 26552196Smckusick nfs_open(vp, mode, cred, procp) 26652196Smckusick register struct vnode *vp; 26738414Smckusick int mode; 26838414Smckusick struct ucred *cred; 26952196Smckusick struct proc *procp; 27038414Smckusick { 27138414Smckusick 27252196Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 27338414Smckusick return (EACCES); 27452196Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 27552196Smckusick VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */ 27652196Smckusick return (0); 27738414Smckusick } 27838414Smckusick 27938414Smckusick /* 28038414Smckusick * nfs close vnode op 28138884Smacklem * For reg files, invalidate any buffer cache entries. 28238414Smckusick */ 28339488Smckusick /* ARGSUSED */ 28452234Sheideman int 28552196Smckusick nfs_close(vp, fflags, cred, procp) 28638414Smckusick register struct vnode *vp; 28738414Smckusick int fflags; 28838414Smckusick struct ucred *cred; 28952196Smckusick struct proc *procp; 29038414Smckusick { 29139488Smckusick register struct nfsnode *np = VTONFS(vp); 29239341Smckusick int error = 0; 29338414Smckusick 29452196Smckusick if ((np->n_flag & NMODIFIED) && 29552196Smckusick (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 29652196Smckusick vp->v_type == VREG) { 29741905Smckusick np->n_flag &= ~NMODIFIED; 29839751Smckusick vinvalbuf(vp, TRUE); 29941905Smckusick np->n_attrstamp = 0; 30039341Smckusick if (np->n_flag & NWRITEERR) { 30139341Smckusick np->n_flag &= ~NWRITEERR; 30239751Smckusick error = np->n_error; 30339341Smckusick } 30438884Smacklem } 30538414Smckusick return (error); 30638414Smckusick } 30738414Smckusick 30838414Smckusick /* 30938414Smckusick * nfs getattr call from vfs. 31038414Smckusick */ 31152234Sheideman int 31252196Smckusick nfs_getattr(vp, vap, cred, procp) 31339488Smckusick register struct vnode *vp; 31439488Smckusick struct vattr *vap; 31538414Smckusick struct ucred *cred; 31652196Smckusick struct proc *procp; 31738414Smckusick { 31839488Smckusick register caddr_t cp; 31939488Smckusick caddr_t bpos, dpos; 32039488Smckusick int error = 0; 32139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 32238414Smckusick 32338414Smckusick /* First look in the cache.. */ 32438414Smckusick if (nfs_getattrcache(vp, vap) == 0) 32538414Smckusick return (0); 32638414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 32752196Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 32838414Smckusick nfsm_fhtom(vp); 32952196Smckusick nfsm_request(vp, NFSPROC_GETATTR, procp, cred); 33038414Smckusick nfsm_loadattr(vp, vap); 33138414Smckusick nfsm_reqdone; 33238414Smckusick return (error); 33338414Smckusick } 33438414Smckusick 33538414Smckusick /* 33638414Smckusick * nfs setattr call. 33738414Smckusick */ 33852234Sheideman int 33952196Smckusick nfs_setattr(vp, vap, cred, procp) 34039488Smckusick register struct vnode *vp; 34138414Smckusick register struct vattr *vap; 34238414Smckusick struct ucred *cred; 34352196Smckusick struct proc *procp; 34438414Smckusick { 34538884Smacklem register struct nfsv2_sattr *sp; 34639488Smckusick register caddr_t cp; 34739488Smckusick register long t1; 34852196Smckusick caddr_t bpos, dpos, cp2; 34952196Smckusick u_long *tl; 35039488Smckusick int error = 0; 35139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 35252196Smckusick struct nfsnode *np = VTONFS(vp); 35352196Smckusick u_quad_t frev; 35438414Smckusick 35538414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 35652196Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR); 35738414Smckusick nfsm_fhtom(vp); 35838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 35938414Smckusick if (vap->va_mode == 0xffff) 36038884Smacklem sp->sa_mode = VNOVAL; 36138414Smckusick else 36238884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 36338414Smckusick if (vap->va_uid == 0xffff) 36438884Smacklem sp->sa_uid = VNOVAL; 36538414Smckusick else 36638884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 36738414Smckusick if (vap->va_gid == 0xffff) 36838884Smacklem sp->sa_gid = VNOVAL; 36938414Smckusick else 37038884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 37138884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 37244988Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec); 37344988Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 37444988Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 37544988Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 37644988Smckusick vap->va_atime.tv_sec != VNOVAL) { 37739359Smckusick if (np->n_flag & NMODIFIED) { 37839359Smckusick np->n_flag &= ~NMODIFIED; 37946988Smckusick if (vap->va_size == 0) 38046988Smckusick vinvalbuf(vp, FALSE); 38146988Smckusick else 38246988Smckusick vinvalbuf(vp, TRUE); 38339359Smckusick } 38439359Smckusick } 38552196Smckusick nfsm_request(vp, NFSPROC_SETATTR, procp, cred); 38638414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 38752196Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 38852196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 38952196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 39052196Smckusick fxdr_hyper(tl, &frev); 39152196Smckusick if (QUADGT(frev, np->n_brev)) 39252196Smckusick np->n_brev = frev; 39352196Smckusick } 39438414Smckusick nfsm_reqdone; 39538414Smckusick return (error); 39638414Smckusick } 39738414Smckusick 39838414Smckusick /* 39938414Smckusick * nfs lookup call, one step at a time... 40038414Smckusick * First look in cache 40138414Smckusick * If not found, unlock the directory nfsnode and do the rpc 40238414Smckusick */ 40352234Sheideman int 40452317Sheideman nfs_lookup(dvp, vpp, cnp) 40552234Sheideman struct vnode *dvp; 40652234Sheideman struct vnode **vpp; 40752234Sheideman struct componentname *cnp; 40838414Smckusick { 40938414Smckusick register struct vnode *vdp; 41048054Smckusick register u_long *tl; 41139488Smckusick register caddr_t cp; 41239488Smckusick register long t1, t2; 41352196Smckusick struct nfsmount *nmp; 41452196Smckusick struct nfsnode *tp; 41539488Smckusick caddr_t bpos, dpos, cp2; 41652196Smckusick time_t reqtime; 41739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 41838414Smckusick struct vnode *newvp; 41938414Smckusick long len; 42038414Smckusick nfsv2fh_t *fhp; 42138414Smckusick struct nfsnode *np; 42252234Sheideman int lockparent, wantparent, error = 0; 42352196Smckusick int nqlflag, cachable; 42452196Smckusick u_quad_t frev; 42538414Smckusick 42652234Sheideman *vpp = NULL; 42752234Sheideman if (dvp->v_type != VDIR) 42838414Smckusick return (ENOTDIR); 42952234Sheideman lockparent = cnp->cn_flags & LOCKPARENT; 43052234Sheideman wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 43152234Sheideman nmp = VFSTONFS(dvp->v_mount); 43252234Sheideman np = VTONFS(dvp); 43352234Sheideman if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 43438884Smacklem struct vattr vattr; 43538884Smacklem int vpid; 43638884Smacklem 43752234Sheideman vdp = *vpp; 43838884Smacklem vpid = vdp->v_id; 43938414Smckusick /* 44038884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 44138884Smacklem * for an explanation of the locking protocol 44238414Smckusick */ 44352234Sheideman if (dvp == vdp) { 44438425Smckusick VREF(vdp); 44539441Smckusick error = 0; 44652196Smckusick } else 44739441Smckusick error = vget(vdp); 44839441Smckusick if (!error) { 44940251Smckusick if (vpid == vdp->v_id) { 45052196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 45152234Sheideman if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 45252196Smckusick if (QUADNE(np->n_lrev, np->n_brev) || 45352196Smckusick (np->n_flag & NMODIFIED)) { 45452196Smckusick np->n_direofoffset = 0; 45552234Sheideman cache_purge(dvp); 45652196Smckusick np->n_flag &= ~NMODIFIED; 45752234Sheideman vinvalbuf(dvp, FALSE); 45852196Smckusick np->n_brev = np->n_lrev; 45952196Smckusick } else { 46052196Smckusick nfsstats.lookupcache_hits++; 46152234Sheideman if (cnp->cn_nameiop != LOOKUP && 46252234Sheideman (cnp->cn_flags&ISLASTCN)) 46352234Sheideman cnp->cn_flags |= SAVENAME; 46452196Smckusick return (0); 46552196Smckusick } 46652196Smckusick } 46752234Sheideman } else if (!nfs_getattr(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 46840251Smckusick vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) { 46939441Smckusick nfsstats.lookupcache_hits++; 47052234Sheideman if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 47152234Sheideman cnp->cn_flags |= SAVENAME; 47239441Smckusick return (0); 47340251Smckusick } 47447289Smckusick cache_purge(vdp); 47539441Smckusick } 47652196Smckusick vrele(vdp); 47738884Smacklem } 47852234Sheideman *vpp = NULLVP; 47952196Smckusick } 48039341Smckusick error = 0; 48138414Smckusick nfsstats.lookupcache_misses++; 48238414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 48352234Sheideman len = cnp->cn_namelen; 48452234Sheideman nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 48552196Smckusick 48652196Smckusick /* 48752196Smckusick * For nqnfs optionally piggyback a getlease request for the name 48852196Smckusick * being looked up. 48952196Smckusick */ 49052196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 49152196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 49252234Sheideman ((cnp->cn_flags&MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN)))) { 49352196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 49452196Smckusick *tl++ = txdr_unsigned(NQL_READ); 49552196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 49652196Smckusick } else { 49752196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 49852196Smckusick *tl = 0; 49952196Smckusick } 50052196Smckusick } 50152234Sheideman nfsm_fhtom(dvp); 50252234Sheideman nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 50352196Smckusick reqtime = time.tv_sec; 50452234Sheideman nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 50538414Smckusick nfsmout: 50638414Smckusick if (error) { 507*52823Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 508*52823Smckusick (cnp->cn_flags & ISLASTCN) && error == ENOENT) 509*52823Smckusick error = EJUSTRETURN; 51052234Sheideman if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 51152234Sheideman cnp->cn_flags |= SAVENAME; 51240483Smckusick return (error); 51338414Smckusick } 51452196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 51552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 51652196Smckusick if (*tl) { 51752196Smckusick nqlflag = fxdr_unsigned(int, *tl); 51852196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 51952196Smckusick cachable = fxdr_unsigned(int, *tl++); 52052196Smckusick reqtime += fxdr_unsigned(int, *tl++); 52152196Smckusick fxdr_hyper(tl, &frev); 52252196Smckusick } else 52352196Smckusick nqlflag = 0; 52452196Smckusick } 52552196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 52638414Smckusick 52738414Smckusick /* 52852196Smckusick * Handle RENAME case... 52938414Smckusick */ 53052234Sheideman if (cnp->cn_nameiop == RENAME && wantparent && (cnp->cn_flags&ISLASTCN)) { 53152196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 53238414Smckusick m_freem(mrep); 53338414Smckusick return (EISDIR); 53438414Smckusick } 53552234Sheideman if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 53638414Smckusick m_freem(mrep); 53738414Smckusick return (error); 53838414Smckusick } 53938414Smckusick newvp = NFSTOV(np); 54039459Smckusick if (error = 54139459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 54252196Smckusick vrele(newvp); 54338414Smckusick m_freem(mrep); 54438414Smckusick return (error); 54538414Smckusick } 54652234Sheideman *vpp = newvp; 54745037Smckusick m_freem(mrep); 54852234Sheideman cnp->cn_flags |= SAVENAME; 54938414Smckusick return (0); 55038414Smckusick } 55138414Smckusick 55252196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 55352234Sheideman VREF(dvp); 55452234Sheideman newvp = dvp; 55538414Smckusick } else { 55652234Sheideman if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 55738414Smckusick m_freem(mrep); 55838414Smckusick return (error); 55938414Smckusick } 56038414Smckusick newvp = NFSTOV(np); 56138414Smckusick } 56239459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 56352196Smckusick vrele(newvp); 56438414Smckusick m_freem(mrep); 56538414Smckusick return (error); 56638414Smckusick } 56738414Smckusick m_freem(mrep); 56852234Sheideman *vpp = newvp; 56952234Sheideman if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 57052234Sheideman cnp->cn_flags |= SAVENAME; 57152234Sheideman if ((cnp->cn_flags&MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN))) { 57252196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 57352196Smckusick np->n_ctime = np->n_vattr.va_ctime.tv_sec; 57452196Smckusick else if (nqlflag && reqtime > time.tv_sec) { 57552196Smckusick if (np->n_tnext) { 57652196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 57752196Smckusick nmp->nm_tprev = np->n_tprev; 57852196Smckusick else 57952196Smckusick np->n_tnext->n_tprev = np->n_tprev; 58052196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 58152196Smckusick nmp->nm_tnext = np->n_tnext; 58252196Smckusick else 58352196Smckusick np->n_tprev->n_tnext = np->n_tnext; 58452196Smckusick if (nqlflag == NQL_WRITE) 58552196Smckusick np->n_flag |= NQNFSWRITE; 58652196Smckusick } else if (nqlflag == NQL_READ) 58752196Smckusick np->n_flag &= ~NQNFSWRITE; 58852196Smckusick else 58952196Smckusick np->n_flag |= NQNFSWRITE; 59052196Smckusick if (cachable) 59152196Smckusick np->n_flag &= ~NQNFSNONCACHE; 59252196Smckusick else 59352196Smckusick np->n_flag |= NQNFSNONCACHE; 59452196Smckusick np->n_expiry = reqtime; 59552196Smckusick np->n_lrev = frev; 59652196Smckusick tp = nmp->nm_tprev; 59752196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 59852196Smckusick tp = tp->n_tprev; 59952196Smckusick if (tp == (struct nfsnode *)nmp) { 60052196Smckusick np->n_tnext = nmp->nm_tnext; 60152196Smckusick nmp->nm_tnext = np; 60252196Smckusick } else { 60352196Smckusick np->n_tnext = tp->n_tnext; 60452196Smckusick tp->n_tnext = np; 60552196Smckusick } 60652196Smckusick np->n_tprev = tp; 60752196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 60852196Smckusick nmp->nm_tprev = np; 60952196Smckusick else 61052196Smckusick np->n_tnext->n_tprev = np; 61152196Smckusick } 61252234Sheideman cache_enter(dvp, *vpp, cnp); 61340251Smckusick } 61452196Smckusick return (0); 61538414Smckusick } 61638414Smckusick 61738414Smckusick /* 61841905Smckusick * nfs read call. 61941905Smckusick * Just call nfs_bioread() to do the work. 62041905Smckusick */ 62152234Sheideman int 62241905Smckusick nfs_read(vp, uiop, ioflag, cred) 62341905Smckusick register struct vnode *vp; 62441905Smckusick struct uio *uiop; 62541905Smckusick int ioflag; 62641905Smckusick struct ucred *cred; 62741905Smckusick { 62841905Smckusick if (vp->v_type != VREG) 62941905Smckusick return (EPERM); 63041905Smckusick return (nfs_bioread(vp, uiop, ioflag, cred)); 63141905Smckusick } 63241905Smckusick 63341905Smckusick /* 63438414Smckusick * nfs readlink call 63538414Smckusick */ 63652234Sheideman int 63738414Smckusick nfs_readlink(vp, uiop, cred) 63841905Smckusick struct vnode *vp; 63941905Smckusick struct uio *uiop; 64041905Smckusick struct ucred *cred; 64141905Smckusick { 64241905Smckusick if (vp->v_type != VLNK) 64341905Smckusick return (EPERM); 64441905Smckusick return (nfs_bioread(vp, uiop, 0, cred)); 64541905Smckusick } 64641905Smckusick 64741905Smckusick /* 64841905Smckusick * Do a readlink rpc. 64941905Smckusick * Called by nfs_doio() from below the buffer cache. 65041905Smckusick */ 65152234Sheideman int 65248054Smckusick nfs_readlinkrpc(vp, uiop, cred) 65339488Smckusick register struct vnode *vp; 65438414Smckusick struct uio *uiop; 65538414Smckusick struct ucred *cred; 65638414Smckusick { 65748054Smckusick register u_long *tl; 65839488Smckusick register caddr_t cp; 65939488Smckusick register long t1; 66039488Smckusick caddr_t bpos, dpos, cp2; 66139488Smckusick int error = 0; 66239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 66338414Smckusick long len; 66438414Smckusick 66538414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 66652196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 66738414Smckusick nfsm_fhtom(vp); 66852196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 66938414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 67038414Smckusick nfsm_mtouio(uiop, len); 67138414Smckusick nfsm_reqdone; 67238414Smckusick return (error); 67338414Smckusick } 67438414Smckusick 67538414Smckusick /* 67641905Smckusick * nfs read rpc call 67741905Smckusick * Ditto above 67838414Smckusick */ 67952234Sheideman int 68048054Smckusick nfs_readrpc(vp, uiop, cred) 68139488Smckusick register struct vnode *vp; 68238414Smckusick struct uio *uiop; 68338414Smckusick struct ucred *cred; 68438414Smckusick { 68548054Smckusick register u_long *tl; 68639488Smckusick register caddr_t cp; 68739488Smckusick register long t1; 68839488Smckusick caddr_t bpos, dpos, cp2; 68939488Smckusick int error = 0; 69039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 69138414Smckusick struct nfsmount *nmp; 69238414Smckusick long len, retlen, tsiz; 69338414Smckusick 69441398Smckusick nmp = VFSTONFS(vp->v_mount); 69538414Smckusick tsiz = uiop->uio_resid; 69638414Smckusick while (tsiz > 0) { 69738414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 69838414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 69952196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 70038414Smckusick nfsm_fhtom(vp); 70148054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 70248054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 70348054Smckusick *tl++ = txdr_unsigned(len); 70448054Smckusick *tl = 0; 70552196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 70638414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 70738414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 70838414Smckusick nfsm_mtouio(uiop, retlen); 70938414Smckusick m_freem(mrep); 71038414Smckusick if (retlen < len) 71138414Smckusick tsiz = 0; 71238414Smckusick else 71338414Smckusick tsiz -= len; 71438414Smckusick } 71538414Smckusick nfsmout: 71638414Smckusick return (error); 71738414Smckusick } 71838414Smckusick 71938414Smckusick /* 72038414Smckusick * nfs write call 72138414Smckusick */ 72252234Sheideman int 72348054Smckusick nfs_writerpc(vp, uiop, cred) 72439488Smckusick register struct vnode *vp; 72538414Smckusick struct uio *uiop; 72638414Smckusick struct ucred *cred; 72738414Smckusick { 72848054Smckusick register u_long *tl; 72939488Smckusick register caddr_t cp; 73039488Smckusick register long t1; 73152196Smckusick caddr_t bpos, dpos, cp2; 73239488Smckusick int error = 0; 73339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73438414Smckusick struct nfsmount *nmp; 73552196Smckusick struct nfsnode *np = VTONFS(vp); 73652196Smckusick u_quad_t frev; 73738414Smckusick long len, tsiz; 73838414Smckusick 73941398Smckusick nmp = VFSTONFS(vp->v_mount); 74038414Smckusick tsiz = uiop->uio_resid; 74138414Smckusick while (tsiz > 0) { 74238414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 74338414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 74452196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 74552196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 74638414Smckusick nfsm_fhtom(vp); 74748054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 74848054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 74948054Smckusick *(tl+3) = txdr_unsigned(len); 75038414Smckusick nfsm_uiotom(uiop, len); 75152196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 75238414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 75352196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 75452196Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec; 75552196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 75652196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 75752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 75852196Smckusick fxdr_hyper(tl, &frev); 75952196Smckusick if (QUADGT(frev, np->n_brev)) 76052196Smckusick np->n_brev = frev; 76152196Smckusick } 76238414Smckusick m_freem(mrep); 76338414Smckusick tsiz -= len; 76438414Smckusick } 76538414Smckusick nfsmout: 76652196Smckusick if (error) 76752196Smckusick uiop->uio_resid = tsiz; 76838414Smckusick return (error); 76938414Smckusick } 77038414Smckusick 77138414Smckusick /* 77239459Smckusick * nfs mknod call 77342246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 77442246Smckusick * set to specify the file type and the size field for rdev. 77539459Smckusick */ 77639459Smckusick /* ARGSUSED */ 77752234Sheideman int 77852317Sheideman nfs_mknod(dvp, vpp, cnp, vap) 77952234Sheideman struct vnode *dvp; 78052234Sheideman struct vnode **vpp; 78152234Sheideman struct componentname *cnp; 78252234Sheideman struct vattr *vap; 78339459Smckusick { 78442246Smckusick register struct nfsv2_sattr *sp; 78548054Smckusick register u_long *tl; 78642246Smckusick register caddr_t cp; 78752196Smckusick register long t2; 78842246Smckusick caddr_t bpos, dpos; 78942246Smckusick int error = 0; 79042246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 79142246Smckusick u_long rdev; 79239459Smckusick 79342246Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 79442246Smckusick rdev = txdr_unsigned(vap->va_rdev); 79542246Smckusick #ifdef FIFO 79642246Smckusick else if (vap->va_type == VFIFO) 79742246Smckusick rdev = 0xffffffff; 79842246Smckusick #endif /* FIFO */ 79942246Smckusick else { 80052234Sheideman VOP_ABORTOP(dvp, cnp); 80152234Sheideman vput(dvp); 80242246Smckusick return (EOPNOTSUPP); 80342246Smckusick } 80442246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 80552234Sheideman nfsm_reqhead(dvp, NFSPROC_CREATE, 80652234Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 80752234Sheideman nfsm_fhtom(dvp); 80852234Sheideman nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 80942246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 81042246Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 81152234Sheideman sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 81252234Sheideman sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 81342246Smckusick sp->sa_size = rdev; 81442246Smckusick /* or should these be VNOVAL ?? */ 81542246Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 81642246Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 81752234Sheideman nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 81842246Smckusick nfsm_reqdone; 81952234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 82052234Sheideman VTONFS(dvp)->n_flag |= NMODIFIED; 82152234Sheideman vrele(dvp); 82242246Smckusick return (error); 82339459Smckusick } 82439459Smckusick 82539459Smckusick /* 82638414Smckusick * nfs file create call 82738414Smckusick */ 82852234Sheideman int 82952317Sheideman nfs_create(dvp, vpp, cnp, vap) 83052234Sheideman struct vnode *dvp; 83152234Sheideman struct vnode **vpp; 83252234Sheideman struct componentname *cnp; 83352234Sheideman struct vattr *vap; 83438414Smckusick { 83538884Smacklem register struct nfsv2_sattr *sp; 83648054Smckusick register u_long *tl; 83739488Smckusick register caddr_t cp; 83839488Smckusick register long t1, t2; 83939488Smckusick caddr_t bpos, dpos, cp2; 84039488Smckusick int error = 0; 84139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 84238414Smckusick 84338414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 84452234Sheideman nfsm_reqhead(dvp, NFSPROC_CREATE, 84552234Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 84652234Sheideman nfsm_fhtom(dvp); 84752234Sheideman nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 84838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 84946988Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 85052234Sheideman sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 85152234Sheideman sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 85238884Smacklem sp->sa_size = txdr_unsigned(0); 85338414Smckusick /* or should these be VNOVAL ?? */ 85438884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 85538884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 85652234Sheideman nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 85752234Sheideman nfsm_mtofh(dvp, *vpp); 85838414Smckusick nfsm_reqdone; 85952234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 86052234Sheideman VTONFS(dvp)->n_flag |= NMODIFIED; 86152234Sheideman vrele(dvp); 86238414Smckusick return (error); 86338414Smckusick } 86438414Smckusick 86538414Smckusick /* 86638414Smckusick * nfs file remove call 86741905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 86841905Smckusick * other processes using the vnode is renamed instead of removed and then 86939341Smckusick * removed later on the last close. 87041905Smckusick * - If v_usecount > 1 87139341Smckusick * If a rename is not already in the works 87239341Smckusick * call nfs_sillyrename() to set it up 87339341Smckusick * else 87439341Smckusick * do the remove rpc 87538414Smckusick */ 87652234Sheideman int 87752317Sheideman nfs_remove(dvp, vp, cnp) 87852234Sheideman struct vnode *dvp, *vp; 87952234Sheideman struct componentname *cnp; 88038414Smckusick { 88152234Sheideman register struct nfsnode *np = VTONFS(vp); 88248054Smckusick register u_long *tl; 88339488Smckusick register caddr_t cp; 88452196Smckusick register long t2; 88539488Smckusick caddr_t bpos, dpos; 88639488Smckusick int error = 0; 88739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 88838414Smckusick 88939810Smckusick if (vp->v_usecount > 1) { 89039341Smckusick if (!np->n_sillyrename) 89152317Sheideman error = nfs_sillyrename(dvp, vp, cnp); 89239341Smckusick } else { 89352196Smckusick /* 89452196Smckusick * Purge the name cache so that the chance of a lookup for 89552196Smckusick * the name succeeding while the remove is in progress is 89652196Smckusick * minimized. Without node locking it can still happen, such 89752196Smckusick * that an I/O op returns ESTALE, but since you get this if 89852196Smckusick * another host removes the file.. 89952196Smckusick */ 90052196Smckusick cache_purge(vp); 90152196Smckusick /* 90252196Smckusick * Throw away biocache buffers. Mainly to avoid 90352196Smckusick * unnecessary delayed writes. 90452196Smckusick */ 90552196Smckusick vinvalbuf(vp, FALSE); 90652196Smckusick /* Do the rpc */ 90738414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 90852234Sheideman nfsm_reqhead(dvp, NFSPROC_REMOVE, 90952234Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 91052234Sheideman nfsm_fhtom(dvp); 91152234Sheideman nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 91252234Sheideman nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 91338414Smckusick nfsm_reqdone; 91452234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 91552234Sheideman VTONFS(dvp)->n_flag |= NMODIFIED; 91639751Smckusick /* 91739751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 91839751Smckusick * the reply to the retransmitted request will be ENOENT 91939751Smckusick * since the file was in fact removed 92039751Smckusick * Therefore, we cheat and return success. 92139751Smckusick */ 92239751Smckusick if (error == ENOENT) 92339751Smckusick error = 0; 92438414Smckusick } 92540042Smckusick np->n_attrstamp = 0; 92652234Sheideman vrele(dvp); 92752196Smckusick vrele(vp); 92838414Smckusick return (error); 92938414Smckusick } 93038414Smckusick 93138414Smckusick /* 93238414Smckusick * nfs file remove rpc called from nfs_inactive 93338414Smckusick */ 93452234Sheideman int 93552196Smckusick nfs_removeit(sp, procp) 93648364Smckusick register struct sillyrename *sp; 93752196Smckusick struct proc *procp; 93838414Smckusick { 93948054Smckusick register u_long *tl; 94039488Smckusick register caddr_t cp; 94152196Smckusick register long t2; 94239488Smckusick caddr_t bpos, dpos; 94339488Smckusick int error = 0; 94439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 94538414Smckusick 94638414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 94752196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 94848364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 94948364Smckusick nfsm_fhtom(sp->s_dvp); 95048364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 95152196Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, procp, sp->s_cred); 95238414Smckusick nfsm_reqdone; 95348364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 95438414Smckusick return (error); 95538414Smckusick } 95638414Smckusick 95738414Smckusick /* 95838414Smckusick * nfs file rename call 95938414Smckusick */ 96052234Sheideman int 96152234Sheideman nfs_rename(fdvp, fvp, fcnp, 96252317Sheideman tdvp, tvp, tcnp) 96352234Sheideman struct vnode *fdvp, *fvp; 96452234Sheideman struct componentname *fcnp; 96552234Sheideman struct vnode *tdvp, *tvp; 96652234Sheideman struct componentname *tcnp; 96738414Smckusick { 96848054Smckusick register u_long *tl; 96939488Smckusick register caddr_t cp; 97052196Smckusick register long t2; 97139488Smckusick caddr_t bpos, dpos; 97239488Smckusick int error = 0; 97339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97438414Smckusick 97538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 97652234Sheideman nfsm_reqhead(fdvp, NFSPROC_RENAME, 97752234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 97852234Sheideman nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 97952234Sheideman nfsm_fhtom(fdvp); 98052234Sheideman nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 98152234Sheideman nfsm_fhtom(tdvp); 98252234Sheideman nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 98352234Sheideman nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 98438414Smckusick nfsm_reqdone; 98552234Sheideman VTONFS(fdvp)->n_flag |= NMODIFIED; 98652234Sheideman VTONFS(tdvp)->n_flag |= NMODIFIED; 98752234Sheideman if (fvp->v_type == VDIR) { 98852234Sheideman if (tvp != NULL && tvp->v_type == VDIR) 98952234Sheideman cache_purge(tdvp); 99052234Sheideman cache_purge(fdvp); 99138414Smckusick } 99252234Sheideman if (tdvp == tvp) 99352234Sheideman vrele(tdvp); 99443360Smckusick else 99552234Sheideman vput(tdvp); 99652234Sheideman if (tvp) 99752234Sheideman vput(tvp); 99852234Sheideman vrele(fdvp); 99952234Sheideman vrele(fvp); 100040112Smckusick /* 100140112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 100240112Smckusick */ 100340112Smckusick if (error == ENOENT) 100440112Smckusick error = 0; 100538414Smckusick return (error); 100638414Smckusick } 100738414Smckusick 100838414Smckusick /* 100941905Smckusick * nfs file rename rpc called from nfs_remove() above 101038414Smckusick */ 101152234Sheideman int 101252234Sheideman nfs_renameit(sdvp, scnp, sp) 101352234Sheideman struct vnode *sdvp; 101452234Sheideman struct componentname *scnp; 101548364Smckusick register struct sillyrename *sp; 101638414Smckusick { 101748054Smckusick register u_long *tl; 101839488Smckusick register caddr_t cp; 101952196Smckusick register long t2; 102039488Smckusick caddr_t bpos, dpos; 102139488Smckusick int error = 0; 102239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 102338414Smckusick 102438414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 102552234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 102652234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 102752196Smckusick nfsm_rndup(sp->s_namlen)); 102852234Sheideman nfsm_fhtom(sdvp); 102952234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 103052234Sheideman nfsm_fhtom(sdvp); 103148364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 103252234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 103338414Smckusick nfsm_reqdone; 103452234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 103552234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 103638414Smckusick return (error); 103738414Smckusick } 103838414Smckusick 103938414Smckusick /* 104038414Smckusick * nfs hard link create call 104138414Smckusick */ 104252234Sheideman int 1043*52823Smckusick nfs_link(tdvp, vp, cnp) 1044*52823Smckusick struct vnode *tdvp; 104552234Sheideman register struct vnode *vp; /* source vnode */ 104652234Sheideman struct componentname *cnp; 104738414Smckusick { 104848054Smckusick register u_long *tl; 104939488Smckusick register caddr_t cp; 105052196Smckusick register long t2; 105139488Smckusick caddr_t bpos, dpos; 105239488Smckusick int error = 0; 105339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 105438414Smckusick 105538414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 105652196Smckusick nfsm_reqhead(vp, NFSPROC_LINK, 105752234Sheideman NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 105838414Smckusick nfsm_fhtom(vp); 105952234Sheideman nfsm_fhtom(tdvp); 106052234Sheideman nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 106152234Sheideman nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 106238414Smckusick nfsm_reqdone; 106352234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 106440042Smckusick VTONFS(vp)->n_attrstamp = 0; 106552234Sheideman VTONFS(tdvp)->n_flag |= NMODIFIED; 106652234Sheideman vrele(tdvp); 106740112Smckusick /* 106840112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 106940112Smckusick */ 107040112Smckusick if (error == EEXIST) 107140112Smckusick error = 0; 107238414Smckusick return (error); 107338414Smckusick } 107438414Smckusick 107538414Smckusick /* 107638414Smckusick * nfs symbolic link create call 107738414Smckusick */ 107852234Sheideman /* start here */ 107952234Sheideman int 108052317Sheideman nfs_symlink(dvp, vpp, cnp, vap, nm) 108152234Sheideman struct vnode *dvp; 108252234Sheideman struct vnode **vpp; 108352234Sheideman struct componentname *cnp; 108438414Smckusick struct vattr *vap; 108552196Smckusick char *nm; 108638414Smckusick { 108738884Smacklem register struct nfsv2_sattr *sp; 108848054Smckusick register u_long *tl; 108939488Smckusick register caddr_t cp; 109052196Smckusick register long t2; 109139488Smckusick caddr_t bpos, dpos; 109252196Smckusick int slen, error = 0; 109339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 109438414Smckusick 109538414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 109652196Smckusick slen = strlen(nm); 109752234Sheideman nfsm_reqhead(dvp, NFSPROC_SYMLINK, 109852234Sheideman NFSX_FH+2*NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR); 109952234Sheideman nfsm_fhtom(dvp); 110052234Sheideman nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 110152196Smckusick nfsm_strtom(nm, slen, NFS_MAXPATHLEN); 110238884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 110338884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 110452234Sheideman sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 110552234Sheideman sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 110638884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 110740112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 110838884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 110952234Sheideman nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 111038414Smckusick nfsm_reqdone; 111152234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 111252234Sheideman VTONFS(dvp)->n_flag |= NMODIFIED; 111352234Sheideman vrele(dvp); 111440112Smckusick /* 111540112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 111640112Smckusick */ 111740112Smckusick if (error == EEXIST) 111840112Smckusick error = 0; 111938414Smckusick return (error); 112038414Smckusick } 112138414Smckusick 112238414Smckusick /* 112338414Smckusick * nfs make dir call 112438414Smckusick */ 112552234Sheideman int 112652317Sheideman nfs_mkdir(dvp, vpp, cnp, vap) 112752234Sheideman struct vnode *dvp; 112852234Sheideman struct vnode **vpp; 112952234Sheideman struct componentname *cnp; 113038414Smckusick struct vattr *vap; 113138414Smckusick { 113238884Smacklem register struct nfsv2_sattr *sp; 113348054Smckusick register u_long *tl; 113439488Smckusick register caddr_t cp; 113539488Smckusick register long t1, t2; 113641905Smckusick register int len; 113739488Smckusick caddr_t bpos, dpos, cp2; 113841905Smckusick int error = 0, firsttry = 1; 113939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 114038414Smckusick 114152234Sheideman len = cnp->cn_namelen; 114238414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 114352234Sheideman nfsm_reqhead(dvp, NFSPROC_MKDIR, 114441905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 114552234Sheideman nfsm_fhtom(dvp); 114652234Sheideman nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 114738884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 114838884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 114952234Sheideman sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 115052234Sheideman sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 115138884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 115240112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 115338884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 115452234Sheideman nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 115552234Sheideman nfsm_mtofh(dvp, *vpp); 115638414Smckusick nfsm_reqdone; 115752234Sheideman VTONFS(dvp)->n_flag |= NMODIFIED; 115840112Smckusick /* 115941905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 116041905Smckusick * if we can succeed in looking up the directory. 116141905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 116241905Smckusick * is above the if on errors. (Ugh) 116340112Smckusick */ 116441905Smckusick if (error == EEXIST && firsttry) { 116541905Smckusick firsttry = 0; 116640112Smckusick error = 0; 116741905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 116852234Sheideman *vpp = NULL; 116952234Sheideman nfsm_reqhead(dvp, NFSPROC_LOOKUP, 117041905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 117152234Sheideman nfsm_fhtom(dvp); 117252234Sheideman nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 117352234Sheideman nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 117452234Sheideman nfsm_mtofh(dvp, *vpp); 117552234Sheideman if ((*vpp)->v_type != VDIR) { 117652234Sheideman vput(*vpp); 117741905Smckusick error = EEXIST; 117841905Smckusick } 117941905Smckusick m_freem(mrep); 118041905Smckusick } 118152234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 118252234Sheideman vrele(dvp); 118338414Smckusick return (error); 118438414Smckusick } 118538414Smckusick 118638414Smckusick /* 118738414Smckusick * nfs remove directory call 118838414Smckusick */ 118952234Sheideman int 119052317Sheideman nfs_rmdir(dvp, vp, cnp) 119152234Sheideman struct vnode *dvp, *vp; 119252234Sheideman struct componentname *cnp; 119338414Smckusick { 119448054Smckusick register u_long *tl; 119539488Smckusick register caddr_t cp; 119652196Smckusick register long t2; 119739488Smckusick caddr_t bpos, dpos; 119839488Smckusick int error = 0; 119939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 120038414Smckusick 120152234Sheideman if (dvp == vp) { 120252234Sheideman vrele(dvp); 120352234Sheideman vrele(dvp); 120452234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 120538414Smckusick return (EINVAL); 120638414Smckusick } 120738414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 120852234Sheideman nfsm_reqhead(dvp, NFSPROC_RMDIR, 120952234Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 121052234Sheideman nfsm_fhtom(dvp); 121152234Sheideman nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 121252234Sheideman nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 121338414Smckusick nfsm_reqdone; 121452234Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 121552234Sheideman VTONFS(dvp)->n_flag |= NMODIFIED; 121652234Sheideman cache_purge(dvp); 121752234Sheideman cache_purge(vp); 121852234Sheideman vrele(vp); 121952234Sheideman vrele(dvp); 122040112Smckusick /* 122140112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 122240112Smckusick */ 122340112Smckusick if (error == ENOENT) 122440112Smckusick error = 0; 122538414Smckusick return (error); 122638414Smckusick } 122738414Smckusick 122838414Smckusick /* 122938414Smckusick * nfs readdir call 123038414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 123138414Smckusick * order so that it looks more sensible. This appears consistent with the 123238414Smckusick * Ultrix implementation of NFS. 123338414Smckusick */ 123452234Sheideman int 123540296Smckusick nfs_readdir(vp, uiop, cred, eofflagp) 123639488Smckusick register struct vnode *vp; 123738414Smckusick struct uio *uiop; 123838414Smckusick struct ucred *cred; 123940296Smckusick int *eofflagp; 124038414Smckusick { 124141905Smckusick register struct nfsnode *np = VTONFS(vp); 124241905Smckusick int tresid, error; 124341905Smckusick struct vattr vattr; 124441905Smckusick 124541905Smckusick if (vp->v_type != VDIR) 124641905Smckusick return (EPERM); 124741905Smckusick /* 124841905Smckusick * First, check for hit on the EOF offset cache 124941905Smckusick */ 125041905Smckusick if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset && 125152196Smckusick (np->n_flag & NMODIFIED) == 0) { 125252196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 125352196Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 125452196Smckusick *eofflagp = 1; 125552196Smckusick nfsstats.direofcache_hits++; 125652196Smckusick return (0); 125752196Smckusick } 125852196Smckusick } else if (nfs_getattr(vp, &vattr, cred, uiop->uio_procp) == 0 && 125952196Smckusick np->n_mtime == vattr.va_mtime.tv_sec) { 126052196Smckusick *eofflagp = 1; 126152196Smckusick nfsstats.direofcache_hits++; 126252196Smckusick return (0); 126352196Smckusick } 126441905Smckusick } 126541905Smckusick 126641905Smckusick /* 126741905Smckusick * Call nfs_bioread() to do the real work. 126841905Smckusick */ 126941905Smckusick tresid = uiop->uio_resid; 127041905Smckusick error = nfs_bioread(vp, uiop, 0, cred); 127141905Smckusick 127241905Smckusick if (!error && uiop->uio_resid == tresid) { 127341905Smckusick *eofflagp = 1; 127441905Smckusick nfsstats.direofcache_misses++; 127541905Smckusick } else 127641905Smckusick *eofflagp = 0; 127741905Smckusick return (error); 127841905Smckusick } 127941905Smckusick 128041905Smckusick /* 128141905Smckusick * Readdir rpc call. 128241905Smckusick * Called from below the buffer cache by nfs_doio(). 128341905Smckusick */ 128452234Sheideman int 128548054Smckusick nfs_readdirrpc(vp, uiop, cred) 128641905Smckusick register struct vnode *vp; 128741905Smckusick struct uio *uiop; 128841905Smckusick struct ucred *cred; 128941905Smckusick { 129038414Smckusick register long len; 129152436Smckusick register struct readdir *dp; 129248054Smckusick register u_long *tl; 129339488Smckusick register caddr_t cp; 129439488Smckusick register long t1; 129541905Smckusick long tlen, lastlen; 129639488Smckusick caddr_t bpos, dpos, cp2; 129739488Smckusick int error = 0; 129839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 129938414Smckusick struct mbuf *md2; 130038414Smckusick caddr_t dpos2; 130138414Smckusick int siz; 130240296Smckusick int more_dirs = 1; 130338414Smckusick off_t off, savoff; 130452436Smckusick struct readdir *savdp; 130540296Smckusick struct nfsmount *nmp; 130640296Smckusick struct nfsnode *np = VTONFS(vp); 130740296Smckusick long tresid; 130838414Smckusick 130941398Smckusick nmp = VFSTONFS(vp->v_mount); 131040296Smckusick tresid = uiop->uio_resid; 131140296Smckusick /* 131240296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 131348054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 131441905Smckusick * The stopping criteria is EOF or buffer full. 131540296Smckusick */ 131648054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 131740296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 131852196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 131952196Smckusick NFSX_FH+2*NFSX_UNSIGNED); 132040296Smckusick nfsm_fhtom(vp); 132148054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 132248054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 132348054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 132448054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 132552196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 132640296Smckusick siz = 0; 132752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 132848054Smckusick more_dirs = fxdr_unsigned(int, *tl); 132940296Smckusick 133040296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 133140296Smckusick dpos2 = dpos; 133240296Smckusick md2 = md; 133340296Smckusick 133440296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 133541905Smckusick off = uiop->uio_offset; 133642246Smckusick #ifdef lint 133752436Smckusick dp = (struct readdir *)0; 133842246Smckusick #endif /* lint */ 133940296Smckusick while (more_dirs && siz < uiop->uio_resid) { 134040296Smckusick savoff = off; /* Hold onto offset and dp */ 134140296Smckusick savdp = dp; 134252196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 134352436Smckusick dp = (struct readdir *)tl; 134448054Smckusick dp->d_ino = fxdr_unsigned(u_long, *tl++); 134548054Smckusick len = fxdr_unsigned(int, *tl); 134640296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 134740296Smckusick error = EBADRPC; 134840296Smckusick m_freem(mrep); 134940296Smckusick goto nfsmout; 135040296Smckusick } 135140296Smckusick dp->d_namlen = (u_short)len; 135240296Smckusick nfsm_adv(len); /* Point past name */ 135340296Smckusick tlen = nfsm_rndup(len); 135440296Smckusick /* 135540296Smckusick * This should not be necessary, but some servers have 135640296Smckusick * broken XDR such that these bytes are not null filled. 135740296Smckusick */ 135840296Smckusick if (tlen != len) { 135940296Smckusick *dpos = '\0'; /* Null-terminate */ 136040296Smckusick nfsm_adv(tlen - len); 136140296Smckusick len = tlen; 136240296Smckusick } 136352196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 136448054Smckusick off = fxdr_unsigned(off_t, *tl); 136548054Smckusick *tl++ = 0; /* Ensures null termination of name */ 136648054Smckusick more_dirs = fxdr_unsigned(int, *tl); 136740296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 136840296Smckusick siz += dp->d_reclen; 136940296Smckusick } 137040296Smckusick /* 137140296Smckusick * If at end of rpc data, get the eof boolean 137240296Smckusick */ 137340296Smckusick if (!more_dirs) { 137452196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 137548054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 137638414Smckusick 137740296Smckusick /* 137840296Smckusick * If at EOF, cache directory offset 137940296Smckusick */ 138041905Smckusick if (!more_dirs) 138140296Smckusick np->n_direofoffset = off; 138238414Smckusick } 138340296Smckusick /* 138440296Smckusick * If there is too much to fit in the data buffer, use savoff and 138540296Smckusick * savdp to trim off the last record. 138640296Smckusick * --> we are not at eof 138740296Smckusick */ 138840296Smckusick if (siz > uiop->uio_resid) { 138940296Smckusick off = savoff; 139040296Smckusick siz -= dp->d_reclen; 139140296Smckusick dp = savdp; 139240296Smckusick more_dirs = 0; /* Paranoia */ 139340113Smckusick } 139440296Smckusick if (siz > 0) { 139541905Smckusick lastlen = dp->d_reclen; 139640296Smckusick md = md2; 139740296Smckusick dpos = dpos2; 139840296Smckusick nfsm_mtouio(uiop, siz); 139940296Smckusick uiop->uio_offset = off; 140040296Smckusick } else 140140296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 140240296Smckusick m_freem(mrep); 140338414Smckusick } 140441905Smckusick /* 140548054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 140641905Smckusick * by increasing d_reclen for the last record. 140741905Smckusick */ 140841905Smckusick if (uiop->uio_resid < tresid) { 140948054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 141041905Smckusick if (len > 0) { 141152436Smckusick dp = (struct readdir *) 141241905Smckusick (uiop->uio_iov->iov_base - lastlen); 141341905Smckusick dp->d_reclen += len; 141441905Smckusick uiop->uio_iov->iov_base += len; 141541905Smckusick uiop->uio_iov->iov_len -= len; 141641905Smckusick uiop->uio_resid -= len; 141741905Smckusick } 141841905Smckusick } 141940296Smckusick nfsmout: 142038414Smckusick return (error); 142138414Smckusick } 142238414Smckusick 142352196Smckusick /* 142452196Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when 142552196Smckusick * the "rdirlook" mount option is specified. 142652196Smckusick */ 142752234Sheideman int 142852196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 142952196Smckusick struct vnode *vp; 143052196Smckusick register struct uio *uiop; 143152196Smckusick struct ucred *cred; 143252196Smckusick { 143352196Smckusick register int len; 143452436Smckusick register struct readdir *dp; 143552196Smckusick register u_long *tl; 143652196Smckusick register caddr_t cp; 143752196Smckusick register long t1; 143852196Smckusick caddr_t bpos, dpos, cp2; 143952196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 144052196Smckusick struct nameidata nami, *ndp = &nami; 144152317Sheideman struct componentname *cnp = &ndp->ni_cnd; 144252196Smckusick off_t off, endoff; 144352196Smckusick time_t reqtime, ltime; 144452196Smckusick struct nfsmount *nmp; 144552196Smckusick struct nfsnode *np, *tp; 144652196Smckusick struct vnode *newvp; 144752196Smckusick nfsv2fh_t *fhp; 144852196Smckusick u_long fileno; 144952196Smckusick u_quad_t frev; 145052196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 145152196Smckusick int cachable; 145252196Smckusick 145352196Smckusick if (uiop->uio_iovcnt != 1) 145452196Smckusick panic("nfs rdirlook"); 145552196Smckusick nmp = VFSTONFS(vp->v_mount); 145652196Smckusick tresid = uiop->uio_resid; 145752196Smckusick ndp->ni_dvp = vp; 145852196Smckusick newvp = NULLVP; 145952196Smckusick /* 146052196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 146152196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 146252196Smckusick * The stopping criteria is EOF or buffer full. 146352196Smckusick */ 146452196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 146552196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 146652196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 146752196Smckusick NFSX_FH+3*NFSX_UNSIGNED); 146852196Smckusick nfsm_fhtom(vp); 146952196Smckusick nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED); 147052196Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 147152196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 147252196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 147352196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 147452196Smckusick reqtime = time.tv_sec; 147552196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 147652196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 147752196Smckusick more_dirs = fxdr_unsigned(int, *tl); 147852196Smckusick 147952196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 148052196Smckusick off = uiop->uio_offset; 148152196Smckusick bigenough = 1; 148252196Smckusick while (more_dirs && bigenough) { 148352196Smckusick doit = 1; 148452196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 148552196Smckusick cachable = fxdr_unsigned(int, *tl++); 148652196Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 148752196Smckusick fxdr_hyper(tl, &frev); 148852196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 148952196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 149052196Smckusick VREF(vp); 149152196Smckusick newvp = vp; 149252196Smckusick np = VTONFS(vp); 149352196Smckusick } else { 149452196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 149552196Smckusick doit = 0; 149652196Smckusick newvp = NFSTOV(np); 149752196Smckusick } 149852196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 149952196Smckusick (struct vattr *)0)) 150052196Smckusick doit = 0; 150152196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 150252196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 150352196Smckusick len = fxdr_unsigned(int, *tl); 150452196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 150552196Smckusick error = EBADRPC; 150652196Smckusick m_freem(mrep); 150752196Smckusick goto nfsmout; 150852196Smckusick } 150952196Smckusick tlen = (len + 4) & ~0x3; 151052196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 151152196Smckusick bigenough = 0; 151252196Smckusick if (bigenough && doit) { 151352436Smckusick dp = (struct readdir *)uiop->uio_iov->iov_base; 151452196Smckusick dp->d_ino = fileno; 151552196Smckusick dp->d_namlen = len; 151652196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 151752196Smckusick uiop->uio_resid -= DIRHDSIZ; 151852196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 151952196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 152052317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 152152317Sheideman cnp->cn_namelen = len; 152252196Smckusick ndp->ni_vp = newvp; 152352196Smckusick nfsm_mtouio(uiop, len); 152452196Smckusick cp = uiop->uio_iov->iov_base; 152552196Smckusick tlen -= len; 152652196Smckusick for (i = 0; i < tlen; i++) 152752196Smckusick *cp++ = '\0'; 152852196Smckusick uiop->uio_iov->iov_base += tlen; 152952196Smckusick uiop->uio_iov->iov_len -= tlen; 153052196Smckusick uiop->uio_resid -= tlen; 153152317Sheideman cnp->cn_hash = 0; 153252317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 153352317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 153452196Smckusick if (ltime > time.tv_sec) { 153552196Smckusick if (np->n_tnext) { 153652196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 153752196Smckusick nmp->nm_tprev = np->n_tprev; 153852196Smckusick else 153952196Smckusick np->n_tnext->n_tprev = np->n_tprev; 154052196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 154152196Smckusick nmp->nm_tnext = np->n_tnext; 154252196Smckusick else 154352196Smckusick np->n_tprev->n_tnext = np->n_tnext; 154452196Smckusick } else 154552196Smckusick np->n_flag &= ~NQNFSWRITE; 154652196Smckusick if (cachable) 154752196Smckusick np->n_flag &= ~NQNFSNONCACHE; 154852196Smckusick else 154952196Smckusick np->n_flag |= NQNFSNONCACHE; 155052196Smckusick np->n_expiry = ltime; 155152196Smckusick np->n_lrev = frev; 155252196Smckusick tp = nmp->nm_tprev; 155352196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 155452196Smckusick tp = tp->n_tprev; 155552196Smckusick if (tp == (struct nfsnode *)nmp) { 155652196Smckusick np->n_tnext = nmp->nm_tnext; 155752196Smckusick nmp->nm_tnext = np; 155852196Smckusick } else { 155952196Smckusick np->n_tnext = tp->n_tnext; 156052196Smckusick tp->n_tnext = np; 156152196Smckusick } 156252196Smckusick np->n_tprev = tp; 156352196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 156452196Smckusick nmp->nm_tprev = np; 156552196Smckusick else 156652196Smckusick np->n_tnext->n_tprev = np; 156752317Sheideman cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 156852196Smckusick } 156952196Smckusick } else { 157052196Smckusick nfsm_adv(nfsm_rndup(len)); 157152196Smckusick } 157252196Smckusick if (newvp != NULLVP) { 157352196Smckusick vrele(newvp); 157452196Smckusick newvp = NULLVP; 157552196Smckusick } 157652196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 157752196Smckusick if (bigenough) 157852196Smckusick endoff = off = fxdr_unsigned(off_t, *tl++); 157952196Smckusick else 158052196Smckusick endoff = fxdr_unsigned(off_t, *tl++); 158152196Smckusick more_dirs = fxdr_unsigned(int, *tl); 158252196Smckusick } 158352196Smckusick /* 158452196Smckusick * If at end of rpc data, get the eof boolean 158552196Smckusick */ 158652196Smckusick if (!more_dirs) { 158752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 158852196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 158952196Smckusick 159052196Smckusick /* 159152196Smckusick * If at EOF, cache directory offset 159252196Smckusick */ 159352196Smckusick if (!more_dirs) 159452196Smckusick VTONFS(vp)->n_direofoffset = endoff; 159552196Smckusick } 159652196Smckusick if (uiop->uio_resid < tresid) 159752196Smckusick uiop->uio_offset = off; 159852196Smckusick else 159952196Smckusick more_dirs = 0; 160052196Smckusick m_freem(mrep); 160152196Smckusick } 160252196Smckusick /* 160352196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 160452196Smckusick * by increasing d_reclen for the last record. 160552196Smckusick */ 160652196Smckusick if (uiop->uio_resid < tresid) { 160752196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 160852196Smckusick if (len > 0) { 160952196Smckusick dp->d_reclen += len; 161052196Smckusick uiop->uio_iov->iov_base += len; 161152196Smckusick uiop->uio_iov->iov_len -= len; 161252196Smckusick uiop->uio_resid -= len; 161352196Smckusick } 161452196Smckusick } 161552196Smckusick nfsmout: 161652196Smckusick if (newvp != NULLVP) 161752196Smckusick vrele(newvp); 161852196Smckusick return (error); 161952196Smckusick } 162039488Smckusick static char hextoasc[] = "0123456789abcdef"; 162138414Smckusick 162238414Smckusick /* 162338414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 162438414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 162538414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 162638414Smckusick * nfsnode. There is the potential for another process on a different client 162738414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 162838414Smckusick * nfs_rename() completes, but... 162938414Smckusick */ 163052234Sheideman int 163152317Sheideman nfs_sillyrename(dvp, vp, cnp) 163252234Sheideman struct vnode *dvp, *vp; 163352234Sheideman struct componentname *cnp; 163438414Smckusick { 163538414Smckusick register struct nfsnode *np; 163638414Smckusick register struct sillyrename *sp; 163738414Smckusick int error; 163838414Smckusick short pid; 163938414Smckusick 164052234Sheideman cache_purge(dvp); 164152234Sheideman np = VTONFS(vp); 164251986Smckusick #ifdef SILLYSEPARATE 164338414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 164448364Smckusick M_NFSREQ, M_WAITOK); 164551986Smckusick #else 164651986Smckusick sp = &np->n_silly; 164751986Smckusick #endif 164852234Sheideman sp->s_cred = crdup(cnp->cn_cred); 164952234Sheideman sp->s_dvp = dvp; 165052234Sheideman VREF(dvp); 165138414Smckusick 165238414Smckusick /* Fudge together a funny name */ 165352234Sheideman pid = cnp->cn_proc->p_pid; 165448364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 165548364Smckusick sp->s_namlen = 12; 165648364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 165748364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 165848364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 165948364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 166038414Smckusick 166138414Smckusick /* Try lookitups until we get one that isn't there */ 166252234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 166348364Smckusick sp->s_name[4]++; 166448364Smckusick if (sp->s_name[4] > 'z') { 166538414Smckusick error = EINVAL; 166638414Smckusick goto bad; 166738414Smckusick } 166838414Smckusick } 166952234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 167038414Smckusick goto bad; 167152234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 167238414Smckusick np->n_sillyrename = sp; 167338414Smckusick return (0); 167438414Smckusick bad: 167548364Smckusick vrele(sp->s_dvp); 167648364Smckusick crfree(sp->s_cred); 167751986Smckusick #ifdef SILLYSEPARATE 167848364Smckusick free((caddr_t)sp, M_NFSREQ); 167951986Smckusick #endif 168038414Smckusick return (error); 168138414Smckusick } 168238414Smckusick 168338414Smckusick /* 168438414Smckusick * Look up a file name for silly rename stuff. 168538414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 168638414Smckusick * into the nfsnode table. 168738414Smckusick * If fhp != NULL it copies the returned file handle out 168838414Smckusick */ 168952234Sheideman int 169052196Smckusick nfs_lookitup(sp, fhp, procp) 169148364Smckusick register struct sillyrename *sp; 169238414Smckusick nfsv2fh_t *fhp; 169352196Smckusick struct proc *procp; 169438414Smckusick { 169548364Smckusick register struct vnode *vp = sp->s_dvp; 169648054Smckusick register u_long *tl; 169739488Smckusick register caddr_t cp; 169839488Smckusick register long t1, t2; 169939488Smckusick caddr_t bpos, dpos, cp2; 170039488Smckusick u_long xid; 170139488Smckusick int error = 0; 170239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 170338414Smckusick long len; 170438414Smckusick 170538414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 170648364Smckusick len = sp->s_namlen; 170752196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 170838414Smckusick nfsm_fhtom(vp); 170948364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 171052196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 171138414Smckusick if (fhp != NULL) { 171252196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 171338414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 171438414Smckusick } 171538414Smckusick nfsm_reqdone; 171638414Smckusick return (error); 171738414Smckusick } 171838414Smckusick 171938414Smckusick /* 172038414Smckusick * Kludge City.. 172138414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 172241905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 172338414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 172438414Smckusick * nfsiobuf area. 172538414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 172638414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 172738414Smckusick * a lot more work than bcopy() and also it currently happens in the 172838414Smckusick * context of the swapper process (2). 172938414Smckusick */ 173052234Sheideman int 173138414Smckusick nfs_bmap(vp, bn, vpp, bnp) 173238414Smckusick struct vnode *vp; 173338414Smckusick daddr_t bn; 173438414Smckusick struct vnode **vpp; 173538414Smckusick daddr_t *bnp; 173638414Smckusick { 173738414Smckusick if (vpp != NULL) 173838414Smckusick *vpp = vp; 173938414Smckusick if (bnp != NULL) 174052196Smckusick *bnp = bn * btodb(vp->v_mount->mnt_stat.f_iosize); 174138414Smckusick return (0); 174238414Smckusick } 174338414Smckusick 174438414Smckusick /* 174538884Smacklem * Strategy routine for phys. i/o 174638884Smacklem * If the biod's are running, queue a request 174738884Smacklem * otherwise just call nfs_doio() to get it done 174838414Smckusick */ 174952234Sheideman int 175038414Smckusick nfs_strategy(bp) 175138414Smckusick register struct buf *bp; 175238414Smckusick { 175338884Smacklem register struct buf *dp; 175439341Smckusick register int i; 175538884Smacklem int error = 0; 175639341Smckusick int fnd = 0; 175738884Smacklem 175838884Smacklem /* 175941905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 176041905Smckusick * doesn't set it, I will. 176146450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 176241905Smckusick * be hanging about after the process terminates. 176341905Smckusick */ 176446988Smckusick if ((bp->b_flags & B_PHYS) == 0) { 176546988Smckusick if (bp->b_flags & B_ASYNC) 176646988Smckusick bp->b_proc = (struct proc *)0; 176746988Smckusick else 176847573Skarels bp->b_proc = curproc; 176946988Smckusick } 177041905Smckusick /* 177146450Skarels * If the op is asynchronous and an i/o daemon is waiting 177238884Smacklem * queue the request, wake it up and wait for completion 177346450Skarels * otherwise just do it ourselves. 177438884Smacklem */ 177546988Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 177646988Smckusick return (nfs_doio(bp)); 177746988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 177846988Smckusick if (nfs_iodwant[i]) { 177939341Smckusick dp = &nfs_bqueue; 178039341Smckusick if (dp->b_actf == NULL) { 178139341Smckusick dp->b_actl = bp; 178239341Smckusick bp->b_actf = dp; 178339341Smckusick } else { 178439341Smckusick dp->b_actf->b_actl = bp; 178539341Smckusick bp->b_actf = dp->b_actf; 178639341Smckusick } 178739341Smckusick dp->b_actf = bp; 178839341Smckusick bp->b_actl = dp; 178939341Smckusick fnd++; 179039341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 179139341Smckusick break; 179238884Smacklem } 179339341Smckusick } 179439341Smckusick if (!fnd) 179538884Smacklem error = nfs_doio(bp); 179638884Smacklem return (error); 179738884Smacklem } 179838884Smacklem 179938884Smacklem /* 180038884Smacklem * Fun and games with i/o 180138884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 180238884Smacklem * mapping the data buffer into kernel virtual space and doing the 180338884Smacklem * nfs read or write rpc's from it. 180441905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 180541905Smckusick * otherwise it is called by the nfsiods to do what would normally be 180638884Smacklem * partially disk interrupt driven. 180738884Smacklem */ 180852234Sheideman int 180938884Smacklem nfs_doio(bp) 181038884Smacklem register struct buf *bp; 181138884Smacklem { 181238414Smckusick register struct uio *uiop; 181338414Smckusick register struct vnode *vp; 181439341Smckusick struct nfsnode *np; 181538884Smacklem struct ucred *cr; 181641539Smckusick int error; 181741539Smckusick struct uio uio; 181841539Smckusick struct iovec io; 181938414Smckusick 182038414Smckusick vp = bp->b_vp; 182140251Smckusick np = VTONFS(vp); 182238414Smckusick uiop = &uio; 182338414Smckusick uiop->uio_iov = &io; 182438414Smckusick uiop->uio_iovcnt = 1; 182538414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 182652196Smckusick uiop->uio_procp = bp->b_proc; 182739751Smckusick 182838414Smckusick /* 182938884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 183038884Smacklem * the Nfsiomap pte's 183138884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 183238884Smacklem * and a guess at a group 183338414Smckusick */ 183438884Smacklem if (bp->b_flags & B_PHYS) { 183548054Smckusick if (bp->b_flags & B_DIRTY) 183648054Smckusick uiop->uio_procp = pageproc; 183748054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 183841539Smckusick /* mapping was already done by vmapbuf */ 183941539Smckusick io.iov_base = bp->b_un.b_addr; 184039751Smckusick 184138884Smacklem /* 184239751Smckusick * And do the i/o rpc 184339751Smckusick */ 184439751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 184539823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 184639751Smckusick if (bp->b_flags & B_READ) { 184739751Smckusick uiop->uio_rw = UIO_READ; 184839751Smckusick nfsstats.read_physios++; 184948054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 185045717Smckusick (void) vnode_pager_uncache(vp); 185139751Smckusick } else { 185239751Smckusick uiop->uio_rw = UIO_WRITE; 185339751Smckusick nfsstats.write_physios++; 185448054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 185539341Smckusick } 185639751Smckusick 185739751Smckusick /* 185839751Smckusick * Finally, release pte's used by physical i/o 185939751Smckusick */ 186038884Smacklem crfree(cr); 186139751Smckusick } else { 186239751Smckusick if (bp->b_flags & B_READ) { 186339751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 186439751Smckusick io.iov_base = bp->b_un.b_addr; 186539751Smckusick uiop->uio_rw = UIO_READ; 186641905Smckusick switch (vp->v_type) { 186741905Smckusick case VREG: 186841905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 186941905Smckusick nfsstats.read_bios++; 187048054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 187141905Smckusick break; 187241905Smckusick case VLNK: 187341905Smckusick uiop->uio_offset = 0; 187441905Smckusick nfsstats.readlink_bios++; 187548054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 187641905Smckusick break; 187741905Smckusick case VDIR: 187841905Smckusick uiop->uio_offset = bp->b_lblkno; 187941905Smckusick nfsstats.readdir_bios++; 188052196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK) 188152196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 188252196Smckusick else 188352196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 188441905Smckusick /* 188541905Smckusick * Save offset cookie in b_blkno. 188641905Smckusick */ 188741905Smckusick bp->b_blkno = uiop->uio_offset; 188841905Smckusick break; 188941905Smckusick }; 189041905Smckusick bp->b_error = error; 189139751Smckusick } else { 189239751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 189339751Smckusick - bp->b_dirtyoff; 189439823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 189539751Smckusick + bp->b_dirtyoff; 189639751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 189739751Smckusick uiop->uio_rw = UIO_WRITE; 189839751Smckusick nfsstats.write_bios++; 189941905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 190048054Smckusick bp->b_wcred); 190139751Smckusick if (error) { 190239751Smckusick np->n_error = error; 190339751Smckusick np->n_flag |= NWRITEERR; 190439751Smckusick } 190539751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 190639751Smckusick } 190738884Smacklem } 190839751Smckusick if (error) 190939751Smckusick bp->b_flags |= B_ERROR; 191039751Smckusick bp->b_resid = uiop->uio_resid; 191138414Smckusick biodone(bp); 191238414Smckusick return (error); 191338414Smckusick } 191438884Smacklem 191538884Smacklem /* 191648054Smckusick * Mmap a file 191748054Smckusick * 191848054Smckusick * NB Currently unsupported. 191948054Smckusick */ 192048054Smckusick /* ARGSUSED */ 192152234Sheideman int 192248054Smckusick nfs_mmap(vp, fflags, cred, p) 192348054Smckusick struct vnode *vp; 192448054Smckusick int fflags; 192548054Smckusick struct ucred *cred; 192648054Smckusick struct proc *p; 192748054Smckusick { 192848054Smckusick 192948054Smckusick return (EINVAL); 193048054Smckusick } 193148054Smckusick 193248054Smckusick /* 193338884Smacklem * Flush all the blocks associated with a vnode. 193438884Smacklem * Walk through the buffer pool and push any dirty pages 193538884Smacklem * associated with the vnode. 193638884Smacklem */ 193739488Smckusick /* ARGSUSED */ 193852234Sheideman int 193948054Smckusick nfs_fsync(vp, fflags, cred, waitfor, p) 194038884Smacklem register struct vnode *vp; 194138884Smacklem int fflags; 194238884Smacklem struct ucred *cred; 194339587Smckusick int waitfor; 194448054Smckusick struct proc *p; 194538884Smacklem { 194638884Smacklem register struct nfsnode *np = VTONFS(vp); 194739751Smckusick int error = 0; 194838884Smacklem 194938884Smacklem if (np->n_flag & NMODIFIED) { 195038884Smacklem np->n_flag &= ~NMODIFIED; 195139751Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 195238884Smacklem } 195339751Smckusick if (!error && (np->n_flag & NWRITEERR)) 195439751Smckusick error = np->n_error; 195538884Smacklem return (error); 195638884Smacklem } 195739672Smckusick 195839672Smckusick /* 195946201Smckusick * NFS advisory byte-level locks. 196046201Smckusick * Currently unsupported. 196146201Smckusick */ 196252234Sheideman int 196346201Smckusick nfs_advlock(vp, id, op, fl, flags) 196446201Smckusick struct vnode *vp; 196546201Smckusick caddr_t id; 196646201Smckusick int op; 196746201Smckusick struct flock *fl; 196846201Smckusick int flags; 196946201Smckusick { 197046201Smckusick 197146201Smckusick return (EOPNOTSUPP); 197246201Smckusick } 197346201Smckusick 197446201Smckusick /* 197539672Smckusick * Print out the contents of an nfsnode. 197639672Smckusick */ 197752234Sheideman int 197839672Smckusick nfs_print(vp) 197939672Smckusick struct vnode *vp; 198039672Smckusick { 198139672Smckusick register struct nfsnode *np = VTONFS(vp); 198239672Smckusick 198340294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 198440294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 198540294Smckusick #ifdef FIFO 198640294Smckusick if (vp->v_type == VFIFO) 198740294Smckusick fifo_printinfo(vp); 198840294Smckusick #endif /* FIFO */ 198939914Smckusick printf("\n"); 199039672Smckusick } 199151573Smckusick 199251573Smckusick /* 199351573Smckusick * NFS directory offset lookup. 199451573Smckusick * Currently unsupported. 199551573Smckusick */ 199652234Sheideman int 199751573Smckusick nfs_blkatoff(vp, offset, res, bpp) 199851573Smckusick struct vnode *vp; 199951573Smckusick off_t offset; 200051573Smckusick char **res; 200151573Smckusick struct buf **bpp; 200251573Smckusick { 200351573Smckusick 200451573Smckusick return (EOPNOTSUPP); 200551573Smckusick } 200651573Smckusick 200751573Smckusick /* 200851573Smckusick * NFS flat namespace lookup. 200951573Smckusick * Currently unsupported. 201051573Smckusick */ 201152234Sheideman int 201251573Smckusick nfs_vget(mp, ino, vpp) 201351573Smckusick struct mount *mp; 201451573Smckusick ino_t ino; 201551573Smckusick struct vnode **vpp; 201651573Smckusick { 201751573Smckusick 201851573Smckusick return (EOPNOTSUPP); 201951573Smckusick } 202051573Smckusick 202151573Smckusick /* 202251573Smckusick * NFS flat namespace allocation. 202351573Smckusick * Currently unsupported. 202451573Smckusick */ 202552234Sheideman int 202651573Smckusick nfs_valloc(pvp, mode, cred, vpp) 202751573Smckusick struct vnode *pvp; 202851573Smckusick int mode; 202951573Smckusick struct ucred *cred; 203051573Smckusick struct vnode **vpp; 203151573Smckusick { 203251573Smckusick 203351573Smckusick return (EOPNOTSUPP); 203451573Smckusick } 203551573Smckusick 203651573Smckusick /* 203751573Smckusick * NFS flat namespace free. 203851573Smckusick * Currently unsupported. 203951573Smckusick */ 204051573Smckusick void 204151573Smckusick nfs_vfree(pvp, ino, mode) 204251573Smckusick struct vnode *pvp; 204351573Smckusick ino_t ino; 204451573Smckusick int mode; 204551573Smckusick { 204651573Smckusick 204751573Smckusick return; 204851573Smckusick } 204951573Smckusick 205051573Smckusick /* 205151573Smckusick * NFS file truncation. 205251573Smckusick */ 205352234Sheideman int 205451573Smckusick nfs_truncate(vp, length, flags) 205551573Smckusick struct vnode *vp; 205651573Smckusick u_long length; 205751573Smckusick int flags; 205851573Smckusick { 205951573Smckusick 206051573Smckusick /* Use nfs_setattr */ 206151573Smckusick printf("nfs_truncate: need to implement!!"); 206251573Smckusick return (EOPNOTSUPP); 206351573Smckusick } 206451573Smckusick 206551573Smckusick /* 206651573Smckusick * NFS update. 206751573Smckusick */ 206852234Sheideman int 206951573Smckusick nfs_update(vp, ta, tm, waitfor) 207051573Smckusick struct vnode *vp; 207151573Smckusick struct timeval *ta; 207251573Smckusick struct timeval *tm; 207351573Smckusick int waitfor; 207451573Smckusick { 207551573Smckusick 207651573Smckusick /* Use nfs_setattr */ 207751573Smckusick printf("nfs_update: need to implement!!"); 207851573Smckusick return (EOPNOTSUPP); 207951573Smckusick } 2080