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*39495Smckusick * @(#)nfs_vnops.c 7.14 (Berkeley) 11/03/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(), 6339459Smckusick nfs_mknod(), 6438414Smckusick nfs_open(), 6538414Smckusick nfs_close(), 6638414Smckusick nfs_access(), 6738414Smckusick nfs_getattr(), 6838414Smckusick nfs_setattr(), 6938414Smckusick nfs_read(), 7038414Smckusick nfs_write(), 7138414Smckusick vfs_noop(), 7238414Smckusick vfs_nullop(), 7338414Smckusick nfs_remove(), 7438414Smckusick nfs_link(), 7538414Smckusick nfs_rename(), 7638414Smckusick nfs_mkdir(), 7738414Smckusick nfs_rmdir(), 7838414Smckusick nfs_symlink(), 7938414Smckusick nfs_readdir(), 8038414Smckusick nfs_readlink(), 8138414Smckusick nfs_abortop(), 8238414Smckusick nfs_lock(), 8338414Smckusick nfs_unlock(), 8438414Smckusick nfs_bmap(), 8538414Smckusick nfs_strategy(), 8638884Smacklem nfs_fsync(), 8739394Smckusick nfs_inactive(), 8839394Smckusick nfs_reclaim(); 8938414Smckusick 9038414Smckusick struct vnodeops nfsv2_vnodeops = { 9138414Smckusick nfs_lookup, 9238414Smckusick nfs_create, 9339459Smckusick nfs_mknod, 9438414Smckusick nfs_open, 9538414Smckusick nfs_close, 9638414Smckusick nfs_access, 9738414Smckusick nfs_getattr, 9838414Smckusick nfs_setattr, 9938414Smckusick nfs_read, 10038414Smckusick nfs_write, 10138414Smckusick vfs_noop, 10238414Smckusick vfs_noop, 10338414Smckusick vfs_noop, 10438884Smacklem nfs_fsync, 10539459Smckusick vfs_nullop, 10638414Smckusick nfs_remove, 10738414Smckusick nfs_link, 10838414Smckusick nfs_rename, 10938414Smckusick nfs_mkdir, 11038414Smckusick nfs_rmdir, 11138414Smckusick nfs_symlink, 11238414Smckusick nfs_readdir, 11338414Smckusick nfs_readlink, 11438414Smckusick nfs_abortop, 11538414Smckusick nfs_inactive, 11639394Smckusick nfs_reclaim, 11738414Smckusick nfs_lock, 11838414Smckusick nfs_unlock, 11938414Smckusick nfs_bmap, 12038414Smckusick nfs_strategy, 12138414Smckusick }; 12238414Smckusick 12338414Smckusick /* Special device vnode ops */ 12439441Smckusick int spec_lookup(), 12539441Smckusick spec_open(), 12639441Smckusick spec_read(), 12739441Smckusick spec_write(), 12839441Smckusick spec_strategy(), 12939441Smckusick spec_ioctl(), 13039441Smckusick spec_select(), 13139441Smckusick spec_close(), 13239441Smckusick spec_badop(), 13339441Smckusick spec_nullop(); 13438414Smckusick 13539441Smckusick struct vnodeops spec_nfsv2nodeops = { 13639441Smckusick spec_lookup, 13739441Smckusick spec_badop, 13839441Smckusick spec_badop, 13939441Smckusick spec_open, 14039441Smckusick spec_close, 14138414Smckusick nfs_access, 14238414Smckusick nfs_getattr, 14338414Smckusick nfs_setattr, 14439441Smckusick spec_read, 14539441Smckusick spec_write, 14639441Smckusick spec_ioctl, 14739441Smckusick spec_select, 14839441Smckusick spec_badop, 14939441Smckusick spec_nullop, 15039441Smckusick spec_badop, 15139441Smckusick spec_badop, 15239441Smckusick spec_badop, 15339441Smckusick spec_badop, 15439441Smckusick spec_badop, 15539441Smckusick spec_badop, 15639441Smckusick spec_badop, 15739441Smckusick spec_badop, 15839441Smckusick spec_badop, 15939441Smckusick spec_badop, 16038414Smckusick nfs_inactive, 16139394Smckusick nfs_reclaim, 16238414Smckusick nfs_lock, 16338414Smckusick nfs_unlock, 16439441Smckusick spec_badop, 16539441Smckusick spec_strategy, 16638414Smckusick }; 16738414Smckusick 16838414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 16938414Smckusick extern u_long nfs_prog, nfs_vers; 17038414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 17138884Smacklem struct map nfsmap[NFS_MSIZ]; 17238414Smckusick enum vtype v_type[NFLNK+1]; 17338884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 17439341Smckusick int nfs_asyncdaemons = 0; 17539341Smckusick struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 17638884Smacklem static int nfsmap_want = 0; 17738414Smckusick 17838414Smckusick /* 17938414Smckusick * nfs null call from vfs. 18038414Smckusick */ 18138414Smckusick nfs_null(vp, cred) 18238414Smckusick struct vnode *vp; 18338414Smckusick struct ucred *cred; 18438414Smckusick { 18539488Smckusick caddr_t bpos, dpos; 18639488Smckusick u_long xid; 18739488Smckusick int error = 0; 18839488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 18938414Smckusick 19038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0); 19138414Smckusick nfsm_request(vp); 19238414Smckusick nfsm_reqdone; 19338414Smckusick return (error); 19438414Smckusick } 19538414Smckusick 19638414Smckusick /* 19738414Smckusick * nfs access vnode op. 19838414Smckusick * Essentially just get vattr and then imitate iaccess() 19938414Smckusick */ 20038414Smckusick nfs_access(vp, mode, cred) 20138414Smckusick struct vnode *vp; 20238414Smckusick int mode; 20338414Smckusick register struct ucred *cred; 20438414Smckusick { 20538414Smckusick register struct vattr *vap; 20638414Smckusick register gid_t *gp; 20738414Smckusick struct vattr vattr; 20838414Smckusick register int i; 20938414Smckusick int error; 21038414Smckusick 21138414Smckusick /* 21238414Smckusick * If you're the super-user, 21338414Smckusick * you always get access. 21438414Smckusick */ 21538414Smckusick if (cred->cr_uid == 0) 21638414Smckusick return (0); 21738414Smckusick vap = &vattr; 21838884Smacklem if (error = nfs_getattr(vp, vap, cred)) 21938884Smacklem return (error); 22038414Smckusick /* 22138414Smckusick * Access check is based on only one of owner, group, public. 22238414Smckusick * If not owner, then check group. If not a member of the 22338414Smckusick * group, then check public access. 22438414Smckusick */ 22538414Smckusick if (cred->cr_uid != vap->va_uid) { 22638414Smckusick mode >>= 3; 22738414Smckusick gp = cred->cr_groups; 22838414Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 22938414Smckusick if (vap->va_gid == *gp) 23038414Smckusick goto found; 23138414Smckusick mode >>= 3; 23238414Smckusick found: 23338414Smckusick ; 23438414Smckusick } 23538414Smckusick if ((vap->va_mode & mode) != 0) 23638414Smckusick return (0); 23738414Smckusick return (EACCES); 23838414Smckusick } 23938414Smckusick 24038414Smckusick /* 24138414Smckusick * nfs open vnode op 24238414Smckusick * Just check to see if the type is ok 24338414Smckusick */ 24439488Smckusick /* ARGSUSED */ 24538414Smckusick nfs_open(vp, mode, cred) 24638414Smckusick struct vnode *vp; 24738414Smckusick int mode; 24838414Smckusick struct ucred *cred; 24938414Smckusick { 25038414Smckusick register enum vtype vtyp; 25138414Smckusick 25238414Smckusick vtyp = vp->v_type; 25338414Smckusick if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK) 25438414Smckusick return (0); 25538414Smckusick else 25638414Smckusick return (EACCES); 25738414Smckusick } 25838414Smckusick 25938414Smckusick /* 26038414Smckusick * nfs close vnode op 26138884Smacklem * For reg files, invalidate any buffer cache entries. 26238414Smckusick */ 26339488Smckusick /* ARGSUSED */ 26438414Smckusick nfs_close(vp, fflags, cred) 26538414Smckusick register struct vnode *vp; 26638414Smckusick int fflags; 26738414Smckusick struct ucred *cred; 26838414Smckusick { 26939488Smckusick register struct nfsnode *np = VTONFS(vp); 27039341Smckusick int error = 0; 27138414Smckusick 27239341Smckusick if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) || 27339341Smckusick ((np->n_flag & NBUFFERED) && np->n_sillyrename))) { 27439441Smckusick nfs_lock(vp); 27539341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 27639341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 27739341Smckusick if (np->n_flag & NWRITEERR) { 27839341Smckusick np->n_flag &= ~NWRITEERR; 27939341Smckusick if (!error) 28039341Smckusick error = np->n_error ? np->n_error : EIO; 28139341Smckusick } 28239441Smckusick nfs_unlock(vp); 28338884Smacklem } 28438414Smckusick return (error); 28538414Smckusick } 28638414Smckusick 28738414Smckusick /* 28838414Smckusick * nfs getattr call from vfs. 28938414Smckusick */ 29038414Smckusick nfs_getattr(vp, vap, cred) 29139488Smckusick register struct vnode *vp; 29239488Smckusick struct vattr *vap; 29338414Smckusick struct ucred *cred; 29438414Smckusick { 29539488Smckusick register caddr_t cp; 29639488Smckusick register long t1; 29739488Smckusick caddr_t bpos, dpos; 29839488Smckusick u_long xid; 29939488Smckusick int error = 0; 30039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 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) 31839488Smckusick register struct vnode *vp; 31938414Smckusick register struct vattr *vap; 32038414Smckusick struct ucred *cred; 32138414Smckusick { 32238884Smacklem register struct nfsv2_sattr *sp; 32339488Smckusick register caddr_t cp; 32439488Smckusick register long t1; 32539488Smckusick caddr_t bpos, dpos; 32639488Smckusick u_long xid; 32739488Smckusick int error = 0; 32839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 32939359Smckusick struct nfsnode *np; 33038414Smckusick 33138414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 33238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR); 33338414Smckusick nfsm_fhtom(vp); 33438884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 33538414Smckusick if (vap->va_mode == 0xffff) 33638884Smacklem sp->sa_mode = VNOVAL; 33738414Smckusick else 33838884Smacklem sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 33938414Smckusick if (vap->va_uid == 0xffff) 34038884Smacklem sp->sa_uid = VNOVAL; 34138414Smckusick else 34238884Smacklem sp->sa_uid = txdr_unsigned(vap->va_uid); 34338414Smckusick if (vap->va_gid == 0xffff) 34438884Smacklem sp->sa_gid = VNOVAL; 34538414Smckusick else 34638884Smacklem sp->sa_gid = txdr_unsigned(vap->va_gid); 34738884Smacklem sp->sa_size = txdr_unsigned(vap->va_size); 34839359Smckusick if (vap->va_size != VNOVAL) { 34939359Smckusick np = VTONFS(vp); 35039359Smckusick if (np->n_flag & NMODIFIED) { 35139359Smckusick np->n_flag &= ~NMODIFIED; 35239359Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 35339359Smckusick } 35439359Smckusick } 35538884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 35638884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 35738414Smckusick nfsm_request(vp); 35838414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 35938414Smckusick /* should we fill in any vap fields ?? */ 36038414Smckusick nfsm_reqdone; 36138414Smckusick return (error); 36238414Smckusick } 36338414Smckusick 36438414Smckusick /* 36538414Smckusick * nfs lookup call, one step at a time... 36638414Smckusick * First look in cache 36738414Smckusick * If not found, unlock the directory nfsnode and do the rpc 36838414Smckusick */ 36938414Smckusick nfs_lookup(vp, ndp) 37038414Smckusick register struct vnode *vp; 37138414Smckusick register struct nameidata *ndp; 37238414Smckusick { 37338414Smckusick register struct vnode *vdp; 37439488Smckusick register u_long *p; 37539488Smckusick register caddr_t cp; 37639488Smckusick register long t1, t2; 37739488Smckusick caddr_t bpos, dpos, cp2; 37839488Smckusick u_long xid; 37939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 38038414Smckusick struct vnode *newvp; 38138414Smckusick long len; 38238414Smckusick nfsv2fh_t *fhp; 38338414Smckusick struct nfsnode *np; 38439488Smckusick int lockparent, wantparent, flag, error = 0; 38538414Smckusick 38638414Smckusick ndp->ni_dvp = vp; 38738414Smckusick ndp->ni_vp = NULL; 38838414Smckusick if (vp->v_type != VDIR) 38938414Smckusick return (ENOTDIR); 39038414Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 39138414Smckusick flag = ndp->ni_nameiop & OPFLAG; 39238414Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 39339341Smckusick if ((error = cache_lookup(ndp)) && error != ENOENT) { 39438884Smacklem struct vattr vattr; 39538884Smacklem int vpid; 39638884Smacklem 39739441Smckusick if (vp == ndp->ni_rdir && ndp->ni_isdotdot) 39839441Smckusick panic("nfs_lookup: .. through root"); 39939441Smckusick vdp = ndp->ni_vp; 40038884Smacklem vpid = vdp->v_id; 40138414Smckusick /* 40238884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 40338884Smacklem * for an explanation of the locking protocol 40438414Smckusick */ 40538414Smckusick if (vp == vdp) { 40638425Smckusick VREF(vdp); 40739441Smckusick error = 0; 40838414Smckusick } else if (ndp->ni_isdotdot) { 40938414Smckusick nfs_unlock(vp); 41039441Smckusick error = vget(vdp); 41138414Smckusick } else { 41239441Smckusick error = vget(vdp); 41338414Smckusick nfs_unlock(vp); 41438414Smckusick } 41539441Smckusick if (!error) { 41639441Smckusick if (vpid == vdp->v_id && 41739441Smckusick !nfs_getattr(vdp, &vattr, ndp->ni_cred)) { 41839441Smckusick nfsstats.lookupcache_hits++; 41939441Smckusick return (0); 42039441Smckusick } else { 42139441Smckusick nfs_nput(vdp); 42239441Smckusick } 42338884Smacklem } 42438884Smacklem nfs_lock(vp); 42538884Smacklem ndp->ni_vp = (struct vnode *)0; 42638414Smckusick } 42739341Smckusick error = 0; 42838414Smckusick nfsstats.lookupcache_misses++; 42938414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 43038414Smckusick len = ndp->ni_namelen; 43138414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 43238414Smckusick nfsm_fhtom(vp); 43338414Smckusick nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN); 43438414Smckusick nfsm_request(vp); 43538414Smckusick nfsmout: 43638414Smckusick if (error) { 43738414Smckusick if ((flag == CREATE || flag == RENAME) && 43838414Smckusick *ndp->ni_next == 0) { 43938414Smckusick if (!lockparent) 44038414Smckusick nfs_unlock(vp); 44138414Smckusick } 44238414Smckusick return (ENOENT); 44338414Smckusick } 44438414Smckusick nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); 44538414Smckusick 44638414Smckusick /* 44738414Smckusick * Handle DELETE and RENAME cases... 44838414Smckusick */ 44938414Smckusick if (flag == DELETE && *ndp->ni_next == 0) { 45038414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 45138425Smckusick VREF(vp); 45238414Smckusick newvp = vp; 45338414Smckusick np = VTONFS(vp); 45438414Smckusick } else { 45538414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 45638414Smckusick m_freem(mrep); 45738414Smckusick return (error); 45838414Smckusick } 45938414Smckusick newvp = NFSTOV(np); 46038414Smckusick } 46139459Smckusick if (error = 46239459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 46338414Smckusick if (newvp != vp) 46438414Smckusick nfs_nput(newvp); 46538414Smckusick else 46638425Smckusick vrele(vp); 46738414Smckusick m_freem(mrep); 46838414Smckusick return (error); 46938414Smckusick } 47038414Smckusick ndp->ni_vp = newvp; 47138414Smckusick if (!lockparent) 47238414Smckusick nfs_unlock(vp); 47338414Smckusick m_freem(mrep); 47438414Smckusick return (0); 47538414Smckusick } 47638414Smckusick 47738414Smckusick if (flag == RENAME && wantparent && *ndp->ni_next == 0) { 47838414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 47938414Smckusick m_freem(mrep); 48038414Smckusick return (EISDIR); 48138414Smckusick } 48238414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 48338414Smckusick m_freem(mrep); 48438414Smckusick return (error); 48538414Smckusick } 48638414Smckusick newvp = NFSTOV(np); 48739459Smckusick if (error = 48839459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 48938425Smckusick nfs_nput(newvp); 49038414Smckusick m_freem(mrep); 49138414Smckusick return (error); 49238414Smckusick } 49338414Smckusick ndp->ni_vp = newvp; 49438414Smckusick if (!lockparent) 49538414Smckusick nfs_unlock(vp); 49638414Smckusick return (0); 49738414Smckusick } 49838414Smckusick 49938414Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 50038425Smckusick VREF(vp); 50138414Smckusick newvp = vp; 50238414Smckusick np = VTONFS(vp); 50338414Smckusick } else if (ndp->ni_isdotdot) { 50438414Smckusick nfs_unlock(vp); 50538414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 50638414Smckusick nfs_lock(vp); 50738414Smckusick m_freem(mrep); 50838414Smckusick return (error); 50938414Smckusick } 51038414Smckusick nfs_lock(vp); 51138414Smckusick newvp = NFSTOV(np); 51238414Smckusick } else { 51338414Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) { 51438414Smckusick m_freem(mrep); 51538414Smckusick return (error); 51638414Smckusick } 51738414Smckusick newvp = NFSTOV(np); 51838414Smckusick } 51939459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 52038414Smckusick if (newvp != vp) 52138414Smckusick nfs_nput(newvp); 52238414Smckusick else 52338425Smckusick vrele(vp); 52438414Smckusick m_freem(mrep); 52538414Smckusick return (error); 52638414Smckusick } 52738414Smckusick m_freem(mrep); 52838414Smckusick 52938414Smckusick if (vp != newvp && (!lockparent || *ndp->ni_next != '\0')) 53038414Smckusick nfs_unlock(vp); 53138414Smckusick ndp->ni_vp = newvp; 53238414Smckusick if (error == 0 && ndp->ni_makeentry) 53338414Smckusick cache_enter(ndp); 53438414Smckusick return (error); 53538414Smckusick } 53638414Smckusick 53738414Smckusick /* 53838414Smckusick * nfs readlink call 53938414Smckusick */ 54038414Smckusick nfs_readlink(vp, uiop, cred) 54139488Smckusick register struct vnode *vp; 54238414Smckusick struct uio *uiop; 54338414Smckusick struct ucred *cred; 54438414Smckusick { 54539488Smckusick register u_long *p; 54639488Smckusick register caddr_t cp; 54739488Smckusick register long t1; 54839488Smckusick caddr_t bpos, dpos, cp2; 54939488Smckusick u_long xid; 55039488Smckusick int error = 0; 55139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 55238414Smckusick long len; 55338414Smckusick 55438414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 55538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH); 55638414Smckusick nfsm_fhtom(vp); 55738414Smckusick nfsm_request(vp); 55838414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 55938414Smckusick nfsm_mtouio(uiop, len); 56038414Smckusick nfsm_reqdone; 56138414Smckusick return (error); 56238414Smckusick } 56338414Smckusick 56438414Smckusick /* 56538414Smckusick * nfs read call 56638414Smckusick */ 56738884Smacklem nfs_readrpc(vp, uiop, offp, cred) 56839488Smckusick register struct vnode *vp; 56938414Smckusick struct uio *uiop; 57038414Smckusick off_t *offp; 57138414Smckusick struct ucred *cred; 57238414Smckusick { 57339488Smckusick register u_long *p; 57439488Smckusick register caddr_t cp; 57539488Smckusick register long t1; 57639488Smckusick caddr_t bpos, dpos, cp2; 57739488Smckusick u_long xid; 57839488Smckusick int error = 0; 57939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 58038414Smckusick struct nfsmount *nmp; 58138414Smckusick long len, retlen, tsiz; 58238414Smckusick 58338414Smckusick nmp = vfs_to_nfs(vp->v_mount); 58438414Smckusick tsiz = uiop->uio_resid; 58538414Smckusick while (tsiz > 0) { 58638414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 58738414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 58838414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3); 58938414Smckusick nfsm_fhtom(vp); 59038414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*3); 59138414Smckusick *p++ = txdr_unsigned(*offp); 59238414Smckusick *p++ = txdr_unsigned(len); 59338414Smckusick *p = 0; 59438414Smckusick nfsm_request(vp); 59538414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 59638414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 59738414Smckusick nfsm_mtouio(uiop, retlen); 59838414Smckusick m_freem(mrep); 59938414Smckusick *offp += retlen; 60038414Smckusick if (retlen < len) 60138414Smckusick tsiz = 0; 60238414Smckusick else 60338414Smckusick tsiz -= len; 60438414Smckusick } 60538414Smckusick nfsmout: 60638414Smckusick return (error); 60738414Smckusick } 60838414Smckusick 60938414Smckusick /* 61038414Smckusick * nfs write call 61138414Smckusick */ 61238884Smacklem nfs_writerpc(vp, uiop, offp, cred) 61339488Smckusick register struct vnode *vp; 61438414Smckusick struct uio *uiop; 61538414Smckusick off_t *offp; 61638414Smckusick struct ucred *cred; 61738414Smckusick { 61839488Smckusick register u_long *p; 61939488Smckusick register caddr_t cp; 62039488Smckusick register long t1; 62139488Smckusick caddr_t bpos, dpos; 62239488Smckusick u_long xid; 62339488Smckusick int error = 0; 62439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 62538414Smckusick struct nfsmount *nmp; 62638414Smckusick long len, tsiz; 62738414Smckusick 62838414Smckusick nmp = vfs_to_nfs(vp->v_mount); 62938414Smckusick tsiz = uiop->uio_resid; 63038414Smckusick while (tsiz > 0) { 63138414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 63238414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 63338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred, 63438414Smckusick NFSX_FH+NFSX_UNSIGNED*4); 63538414Smckusick nfsm_fhtom(vp); 63638414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED*4); 63738414Smckusick *(p+1) = txdr_unsigned(*offp); 63838414Smckusick *(p+3) = txdr_unsigned(len); 63938414Smckusick nfsm_uiotom(uiop, len); 64038414Smckusick nfsm_request(vp); 64138414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 64238414Smckusick m_freem(mrep); 64338414Smckusick tsiz -= len; 64438414Smckusick *offp += len; 64538414Smckusick } 64638414Smckusick nfsmout: 64738414Smckusick return (error); 64838414Smckusick } 64938414Smckusick 65038414Smckusick /* 65139459Smckusick * nfs mknod call 65239459Smckusick * This call is currently not supported. 65339459Smckusick */ 65439459Smckusick /* ARGSUSED */ 65539459Smckusick nfs_mknod(ndp, vap, cred) 65639459Smckusick struct nameidata *ndp; 65739459Smckusick struct ucred *cred; 65839459Smckusick struct vattr *vap; 65939459Smckusick { 66039459Smckusick 66139459Smckusick nfs_abortop(ndp); 66239459Smckusick return (EOPNOTSUPP); 66339459Smckusick } 66439459Smckusick 66539459Smckusick /* 66638414Smckusick * nfs file create call 66738414Smckusick */ 66838414Smckusick nfs_create(ndp, vap) 66938414Smckusick register struct nameidata *ndp; 67038414Smckusick register struct vattr *vap; 67138414Smckusick { 67238884Smacklem register struct nfsv2_sattr *sp; 67339488Smckusick register u_long *p; 67439488Smckusick register caddr_t cp; 67539488Smckusick register long t1, t2; 67639488Smckusick caddr_t bpos, dpos, cp2; 67739488Smckusick u_long xid; 67839488Smckusick int error = 0; 67939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 68038414Smckusick 68138414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 68238414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred, 68338414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 68438414Smckusick nfsm_fhtom(ndp->ni_dvp); 68538414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 68638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 68738884Smacklem sp->sa_mode = vtonfs_mode(VREG, vap->va_mode); 68838884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 68938884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 69038884Smacklem sp->sa_size = txdr_unsigned(0); 69138414Smckusick /* or should these be VNOVAL ?? */ 69238884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); 69338884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); 69438414Smckusick nfsm_request(ndp->ni_dvp); 69538414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 69638414Smckusick nfsm_reqdone; 69738414Smckusick nfs_nput(ndp->ni_dvp); 69838414Smckusick return (error); 69938414Smckusick } 70038414Smckusick 70138414Smckusick /* 70238414Smckusick * nfs file remove call 70339341Smckusick * To try and make nfs semantics closer to vfs semantics, a file that has 70439341Smckusick * other references to the vnode is renamed instead of removed and then 70539341Smckusick * removed later on the last close. 70639341Smckusick * Unfortunately you must flush the buffer cache and cmap to get rid of 70739341Smckusick * all extraneous vnode references before you check the reference cnt. 70839341Smckusick * 1 - If the file could have blocks in the buffer cache 70939341Smckusick * flush them out and invalidate them 71039341Smckusick * mpurge the vnode to flush out cmap references 71139341Smckusick * (This is necessary to update the vnode ref cnt as well as sensible 71239341Smckusick * for actual removes, to free up the buffers) 71339341Smckusick * 2 - If v_count > 1 71439341Smckusick * If a rename is not already in the works 71539341Smckusick * call nfs_sillyrename() to set it up 71639341Smckusick * else 71739341Smckusick * do the remove rpc 71838414Smckusick */ 71938414Smckusick nfs_remove(ndp) 72038414Smckusick register struct nameidata *ndp; 72138414Smckusick { 72239341Smckusick register struct vnode *vp = ndp->ni_vp; 72339341Smckusick register struct nfsnode *np = VTONFS(ndp->ni_vp); 72439488Smckusick register u_long *p; 72539488Smckusick register caddr_t cp; 72639488Smckusick register long t1, t2; 72739488Smckusick caddr_t bpos, dpos; 72839488Smckusick u_long xid; 72939488Smckusick int error = 0; 73039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73138414Smckusick 73239341Smckusick if (vp->v_type == VREG) { 73339341Smckusick if (np->n_flag & (NMODIFIED|NBUFFERED)) { 73439341Smckusick np->n_flag &= ~(NMODIFIED|NBUFFERED); 73539341Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 73639341Smckusick } 73739341Smckusick if (np->n_flag & NPAGEDON) 73839341Smckusick mpurge(vp); /* In case cmap entries still ref it */ 73939341Smckusick } 74039341Smckusick if (vp->v_count > 1) { 74139341Smckusick if (!np->n_sillyrename) 74239341Smckusick error = nfs_sillyrename(ndp, REMOVE); 74339341Smckusick } else { 74438414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 74538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 74638414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 74738414Smckusick nfsm_fhtom(ndp->ni_dvp); 74838414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 74938414Smckusick nfsm_request(ndp->ni_dvp); 75038414Smckusick nfsm_reqdone; 75138414Smckusick } 75238414Smckusick if (ndp->ni_dvp == ndp->ni_vp) 75338425Smckusick vrele(ndp->ni_vp); 75438414Smckusick else 75538425Smckusick nfs_nput(ndp->ni_vp); 75638425Smckusick nfs_nput(ndp->ni_dvp); 75738414Smckusick return (error); 75838414Smckusick } 75938414Smckusick 76038414Smckusick /* 76138414Smckusick * nfs file remove rpc called from nfs_inactive 76238414Smckusick */ 76338414Smckusick nfs_removeit(ndp) 76438414Smckusick register struct nameidata *ndp; 76538414Smckusick { 76639488Smckusick register u_long *p; 76739488Smckusick register caddr_t cp; 76839488Smckusick register long t1, t2; 76939488Smckusick caddr_t bpos, dpos; 77039488Smckusick u_long xid; 77139488Smckusick int error = 0; 77239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 77338414Smckusick 77438414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 77538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred, 77638414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 77738414Smckusick nfsm_fhtom(ndp->ni_dvp); 77838414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 77938414Smckusick nfsm_request(ndp->ni_dvp); 78038414Smckusick nfsm_reqdone; 78138414Smckusick return (error); 78238414Smckusick } 78338414Smckusick 78438414Smckusick /* 78538414Smckusick * nfs file rename call 78638414Smckusick */ 78738414Smckusick nfs_rename(sndp, tndp) 78838414Smckusick register struct nameidata *sndp, *tndp; 78938414Smckusick { 79039488Smckusick register u_long *p; 79139488Smckusick register caddr_t cp; 79239488Smckusick register long t1, t2; 79339488Smckusick caddr_t bpos, dpos; 79439488Smckusick u_long xid; 79539488Smckusick int error = 0; 79639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 79738414Smckusick 79838414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 79938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 80038414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 80138414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 80238414Smckusick nfsm_fhtom(sndp->ni_dvp); 80338414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 80438414Smckusick nfsm_fhtom(tndp->ni_dvp); 80538414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 80638414Smckusick nfsm_request(sndp->ni_dvp); 80738414Smckusick nfsm_reqdone; 80838414Smckusick if (sndp->ni_vp->v_type == VDIR) { 80938414Smckusick if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR) 81038414Smckusick cache_purge(tndp->ni_dvp); 81138414Smckusick cache_purge(sndp->ni_dvp); 81238414Smckusick } 81338414Smckusick nfs_abortop(sndp); 81438414Smckusick nfs_abortop(tndp); 81538414Smckusick return (error); 81638414Smckusick } 81738414Smckusick 81838414Smckusick /* 81938414Smckusick * nfs file rename rpc called from above 82038414Smckusick */ 82138414Smckusick nfs_renameit(sndp, tndp) 82238414Smckusick register struct nameidata *sndp, *tndp; 82338414Smckusick { 82439488Smckusick register u_long *p; 82539488Smckusick register caddr_t cp; 82639488Smckusick register long t1, t2; 82739488Smckusick caddr_t bpos, dpos; 82839488Smckusick u_long xid; 82939488Smckusick int error = 0; 83039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 83138414Smckusick 83238414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 83338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred, 83438414Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+ 83538414Smckusick nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/ 83638414Smckusick nfsm_fhtom(sndp->ni_dvp); 83738414Smckusick nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 83838414Smckusick nfsm_fhtom(tndp->ni_dvp); 83938414Smckusick nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN); 84038414Smckusick nfsm_request(sndp->ni_dvp); 84138414Smckusick nfsm_reqdone; 84238414Smckusick return (error); 84338414Smckusick } 84438414Smckusick 84538414Smckusick /* 84638414Smckusick * nfs hard link create call 84738414Smckusick */ 84838414Smckusick nfs_link(vp, ndp) 84939488Smckusick register struct vnode *vp; 85038414Smckusick register struct nameidata *ndp; 85138414Smckusick { 85239488Smckusick register u_long *p; 85339488Smckusick register caddr_t cp; 85439488Smckusick register long t1, t2; 85539488Smckusick caddr_t bpos, dpos; 85639488Smckusick u_long xid; 85739488Smckusick int error = 0; 85839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 85938414Smckusick 86038425Smckusick if (ndp->ni_dvp != vp) 86138425Smckusick nfs_lock(vp); 86238414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 86338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred, 86438414Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 86538414Smckusick nfsm_fhtom(vp); 86638414Smckusick nfsm_fhtom(ndp->ni_dvp); 86738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 86838414Smckusick nfsm_request(vp); 86938414Smckusick nfsm_reqdone; 87038425Smckusick if (ndp->ni_dvp != vp) 87138425Smckusick nfs_unlock(vp); 87238414Smckusick nfs_nput(ndp->ni_dvp); 87338414Smckusick return (error); 87438414Smckusick } 87538414Smckusick 87638414Smckusick /* 87738414Smckusick * nfs symbolic link create call 87838414Smckusick */ 87938414Smckusick nfs_symlink(ndp, vap, nm) 88038414Smckusick struct nameidata *ndp; 88138414Smckusick struct vattr *vap; 88238414Smckusick char *nm; /* is this the path ?? */ 88338414Smckusick { 88438884Smacklem register struct nfsv2_sattr *sp; 88539488Smckusick register u_long *p; 88639488Smckusick register caddr_t cp; 88739488Smckusick register long t1, t2; 88839488Smckusick caddr_t bpos, dpos; 88939488Smckusick u_long xid; 89039488Smckusick int error = 0; 89139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 89238414Smckusick 89338414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 89438414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred, 89538414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED); 89638414Smckusick nfsm_fhtom(ndp->ni_dvp); 89738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 89838414Smckusick nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN); 89938884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 90038884Smacklem sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 90138884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 90238884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 90338884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 90438884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 90538884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 90638414Smckusick nfsm_request(ndp->ni_dvp); 90738414Smckusick nfsm_reqdone; 90838414Smckusick nfs_nput(ndp->ni_dvp); 90938414Smckusick return (error); 91038414Smckusick } 91138414Smckusick 91238414Smckusick /* 91338414Smckusick * nfs make dir call 91438414Smckusick */ 91538414Smckusick nfs_mkdir(ndp, vap) 91639488Smckusick register struct nameidata *ndp; 91738414Smckusick struct vattr *vap; 91838414Smckusick { 91938884Smacklem register struct nfsv2_sattr *sp; 92039488Smckusick register u_long *p; 92139488Smckusick register caddr_t cp; 92239488Smckusick register long t1, t2; 92339488Smckusick caddr_t bpos, dpos, cp2; 92439488Smckusick u_long xid; 92539488Smckusick int error = 0; 92639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92738414Smckusick 92838414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 92938414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred, 93038414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR); 93138414Smckusick nfsm_fhtom(ndp->ni_dvp); 93238414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 93338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 93438884Smacklem sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 93538884Smacklem sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid); 93638884Smacklem sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid); 93738884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 93838884Smacklem txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 93938884Smacklem txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 94038414Smckusick nfsm_request(ndp->ni_dvp); 94138414Smckusick nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp); 94238414Smckusick nfsm_reqdone; 94338414Smckusick nfs_nput(ndp->ni_dvp); 94438414Smckusick return (error); 94538414Smckusick } 94638414Smckusick 94738414Smckusick /* 94838414Smckusick * nfs remove directory call 94938414Smckusick */ 95038414Smckusick nfs_rmdir(ndp) 95138414Smckusick register struct nameidata *ndp; 95238414Smckusick { 95339488Smckusick register u_long *p; 95439488Smckusick register caddr_t cp; 95539488Smckusick register long t1, t2; 95639488Smckusick caddr_t bpos, dpos; 95739488Smckusick u_long xid; 95839488Smckusick int error = 0; 95939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 96038414Smckusick 96138414Smckusick if (ndp->ni_dvp == ndp->ni_vp) { 96238414Smckusick vrele(ndp->ni_dvp); 96338414Smckusick nfs_nput(ndp->ni_dvp); 96438414Smckusick return (EINVAL); 96538414Smckusick } 96638414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 96738414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred, 96838414Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)); 96938414Smckusick nfsm_fhtom(ndp->ni_dvp); 97038414Smckusick nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN); 97138414Smckusick nfsm_request(ndp->ni_dvp); 97238414Smckusick nfsm_reqdone; 97338884Smacklem cache_purge(ndp->ni_dvp); 97438884Smacklem cache_purge(ndp->ni_vp); 97538884Smacklem nfs_nput(ndp->ni_vp); 97638884Smacklem nfs_nput(ndp->ni_dvp); 97738414Smckusick return (error); 97838414Smckusick } 97938414Smckusick 98038414Smckusick /* 98138414Smckusick * nfs readdir call 98238414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 98338414Smckusick * order so that it looks more sensible. This appears consistent with the 98438414Smckusick * Ultrix implementation of NFS. 98538414Smckusick */ 98638414Smckusick nfs_readdir(vp, uiop, offp, cred) 98739488Smckusick register struct vnode *vp; 98838414Smckusick struct uio *uiop; 98938414Smckusick off_t *offp; 99038414Smckusick struct ucred *cred; 99138414Smckusick { 99238414Smckusick register long len; 99338414Smckusick register struct direct *dp; 99439488Smckusick register u_long *p; 99539488Smckusick register caddr_t cp; 99639488Smckusick register long t1; 99739488Smckusick caddr_t bpos, dpos, cp2; 99839488Smckusick u_long xid; 99939488Smckusick int error = 0; 100039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 100138414Smckusick struct mbuf *md2; 100238414Smckusick caddr_t dpos2; 100338414Smckusick int siz; 1004*39495Smckusick int more_dirs; 100538414Smckusick off_t off, savoff; 100638414Smckusick struct direct *savdp; 100738414Smckusick 100838414Smckusick nfs_lock(vp); 100938414Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 101038414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid); 101138414Smckusick nfsm_fhtom(vp); 101238414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 101338414Smckusick off = *offp; 101438414Smckusick *p++ = txdr_unsigned(off); 101538414Smckusick *p = txdr_unsigned(uiop->uio_resid); 101638414Smckusick nfsm_request(vp); 101738414Smckusick siz = 0; 101838414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 101938414Smckusick more_dirs = fxdr_unsigned(int, *p); 102038414Smckusick 102138414Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 102238414Smckusick dpos2 = dpos; 102338414Smckusick md2 = md; 102438414Smckusick 102538414Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 102639488Smckusick savoff = off = 0; 102739488Smckusick savdp = dp = NULL; 102838414Smckusick while (more_dirs && siz < uiop->uio_resid) { 102938414Smckusick savoff = off; /* Hold onto offset and dp */ 103038414Smckusick savdp = dp; 103138414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 103238414Smckusick dp = (struct direct *)p; 103338414Smckusick dp->d_ino = fxdr_unsigned(u_long, *p++); 103438414Smckusick len = fxdr_unsigned(int, *p); 103538414Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 103638414Smckusick error = EBADRPC; 103738414Smckusick m_freem(mrep); 103838414Smckusick goto nfsmout; 103938414Smckusick } 104038414Smckusick dp->d_namlen = (u_short)len; 104138414Smckusick len = nfsm_rndup(len); 104238414Smckusick nfsm_adv(len); 104338414Smckusick nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED); 104438414Smckusick off = fxdr_unsigned(off_t, *p); 104538414Smckusick *p++ = 0; /* Ensures null termination of name */ 104638414Smckusick more_dirs = fxdr_unsigned(int, *p); 104738414Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 104838414Smckusick siz += dp->d_reclen; 104938414Smckusick } 105038414Smckusick /* 105138414Smckusick * If at end of rpc data, get the eof boolean 105238414Smckusick */ 1053*39495Smckusick if (!more_dirs) 105438414Smckusick nfsm_disecton(p, u_long *, NFSX_UNSIGNED); 105538414Smckusick /* 105638414Smckusick * If there is too much to fit in the data buffer, use savoff and 105738414Smckusick * savdp to trim off the last record. 105838414Smckusick * --> we are not at eof 105938414Smckusick */ 106038414Smckusick if (siz > uiop->uio_resid) { 106138414Smckusick off = savoff; 106238414Smckusick siz -= dp->d_reclen; 106338414Smckusick dp = savdp; 106438414Smckusick } 106538414Smckusick if (siz > 0) { 106638414Smckusick md = md2; 106738414Smckusick dpos = dpos2; 106838414Smckusick nfsm_mtouio(uiop, siz); 106938414Smckusick *offp = off; 107038414Smckusick } 107138414Smckusick nfsm_reqdone; 107238414Smckusick nfs_unlock(vp); 107338414Smckusick return (error); 107438414Smckusick } 107538414Smckusick 107638414Smckusick /* 107738414Smckusick * nfs statfs call 107838414Smckusick * (Actually a vfsop, not a vnode op) 107938414Smckusick */ 108038414Smckusick nfs_statfs(mp, sbp) 108138414Smckusick struct mount *mp; 108238414Smckusick register struct statfs *sbp; 108338414Smckusick { 108439488Smckusick register struct vnode *vp; 108538884Smacklem register struct nfsv2_statfs *sfp; 108639488Smckusick register caddr_t cp; 108739488Smckusick register long t1; 108839488Smckusick caddr_t bpos, dpos, cp2; 108939488Smckusick u_long xid; 109039488Smckusick int error = 0; 109139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 109238884Smacklem struct nfsmount *nmp; 109338414Smckusick struct ucred *cred; 109438414Smckusick struct nfsnode *np; 109538414Smckusick 109638414Smckusick nmp = vfs_to_nfs(mp); 109738414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 109838414Smckusick return (error); 109938414Smckusick vp = NFSTOV(np); 110038414Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 110138414Smckusick cred = crget(); 110238414Smckusick cred->cr_ngroups = 1; 110338414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 110438414Smckusick nfsm_fhtom(vp); 110538414Smckusick nfsm_request(vp); 110638884Smacklem nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 110738414Smckusick sbp->f_type = MOUNT_NFS; 110838884Smacklem sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 110938884Smacklem sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 111038884Smacklem sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 111138884Smacklem sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 111238884Smacklem sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 111338739Smckusick sbp->f_files = 0; 111438739Smckusick sbp->f_ffree = 0; 111538414Smckusick bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN); 111638414Smckusick bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN); 111738414Smckusick nfsm_reqdone; 111838414Smckusick nfs_nput(vp); 111938414Smckusick crfree(cred); 112038414Smckusick return (error); 112138414Smckusick } 112238414Smckusick 112339488Smckusick static char hextoasc[] = "0123456789abcdef"; 112438414Smckusick 112538414Smckusick /* 112638414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 112738414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 112838414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 112938414Smckusick * nfsnode. There is the potential for another process on a different client 113038414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 113138414Smckusick * nfs_rename() completes, but... 113238414Smckusick */ 113338414Smckusick nfs_sillyrename(ndp, flag) 113439488Smckusick register struct nameidata *ndp; 113538414Smckusick int flag; 113638414Smckusick { 113738414Smckusick register struct nfsnode *np; 113838414Smckusick register struct sillyrename *sp; 113938414Smckusick register struct nameidata *tndp; 114038414Smckusick int error; 114138414Smckusick short pid; 114238414Smckusick 114338414Smckusick np = VTONFS(ndp->ni_dvp); 114439341Smckusick cache_purge(ndp->ni_dvp); 114538414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 114638884Smacklem M_TEMP, M_WAITOK); 114738414Smckusick sp->s_flag = flag; 114838414Smckusick bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH); 114938414Smckusick np = VTONFS(ndp->ni_vp); 115038414Smckusick tndp = &sp->s_namei; 115138414Smckusick tndp->ni_cred = crdup(ndp->ni_cred); 115238414Smckusick 115338414Smckusick /* Fudge together a funny name */ 115438414Smckusick pid = u.u_procp->p_pid; 115538414Smckusick bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13); 115638414Smckusick tndp->ni_dent.d_namlen = 12; 115739488Smckusick tndp->ni_dent.d_name[8] = hextoasc[pid & 0xf]; 115839488Smckusick tndp->ni_dent.d_name[7] = hextoasc[(pid >> 4) & 0xf]; 115939488Smckusick tndp->ni_dent.d_name[6] = hextoasc[(pid >> 8) & 0xf]; 116039488Smckusick tndp->ni_dent.d_name[5] = hextoasc[(pid >> 12) & 0xf]; 116138414Smckusick 116238414Smckusick /* Try lookitups until we get one that isn't there */ 116338414Smckusick while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) { 116438414Smckusick tndp->ni_dent.d_name[4]++; 116538414Smckusick if (tndp->ni_dent.d_name[4] > 'z') { 116638414Smckusick error = EINVAL; 116738414Smckusick goto bad; 116838414Smckusick } 116938414Smckusick } 117038414Smckusick if (error = nfs_renameit(ndp, tndp)) 117138414Smckusick goto bad; 117238414Smckusick nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh); 117338414Smckusick np->n_sillyrename = sp; 117438414Smckusick return (0); 117538414Smckusick bad: 117638884Smacklem crfree(tndp->ni_cred); 117738414Smckusick free((caddr_t)sp, M_TEMP); 117838414Smckusick return (error); 117938414Smckusick } 118038414Smckusick 118138414Smckusick /* 118238414Smckusick * Look up a file name for silly rename stuff. 118338414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 118438414Smckusick * into the nfsnode table. 118538414Smckusick * If fhp != NULL it copies the returned file handle out 118638414Smckusick */ 118738414Smckusick nfs_lookitup(vp, ndp, fhp) 118838414Smckusick register struct vnode *vp; 118938414Smckusick register struct nameidata *ndp; 119038414Smckusick nfsv2fh_t *fhp; 119138414Smckusick { 119239488Smckusick register u_long *p; 119339488Smckusick register caddr_t cp; 119439488Smckusick register long t1, t2; 119539488Smckusick caddr_t bpos, dpos, cp2; 119639488Smckusick u_long xid; 119739488Smckusick int error = 0; 119839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 119938414Smckusick long len; 120038414Smckusick 120138414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 120238414Smckusick ndp->ni_dvp = vp; 120338414Smckusick ndp->ni_vp = NULL; 120438414Smckusick len = ndp->ni_dent.d_namlen; 120538414Smckusick nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 120638414Smckusick nfsm_fhtom(vp); 120738414Smckusick nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN); 120838414Smckusick nfsm_request(vp); 120938414Smckusick if (fhp != NULL) { 121038414Smckusick nfsm_disect(cp, caddr_t, NFSX_FH); 121138414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 121238414Smckusick } 121338414Smckusick nfsm_reqdone; 121438414Smckusick return (error); 121538414Smckusick } 121638414Smckusick 121738414Smckusick /* 121838414Smckusick * Kludge City.. 121938414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 122038414Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit 122138414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 122238414Smckusick * nfsiobuf area. 122338414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 122438414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 122538414Smckusick * a lot more work than bcopy() and also it currently happens in the 122638414Smckusick * context of the swapper process (2). 122738414Smckusick */ 122838414Smckusick nfs_bmap(vp, bn, vpp, bnp) 122938414Smckusick struct vnode *vp; 123038414Smckusick daddr_t bn; 123138414Smckusick struct vnode **vpp; 123238414Smckusick daddr_t *bnp; 123338414Smckusick { 123438414Smckusick if (vpp != NULL) 123538414Smckusick *vpp = vp; 123638414Smckusick if (bnp != NULL) 123738414Smckusick *bnp = bn * btodb(vp->v_mount->m_bsize); 123838414Smckusick return (0); 123938414Smckusick } 124038414Smckusick 124138414Smckusick /* 124238884Smacklem * Strategy routine for phys. i/o 124338884Smacklem * If the biod's are running, queue a request 124438884Smacklem * otherwise just call nfs_doio() to get it done 124538414Smckusick */ 124638414Smckusick nfs_strategy(bp) 124738414Smckusick register struct buf *bp; 124838414Smckusick { 124938884Smacklem register struct buf *dp; 125039341Smckusick register int i; 125138884Smacklem struct proc *rp; 125238884Smacklem int error = 0; 125339341Smckusick int fnd = 0; 125438884Smacklem 125538884Smacklem /* 125638884Smacklem * If an i/o daemon is waiting 125738884Smacklem * queue the request, wake it up and wait for completion 125838884Smacklem * otherwise just do it ourselves 125938884Smacklem */ 126039341Smckusick for (i = 0; i < nfs_asyncdaemons; i++) { 126139341Smckusick if (rp = nfs_iodwant[i]) { 126239341Smckusick /* 126339341Smckusick * Ensure that the async_daemon is still waiting here 126439341Smckusick */ 126539341Smckusick if (rp->p_stat != SSLEEP || 126639341Smckusick rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) { 126739341Smckusick nfs_iodwant[i] = (struct proc *)0; 126839341Smckusick continue; 126939341Smckusick } 127039341Smckusick dp = &nfs_bqueue; 127139341Smckusick if (dp->b_actf == NULL) { 127239341Smckusick dp->b_actl = bp; 127339341Smckusick bp->b_actf = dp; 127439341Smckusick } else { 127539341Smckusick dp->b_actf->b_actl = bp; 127639341Smckusick bp->b_actf = dp->b_actf; 127739341Smckusick } 127839341Smckusick dp->b_actf = bp; 127939341Smckusick bp->b_actl = dp; 128039341Smckusick fnd++; 128139341Smckusick nfs_iodwant[i] = (struct proc *)0; 128239341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 128339341Smckusick break; 128438884Smacklem } 128539341Smckusick } 128639341Smckusick if (!fnd) 128738884Smacklem error = nfs_doio(bp); 128838884Smacklem return (error); 128938884Smacklem } 129038884Smacklem 129138884Smacklem /* 129238884Smacklem * Fun and games with i/o 129338884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 129438884Smacklem * mapping the data buffer into kernel virtual space and doing the 129538884Smacklem * nfs read or write rpc's from it. 129638884Smacklem * If the biod's are not running, this is just called from nfs_strategy(), 129738884Smacklem * otherwise it is called by the biod's to do what would normally be 129838884Smacklem * partially disk interrupt driven. 129938884Smacklem */ 130038884Smacklem nfs_doio(bp) 130138884Smacklem register struct buf *bp; 130238884Smacklem { 130338414Smckusick register struct pte *pte, *ppte; 130438414Smckusick register caddr_t vaddr; 130538414Smckusick register struct uio *uiop; 130638414Smckusick register struct vnode *vp; 130739341Smckusick struct nfsnode *np; 130838884Smacklem struct ucred *cr; 130938884Smacklem int npf, npf2; 131038884Smacklem int reg; 131138884Smacklem caddr_t vbase; 131238884Smacklem caddr_t addr; 131338414Smckusick unsigned v; 131438414Smckusick struct proc *rp; 131538414Smckusick int o, error; 131638884Smacklem int bcnt; 131738414Smckusick off_t off; 131838414Smckusick struct uio uio; 131938414Smckusick struct iovec io; 132038414Smckusick 132138414Smckusick vp = bp->b_vp; 132238414Smckusick uiop = &uio; 132338414Smckusick uiop->uio_iov = &io; 132438414Smckusick uiop->uio_iovcnt = 1; 132538414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 132638884Smacklem if (bp->b_flags & B_READ) { 132738884Smacklem io.iov_len = uiop->uio_resid = bp->b_bcount; 132838884Smacklem uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE; 132938884Smacklem addr = bp->b_un.b_addr; 133038884Smacklem bcnt = bp->b_bcount; 133138884Smacklem } else { 133238884Smacklem io.iov_len = uiop->uio_resid = bp->b_dirtyend-bp->b_dirtyoff; 133338884Smacklem uiop->uio_offset = off = (bp->b_blkno*DEV_BSIZE)+bp->b_dirtyoff; 133438884Smacklem addr = bp->b_un.b_addr+bp->b_dirtyoff; 133538884Smacklem bcnt = bp->b_dirtyend-bp->b_dirtyoff; 133638414Smckusick } 133738414Smckusick /* 133838884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 133938884Smacklem * the Nfsiomap pte's 134038884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 134138884Smacklem * and a guess at a group 134238414Smckusick */ 134338884Smacklem if (bp->b_flags & B_PHYS) { 134439341Smckusick VTONFS(vp)->n_flag |= NPAGEDON; 134538884Smacklem bp->b_rcred = cr = crget(); 134638884Smacklem rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc; 134738884Smacklem cr->cr_uid = rp->p_uid; 134838884Smacklem cr->cr_gid = 0; /* Anything ?? */ 134938884Smacklem cr->cr_ngroups = 1; 135038884Smacklem o = (int)addr & PGOFSET; 135138884Smacklem npf2 = npf = btoc(bcnt + o); 135238884Smacklem /* 135338884Smacklem * Get some mapping page table entries 135438884Smacklem */ 135538884Smacklem while ((reg = rmalloc(nfsmap, (long)npf)) == 0) { 135638884Smacklem nfsmap_want++; 135738884Smacklem sleep((caddr_t)&nfsmap_want, PZERO-1); 135838884Smacklem } 135938884Smacklem reg--; 136038884Smacklem /* I know it is always the else, but that may change someday */ 136138884Smacklem if ((bp->b_flags & B_PHYS) == 0) 136238884Smacklem pte = kvtopte(bp->b_un.b_addr); 136338884Smacklem else if (bp->b_flags & B_PAGET) 136438884Smacklem pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 136538884Smacklem else { 136638884Smacklem v = btop(bp->b_un.b_addr); 136738884Smacklem if (bp->b_flags & B_UAREA) 136838884Smacklem pte = &rp->p_addr[v]; 136938884Smacklem else 137038884Smacklem pte = vtopte(rp, v); 137138884Smacklem } 137238884Smacklem /* 137338884Smacklem * Play vmaccess() but with the Nfsiomap page table 137438884Smacklem */ 137538884Smacklem ppte = &Nfsiomap[reg]; 137638884Smacklem vbase = vaddr = &nfsiobuf[reg*NBPG]; 137738884Smacklem while (npf != 0) { 137838884Smacklem mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW)); 137938414Smckusick #if defined(tahoe) 138038884Smacklem mtpr(P1DC, vaddr); 138138414Smckusick #endif 138238884Smacklem ppte++; 138338884Smacklem pte++; 138438884Smacklem vaddr += NBPG; 138538884Smacklem --npf; 138638884Smacklem } 138738884Smacklem io.iov_base = vbase+o; 138838884Smacklem } else { 138938884Smacklem io.iov_base = addr; 139038414Smckusick } 139138414Smckusick if (bp->b_flags & B_READ) { 139238414Smckusick uiop->uio_rw = UIO_READ; 139338884Smacklem bp->b_error = error = nfs_readrpc(vp, uiop, &off, bp->b_rcred); 139438414Smckusick } else { 139538414Smckusick uiop->uio_rw = UIO_WRITE; 139638884Smacklem bp->b_error = error = nfs_writerpc(vp, uiop, &off, bp->b_wcred); 139739341Smckusick if (error) { 139839341Smckusick np = VTONFS(vp); 139939341Smckusick np->n_error = error; 140039341Smckusick np->n_flag |= NWRITEERR; 140139341Smckusick } 140238884Smacklem bp->b_dirtyoff = bp->b_dirtyend = 0; 140338414Smckusick } 140438884Smacklem if (error) 140538884Smacklem bp->b_flags |= B_ERROR; 140638414Smckusick bp->b_resid = uiop->uio_resid; 140738884Smacklem /* 140838884Smacklem * Release pte's used by physical i/o 140938884Smacklem */ 141038884Smacklem if (bp->b_flags & B_PHYS) { 141138884Smacklem crfree(cr); 141238884Smacklem rmfree(nfsmap, (long)npf2, (long)++reg); 141338884Smacklem if (nfsmap_want) { 141438884Smacklem nfsmap_want = 0; 141538884Smacklem wakeup((caddr_t)&nfsmap_want); 141638884Smacklem } 141738884Smacklem } 141838414Smckusick biodone(bp); 141938414Smckusick return (error); 142038414Smckusick } 142138884Smacklem 142238884Smacklem /* 142338884Smacklem * Flush all the blocks associated with a vnode. 142438884Smacklem * Walk through the buffer pool and push any dirty pages 142538884Smacklem * associated with the vnode. 142638884Smacklem */ 142739488Smckusick /* ARGSUSED */ 142838884Smacklem nfs_fsync(vp, fflags, cred) 142938884Smacklem register struct vnode *vp; 143038884Smacklem int fflags; 143138884Smacklem struct ucred *cred; 143238884Smacklem { 143338884Smacklem register struct nfsnode *np = VTONFS(vp); 143438884Smacklem int error; 143538884Smacklem 143638884Smacklem nfs_lock(vp); 143738884Smacklem if (np->n_flag & NMODIFIED) { 143838884Smacklem np->n_flag &= ~NMODIFIED; 143939341Smckusick error = nfs_blkflush(vp, (daddr_t)0, np->n_size, FALSE); 144038884Smacklem } 144138884Smacklem nfs_unlock(vp); 144238884Smacklem return (error); 144338884Smacklem } 1444