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*39359Smckusick * @(#)nfs_vnops.c 7.7 (Berkeley) 10/21/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(), 8638414Smckusick nfs_inactive(); 8738414Smckusick 8838414Smckusick struct vnodeops nfsv2_vnodeops = { 8938414Smckusick nfs_lookup, 9038414Smckusick nfs_create, 9138414Smckusick vfs_noop, 9238414Smckusick nfs_open, 9338414Smckusick nfs_close, 9438414Smckusick nfs_access, 9538414Smckusick nfs_getattr, 9638414Smckusick nfs_setattr, 9738414Smckusick nfs_read, 9838414Smckusick nfs_write, 9938414Smckusick vfs_noop, 10038414Smckusick vfs_noop, 10138414Smckusick vfs_noop, 10238884Smacklem nfs_fsync, 10338414Smckusick vfs_noop, 10438414Smckusick nfs_remove, 10538414Smckusick nfs_link, 10638414Smckusick nfs_rename, 10738414Smckusick nfs_mkdir, 10838414Smckusick nfs_rmdir, 10938414Smckusick nfs_symlink, 11038414Smckusick nfs_readdir, 11138414Smckusick nfs_readlink, 11238414Smckusick nfs_abortop, 11338414Smckusick nfs_inactive, 11438414Smckusick nfs_lock, 11538414Smckusick nfs_unlock, 11638414Smckusick nfs_bmap, 11738414Smckusick nfs_strategy, 11838414Smckusick }; 11938414Smckusick 12038414Smckusick /* Special device vnode ops */ 12138414Smckusick int blk_open(), 12238414Smckusick blk_read(), 12338414Smckusick blk_write(), 12438414Smckusick blk_ioctl(), 125*39359Smckusick blk_select(); 12638414Smckusick 12738414Smckusick struct vnodeops nfsv2chr_vnodeops = { 12838414Smckusick vfs_noop, 12938414Smckusick vfs_noop, 13038414Smckusick vfs_noop, 13138414Smckusick blk_open, 13238414Smckusick nfs_close, 13338414Smckusick nfs_access, 13438414Smckusick nfs_getattr, 13538414Smckusick nfs_setattr, 13638414Smckusick blk_read, 13738414Smckusick blk_write, 13838414Smckusick blk_ioctl, 13938414Smckusick blk_select, 14038414Smckusick vfs_noop, 14138414Smckusick vfs_nullop, 14238414Smckusick vfs_noop, 14338414Smckusick nfs_remove, 14438414Smckusick nfs_link, 14538414Smckusick nfs_rename, 14638414Smckusick vfs_noop, 14738414Smckusick vfs_noop, 14838414Smckusick nfs_symlink, 14938414Smckusick vfs_noop, 15038414Smckusick vfs_noop, 15138414Smckusick nfs_abortop, 15238414Smckusick nfs_inactive, 15338414Smckusick nfs_lock, 15438414Smckusick nfs_unlock, 155*39359Smckusick vfs_noop, 156*39359Smckusick vfs_noop, 15738414Smckusick }; 15838414Smckusick 15938414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 16038414Smckusick extern u_long nfs_prog, nfs_vers; 16138414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 16238884Smacklem struct map nfsmap[NFS_MSIZ]; 16338414Smckusick enum vtype v_type[NFLNK+1]; 16438884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 16539341Smckusick int nfs_asyncdaemons = 0; 16639341Smckusick struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 16738884Smacklem static int nfsmap_want = 0; 16838414Smckusick 16938414Smckusick /* 17038414Smckusick * nfs null call from vfs. 17138414Smckusick */ 17238414Smckusick nfs_null(vp, cred) 17338414Smckusick struct vnode *vp; 17438414Smckusick struct ucred *cred; 17538414Smckusick { 17638414Smckusick nfsm_vars; 17738414Smckusick 17838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 17938414Smckusick nfsm_request(vp); 18038414Smckusick nfsm_reqdone; 18138414Smckusick return (error); 18238414Smckusick } 18338414Smckusick 18438414Smckusick /* 18538414Smckusick * nfs access vnode op. 18638414Smckusick * Essentially just get vattr and then imitate iaccess() 18738414Smckusick */ 18838414Smckusick nfs_access(vp, mode, cred) 18938414Smckusick struct vnode *vp; 19038414Smckusick int mode; 19138414Smckusick register struct ucred *cred; 19238414Smckusick { 19338414Smckusick register struct vattr *vap; 19438414Smckusick register gid_t *gp; 19538414Smckusick struct vattr vattr; 19638414Smckusick register int i; 19738414Smckusick int error; 19838414Smckusick 19938414Smckusick /* 20038414Smckusick * If you're the super-user, 20138414Smckusick * you always get access. 20238414Smckusick */ 20338414Smckusick if (cred->cr_uid == 0) 20438414Smckusick return (0); 20538414Smckusick vap = &vattr; 20638884Smacklem if (error = nfs_getattr(vp, vap, cred)) 20738884Smacklem return (error); 20838414Smckusick /* 20938414Smckusick * Access check is based on only one of owner, group, public. 21038414Smckusick * If not owner, then check group. If not a member of the 21138414Smckusick * group, then check public access. 21238414Smckusick */ 21338414Smckusick if (cred->cr_uid != vap->va_uid) { 21438414Smckusick mode >>= 3; 21538414Smckusick gp = cred->cr_groups; 21638414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 21738414Smckusick if (vap->va_gid == *gp) 21838414Smckusick goto found; 21938414Smckusick mode >>= 3; 22038414Smckusick found: 22138414Smckusick ; 22238414Smckusick } 22338414Smckusick if ((vap->va_mode & mode) != 0) 22438414Smckusick return (0); 22538414Smckusick return (EACCES); 22638414Smckusick } 22738414Smckusick 22838414Smckusick /* 22938414Smckusick * nfs open vnode op 23038414Smckusick * Just check to see if the type is ok 23138414Smckusick */ 23238414Smckusick nfs_open(vp, mode, cred) 23338414Smckusick struct vnode *vp; 23438414Smckusick int mode; 23538414Smckusick struct ucred *cred; 23638414Smckusick { 23738414Smckusick register enum vtype vtyp; 23838414Smckusick 23938414Smckusick vtyp = vp->v_type; 24038414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 24138414Smckusick return (0); 24238414Smckusick else 24338414Smckusick return (EACCES); 24438414Smckusick } 24538414Smckusick 24638414Smckusick /* 24738414Smckusick * nfs close vnode op 24838884Smacklem * For reg files, invalidate any buffer cache entries. 24938884Smacklem * For VCHR, do the device close 25038414Smckusick */ 25138414Smckusick nfs_close(vp, fflags, cred) 25238414Smckusick register struct vnode *vp; 25338414Smckusick int fflags; 25438414Smckusick struct ucred *cred; 25538414Smckusick { 25638884Smacklem struct nfsnode *np = VTONFS(vp); 25738414Smckusick dev_t dev; 25839341Smckusick int error = 0; 25938414Smckusick 26038884Smacklem nfs_lock(vp); 26139341Smckusick if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) || 26239341Smckusick ((np->n_flag & NBUFFERED) && np->n_sillyrename))) { 26339341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 26439341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 26539341Smckusick if (np->n_flag & NWRITEERR) { 26639341Smckusick np->n_flag &= ~NWRITEERR; 26739341Smckusick if (!error) 26839341Smckusick error = np->n_error ? np->n_error : EIO; 26939341Smckusick } 27038884Smacklem } 27138884Smacklem nfs_unlock(vp); 27238414Smckusick if (vp->v_type != VCHR || vp->v_count > 1) 27339341Smckusick return (error); 27438414Smckusick dev = vp->v_rdev; 27538414Smckusick /* XXX what is this doing below the vnode op call */ 27638414Smckusick if (setjmp(&u.u_qsave)) { 27738414Smckusick /* 27838414Smckusick * If device close routine is interrupted, 27938414Smckusick * must return so closef can clean up. 28038414Smckusick */ 28138414Smckusick error = EINTR; 28238414Smckusick } else 28338414Smckusick error = (*cdevsw[major(dev)].d_close)(dev, fflags, IFCHR); 28438414Smckusick /* 28538414Smckusick * Most device close routines don't return errors, 28638414Smckusick * and dup2() doesn't work right on error. 28738414Smckusick */ 28838414Smckusick error = 0; /* XXX */ 28938414Smckusick return (error); 29038414Smckusick } 29138414Smckusick 29238414Smckusick /* 29338414Smckusick * nfs getattr call from vfs. 29438414Smckusick */ 29538414Smckusick nfs_getattr(vp, vap, cred) 29638414Smckusick struct vnode *vp; 29738414Smckusick register struct vattr *vap; 29838414Smckusick struct ucred *cred; 29938414Smckusick { 30038414Smckusick nfsm_vars; 30138414Smckusick 30238414Smckusick /* First look in the cache.. */ 30338414Smckusick if (nfs_getattrcache(vp, vap) == 0) 30438414Smckusick return (0); 30538414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 30638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH); 30738414Smckusick nfsm_fhtom(vp); 30838414Smckusick nfsm_request(vp); 30938414Smckusick nfsm_loadattr(vp, vap); 31038414Smckusick nfsm_reqdone; 31138414Smckusick return (error); 31238414Smckusick } 31338414Smckusick 31438414Smckusick /* 31538414Smckusick * nfs setattr call. 31638414Smckusick */ 31738414Smckusick nfs_setattr(vp, vap, cred) 31838414Smckusick struct vnode *vp; 31938414Smckusick register struct vattr *vap; 32038414Smckusick struct ucred *cred; 32138414Smckusick { 32238884Smacklem register struct nfsv2_sattr *sp; 32338414Smckusick nfsm_vars; 324*39359Smckusick struct nfsnode *np; 32538414Smckusick 32638414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 32738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 32838414Smckusick nfsm_fhtom(vp); 32938884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 33038414Smckusick if (vap->va_mode == 0xffff) 33138884Smacklem sp->sa_mode = VNOVAL; 33238414Smckusick else 33338884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 33438414Smckusick if (vap->va_uid == 0xffff) 33538884Smacklem sp->sa_uid = VNOVAL; 33638414Smckusick else 33738884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 33838414Smckusick if (vap->va_gid == 0xffff) 33938884Smacklem sp->sa_gid = VNOVAL; 34038414Smckusick else 34138884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 34238884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 343*39359Smckusick if (vap->va_size != VNOVAL) { 344*39359Smckusick np = VTONFS(vp); 345*39359Smckusick if (np->n_flag & NMODIFIED) { 346*39359Smckusick np->n_flag &= ~NMODIFIED; 347*39359Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 348*39359Smckusick } 349*39359Smckusick } 35038884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 35138884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 35238414Smckusick nfsm_request(vp); 35338414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 35438414Smckusick /* should we fill in any vap fields ?? */ 35538414Smckusick nfsm_reqdone; 35638414Smckusick return (error); 35738414Smckusick } 35838414Smckusick 35938414Smckusick /* 36038414Smckusick * nfs lookup call, one step at a time... 36138414Smckusick * First look in cache 36238414Smckusick * If not found, unlock the directory nfsnode and do the rpc 36338414Smckusick */ 36438414Smckusick nfs_lookup(vp, ndp) 36538414Smckusick register struct vnode *vp; 36638414Smckusick register struct nameidata *ndp; 36738414Smckusick { 36838414Smckusick register struct vnode *vdp; 36938414Smckusick nfsm_vars; 37038414Smckusick struct vnode *newvp; 37138414Smckusick long len; 37238414Smckusick nfsv2fh_t *fhp; 37338414Smckusick struct nfsnode *np; 37438414Smckusick int lockparent, wantparent, flag; 37538414Smckusick dev_t rdev; 37638414Smckusick 37738414Smckusick ndp->ni_dvp = vp; 37838414Smckusick ndp->ni_vp = NULL; 37938414Smckusick if (vp->v_type != VDIR) 38038414Smckusick return (ENOTDIR); 38138414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 38238414Smckusick flag = ndp->ni_nameiop & OPFLAG; 38338414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 38439341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 38538884Smacklem struct vattr vattr; 38638884Smacklem int vpid; 38738884Smacklem 38838884Smacklem if (ndp->ni_vp == ndp->ni_rdir && ndp->ni_isdotdot) 38938884Smacklem vdp = vp; 39038884Smacklem else 39138884Smacklem vdp = ndp->ni_vp; 39238884Smacklem vpid = vdp->v_id; 39338414Smckusick /* 39438884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 39538884Smacklem * for an explanation of the locking protocol 39638414Smckusick */ 39738414Smckusick if (vp == vdp) { 39838425Smckusick VREF(vdp); 39938414Smckusick } else if (ndp->ni_isdotdot) { 40038414Smckusick nfs_unlock(vp); 40138414Smckusick nfs_ngrab(VTONFS(vdp)); 40238414Smckusick } else { 40338414Smckusick nfs_ngrab(VTONFS(vdp)); 40438414Smckusick nfs_unlock(vp); 40538414Smckusick } 40638884Smacklem if (vpid == vdp->v_id && 40739341Smckusick !nfs_getattr(vdp, &vattr, ndp->ni_cred)) { 40838884Smacklem nfsstats.lookupcache_hits++; 40938884Smacklem return (0); 41038884Smacklem } 41138884Smacklem nfs_nput(vdp); 41238884Smacklem nfs_lock(vp); 41338884Smacklem ndp->ni_vp = (struct vnode *)0; 41438414Smckusick } 41539341Smckusick error = 0; 41638414Smckusick nfsstats.lookupcache_misses++; 41738414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 41838414Smckusick len = ndp->ni_namelen; 41938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 42038414Smckusick nfsm_fhtom(vp); 42138414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 42238414Smckusick nfsm_request(vp); 42338414Smckusick nfsmout: 42438414Smckusick if (error) { 42538414Smckusick if ((flag == CREATE || flag == RENAME) && 42638414Smckusick *ndp->ni_next == 0) { 42738414Smckusick if (!lockparent) 42838414Smckusick nfs_unlock(vp); 42938414Smckusick } 43038414Smckusick return (ENOENT); 43138414Smckusick } 43238414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 43338414Smckusick 43438414Smckusick /* 43538414Smckusick * Handle DELETE and RENAME cases... 43638414Smckusick */ 43738414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 43838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 43938425Smckusick VREF(vp); 44038414Smckusick newvp = vp; 44138414Smckusick np = VTONFS(vp); 44238414Smckusick } else { 44338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 44438414Smckusick m_freem(mrep); 44538414Smckusick return (error); 44638414Smckusick } 44738414Smckusick newvp = NFSTOV(np); 44838414Smckusick } 44938414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 45038414Smckusick if (newvp != vp) 45138414Smckusick nfs_nput(newvp); 45238414Smckusick else 45338425Smckusick vrele(vp); 45438414Smckusick m_freem(mrep); 45538414Smckusick return (error); 45638414Smckusick } 45738414Smckusick ndp->ni_vp = newvp; 45838414Smckusick if (!lockparent) 45938414Smckusick nfs_unlock(vp); 46038414Smckusick m_freem(mrep); 46138414Smckusick return (0); 46238414Smckusick } 46338414Smckusick 46438414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 46538414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 46638414Smckusick m_freem(mrep); 46738414Smckusick return (EISDIR); 46838414Smckusick } 46938414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 47038414Smckusick m_freem(mrep); 47138414Smckusick return (error); 47238414Smckusick } 47338414Smckusick newvp = NFSTOV(np); 47438414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 47538425Smckusick nfs_nput(newvp); 47638414Smckusick m_freem(mrep); 47738414Smckusick return (error); 47838414Smckusick } 47938414Smckusick ndp->ni_vp = newvp; 48038414Smckusick if (!lockparent) 48138414Smckusick nfs_unlock(vp); 48238414Smckusick return (0); 48338414Smckusick } 48438414Smckusick 48538414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 48638425Smckusick VREF(vp); 48738414Smckusick newvp = vp; 48838414Smckusick np = VTONFS(vp); 48938414Smckusick } else if (ndp->ni_isdotdot) { 49038414Smckusick nfs_unlock(vp); 49138414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 49238414Smckusick nfs_lock(vp); 49338414Smckusick m_freem(mrep); 49438414Smckusick return (error); 49538414Smckusick } 49638414Smckusick nfs_lock(vp); 49738414Smckusick newvp = NFSTOV(np); 49838414Smckusick } else { 49938414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 50038414Smckusick m_freem(mrep); 50138414Smckusick return (error); 50238414Smckusick } 50338414Smckusick newvp = NFSTOV(np); 50438414Smckusick } 50538414Smckusick if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) { 50638414Smckusick if (newvp != vp) 50738414Smckusick nfs_nput(newvp); 50838414Smckusick else 50938425Smckusick vrele(vp); 51038414Smckusick m_freem(mrep); 51138414Smckusick return (error); 51238414Smckusick } 51338414Smckusick m_freem(mrep); 51438414Smckusick 51538414Smckusick if (vp != newvp && (!lockparent || *ndp->ni_next != '\0')) 51638414Smckusick nfs_unlock(vp); 51738414Smckusick ndp->ni_vp = newvp; 51838414Smckusick if (error == 0 && ndp->ni_makeentry) 51938414Smckusick cache_enter(ndp); 52038414Smckusick return (error); 52138414Smckusick } 52238414Smckusick 52338414Smckusick /* 52438414Smckusick * nfs readlink call 52538414Smckusick */ 52638414Smckusick nfs_readlink(vp, uiop, cred) 52738414Smckusick struct vnode *vp; 52838414Smckusick struct uio *uiop; 52938414Smckusick struct ucred *cred; 53038414Smckusick { 53138414Smckusick nfsm_vars; 53238414Smckusick long len; 53338414Smckusick 53438414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 53538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 53638414Smckusick nfsm_fhtom(vp); 53738414Smckusick nfsm_request(vp); 53838414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 53938414Smckusick nfsm_mtouio(uiop, len); 54038414Smckusick nfsm_reqdone; 54138414Smckusick return (error); 54238414Smckusick } 54338414Smckusick 54438414Smckusick /* 54538414Smckusick * nfs read call 54638414Smckusick */ 54738884Smacklem nfs_readrpc(vp, uiop, offp, cred) 54838414Smckusick struct vnode *vp; 54938414Smckusick struct uio *uiop; 55038414Smckusick off_t *offp; 55138414Smckusick struct ucred *cred; 55238414Smckusick { 55338414Smckusick nfsm_vars; 55438414Smckusick struct nfsmount *nmp; 55538414Smckusick long len, retlen, tsiz; 55638414Smckusick 55738414Smckusick nmp = vfs_to_nfs(vp->v_mount); 55838414Smckusick tsiz = uiop->uio_resid; 55938414Smckusick while (tsiz > 0) { 56038414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 56138414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 56238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 56338414Smckusick nfsm_fhtom(vp); 56438414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*3); 56538414Smckusick *p++ = txdr_unsigned(*offp); 56638414Smckusick *p++ = txdr_unsigned(len); 56738414Smckusick *p = 0; 56838414Smckusick nfsm_request(vp); 56938414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 57038414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 57138414Smckusick nfsm_mtouio(uiop, retlen); 57238414Smckusick m_freem(mrep); 57338414Smckusick *offp += retlen; 57438414Smckusick if (retlen < len) 57538414Smckusick tsiz = 0; 57638414Smckusick else 57738414Smckusick tsiz -= len; 57838414Smckusick } 57938414Smckusick nfsmout: 58038414Smckusick return (error); 58138414Smckusick } 58238414Smckusick 58338414Smckusick /* 58438414Smckusick * nfs write call 58538414Smckusick */ 58638884Smacklem nfs_writerpc(vp, uiop, offp, cred) 58738414Smckusick struct vnode *vp; 58838414Smckusick struct uio *uiop; 58938414Smckusick off_t *offp; 59038414Smckusick struct ucred *cred; 59138414Smckusick { 59238414Smckusick nfsm_vars; 59338414Smckusick struct nfsmount *nmp; 59438414Smckusick long len, tsiz; 59538414Smckusick 59638414Smckusick nmp = vfs_to_nfs(vp->v_mount); 59738414Smckusick tsiz = uiop->uio_resid; 59838414Smckusick while (tsiz > 0) { 59938414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 60038414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 60138414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 60238414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 60338414Smckusick nfsm_fhtom(vp); 60438414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*4); 60538414Smckusick *(p+1) = txdr_unsigned(*offp); 60638414Smckusick *(p+3) = txdr_unsigned(len); 60738414Smckusick nfsm_uiotom(uiop, len); 60838414Smckusick nfsm_request(vp); 60938414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 61038414Smckusick m_freem(mrep); 61138414Smckusick tsiz -= len; 61238414Smckusick *offp += len; 61338414Smckusick } 61438414Smckusick nfsmout: 61538414Smckusick return (error); 61638414Smckusick } 61738414Smckusick 61838414Smckusick /* 61938414Smckusick * nfs file create call 62038414Smckusick */ 62138414Smckusick nfs_create(ndp, vap) 62238414Smckusick register struct nameidata *ndp; 62338414Smckusick register struct vattr *vap; 62438414Smckusick { 62538884Smacklem register struct nfsv2_sattr *sp; 62638414Smckusick nfsm_vars; 62738414Smckusick 62838414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 62938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 63038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 63138414Smckusick nfsm_fhtom(ndp->ni_dvp); 63238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 63338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 63438884Smacklem sp->sa_mode = vtonfs_mode(VREG, vap->va_mode); 63538884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 63638884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 63738884Smacklem sp->sa_size = txdr_unsigned(0); 63838414Smckusick /* or should these be VNOVAL ?? */ 63938884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 64038884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 64138414Smckusick nfsm_request(ndp->ni_dvp); 64238414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 64338414Smckusick nfsm_reqdone; 64438414Smckusick nfs_nput(ndp->ni_dvp); 64538414Smckusick return (error); 64638414Smckusick } 64738414Smckusick 64838414Smckusick /* 64938414Smckusick * nfs file remove call 65039341Smckusick * To try and make nfs semantics closer to vfs semantics, a file that has 65139341Smckusick * other references to the vnode is renamed instead of removed and then 65239341Smckusick * removed later on the last close. 65339341Smckusick * Unfortunately you must flush the buffer cache and cmap to get rid of 65439341Smckusick * all extraneous vnode references before you check the reference cnt. 65539341Smckusick * 1 - If the file could have blocks in the buffer cache 65639341Smckusick * flush them out and invalidate them 65739341Smckusick * mpurge the vnode to flush out cmap references 65839341Smckusick * (This is necessary to update the vnode ref cnt as well as sensible 65939341Smckusick * for actual removes, to free up the buffers) 66039341Smckusick * 2 - If v_count > 1 66139341Smckusick * If a rename is not already in the works 66239341Smckusick * call nfs_sillyrename() to set it up 66339341Smckusick * else 66439341Smckusick * do the remove rpc 66538414Smckusick */ 66638414Smckusick nfs_remove(ndp) 66738414Smckusick register struct nameidata *ndp; 66838414Smckusick { 66939341Smckusick register struct vnode *vp = ndp->ni_vp; 67039341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 67138414Smckusick nfsm_vars; 67238414Smckusick 67339341Smckusick if (vp->v_type == VREG) { 67439341Smckusick if (np->n_flag & (NMODIFIED|NBUFFERED)) { 67539341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 67639341Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 67739341Smckusick } 67839341Smckusick if (np->n_flag & NPAGEDON) 67939341Smckusick mpurge(vp); /* In case cmap entries still ref it */ 68039341Smckusick } 68139341Smckusick if (vp->v_count > 1) { 68239341Smckusick if (!np->n_sillyrename) 68339341Smckusick error = nfs_sillyrename(ndp, REMOVE); 68439341Smckusick } else { 68538414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 68638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 68738414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 68838414Smckusick nfsm_fhtom(ndp->ni_dvp); 68938414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 69038414Smckusick nfsm_request(ndp->ni_dvp); 69138414Smckusick nfsm_reqdone; 69238414Smckusick } 69338414Smckusick if (ndp->ni_dvp == ndp->ni_vp) 69438425Smckusick vrele(ndp->ni_vp); 69538414Smckusick else 69638425Smckusick nfs_nput(ndp->ni_vp); 69738425Smckusick nfs_nput(ndp->ni_dvp); 69838414Smckusick return (error); 69938414Smckusick } 70038414Smckusick 70138414Smckusick /* 70238414Smckusick * nfs file remove rpc called from nfs_inactive 70338414Smckusick */ 70438414Smckusick nfs_removeit(ndp) 70538414Smckusick register struct nameidata *ndp; 70638414Smckusick { 70738414Smckusick nfsm_vars; 70838414Smckusick 70938414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 71038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 71138414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 71238414Smckusick nfsm_fhtom(ndp->ni_dvp); 71338414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 71438414Smckusick nfsm_request(ndp->ni_dvp); 71538414Smckusick nfsm_reqdone; 71638414Smckusick return (error); 71738414Smckusick } 71838414Smckusick 71938414Smckusick /* 72038414Smckusick * nfs file rename call 72138414Smckusick */ 72238414Smckusick nfs_rename(sndp, tndp) 72338414Smckusick register struct nameidata *sndp, *tndp; 72438414Smckusick { 72538414Smckusick nfsm_vars; 72638414Smckusick 72738414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 72838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 72938414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 73038414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 73138414Smckusick nfsm_fhtom(sndp->ni_dvp); 73238414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 73338414Smckusick nfsm_fhtom(tndp->ni_dvp); 73438414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 73538414Smckusick nfsm_request(sndp->ni_dvp); 73638414Smckusick nfsm_reqdone; 73738414Smckusick if (sndp->ni_vp->v_type == VDIR) { 73838414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 73938414Smckusick cache_purge(tndp->ni_dvp); 74038414Smckusick cache_purge(sndp->ni_dvp); 74138414Smckusick } 74238414Smckusick nfs_abortop(sndp); 74338414Smckusick nfs_abortop(tndp); 74438414Smckusick return (error); 74538414Smckusick } 74638414Smckusick 74738414Smckusick /* 74838414Smckusick * nfs file rename rpc called from above 74938414Smckusick */ 75038414Smckusick nfs_renameit(sndp, tndp) 75138414Smckusick register struct nameidata *sndp, *tndp; 75238414Smckusick { 75338414Smckusick nfsm_vars; 75438414Smckusick 75538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 75638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 75738414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 75838414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 75938414Smckusick nfsm_fhtom(sndp->ni_dvp); 76038414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 76138414Smckusick nfsm_fhtom(tndp->ni_dvp); 76238414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 76338414Smckusick nfsm_request(sndp->ni_dvp); 76438414Smckusick nfsm_reqdone; 76538414Smckusick return (error); 76638414Smckusick } 76738414Smckusick 76838414Smckusick /* 76938414Smckusick * nfs hard link create call 77038414Smckusick */ 77138414Smckusick nfs_link(vp, ndp) 77238414Smckusick struct vnode *vp; 77338414Smckusick register struct nameidata *ndp; 77438414Smckusick { 77538414Smckusick nfsm_vars; 77638414Smckusick 77738425Smckusick if (ndp->ni_dvp != vp) 77838425Smckusick nfs_lock(vp); 77938414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 78038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 78138414Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 78238414Smckusick nfsm_fhtom(vp); 78338414Smckusick nfsm_fhtom(ndp->ni_dvp); 78438414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 78538414Smckusick nfsm_request(vp); 78638414Smckusick nfsm_reqdone; 78738425Smckusick if (ndp->ni_dvp != vp) 78838425Smckusick nfs_unlock(vp); 78938414Smckusick nfs_nput(ndp->ni_dvp); 79038414Smckusick return (error); 79138414Smckusick } 79238414Smckusick 79338414Smckusick /* 79438414Smckusick * nfs symbolic link create call 79538414Smckusick */ 79638414Smckusick nfs_symlink(ndp, vap, nm) 79738414Smckusick struct nameidata *ndp; 79838414Smckusick struct vattr *vap; 79938414Smckusick char *nm; /* is this the path ?? */ 80038414Smckusick { 80138884Smacklem register struct nfsv2_sattr *sp; 80238414Smckusick nfsm_vars; 80338414Smckusick 80438414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 80538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 80638414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED); 80738414Smckusick nfsm_fhtom(ndp->ni_dvp); 80838414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 80938414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 81038884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 81138884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 81238884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 81338884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 81438884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 81538884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 81638884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 81738414Smckusick nfsm_request(ndp->ni_dvp); 81838414Smckusick nfsm_reqdone; 81938414Smckusick nfs_nput(ndp->ni_dvp); 82038414Smckusick return (error); 82138414Smckusick } 82238414Smckusick 82338414Smckusick /* 82438414Smckusick * nfs make dir call 82538414Smckusick */ 82638414Smckusick nfs_mkdir(ndp, vap) 82738414Smckusick struct nameidata *ndp; 82838414Smckusick struct vattr *vap; 82938414Smckusick { 83038884Smacklem register struct nfsv2_sattr *sp; 83138414Smckusick nfsm_vars; 83238414Smckusick 83338414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 83438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 83538414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 83638414Smckusick nfsm_fhtom(ndp->ni_dvp); 83738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 83838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 83938884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 84038884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 84138884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 84238884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 84338884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 84438884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 84538414Smckusick nfsm_request(ndp->ni_dvp); 84638414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 84738414Smckusick nfsm_reqdone; 84838414Smckusick nfs_nput(ndp->ni_dvp); 84938414Smckusick return (error); 85038414Smckusick } 85138414Smckusick 85238414Smckusick /* 85338414Smckusick * nfs remove directory call 85438414Smckusick */ 85538414Smckusick nfs_rmdir(ndp) 85638414Smckusick register struct nameidata *ndp; 85738414Smckusick { 85838414Smckusick nfsm_vars; 85938414Smckusick 86038414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 86138414Smckusick vrele(ndp->ni_dvp); 86238414Smckusick nfs_nput(ndp->ni_dvp); 86338414Smckusick return (EINVAL); 86438414Smckusick } 86538414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 86638414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 86738414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 86838414Smckusick nfsm_fhtom(ndp->ni_dvp); 86938414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 87038414Smckusick nfsm_request(ndp->ni_dvp); 87138414Smckusick nfsm_reqdone; 87238884Smacklem cache_purge(ndp->ni_dvp); 87338884Smacklem cache_purge(ndp->ni_vp); 87438884Smacklem nfs_nput(ndp->ni_vp); 87538884Smacklem nfs_nput(ndp->ni_dvp); 87638414Smckusick return (error); 87738414Smckusick } 87838414Smckusick 87938414Smckusick /* 88038414Smckusick * nfs readdir call 88138414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 88238414Smckusick * order so that it looks more sensible. This appears consistent with the 88338414Smckusick * Ultrix implementation of NFS. 88438414Smckusick */ 88538414Smckusick nfs_readdir(vp, uiop, offp, cred) 88638414Smckusick struct vnode *vp; 88738414Smckusick struct uio *uiop; 88838414Smckusick off_t *offp; 88938414Smckusick struct ucred *cred; 89038414Smckusick { 89138414Smckusick register long len; 89238414Smckusick register struct direct *dp; 89338414Smckusick nfsm_vars; 89438414Smckusick struct mbuf *md2; 89538414Smckusick caddr_t dpos2; 89638414Smckusick int siz; 89738414Smckusick int more_dirs, eofflg; 89838414Smckusick off_t off, savoff; 89938414Smckusick struct direct *savdp; 90038414Smckusick 90138414Smckusick nfs_lock(vp); 90238414Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 90338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 90438414Smckusick nfsm_fhtom(vp); 90538414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 90638414Smckusick off = *offp; 90738414Smckusick *p++ = txdr_unsigned(off); 90838414Smckusick *p = txdr_unsigned(uiop->uio_resid); 90938414Smckusick nfsm_request(vp); 91038414Smckusick siz = 0; 91138414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 91238414Smckusick more_dirs = fxdr_unsigned(int, *p); 91338414Smckusick 91438414Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 91538414Smckusick dpos2 = dpos; 91638414Smckusick md2 = md; 91738414Smckusick 91838414Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 91938414Smckusick while (more_dirs && siz < uiop->uio_resid) { 92038414Smckusick savoff = off; /* Hold onto offset and dp */ 92138414Smckusick savdp = dp; 92238414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 92338414Smckusick dp = (struct direct *)p; 92438414Smckusick dp->d_ino = fxdr_unsigned(u_long, *p++); 92538414Smckusick len = fxdr_unsigned(int, *p); 92638414Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 92738414Smckusick error = EBADRPC; 92838414Smckusick m_freem(mrep); 92938414Smckusick goto nfsmout; 93038414Smckusick } 93138414Smckusick dp->d_namlen = (u_short)len; 93238414Smckusick len = nfsm_rndup(len); 93338414Smckusick nfsm_adv(len); 93438414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 93538414Smckusick off = fxdr_unsigned(off_t, *p); 93638414Smckusick *p++ = 0; /* Ensures null termination of name */ 93738414Smckusick more_dirs = fxdr_unsigned(int, *p); 93838414Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 93938414Smckusick siz += dp->d_reclen; 94038414Smckusick } 94138414Smckusick /* 94238414Smckusick * If at end of rpc data, get the eof boolean 94338414Smckusick */ 94438414Smckusick if (!more_dirs) { 94538414Smckusick nfsm_disecton(p, u_long *, NFSX_UNSIGNED); 94638414Smckusick eofflg = fxdr_unsigned(long, *p); 94738414Smckusick } 94838414Smckusick /* 94938414Smckusick * If there is too much to fit in the data buffer, use savoff and 95038414Smckusick * savdp to trim off the last record. 95138414Smckusick * --> we are not at eof 95238414Smckusick */ 95338414Smckusick if (siz > uiop->uio_resid) { 95438414Smckusick eofflg = FALSE; 95538414Smckusick off = savoff; 95638414Smckusick siz -= dp->d_reclen; 95738414Smckusick dp = savdp; 95838414Smckusick } 95938414Smckusick if (siz > 0) { 96038414Smckusick #ifdef notdef 96138414Smckusick if (!eofflg) 96238414Smckusick dp->d_reclen += (uiop->uio_resid-siz); 96338414Smckusick #endif 96438414Smckusick md = md2; 96538414Smckusick dpos = dpos2; 96638414Smckusick nfsm_mtouio(uiop, siz); 96738414Smckusick #ifdef notdef 96838414Smckusick if (!eofflg) 96938414Smckusick uiop->uio_resid = 0; 97038414Smckusick #endif 97138414Smckusick *offp = off; 97238414Smckusick } 97338414Smckusick nfsm_reqdone; 97438414Smckusick nfs_unlock(vp); 97538414Smckusick return (error); 97638414Smckusick } 97738414Smckusick 97838414Smckusick /* 97938414Smckusick * nfs statfs call 98038414Smckusick * (Actually a vfsop, not a vnode op) 98138414Smckusick */ 98238414Smckusick nfs_statfs(mp, sbp) 98338414Smckusick struct mount *mp; 98438414Smckusick register struct statfs *sbp; 98538414Smckusick { 98638884Smacklem register struct nfsv2_statfs *sfp; 98738414Smckusick nfsm_vars; 98838884Smacklem struct nfsmount *nmp; 98938414Smckusick struct ucred *cred; 99038414Smckusick struct nfsnode *np; 99138414Smckusick struct vnode *vp; 99238414Smckusick 99338414Smckusick nmp = vfs_to_nfs(mp); 99438414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 99538414Smckusick return (error); 99638414Smckusick vp = NFSTOV(np); 99738414Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 99838414Smckusick cred = crget(); 99938414Smckusick cred->cr_ngroups = 1; 100038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 100138414Smckusick nfsm_fhtom(vp); 100238414Smckusick nfsm_request(vp); 100338884Smacklem nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 100438414Smckusick sbp->f_type = MOUNT_NFS; 100538414Smckusick sbp->f_flags = nmp->nm_flag; 100638884Smacklem sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 100738884Smacklem sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 100838884Smacklem sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 100938884Smacklem sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 101038884Smacklem sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 101138739Smckusick sbp->f_files = 0; 101238739Smckusick sbp->f_ffree = 0; 101338414Smckusick sbp->f_fsid.val[0] = mp->m_fsid.val[0]; 101438414Smckusick sbp->f_fsid.val[1] = mp->m_fsid.val[1]; 101538414Smckusick bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN); 101638414Smckusick bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN); 101738414Smckusick nfsm_reqdone; 101838414Smckusick nfs_nput(vp); 101938414Smckusick crfree(cred); 102038414Smckusick return (error); 102138414Smckusick } 102238414Smckusick 102338414Smckusick #define HEXTOASC(x) "0123456789abcdef"[x] 102438414Smckusick 102538414Smckusick /* 102638414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 102738414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 102838414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 102938414Smckusick * nfsnode. There is the potential for another process on a different client 103038414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 103138414Smckusick * nfs_rename() completes, but... 103238414Smckusick */ 103338414Smckusick nfs_sillyrename(ndp, flag) 103438414Smckusick struct nameidata *ndp; 103538414Smckusick int flag; 103638414Smckusick { 103738414Smckusick register struct nfsnode *np; 103838414Smckusick register struct sillyrename *sp; 103938414Smckusick register struct nameidata *tndp; 104038414Smckusick int error; 104138414Smckusick short pid; 104238414Smckusick 104338414Smckusick np = VTONFS(ndp->ni_dvp); 104439341Smckusick cache_purge(ndp->ni_dvp); 104538414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 104638884Smacklem M_TEMP, M_WAITOK); 104738414Smckusick sp->s_flag = flag; 104838414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 104938414Smckusick np = VTONFS(ndp->ni_vp); 105038414Smckusick tndp = &sp->s_namei; 105138414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 105238414Smckusick 105338414Smckusick /* Fudge together a funny name */ 105438414Smckusick pid = u.u_procp->p_pid; 105538414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 105638414Smckusick tndp->ni_dent.d_namlen = 12; 105738414Smckusick tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf); 105838414Smckusick tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf); 105938414Smckusick tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf); 106038414Smckusick tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf); 106138414Smckusick 106238414Smckusick /* Try lookitups until we get one that isn't there */ 106338414Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) { 106438414Smckusick tndp->ni_dent.d_name[4]++; 106538414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 106638414Smckusick error = EINVAL; 106738414Smckusick goto bad; 106838414Smckusick } 106938414Smckusick } 107038414Smckusick if (error = nfs_renameit(ndp, tndp)) 107138414Smckusick goto bad; 107238414Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh); 107338414Smckusick np->n_sillyrename = sp; 107438414Smckusick return (0); 107538414Smckusick bad: 107638884Smacklem crfree(tndp->ni_cred); 107738414Smckusick free((caddr_t)sp, M_TEMP); 107838414Smckusick return (error); 107938414Smckusick } 108038414Smckusick 108138414Smckusick /* 108238414Smckusick * Look up a file name for silly rename stuff. 108338414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 108438414Smckusick * into the nfsnode table. 108538414Smckusick * If fhp != NULL it copies the returned file handle out 108638414Smckusick */ 108738414Smckusick nfs_lookitup(vp, ndp, fhp) 108838414Smckusick register struct vnode *vp; 108938414Smckusick register struct nameidata *ndp; 109038414Smckusick nfsv2fh_t *fhp; 109138414Smckusick { 109238414Smckusick nfsm_vars; 109338414Smckusick long len; 109438414Smckusick 109538414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 109638414Smckusick ndp->ni_dvp = vp; 109738414Smckusick ndp->ni_vp = NULL; 109838414Smckusick len = ndp->ni_dent.d_namlen; 109938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 110038414Smckusick nfsm_fhtom(vp); 110138414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 110238414Smckusick nfsm_request(vp); 110338414Smckusick if (fhp != NULL) { 110438414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 110538414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 110638414Smckusick } 110738414Smckusick nfsm_reqdone; 110838414Smckusick return (error); 110938414Smckusick } 111038414Smckusick 111138414Smckusick /* 111238414Smckusick * Kludge City.. 111338414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 111438414Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit 111538414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 111638414Smckusick * nfsiobuf area. 111738414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 111838414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 111938414Smckusick * a lot more work than bcopy() and also it currently happens in the 112038414Smckusick * context of the swapper process (2). 112138414Smckusick */ 112238414Smckusick nfs_bmap(vp, bn, vpp, bnp) 112338414Smckusick struct vnode *vp; 112438414Smckusick daddr_t bn; 112538414Smckusick struct vnode **vpp; 112638414Smckusick daddr_t *bnp; 112738414Smckusick { 112838414Smckusick if (vpp != NULL) 112938414Smckusick *vpp = vp; 113038414Smckusick if (bnp != NULL) 113138414Smckusick *bnp = bn * btodb(vp->v_mount->m_bsize); 113238414Smckusick return (0); 113338414Smckusick } 113438414Smckusick 113538414Smckusick /* 113638884Smacklem * Strategy routine for phys. i/o 113738884Smacklem * If the biod's are running, queue a request 113838884Smacklem * otherwise just call nfs_doio() to get it done 113938414Smckusick */ 114038414Smckusick nfs_strategy(bp) 114138414Smckusick register struct buf *bp; 114238414Smckusick { 114338884Smacklem register struct buf *dp; 114439341Smckusick register int i; 114538884Smacklem struct proc *rp; 114638884Smacklem int error = 0; 114739341Smckusick int fnd = 0; 114838884Smacklem 114938884Smacklem /* 115038884Smacklem * If an i/o daemon is waiting 115138884Smacklem * queue the request, wake it up and wait for completion 115238884Smacklem * otherwise just do it ourselves 115338884Smacklem */ 115439341Smckusick for (i = 0; i < nfs_asyncdaemons; i++) { 115539341Smckusick if (rp = nfs_iodwant[i]) { 115639341Smckusick /* 115739341Smckusick * Ensure that the async_daemon is still waiting here 115839341Smckusick */ 115939341Smckusick if (rp->p_stat != SSLEEP || 116039341Smckusick rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) { 116139341Smckusick nfs_iodwant[i] = (struct proc *)0; 116239341Smckusick continue; 116339341Smckusick } 116439341Smckusick dp = &nfs_bqueue; 116539341Smckusick if (dp->b_actf == NULL) { 116639341Smckusick dp->b_actl = bp; 116739341Smckusick bp->b_actf = dp; 116839341Smckusick } else { 116939341Smckusick dp->b_actf->b_actl = bp; 117039341Smckusick bp->b_actf = dp->b_actf; 117139341Smckusick } 117239341Smckusick dp->b_actf = bp; 117339341Smckusick bp->b_actl = dp; 117439341Smckusick fnd++; 117539341Smckusick nfs_iodwant[i] = (struct proc *)0; 117639341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 117739341Smckusick break; 117838884Smacklem } 117939341Smckusick } 118039341Smckusick if (!fnd) 118138884Smacklem error = nfs_doio(bp); 118238884Smacklem return (error); 118338884Smacklem } 118438884Smacklem 118538884Smacklem /* 118638884Smacklem * Fun and games with i/o 118738884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 118838884Smacklem * mapping the data buffer into kernel virtual space and doing the 118938884Smacklem * nfs read or write rpc's from it. 119038884Smacklem * If the biod's are not running, this is just called from nfs_strategy(), 119138884Smacklem * otherwise it is called by the biod's to do what would normally be 119238884Smacklem * partially disk interrupt driven. 119338884Smacklem */ 119438884Smacklem nfs_doio(bp) 119538884Smacklem register struct buf *bp; 119638884Smacklem { 119738414Smckusick register struct pte *pte, *ppte; 119838414Smckusick register caddr_t vaddr; 119938414Smckusick register struct uio *uiop; 120038414Smckusick register struct vnode *vp; 120139341Smckusick struct nfsnode *np; 120238884Smacklem struct ucred *cr; 120338884Smacklem int npf, npf2; 120438884Smacklem int reg; 120538884Smacklem caddr_t vbase; 120638884Smacklem caddr_t addr; 120738414Smckusick unsigned v; 120838414Smckusick struct proc *rp; 120938414Smckusick int o, error; 121038884Smacklem int bcnt; 121138414Smckusick off_t off; 121238414Smckusick struct uio uio; 121338414Smckusick struct iovec io; 121438414Smckusick 121538414Smckusick vp = bp->b_vp; 121638414Smckusick uiop = &uio; 121738414Smckusick uiop->uio_iov = &io; 121838414Smckusick uiop->uio_iovcnt = 1; 121938414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 122038884Smacklem if (bp->b_flags & B_READ) { 122138884Smacklem io.iov_len = uiop->uio_resid = bp->b_bcount; 122238884Smacklem uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE; 122338884Smacklem addr = bp->b_un.b_addr; 122438884Smacklem bcnt = bp->b_bcount; 122538884Smacklem } else { 122638884Smacklem io.iov_len = uiop->uio_resid = bp->b_dirtyend-bp->b_dirtyoff; 122738884Smacklem uiop->uio_offset = off = (bp->b_blkno*DEV_BSIZE)+bp->b_dirtyoff; 122838884Smacklem addr = bp->b_un.b_addr+bp->b_dirtyoff; 122938884Smacklem bcnt = bp->b_dirtyend-bp->b_dirtyoff; 123038414Smckusick } 123138414Smckusick /* 123238884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 123338884Smacklem * the Nfsiomap pte's 123438884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 123538884Smacklem * and a guess at a group 123638414Smckusick */ 123738884Smacklem if (bp->b_flags & B_PHYS) { 123839341Smckusick VTONFS(vp)->n_flag |= NPAGEDON; 123938884Smacklem bp->b_rcred = cr = crget(); 124038884Smacklem rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc; 124138884Smacklem cr->cr_uid = rp->p_uid; 124238884Smacklem cr->cr_gid = 0; /* Anything ?? */ 124338884Smacklem cr->cr_ngroups = 1; 124438884Smacklem o = (int)addr & PGOFSET; 124538884Smacklem npf2 = npf = btoc(bcnt + o); 124638884Smacklem /* 124738884Smacklem * Get some mapping page table entries 124838884Smacklem */ 124938884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 125038884Smacklem nfsmap_want++; 125138884Smacklem sleep((caddr_t)&nfsmap_want, PZERO-1); 125238884Smacklem } 125338884Smacklem reg--; 125438884Smacklem /* I know it is always the else, but that may change someday */ 125538884Smacklem if ((bp->b_flags & B_PHYS) == 0) 125638884Smacklem pte = kvtopte(bp->b_un.b_addr); 125738884Smacklem else if (bp->b_flags & B_PAGET) 125838884Smacklem pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 125938884Smacklem else { 126038884Smacklem v = btop(bp->b_un.b_addr); 126138884Smacklem if (bp->b_flags & B_UAREA) 126238884Smacklem pte = &rp->p_addr[v]; 126338884Smacklem else 126438884Smacklem pte = vtopte(rp, v); 126538884Smacklem } 126638884Smacklem /* 126738884Smacklem * Play vmaccess() but with the Nfsiomap page table 126838884Smacklem */ 126938884Smacklem ppte = &Nfsiomap[reg]; 127038884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 127138884Smacklem while (npf != 0) { 127238884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 127338414Smckusick #if defined(tahoe) 127438884Smacklem mtpr(P1DC, vaddr); 127538414Smckusick #endif 127638884Smacklem ppte++; 127738884Smacklem pte++; 127838884Smacklem vaddr += NBPG; 127938884Smacklem --npf; 128038884Smacklem } 128138884Smacklem io.iov_base = vbase+o; 128238884Smacklem } else { 128338884Smacklem io.iov_base = addr; 128438414Smckusick } 128538414Smckusick if (bp->b_flags & B_READ) { 128638414Smckusick uiop->uio_rw = UIO_READ; 128738884Smacklem bp->b_error = error = nfs_readrpc(vp, uiop, &off, bp->b_rcred); 128838414Smckusick } else { 128938414Smckusick uiop->uio_rw = UIO_WRITE; 129038884Smacklem bp->b_error = error = nfs_writerpc(vp, uiop, &off, bp->b_wcred); 129139341Smckusick if (error) { 129239341Smckusick np = VTONFS(vp); 129339341Smckusick np->n_error = error; 129439341Smckusick np->n_flag |= NWRITEERR; 129539341Smckusick } 129638884Smacklem bp->b_dirtyoff = bp->b_dirtyend = 0; 129738414Smckusick } 129838884Smacklem if (error) 129938884Smacklem bp->b_flags |= B_ERROR; 130038414Smckusick bp->b_resid = uiop->uio_resid; 130138884Smacklem /* 130238884Smacklem * Release pte's used by physical i/o 130338884Smacklem */ 130438884Smacklem if (bp->b_flags & B_PHYS) { 130538884Smacklem crfree(cr); 130638884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 130738884Smacklem if (nfsmap_want) { 130838884Smacklem nfsmap_want = 0; 130938884Smacklem wakeup((caddr_t)&nfsmap_want); 131038884Smacklem } 131138884Smacklem } 131238414Smckusick biodone(bp); 131338414Smckusick return (error); 131438414Smckusick } 131538884Smacklem 131638884Smacklem /* 131738884Smacklem * Flush all the blocks associated with a vnode. 131838884Smacklem * Walk through the buffer pool and push any dirty pages 131938884Smacklem * associated with the vnode. 132038884Smacklem */ 132138884Smacklem nfs_fsync(vp, fflags, cred) 132238884Smacklem register struct vnode *vp; 132338884Smacklem int fflags; 132438884Smacklem struct ucred *cred; 132538884Smacklem { 132638884Smacklem register struct nfsnode *np = VTONFS(vp); 132738884Smacklem int error; 132838884Smacklem 132938884Smacklem nfs_lock(vp); 133038884Smacklem if (np->n_flag & NMODIFIED) { 133138884Smacklem np->n_flag &= ~NMODIFIED; 133239341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, FALSE); 133338884Smacklem } 133438884Smacklem nfs_unlock(vp); 133538884Smacklem return (error); 133638884Smacklem } 1337