138414Smckusick /* 238414Smckusick * Copyright (c) 1989 The Regents of the University of California. 338414Smckusick * All rights reserved. 438414Smckusick * 538414Smckusick * This code is derived from software contributed to Berkeley by 638414Smckusick * Rick Macklem at The University of Guelph. 738414Smckusick * 844514Sbostic * %sccs.include.redist.c% 938414Smckusick * 10*55184Smckusick * @(#)nfs_vnops.c 7.89 (Berkeley) 07/13/92 1138414Smckusick */ 1238414Smckusick 1338414Smckusick /* 1438414Smckusick * vnode op calls for sun nfs version 2 1538414Smckusick */ 1638414Smckusick 1753322Smckusick #include <sys/param.h> 1853322Smckusick #include <sys/proc.h> 1953322Smckusick #include <sys/kernel.h> 2053322Smckusick #include <sys/systm.h> 2153322Smckusick #include <sys/mount.h> 2253322Smckusick #include <sys/buf.h> 2353322Smckusick #include <sys/malloc.h> 2453322Smckusick #include <sys/mbuf.h> 2553322Smckusick #include <sys/conf.h> 2653322Smckusick #include <sys/namei.h> 2753322Smckusick #include <sys/vnode.h> 2853322Smckusick #include <sys/map.h> 2954740Smckusick #include <sys/dirent.h> 3047573Skarels 3153322Smckusick #include <vm/vm.h> 3238414Smckusick 3355041Smckusick #include <miscfs/specfs/specdev.h> 3455041Smckusick #include <miscfs/fifofs/fifo.h> 3555041Smckusick 3653322Smckusick #include <nfs/rpcv2.h> 3753322Smckusick #include <nfs/nfsv2.h> 3853322Smckusick #include <nfs/nfs.h> 3953322Smckusick #include <nfs/nfsnode.h> 4053322Smckusick #include <nfs/nfsmount.h> 4153322Smckusick #include <nfs/xdr_subs.h> 4253322Smckusick #include <nfs/nfsm_subs.h> 4353322Smckusick #include <nfs/nqnfs.h> 4453322Smckusick 4538414Smckusick /* Defs */ 4638414Smckusick #define TRUE 1 4738414Smckusick #define FALSE 0 4838414Smckusick 4948054Smckusick /* 5048054Smckusick * Global vfs data structures for nfs 5148054Smckusick */ 5253554Sheideman int (**nfsv2_vnodeop_p)(); 5353554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 5453554Sheideman { &vop_default_desc, vn_default_error }, 5553806Smckusick { &vop_lookup_desc, nfs_lookup }, /* lookup */ 5653806Smckusick { &vop_create_desc, nfs_create }, /* create */ 5753554Sheideman { &vop_mknod_desc, nfs_mknod }, /* mknod */ 5853554Sheideman { &vop_open_desc, nfs_open }, /* open */ 5953554Sheideman { &vop_close_desc, nfs_close }, /* close */ 6053806Smckusick { &vop_access_desc, nfs_access }, /* access */ 6153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 6253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 6353554Sheideman { &vop_read_desc, nfs_read }, /* read */ 6453554Sheideman { &vop_write_desc, nfs_write }, /* write */ 6553554Sheideman { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ 6653806Smckusick { &vop_select_desc, nfs_select }, /* select */ 6753554Sheideman { &vop_mmap_desc, nfs_mmap }, /* mmap */ 6853554Sheideman { &vop_fsync_desc, nfs_fsync }, /* fsync */ 6953554Sheideman { &vop_seek_desc, nfs_seek }, /* seek */ 7053806Smckusick { &vop_remove_desc, nfs_remove }, /* remove */ 7153554Sheideman { &vop_link_desc, nfs_link }, /* link */ 7253806Smckusick { &vop_rename_desc, nfs_rename }, /* rename */ 7353554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 7453554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 7553806Smckusick { &vop_symlink_desc, nfs_symlink }, /* symlink */ 7653806Smckusick { &vop_readdir_desc, nfs_readdir }, /* readdir */ 7753806Smckusick { &vop_readlink_desc, nfs_readlink }, /* readlink */ 7853806Smckusick { &vop_abortop_desc, nfs_abortop }, /* abortop */ 7953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 8053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 8153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 8253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 8353554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */ 8453806Smckusick { &vop_strategy_desc, nfs_strategy }, /* strategy */ 8553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 8653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 8753806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8853806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 8953806Smckusick { &vop_valloc_desc, nfs_valloc }, /* valloc */ 9053554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */ 9153806Smckusick { &vop_truncate_desc, nfs_truncate }, /* truncate */ 9253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 9353582Sheideman { &vop_bwrite_desc, vn_bwrite }, 9453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 9538414Smckusick }; 9653554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 9753554Sheideman { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 9838414Smckusick 9948054Smckusick /* 10048054Smckusick * Special device vnode ops 10148054Smckusick */ 10253554Sheideman int (**spec_nfsv2nodeop_p)(); 10353554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 10453554Sheideman { &vop_default_desc, vn_default_error }, 10553806Smckusick { &vop_lookup_desc, spec_lookup }, /* lookup */ 10653806Smckusick { &vop_create_desc, spec_create }, /* create */ 10753806Smckusick { &vop_mknod_desc, spec_mknod }, /* mknod */ 10853554Sheideman { &vop_open_desc, spec_open }, /* open */ 10953806Smckusick { &vop_close_desc, nfsspec_close }, /* close */ 11053806Smckusick { &vop_access_desc, nfs_access }, /* access */ 11153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 11253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 11353806Smckusick { &vop_read_desc, nfsspec_read }, /* read */ 11453806Smckusick { &vop_write_desc, nfsspec_write }, /* write */ 11553806Smckusick { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 11653806Smckusick { &vop_select_desc, spec_select }, /* select */ 11753554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 11854451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 11953554Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 12053806Smckusick { &vop_remove_desc, spec_remove }, /* remove */ 12153554Sheideman { &vop_link_desc, spec_link }, /* link */ 12253806Smckusick { &vop_rename_desc, spec_rename }, /* rename */ 12353806Smckusick { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 12453806Smckusick { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 12553806Smckusick { &vop_symlink_desc, spec_symlink }, /* symlink */ 12653806Smckusick { &vop_readdir_desc, spec_readdir }, /* readdir */ 12753806Smckusick { &vop_readlink_desc, spec_readlink }, /* readlink */ 12853806Smckusick { &vop_abortop_desc, spec_abortop }, /* abortop */ 12953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 13053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 13153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 13253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 13353554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 13453806Smckusick { &vop_strategy_desc, spec_strategy }, /* strategy */ 13553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 13653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 13753806Smckusick { &vop_advlock_desc, spec_advlock }, /* advlock */ 13853806Smckusick { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 13953806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */ 14053806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */ 14153806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */ 14253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 14353582Sheideman { &vop_bwrite_desc, vn_bwrite }, 14453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 14538414Smckusick }; 14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 14753554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 14838414Smckusick 14940294Smckusick #ifdef FIFO 15053554Sheideman int (**fifo_nfsv2nodeop_p)(); 15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 15253554Sheideman { &vop_default_desc, vn_default_error }, 15353806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15453806Smckusick { &vop_create_desc, fifo_create }, /* create */ 15553806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15653554Sheideman { &vop_open_desc, fifo_open }, /* open */ 15753806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 15853806Smckusick { &vop_access_desc, nfs_access }, /* access */ 15953806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 16053806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 16153806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 16253806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16353806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16453806Smckusick { &vop_select_desc, fifo_select }, /* select */ 16553554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16654451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 16753554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 16853806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */ 16953554Sheideman { &vop_link_desc, fifo_link }, /* link */ 17053806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */ 17153806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17253806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17353806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17453806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17553806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17653806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17753806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 17853806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 17953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 18053806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18153554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18253806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */ 18353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18453806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 18553806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18653806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 18753806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */ 18853806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */ 18953806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */ 19053806Smckusick { &vop_update_desc, nfs_update }, /* update */ 19153582Sheideman { &vop_bwrite_desc, vn_bwrite }, 19253554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 19340294Smckusick }; 19453554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 19553554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 19640294Smckusick #endif /* FIFO */ 19740294Smckusick 19848054Smckusick /* 19952196Smckusick * Global variables 20048054Smckusick */ 20138414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 20238414Smckusick extern u_long nfs_prog, nfs_vers; 20338414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20438884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 20541905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 20646988Smckusick int nfs_numasync = 0; 20754740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 20838414Smckusick 20938414Smckusick /* 21038414Smckusick * nfs null call from vfs. 21138414Smckusick */ 21252234Sheideman int 21352196Smckusick nfs_null(vp, cred, procp) 21438414Smckusick struct vnode *vp; 21538414Smckusick struct ucred *cred; 21652196Smckusick struct proc *procp; 21738414Smckusick { 21839488Smckusick caddr_t bpos, dpos; 21939488Smckusick int error = 0; 22039488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22138414Smckusick 22252196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22352196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 22438414Smckusick nfsm_reqdone; 22538414Smckusick return (error); 22638414Smckusick } 22738414Smckusick 22838414Smckusick /* 22938414Smckusick * nfs access vnode op. 23038414Smckusick * Essentially just get vattr and then imitate iaccess() 23138414Smckusick */ 23252234Sheideman int 23353806Smckusick nfs_access(ap) 23454668Smckusick struct vop_access_args /* { 23554668Smckusick struct vnode *a_vp; 23654668Smckusick int a_mode; 23754668Smckusick struct ucred *a_cred; 23854668Smckusick struct proc *a_p; 23954668Smckusick } */ *ap; 24038414Smckusick { 24138414Smckusick register struct vattr *vap; 24238414Smckusick register gid_t *gp; 24353806Smckusick register struct ucred *cred = ap->a_cred; 24453806Smckusick mode_t mode = ap->a_mode; 24538414Smckusick struct vattr vattr; 24638414Smckusick register int i; 24738414Smckusick int error; 24838414Smckusick 24938414Smckusick /* 25038414Smckusick * If you're the super-user, 25138414Smckusick * you always get access. 25238414Smckusick */ 25353806Smckusick if (cred->cr_uid == 0) 25438414Smckusick return (0); 25538414Smckusick vap = &vattr; 25653806Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 25738884Smacklem return (error); 25838414Smckusick /* 25938414Smckusick * Access check is based on only one of owner, group, public. 26038414Smckusick * If not owner, then check group. If not a member of the 26138414Smckusick * group, then check public access. 26238414Smckusick */ 26353806Smckusick if (cred->cr_uid != vap->va_uid) { 26453806Smckusick mode >>= 3; 26553806Smckusick gp = cred->cr_groups; 26653806Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 26738414Smckusick if (vap->va_gid == *gp) 26838414Smckusick goto found; 26953806Smckusick mode >>= 3; 27038414Smckusick found: 27138414Smckusick ; 27238414Smckusick } 27353806Smckusick if ((vap->va_mode & mode) != 0) 27438414Smckusick return (0); 27538414Smckusick return (EACCES); 27638414Smckusick } 27738414Smckusick 27838414Smckusick /* 27938414Smckusick * nfs open vnode op 28038414Smckusick * Just check to see if the type is ok 28152196Smckusick * and that deletion is not in progress. 28238414Smckusick */ 28339488Smckusick /* ARGSUSED */ 28452234Sheideman int 28553806Smckusick nfs_open(ap) 28654668Smckusick struct vop_open_args /* { 28754668Smckusick struct vnode *a_vp; 28854668Smckusick int a_mode; 28954668Smckusick struct ucred *a_cred; 29054668Smckusick struct proc *a_p; 29154668Smckusick } */ *ap; 29238414Smckusick { 29353806Smckusick register struct vnode *vp = ap->a_vp; 29438414Smckusick 29553806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 29638414Smckusick return (EACCES); 29753806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 29853806Smckusick VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */ 29952196Smckusick return (0); 30038414Smckusick } 30138414Smckusick 30238414Smckusick /* 30338414Smckusick * nfs close vnode op 30438884Smacklem * For reg files, invalidate any buffer cache entries. 30538414Smckusick */ 30639488Smckusick /* ARGSUSED */ 30752234Sheideman int 30853806Smckusick nfs_close(ap) 30954451Smckusick struct vop_close_args /* { 31054451Smckusick struct vnodeop_desc *a_desc; 31154451Smckusick struct vnode *a_vp; 31254451Smckusick int a_fflag; 31354451Smckusick struct ucred *a_cred; 31454451Smckusick struct proc *a_p; 31554451Smckusick } */ *ap; 31638414Smckusick { 31753806Smckusick register struct vnode *vp = ap->a_vp; 31853806Smckusick register struct nfsnode *np = VTONFS(vp); 31939341Smckusick int error = 0; 32038414Smckusick 32153806Smckusick if (vp->v_type == VREG) { 32253806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 32353629Smckusick (np->n_flag & NMODIFIED)) { 32454451Smckusick error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 32541905Smckusick np->n_flag &= ~NMODIFIED; 32641905Smckusick np->n_attrstamp = 0; 32753629Smckusick } 32853629Smckusick if (np->n_flag & NWRITEERR) { 32953629Smckusick np->n_flag &= ~NWRITEERR; 33053629Smckusick error = np->n_error; 33153629Smckusick } 33238884Smacklem } 33338414Smckusick return (error); 33438414Smckusick } 33538414Smckusick 33638414Smckusick /* 33738414Smckusick * nfs getattr call from vfs. 33838414Smckusick */ 33952234Sheideman int 34053805Smckusick nfs_getattr(ap) 34154668Smckusick struct vop_getattr_args /* { 34254668Smckusick struct vnode *a_vp; 34354668Smckusick struct vattr *a_vap; 34454668Smckusick struct ucred *a_cred; 34554668Smckusick struct proc *a_p; 34654668Smckusick } */ *ap; 34738414Smckusick { 34853805Smckusick register struct vnode *vp = ap->a_vp; 34953805Smckusick register struct nfsnode *np = VTONFS(vp); 35039488Smckusick register caddr_t cp; 35139488Smckusick caddr_t bpos, dpos; 35239488Smckusick int error = 0; 35339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 35438414Smckusick 35553805Smckusick /* 35653805Smckusick * Update local times for special files. 35753805Smckusick */ 35853805Smckusick if (np->n_flag & (NACC | NUPD)) { 35953805Smckusick if (np->n_flag & NACC) 36053805Smckusick np->n_atim = time; 36153805Smckusick if (np->n_flag & NUPD) 36253805Smckusick np->n_mtim = time; 36353805Smckusick np->n_flag |= NCHG; 36453805Smckusick } 36553805Smckusick /* 36653805Smckusick * First look in the cache. 36753805Smckusick */ 36853805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 36938414Smckusick return (0); 37038414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 37153805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 37253805Smckusick nfsm_fhtom(vp); 37353805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 37453805Smckusick nfsm_loadattr(vp, ap->a_vap); 37538414Smckusick nfsm_reqdone; 37638414Smckusick return (error); 37738414Smckusick } 37838414Smckusick 37938414Smckusick /* 38038414Smckusick * nfs setattr call. 38138414Smckusick */ 38252234Sheideman int 38353806Smckusick nfs_setattr(ap) 38454451Smckusick struct vop_setattr_args /* { 38554451Smckusick struct vnodeop_desc *a_desc; 38654451Smckusick struct vnode *a_vp; 38754451Smckusick struct vattr *a_vap; 38854451Smckusick struct ucred *a_cred; 38954451Smckusick struct proc *a_p; 39054451Smckusick } */ *ap; 39138414Smckusick { 39238884Smacklem register struct nfsv2_sattr *sp; 39339488Smckusick register caddr_t cp; 39439488Smckusick register long t1; 39552196Smckusick caddr_t bpos, dpos, cp2; 39652196Smckusick u_long *tl; 39739488Smckusick int error = 0; 39839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 39953806Smckusick register struct vnode *vp = ap->a_vp; 40053806Smckusick register struct nfsnode *np = VTONFS(vp); 40153806Smckusick register struct vattr *vap = ap->a_vap; 40252196Smckusick u_quad_t frev; 40338414Smckusick 40438414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 40553806Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR); 40653806Smckusick nfsm_fhtom(vp); 40738884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 40853806Smckusick if (vap->va_mode == 0xffff) 40938884Smacklem sp->sa_mode = VNOVAL; 41038414Smckusick else 41153806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 41253806Smckusick if (vap->va_uid == 0xffff) 41338884Smacklem sp->sa_uid = VNOVAL; 41438414Smckusick else 41553806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 41653806Smckusick if (vap->va_gid == 0xffff) 41738884Smacklem sp->sa_gid = VNOVAL; 41838414Smckusick else 41953806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 42053806Smckusick sp->sa_size = txdr_unsigned(vap->va_size); 42154106Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.ts_sec); 42253806Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 42353806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 42454106Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || 42554106Smckusick vap->va_atime.ts_sec != VNOVAL) { 42639359Smckusick if (np->n_flag & NMODIFIED) { 42753806Smckusick if (vap->va_size == 0) 42854451Smckusick error = 42954451Smckusick vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p); 43046988Smckusick else 43154451Smckusick error = 43254451Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 43354451Smckusick np->n_flag &= ~NMODIFIED; 43439359Smckusick } 43539359Smckusick } 43653806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 43753806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 43853806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 43953806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 44052196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 44152196Smckusick fxdr_hyper(tl, &frev); 44254451Smckusick if (frev > np->n_brev) 44352196Smckusick np->n_brev = frev; 44452196Smckusick } 44538414Smckusick nfsm_reqdone; 44638414Smckusick return (error); 44738414Smckusick } 44838414Smckusick 44938414Smckusick /* 45038414Smckusick * nfs lookup call, one step at a time... 45138414Smckusick * First look in cache 45238414Smckusick * If not found, unlock the directory nfsnode and do the rpc 45338414Smckusick */ 45452234Sheideman int 45553806Smckusick nfs_lookup(ap) 45654451Smckusick struct vop_lookup_args /* { 45754451Smckusick struct vnodeop_desc *a_desc; 45854451Smckusick struct vnode *a_dvp; 45954451Smckusick struct vnode **a_vpp; 46054451Smckusick struct componentname *a_cnp; 46154451Smckusick } */ *ap; 46238414Smckusick { 46353806Smckusick register struct componentname *cnp = ap->a_cnp; 46453806Smckusick register struct vnode *dvp = ap->a_dvp; 46554668Smckusick register struct vnode **vpp = ap->a_vpp; 466*55184Smckusick register int flags = cnp->cn_flags; 46738414Smckusick register struct vnode *vdp; 46848054Smckusick register u_long *tl; 46939488Smckusick register caddr_t cp; 47039488Smckusick register long t1, t2; 47152196Smckusick struct nfsmount *nmp; 47252196Smckusick struct nfsnode *tp; 47339488Smckusick caddr_t bpos, dpos, cp2; 47452196Smckusick time_t reqtime; 47539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 47638414Smckusick struct vnode *newvp; 47738414Smckusick long len; 47838414Smckusick nfsv2fh_t *fhp; 47938414Smckusick struct nfsnode *np; 48052234Sheideman int lockparent, wantparent, error = 0; 48152196Smckusick int nqlflag, cachable; 48252196Smckusick u_quad_t frev; 48338414Smckusick 48454668Smckusick *vpp = NULL; 48553806Smckusick if (dvp->v_type != VDIR) 48638414Smckusick return (ENOTDIR); 487*55184Smckusick lockparent = flags & LOCKPARENT; 488*55184Smckusick wantparent = flags & (LOCKPARENT|WANTPARENT); 48953806Smckusick nmp = VFSTONFS(dvp->v_mount); 49053806Smckusick np = VTONFS(dvp); 49154668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 49238884Smacklem struct vattr vattr; 49338884Smacklem int vpid; 49438884Smacklem 49554668Smckusick vdp = *vpp; 49638884Smacklem vpid = vdp->v_id; 49738414Smckusick /* 49838884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 49938884Smacklem * for an explanation of the locking protocol 50038414Smckusick */ 50153806Smckusick if (dvp == vdp) { 50238425Smckusick VREF(vdp); 50339441Smckusick error = 0; 50452196Smckusick } else 50539441Smckusick error = vget(vdp); 50639441Smckusick if (!error) { 50740251Smckusick if (vpid == vdp->v_id) { 50852196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 50953806Smckusick if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 51054451Smckusick if (np->n_lrev != np->n_brev || 51152196Smckusick (np->n_flag & NMODIFIED)) { 51252196Smckusick np->n_direofoffset = 0; 51353806Smckusick cache_purge(dvp); 51454451Smckusick error = vinvalbuf(dvp, FALSE, 51554451Smckusick cnp->cn_cred, cnp->cn_proc); 51652196Smckusick np->n_flag &= ~NMODIFIED; 51752196Smckusick np->n_brev = np->n_lrev; 51852196Smckusick } else { 51952196Smckusick nfsstats.lookupcache_hits++; 52053806Smckusick if (cnp->cn_nameiop != LOOKUP && 521*55184Smckusick (flags & ISLASTCN)) 52253806Smckusick cnp->cn_flags |= SAVENAME; 52352196Smckusick return (0); 52452196Smckusick } 52552196Smckusick } 52653806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 52754106Smckusick vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { 52839441Smckusick nfsstats.lookupcache_hits++; 52953806Smckusick if (cnp->cn_nameiop != LOOKUP && 530*55184Smckusick (flags & ISLASTCN)) 53153806Smckusick cnp->cn_flags |= SAVENAME; 53239441Smckusick return (0); 53340251Smckusick } 53447289Smckusick cache_purge(vdp); 53539441Smckusick } 53652196Smckusick vrele(vdp); 53738884Smacklem } 53854668Smckusick *vpp = NULLVP; 53952196Smckusick } 54039341Smckusick error = 0; 54138414Smckusick nfsstats.lookupcache_misses++; 54238414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 54353806Smckusick len = cnp->cn_namelen; 54453806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 54552196Smckusick 54652196Smckusick /* 54752196Smckusick * For nqnfs optionally piggyback a getlease request for the name 54852196Smckusick * being looked up. 54952196Smckusick */ 55052196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 55152196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 552*55184Smckusick ((cnp->cn_flags & MAKEENTRY) && 553*55184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) { 55452196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 55552196Smckusick *tl++ = txdr_unsigned(NQL_READ); 55652196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 55752196Smckusick } else { 55852196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 55952196Smckusick *tl = 0; 56052196Smckusick } 56152196Smckusick } 56253806Smckusick nfsm_fhtom(dvp); 56353806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 56452196Smckusick reqtime = time.tv_sec; 56553806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 56638414Smckusick nfsmout: 56738414Smckusick if (error) { 56853806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 569*55184Smckusick (flags & ISLASTCN) && error == ENOENT) 57052823Smckusick error = EJUSTRETURN; 571*55184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 57253806Smckusick cnp->cn_flags |= SAVENAME; 57340483Smckusick return (error); 57438414Smckusick } 57552196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 57652196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 57752196Smckusick if (*tl) { 57852196Smckusick nqlflag = fxdr_unsigned(int, *tl); 57952196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 58052196Smckusick cachable = fxdr_unsigned(int, *tl++); 58152196Smckusick reqtime += fxdr_unsigned(int, *tl++); 58252196Smckusick fxdr_hyper(tl, &frev); 58352196Smckusick } else 58452196Smckusick nqlflag = 0; 58552196Smckusick } 58652196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 58738414Smckusick 58838414Smckusick /* 58952196Smckusick * Handle RENAME case... 59038414Smckusick */ 591*55184Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 59252196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 59338414Smckusick m_freem(mrep); 59438414Smckusick return (EISDIR); 59538414Smckusick } 59653806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 59738414Smckusick m_freem(mrep); 59838414Smckusick return (error); 59938414Smckusick } 60038414Smckusick newvp = NFSTOV(np); 60139459Smckusick if (error = 60239459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 60352196Smckusick vrele(newvp); 60438414Smckusick m_freem(mrep); 60538414Smckusick return (error); 60638414Smckusick } 60754668Smckusick *vpp = newvp; 60845037Smckusick m_freem(mrep); 60953806Smckusick cnp->cn_flags |= SAVENAME; 61038414Smckusick return (0); 61138414Smckusick } 61238414Smckusick 61352196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 61453806Smckusick VREF(dvp); 61553806Smckusick newvp = dvp; 61638414Smckusick } else { 61753806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 61838414Smckusick m_freem(mrep); 61938414Smckusick return (error); 62038414Smckusick } 62138414Smckusick newvp = NFSTOV(np); 62238414Smckusick } 62339459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 62452196Smckusick vrele(newvp); 62538414Smckusick m_freem(mrep); 62638414Smckusick return (error); 62738414Smckusick } 62838414Smckusick m_freem(mrep); 62954668Smckusick *vpp = newvp; 630*55184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 63153806Smckusick cnp->cn_flags |= SAVENAME; 632*55184Smckusick if ((cnp->cn_flags & MAKEENTRY) && 633*55184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { 63452196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 63554106Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec; 63652196Smckusick else if (nqlflag && reqtime > time.tv_sec) { 63752196Smckusick if (np->n_tnext) { 63852196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 63952196Smckusick nmp->nm_tprev = np->n_tprev; 64052196Smckusick else 64152196Smckusick np->n_tnext->n_tprev = np->n_tprev; 64252196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 64352196Smckusick nmp->nm_tnext = np->n_tnext; 64452196Smckusick else 64552196Smckusick np->n_tprev->n_tnext = np->n_tnext; 64652196Smckusick if (nqlflag == NQL_WRITE) 64752196Smckusick np->n_flag |= NQNFSWRITE; 64852196Smckusick } else if (nqlflag == NQL_READ) 64952196Smckusick np->n_flag &= ~NQNFSWRITE; 65052196Smckusick else 65152196Smckusick np->n_flag |= NQNFSWRITE; 65252196Smckusick if (cachable) 65352196Smckusick np->n_flag &= ~NQNFSNONCACHE; 65452196Smckusick else 65552196Smckusick np->n_flag |= NQNFSNONCACHE; 65652196Smckusick np->n_expiry = reqtime; 65752196Smckusick np->n_lrev = frev; 65852196Smckusick tp = nmp->nm_tprev; 65952196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 66052196Smckusick tp = tp->n_tprev; 66152196Smckusick if (tp == (struct nfsnode *)nmp) { 66252196Smckusick np->n_tnext = nmp->nm_tnext; 66352196Smckusick nmp->nm_tnext = np; 66452196Smckusick } else { 66552196Smckusick np->n_tnext = tp->n_tnext; 66652196Smckusick tp->n_tnext = np; 66752196Smckusick } 66852196Smckusick np->n_tprev = tp; 66952196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 67052196Smckusick nmp->nm_tprev = np; 67152196Smckusick else 67252196Smckusick np->n_tnext->n_tprev = np; 67352196Smckusick } 67454668Smckusick cache_enter(dvp, *vpp, cnp); 67540251Smckusick } 67652196Smckusick return (0); 67738414Smckusick } 67838414Smckusick 67938414Smckusick /* 68041905Smckusick * nfs read call. 68141905Smckusick * Just call nfs_bioread() to do the work. 68241905Smckusick */ 68352234Sheideman int 68453806Smckusick nfs_read(ap) 68554668Smckusick struct vop_read_args /* { 68654668Smckusick struct vnode *a_vp; 68754668Smckusick struct uio *a_uio; 68854668Smckusick int a_ioflag; 68954668Smckusick struct ucred *a_cred; 69054668Smckusick } */ *ap; 69141905Smckusick { 69253806Smckusick register struct vnode *vp = ap->a_vp; 69353806Smckusick 69453806Smckusick if (vp->v_type != VREG) 69541905Smckusick return (EPERM); 69653806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 69741905Smckusick } 69841905Smckusick 69941905Smckusick /* 70038414Smckusick * nfs readlink call 70138414Smckusick */ 70252234Sheideman int 70353806Smckusick nfs_readlink(ap) 70454668Smckusick struct vop_readlink_args /* { 70554668Smckusick struct vnode *a_vp; 70654668Smckusick struct uio *a_uio; 70754668Smckusick struct ucred *a_cred; 70854668Smckusick } */ *ap; 70941905Smckusick { 71053806Smckusick register struct vnode *vp = ap->a_vp; 71153806Smckusick 71253806Smckusick if (vp->v_type != VLNK) 71341905Smckusick return (EPERM); 71453806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 71541905Smckusick } 71641905Smckusick 71741905Smckusick /* 71841905Smckusick * Do a readlink rpc. 71941905Smckusick * Called by nfs_doio() from below the buffer cache. 72041905Smckusick */ 72152234Sheideman int 72248054Smckusick nfs_readlinkrpc(vp, uiop, cred) 72339488Smckusick register struct vnode *vp; 72438414Smckusick struct uio *uiop; 72538414Smckusick struct ucred *cred; 72638414Smckusick { 72748054Smckusick register u_long *tl; 72839488Smckusick register caddr_t cp; 72939488Smckusick register long t1; 73039488Smckusick caddr_t bpos, dpos, cp2; 73139488Smckusick int error = 0; 73239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73338414Smckusick long len; 73438414Smckusick 73538414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 73652196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 73738414Smckusick nfsm_fhtom(vp); 73852196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 73938414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 74038414Smckusick nfsm_mtouio(uiop, len); 74138414Smckusick nfsm_reqdone; 74238414Smckusick return (error); 74338414Smckusick } 74438414Smckusick 74538414Smckusick /* 74641905Smckusick * nfs read rpc call 74741905Smckusick * Ditto above 74838414Smckusick */ 74952234Sheideman int 75048054Smckusick nfs_readrpc(vp, uiop, cred) 75139488Smckusick register struct vnode *vp; 75238414Smckusick struct uio *uiop; 75338414Smckusick struct ucred *cred; 75438414Smckusick { 75548054Smckusick register u_long *tl; 75639488Smckusick register caddr_t cp; 75739488Smckusick register long t1; 75839488Smckusick caddr_t bpos, dpos, cp2; 75939488Smckusick int error = 0; 76039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 76138414Smckusick struct nfsmount *nmp; 76238414Smckusick long len, retlen, tsiz; 76338414Smckusick 76441398Smckusick nmp = VFSTONFS(vp->v_mount); 76538414Smckusick tsiz = uiop->uio_resid; 76638414Smckusick while (tsiz > 0) { 76738414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 76838414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 76952196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 77038414Smckusick nfsm_fhtom(vp); 77148054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 77248054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 77348054Smckusick *tl++ = txdr_unsigned(len); 77448054Smckusick *tl = 0; 77552196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 77638414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 77738414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 77838414Smckusick nfsm_mtouio(uiop, retlen); 77938414Smckusick m_freem(mrep); 78038414Smckusick if (retlen < len) 78138414Smckusick tsiz = 0; 78238414Smckusick else 78338414Smckusick tsiz -= len; 78438414Smckusick } 78538414Smckusick nfsmout: 78638414Smckusick return (error); 78738414Smckusick } 78838414Smckusick 78938414Smckusick /* 79038414Smckusick * nfs write call 79138414Smckusick */ 79252234Sheideman int 79348054Smckusick nfs_writerpc(vp, uiop, cred) 79439488Smckusick register struct vnode *vp; 79538414Smckusick struct uio *uiop; 79638414Smckusick struct ucred *cred; 79738414Smckusick { 79848054Smckusick register u_long *tl; 79939488Smckusick register caddr_t cp; 80039488Smckusick register long t1; 80152196Smckusick caddr_t bpos, dpos, cp2; 80239488Smckusick int error = 0; 80339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 80438414Smckusick struct nfsmount *nmp; 80552196Smckusick struct nfsnode *np = VTONFS(vp); 80652196Smckusick u_quad_t frev; 80738414Smckusick long len, tsiz; 80838414Smckusick 80941398Smckusick nmp = VFSTONFS(vp->v_mount); 81038414Smckusick tsiz = uiop->uio_resid; 81138414Smckusick while (tsiz > 0) { 81238414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 81338414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 81452196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 81552196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 81638414Smckusick nfsm_fhtom(vp); 81748054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 81848054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 81948054Smckusick *(tl+3) = txdr_unsigned(len); 82038414Smckusick nfsm_uiotom(uiop, len); 82152196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 82238414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 82352196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 82454106Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; 82552196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 82652196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 82752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 82852196Smckusick fxdr_hyper(tl, &frev); 82954451Smckusick if (frev > np->n_brev) 83052196Smckusick np->n_brev = frev; 83152196Smckusick } 83238414Smckusick m_freem(mrep); 83338414Smckusick tsiz -= len; 83438414Smckusick } 83538414Smckusick nfsmout: 83652196Smckusick if (error) 83752196Smckusick uiop->uio_resid = tsiz; 83838414Smckusick return (error); 83938414Smckusick } 84038414Smckusick 84138414Smckusick /* 84239459Smckusick * nfs mknod call 84342246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 84442246Smckusick * set to specify the file type and the size field for rdev. 84539459Smckusick */ 84639459Smckusick /* ARGSUSED */ 84752234Sheideman int 84853806Smckusick nfs_mknod(ap) 84954668Smckusick struct vop_mknod_args /* { 85054668Smckusick struct vnode *a_dvp; 85154668Smckusick struct vnode **a_vpp; 85254668Smckusick struct componentname *a_cnp; 85354668Smckusick struct vattr *a_vap; 85454668Smckusick } */ *ap; 85539459Smckusick { 85653806Smckusick register struct vnode *dvp = ap->a_dvp; 85753806Smckusick register struct vattr *vap = ap->a_vap; 85853806Smckusick register struct componentname *cnp = ap->a_cnp; 85942246Smckusick register struct nfsv2_sattr *sp; 86048054Smckusick register u_long *tl; 86142246Smckusick register caddr_t cp; 86252196Smckusick register long t2; 86342246Smckusick caddr_t bpos, dpos; 86442246Smckusick int error = 0; 86542246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 86642246Smckusick u_long rdev; 86739459Smckusick 86853806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 86953806Smckusick rdev = txdr_unsigned(vap->va_rdev); 87042246Smckusick #ifdef FIFO 87153806Smckusick else if (vap->va_type == VFIFO) 87242246Smckusick rdev = 0xffffffff; 87342246Smckusick #endif /* FIFO */ 87442246Smckusick else { 87553806Smckusick VOP_ABORTOP(dvp, cnp); 87653806Smckusick vput(dvp); 87742246Smckusick return (EOPNOTSUPP); 87842246Smckusick } 87942246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 88053806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 88153806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 88253806Smckusick nfsm_fhtom(dvp); 88353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 88442246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 88553806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 88653806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 88753806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 88842246Smckusick sp->sa_size = rdev; 88942246Smckusick /* or should these be VNOVAL ?? */ 89053806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 89153806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 89253806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 89342246Smckusick nfsm_reqdone; 89453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 89553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 89653806Smckusick vrele(dvp); 89742246Smckusick return (error); 89839459Smckusick } 89939459Smckusick 90039459Smckusick /* 90138414Smckusick * nfs file create call 90238414Smckusick */ 90352234Sheideman int 90453806Smckusick nfs_create(ap) 90554668Smckusick struct vop_create_args /* { 90654668Smckusick struct vnode *a_dvp; 90754668Smckusick struct vnode **a_vpp; 90854668Smckusick struct componentname *a_cnp; 90954668Smckusick struct vattr *a_vap; 91054668Smckusick } */ *ap; 91138414Smckusick { 91253806Smckusick register struct vnode *dvp = ap->a_dvp; 91353806Smckusick register struct vattr *vap = ap->a_vap; 91453806Smckusick register struct componentname *cnp = ap->a_cnp; 91538884Smacklem register struct nfsv2_sattr *sp; 91648054Smckusick register u_long *tl; 91739488Smckusick register caddr_t cp; 91839488Smckusick register long t1, t2; 91939488Smckusick caddr_t bpos, dpos, cp2; 92039488Smckusick int error = 0; 92139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92238414Smckusick 92338414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 92453806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 92553806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 92653806Smckusick nfsm_fhtom(dvp); 92753806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 92838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 92953806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 93053806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 93153806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 93238884Smacklem sp->sa_size = txdr_unsigned(0); 93338414Smckusick /* or should these be VNOVAL ?? */ 93453806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 93553806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 93653806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 93753806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 93838414Smckusick nfsm_reqdone; 93953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 94053806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 94153806Smckusick vrele(dvp); 94238414Smckusick return (error); 94338414Smckusick } 94438414Smckusick 94538414Smckusick /* 94638414Smckusick * nfs file remove call 94741905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 94841905Smckusick * other processes using the vnode is renamed instead of removed and then 94939341Smckusick * removed later on the last close. 95041905Smckusick * - If v_usecount > 1 95139341Smckusick * If a rename is not already in the works 95239341Smckusick * call nfs_sillyrename() to set it up 95339341Smckusick * else 95439341Smckusick * do the remove rpc 95538414Smckusick */ 95652234Sheideman int 95753806Smckusick nfs_remove(ap) 95854451Smckusick struct vop_remove_args /* { 95954451Smckusick struct vnodeop_desc *a_desc; 96054451Smckusick struct vnode * a_dvp; 96154451Smckusick struct vnode * a_vp; 96254451Smckusick struct componentname * a_cnp; 96354451Smckusick } */ *ap; 96438414Smckusick { 96553806Smckusick register struct vnode *vp = ap->a_vp; 96653806Smckusick register struct vnode *dvp = ap->a_dvp; 96753806Smckusick register struct componentname *cnp = ap->a_cnp; 96853806Smckusick register struct nfsnode *np = VTONFS(vp); 96948054Smckusick register u_long *tl; 97039488Smckusick register caddr_t cp; 97152196Smckusick register long t2; 97239488Smckusick caddr_t bpos, dpos; 97339488Smckusick int error = 0; 97439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97538414Smckusick 97653806Smckusick if (vp->v_usecount > 1) { 97739341Smckusick if (!np->n_sillyrename) 97853806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 97939341Smckusick } else { 98052196Smckusick /* 98152196Smckusick * Purge the name cache so that the chance of a lookup for 98252196Smckusick * the name succeeding while the remove is in progress is 98352196Smckusick * minimized. Without node locking it can still happen, such 98452196Smckusick * that an I/O op returns ESTALE, but since you get this if 98552196Smckusick * another host removes the file.. 98652196Smckusick */ 98753806Smckusick cache_purge(vp); 98852196Smckusick /* 98952196Smckusick * Throw away biocache buffers. Mainly to avoid 99052196Smckusick * unnecessary delayed writes. 99152196Smckusick */ 99254451Smckusick error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc); 99352196Smckusick /* Do the rpc */ 99438414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 99553806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 99653806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 99753806Smckusick nfsm_fhtom(dvp); 99853806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 99953806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 100038414Smckusick nfsm_reqdone; 100153806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 100253806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 100339751Smckusick /* 100439751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 100539751Smckusick * the reply to the retransmitted request will be ENOENT 100639751Smckusick * since the file was in fact removed 100739751Smckusick * Therefore, we cheat and return success. 100839751Smckusick */ 100939751Smckusick if (error == ENOENT) 101039751Smckusick error = 0; 101138414Smckusick } 101240042Smckusick np->n_attrstamp = 0; 101353806Smckusick vrele(dvp); 101453806Smckusick vrele(vp); 101538414Smckusick return (error); 101638414Smckusick } 101738414Smckusick 101838414Smckusick /* 101938414Smckusick * nfs file remove rpc called from nfs_inactive 102038414Smckusick */ 102152234Sheideman int 102254451Smckusick nfs_removeit(sp) 102348364Smckusick register struct sillyrename *sp; 102438414Smckusick { 102548054Smckusick register u_long *tl; 102639488Smckusick register caddr_t cp; 102752196Smckusick register long t2; 102839488Smckusick caddr_t bpos, dpos; 102939488Smckusick int error = 0; 103039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 103138414Smckusick 103238414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 103352196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 103448364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 103548364Smckusick nfsm_fhtom(sp->s_dvp); 103648364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 103754451Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); 103838414Smckusick nfsm_reqdone; 103948364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 104038414Smckusick return (error); 104138414Smckusick } 104238414Smckusick 104338414Smckusick /* 104438414Smckusick * nfs file rename call 104538414Smckusick */ 104652234Sheideman int 104753806Smckusick nfs_rename(ap) 104854668Smckusick struct vop_rename_args /* { 104954668Smckusick struct vnode *a_fdvp; 105054668Smckusick struct vnode *a_fvp; 105154668Smckusick struct componentname *a_fcnp; 105254668Smckusick struct vnode *a_tdvp; 105354668Smckusick struct vnode *a_tvp; 105454668Smckusick struct componentname *a_tcnp; 105554668Smckusick } */ *ap; 105638414Smckusick { 105753806Smckusick register struct vnode *fvp = ap->a_fvp; 105853806Smckusick register struct vnode *tvp = ap->a_tvp; 105953806Smckusick register struct vnode *fdvp = ap->a_fdvp; 106053806Smckusick register struct vnode *tdvp = ap->a_tdvp; 106153806Smckusick register struct componentname *tcnp = ap->a_tcnp; 106253806Smckusick register struct componentname *fcnp = ap->a_fcnp; 106348054Smckusick register u_long *tl; 106439488Smckusick register caddr_t cp; 106552196Smckusick register long t2; 106639488Smckusick caddr_t bpos, dpos; 106739488Smckusick int error = 0; 106839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 106938414Smckusick 107053804Spendry /* Check for cross-device rename */ 107153806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 107253806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 107353804Spendry error = EXDEV; 107453804Spendry goto out; 107553804Spendry } 107653804Spendry 107753804Spendry 107838414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 107953806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 108053806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 108153806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 108253806Smckusick nfsm_fhtom(fdvp); 108353806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 108453806Smckusick nfsm_fhtom(tdvp); 108553806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 108653806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 108738414Smckusick nfsm_reqdone; 108853806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 108953806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 109053806Smckusick if (fvp->v_type == VDIR) { 109153806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 109253806Smckusick cache_purge(tdvp); 109353806Smckusick cache_purge(fdvp); 109438414Smckusick } 109553804Spendry out: 109653806Smckusick if (tdvp == tvp) 109753806Smckusick vrele(tdvp); 109843360Smckusick else 109953806Smckusick vput(tdvp); 110053806Smckusick if (tvp) 110153806Smckusick vput(tvp); 110253806Smckusick vrele(fdvp); 110353806Smckusick vrele(fvp); 110440112Smckusick /* 110540112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 110640112Smckusick */ 110740112Smckusick if (error == ENOENT) 110840112Smckusick error = 0; 110938414Smckusick return (error); 111038414Smckusick } 111138414Smckusick 111238414Smckusick /* 111341905Smckusick * nfs file rename rpc called from nfs_remove() above 111438414Smckusick */ 111552234Sheideman int 111652234Sheideman nfs_renameit(sdvp, scnp, sp) 111752234Sheideman struct vnode *sdvp; 111852234Sheideman struct componentname *scnp; 111948364Smckusick register struct sillyrename *sp; 112038414Smckusick { 112148054Smckusick register u_long *tl; 112239488Smckusick register caddr_t cp; 112352196Smckusick register long t2; 112439488Smckusick caddr_t bpos, dpos; 112539488Smckusick int error = 0; 112639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 112738414Smckusick 112838414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 112952234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 113052234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 113152196Smckusick nfsm_rndup(sp->s_namlen)); 113252234Sheideman nfsm_fhtom(sdvp); 113352234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 113452234Sheideman nfsm_fhtom(sdvp); 113548364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 113652234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 113738414Smckusick nfsm_reqdone; 113852234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 113952234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 114038414Smckusick return (error); 114138414Smckusick } 114238414Smckusick 114338414Smckusick /* 114438414Smckusick * nfs hard link create call 114538414Smckusick */ 114652234Sheideman int 114753806Smckusick nfs_link(ap) 114854668Smckusick struct vop_link_args /* { 114954668Smckusick struct vnode *a_vp; 115054668Smckusick struct vnode *a_tdvp; 115154668Smckusick struct componentname *a_cnp; 115254668Smckusick } */ *ap; 115338414Smckusick { 115453806Smckusick register struct vnode *vp = ap->a_vp; 115553806Smckusick register struct vnode *tdvp = ap->a_tdvp; 115653806Smckusick register struct componentname *cnp = ap->a_cnp; 115748054Smckusick register u_long *tl; 115839488Smckusick register caddr_t cp; 115952196Smckusick register long t2; 116039488Smckusick caddr_t bpos, dpos; 116139488Smckusick int error = 0; 116239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 116338414Smckusick 116453806Smckusick if (vp->v_mount != tdvp->v_mount) { 116553806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 116653806Smckusick if (tdvp == vp) 116753806Smckusick vrele(vp); 116853804Spendry else 116953806Smckusick vput(vp); 117053804Spendry return (EXDEV); 117153804Spendry } 117253804Spendry 117338414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 117453806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 117553806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 117653806Smckusick nfsm_fhtom(tdvp); 117753806Smckusick nfsm_fhtom(vp); 117853806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 117953806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 118038414Smckusick nfsm_reqdone; 118153806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 118253806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 118353806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 118453806Smckusick vrele(vp); 118540112Smckusick /* 118640112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 118740112Smckusick */ 118840112Smckusick if (error == EEXIST) 118940112Smckusick error = 0; 119038414Smckusick return (error); 119138414Smckusick } 119238414Smckusick 119338414Smckusick /* 119438414Smckusick * nfs symbolic link create call 119538414Smckusick */ 119652234Sheideman /* start here */ 119752234Sheideman int 119853806Smckusick nfs_symlink(ap) 119954668Smckusick struct vop_symlink_args /* { 120054668Smckusick struct vnode *a_dvp; 120154668Smckusick struct vnode **a_vpp; 120254668Smckusick struct componentname *a_cnp; 120354668Smckusick struct vattr *a_vap; 120454668Smckusick char *a_target; 120554668Smckusick } */ *ap; 120638414Smckusick { 120753806Smckusick register struct vnode *dvp = ap->a_dvp; 120853806Smckusick register struct vattr *vap = ap->a_vap; 120953806Smckusick register struct componentname *cnp = ap->a_cnp; 121038884Smacklem register struct nfsv2_sattr *sp; 121148054Smckusick register u_long *tl; 121239488Smckusick register caddr_t cp; 121352196Smckusick register long t2; 121439488Smckusick caddr_t bpos, dpos; 121552196Smckusick int slen, error = 0; 121639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 121738414Smckusick 121838414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 121953600Sheideman slen = strlen(ap->a_target); 122053806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 122153806Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR); 122253806Smckusick nfsm_fhtom(dvp); 122353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 122453600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 122538884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 122653806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 122753806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 122853806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 122938884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 123053806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 123153806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 123253806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 123338414Smckusick nfsm_reqdone; 123453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 123553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 123653806Smckusick vrele(dvp); 123740112Smckusick /* 123840112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 123940112Smckusick */ 124040112Smckusick if (error == EEXIST) 124140112Smckusick error = 0; 124238414Smckusick return (error); 124338414Smckusick } 124438414Smckusick 124538414Smckusick /* 124638414Smckusick * nfs make dir call 124738414Smckusick */ 124852234Sheideman int 124953806Smckusick nfs_mkdir(ap) 125054668Smckusick struct vop_mkdir_args /* { 125154668Smckusick struct vnode *a_dvp; 125254668Smckusick struct vnode **a_vpp; 125354668Smckusick struct componentname *a_cnp; 125454668Smckusick struct vattr *a_vap; 125554668Smckusick } */ *ap; 125638414Smckusick { 125753806Smckusick register struct vnode *dvp = ap->a_dvp; 125853806Smckusick register struct vattr *vap = ap->a_vap; 125953806Smckusick register struct componentname *cnp = ap->a_cnp; 126054668Smckusick register struct vnode **vpp = ap->a_vpp; 126138884Smacklem register struct nfsv2_sattr *sp; 126248054Smckusick register u_long *tl; 126339488Smckusick register caddr_t cp; 126439488Smckusick register long t1, t2; 126541905Smckusick register int len; 126639488Smckusick caddr_t bpos, dpos, cp2; 126741905Smckusick int error = 0, firsttry = 1; 126839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 126938414Smckusick 127053806Smckusick len = cnp->cn_namelen; 127138414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 127253806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 127341905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 127453806Smckusick nfsm_fhtom(dvp); 127553806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 127638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 127753806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 127853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 127953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 128038884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 128153806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 128253806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 128353806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 128454668Smckusick nfsm_mtofh(dvp, *vpp); 128538414Smckusick nfsm_reqdone; 128653806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 128740112Smckusick /* 128841905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 128941905Smckusick * if we can succeed in looking up the directory. 129041905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 129141905Smckusick * is above the if on errors. (Ugh) 129240112Smckusick */ 129341905Smckusick if (error == EEXIST && firsttry) { 129441905Smckusick firsttry = 0; 129540112Smckusick error = 0; 129641905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 129754668Smckusick *vpp = NULL; 129853806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 129941905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 130053806Smckusick nfsm_fhtom(dvp); 130153806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 130253806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 130354668Smckusick nfsm_mtofh(dvp, *vpp); 130454668Smckusick if ((*vpp)->v_type != VDIR) { 130554668Smckusick vput(*vpp); 130641905Smckusick error = EEXIST; 130741905Smckusick } 130841905Smckusick m_freem(mrep); 130941905Smckusick } 131053806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 131153806Smckusick vrele(dvp); 131238414Smckusick return (error); 131338414Smckusick } 131438414Smckusick 131538414Smckusick /* 131638414Smckusick * nfs remove directory call 131738414Smckusick */ 131852234Sheideman int 131953806Smckusick nfs_rmdir(ap) 132054668Smckusick struct vop_rmdir_args /* { 132154668Smckusick struct vnode *a_dvp; 132254668Smckusick struct vnode *a_vp; 132354668Smckusick struct componentname *a_cnp; 132454668Smckusick } */ *ap; 132538414Smckusick { 132653806Smckusick register struct vnode *vp = ap->a_vp; 132753806Smckusick register struct vnode *dvp = ap->a_dvp; 132853806Smckusick register struct componentname *cnp = ap->a_cnp; 132948054Smckusick register u_long *tl; 133039488Smckusick register caddr_t cp; 133152196Smckusick register long t2; 133239488Smckusick caddr_t bpos, dpos; 133339488Smckusick int error = 0; 133439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 133538414Smckusick 133653806Smckusick if (dvp == vp) { 133753806Smckusick vrele(dvp); 133853806Smckusick vrele(dvp); 133953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 134038414Smckusick return (EINVAL); 134138414Smckusick } 134238414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 134353806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 134453806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 134553806Smckusick nfsm_fhtom(dvp); 134653806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 134753806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 134838414Smckusick nfsm_reqdone; 134953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 135053806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 135153806Smckusick cache_purge(dvp); 135253806Smckusick cache_purge(vp); 135353806Smckusick vrele(vp); 135453806Smckusick vrele(dvp); 135540112Smckusick /* 135640112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 135740112Smckusick */ 135840112Smckusick if (error == ENOENT) 135940112Smckusick error = 0; 136038414Smckusick return (error); 136138414Smckusick } 136238414Smckusick 136338414Smckusick /* 136438414Smckusick * nfs readdir call 136538414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 136638414Smckusick * order so that it looks more sensible. This appears consistent with the 136738414Smckusick * Ultrix implementation of NFS. 136838414Smckusick */ 136952234Sheideman int 137053806Smckusick nfs_readdir(ap) 137154668Smckusick struct vop_readdir_args /* { 137254668Smckusick struct vnode *a_vp; 137354668Smckusick struct uio *a_uio; 137454668Smckusick struct ucred *a_cred; 137554668Smckusick } */ *ap; 137638414Smckusick { 137753806Smckusick register struct vnode *vp = ap->a_vp; 137853806Smckusick register struct nfsnode *np = VTONFS(vp); 137953806Smckusick register struct uio *uio = ap->a_uio; 138041905Smckusick int tresid, error; 138141905Smckusick struct vattr vattr; 138241905Smckusick 138353806Smckusick if (vp->v_type != VDIR) 138441905Smckusick return (EPERM); 138541905Smckusick /* 138641905Smckusick * First, check for hit on the EOF offset cache 138741905Smckusick */ 138853806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 138952196Smckusick (np->n_flag & NMODIFIED) == 0) { 139053806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 139153806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 139252196Smckusick nfsstats.direofcache_hits++; 139352196Smckusick return (0); 139452196Smckusick } 139553806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 139654106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) { 139752196Smckusick nfsstats.direofcache_hits++; 139852196Smckusick return (0); 139952196Smckusick } 140041905Smckusick } 140141905Smckusick 140241905Smckusick /* 140341905Smckusick * Call nfs_bioread() to do the real work. 140441905Smckusick */ 140553806Smckusick tresid = uio->uio_resid; 140653806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 140741905Smckusick 140854451Smckusick if (!error && uio->uio_resid == tresid) 140941905Smckusick nfsstats.direofcache_misses++; 141041905Smckusick return (error); 141141905Smckusick } 141241905Smckusick 141341905Smckusick /* 141441905Smckusick * Readdir rpc call. 141541905Smckusick * Called from below the buffer cache by nfs_doio(). 141641905Smckusick */ 141752234Sheideman int 141848054Smckusick nfs_readdirrpc(vp, uiop, cred) 141941905Smckusick register struct vnode *vp; 142041905Smckusick struct uio *uiop; 142141905Smckusick struct ucred *cred; 142241905Smckusick { 142338414Smckusick register long len; 142454740Smckusick register struct dirent *dp; 142548054Smckusick register u_long *tl; 142639488Smckusick register caddr_t cp; 142739488Smckusick register long t1; 142841905Smckusick long tlen, lastlen; 142939488Smckusick caddr_t bpos, dpos, cp2; 143039488Smckusick int error = 0; 143139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 143238414Smckusick struct mbuf *md2; 143338414Smckusick caddr_t dpos2; 143438414Smckusick int siz; 143540296Smckusick int more_dirs = 1; 143638414Smckusick off_t off, savoff; 143754740Smckusick struct dirent *savdp; 143840296Smckusick struct nfsmount *nmp; 143940296Smckusick struct nfsnode *np = VTONFS(vp); 144040296Smckusick long tresid; 144138414Smckusick 144241398Smckusick nmp = VFSTONFS(vp->v_mount); 144340296Smckusick tresid = uiop->uio_resid; 144440296Smckusick /* 144540296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 144648054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 144741905Smckusick * The stopping criteria is EOF or buffer full. 144840296Smckusick */ 144948054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 145040296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 145152196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 145252196Smckusick NFSX_FH+2*NFSX_UNSIGNED); 145340296Smckusick nfsm_fhtom(vp); 145448054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 145548054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 145648054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 145748054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 145852196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 145940296Smckusick siz = 0; 146052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 146148054Smckusick more_dirs = fxdr_unsigned(int, *tl); 146240296Smckusick 146340296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 146440296Smckusick dpos2 = dpos; 146540296Smckusick md2 = md; 146640296Smckusick 146740296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 146841905Smckusick off = uiop->uio_offset; 146942246Smckusick #ifdef lint 147054740Smckusick dp = (struct dirent *)0; 147142246Smckusick #endif /* lint */ 147240296Smckusick while (more_dirs && siz < uiop->uio_resid) { 147340296Smckusick savoff = off; /* Hold onto offset and dp */ 147440296Smckusick savdp = dp; 147552196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 147654740Smckusick dp = (struct dirent *)tl; 147754740Smckusick dp->d_fileno = fxdr_unsigned(u_long, *tl++); 147848054Smckusick len = fxdr_unsigned(int, *tl); 147940296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 148040296Smckusick error = EBADRPC; 148140296Smckusick m_freem(mrep); 148240296Smckusick goto nfsmout; 148340296Smckusick } 148454986Smckusick dp->d_namlen = (u_char)len; 148554986Smckusick dp->d_type = DT_UNKNOWN; 148640296Smckusick nfsm_adv(len); /* Point past name */ 148740296Smckusick tlen = nfsm_rndup(len); 148840296Smckusick /* 148940296Smckusick * This should not be necessary, but some servers have 149040296Smckusick * broken XDR such that these bytes are not null filled. 149140296Smckusick */ 149240296Smckusick if (tlen != len) { 149340296Smckusick *dpos = '\0'; /* Null-terminate */ 149440296Smckusick nfsm_adv(tlen - len); 149540296Smckusick len = tlen; 149640296Smckusick } 149752196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 149854986Smckusick off = fxdr_unsigned(u_long, *tl); 149948054Smckusick *tl++ = 0; /* Ensures null termination of name */ 150048054Smckusick more_dirs = fxdr_unsigned(int, *tl); 150140296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 150240296Smckusick siz += dp->d_reclen; 150340296Smckusick } 150440296Smckusick /* 150540296Smckusick * If at end of rpc data, get the eof boolean 150640296Smckusick */ 150740296Smckusick if (!more_dirs) { 150852196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 150948054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 151038414Smckusick 151140296Smckusick /* 151240296Smckusick * If at EOF, cache directory offset 151340296Smckusick */ 151441905Smckusick if (!more_dirs) 151540296Smckusick np->n_direofoffset = off; 151638414Smckusick } 151740296Smckusick /* 151840296Smckusick * If there is too much to fit in the data buffer, use savoff and 151940296Smckusick * savdp to trim off the last record. 152040296Smckusick * --> we are not at eof 152140296Smckusick */ 152240296Smckusick if (siz > uiop->uio_resid) { 152340296Smckusick off = savoff; 152440296Smckusick siz -= dp->d_reclen; 152540296Smckusick dp = savdp; 152640296Smckusick more_dirs = 0; /* Paranoia */ 152740113Smckusick } 152840296Smckusick if (siz > 0) { 152941905Smckusick lastlen = dp->d_reclen; 153040296Smckusick md = md2; 153140296Smckusick dpos = dpos2; 153240296Smckusick nfsm_mtouio(uiop, siz); 153340296Smckusick uiop->uio_offset = off; 153440296Smckusick } else 153540296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 153640296Smckusick m_freem(mrep); 153738414Smckusick } 153841905Smckusick /* 153948054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 154041905Smckusick * by increasing d_reclen for the last record. 154141905Smckusick */ 154241905Smckusick if (uiop->uio_resid < tresid) { 154348054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 154441905Smckusick if (len > 0) { 154554740Smckusick dp = (struct dirent *) 154641905Smckusick (uiop->uio_iov->iov_base - lastlen); 154741905Smckusick dp->d_reclen += len; 154841905Smckusick uiop->uio_iov->iov_base += len; 154941905Smckusick uiop->uio_iov->iov_len -= len; 155041905Smckusick uiop->uio_resid -= len; 155141905Smckusick } 155241905Smckusick } 155340296Smckusick nfsmout: 155438414Smckusick return (error); 155538414Smckusick } 155638414Smckusick 155752196Smckusick /* 155852196Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when 155952196Smckusick * the "rdirlook" mount option is specified. 156052196Smckusick */ 156152234Sheideman int 156252196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 156352196Smckusick struct vnode *vp; 156452196Smckusick register struct uio *uiop; 156552196Smckusick struct ucred *cred; 156652196Smckusick { 156752196Smckusick register int len; 156854740Smckusick register struct dirent *dp; 156952196Smckusick register u_long *tl; 157052196Smckusick register caddr_t cp; 157152196Smckusick register long t1; 157252196Smckusick caddr_t bpos, dpos, cp2; 157352196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 157452196Smckusick struct nameidata nami, *ndp = &nami; 157552317Sheideman struct componentname *cnp = &ndp->ni_cnd; 157652196Smckusick off_t off, endoff; 157752196Smckusick time_t reqtime, ltime; 157852196Smckusick struct nfsmount *nmp; 157952196Smckusick struct nfsnode *np, *tp; 158052196Smckusick struct vnode *newvp; 158152196Smckusick nfsv2fh_t *fhp; 158252196Smckusick u_long fileno; 158352196Smckusick u_quad_t frev; 158452196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 158552196Smckusick int cachable; 158652196Smckusick 158752196Smckusick if (uiop->uio_iovcnt != 1) 158852196Smckusick panic("nfs rdirlook"); 158952196Smckusick nmp = VFSTONFS(vp->v_mount); 159052196Smckusick tresid = uiop->uio_resid; 159152196Smckusick ndp->ni_dvp = vp; 159252196Smckusick newvp = NULLVP; 159352196Smckusick /* 159452196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 159552196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 159652196Smckusick * The stopping criteria is EOF or buffer full. 159752196Smckusick */ 159852196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 159952196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 160052196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 160152196Smckusick NFSX_FH+3*NFSX_UNSIGNED); 160252196Smckusick nfsm_fhtom(vp); 160352196Smckusick nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED); 160452196Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 160552196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 160652196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 160752196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 160852196Smckusick reqtime = time.tv_sec; 160952196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 161052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 161152196Smckusick more_dirs = fxdr_unsigned(int, *tl); 161252196Smckusick 161352196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 161452196Smckusick off = uiop->uio_offset; 161552196Smckusick bigenough = 1; 161652196Smckusick while (more_dirs && bigenough) { 161752196Smckusick doit = 1; 161852196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 161952196Smckusick cachable = fxdr_unsigned(int, *tl++); 162052196Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 162152196Smckusick fxdr_hyper(tl, &frev); 162252196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 162352196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 162452196Smckusick VREF(vp); 162552196Smckusick newvp = vp; 162652196Smckusick np = VTONFS(vp); 162752196Smckusick } else { 162852196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 162952196Smckusick doit = 0; 163052196Smckusick newvp = NFSTOV(np); 163152196Smckusick } 163252196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 163352196Smckusick (struct vattr *)0)) 163452196Smckusick doit = 0; 163552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 163652196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 163752196Smckusick len = fxdr_unsigned(int, *tl); 163852196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 163952196Smckusick error = EBADRPC; 164052196Smckusick m_freem(mrep); 164152196Smckusick goto nfsmout; 164252196Smckusick } 164352196Smckusick tlen = (len + 4) & ~0x3; 164452196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 164552196Smckusick bigenough = 0; 164652196Smckusick if (bigenough && doit) { 164754740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base; 164854740Smckusick dp->d_fileno = fileno; 164952196Smckusick dp->d_namlen = len; 165052196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 165154986Smckusick dp->d_type = 165254986Smckusick IFTODT(VTTOIF(np->n_vattr.va_type)); 165352196Smckusick uiop->uio_resid -= DIRHDSIZ; 165452196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 165552196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 165652317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 165752317Sheideman cnp->cn_namelen = len; 165852196Smckusick ndp->ni_vp = newvp; 165952196Smckusick nfsm_mtouio(uiop, len); 166052196Smckusick cp = uiop->uio_iov->iov_base; 166152196Smckusick tlen -= len; 166252196Smckusick for (i = 0; i < tlen; i++) 166352196Smckusick *cp++ = '\0'; 166452196Smckusick uiop->uio_iov->iov_base += tlen; 166552196Smckusick uiop->uio_iov->iov_len -= tlen; 166652196Smckusick uiop->uio_resid -= tlen; 166752317Sheideman cnp->cn_hash = 0; 166852317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 166952317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 167052196Smckusick if (ltime > time.tv_sec) { 167152196Smckusick if (np->n_tnext) { 167252196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 167352196Smckusick nmp->nm_tprev = np->n_tprev; 167452196Smckusick else 167552196Smckusick np->n_tnext->n_tprev = np->n_tprev; 167652196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 167752196Smckusick nmp->nm_tnext = np->n_tnext; 167852196Smckusick else 167952196Smckusick np->n_tprev->n_tnext = np->n_tnext; 168052196Smckusick } else 168152196Smckusick np->n_flag &= ~NQNFSWRITE; 168252196Smckusick if (cachable) 168352196Smckusick np->n_flag &= ~NQNFSNONCACHE; 168452196Smckusick else 168552196Smckusick np->n_flag |= NQNFSNONCACHE; 168652196Smckusick np->n_expiry = ltime; 168752196Smckusick np->n_lrev = frev; 168852196Smckusick tp = nmp->nm_tprev; 168952196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 169052196Smckusick tp = tp->n_tprev; 169152196Smckusick if (tp == (struct nfsnode *)nmp) { 169252196Smckusick np->n_tnext = nmp->nm_tnext; 169352196Smckusick nmp->nm_tnext = np; 169452196Smckusick } else { 169552196Smckusick np->n_tnext = tp->n_tnext; 169652196Smckusick tp->n_tnext = np; 169752196Smckusick } 169852196Smckusick np->n_tprev = tp; 169952196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 170052196Smckusick nmp->nm_tprev = np; 170152196Smckusick else 170252196Smckusick np->n_tnext->n_tprev = np; 170352317Sheideman cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 170452196Smckusick } 170552196Smckusick } else { 170652196Smckusick nfsm_adv(nfsm_rndup(len)); 170752196Smckusick } 170852196Smckusick if (newvp != NULLVP) { 170952196Smckusick vrele(newvp); 171052196Smckusick newvp = NULLVP; 171152196Smckusick } 171252196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 171352196Smckusick if (bigenough) 171452196Smckusick endoff = off = fxdr_unsigned(off_t, *tl++); 171552196Smckusick else 171652196Smckusick endoff = fxdr_unsigned(off_t, *tl++); 171752196Smckusick more_dirs = fxdr_unsigned(int, *tl); 171852196Smckusick } 171952196Smckusick /* 172052196Smckusick * If at end of rpc data, get the eof boolean 172152196Smckusick */ 172252196Smckusick if (!more_dirs) { 172352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 172452196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 172552196Smckusick 172652196Smckusick /* 172752196Smckusick * If at EOF, cache directory offset 172852196Smckusick */ 172952196Smckusick if (!more_dirs) 173052196Smckusick VTONFS(vp)->n_direofoffset = endoff; 173152196Smckusick } 173252196Smckusick if (uiop->uio_resid < tresid) 173352196Smckusick uiop->uio_offset = off; 173452196Smckusick else 173552196Smckusick more_dirs = 0; 173652196Smckusick m_freem(mrep); 173752196Smckusick } 173852196Smckusick /* 173952196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 174052196Smckusick * by increasing d_reclen for the last record. 174152196Smckusick */ 174252196Smckusick if (uiop->uio_resid < tresid) { 174352196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 174452196Smckusick if (len > 0) { 174552196Smckusick dp->d_reclen += len; 174652196Smckusick uiop->uio_iov->iov_base += len; 174752196Smckusick uiop->uio_iov->iov_len -= len; 174852196Smckusick uiop->uio_resid -= len; 174952196Smckusick } 175052196Smckusick } 175152196Smckusick nfsmout: 175252196Smckusick if (newvp != NULLVP) 175352196Smckusick vrele(newvp); 175452196Smckusick return (error); 175552196Smckusick } 175639488Smckusick static char hextoasc[] = "0123456789abcdef"; 175738414Smckusick 175838414Smckusick /* 175938414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 176038414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 176138414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 176238414Smckusick * nfsnode. There is the potential for another process on a different client 176338414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 176438414Smckusick * nfs_rename() completes, but... 176538414Smckusick */ 176652234Sheideman int 176752317Sheideman nfs_sillyrename(dvp, vp, cnp) 176852234Sheideman struct vnode *dvp, *vp; 176952234Sheideman struct componentname *cnp; 177038414Smckusick { 177138414Smckusick register struct nfsnode *np; 177238414Smckusick register struct sillyrename *sp; 177338414Smckusick int error; 177438414Smckusick short pid; 177538414Smckusick 177652234Sheideman cache_purge(dvp); 177752234Sheideman np = VTONFS(vp); 177851986Smckusick #ifdef SILLYSEPARATE 177938414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 178048364Smckusick M_NFSREQ, M_WAITOK); 178151986Smckusick #else 178251986Smckusick sp = &np->n_silly; 178351986Smckusick #endif 178452234Sheideman sp->s_cred = crdup(cnp->cn_cred); 178552234Sheideman sp->s_dvp = dvp; 178652234Sheideman VREF(dvp); 178738414Smckusick 178838414Smckusick /* Fudge together a funny name */ 178952234Sheideman pid = cnp->cn_proc->p_pid; 179048364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 179148364Smckusick sp->s_namlen = 12; 179248364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 179348364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 179448364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 179548364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 179638414Smckusick 179738414Smckusick /* Try lookitups until we get one that isn't there */ 179852234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 179948364Smckusick sp->s_name[4]++; 180048364Smckusick if (sp->s_name[4] > 'z') { 180138414Smckusick error = EINVAL; 180238414Smckusick goto bad; 180338414Smckusick } 180438414Smckusick } 180552234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 180638414Smckusick goto bad; 180752234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 180838414Smckusick np->n_sillyrename = sp; 180938414Smckusick return (0); 181038414Smckusick bad: 181148364Smckusick vrele(sp->s_dvp); 181248364Smckusick crfree(sp->s_cred); 181351986Smckusick #ifdef SILLYSEPARATE 181448364Smckusick free((caddr_t)sp, M_NFSREQ); 181551986Smckusick #endif 181638414Smckusick return (error); 181738414Smckusick } 181838414Smckusick 181938414Smckusick /* 182038414Smckusick * Look up a file name for silly rename stuff. 182138414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 182238414Smckusick * into the nfsnode table. 182338414Smckusick * If fhp != NULL it copies the returned file handle out 182438414Smckusick */ 182552234Sheideman int 182652196Smckusick nfs_lookitup(sp, fhp, procp) 182748364Smckusick register struct sillyrename *sp; 182838414Smckusick nfsv2fh_t *fhp; 182952196Smckusick struct proc *procp; 183038414Smckusick { 183148364Smckusick register struct vnode *vp = sp->s_dvp; 183248054Smckusick register u_long *tl; 183339488Smckusick register caddr_t cp; 183439488Smckusick register long t1, t2; 183539488Smckusick caddr_t bpos, dpos, cp2; 183639488Smckusick u_long xid; 183739488Smckusick int error = 0; 183839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 183938414Smckusick long len; 184038414Smckusick 184138414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 184248364Smckusick len = sp->s_namlen; 184352196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 184438414Smckusick nfsm_fhtom(vp); 184548364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 184652196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 184738414Smckusick if (fhp != NULL) { 184852196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 184938414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 185038414Smckusick } 185138414Smckusick nfsm_reqdone; 185238414Smckusick return (error); 185338414Smckusick } 185438414Smckusick 185538414Smckusick /* 185638414Smckusick * Kludge City.. 185738414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 185841905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 185938414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 186038414Smckusick * nfsiobuf area. 186138414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 186238414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 186338414Smckusick * a lot more work than bcopy() and also it currently happens in the 186438414Smckusick * context of the swapper process (2). 186538414Smckusick */ 186652234Sheideman int 186753806Smckusick nfs_bmap(ap) 186854668Smckusick struct vop_bmap_args /* { 186954668Smckusick struct vnode *a_vp; 187054668Smckusick daddr_t a_bn; 187154668Smckusick struct vnode **a_vpp; 187254668Smckusick daddr_t *a_bnp; 187354668Smckusick } */ *ap; 187438414Smckusick { 187553806Smckusick register struct vnode *vp = ap->a_vp; 187653806Smckusick 187753600Sheideman if (ap->a_vpp != NULL) 187853806Smckusick *ap->a_vpp = vp; 187953600Sheideman if (ap->a_bnp != NULL) 188053806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 188138414Smckusick return (0); 188238414Smckusick } 188338414Smckusick 188438414Smckusick /* 188538884Smacklem * Strategy routine for phys. i/o 188638884Smacklem * If the biod's are running, queue a request 188738884Smacklem * otherwise just call nfs_doio() to get it done 188838414Smckusick */ 188952234Sheideman int 189053806Smckusick nfs_strategy(ap) 189154668Smckusick struct vop_strategy_args /* { 189254668Smckusick struct buf *a_bp; 189354668Smckusick } */ *ap; 189438414Smckusick { 189553806Smckusick register struct buf *bp = ap->a_bp; 189638884Smacklem register struct buf *dp; 189739341Smckusick register int i; 189838884Smacklem int error = 0; 189939341Smckusick int fnd = 0; 190038884Smacklem 190138884Smacklem /* 190241905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 190341905Smckusick * doesn't set it, I will. 190446450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 190541905Smckusick * be hanging about after the process terminates. 190641905Smckusick */ 190753806Smckusick if ((bp->b_flags & B_PHYS) == 0) { 190853806Smckusick if (bp->b_flags & B_ASYNC) 190953806Smckusick bp->b_proc = (struct proc *)0; 191046988Smckusick else 191153806Smckusick bp->b_proc = curproc; 191246988Smckusick } 191341905Smckusick /* 191446450Skarels * If the op is asynchronous and an i/o daemon is waiting 191538884Smacklem * queue the request, wake it up and wait for completion 191646450Skarels * otherwise just do it ourselves. 191738884Smacklem */ 191853806Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 191953806Smckusick return (nfs_doio(bp)); 192046988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 192146988Smckusick if (nfs_iodwant[i]) { 192239341Smckusick dp = &nfs_bqueue; 192339341Smckusick if (dp->b_actf == NULL) { 192453806Smckusick dp->b_actl = bp; 192553806Smckusick bp->b_actf = dp; 192639341Smckusick } else { 192753806Smckusick dp->b_actf->b_actl = bp; 192853806Smckusick bp->b_actf = dp->b_actf; 192939341Smckusick } 193053806Smckusick dp->b_actf = bp; 193153806Smckusick bp->b_actl = dp; 193239341Smckusick fnd++; 193339341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 193439341Smckusick break; 193538884Smacklem } 193639341Smckusick } 193739341Smckusick if (!fnd) 193853806Smckusick error = nfs_doio(bp); 193938884Smacklem return (error); 194038884Smacklem } 194138884Smacklem 194238884Smacklem /* 194338884Smacklem * Fun and games with i/o 194438884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 194538884Smacklem * mapping the data buffer into kernel virtual space and doing the 194638884Smacklem * nfs read or write rpc's from it. 194741905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 194841905Smckusick * otherwise it is called by the nfsiods to do what would normally be 194938884Smacklem * partially disk interrupt driven. 195038884Smacklem */ 195152234Sheideman int 195238884Smacklem nfs_doio(bp) 195338884Smacklem register struct buf *bp; 195438884Smacklem { 195538414Smckusick register struct uio *uiop; 195638414Smckusick register struct vnode *vp; 195739341Smckusick struct nfsnode *np; 195838884Smacklem struct ucred *cr; 195941539Smckusick int error; 196041539Smckusick struct uio uio; 196141539Smckusick struct iovec io; 196238414Smckusick 196338414Smckusick vp = bp->b_vp; 196440251Smckusick np = VTONFS(vp); 196538414Smckusick uiop = &uio; 196638414Smckusick uiop->uio_iov = &io; 196738414Smckusick uiop->uio_iovcnt = 1; 196838414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 196952196Smckusick uiop->uio_procp = bp->b_proc; 197039751Smckusick 197138414Smckusick /* 197238884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 197338884Smacklem * the Nfsiomap pte's 197438884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 197538884Smacklem * and a guess at a group 197638414Smckusick */ 197738884Smacklem if (bp->b_flags & B_PHYS) { 197848054Smckusick if (bp->b_flags & B_DIRTY) 197948054Smckusick uiop->uio_procp = pageproc; 198048054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 198141539Smckusick /* mapping was already done by vmapbuf */ 198241539Smckusick io.iov_base = bp->b_un.b_addr; 198339751Smckusick 198438884Smacklem /* 198539751Smckusick * And do the i/o rpc 198639751Smckusick */ 198739751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 198839823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 198939751Smckusick if (bp->b_flags & B_READ) { 199039751Smckusick uiop->uio_rw = UIO_READ; 199139751Smckusick nfsstats.read_physios++; 199248054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 199345717Smckusick (void) vnode_pager_uncache(vp); 199439751Smckusick } else { 199539751Smckusick uiop->uio_rw = UIO_WRITE; 199639751Smckusick nfsstats.write_physios++; 199748054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 199839341Smckusick } 199939751Smckusick 200039751Smckusick /* 200139751Smckusick * Finally, release pte's used by physical i/o 200239751Smckusick */ 200338884Smacklem crfree(cr); 200439751Smckusick } else { 200539751Smckusick if (bp->b_flags & B_READ) { 200639751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 200739751Smckusick io.iov_base = bp->b_un.b_addr; 200839751Smckusick uiop->uio_rw = UIO_READ; 200941905Smckusick switch (vp->v_type) { 201041905Smckusick case VREG: 201141905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 201241905Smckusick nfsstats.read_bios++; 201348054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 201441905Smckusick break; 201541905Smckusick case VLNK: 201641905Smckusick uiop->uio_offset = 0; 201741905Smckusick nfsstats.readlink_bios++; 201848054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 201941905Smckusick break; 202041905Smckusick case VDIR: 202141905Smckusick uiop->uio_offset = bp->b_lblkno; 202241905Smckusick nfsstats.readdir_bios++; 202352196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK) 202452196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 202552196Smckusick else 202652196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 202741905Smckusick /* 202841905Smckusick * Save offset cookie in b_blkno. 202941905Smckusick */ 203041905Smckusick bp->b_blkno = uiop->uio_offset; 203141905Smckusick break; 203241905Smckusick }; 203341905Smckusick bp->b_error = error; 203439751Smckusick } else { 203539751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 203639751Smckusick - bp->b_dirtyoff; 203739823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 203839751Smckusick + bp->b_dirtyoff; 203939751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 204039751Smckusick uiop->uio_rw = UIO_WRITE; 204139751Smckusick nfsstats.write_bios++; 204241905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 204348054Smckusick bp->b_wcred); 204439751Smckusick if (error) { 204539751Smckusick np->n_error = error; 204639751Smckusick np->n_flag |= NWRITEERR; 204739751Smckusick } 204839751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 204939751Smckusick } 205038884Smacklem } 205139751Smckusick if (error) 205239751Smckusick bp->b_flags |= B_ERROR; 205339751Smckusick bp->b_resid = uiop->uio_resid; 205438414Smckusick biodone(bp); 205538414Smckusick return (error); 205638414Smckusick } 205738884Smacklem 205838884Smacklem /* 205948054Smckusick * Mmap a file 206048054Smckusick * 206148054Smckusick * NB Currently unsupported. 206248054Smckusick */ 206348054Smckusick /* ARGSUSED */ 206452234Sheideman int 206553806Smckusick nfs_mmap(ap) 206654668Smckusick struct vop_mmap_args /* { 206754668Smckusick struct vnode *a_vp; 206854668Smckusick int a_fflags; 206954668Smckusick struct ucred *a_cred; 207054668Smckusick struct proc *a_p; 207154668Smckusick } */ *ap; 207248054Smckusick { 207348054Smckusick 207448054Smckusick return (EINVAL); 207548054Smckusick } 207648054Smckusick 207748054Smckusick /* 207838884Smacklem * Flush all the blocks associated with a vnode. 207938884Smacklem * Walk through the buffer pool and push any dirty pages 208038884Smacklem * associated with the vnode. 208138884Smacklem */ 208239488Smckusick /* ARGSUSED */ 208352234Sheideman int 208453806Smckusick nfs_fsync(ap) 208554451Smckusick struct vop_fsync_args /* { 208654451Smckusick struct vnodeop_desc *a_desc; 208754451Smckusick struct vnode * a_vp; 208854451Smckusick struct ucred * a_cred; 208954451Smckusick int a_waitfor; 209054451Smckusick struct proc * a_p; 209154451Smckusick } */ *ap; 209238884Smacklem { 209354451Smckusick register struct vnode *vp = ap->a_vp; 209454451Smckusick register struct nfsnode *np = VTONFS(vp); 209554451Smckusick register struct buf *bp; 209654451Smckusick struct buf *nbp; 209754451Smckusick int s, error = 0; 209838884Smacklem 209954451Smckusick loop: 210054451Smckusick s = splbio(); 210154451Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 210254451Smckusick nbp = bp->b_blockf; 210354451Smckusick if ((bp->b_flags & B_BUSY)) 210454451Smckusick continue; 210554451Smckusick if ((bp->b_flags & B_DELWRI) == 0) 210654451Smckusick panic("nfs_fsync: not dirty"); 210754451Smckusick bremfree(bp); 210854451Smckusick bp->b_flags |= B_BUSY; 210954451Smckusick splx(s); 211054451Smckusick error = bawrite(bp); 211154451Smckusick goto loop; 211238884Smacklem } 211354451Smckusick if (ap->a_waitfor == MNT_WAIT) { 211454451Smckusick while (vp->v_numoutput) { 211554451Smckusick vp->v_flag |= VBWAIT; 211654451Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 211754451Smckusick } 211854451Smckusick #ifdef DIAGNOSTIC 211954451Smckusick if (vp->v_dirtyblkhd) { 212054451Smckusick vprint("nfs_fsync: dirty", vp); 212154451Smckusick goto loop; 212254451Smckusick } 212354451Smckusick #endif 212454451Smckusick } 212554451Smckusick splx(s); 212654451Smckusick np->n_flag &= ~NMODIFIED; 212753629Smckusick if (np->n_flag & NWRITEERR) { 212839751Smckusick error = np->n_error; 212953629Smckusick np->n_flag &= ~NWRITEERR; 213053629Smckusick } 213138884Smacklem return (error); 213238884Smacklem } 213339672Smckusick 213439672Smckusick /* 213546201Smckusick * NFS advisory byte-level locks. 213646201Smckusick * Currently unsupported. 213746201Smckusick */ 213852234Sheideman int 213953806Smckusick nfs_advlock(ap) 214054668Smckusick struct vop_advlock_args /* { 214154668Smckusick struct vnode *a_vp; 214254668Smckusick caddr_t a_id; 214354668Smckusick int a_op; 214454668Smckusick struct flock *a_fl; 214554668Smckusick int a_flags; 214654668Smckusick } */ *ap; 214746201Smckusick { 214846201Smckusick 214946201Smckusick return (EOPNOTSUPP); 215046201Smckusick } 215146201Smckusick 215246201Smckusick /* 215339672Smckusick * Print out the contents of an nfsnode. 215439672Smckusick */ 215552234Sheideman int 215653806Smckusick nfs_print(ap) 215754668Smckusick struct vop_print_args /* { 215854668Smckusick struct vnode *a_vp; 215954668Smckusick } */ *ap; 216039672Smckusick { 216153806Smckusick register struct vnode *vp = ap->a_vp; 216253806Smckusick register struct nfsnode *np = VTONFS(vp); 216339672Smckusick 216440294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 216540294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 216640294Smckusick #ifdef FIFO 216753806Smckusick if (vp->v_type == VFIFO) 216853806Smckusick fifo_printinfo(vp); 216940294Smckusick #endif /* FIFO */ 217039914Smckusick printf("\n"); 217139672Smckusick } 217251573Smckusick 217351573Smckusick /* 217451573Smckusick * NFS directory offset lookup. 217551573Smckusick * Currently unsupported. 217651573Smckusick */ 217752234Sheideman int 217853806Smckusick nfs_blkatoff(ap) 217954668Smckusick struct vop_blkatoff_args /* { 218054668Smckusick struct vnode *a_vp; 218154668Smckusick off_t a_offset; 218254668Smckusick char **a_res; 218354668Smckusick struct buf **a_bpp; 218454668Smckusick } */ *ap; 218551573Smckusick { 218651573Smckusick 218751573Smckusick return (EOPNOTSUPP); 218851573Smckusick } 218951573Smckusick 219051573Smckusick /* 219151573Smckusick * NFS flat namespace allocation. 219251573Smckusick * Currently unsupported. 219351573Smckusick */ 219452234Sheideman int 219553806Smckusick nfs_valloc(ap) 219654668Smckusick struct vop_valloc_args /* { 219754668Smckusick struct vnode *a_pvp; 219854668Smckusick int a_mode; 219954668Smckusick struct ucred *a_cred; 220054668Smckusick struct vnode **a_vpp; 220154668Smckusick } */ *ap; 220251573Smckusick { 220351573Smckusick 220451573Smckusick return (EOPNOTSUPP); 220551573Smckusick } 220651573Smckusick 220751573Smckusick /* 220851573Smckusick * NFS flat namespace free. 220951573Smckusick * Currently unsupported. 221051573Smckusick */ 221153582Sheideman int 221253806Smckusick nfs_vfree(ap) 221354668Smckusick struct vop_vfree_args /* { 221454668Smckusick struct vnode *a_pvp; 221554668Smckusick ino_t a_ino; 221654668Smckusick int a_mode; 221754668Smckusick } */ *ap; 221851573Smckusick { 221951573Smckusick 222053582Sheideman return (EOPNOTSUPP); 222151573Smckusick } 222251573Smckusick 222351573Smckusick /* 222451573Smckusick * NFS file truncation. 222551573Smckusick */ 222652234Sheideman int 222753806Smckusick nfs_truncate(ap) 222854668Smckusick struct vop_truncate_args /* { 222954668Smckusick struct vnode *a_vp; 223054668Smckusick off_t a_length; 223154668Smckusick int a_flags; 223254668Smckusick struct ucred *a_cred; 223354668Smckusick struct proc *a_p; 223454668Smckusick } */ *ap; 223551573Smckusick { 223651573Smckusick 223751573Smckusick /* Use nfs_setattr */ 223851573Smckusick printf("nfs_truncate: need to implement!!"); 223951573Smckusick return (EOPNOTSUPP); 224051573Smckusick } 224151573Smckusick 224251573Smckusick /* 224351573Smckusick * NFS update. 224451573Smckusick */ 224552234Sheideman int 224653806Smckusick nfs_update(ap) 224754668Smckusick struct vop_update_args /* { 224854668Smckusick struct vnode *a_vp; 224954668Smckusick struct timeval *a_ta; 225054668Smckusick struct timeval *a_tm; 225154668Smckusick int a_waitfor; 225254668Smckusick } */ *ap; 225351573Smckusick { 225451573Smckusick 225551573Smckusick /* Use nfs_setattr */ 225651573Smckusick printf("nfs_update: need to implement!!"); 225751573Smckusick return (EOPNOTSUPP); 225851573Smckusick } 225953629Smckusick 226053629Smckusick /* 226153629Smckusick * Read wrapper for special devices. 226253629Smckusick */ 226353629Smckusick int 226453629Smckusick nfsspec_read(ap) 226554668Smckusick struct vop_read_args /* { 226654668Smckusick struct vnode *a_vp; 226754668Smckusick struct uio *a_uio; 226854668Smckusick int a_ioflag; 226954668Smckusick struct ucred *a_cred; 227054668Smckusick } */ *ap; 227153629Smckusick { 227253629Smckusick extern int (**spec_vnodeop_p)(); 227354032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 227453629Smckusick 227553629Smckusick /* 227653629Smckusick * Set access flag. 227753629Smckusick */ 227854032Smckusick np->n_flag |= NACC; 227954032Smckusick np->n_atim = time; 228053629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 228153629Smckusick } 228253629Smckusick 228353629Smckusick /* 228453629Smckusick * Write wrapper for special devices. 228553629Smckusick */ 228653629Smckusick int 228753629Smckusick nfsspec_write(ap) 228854668Smckusick struct vop_write_args /* { 228954668Smckusick struct vnode *a_vp; 229054668Smckusick struct uio *a_uio; 229154668Smckusick int a_ioflag; 229254668Smckusick struct ucred *a_cred; 229354668Smckusick } */ *ap; 229453629Smckusick { 229553629Smckusick extern int (**spec_vnodeop_p)(); 229654032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 229753629Smckusick 229853629Smckusick /* 229954032Smckusick * Set update flag. 230053629Smckusick */ 230154032Smckusick np->n_flag |= NUPD; 230254032Smckusick np->n_mtim = time; 230353629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 230453629Smckusick } 230553629Smckusick 230653629Smckusick /* 230753629Smckusick * Close wrapper for special devices. 230853629Smckusick * 230953629Smckusick * Update the times on the nfsnode then do device close. 231053629Smckusick */ 231153629Smckusick int 231253629Smckusick nfsspec_close(ap) 231354668Smckusick struct vop_close_args /* { 231454668Smckusick struct vnode *a_vp; 231554668Smckusick int a_fflag; 231654668Smckusick struct ucred *a_cred; 231754668Smckusick struct proc *a_p; 231854668Smckusick } */ *ap; 231953629Smckusick { 232053806Smckusick register struct vnode *vp = ap->a_vp; 232153806Smckusick register struct nfsnode *np = VTONFS(vp); 232253629Smckusick struct vattr vattr; 232353629Smckusick extern int (**spec_vnodeop_p)(); 232453629Smckusick 232553629Smckusick if (np->n_flag & (NACC | NUPD)) { 232653629Smckusick if (np->n_flag & NACC) 232753629Smckusick np->n_atim = time; 232853629Smckusick if (np->n_flag & NUPD) 232953629Smckusick np->n_mtim = time; 233053629Smckusick np->n_flag |= NCHG; 233153806Smckusick if (vp->v_usecount == 1 && 233253806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 233353629Smckusick VATTR_NULL(&vattr); 233454106Smckusick if (np->n_flag & NACC) { 233554106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 233654106Smckusick vattr.va_atime.ts_nsec = 233754106Smckusick np->n_atim.tv_usec * 1000; 233854106Smckusick } 233954106Smckusick if (np->n_flag & NUPD) { 234054106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 234154106Smckusick vattr.va_mtime.ts_nsec = 234254106Smckusick np->n_mtim.tv_usec * 1000; 234354106Smckusick } 234453806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 234553629Smckusick } 234653629Smckusick } 234753629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 234853629Smckusick } 234953629Smckusick 235053629Smckusick #ifdef FIFO 235153629Smckusick /* 235253629Smckusick * Read wrapper for fifos. 235353629Smckusick */ 235453629Smckusick int 235553629Smckusick nfsfifo_read(ap) 235654668Smckusick struct vop_read_args /* { 235754668Smckusick struct vnode *a_vp; 235854668Smckusick struct uio *a_uio; 235954668Smckusick int a_ioflag; 236054668Smckusick struct ucred *a_cred; 236154668Smckusick } */ *ap; 236253629Smckusick { 236353629Smckusick extern int (**fifo_vnodeop_p)(); 236454032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 236553629Smckusick 236653629Smckusick /* 236753629Smckusick * Set access flag. 236853629Smckusick */ 236954032Smckusick np->n_flag |= NACC; 237054032Smckusick np->n_atim = time; 237153629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 237253629Smckusick } 237353629Smckusick 237453629Smckusick /* 237553629Smckusick * Write wrapper for fifos. 237653629Smckusick */ 237753629Smckusick int 237853629Smckusick nfsfifo_write(ap) 237954668Smckusick struct vop_write_args /* { 238054668Smckusick struct vnode *a_vp; 238154668Smckusick struct uio *a_uio; 238254668Smckusick int a_ioflag; 238354668Smckusick struct ucred *a_cred; 238454668Smckusick } */ *ap; 238553629Smckusick { 238653629Smckusick extern int (**fifo_vnodeop_p)(); 238754032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 238853629Smckusick 238953629Smckusick /* 239053629Smckusick * Set update flag. 239153629Smckusick */ 239254032Smckusick np->n_flag |= NUPD; 239354032Smckusick np->n_mtim = time; 239453629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 239553629Smckusick } 239653629Smckusick 239753629Smckusick /* 239853629Smckusick * Close wrapper for fifos. 239953629Smckusick * 240053629Smckusick * Update the times on the nfsnode then do fifo close. 240153629Smckusick */ 240253629Smckusick int 240353629Smckusick nfsfifo_close(ap) 240454668Smckusick struct vop_close_args /* { 240554668Smckusick struct vnode *a_vp; 240654668Smckusick int a_fflag; 240754668Smckusick struct ucred *a_cred; 240854668Smckusick struct proc *a_p; 240954668Smckusick } */ *ap; 241053629Smckusick { 241153806Smckusick register struct vnode *vp = ap->a_vp; 241253806Smckusick register struct nfsnode *np = VTONFS(vp); 241353629Smckusick struct vattr vattr; 241453629Smckusick extern int (**fifo_vnodeop_p)(); 241553629Smckusick 241653629Smckusick if (np->n_flag & (NACC | NUPD)) { 241753629Smckusick if (np->n_flag & NACC) 241853629Smckusick np->n_atim = time; 241953629Smckusick if (np->n_flag & NUPD) 242053629Smckusick np->n_mtim = time; 242153629Smckusick np->n_flag |= NCHG; 242253806Smckusick if (vp->v_usecount == 1 && 242353806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 242453629Smckusick VATTR_NULL(&vattr); 242554106Smckusick if (np->n_flag & NACC) { 242654106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 242754106Smckusick vattr.va_atime.ts_nsec = 242854106Smckusick np->n_atim.tv_usec * 1000; 242954106Smckusick } 243054106Smckusick if (np->n_flag & NUPD) { 243154106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 243254106Smckusick vattr.va_mtime.ts_nsec = 243354106Smckusick np->n_mtim.tv_usec * 1000; 243454106Smckusick } 243553806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 243653629Smckusick } 243753629Smckusick } 243853629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 243953629Smckusick } 244053629Smckusick #endif /* FIFO */ 2441