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*51986Smckusick * @(#)nfs_vnops.c 7.64 (Berkeley) 12/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" 2648054Smckusick #include "namei.h" 2738414Smckusick #include "vnode.h" 2848054Smckusick #include "specdev.h" 2948054Smckusick #include "fifo.h" 3038884Smacklem #include "map.h" 3147573Skarels 3251466Sbostic #include "ufs/ufs/quota.h" 3351466Sbostic #include "ufs/ufs/inode.h" 3451466Sbostic #include "ufs/ufs/dir.h" 3547573Skarels 3638414Smckusick #include "nfsv2.h" 3738414Smckusick #include "nfs.h" 3838414Smckusick #include "nfsnode.h" 3938414Smckusick #include "nfsmount.h" 4038414Smckusick #include "xdr_subs.h" 4138414Smckusick #include "nfsm_subs.h" 4238884Smacklem #include "nfsiom.h" 4338414Smckusick 4438414Smckusick /* Defs */ 4538414Smckusick #define TRUE 1 4638414Smckusick #define FALSE 0 4738414Smckusick 4848054Smckusick /* 4948054Smckusick * Global vfs data structures for nfs 5048054Smckusick */ 5138414Smckusick struct vnodeops nfsv2_vnodeops = { 5239672Smckusick nfs_lookup, /* lookup */ 5339672Smckusick nfs_create, /* create */ 5439672Smckusick nfs_mknod, /* mknod */ 5539672Smckusick nfs_open, /* open */ 5639672Smckusick nfs_close, /* close */ 5739672Smckusick nfs_access, /* access */ 5839672Smckusick nfs_getattr, /* getattr */ 5939672Smckusick nfs_setattr, /* setattr */ 6039672Smckusick nfs_read, /* read */ 6139672Smckusick nfs_write, /* write */ 6248054Smckusick nfs_ioctl, /* ioctl */ 6348054Smckusick nfs_select, /* select */ 6448054Smckusick nfs_mmap, /* mmap */ 6539672Smckusick nfs_fsync, /* fsync */ 6648054Smckusick nfs_seek, /* seek */ 6739672Smckusick nfs_remove, /* remove */ 6839672Smckusick nfs_link, /* link */ 6939672Smckusick nfs_rename, /* rename */ 7039672Smckusick nfs_mkdir, /* mkdir */ 7139672Smckusick nfs_rmdir, /* rmdir */ 7239672Smckusick nfs_symlink, /* symlink */ 7339672Smckusick nfs_readdir, /* readdir */ 7439672Smckusick nfs_readlink, /* readlink */ 7539672Smckusick nfs_abortop, /* abortop */ 7639672Smckusick nfs_inactive, /* inactive */ 7739672Smckusick nfs_reclaim, /* reclaim */ 7839672Smckusick nfs_lock, /* lock */ 7939672Smckusick nfs_unlock, /* unlock */ 8039672Smckusick nfs_bmap, /* bmap */ 8139672Smckusick nfs_strategy, /* strategy */ 8239672Smckusick nfs_print, /* print */ 8339906Smckusick nfs_islocked, /* islocked */ 8446201Smckusick nfs_advlock, /* advlock */ 8551573Smckusick nfs_blkatoff, /* blkatoff */ 8651573Smckusick nfs_vget, /* vget */ 8751573Smckusick nfs_valloc, /* valloc */ 8851573Smckusick nfs_vfree, /* vfree */ 8951573Smckusick nfs_truncate, /* truncate */ 9051573Smckusick nfs_update, /* update */ 9151573Smckusick bwrite, /* bwrite */ 9238414Smckusick }; 9338414Smckusick 9448054Smckusick /* 9548054Smckusick * Special device vnode ops 9648054Smckusick */ 9739441Smckusick struct vnodeops spec_nfsv2nodeops = { 9839599Smckusick spec_lookup, /* lookup */ 9948054Smckusick spec_create, /* create */ 10048054Smckusick spec_mknod, /* mknod */ 10139599Smckusick spec_open, /* open */ 10239599Smckusick spec_close, /* close */ 10339599Smckusick nfs_access, /* access */ 10439599Smckusick nfs_getattr, /* getattr */ 10539599Smckusick nfs_setattr, /* setattr */ 10639599Smckusick spec_read, /* read */ 10739599Smckusick spec_write, /* write */ 10839599Smckusick spec_ioctl, /* ioctl */ 10939599Smckusick spec_select, /* select */ 11048054Smckusick spec_mmap, /* mmap */ 11148054Smckusick spec_fsync, /* fsync */ 11248054Smckusick spec_seek, /* seek */ 11348054Smckusick spec_remove, /* remove */ 11448054Smckusick spec_link, /* link */ 11548054Smckusick spec_rename, /* rename */ 11648054Smckusick spec_mkdir, /* mkdir */ 11748054Smckusick spec_rmdir, /* rmdir */ 11848054Smckusick spec_symlink, /* symlink */ 11948054Smckusick spec_readdir, /* readdir */ 12048054Smckusick spec_readlink, /* readlink */ 12148054Smckusick spec_abortop, /* abortop */ 12239599Smckusick nfs_inactive, /* inactive */ 12339599Smckusick nfs_reclaim, /* reclaim */ 12439599Smckusick nfs_lock, /* lock */ 12539599Smckusick nfs_unlock, /* unlock */ 12639672Smckusick spec_bmap, /* bmap */ 12739599Smckusick spec_strategy, /* strategy */ 12839672Smckusick nfs_print, /* print */ 12939906Smckusick nfs_islocked, /* islocked */ 13046201Smckusick spec_advlock, /* advlock */ 13151573Smckusick spec_blkatoff, /* blkatoff */ 13251573Smckusick spec_vget, /* vget */ 13351573Smckusick spec_valloc, /* valloc */ 13451573Smckusick spec_vfree, /* vfree */ 13551573Smckusick spec_truncate, /* truncate */ 13651573Smckusick nfs_update, /* update */ 13751573Smckusick bwrite, /* bwrite */ 13838414Smckusick }; 13938414Smckusick 14040294Smckusick #ifdef FIFO 14140294Smckusick struct vnodeops fifo_nfsv2nodeops = { 14240294Smckusick fifo_lookup, /* lookup */ 14348054Smckusick fifo_create, /* create */ 14448054Smckusick fifo_mknod, /* mknod */ 14540294Smckusick fifo_open, /* open */ 14640294Smckusick fifo_close, /* close */ 14740294Smckusick nfs_access, /* access */ 14840294Smckusick nfs_getattr, /* getattr */ 14940294Smckusick nfs_setattr, /* setattr */ 15040294Smckusick fifo_read, /* read */ 15140294Smckusick fifo_write, /* write */ 15240294Smckusick fifo_ioctl, /* ioctl */ 15340294Smckusick fifo_select, /* select */ 15448054Smckusick fifo_mmap, /* mmap */ 15548054Smckusick fifo_fsync, /* fsync */ 15648054Smckusick fifo_seek, /* seek */ 15748054Smckusick fifo_remove, /* remove */ 15848054Smckusick fifo_link, /* link */ 15948054Smckusick fifo_rename, /* rename */ 16048054Smckusick fifo_mkdir, /* mkdir */ 16148054Smckusick fifo_rmdir, /* rmdir */ 16248054Smckusick fifo_symlink, /* symlink */ 16348054Smckusick fifo_readdir, /* readdir */ 16448054Smckusick fifo_readlink, /* readlink */ 16548054Smckusick fifo_abortop, /* abortop */ 16640294Smckusick nfs_inactive, /* inactive */ 16740294Smckusick nfs_reclaim, /* reclaim */ 16840294Smckusick nfs_lock, /* lock */ 16940294Smckusick nfs_unlock, /* unlock */ 17040294Smckusick fifo_bmap, /* bmap */ 17140294Smckusick fifo_badop, /* strategy */ 17240294Smckusick nfs_print, /* print */ 17340294Smckusick nfs_islocked, /* islocked */ 17446201Smckusick fifo_advlock, /* advlock */ 17551573Smckusick fifo_blkatoff, /* blkatoff */ 17651573Smckusick fifo_vget, /* vget */ 17751573Smckusick fifo_valloc, /* valloc */ 17851573Smckusick fifo_vfree, /* vfree */ 17951573Smckusick fifo_truncate, /* truncate */ 18051573Smckusick nfs_update, /* update */ 18151573Smckusick bwrite, /* bwrite */ 18240294Smckusick }; 18340294Smckusick #endif /* FIFO */ 18440294Smckusick 18548054Smckusick /* 18648054Smckusick * Global vars 18748054Smckusick */ 18838414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 18938414Smckusick extern u_long nfs_prog, nfs_vers; 19038414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 19138884Smacklem struct map nfsmap[NFS_MSIZ]; 19238884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 19341905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 19446988Smckusick int nfs_numasync = 0; 19538884Smacklem static int nfsmap_want = 0; 19638414Smckusick 19738414Smckusick /* 19838414Smckusick * nfs null call from vfs. 19938414Smckusick */ 20048054Smckusick nfs_null(vp, cred, p) 20138414Smckusick struct vnode *vp; 20238414Smckusick struct ucred *cred; 20348054Smckusick struct proc *p; 20438414Smckusick { 20539488Smckusick caddr_t bpos, dpos; 20639488Smckusick u_long xid; 20739488Smckusick int error = 0; 20839488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 20938414Smckusick 21038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 21148054Smckusick nfsm_request(vp, NFSPROC_NULL, p, 0); 21238414Smckusick nfsm_reqdone; 21338414Smckusick return (error); 21438414Smckusick } 21538414Smckusick 21638414Smckusick /* 21738414Smckusick * nfs access vnode op. 21838414Smckusick * Essentially just get vattr and then imitate iaccess() 21938414Smckusick */ 22048054Smckusick nfs_access(vp, mode, cred, p) 22138414Smckusick struct vnode *vp; 22238414Smckusick int mode; 22338414Smckusick register struct ucred *cred; 22448054Smckusick struct proc *p; 22538414Smckusick { 22638414Smckusick register struct vattr *vap; 22738414Smckusick register gid_t *gp; 22838414Smckusick struct vattr vattr; 22938414Smckusick register int i; 23038414Smckusick int error; 23138414Smckusick 23238414Smckusick /* 23338414Smckusick * If you're the super-user, 23438414Smckusick * you always get access. 23538414Smckusick */ 23638414Smckusick if (cred->cr_uid == 0) 23738414Smckusick return (0); 23838414Smckusick vap = &vattr; 23948054Smckusick if (error = nfs_dogetattr(vp, vap, cred, 0, p)) 24038884Smacklem return (error); 24138414Smckusick /* 24238414Smckusick * Access check is based on only one of owner, group, public. 24338414Smckusick * If not owner, then check group. If not a member of the 24438414Smckusick * group, then check public access. 24538414Smckusick */ 24638414Smckusick if (cred->cr_uid != vap->va_uid) { 24738414Smckusick mode >>= 3; 24838414Smckusick gp = cred->cr_groups; 24938414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 25038414Smckusick if (vap->va_gid == *gp) 25138414Smckusick goto found; 25238414Smckusick mode >>= 3; 25338414Smckusick found: 25438414Smckusick ; 25538414Smckusick } 25638414Smckusick if ((vap->va_mode & mode) != 0) 25738414Smckusick return (0); 25838414Smckusick return (EACCES); 25938414Smckusick } 26038414Smckusick 26138414Smckusick /* 26238414Smckusick * nfs open vnode op 26338414Smckusick * Just check to see if the type is ok 26438414Smckusick */ 26539488Smckusick /* ARGSUSED */ 26648054Smckusick nfs_open(vp, mode, cred, p) 26738414Smckusick struct vnode *vp; 26838414Smckusick int mode; 26938414Smckusick struct ucred *cred; 27048054Smckusick struct proc *p; 27138414Smckusick { 27238414Smckusick register enum vtype vtyp; 27338414Smckusick 27438414Smckusick vtyp = vp->v_type; 27538414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 27638414Smckusick return (0); 27738414Smckusick else 27838414Smckusick return (EACCES); 27938414Smckusick } 28038414Smckusick 28138414Smckusick /* 28238414Smckusick * nfs close vnode op 28338884Smacklem * For reg files, invalidate any buffer cache entries. 28438414Smckusick */ 28539488Smckusick /* ARGSUSED */ 28648054Smckusick nfs_close(vp, fflags, cred, p) 28738414Smckusick register struct vnode *vp; 28838414Smckusick int fflags; 28938414Smckusick struct ucred *cred; 29048054Smckusick struct proc *p; 29138414Smckusick { 29239488Smckusick register struct nfsnode *np = VTONFS(vp); 29339341Smckusick int error = 0; 29438414Smckusick 29541905Smckusick if (vp->v_type == VREG && (np->n_flag & NMODIFIED)) { 29639441Smckusick nfs_lock(vp); 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 } 30439441Smckusick nfs_unlock(vp); 30538884Smacklem } 30638414Smckusick return (error); 30738414Smckusick } 30838414Smckusick 30938414Smckusick /* 31038414Smckusick * nfs getattr call from vfs. 31138414Smckusick */ 31248054Smckusick nfs_getattr(vp, vap, cred, p) 31339488Smckusick register struct vnode *vp; 31439488Smckusick struct vattr *vap; 31538414Smckusick struct ucred *cred; 31648054Smckusick struct proc *p; 31738414Smckusick { 31848054Smckusick return (nfs_dogetattr(vp, vap, cred, 0, p)); 31943356Smckusick } 32043356Smckusick 32148054Smckusick nfs_dogetattr(vp, vap, cred, tryhard, p) 32243356Smckusick register struct vnode *vp; 32343356Smckusick struct vattr *vap; 32443356Smckusick struct ucred *cred; 32543356Smckusick int tryhard; 32648054Smckusick struct proc *p; 32743356Smckusick { 32839488Smckusick register caddr_t cp; 32939488Smckusick register long t1; 33039488Smckusick caddr_t bpos, dpos; 33139488Smckusick u_long xid; 33239488Smckusick int error = 0; 33339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 33438414Smckusick 33538414Smckusick /* First look in the cache.. */ 33638414Smckusick if (nfs_getattrcache(vp, vap) == 0) 33738414Smckusick return (0); 33838414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 33938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH); 34038414Smckusick nfsm_fhtom(vp); 34148054Smckusick nfsm_request(vp, NFSPROC_GETATTR, p, tryhard); 34238414Smckusick nfsm_loadattr(vp, vap); 34338414Smckusick nfsm_reqdone; 34438414Smckusick return (error); 34538414Smckusick } 34638414Smckusick 34738414Smckusick /* 34838414Smckusick * nfs setattr call. 34938414Smckusick */ 35048054Smckusick nfs_setattr(vp, vap, cred, p) 35139488Smckusick register struct vnode *vp; 35238414Smckusick register struct vattr *vap; 35338414Smckusick struct ucred *cred; 35448054Smckusick struct proc *p; 35538414Smckusick { 35638884Smacklem register struct nfsv2_sattr *sp; 35739488Smckusick register caddr_t cp; 35839488Smckusick register long t1; 35939488Smckusick caddr_t bpos, dpos; 36039488Smckusick u_long xid; 36139488Smckusick int error = 0; 36239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 36339359Smckusick struct nfsnode *np; 36438414Smckusick 36538414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 36638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 36738414Smckusick nfsm_fhtom(vp); 36838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 36938414Smckusick if (vap->va_mode == 0xffff) 37038884Smacklem sp->sa_mode = VNOVAL; 37138414Smckusick else 37238884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 37338414Smckusick if (vap->va_uid == 0xffff) 37438884Smacklem sp->sa_uid = VNOVAL; 37538414Smckusick else 37638884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 37738414Smckusick if (vap->va_gid == 0xffff) 37838884Smacklem sp->sa_gid = VNOVAL; 37938414Smckusick else 38038884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 38138884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 38244988Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec); 38344988Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 38444988Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 38544988Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 38644988Smckusick vap->va_atime.tv_sec != VNOVAL) { 38739359Smckusick np = VTONFS(vp); 38839359Smckusick if (np->n_flag & NMODIFIED) { 38939359Smckusick np->n_flag &= ~NMODIFIED; 39046988Smckusick if (vap->va_size == 0) 39146988Smckusick vinvalbuf(vp, FALSE); 39246988Smckusick else 39346988Smckusick vinvalbuf(vp, TRUE); 39441905Smckusick np->n_attrstamp = 0; 39539359Smckusick } 39639359Smckusick } 39748054Smckusick nfsm_request(vp, NFSPROC_SETATTR, p, 1); 39838414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 39938414Smckusick /* should we fill in any vap fields ?? */ 40038414Smckusick nfsm_reqdone; 40138414Smckusick return (error); 40238414Smckusick } 40338414Smckusick 40438414Smckusick /* 40538414Smckusick * nfs lookup call, one step at a time... 40638414Smckusick * First look in cache 40738414Smckusick * If not found, unlock the directory nfsnode and do the rpc 40838414Smckusick */ 40948054Smckusick nfs_lookup(vp, ndp, p) 41038414Smckusick register struct vnode *vp; 41138414Smckusick register struct nameidata *ndp; 41248054Smckusick struct proc *p; 41338414Smckusick { 41438414Smckusick register struct vnode *vdp; 41548054Smckusick register u_long *tl; 41639488Smckusick register caddr_t cp; 41739488Smckusick register long t1, t2; 41839488Smckusick caddr_t bpos, dpos, cp2; 41939488Smckusick u_long xid; 42039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 42138414Smckusick struct vnode *newvp; 42238414Smckusick long len; 42338414Smckusick nfsv2fh_t *fhp; 42438414Smckusick struct nfsnode *np; 42539488Smckusick int lockparent, wantparent, flag, error = 0; 42638414Smckusick 42738414Smckusick ndp->ni_dvp = vp; 42838414Smckusick ndp->ni_vp = NULL; 42938414Smckusick if (vp->v_type != VDIR) 43038414Smckusick return (ENOTDIR); 43138414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 43246510Smckusick flag = ndp->ni_nameiop & OPMASK; 43338414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 43439341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 43538884Smacklem struct vattr vattr; 43638884Smacklem int vpid; 43738884Smacklem 43839441Smckusick vdp = ndp->ni_vp; 43938884Smacklem vpid = vdp->v_id; 44038414Smckusick /* 44138884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 44238884Smacklem * for an explanation of the locking protocol 44338414Smckusick */ 44438414Smckusick if (vp == vdp) { 44538425Smckusick VREF(vdp); 44639441Smckusick error = 0; 44738414Smckusick } else if (ndp->ni_isdotdot) { 44838414Smckusick nfs_unlock(vp); 44939441Smckusick error = vget(vdp); 45047289Smckusick if (!error && lockparent && *ndp->ni_next == '\0') 45147289Smckusick nfs_lock(vp); 45238414Smckusick } else { 45339441Smckusick error = vget(vdp); 45447289Smckusick if (!lockparent || error || *ndp->ni_next != '\0') 45547289Smckusick nfs_unlock(vp); 45638414Smckusick } 45739441Smckusick if (!error) { 45840251Smckusick if (vpid == vdp->v_id) { 45948054Smckusick if (!nfs_dogetattr(vdp, &vattr, ndp->ni_cred, 0, p)&& 46040251Smckusick vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) { 46139441Smckusick nfsstats.lookupcache_hits++; 46249872Smckusick if (flag != LOOKUP && *ndp->ni_next == 0) 46349741Smckusick ndp->ni_nameiop |= SAVENAME; 46439441Smckusick return (0); 46540251Smckusick } 46647289Smckusick cache_purge(vdp); 46739441Smckusick } 46847289Smckusick nfs_nput(vdp); 46947289Smckusick if (lockparent && vdp != vp && *ndp->ni_next == '\0') 47047289Smckusick nfs_unlock(vp); 47138884Smacklem } 47241398Smckusick ndp->ni_vp = NULLVP; 47339751Smckusick } else 47439751Smckusick nfs_unlock(vp); 47539341Smckusick error = 0; 47638414Smckusick nfsstats.lookupcache_misses++; 47738414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 47838414Smckusick len = ndp->ni_namelen; 47938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 48038414Smckusick nfsm_fhtom(vp); 48138414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 48248054Smckusick nfsm_request(vp, NFSPROC_LOOKUP, p, 0); 48338414Smckusick nfsmout: 48438414Smckusick if (error) { 48539751Smckusick if (lockparent || (flag != CREATE && flag != RENAME) || 48639751Smckusick *ndp->ni_next != 0) 48739751Smckusick nfs_lock(vp); 48849872Smckusick if (flag != LOOKUP && *ndp->ni_next == 0) 48949741Smckusick ndp->ni_nameiop |= SAVENAME; 49040483Smckusick return (error); 49138414Smckusick } 49238414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 49338414Smckusick 49438414Smckusick /* 49538414Smckusick * Handle DELETE and RENAME cases... 49638414Smckusick */ 49738414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 49838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 49938425Smckusick VREF(vp); 50038414Smckusick newvp = vp; 50138414Smckusick np = VTONFS(vp); 50238414Smckusick } else { 50338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 50439751Smckusick nfs_lock(vp); 50538414Smckusick m_freem(mrep); 50638414Smckusick return (error); 50738414Smckusick } 50838414Smckusick newvp = NFSTOV(np); 50938414Smckusick } 51039459Smckusick if (error = 51139459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 51239751Smckusick nfs_lock(vp); 51338414Smckusick if (newvp != vp) 51438414Smckusick nfs_nput(newvp); 51538414Smckusick else 51638425Smckusick vrele(vp); 51738414Smckusick m_freem(mrep); 51838414Smckusick return (error); 51938414Smckusick } 52038414Smckusick ndp->ni_vp = newvp; 52139751Smckusick if (lockparent || vp == newvp) 52239751Smckusick nfs_lock(vp); 52338414Smckusick m_freem(mrep); 52449741Smckusick ndp->ni_nameiop |= SAVENAME; 52538414Smckusick return (0); 52638414Smckusick } 52738414Smckusick 52838414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 52938414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 53039751Smckusick nfs_lock(vp); 53138414Smckusick m_freem(mrep); 53238414Smckusick return (EISDIR); 53338414Smckusick } 53438414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 53539751Smckusick nfs_lock(vp); 53638414Smckusick m_freem(mrep); 53738414Smckusick return (error); 53838414Smckusick } 53938414Smckusick newvp = NFSTOV(np); 54039459Smckusick if (error = 54139459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 54239751Smckusick nfs_lock(vp); 54338425Smckusick nfs_nput(newvp); 54438414Smckusick m_freem(mrep); 54538414Smckusick return (error); 54638414Smckusick } 54738414Smckusick ndp->ni_vp = newvp; 54839751Smckusick if (lockparent) 54939751Smckusick nfs_lock(vp); 55045037Smckusick m_freem(mrep); 55149741Smckusick ndp->ni_nameiop |= SAVENAME; 55238414Smckusick return (0); 55338414Smckusick } 55438414Smckusick 55538414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 55638425Smckusick VREF(vp); 55738414Smckusick newvp = vp; 55838414Smckusick np = VTONFS(vp); 55938414Smckusick } else if (ndp->ni_isdotdot) { 56038414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 56138414Smckusick nfs_lock(vp); 56238414Smckusick m_freem(mrep); 56338414Smckusick return (error); 56438414Smckusick } 56538414Smckusick newvp = NFSTOV(np); 56638414Smckusick } else { 56738414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 56839751Smckusick nfs_lock(vp); 56938414Smckusick m_freem(mrep); 57038414Smckusick return (error); 57138414Smckusick } 57238414Smckusick newvp = NFSTOV(np); 57338414Smckusick } 57439459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 57539751Smckusick nfs_lock(vp); 57638414Smckusick if (newvp != vp) 57738414Smckusick nfs_nput(newvp); 57838414Smckusick else 57938425Smckusick vrele(vp); 58038414Smckusick m_freem(mrep); 58138414Smckusick return (error); 58238414Smckusick } 58338414Smckusick m_freem(mrep); 58438414Smckusick 58539751Smckusick if (vp == newvp || (lockparent && *ndp->ni_next == '\0')) 58639751Smckusick nfs_lock(vp); 58738414Smckusick ndp->ni_vp = newvp; 58849872Smckusick if (flag != LOOKUP && *ndp->ni_next == 0) 58949741Smckusick ndp->ni_nameiop |= SAVENAME; 59040251Smckusick if (error == 0 && ndp->ni_makeentry) { 59140251Smckusick np->n_ctime = np->n_vattr.va_ctime.tv_sec; 59238414Smckusick cache_enter(ndp); 59340251Smckusick } 59438414Smckusick return (error); 59538414Smckusick } 59638414Smckusick 59738414Smckusick /* 59841905Smckusick * nfs read call. 59941905Smckusick * Just call nfs_bioread() to do the work. 60041905Smckusick */ 60141905Smckusick nfs_read(vp, uiop, ioflag, cred) 60241905Smckusick register struct vnode *vp; 60341905Smckusick struct uio *uiop; 60441905Smckusick int ioflag; 60541905Smckusick struct ucred *cred; 60641905Smckusick { 60741905Smckusick if (vp->v_type != VREG) 60841905Smckusick return (EPERM); 60941905Smckusick return (nfs_bioread(vp, uiop, ioflag, cred)); 61041905Smckusick } 61141905Smckusick 61241905Smckusick /* 61338414Smckusick * nfs readlink call 61438414Smckusick */ 61538414Smckusick nfs_readlink(vp, uiop, cred) 61641905Smckusick struct vnode *vp; 61741905Smckusick struct uio *uiop; 61841905Smckusick struct ucred *cred; 61941905Smckusick { 62041905Smckusick if (vp->v_type != VLNK) 62141905Smckusick return (EPERM); 62241905Smckusick return (nfs_bioread(vp, uiop, 0, cred)); 62341905Smckusick } 62441905Smckusick 62541905Smckusick /* 62641905Smckusick * Do a readlink rpc. 62741905Smckusick * Called by nfs_doio() from below the buffer cache. 62841905Smckusick */ 62948054Smckusick nfs_readlinkrpc(vp, uiop, cred) 63039488Smckusick register struct vnode *vp; 63138414Smckusick struct uio *uiop; 63238414Smckusick struct ucred *cred; 63338414Smckusick { 63448054Smckusick register u_long *tl; 63539488Smckusick register caddr_t cp; 63639488Smckusick register long t1; 63739488Smckusick caddr_t bpos, dpos, cp2; 63839488Smckusick u_long xid; 63939488Smckusick int error = 0; 64039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 64138414Smckusick long len; 64238414Smckusick 64338414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 64438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 64538414Smckusick nfsm_fhtom(vp); 64648054Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, 0); 64738414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 64838414Smckusick nfsm_mtouio(uiop, len); 64938414Smckusick nfsm_reqdone; 65038414Smckusick return (error); 65138414Smckusick } 65238414Smckusick 65338414Smckusick /* 65441905Smckusick * nfs read rpc call 65541905Smckusick * Ditto above 65638414Smckusick */ 65748054Smckusick nfs_readrpc(vp, uiop, cred) 65839488Smckusick register struct vnode *vp; 65938414Smckusick struct uio *uiop; 66038414Smckusick struct ucred *cred; 66138414Smckusick { 66248054Smckusick register u_long *tl; 66339488Smckusick register caddr_t cp; 66439488Smckusick register long t1; 66539488Smckusick caddr_t bpos, dpos, cp2; 66639488Smckusick u_long xid; 66739488Smckusick int error = 0; 66839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 66938414Smckusick struct nfsmount *nmp; 67038414Smckusick long len, retlen, tsiz; 67138414Smckusick 67241398Smckusick nmp = VFSTONFS(vp->v_mount); 67338414Smckusick tsiz = uiop->uio_resid; 67438414Smckusick while (tsiz > 0) { 67538414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 67638414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 67738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 67838414Smckusick nfsm_fhtom(vp); 67948054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 68048054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 68148054Smckusick *tl++ = txdr_unsigned(len); 68248054Smckusick *tl = 0; 68348054Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, 1); 68438414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 68538414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 68638414Smckusick nfsm_mtouio(uiop, retlen); 68738414Smckusick m_freem(mrep); 68838414Smckusick if (retlen < len) 68938414Smckusick tsiz = 0; 69038414Smckusick else 69138414Smckusick tsiz -= len; 69238414Smckusick } 69338414Smckusick nfsmout: 69438414Smckusick return (error); 69538414Smckusick } 69638414Smckusick 69738414Smckusick /* 69838414Smckusick * nfs write call 69938414Smckusick */ 70048054Smckusick nfs_writerpc(vp, uiop, cred) 70139488Smckusick register struct vnode *vp; 70238414Smckusick struct uio *uiop; 70338414Smckusick struct ucred *cred; 70438414Smckusick { 70548054Smckusick register u_long *tl; 70639488Smckusick register caddr_t cp; 70739488Smckusick register long t1; 70839488Smckusick caddr_t bpos, dpos; 70939488Smckusick u_long xid; 71039488Smckusick int error = 0; 71139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 71238414Smckusick struct nfsmount *nmp; 71338414Smckusick long len, tsiz; 71438414Smckusick 71541398Smckusick nmp = VFSTONFS(vp->v_mount); 71638414Smckusick tsiz = uiop->uio_resid; 71738414Smckusick while (tsiz > 0) { 71838414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 71938414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 72038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 72138414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 72238414Smckusick nfsm_fhtom(vp); 72348054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 72448054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 72548054Smckusick *(tl+3) = txdr_unsigned(len); 72638414Smckusick nfsm_uiotom(uiop, len); 72748054Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, 1); 72838414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 72938414Smckusick m_freem(mrep); 73038414Smckusick tsiz -= len; 73138414Smckusick } 73238414Smckusick nfsmout: 73338414Smckusick return (error); 73438414Smckusick } 73538414Smckusick 73638414Smckusick /* 73739459Smckusick * nfs mknod call 73842246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 73942246Smckusick * set to specify the file type and the size field for rdev. 74039459Smckusick */ 74139459Smckusick /* ARGSUSED */ 74248054Smckusick nfs_mknod(ndp, vap, cred, p) 74339459Smckusick struct nameidata *ndp; 74439459Smckusick struct ucred *cred; 74542246Smckusick register struct vattr *vap; 74648054Smckusick struct proc *p; 74739459Smckusick { 74842246Smckusick register struct nfsv2_sattr *sp; 74948054Smckusick register u_long *tl; 75042246Smckusick register caddr_t cp; 75142246Smckusick register long t1, t2; 75242246Smckusick caddr_t bpos, dpos; 75342246Smckusick u_long xid; 75442246Smckusick int error = 0; 75542246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 75642246Smckusick u_long rdev; 75739459Smckusick 75842246Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 75942246Smckusick rdev = txdr_unsigned(vap->va_rdev); 76042246Smckusick #ifdef FIFO 76142246Smckusick else if (vap->va_type == VFIFO) 76242246Smckusick rdev = 0xffffffff; 76342246Smckusick #endif /* FIFO */ 76442246Smckusick else { 76542246Smckusick VOP_ABORTOP(ndp); 76642467Smckusick vput(ndp->ni_dvp); 76742246Smckusick return (EOPNOTSUPP); 76842246Smckusick } 76942246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 77042246Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 77149741Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR); 77242246Smckusick nfsm_fhtom(ndp->ni_dvp); 77349741Smckusick nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN); 77442246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 77542246Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 77642246Smckusick sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 77742246Smckusick sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 77842246Smckusick sp->sa_size = rdev; 77942246Smckusick /* or should these be VNOVAL ?? */ 78042246Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 78142246Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 78248054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1); 78342246Smckusick nfsm_reqdone; 78449741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 78542246Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 78642246Smckusick nfs_nput(ndp->ni_dvp); 78742246Smckusick return (error); 78839459Smckusick } 78939459Smckusick 79039459Smckusick /* 79138414Smckusick * nfs file create call 79238414Smckusick */ 79348054Smckusick nfs_create(ndp, vap, p) 79438414Smckusick register struct nameidata *ndp; 79538414Smckusick register struct vattr *vap; 79648054Smckusick struct proc *p; 79738414Smckusick { 79838884Smacklem register struct nfsv2_sattr *sp; 79948054Smckusick register u_long *tl; 80039488Smckusick register caddr_t cp; 80139488Smckusick register long t1, t2; 80239488Smckusick caddr_t bpos, dpos, cp2; 80339488Smckusick u_long xid; 80439488Smckusick int error = 0; 80539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 80638414Smckusick 80738414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 80838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 80949741Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR); 81038414Smckusick nfsm_fhtom(ndp->ni_dvp); 81149741Smckusick nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN); 81238884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 81346988Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 81438884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 81538884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 81638884Smacklem sp->sa_size = txdr_unsigned(0); 81738414Smckusick /* or should these be VNOVAL ?? */ 81838884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 81938884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 82048054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1); 82138414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 82238414Smckusick nfsm_reqdone; 82349741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 82441905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 82538414Smckusick nfs_nput(ndp->ni_dvp); 82638414Smckusick return (error); 82738414Smckusick } 82838414Smckusick 82938414Smckusick /* 83038414Smckusick * nfs file remove call 83141905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 83241905Smckusick * other processes using the vnode is renamed instead of removed and then 83339341Smckusick * removed later on the last close. 83441905Smckusick * - If v_usecount > 1 83539341Smckusick * If a rename is not already in the works 83639341Smckusick * call nfs_sillyrename() to set it up 83739341Smckusick * else 83839341Smckusick * do the remove rpc 83938414Smckusick */ 84048054Smckusick nfs_remove(ndp, p) 84138414Smckusick register struct nameidata *ndp; 84248054Smckusick struct proc *p; 84338414Smckusick { 84439341Smckusick register struct vnode *vp = ndp->ni_vp; 84539341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 84648054Smckusick register u_long *tl; 84739488Smckusick register caddr_t cp; 84839488Smckusick register long t1, t2; 84939488Smckusick caddr_t bpos, dpos; 85039488Smckusick u_long xid; 85139488Smckusick int error = 0; 85239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 85338414Smckusick 85439810Smckusick if (vp->v_usecount > 1) { 85539341Smckusick if (!np->n_sillyrename) 85648364Smckusick error = nfs_sillyrename(ndp, p); 85739341Smckusick } else { 85838414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 85938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 86049741Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)); 86138414Smckusick nfsm_fhtom(ndp->ni_dvp); 86249741Smckusick nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN); 86348054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, p, 1); 86438414Smckusick nfsm_reqdone; 86549741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 86641905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 86739751Smckusick /* 86839751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 86939751Smckusick * the reply to the retransmitted request will be ENOENT 87039751Smckusick * since the file was in fact removed 87139751Smckusick * Therefore, we cheat and return success. 87239751Smckusick */ 87339751Smckusick if (error == ENOENT) 87439751Smckusick error = 0; 87538414Smckusick } 87640042Smckusick np->n_attrstamp = 0; 87740112Smckusick if (ndp->ni_dvp == vp) 87840112Smckusick vrele(vp); 87938414Smckusick else 88040112Smckusick nfs_nput(ndp->ni_dvp); 88140112Smckusick nfs_nput(vp); 88238414Smckusick return (error); 88338414Smckusick } 88438414Smckusick 88538414Smckusick /* 88638414Smckusick * nfs file remove rpc called from nfs_inactive 88738414Smckusick */ 88848364Smckusick nfs_removeit(sp, p) 88948364Smckusick register struct sillyrename *sp; 89048054Smckusick struct proc *p; 89138414Smckusick { 89248054Smckusick register u_long *tl; 89339488Smckusick register caddr_t cp; 89439488Smckusick register long t1, t2; 89539488Smckusick caddr_t bpos, dpos; 89639488Smckusick u_long xid; 89739488Smckusick int error = 0; 89839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 89938414Smckusick 90038414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 90148364Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], sp->s_cred, 90248364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 90348364Smckusick nfsm_fhtom(sp->s_dvp); 90448364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 90548364Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, p, 1); 90638414Smckusick nfsm_reqdone; 90748364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 90838414Smckusick return (error); 90938414Smckusick } 91038414Smckusick 91138414Smckusick /* 91238414Smckusick * nfs file rename call 91338414Smckusick */ 91448054Smckusick nfs_rename(sndp, tndp, p) 91538414Smckusick register struct nameidata *sndp, *tndp; 91648054Smckusick struct proc *p; 91738414Smckusick { 91848054Smckusick register u_long *tl; 91939488Smckusick register caddr_t cp; 92039488Smckusick register long t1, t2; 92139488Smckusick caddr_t bpos, dpos; 92239488Smckusick u_long xid; 92339488Smckusick int error = 0; 92439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92538414Smckusick 92638414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 92738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 92849741Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) + 92949741Smckusick nfsm_rndup(tndp->ni_namelen)); /* or sndp->ni_cred?*/ 93038414Smckusick nfsm_fhtom(sndp->ni_dvp); 93149741Smckusick nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN); 93238414Smckusick nfsm_fhtom(tndp->ni_dvp); 93349741Smckusick nfsm_strtom(tndp->ni_ptr, tndp->ni_namelen, NFS_MAXNAMLEN); 93448054Smckusick nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1); 93538414Smckusick nfsm_reqdone; 93641905Smckusick VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED; 93741905Smckusick VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED; 93838414Smckusick if (sndp->ni_vp->v_type == VDIR) { 93938414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 94038414Smckusick cache_purge(tndp->ni_dvp); 94138414Smckusick cache_purge(sndp->ni_dvp); 94238414Smckusick } 94343360Smckusick if (tndp->ni_dvp == tndp->ni_vp) 94443360Smckusick vrele(tndp->ni_dvp); 94543360Smckusick else 94643360Smckusick vput(tndp->ni_dvp); 94742467Smckusick if (tndp->ni_vp) 94842467Smckusick vput(tndp->ni_vp); 94942467Smckusick vrele(sndp->ni_dvp); 95042467Smckusick vrele(sndp->ni_vp); 95140112Smckusick /* 95240112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 95340112Smckusick */ 95440112Smckusick if (error == ENOENT) 95540112Smckusick error = 0; 95638414Smckusick return (error); 95738414Smckusick } 95838414Smckusick 95938414Smckusick /* 96041905Smckusick * nfs file rename rpc called from nfs_remove() above 96138414Smckusick */ 96248364Smckusick nfs_renameit(sndp, sp, p) 96348364Smckusick register struct nameidata *sndp; 96448364Smckusick register struct sillyrename *sp; 96548054Smckusick struct proc *p; 96638414Smckusick { 96748054Smckusick register u_long *tl; 96839488Smckusick register caddr_t cp; 96939488Smckusick register long t1, t2; 97039488Smckusick caddr_t bpos, dpos; 97139488Smckusick u_long xid; 97239488Smckusick int error = 0; 97339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97438414Smckusick 97538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 97648364Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], sp->s_cred, 97749741Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) + 97848364Smckusick nfsm_rndup(sp->s_namlen)); /* or sndp->ni_cred?*/ 97938414Smckusick nfsm_fhtom(sndp->ni_dvp); 98049741Smckusick nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN); 98148364Smckusick nfsm_fhtom(sp->s_dvp); 98248364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 98348054Smckusick nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1); 98438414Smckusick nfsm_reqdone; 98549741Smckusick FREE(sndp->ni_pnbuf, M_NAMEI); 98641905Smckusick VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED; 98748364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 98838414Smckusick return (error); 98938414Smckusick } 99038414Smckusick 99138414Smckusick /* 99238414Smckusick * nfs hard link create call 99338414Smckusick */ 99448054Smckusick nfs_link(vp, ndp, p) 99539488Smckusick register struct vnode *vp; 99638414Smckusick register struct nameidata *ndp; 99748054Smckusick struct proc *p; 99838414Smckusick { 99948054Smckusick register u_long *tl; 100039488Smckusick register caddr_t cp; 100139488Smckusick register long t1, t2; 100239488Smckusick caddr_t bpos, dpos; 100339488Smckusick u_long xid; 100439488Smckusick int error = 0; 100539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 100638414Smckusick 100738425Smckusick if (ndp->ni_dvp != vp) 100838425Smckusick nfs_lock(vp); 100938414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 101038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 101149741Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)); 101238414Smckusick nfsm_fhtom(vp); 101338414Smckusick nfsm_fhtom(ndp->ni_dvp); 101449741Smckusick nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN); 101548054Smckusick nfsm_request(vp, NFSPROC_LINK, p, 1); 101638414Smckusick nfsm_reqdone; 101749741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 101840042Smckusick VTONFS(vp)->n_attrstamp = 0; 101941905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 102038425Smckusick if (ndp->ni_dvp != vp) 102138425Smckusick nfs_unlock(vp); 102238414Smckusick nfs_nput(ndp->ni_dvp); 102340112Smckusick /* 102440112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 102540112Smckusick */ 102640112Smckusick if (error == EEXIST) 102740112Smckusick error = 0; 102838414Smckusick return (error); 102938414Smckusick } 103038414Smckusick 103138414Smckusick /* 103238414Smckusick * nfs symbolic link create call 103338414Smckusick */ 103448054Smckusick nfs_symlink(ndp, vap, nm, p) 103538414Smckusick struct nameidata *ndp; 103638414Smckusick struct vattr *vap; 103738414Smckusick char *nm; /* is this the path ?? */ 103848054Smckusick struct proc *p; 103938414Smckusick { 104038884Smacklem register struct nfsv2_sattr *sp; 104148054Smckusick register u_long *tl; 104239488Smckusick register caddr_t cp; 104339488Smckusick register long t1, t2; 104439488Smckusick caddr_t bpos, dpos; 104539488Smckusick u_long xid; 104639488Smckusick int error = 0; 104739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 104838414Smckusick 104938414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 105038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 105149741Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_UNSIGNED); 105238414Smckusick nfsm_fhtom(ndp->ni_dvp); 105349741Smckusick nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN); 105438414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 105538884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 105638884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 105738884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 105838884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 105938884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 106040112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 106138884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 106248054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_SYMLINK, p, 1); 106338414Smckusick nfsm_reqdone; 106449741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 106541905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 106638414Smckusick nfs_nput(ndp->ni_dvp); 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 make dir call 107738414Smckusick */ 107848054Smckusick nfs_mkdir(ndp, vap, p) 107939488Smckusick register struct nameidata *ndp; 108038414Smckusick struct vattr *vap; 108148054Smckusick struct proc *p; 108238414Smckusick { 108338884Smacklem register struct nfsv2_sattr *sp; 108448054Smckusick register u_long *tl; 108539488Smckusick register caddr_t cp; 108639488Smckusick register long t1, t2; 108741905Smckusick register int len; 108839488Smckusick caddr_t bpos, dpos, cp2; 108939488Smckusick u_long xid; 109041905Smckusick int error = 0, firsttry = 1; 109139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 109238414Smckusick 109349741Smckusick len = ndp->ni_namelen; 109438414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 109538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 109641905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 109738414Smckusick nfsm_fhtom(ndp->ni_dvp); 109849741Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 109938884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 110038884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 110138884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 110238884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 110338884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 110440112Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 110538884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 110648054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_MKDIR, p, 1); 110738414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 110838414Smckusick nfsm_reqdone; 110941905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 111040112Smckusick /* 111141905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 111241905Smckusick * if we can succeed in looking up the directory. 111341905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 111441905Smckusick * is above the if on errors. (Ugh) 111540112Smckusick */ 111641905Smckusick if (error == EEXIST && firsttry) { 111741905Smckusick firsttry = 0; 111840112Smckusick error = 0; 111941905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 112041905Smckusick ndp->ni_vp = NULL; 112141905Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, 112241905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 112341905Smckusick nfsm_fhtom(ndp->ni_dvp); 112449741Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 112548054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_LOOKUP, p, 1); 112641905Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 112741905Smckusick if (ndp->ni_vp->v_type != VDIR) { 112841905Smckusick vput(ndp->ni_vp); 112941905Smckusick error = EEXIST; 113041905Smckusick } 113141905Smckusick m_freem(mrep); 113241905Smckusick } 113349741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 113441905Smckusick nfs_nput(ndp->ni_dvp); 113538414Smckusick return (error); 113638414Smckusick } 113738414Smckusick 113838414Smckusick /* 113938414Smckusick * nfs remove directory call 114038414Smckusick */ 114148054Smckusick nfs_rmdir(ndp, p) 114238414Smckusick register struct nameidata *ndp; 114348054Smckusick struct proc *p; 114438414Smckusick { 114548054Smckusick register u_long *tl; 114639488Smckusick register caddr_t cp; 114739488Smckusick register long t1, t2; 114839488Smckusick caddr_t bpos, dpos; 114939488Smckusick u_long xid; 115039488Smckusick int error = 0; 115139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 115238414Smckusick 115338414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 115438414Smckusick vrele(ndp->ni_dvp); 115538414Smckusick nfs_nput(ndp->ni_dvp); 115638414Smckusick return (EINVAL); 115738414Smckusick } 115838414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 115938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 116049741Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)); 116138414Smckusick nfsm_fhtom(ndp->ni_dvp); 116249741Smckusick nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN); 116348054Smckusick nfsm_request(ndp->ni_dvp, NFSPROC_RMDIR, p, 1); 116438414Smckusick nfsm_reqdone; 116549741Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 116641905Smckusick VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED; 116738884Smacklem cache_purge(ndp->ni_dvp); 116838884Smacklem cache_purge(ndp->ni_vp); 116938884Smacklem nfs_nput(ndp->ni_vp); 117038884Smacklem nfs_nput(ndp->ni_dvp); 117140112Smckusick /* 117240112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 117340112Smckusick */ 117440112Smckusick if (error == ENOENT) 117540112Smckusick error = 0; 117638414Smckusick return (error); 117738414Smckusick } 117838414Smckusick 117938414Smckusick /* 118038414Smckusick * nfs readdir call 118138414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 118238414Smckusick * order so that it looks more sensible. This appears consistent with the 118338414Smckusick * Ultrix implementation of NFS. 118438414Smckusick */ 118540296Smckusick nfs_readdir(vp, uiop, cred, eofflagp) 118639488Smckusick register struct vnode *vp; 118738414Smckusick struct uio *uiop; 118838414Smckusick struct ucred *cred; 118940296Smckusick int *eofflagp; 119038414Smckusick { 119141905Smckusick register struct nfsnode *np = VTONFS(vp); 119241905Smckusick int tresid, error; 119341905Smckusick struct vattr vattr; 119441905Smckusick 119541905Smckusick if (vp->v_type != VDIR) 119641905Smckusick return (EPERM); 119741905Smckusick /* 119841905Smckusick * First, check for hit on the EOF offset cache 119941905Smckusick */ 120041905Smckusick if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset && 120141905Smckusick (np->n_flag & NMODIFIED) == 0 && 120248054Smckusick nfs_dogetattr(vp, &vattr, cred, 0, uiop->uio_procp) == 0 && 120341905Smckusick np->n_mtime == vattr.va_mtime.tv_sec) { 120441905Smckusick *eofflagp = 1; 120541905Smckusick nfsstats.direofcache_hits++; 120641905Smckusick return (0); 120741905Smckusick } 120841905Smckusick 120941905Smckusick /* 121041905Smckusick * Call nfs_bioread() to do the real work. 121141905Smckusick */ 121241905Smckusick tresid = uiop->uio_resid; 121341905Smckusick error = nfs_bioread(vp, uiop, 0, cred); 121441905Smckusick 121541905Smckusick if (!error && uiop->uio_resid == tresid) { 121641905Smckusick *eofflagp = 1; 121741905Smckusick nfsstats.direofcache_misses++; 121841905Smckusick } else 121941905Smckusick *eofflagp = 0; 122041905Smckusick return (error); 122141905Smckusick } 122241905Smckusick 122341905Smckusick /* 122441905Smckusick * Readdir rpc call. 122541905Smckusick * Called from below the buffer cache by nfs_doio(). 122641905Smckusick */ 122748054Smckusick nfs_readdirrpc(vp, uiop, cred) 122841905Smckusick register struct vnode *vp; 122941905Smckusick struct uio *uiop; 123041905Smckusick struct ucred *cred; 123141905Smckusick { 123238414Smckusick register long len; 123338414Smckusick register struct direct *dp; 123448054Smckusick register u_long *tl; 123539488Smckusick register caddr_t cp; 123639488Smckusick register long t1; 123741905Smckusick long tlen, lastlen; 123839488Smckusick caddr_t bpos, dpos, cp2; 123939488Smckusick u_long xid; 124039488Smckusick int error = 0; 124139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 124238414Smckusick struct mbuf *md2; 124338414Smckusick caddr_t dpos2; 124438414Smckusick int siz; 124540296Smckusick int more_dirs = 1; 124638414Smckusick off_t off, savoff; 124738414Smckusick struct direct *savdp; 124840296Smckusick struct nfsmount *nmp; 124940296Smckusick struct nfsnode *np = VTONFS(vp); 125040296Smckusick long tresid; 125138414Smckusick 125241398Smckusick nmp = VFSTONFS(vp->v_mount); 125340296Smckusick tresid = uiop->uio_resid; 125440296Smckusick /* 125540296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 125648054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 125741905Smckusick * The stopping criteria is EOF or buffer full. 125840296Smckusick */ 125948054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 126040296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 126140296Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 126240296Smckusick nfsm_fhtom(vp); 126348054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 126448054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 126548054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 126648054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 126748054Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, 0); 126840296Smckusick siz = 0; 126948054Smckusick nfsm_disect(tl, u_long *, NFSX_UNSIGNED); 127048054Smckusick more_dirs = fxdr_unsigned(int, *tl); 127140296Smckusick 127240296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 127340296Smckusick dpos2 = dpos; 127440296Smckusick md2 = md; 127540296Smckusick 127640296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 127741905Smckusick off = uiop->uio_offset; 127842246Smckusick #ifdef lint 127942246Smckusick dp = (struct direct *)0; 128042246Smckusick #endif /* lint */ 128140296Smckusick while (more_dirs && siz < uiop->uio_resid) { 128240296Smckusick savoff = off; /* Hold onto offset and dp */ 128340296Smckusick savdp = dp; 128448054Smckusick nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED); 128548054Smckusick dp = (struct direct *)tl; 128648054Smckusick dp->d_ino = fxdr_unsigned(u_long, *tl++); 128748054Smckusick len = fxdr_unsigned(int, *tl); 128840296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 128940296Smckusick error = EBADRPC; 129040296Smckusick m_freem(mrep); 129140296Smckusick goto nfsmout; 129240296Smckusick } 129340296Smckusick dp->d_namlen = (u_short)len; 129440296Smckusick nfsm_adv(len); /* Point past name */ 129540296Smckusick tlen = nfsm_rndup(len); 129640296Smckusick /* 129740296Smckusick * This should not be necessary, but some servers have 129840296Smckusick * broken XDR such that these bytes are not null filled. 129940296Smckusick */ 130040296Smckusick if (tlen != len) { 130140296Smckusick *dpos = '\0'; /* Null-terminate */ 130240296Smckusick nfsm_adv(tlen - len); 130340296Smckusick len = tlen; 130440296Smckusick } 130548054Smckusick nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED); 130648054Smckusick off = fxdr_unsigned(off_t, *tl); 130748054Smckusick *tl++ = 0; /* Ensures null termination of name */ 130848054Smckusick more_dirs = fxdr_unsigned(int, *tl); 130940296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 131040296Smckusick siz += dp->d_reclen; 131140296Smckusick } 131240296Smckusick /* 131340296Smckusick * If at end of rpc data, get the eof boolean 131440296Smckusick */ 131540296Smckusick if (!more_dirs) { 131648054Smckusick nfsm_disecton(tl, u_long *, NFSX_UNSIGNED); 131748054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 131838414Smckusick 131940296Smckusick /* 132040296Smckusick * If at EOF, cache directory offset 132140296Smckusick */ 132241905Smckusick if (!more_dirs) 132340296Smckusick np->n_direofoffset = off; 132438414Smckusick } 132540296Smckusick /* 132640296Smckusick * If there is too much to fit in the data buffer, use savoff and 132740296Smckusick * savdp to trim off the last record. 132840296Smckusick * --> we are not at eof 132940296Smckusick */ 133040296Smckusick if (siz > uiop->uio_resid) { 133140296Smckusick off = savoff; 133240296Smckusick siz -= dp->d_reclen; 133340296Smckusick dp = savdp; 133440296Smckusick more_dirs = 0; /* Paranoia */ 133540113Smckusick } 133640296Smckusick if (siz > 0) { 133741905Smckusick lastlen = dp->d_reclen; 133840296Smckusick md = md2; 133940296Smckusick dpos = dpos2; 134040296Smckusick nfsm_mtouio(uiop, siz); 134140296Smckusick uiop->uio_offset = off; 134240296Smckusick } else 134340296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 134440296Smckusick m_freem(mrep); 134538414Smckusick } 134641905Smckusick /* 134748054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 134841905Smckusick * by increasing d_reclen for the last record. 134941905Smckusick */ 135041905Smckusick if (uiop->uio_resid < tresid) { 135148054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 135241905Smckusick if (len > 0) { 135341905Smckusick dp = (struct direct *) 135441905Smckusick (uiop->uio_iov->iov_base - lastlen); 135541905Smckusick dp->d_reclen += len; 135641905Smckusick uiop->uio_iov->iov_base += len; 135741905Smckusick uiop->uio_iov->iov_len -= len; 135841905Smckusick uiop->uio_resid -= len; 135941905Smckusick } 136041905Smckusick } 136140296Smckusick nfsmout: 136238414Smckusick return (error); 136338414Smckusick } 136438414Smckusick 136539488Smckusick static char hextoasc[] = "0123456789abcdef"; 136638414Smckusick 136738414Smckusick /* 136838414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 136938414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 137038414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 137138414Smckusick * nfsnode. There is the potential for another process on a different client 137238414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 137338414Smckusick * nfs_rename() completes, but... 137438414Smckusick */ 137548364Smckusick nfs_sillyrename(ndp, p) 137639488Smckusick register struct nameidata *ndp; 137748054Smckusick struct proc *p; 137838414Smckusick { 137938414Smckusick register struct nfsnode *np; 138038414Smckusick register struct sillyrename *sp; 138138414Smckusick int error; 138238414Smckusick short pid; 138338414Smckusick 138438414Smckusick np = VTONFS(ndp->ni_dvp); 138539341Smckusick cache_purge(ndp->ni_dvp); 1386*51986Smckusick #ifdef SILLYSEPARATE 138738414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 138848364Smckusick M_NFSREQ, M_WAITOK); 1389*51986Smckusick #else 1390*51986Smckusick sp = &np->n_silly; 1391*51986Smckusick #endif 139238414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 139338414Smckusick np = VTONFS(ndp->ni_vp); 139448364Smckusick sp->s_cred = crdup(ndp->ni_cred); 139548364Smckusick sp->s_dvp = ndp->ni_dvp; 139648364Smckusick VREF(sp->s_dvp); 139738414Smckusick 139838414Smckusick /* Fudge together a funny name */ 139948054Smckusick pid = p->p_pid; 140048364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 140148364Smckusick sp->s_namlen = 12; 140248364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 140348364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 140448364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 140548364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 140638414Smckusick 140738414Smckusick /* Try lookitups until we get one that isn't there */ 140848364Smckusick while (nfs_lookitup(sp, (nfsv2fh_t *)0, p) == 0) { 140948364Smckusick sp->s_name[4]++; 141048364Smckusick if (sp->s_name[4] > 'z') { 141138414Smckusick error = EINVAL; 141238414Smckusick goto bad; 141338414Smckusick } 141438414Smckusick } 141548364Smckusick if (error = nfs_renameit(ndp, sp, p)) 141638414Smckusick goto bad; 141748364Smckusick nfs_lookitup(sp, &np->n_fh, p); 141838414Smckusick np->n_sillyrename = sp; 141938414Smckusick return (0); 142038414Smckusick bad: 142148364Smckusick vrele(sp->s_dvp); 142248364Smckusick crfree(sp->s_cred); 1423*51986Smckusick #ifdef SILLYSEPARATE 142448364Smckusick free((caddr_t)sp, M_NFSREQ); 1425*51986Smckusick #endif 142638414Smckusick return (error); 142738414Smckusick } 142838414Smckusick 142938414Smckusick /* 143038414Smckusick * Look up a file name for silly rename stuff. 143138414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 143238414Smckusick * into the nfsnode table. 143338414Smckusick * If fhp != NULL it copies the returned file handle out 143438414Smckusick */ 143548364Smckusick nfs_lookitup(sp, fhp, p) 143648364Smckusick register struct sillyrename *sp; 143738414Smckusick nfsv2fh_t *fhp; 143848054Smckusick struct proc *p; 143938414Smckusick { 144048364Smckusick register struct vnode *vp = sp->s_dvp; 144148054Smckusick register u_long *tl; 144239488Smckusick register caddr_t cp; 144339488Smckusick register long t1, t2; 144439488Smckusick caddr_t bpos, dpos, cp2; 144539488Smckusick u_long xid; 144639488Smckusick int error = 0; 144739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 144838414Smckusick long len; 144938414Smckusick 145038414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 145148364Smckusick len = sp->s_namlen; 145248364Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], sp->s_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 145338414Smckusick nfsm_fhtom(vp); 145448364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 145548054Smckusick nfsm_request(vp, NFSPROC_LOOKUP, p, 1); 145638414Smckusick if (fhp != NULL) { 145738414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 145838414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 145938414Smckusick } 146038414Smckusick nfsm_reqdone; 146138414Smckusick return (error); 146238414Smckusick } 146338414Smckusick 146438414Smckusick /* 146538414Smckusick * Kludge City.. 146638414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 146741905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 146838414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 146938414Smckusick * nfsiobuf area. 147038414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 147138414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 147238414Smckusick * a lot more work than bcopy() and also it currently happens in the 147338414Smckusick * context of the swapper process (2). 147438414Smckusick */ 147538414Smckusick nfs_bmap(vp, bn, vpp, bnp) 147638414Smckusick struct vnode *vp; 147738414Smckusick daddr_t bn; 147838414Smckusick struct vnode **vpp; 147938414Smckusick daddr_t *bnp; 148038414Smckusick { 148138414Smckusick if (vpp != NULL) 148238414Smckusick *vpp = vp; 148338414Smckusick if (bnp != NULL) 148441398Smckusick *bnp = bn * btodb(vp->v_mount->mnt_stat.f_bsize); 148538414Smckusick return (0); 148638414Smckusick } 148738414Smckusick 148838414Smckusick /* 148938884Smacklem * Strategy routine for phys. i/o 149038884Smacklem * If the biod's are running, queue a request 149138884Smacklem * otherwise just call nfs_doio() to get it done 149238414Smckusick */ 149338414Smckusick nfs_strategy(bp) 149438414Smckusick register struct buf *bp; 149538414Smckusick { 149638884Smacklem register struct buf *dp; 149739341Smckusick register int i; 149838884Smacklem int error = 0; 149939341Smckusick int fnd = 0; 150038884Smacklem 150138884Smacklem /* 150241905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 150341905Smckusick * doesn't set it, I will. 150446450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 150541905Smckusick * be hanging about after the process terminates. 150641905Smckusick */ 150746988Smckusick if ((bp->b_flags & B_PHYS) == 0) { 150846988Smckusick if (bp->b_flags & B_ASYNC) 150946988Smckusick bp->b_proc = (struct proc *)0; 151046988Smckusick else 151147573Skarels bp->b_proc = curproc; 151246988Smckusick } 151341905Smckusick /* 151446450Skarels * If the op is asynchronous and an i/o daemon is waiting 151538884Smacklem * queue the request, wake it up and wait for completion 151646450Skarels * otherwise just do it ourselves. 151738884Smacklem */ 151846988Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 151946988Smckusick return (nfs_doio(bp)); 152046988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 152146988Smckusick if (nfs_iodwant[i]) { 152239341Smckusick dp = &nfs_bqueue; 152339341Smckusick if (dp->b_actf == NULL) { 152439341Smckusick dp->b_actl = bp; 152539341Smckusick bp->b_actf = dp; 152639341Smckusick } else { 152739341Smckusick dp->b_actf->b_actl = bp; 152839341Smckusick bp->b_actf = dp->b_actf; 152939341Smckusick } 153039341Smckusick dp->b_actf = bp; 153139341Smckusick bp->b_actl = dp; 153239341Smckusick fnd++; 153339341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 153439341Smckusick break; 153538884Smacklem } 153639341Smckusick } 153739341Smckusick if (!fnd) 153838884Smacklem error = nfs_doio(bp); 153938884Smacklem return (error); 154038884Smacklem } 154138884Smacklem 154238884Smacklem /* 154338884Smacklem * Fun and games with i/o 154438884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 154538884Smacklem * mapping the data buffer into kernel virtual space and doing the 154638884Smacklem * nfs read or write rpc's from it. 154741905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 154841905Smckusick * otherwise it is called by the nfsiods to do what would normally be 154938884Smacklem * partially disk interrupt driven. 155038884Smacklem */ 155138884Smacklem nfs_doio(bp) 155238884Smacklem register struct buf *bp; 155338884Smacklem { 155438414Smckusick register struct uio *uiop; 155538414Smckusick register struct vnode *vp; 155639341Smckusick struct nfsnode *np; 155738884Smacklem struct ucred *cr; 155841539Smckusick int error; 155941539Smckusick struct uio uio; 156041539Smckusick struct iovec io; 156138414Smckusick 156238414Smckusick vp = bp->b_vp; 156340251Smckusick np = VTONFS(vp); 156438414Smckusick uiop = &uio; 156538414Smckusick uiop->uio_iov = &io; 156638414Smckusick uiop->uio_iovcnt = 1; 156738414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 156848054Smckusick uiop->uio_procp = (struct proc *)0; 156939751Smckusick 157038414Smckusick /* 157138884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 157238884Smacklem * the Nfsiomap pte's 157338884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 157438884Smacklem * and a guess at a group 157538414Smckusick */ 157638884Smacklem if (bp->b_flags & B_PHYS) { 157748054Smckusick if (bp->b_flags & B_DIRTY) 157848054Smckusick uiop->uio_procp = pageproc; 157948054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 158041539Smckusick /* mapping was already done by vmapbuf */ 158141539Smckusick io.iov_base = bp->b_un.b_addr; 158239751Smckusick 158338884Smacklem /* 158439751Smckusick * And do the i/o rpc 158539751Smckusick */ 158639751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 158739823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 158839751Smckusick if (bp->b_flags & B_READ) { 158939751Smckusick uiop->uio_rw = UIO_READ; 159039751Smckusick nfsstats.read_physios++; 159148054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 159245717Smckusick (void) vnode_pager_uncache(vp); 159339751Smckusick } else { 159439751Smckusick uiop->uio_rw = UIO_WRITE; 159539751Smckusick nfsstats.write_physios++; 159648054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 159739341Smckusick } 159839751Smckusick 159939751Smckusick /* 160039751Smckusick * Finally, release pte's used by physical i/o 160139751Smckusick */ 160238884Smacklem crfree(cr); 160339751Smckusick } else { 160439751Smckusick if (bp->b_flags & B_READ) { 160539751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 160639751Smckusick io.iov_base = bp->b_un.b_addr; 160739751Smckusick uiop->uio_rw = UIO_READ; 160841905Smckusick switch (vp->v_type) { 160941905Smckusick case VREG: 161041905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 161141905Smckusick nfsstats.read_bios++; 161248054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 161341905Smckusick break; 161441905Smckusick case VLNK: 161541905Smckusick uiop->uio_offset = 0; 161641905Smckusick nfsstats.readlink_bios++; 161748054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 161841905Smckusick break; 161941905Smckusick case VDIR: 162041905Smckusick uiop->uio_offset = bp->b_lblkno; 162141905Smckusick nfsstats.readdir_bios++; 162248054Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 162341905Smckusick /* 162441905Smckusick * Save offset cookie in b_blkno. 162541905Smckusick */ 162641905Smckusick bp->b_blkno = uiop->uio_offset; 162741905Smckusick break; 162841905Smckusick }; 162941905Smckusick bp->b_error = error; 163039751Smckusick } else { 163139751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 163239751Smckusick - bp->b_dirtyoff; 163339823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 163439751Smckusick + bp->b_dirtyoff; 163539751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 163639751Smckusick uiop->uio_rw = UIO_WRITE; 163739751Smckusick nfsstats.write_bios++; 163841905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 163948054Smckusick bp->b_wcred); 164039751Smckusick if (error) { 164139751Smckusick np->n_error = error; 164239751Smckusick np->n_flag |= NWRITEERR; 164339751Smckusick } 164439751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 164539751Smckusick } 164638884Smacklem } 164739751Smckusick if (error) 164839751Smckusick bp->b_flags |= B_ERROR; 164939751Smckusick bp->b_resid = uiop->uio_resid; 165038414Smckusick biodone(bp); 165138414Smckusick return (error); 165238414Smckusick } 165338884Smacklem 165438884Smacklem /* 165548054Smckusick * Mmap a file 165648054Smckusick * 165748054Smckusick * NB Currently unsupported. 165848054Smckusick */ 165948054Smckusick /* ARGSUSED */ 166048054Smckusick nfs_mmap(vp, fflags, cred, p) 166148054Smckusick struct vnode *vp; 166248054Smckusick int fflags; 166348054Smckusick struct ucred *cred; 166448054Smckusick struct proc *p; 166548054Smckusick { 166648054Smckusick 166748054Smckusick return (EINVAL); 166848054Smckusick } 166948054Smckusick 167048054Smckusick /* 167138884Smacklem * Flush all the blocks associated with a vnode. 167238884Smacklem * Walk through the buffer pool and push any dirty pages 167338884Smacklem * associated with the vnode. 167438884Smacklem */ 167539488Smckusick /* ARGSUSED */ 167648054Smckusick nfs_fsync(vp, fflags, cred, waitfor, p) 167738884Smacklem register struct vnode *vp; 167838884Smacklem int fflags; 167938884Smacklem struct ucred *cred; 168039587Smckusick int waitfor; 168148054Smckusick struct proc *p; 168238884Smacklem { 168338884Smacklem register struct nfsnode *np = VTONFS(vp); 168439751Smckusick int error = 0; 168538884Smacklem 168638884Smacklem if (np->n_flag & NMODIFIED) { 168738884Smacklem np->n_flag &= ~NMODIFIED; 168839751Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 168938884Smacklem } 169039751Smckusick if (!error && (np->n_flag & NWRITEERR)) 169139751Smckusick error = np->n_error; 169238884Smacklem return (error); 169338884Smacklem } 169439672Smckusick 169539672Smckusick /* 169646201Smckusick * NFS advisory byte-level locks. 169746201Smckusick * Currently unsupported. 169846201Smckusick */ 169946201Smckusick nfs_advlock(vp, id, op, fl, flags) 170046201Smckusick struct vnode *vp; 170146201Smckusick caddr_t id; 170246201Smckusick int op; 170346201Smckusick struct flock *fl; 170446201Smckusick int flags; 170546201Smckusick { 170646201Smckusick 170746201Smckusick return (EOPNOTSUPP); 170846201Smckusick } 170946201Smckusick 171046201Smckusick /* 171139672Smckusick * Print out the contents of an nfsnode. 171239672Smckusick */ 171339672Smckusick nfs_print(vp) 171439672Smckusick struct vnode *vp; 171539672Smckusick { 171639672Smckusick register struct nfsnode *np = VTONFS(vp); 171739672Smckusick 171840294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 171940294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 172040294Smckusick #ifdef FIFO 172140294Smckusick if (vp->v_type == VFIFO) 172240294Smckusick fifo_printinfo(vp); 172340294Smckusick #endif /* FIFO */ 172440294Smckusick printf("%s\n", (np->n_flag & NLOCKED) ? " (LOCKED)" : ""); 172539914Smckusick if (np->n_lockholder == 0) 172639914Smckusick return; 172739914Smckusick printf("\towner pid %d", np->n_lockholder); 172839914Smckusick if (np->n_lockwaiter) 172939914Smckusick printf(" waiting pid %d", np->n_lockwaiter); 173039914Smckusick printf("\n"); 173139672Smckusick } 173251573Smckusick 173351573Smckusick /* 173451573Smckusick * NFS directory offset lookup. 173551573Smckusick * Currently unsupported. 173651573Smckusick */ 173751573Smckusick nfs_blkatoff(vp, offset, res, bpp) 173851573Smckusick struct vnode *vp; 173951573Smckusick off_t offset; 174051573Smckusick char **res; 174151573Smckusick struct buf **bpp; 174251573Smckusick { 174351573Smckusick 174451573Smckusick return (EOPNOTSUPP); 174551573Smckusick } 174651573Smckusick 174751573Smckusick /* 174851573Smckusick * NFS flat namespace lookup. 174951573Smckusick * Currently unsupported. 175051573Smckusick */ 175151573Smckusick nfs_vget(mp, ino, vpp) 175251573Smckusick struct mount *mp; 175351573Smckusick ino_t ino; 175451573Smckusick struct vnode **vpp; 175551573Smckusick { 175651573Smckusick 175751573Smckusick return (EOPNOTSUPP); 175851573Smckusick } 175951573Smckusick 176051573Smckusick /* 176151573Smckusick * NFS flat namespace allocation. 176251573Smckusick * Currently unsupported. 176351573Smckusick */ 176451573Smckusick nfs_valloc(pvp, mode, cred, vpp) 176551573Smckusick struct vnode *pvp; 176651573Smckusick int mode; 176751573Smckusick struct ucred *cred; 176851573Smckusick struct vnode **vpp; 176951573Smckusick { 177051573Smckusick 177151573Smckusick return (EOPNOTSUPP); 177251573Smckusick } 177351573Smckusick 177451573Smckusick /* 177551573Smckusick * NFS flat namespace free. 177651573Smckusick * Currently unsupported. 177751573Smckusick */ 177851573Smckusick void 177951573Smckusick nfs_vfree(pvp, ino, mode) 178051573Smckusick struct vnode *pvp; 178151573Smckusick ino_t ino; 178251573Smckusick int mode; 178351573Smckusick { 178451573Smckusick 178551573Smckusick return; 178651573Smckusick } 178751573Smckusick 178851573Smckusick /* 178951573Smckusick * NFS file truncation. 179051573Smckusick */ 179151573Smckusick nfs_truncate(vp, length, flags) 179251573Smckusick struct vnode *vp; 179351573Smckusick u_long length; 179451573Smckusick int flags; 179551573Smckusick { 179651573Smckusick 179751573Smckusick /* Use nfs_setattr */ 179851573Smckusick printf("nfs_truncate: need to implement!!"); 179951573Smckusick return (EOPNOTSUPP); 180051573Smckusick } 180151573Smckusick 180251573Smckusick /* 180351573Smckusick * NFS update. 180451573Smckusick */ 180551573Smckusick nfs_update(vp, ta, tm, waitfor) 180651573Smckusick struct vnode *vp; 180751573Smckusick struct timeval *ta; 180851573Smckusick struct timeval *tm; 180951573Smckusick int waitfor; 181051573Smckusick { 181151573Smckusick 181251573Smckusick /* Use nfs_setattr */ 181351573Smckusick printf("nfs_update: need to implement!!"); 181451573Smckusick return (EOPNOTSUPP); 181551573Smckusick } 1816