138414Smckusick /* 238414Smckusick * Copyright (c) 1989 The Regents of the University of California. 338414Smckusick * All rights reserved. 438414Smckusick * 538414Smckusick * This code is derived from software contributed to Berkeley by 638414Smckusick * Rick Macklem at The University of Guelph. 738414Smckusick * 838414Smckusick * Redistribution and use in source and binary forms are permitted 938414Smckusick * provided that the above copyright notice and this paragraph are 1038414Smckusick * duplicated in all such forms and that any documentation, 1138414Smckusick * advertising materials, and other materials related to such 1238414Smckusick * distribution and use acknowledge that the software was developed 1338414Smckusick * by the University of California, Berkeley. The name of the 1438414Smckusick * University may not be used to endorse or promote products derived 1538414Smckusick * from this software without specific prior written permission. 1638414Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738414Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838414Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938414Smckusick * 20*39394Smckusick * @(#)nfs_vnops.c 7.9 (Berkeley) 10/24/89 2138414Smckusick */ 2238414Smckusick 2338414Smckusick /* 2438414Smckusick * vnode op calls for sun nfs version 2 2538414Smckusick */ 2638414Smckusick 2738414Smckusick #include "machine/pte.h" 2838414Smckusick #include "machine/mtpr.h" 2938414Smckusick #include "strings.h" 3038414Smckusick #include "param.h" 3138414Smckusick #include "user.h" 3238414Smckusick #include "proc.h" 3338414Smckusick #include "mount.h" 3438414Smckusick #include "buf.h" 3538414Smckusick #include "vm.h" 3638425Smckusick #include "../ufs/dir.h" 3738414Smckusick #include "malloc.h" 3838414Smckusick #include "mbuf.h" 3938414Smckusick #include "uio.h" 4038414Smckusick #include "ucred.h" 4138414Smckusick #include "namei.h" 4238414Smckusick #include "errno.h" 4338414Smckusick #include "file.h" 4438414Smckusick #include "conf.h" 4538414Smckusick #include "vnode.h" 4638414Smckusick #include "../ufs/inode.h" 4738884Smacklem #include "map.h" 4838414Smckusick #include "nfsv2.h" 4938414Smckusick #include "nfs.h" 5038414Smckusick #include "nfsnode.h" 5138414Smckusick #include "nfsmount.h" 5238414Smckusick #include "xdr_subs.h" 5338414Smckusick #include "nfsm_subs.h" 5438884Smacklem #include "nfsiom.h" 5538414Smckusick 5638414Smckusick /* Defs */ 5738414Smckusick #define TRUE 1 5838414Smckusick #define FALSE 0 5938414Smckusick 6038414Smckusick /* Global vars */ 6138414Smckusick int nfs_lookup(), 6238414Smckusick nfs_create(), 6338414Smckusick nfs_open(), 6438414Smckusick nfs_close(), 6538414Smckusick nfs_access(), 6638414Smckusick nfs_getattr(), 6738414Smckusick nfs_setattr(), 6838414Smckusick nfs_read(), 6938414Smckusick nfs_write(), 7038414Smckusick vfs_noop(), 7138414Smckusick vfs_nullop(), 7238414Smckusick nfs_remove(), 7338414Smckusick nfs_link(), 7438414Smckusick nfs_rename(), 7538414Smckusick nfs_mkdir(), 7638414Smckusick nfs_rmdir(), 7738414Smckusick nfs_symlink(), 7838414Smckusick nfs_readdir(), 7938414Smckusick nfs_readlink(), 8038414Smckusick nfs_abortop(), 8138414Smckusick nfs_lock(), 8238414Smckusick nfs_unlock(), 8338414Smckusick nfs_bmap(), 8438414Smckusick nfs_strategy(), 8538884Smacklem nfs_fsync(), 86*39394Smckusick nfs_inactive(), 87*39394Smckusick nfs_reclaim(); 8838414Smckusick 8938414Smckusick struct vnodeops nfsv2_vnodeops = { 9038414Smckusick nfs_lookup, 9138414Smckusick nfs_create, 9238414Smckusick vfs_noop, 9338414Smckusick nfs_open, 9438414Smckusick nfs_close, 9538414Smckusick nfs_access, 9638414Smckusick nfs_getattr, 9738414Smckusick nfs_setattr, 9838414Smckusick nfs_read, 9938414Smckusick nfs_write, 10038414Smckusick vfs_noop, 10138414Smckusick vfs_noop, 10238414Smckusick vfs_noop, 10338884Smacklem nfs_fsync, 10438414Smckusick vfs_noop, 10538414Smckusick nfs_remove, 10638414Smckusick nfs_link, 10738414Smckusick nfs_rename, 10838414Smckusick nfs_mkdir, 10938414Smckusick nfs_rmdir, 11038414Smckusick nfs_symlink, 11138414Smckusick nfs_readdir, 11238414Smckusick nfs_readlink, 11338414Smckusick nfs_abortop, 11438414Smckusick nfs_inactive, 115*39394Smckusick nfs_reclaim, 11638414Smckusick nfs_lock, 11738414Smckusick nfs_unlock, 11838414Smckusick nfs_bmap, 11938414Smckusick nfs_strategy, 12038414Smckusick }; 12138414Smckusick 12238414Smckusick /* Special device vnode ops */ 12339362Smckusick int blk_lookup(), 12439362Smckusick blk_open(), 12538414Smckusick blk_read(), 12638414Smckusick blk_write(), 12738414Smckusick blk_ioctl(), 12839359Smckusick blk_select(); 12938414Smckusick 13038414Smckusick struct vnodeops nfsv2chr_vnodeops = { 13139362Smckusick blk_lookup, 13238414Smckusick vfs_noop, 13338414Smckusick vfs_noop, 13438414Smckusick blk_open, 13538414Smckusick nfs_close, 13638414Smckusick nfs_access, 13738414Smckusick nfs_getattr, 13838414Smckusick nfs_setattr, 13938414Smckusick blk_read, 14038414Smckusick blk_write, 14138414Smckusick blk_ioctl, 14238414Smckusick blk_select, 14338414Smckusick vfs_noop, 14438414Smckusick vfs_nullop, 14538414Smckusick vfs_noop, 14638414Smckusick nfs_remove, 14738414Smckusick nfs_link, 14838414Smckusick nfs_rename, 14938414Smckusick vfs_noop, 15038414Smckusick vfs_noop, 15138414Smckusick nfs_symlink, 15238414Smckusick vfs_noop, 15338414Smckusick vfs_noop, 15438414Smckusick nfs_abortop, 15538414Smckusick nfs_inactive, 156*39394Smckusick nfs_reclaim, 15738414Smckusick nfs_lock, 15838414Smckusick nfs_unlock, 15939359Smckusick vfs_noop, 16039359Smckusick vfs_noop, 16138414Smckusick }; 16238414Smckusick 16338414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 16438414Smckusick extern u_long nfs_prog, nfs_vers; 16538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 16638884Smacklem struct map nfsmap[NFS_MSIZ]; 16738414Smckusick enum vtype v_type[NFLNK+1]; 16838884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 16939341Smckusick int nfs_asyncdaemons = 0; 17039341Smckusick struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 17138884Smacklem static int nfsmap_want = 0; 17238414Smckusick 17338414Smckusick /* 17438414Smckusick * nfs null call from vfs. 17538414Smckusick */ 17638414Smckusick nfs_null(vp, cred) 17738414Smckusick struct vnode *vp; 17838414Smckusick struct ucred *cred; 17938414Smckusick { 18038414Smckusick nfsm_vars; 18138414Smckusick 18238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 18338414Smckusick nfsm_request(vp); 18438414Smckusick nfsm_reqdone; 18538414Smckusick return (error); 18638414Smckusick } 18738414Smckusick 18838414Smckusick /* 18938414Smckusick * nfs access vnode op. 19038414Smckusick * Essentially just get vattr and then imitate iaccess() 19138414Smckusick */ 19238414Smckusick nfs_access(vp, mode, cred) 19338414Smckusick struct vnode *vp; 19438414Smckusick int mode; 19538414Smckusick register struct ucred *cred; 19638414Smckusick { 19738414Smckusick register struct vattr *vap; 19838414Smckusick register gid_t *gp; 19938414Smckusick struct vattr vattr; 20038414Smckusick register int i; 20138414Smckusick int error; 20238414Smckusick 20338414Smckusick /* 20438414Smckusick * If you're the super-user, 20538414Smckusick * you always get access. 20638414Smckusick */ 20738414Smckusick if (cred->cr_uid == 0) 20838414Smckusick return (0); 20938414Smckusick vap = &vattr; 21038884Smacklem if (error = nfs_getattr(vp, vap, cred)) 21138884Smacklem return (error); 21238414Smckusick /* 21338414Smckusick * Access check is based on only one of owner, group, public. 21438414Smckusick * If not owner, then check group. If not a member of the 21538414Smckusick * group, then check public access. 21638414Smckusick */ 21738414Smckusick if (cred->cr_uid != vap->va_uid) { 21838414Smckusick mode >>= 3; 21938414Smckusick gp = cred->cr_groups; 22038414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 22138414Smckusick if (vap->va_gid == *gp) 22238414Smckusick goto found; 22338414Smckusick mode >>= 3; 22438414Smckusick found: 22538414Smckusick ; 22638414Smckusick } 22738414Smckusick if ((vap->va_mode & mode) != 0) 22838414Smckusick return (0); 22938414Smckusick return (EACCES); 23038414Smckusick } 23138414Smckusick 23238414Smckusick /* 23338414Smckusick * nfs open vnode op 23438414Smckusick * Just check to see if the type is ok 23538414Smckusick */ 23638414Smckusick nfs_open(vp, mode, cred) 23738414Smckusick struct vnode *vp; 23838414Smckusick int mode; 23938414Smckusick struct ucred *cred; 24038414Smckusick { 24138414Smckusick register enum vtype vtyp; 24238414Smckusick 24338414Smckusick vtyp = vp->v_type; 24438414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 24538414Smckusick return (0); 24638414Smckusick else 24738414Smckusick return (EACCES); 24838414Smckusick } 24938414Smckusick 25038414Smckusick /* 25138414Smckusick * nfs close vnode op 25238884Smacklem * For reg files, invalidate any buffer cache entries. 25338884Smacklem * For VCHR, do the device close 25438414Smckusick */ 25538414Smckusick nfs_close(vp, fflags, cred) 25638414Smckusick register struct vnode *vp; 25738414Smckusick int fflags; 25838414Smckusick struct ucred *cred; 25938414Smckusick { 26038884Smacklem struct nfsnode *np = VTONFS(vp); 26138414Smckusick dev_t dev; 26239341Smckusick int error = 0; 26338414Smckusick 26438884Smacklem nfs_lock(vp); 26539341Smckusick if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) || 26639341Smckusick ((np->n_flag & NBUFFERED) && np->n_sillyrename))) { 26739341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 26839341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 26939341Smckusick if (np->n_flag & NWRITEERR) { 27039341Smckusick np->n_flag &= ~NWRITEERR; 27139341Smckusick if (!error) 27239341Smckusick error = np->n_error ? np->n_error : EIO; 27339341Smckusick } 27438884Smacklem } 27538884Smacklem nfs_unlock(vp); 27638414Smckusick if (vp->v_type != VCHR || vp->v_count > 1) 27739341Smckusick return (error); 27838414Smckusick dev = vp->v_rdev; 27938414Smckusick /* XXX what is this doing below the vnode op call */ 28038414Smckusick if (setjmp(&u.u_qsave)) { 28138414Smckusick /* 28238414Smckusick * If device close routine is interrupted, 28338414Smckusick * must return so closef can clean up. 28438414Smckusick */ 28538414Smckusick error = EINTR; 28638414Smckusick } else 28738414Smckusick error = (*cdevsw[major(dev)].d_close)(dev, fflags, IFCHR); 28838414Smckusick /* 28938414Smckusick * Most device close routines don't return errors, 29038414Smckusick * and dup2() doesn't work right on error. 29138414Smckusick */ 29238414Smckusick error = 0; /* XXX */ 29338414Smckusick return (error); 29438414Smckusick } 29538414Smckusick 29638414Smckusick /* 29738414Smckusick * nfs getattr call from vfs. 29838414Smckusick */ 29938414Smckusick nfs_getattr(vp, vap, cred) 30038414Smckusick struct vnode *vp; 30138414Smckusick register struct vattr *vap; 30238414Smckusick struct ucred *cred; 30338414Smckusick { 30438414Smckusick nfsm_vars; 30538414Smckusick 30638414Smckusick /* First look in the cache.. */ 30738414Smckusick if (nfs_getattrcache(vp, vap) == 0) 30838414Smckusick return (0); 30938414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 31038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH); 31138414Smckusick nfsm_fhtom(vp); 31238414Smckusick nfsm_request(vp); 31338414Smckusick nfsm_loadattr(vp, vap); 31438414Smckusick nfsm_reqdone; 31538414Smckusick return (error); 31638414Smckusick } 31738414Smckusick 31838414Smckusick /* 31938414Smckusick * nfs setattr call. 32038414Smckusick */ 32138414Smckusick nfs_setattr(vp, vap, cred) 32238414Smckusick struct vnode *vp; 32338414Smckusick register struct vattr *vap; 32438414Smckusick struct ucred *cred; 32538414Smckusick { 32638884Smacklem register struct nfsv2_sattr *sp; 32738414Smckusick nfsm_vars; 32839359Smckusick struct nfsnode *np; 32938414Smckusick 33038414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 33138414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 33238414Smckusick nfsm_fhtom(vp); 33338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 33438414Smckusick if (vap->va_mode == 0xffff) 33538884Smacklem sp->sa_mode = VNOVAL; 33638414Smckusick else 33738884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 33838414Smckusick if (vap->va_uid == 0xffff) 33938884Smacklem sp->sa_uid = VNOVAL; 34038414Smckusick else 34138884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 34238414Smckusick if (vap->va_gid == 0xffff) 34338884Smacklem sp->sa_gid = VNOVAL; 34438414Smckusick else 34538884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 34638884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 34739359Smckusick if (vap->va_size != VNOVAL) { 34839359Smckusick np = VTONFS(vp); 34939359Smckusick if (np->n_flag & NMODIFIED) { 35039359Smckusick np->n_flag &= ~NMODIFIED; 35139359Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 35239359Smckusick } 35339359Smckusick } 35438884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 35538884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 35638414Smckusick nfsm_request(vp); 35738414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 35838414Smckusick /* should we fill in any vap fields ?? */ 35938414Smckusick nfsm_reqdone; 36038414Smckusick return (error); 36138414Smckusick } 36238414Smckusick 36338414Smckusick /* 36438414Smckusick * nfs lookup call, one step at a time... 36538414Smckusick * First look in cache 36638414Smckusick * If not found, unlock the directory nfsnode and do the rpc 36738414Smckusick */ 36838414Smckusick nfs_lookup(vp, ndp) 36938414Smckusick register struct vnode *vp; 37038414Smckusick register struct nameidata *ndp; 37138414Smckusick { 37238414Smckusick register struct vnode *vdp; 37338414Smckusick nfsm_vars; 37438414Smckusick struct vnode *newvp; 37538414Smckusick long len; 37638414Smckusick nfsv2fh_t *fhp; 37738414Smckusick struct nfsnode *np; 37838414Smckusick int lockparent, wantparent, flag; 37938414Smckusick dev_t rdev; 38038414Smckusick 38138414Smckusick ndp->ni_dvp = vp; 38238414Smckusick ndp->ni_vp = NULL; 38338414Smckusick if (vp->v_type != VDIR) 38438414Smckusick return (ENOTDIR); 38538414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 38638414Smckusick flag = ndp->ni_nameiop & OPFLAG; 38738414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 38839341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 38938884Smacklem struct vattr vattr; 39038884Smacklem int vpid; 39138884Smacklem 39238884Smacklem if (ndp->ni_vp == ndp->ni_rdir && ndp->ni_isdotdot) 39338884Smacklem vdp = vp; 39438884Smacklem else 39538884Smacklem vdp = ndp->ni_vp; 39638884Smacklem vpid = vdp->v_id; 39738414Smckusick /* 39838884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 39938884Smacklem * for an explanation of the locking protocol 40038414Smckusick */ 40138414Smckusick if (vp == vdp) { 40238425Smckusick VREF(vdp); 40338414Smckusick } else if (ndp->ni_isdotdot) { 40438414Smckusick nfs_unlock(vp); 40538414Smckusick nfs_ngrab(VTONFS(vdp)); 40638414Smckusick } else { 40738414Smckusick nfs_ngrab(VTONFS(vdp)); 40838414Smckusick nfs_unlock(vp); 40938414Smckusick } 41038884Smacklem if (vpid == vdp->v_id && 41139341Smckusick !nfs_getattr(vdp, &vattr, ndp->ni_cred)) { 41238884Smacklem nfsstats.lookupcache_hits++; 41338884Smacklem return (0); 41438884Smacklem } 41538884Smacklem nfs_nput(vdp); 41638884Smacklem nfs_lock(vp); 41738884Smacklem ndp->ni_vp = (struct vnode *)0; 41838414Smckusick } 41939341Smckusick error = 0; 42038414Smckusick nfsstats.lookupcache_misses++; 42138414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 42238414Smckusick len = ndp->ni_namelen; 42338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 42438414Smckusick nfsm_fhtom(vp); 42538414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 42638414Smckusick nfsm_request(vp); 42738414Smckusick nfsmout: 42838414Smckusick if (error) { 42938414Smckusick if ((flag == CREATE || flag == RENAME) && 43038414Smckusick *ndp->ni_next == 0) { 43138414Smckusick if (!lockparent) 43238414Smckusick nfs_unlock(vp); 43338414Smckusick } 43438414Smckusick return (ENOENT); 43538414Smckusick } 43638414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 43738414Smckusick 43838414Smckusick /* 43938414Smckusick * Handle DELETE and RENAME cases... 44038414Smckusick */ 44138414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 44238414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 44338425Smckusick VREF(vp); 44438414Smckusick newvp = vp; 44538414Smckusick np = VTONFS(vp); 44638414Smckusick } else { 44738414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 44838414Smckusick m_freem(mrep); 44938414Smckusick return (error); 45038414Smckusick } 45138414Smckusick newvp = NFSTOV(np); 45238414Smckusick } 45338414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 45438414Smckusick if (newvp != vp) 45538414Smckusick nfs_nput(newvp); 45638414Smckusick else 45738425Smckusick vrele(vp); 45838414Smckusick m_freem(mrep); 45938414Smckusick return (error); 46038414Smckusick } 46138414Smckusick ndp->ni_vp = newvp; 46238414Smckusick if (!lockparent) 46338414Smckusick nfs_unlock(vp); 46438414Smckusick m_freem(mrep); 46538414Smckusick return (0); 46638414Smckusick } 46738414Smckusick 46838414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 46938414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 47038414Smckusick m_freem(mrep); 47138414Smckusick return (EISDIR); 47238414Smckusick } 47338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 47438414Smckusick m_freem(mrep); 47538414Smckusick return (error); 47638414Smckusick } 47738414Smckusick newvp = NFSTOV(np); 47838414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 47938425Smckusick nfs_nput(newvp); 48038414Smckusick m_freem(mrep); 48138414Smckusick return (error); 48238414Smckusick } 48338414Smckusick ndp->ni_vp = newvp; 48438414Smckusick if (!lockparent) 48538414Smckusick nfs_unlock(vp); 48638414Smckusick return (0); 48738414Smckusick } 48838414Smckusick 48938414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 49038425Smckusick VREF(vp); 49138414Smckusick newvp = vp; 49238414Smckusick np = VTONFS(vp); 49338414Smckusick } else if (ndp->ni_isdotdot) { 49438414Smckusick nfs_unlock(vp); 49538414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 49638414Smckusick nfs_lock(vp); 49738414Smckusick m_freem(mrep); 49838414Smckusick return (error); 49938414Smckusick } 50038414Smckusick nfs_lock(vp); 50138414Smckusick newvp = NFSTOV(np); 50238414Smckusick } else { 50338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 50438414Smckusick m_freem(mrep); 50538414Smckusick return (error); 50638414Smckusick } 50738414Smckusick newvp = NFSTOV(np); 50838414Smckusick } 50938414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 51038414Smckusick if (newvp != vp) 51138414Smckusick nfs_nput(newvp); 51238414Smckusick else 51338425Smckusick vrele(vp); 51438414Smckusick m_freem(mrep); 51538414Smckusick return (error); 51638414Smckusick } 51738414Smckusick m_freem(mrep); 51838414Smckusick 51938414Smckusick if (vp != newvp && (!lockparent || *ndp->ni_next != '\0')) 52038414Smckusick nfs_unlock(vp); 52138414Smckusick ndp->ni_vp = newvp; 52238414Smckusick if (error == 0 && ndp->ni_makeentry) 52338414Smckusick cache_enter(ndp); 52438414Smckusick return (error); 52538414Smckusick } 52638414Smckusick 52738414Smckusick /* 52838414Smckusick * nfs readlink call 52938414Smckusick */ 53038414Smckusick nfs_readlink(vp, uiop, cred) 53138414Smckusick struct vnode *vp; 53238414Smckusick struct uio *uiop; 53338414Smckusick struct ucred *cred; 53438414Smckusick { 53538414Smckusick nfsm_vars; 53638414Smckusick long len; 53738414Smckusick 53838414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 53938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 54038414Smckusick nfsm_fhtom(vp); 54138414Smckusick nfsm_request(vp); 54238414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 54338414Smckusick nfsm_mtouio(uiop, len); 54438414Smckusick nfsm_reqdone; 54538414Smckusick return (error); 54638414Smckusick } 54738414Smckusick 54838414Smckusick /* 54938414Smckusick * nfs read call 55038414Smckusick */ 55138884Smacklem nfs_readrpc(vp, uiop, offp, cred) 55238414Smckusick struct vnode *vp; 55338414Smckusick struct uio *uiop; 55438414Smckusick off_t *offp; 55538414Smckusick struct ucred *cred; 55638414Smckusick { 55738414Smckusick nfsm_vars; 55838414Smckusick struct nfsmount *nmp; 55938414Smckusick long len, retlen, tsiz; 56038414Smckusick 56138414Smckusick nmp = vfs_to_nfs(vp->v_mount); 56238414Smckusick tsiz = uiop->uio_resid; 56338414Smckusick while (tsiz > 0) { 56438414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 56538414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 56638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 56738414Smckusick nfsm_fhtom(vp); 56838414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*3); 56938414Smckusick *p++ = txdr_unsigned(*offp); 57038414Smckusick *p++ = txdr_unsigned(len); 57138414Smckusick *p = 0; 57238414Smckusick nfsm_request(vp); 57338414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 57438414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 57538414Smckusick nfsm_mtouio(uiop, retlen); 57638414Smckusick m_freem(mrep); 57738414Smckusick *offp += retlen; 57838414Smckusick if (retlen < len) 57938414Smckusick tsiz = 0; 58038414Smckusick else 58138414Smckusick tsiz -= len; 58238414Smckusick } 58338414Smckusick nfsmout: 58438414Smckusick return (error); 58538414Smckusick } 58638414Smckusick 58738414Smckusick /* 58838414Smckusick * nfs write call 58938414Smckusick */ 59038884Smacklem nfs_writerpc(vp, uiop, offp, cred) 59138414Smckusick struct vnode *vp; 59238414Smckusick struct uio *uiop; 59338414Smckusick off_t *offp; 59438414Smckusick struct ucred *cred; 59538414Smckusick { 59638414Smckusick nfsm_vars; 59738414Smckusick struct nfsmount *nmp; 59838414Smckusick long len, tsiz; 59938414Smckusick 60038414Smckusick nmp = vfs_to_nfs(vp->v_mount); 60138414Smckusick tsiz = uiop->uio_resid; 60238414Smckusick while (tsiz > 0) { 60338414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 60438414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 60538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 60638414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 60738414Smckusick nfsm_fhtom(vp); 60838414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*4); 60938414Smckusick *(p+1) = txdr_unsigned(*offp); 61038414Smckusick *(p+3) = txdr_unsigned(len); 61138414Smckusick nfsm_uiotom(uiop, len); 61238414Smckusick nfsm_request(vp); 61338414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 61438414Smckusick m_freem(mrep); 61538414Smckusick tsiz -= len; 61638414Smckusick *offp += len; 61738414Smckusick } 61838414Smckusick nfsmout: 61938414Smckusick return (error); 62038414Smckusick } 62138414Smckusick 62238414Smckusick /* 62338414Smckusick * nfs file create call 62438414Smckusick */ 62538414Smckusick nfs_create(ndp, vap) 62638414Smckusick register struct nameidata *ndp; 62738414Smckusick register struct vattr *vap; 62838414Smckusick { 62938884Smacklem register struct nfsv2_sattr *sp; 63038414Smckusick nfsm_vars; 63138414Smckusick 63238414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 63338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 63438414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 63538414Smckusick nfsm_fhtom(ndp->ni_dvp); 63638414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 63738884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 63838884Smacklem sp->sa_mode = vtonfs_mode(VREG, vap->va_mode); 63938884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 64038884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 64138884Smacklem sp->sa_size = txdr_unsigned(0); 64238414Smckusick /* or should these be VNOVAL ?? */ 64338884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 64438884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 64538414Smckusick nfsm_request(ndp->ni_dvp); 64638414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 64738414Smckusick nfsm_reqdone; 64838414Smckusick nfs_nput(ndp->ni_dvp); 64938414Smckusick return (error); 65038414Smckusick } 65138414Smckusick 65238414Smckusick /* 65338414Smckusick * nfs file remove call 65439341Smckusick * To try and make nfs semantics closer to vfs semantics, a file that has 65539341Smckusick * other references to the vnode is renamed instead of removed and then 65639341Smckusick * removed later on the last close. 65739341Smckusick * Unfortunately you must flush the buffer cache and cmap to get rid of 65839341Smckusick * all extraneous vnode references before you check the reference cnt. 65939341Smckusick * 1 - If the file could have blocks in the buffer cache 66039341Smckusick * flush them out and invalidate them 66139341Smckusick * mpurge the vnode to flush out cmap references 66239341Smckusick * (This is necessary to update the vnode ref cnt as well as sensible 66339341Smckusick * for actual removes, to free up the buffers) 66439341Smckusick * 2 - If v_count > 1 66539341Smckusick * If a rename is not already in the works 66639341Smckusick * call nfs_sillyrename() to set it up 66739341Smckusick * else 66839341Smckusick * do the remove rpc 66938414Smckusick */ 67038414Smckusick nfs_remove(ndp) 67138414Smckusick register struct nameidata *ndp; 67238414Smckusick { 67339341Smckusick register struct vnode *vp = ndp->ni_vp; 67439341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 67538414Smckusick nfsm_vars; 67638414Smckusick 67739341Smckusick if (vp->v_type == VREG) { 67839341Smckusick if (np->n_flag & (NMODIFIED|NBUFFERED)) { 67939341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 68039341Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 68139341Smckusick } 68239341Smckusick if (np->n_flag & NPAGEDON) 68339341Smckusick mpurge(vp); /* In case cmap entries still ref it */ 68439341Smckusick } 68539341Smckusick if (vp->v_count > 1) { 68639341Smckusick if (!np->n_sillyrename) 68739341Smckusick error = nfs_sillyrename(ndp, REMOVE); 68839341Smckusick } else { 68938414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 69038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 69138414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 69238414Smckusick nfsm_fhtom(ndp->ni_dvp); 69338414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 69438414Smckusick nfsm_request(ndp->ni_dvp); 69538414Smckusick nfsm_reqdone; 69638414Smckusick } 69738414Smckusick if (ndp->ni_dvp == ndp->ni_vp) 69838425Smckusick vrele(ndp->ni_vp); 69938414Smckusick else 70038425Smckusick nfs_nput(ndp->ni_vp); 70138425Smckusick nfs_nput(ndp->ni_dvp); 70238414Smckusick return (error); 70338414Smckusick } 70438414Smckusick 70538414Smckusick /* 70638414Smckusick * nfs file remove rpc called from nfs_inactive 70738414Smckusick */ 70838414Smckusick nfs_removeit(ndp) 70938414Smckusick register struct nameidata *ndp; 71038414Smckusick { 71138414Smckusick nfsm_vars; 71238414Smckusick 71338414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 71438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 71538414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 71638414Smckusick nfsm_fhtom(ndp->ni_dvp); 71738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 71838414Smckusick nfsm_request(ndp->ni_dvp); 71938414Smckusick nfsm_reqdone; 72038414Smckusick return (error); 72138414Smckusick } 72238414Smckusick 72338414Smckusick /* 72438414Smckusick * nfs file rename call 72538414Smckusick */ 72638414Smckusick nfs_rename(sndp, tndp) 72738414Smckusick register struct nameidata *sndp, *tndp; 72838414Smckusick { 72938414Smckusick nfsm_vars; 73038414Smckusick 73138414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 73238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 73338414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 73438414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 73538414Smckusick nfsm_fhtom(sndp->ni_dvp); 73638414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 73738414Smckusick nfsm_fhtom(tndp->ni_dvp); 73838414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 73938414Smckusick nfsm_request(sndp->ni_dvp); 74038414Smckusick nfsm_reqdone; 74138414Smckusick if (sndp->ni_vp->v_type == VDIR) { 74238414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 74338414Smckusick cache_purge(tndp->ni_dvp); 74438414Smckusick cache_purge(sndp->ni_dvp); 74538414Smckusick } 74638414Smckusick nfs_abortop(sndp); 74738414Smckusick nfs_abortop(tndp); 74838414Smckusick return (error); 74938414Smckusick } 75038414Smckusick 75138414Smckusick /* 75238414Smckusick * nfs file rename rpc called from above 75338414Smckusick */ 75438414Smckusick nfs_renameit(sndp, tndp) 75538414Smckusick register struct nameidata *sndp, *tndp; 75638414Smckusick { 75738414Smckusick nfsm_vars; 75838414Smckusick 75938414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 76038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 76138414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 76238414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 76338414Smckusick nfsm_fhtom(sndp->ni_dvp); 76438414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 76538414Smckusick nfsm_fhtom(tndp->ni_dvp); 76638414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 76738414Smckusick nfsm_request(sndp->ni_dvp); 76838414Smckusick nfsm_reqdone; 76938414Smckusick return (error); 77038414Smckusick } 77138414Smckusick 77238414Smckusick /* 77338414Smckusick * nfs hard link create call 77438414Smckusick */ 77538414Smckusick nfs_link(vp, ndp) 77638414Smckusick struct vnode *vp; 77738414Smckusick register struct nameidata *ndp; 77838414Smckusick { 77938414Smckusick nfsm_vars; 78038414Smckusick 78138425Smckusick if (ndp->ni_dvp != vp) 78238425Smckusick nfs_lock(vp); 78338414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 78438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 78538414Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 78638414Smckusick nfsm_fhtom(vp); 78738414Smckusick nfsm_fhtom(ndp->ni_dvp); 78838414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 78938414Smckusick nfsm_request(vp); 79038414Smckusick nfsm_reqdone; 79138425Smckusick if (ndp->ni_dvp != vp) 79238425Smckusick nfs_unlock(vp); 79338414Smckusick nfs_nput(ndp->ni_dvp); 79438414Smckusick return (error); 79538414Smckusick } 79638414Smckusick 79738414Smckusick /* 79838414Smckusick * nfs symbolic link create call 79938414Smckusick */ 80038414Smckusick nfs_symlink(ndp, vap, nm) 80138414Smckusick struct nameidata *ndp; 80238414Smckusick struct vattr *vap; 80338414Smckusick char *nm; /* is this the path ?? */ 80438414Smckusick { 80538884Smacklem register struct nfsv2_sattr *sp; 80638414Smckusick nfsm_vars; 80738414Smckusick 80838414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 80938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 81038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED); 81138414Smckusick nfsm_fhtom(ndp->ni_dvp); 81238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 81338414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 81438884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 81538884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 81638884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 81738884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 81838884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 81938884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 82038884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 82138414Smckusick nfsm_request(ndp->ni_dvp); 82238414Smckusick nfsm_reqdone; 82338414Smckusick nfs_nput(ndp->ni_dvp); 82438414Smckusick return (error); 82538414Smckusick } 82638414Smckusick 82738414Smckusick /* 82838414Smckusick * nfs make dir call 82938414Smckusick */ 83038414Smckusick nfs_mkdir(ndp, vap) 83138414Smckusick struct nameidata *ndp; 83238414Smckusick struct vattr *vap; 83338414Smckusick { 83438884Smacklem register struct nfsv2_sattr *sp; 83538414Smckusick nfsm_vars; 83638414Smckusick 83738414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 83838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 83938414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 84038414Smckusick nfsm_fhtom(ndp->ni_dvp); 84138414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 84238884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 84338884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 84438884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 84538884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 84638884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 84738884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 84838884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 84938414Smckusick nfsm_request(ndp->ni_dvp); 85038414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 85138414Smckusick nfsm_reqdone; 85238414Smckusick nfs_nput(ndp->ni_dvp); 85338414Smckusick return (error); 85438414Smckusick } 85538414Smckusick 85638414Smckusick /* 85738414Smckusick * nfs remove directory call 85838414Smckusick */ 85938414Smckusick nfs_rmdir(ndp) 86038414Smckusick register struct nameidata *ndp; 86138414Smckusick { 86238414Smckusick nfsm_vars; 86338414Smckusick 86438414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 86538414Smckusick vrele(ndp->ni_dvp); 86638414Smckusick nfs_nput(ndp->ni_dvp); 86738414Smckusick return (EINVAL); 86838414Smckusick } 86938414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 87038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 87138414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 87238414Smckusick nfsm_fhtom(ndp->ni_dvp); 87338414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 87438414Smckusick nfsm_request(ndp->ni_dvp); 87538414Smckusick nfsm_reqdone; 87638884Smacklem cache_purge(ndp->ni_dvp); 87738884Smacklem cache_purge(ndp->ni_vp); 87838884Smacklem nfs_nput(ndp->ni_vp); 87938884Smacklem nfs_nput(ndp->ni_dvp); 88038414Smckusick return (error); 88138414Smckusick } 88238414Smckusick 88338414Smckusick /* 88438414Smckusick * nfs readdir call 88538414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 88638414Smckusick * order so that it looks more sensible. This appears consistent with the 88738414Smckusick * Ultrix implementation of NFS. 88838414Smckusick */ 88938414Smckusick nfs_readdir(vp, uiop, offp, cred) 89038414Smckusick struct vnode *vp; 89138414Smckusick struct uio *uiop; 89238414Smckusick off_t *offp; 89338414Smckusick struct ucred *cred; 89438414Smckusick { 89538414Smckusick register long len; 89638414Smckusick register struct direct *dp; 89738414Smckusick nfsm_vars; 89838414Smckusick struct mbuf *md2; 89938414Smckusick caddr_t dpos2; 90038414Smckusick int siz; 90138414Smckusick int more_dirs, eofflg; 90238414Smckusick off_t off, savoff; 90338414Smckusick struct direct *savdp; 90438414Smckusick 90538414Smckusick nfs_lock(vp); 90638414Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 90738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 90838414Smckusick nfsm_fhtom(vp); 90938414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 91038414Smckusick off = *offp; 91138414Smckusick *p++ = txdr_unsigned(off); 91238414Smckusick *p = txdr_unsigned(uiop->uio_resid); 91338414Smckusick nfsm_request(vp); 91438414Smckusick siz = 0; 91538414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 91638414Smckusick more_dirs = fxdr_unsigned(int, *p); 91738414Smckusick 91838414Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 91938414Smckusick dpos2 = dpos; 92038414Smckusick md2 = md; 92138414Smckusick 92238414Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 92338414Smckusick while (more_dirs && siz < uiop->uio_resid) { 92438414Smckusick savoff = off; /* Hold onto offset and dp */ 92538414Smckusick savdp = dp; 92638414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 92738414Smckusick dp = (struct direct *)p; 92838414Smckusick dp->d_ino = fxdr_unsigned(u_long, *p++); 92938414Smckusick len = fxdr_unsigned(int, *p); 93038414Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 93138414Smckusick error = EBADRPC; 93238414Smckusick m_freem(mrep); 93338414Smckusick goto nfsmout; 93438414Smckusick } 93538414Smckusick dp->d_namlen = (u_short)len; 93638414Smckusick len = nfsm_rndup(len); 93738414Smckusick nfsm_adv(len); 93838414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 93938414Smckusick off = fxdr_unsigned(off_t, *p); 94038414Smckusick *p++ = 0; /* Ensures null termination of name */ 94138414Smckusick more_dirs = fxdr_unsigned(int, *p); 94238414Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 94338414Smckusick siz += dp->d_reclen; 94438414Smckusick } 94538414Smckusick /* 94638414Smckusick * If at end of rpc data, get the eof boolean 94738414Smckusick */ 94838414Smckusick if (!more_dirs) { 94938414Smckusick nfsm_disecton(p, u_long *, NFSX_UNSIGNED); 95038414Smckusick eofflg = fxdr_unsigned(long, *p); 95138414Smckusick } 95238414Smckusick /* 95338414Smckusick * If there is too much to fit in the data buffer, use savoff and 95438414Smckusick * savdp to trim off the last record. 95538414Smckusick * --> we are not at eof 95638414Smckusick */ 95738414Smckusick if (siz > uiop->uio_resid) { 95838414Smckusick eofflg = FALSE; 95938414Smckusick off = savoff; 96038414Smckusick siz -= dp->d_reclen; 96138414Smckusick dp = savdp; 96238414Smckusick } 96338414Smckusick if (siz > 0) { 96438414Smckusick #ifdef notdef 96538414Smckusick if (!eofflg) 96638414Smckusick dp->d_reclen += (uiop->uio_resid-siz); 96738414Smckusick #endif 96838414Smckusick md = md2; 96938414Smckusick dpos = dpos2; 97038414Smckusick nfsm_mtouio(uiop, siz); 97138414Smckusick #ifdef notdef 97238414Smckusick if (!eofflg) 97338414Smckusick uiop->uio_resid = 0; 97438414Smckusick #endif 97538414Smckusick *offp = off; 97638414Smckusick } 97738414Smckusick nfsm_reqdone; 97838414Smckusick nfs_unlock(vp); 97938414Smckusick return (error); 98038414Smckusick } 98138414Smckusick 98238414Smckusick /* 98338414Smckusick * nfs statfs call 98438414Smckusick * (Actually a vfsop, not a vnode op) 98538414Smckusick */ 98638414Smckusick nfs_statfs(mp, sbp) 98738414Smckusick struct mount *mp; 98838414Smckusick register struct statfs *sbp; 98938414Smckusick { 99038884Smacklem register struct nfsv2_statfs *sfp; 99138414Smckusick nfsm_vars; 99238884Smacklem struct nfsmount *nmp; 99338414Smckusick struct ucred *cred; 99438414Smckusick struct nfsnode *np; 99538414Smckusick struct vnode *vp; 99638414Smckusick 99738414Smckusick nmp = vfs_to_nfs(mp); 99838414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 99938414Smckusick return (error); 100038414Smckusick vp = NFSTOV(np); 100138414Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 100238414Smckusick cred = crget(); 100338414Smckusick cred->cr_ngroups = 1; 100438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 100538414Smckusick nfsm_fhtom(vp); 100638414Smckusick nfsm_request(vp); 100738884Smacklem nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 100838414Smckusick sbp->f_type = MOUNT_NFS; 100938414Smckusick sbp->f_flags = nmp->nm_flag; 101038884Smacklem sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 101138884Smacklem sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 101238884Smacklem sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 101338884Smacklem sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 101438884Smacklem sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 101538739Smckusick sbp->f_files = 0; 101638739Smckusick sbp->f_ffree = 0; 101738414Smckusick sbp->f_fsid.val[0] = mp->m_fsid.val[0]; 101838414Smckusick sbp->f_fsid.val[1] = mp->m_fsid.val[1]; 101938414Smckusick bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN); 102038414Smckusick bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN); 102138414Smckusick nfsm_reqdone; 102238414Smckusick nfs_nput(vp); 102338414Smckusick crfree(cred); 102438414Smckusick return (error); 102538414Smckusick } 102638414Smckusick 102738414Smckusick #define HEXTOASC(x) "0123456789abcdef"[x] 102838414Smckusick 102938414Smckusick /* 103038414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 103138414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 103238414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 103338414Smckusick * nfsnode. There is the potential for another process on a different client 103438414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 103538414Smckusick * nfs_rename() completes, but... 103638414Smckusick */ 103738414Smckusick nfs_sillyrename(ndp, flag) 103838414Smckusick struct nameidata *ndp; 103938414Smckusick int flag; 104038414Smckusick { 104138414Smckusick register struct nfsnode *np; 104238414Smckusick register struct sillyrename *sp; 104338414Smckusick register struct nameidata *tndp; 104438414Smckusick int error; 104538414Smckusick short pid; 104638414Smckusick 104738414Smckusick np = VTONFS(ndp->ni_dvp); 104839341Smckusick cache_purge(ndp->ni_dvp); 104938414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 105038884Smacklem M_TEMP, M_WAITOK); 105138414Smckusick sp->s_flag = flag; 105238414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 105338414Smckusick np = VTONFS(ndp->ni_vp); 105438414Smckusick tndp = &sp->s_namei; 105538414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 105638414Smckusick 105738414Smckusick /* Fudge together a funny name */ 105838414Smckusick pid = u.u_procp->p_pid; 105938414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 106038414Smckusick tndp->ni_dent.d_namlen = 12; 106138414Smckusick tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf); 106238414Smckusick tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf); 106338414Smckusick tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf); 106438414Smckusick tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf); 106538414Smckusick 106638414Smckusick /* Try lookitups until we get one that isn't there */ 106738414Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) { 106838414Smckusick tndp->ni_dent.d_name[4]++; 106938414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 107038414Smckusick error = EINVAL; 107138414Smckusick goto bad; 107238414Smckusick } 107338414Smckusick } 107438414Smckusick if (error = nfs_renameit(ndp, tndp)) 107538414Smckusick goto bad; 107638414Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh); 107738414Smckusick np->n_sillyrename = sp; 107838414Smckusick return (0); 107938414Smckusick bad: 108038884Smacklem crfree(tndp->ni_cred); 108138414Smckusick free((caddr_t)sp, M_TEMP); 108238414Smckusick return (error); 108338414Smckusick } 108438414Smckusick 108538414Smckusick /* 108638414Smckusick * Look up a file name for silly rename stuff. 108738414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 108838414Smckusick * into the nfsnode table. 108938414Smckusick * If fhp != NULL it copies the returned file handle out 109038414Smckusick */ 109138414Smckusick nfs_lookitup(vp, ndp, fhp) 109238414Smckusick register struct vnode *vp; 109338414Smckusick register struct nameidata *ndp; 109438414Smckusick nfsv2fh_t *fhp; 109538414Smckusick { 109638414Smckusick nfsm_vars; 109738414Smckusick long len; 109838414Smckusick 109938414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 110038414Smckusick ndp->ni_dvp = vp; 110138414Smckusick ndp->ni_vp = NULL; 110238414Smckusick len = ndp->ni_dent.d_namlen; 110338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 110438414Smckusick nfsm_fhtom(vp); 110538414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 110638414Smckusick nfsm_request(vp); 110738414Smckusick if (fhp != NULL) { 110838414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 110938414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 111038414Smckusick } 111138414Smckusick nfsm_reqdone; 111238414Smckusick return (error); 111338414Smckusick } 111438414Smckusick 111538414Smckusick /* 111638414Smckusick * Kludge City.. 111738414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 111838414Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit 111938414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 112038414Smckusick * nfsiobuf area. 112138414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 112238414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 112338414Smckusick * a lot more work than bcopy() and also it currently happens in the 112438414Smckusick * context of the swapper process (2). 112538414Smckusick */ 112638414Smckusick nfs_bmap(vp, bn, vpp, bnp) 112738414Smckusick struct vnode *vp; 112838414Smckusick daddr_t bn; 112938414Smckusick struct vnode **vpp; 113038414Smckusick daddr_t *bnp; 113138414Smckusick { 113238414Smckusick if (vpp != NULL) 113338414Smckusick *vpp = vp; 113438414Smckusick if (bnp != NULL) 113538414Smckusick *bnp = bn * btodb(vp->v_mount->m_bsize); 113638414Smckusick return (0); 113738414Smckusick } 113838414Smckusick 113938414Smckusick /* 114038884Smacklem * Strategy routine for phys. i/o 114138884Smacklem * If the biod's are running, queue a request 114238884Smacklem * otherwise just call nfs_doio() to get it done 114338414Smckusick */ 114438414Smckusick nfs_strategy(bp) 114538414Smckusick register struct buf *bp; 114638414Smckusick { 114738884Smacklem register struct buf *dp; 114839341Smckusick register int i; 114938884Smacklem struct proc *rp; 115038884Smacklem int error = 0; 115139341Smckusick int fnd = 0; 115238884Smacklem 115338884Smacklem /* 115438884Smacklem * If an i/o daemon is waiting 115538884Smacklem * queue the request, wake it up and wait for completion 115638884Smacklem * otherwise just do it ourselves 115738884Smacklem */ 115839341Smckusick for (i = 0; i < nfs_asyncdaemons; i++) { 115939341Smckusick if (rp = nfs_iodwant[i]) { 116039341Smckusick /* 116139341Smckusick * Ensure that the async_daemon is still waiting here 116239341Smckusick */ 116339341Smckusick if (rp->p_stat != SSLEEP || 116439341Smckusick rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) { 116539341Smckusick nfs_iodwant[i] = (struct proc *)0; 116639341Smckusick continue; 116739341Smckusick } 116839341Smckusick dp = &nfs_bqueue; 116939341Smckusick if (dp->b_actf == NULL) { 117039341Smckusick dp->b_actl = bp; 117139341Smckusick bp->b_actf = dp; 117239341Smckusick } else { 117339341Smckusick dp->b_actf->b_actl = bp; 117439341Smckusick bp->b_actf = dp->b_actf; 117539341Smckusick } 117639341Smckusick dp->b_actf = bp; 117739341Smckusick bp->b_actl = dp; 117839341Smckusick fnd++; 117939341Smckusick nfs_iodwant[i] = (struct proc *)0; 118039341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 118139341Smckusick break; 118238884Smacklem } 118339341Smckusick } 118439341Smckusick if (!fnd) 118538884Smacklem error = nfs_doio(bp); 118638884Smacklem return (error); 118738884Smacklem } 118838884Smacklem 118938884Smacklem /* 119038884Smacklem * Fun and games with i/o 119138884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 119238884Smacklem * mapping the data buffer into kernel virtual space and doing the 119338884Smacklem * nfs read or write rpc's from it. 119438884Smacklem * If the biod's are not running, this is just called from nfs_strategy(), 119538884Smacklem * otherwise it is called by the biod's to do what would normally be 119638884Smacklem * partially disk interrupt driven. 119738884Smacklem */ 119838884Smacklem nfs_doio(bp) 119938884Smacklem register struct buf *bp; 120038884Smacklem { 120138414Smckusick register struct pte *pte, *ppte; 120238414Smckusick register caddr_t vaddr; 120338414Smckusick register struct uio *uiop; 120438414Smckusick register struct vnode *vp; 120539341Smckusick struct nfsnode *np; 120638884Smacklem struct ucred *cr; 120738884Smacklem int npf, npf2; 120838884Smacklem int reg; 120938884Smacklem caddr_t vbase; 121038884Smacklem caddr_t addr; 121138414Smckusick unsigned v; 121238414Smckusick struct proc *rp; 121338414Smckusick int o, error; 121438884Smacklem int bcnt; 121538414Smckusick off_t off; 121638414Smckusick struct uio uio; 121738414Smckusick struct iovec io; 121838414Smckusick 121938414Smckusick vp = bp->b_vp; 122038414Smckusick uiop = &uio; 122138414Smckusick uiop->uio_iov = &io; 122238414Smckusick uiop->uio_iovcnt = 1; 122338414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 122438884Smacklem if (bp->b_flags & B_READ) { 122538884Smacklem io.iov_len = uiop->uio_resid = bp->b_bcount; 122638884Smacklem uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE; 122738884Smacklem addr = bp->b_un.b_addr; 122838884Smacklem bcnt = bp->b_bcount; 122938884Smacklem } else { 123038884Smacklem io.iov_len = uiop->uio_resid = bp->b_dirtyend-bp->b_dirtyoff; 123138884Smacklem uiop->uio_offset = off = (bp->b_blkno*DEV_BSIZE)+bp->b_dirtyoff; 123238884Smacklem addr = bp->b_un.b_addr+bp->b_dirtyoff; 123338884Smacklem bcnt = bp->b_dirtyend-bp->b_dirtyoff; 123438414Smckusick } 123538414Smckusick /* 123638884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 123738884Smacklem * the Nfsiomap pte's 123838884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 123938884Smacklem * and a guess at a group 124038414Smckusick */ 124138884Smacklem if (bp->b_flags & B_PHYS) { 124239341Smckusick VTONFS(vp)->n_flag |= NPAGEDON; 124338884Smacklem bp->b_rcred = cr = crget(); 124438884Smacklem rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc; 124538884Smacklem cr->cr_uid = rp->p_uid; 124638884Smacklem cr->cr_gid = 0; /* Anything ?? */ 124738884Smacklem cr->cr_ngroups = 1; 124838884Smacklem o = (int)addr & PGOFSET; 124938884Smacklem npf2 = npf = btoc(bcnt + o); 125038884Smacklem /* 125138884Smacklem * Get some mapping page table entries 125238884Smacklem */ 125338884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 125438884Smacklem nfsmap_want++; 125538884Smacklem sleep((caddr_t)&nfsmap_want, PZERO-1); 125638884Smacklem } 125738884Smacklem reg--; 125838884Smacklem /* I know it is always the else, but that may change someday */ 125938884Smacklem if ((bp->b_flags & B_PHYS) == 0) 126038884Smacklem pte = kvtopte(bp->b_un.b_addr); 126138884Smacklem else if (bp->b_flags & B_PAGET) 126238884Smacklem pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 126338884Smacklem else { 126438884Smacklem v = btop(bp->b_un.b_addr); 126538884Smacklem if (bp->b_flags & B_UAREA) 126638884Smacklem pte = &rp->p_addr[v]; 126738884Smacklem else 126838884Smacklem pte = vtopte(rp, v); 126938884Smacklem } 127038884Smacklem /* 127138884Smacklem * Play vmaccess() but with the Nfsiomap page table 127238884Smacklem */ 127338884Smacklem ppte = &Nfsiomap[reg]; 127438884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 127538884Smacklem while (npf != 0) { 127638884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 127738414Smckusick #if defined(tahoe) 127838884Smacklem mtpr(P1DC, vaddr); 127938414Smckusick #endif 128038884Smacklem ppte++; 128138884Smacklem pte++; 128238884Smacklem vaddr += NBPG; 128338884Smacklem --npf; 128438884Smacklem } 128538884Smacklem io.iov_base = vbase+o; 128638884Smacklem } else { 128738884Smacklem io.iov_base = addr; 128838414Smckusick } 128938414Smckusick if (bp->b_flags & B_READ) { 129038414Smckusick uiop->uio_rw = UIO_READ; 129138884Smacklem bp->b_error = error = nfs_readrpc(vp, uiop, &off, bp->b_rcred); 129238414Smckusick } else { 129338414Smckusick uiop->uio_rw = UIO_WRITE; 129438884Smacklem bp->b_error = error = nfs_writerpc(vp, uiop, &off, bp->b_wcred); 129539341Smckusick if (error) { 129639341Smckusick np = VTONFS(vp); 129739341Smckusick np->n_error = error; 129839341Smckusick np->n_flag |= NWRITEERR; 129939341Smckusick } 130038884Smacklem bp->b_dirtyoff = bp->b_dirtyend = 0; 130138414Smckusick } 130238884Smacklem if (error) 130338884Smacklem bp->b_flags |= B_ERROR; 130438414Smckusick bp->b_resid = uiop->uio_resid; 130538884Smacklem /* 130638884Smacklem * Release pte's used by physical i/o 130738884Smacklem */ 130838884Smacklem if (bp->b_flags & B_PHYS) { 130938884Smacklem crfree(cr); 131038884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 131138884Smacklem if (nfsmap_want) { 131238884Smacklem nfsmap_want = 0; 131338884Smacklem wakeup((caddr_t)&nfsmap_want); 131438884Smacklem } 131538884Smacklem } 131638414Smckusick biodone(bp); 131738414Smckusick return (error); 131838414Smckusick } 131938884Smacklem 132038884Smacklem /* 132138884Smacklem * Flush all the blocks associated with a vnode. 132238884Smacklem * Walk through the buffer pool and push any dirty pages 132338884Smacklem * associated with the vnode. 132438884Smacklem */ 132538884Smacklem nfs_fsync(vp, fflags, cred) 132638884Smacklem register struct vnode *vp; 132738884Smacklem int fflags; 132838884Smacklem struct ucred *cred; 132938884Smacklem { 133038884Smacklem register struct nfsnode *np = VTONFS(vp); 133138884Smacklem int error; 133238884Smacklem 133338884Smacklem nfs_lock(vp); 133438884Smacklem if (np->n_flag & NMODIFIED) { 133538884Smacklem np->n_flag &= ~NMODIFIED; 133639341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, FALSE); 133738884Smacklem } 133838884Smacklem nfs_unlock(vp); 133938884Smacklem return (error); 134038884Smacklem } 1341