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*54986Smckusick * @(#)nfs_vnops.c 7.87 (Berkeley) 07/12/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/specdev.h> 2953322Smckusick #include <sys/fifo.h> 3053322Smckusick #include <sys/map.h> 3154740Smckusick #include <sys/dirent.h> 3247573Skarels 3353322Smckusick #include <vm/vm.h> 3438414Smckusick 3553322Smckusick #include <nfs/rpcv2.h> 3653322Smckusick #include <nfs/nfsv2.h> 3753322Smckusick #include <nfs/nfs.h> 3853322Smckusick #include <nfs/nfsnode.h> 3953322Smckusick #include <nfs/nfsmount.h> 4053322Smckusick #include <nfs/xdr_subs.h> 4153322Smckusick #include <nfs/nfsm_subs.h> 4253322Smckusick #include <nfs/nqnfs.h> 4353322Smckusick 4438414Smckusick /* Defs */ 4538414Smckusick #define TRUE 1 4638414Smckusick #define FALSE 0 4738414Smckusick 4848054Smckusick /* 4948054Smckusick * Global vfs data structures for nfs 5048054Smckusick */ 5153554Sheideman int (**nfsv2_vnodeop_p)(); 5253554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 5353554Sheideman { &vop_default_desc, vn_default_error }, 5453806Smckusick { &vop_lookup_desc, nfs_lookup }, /* lookup */ 5553806Smckusick { &vop_create_desc, nfs_create }, /* create */ 5653554Sheideman { &vop_mknod_desc, nfs_mknod }, /* mknod */ 5753554Sheideman { &vop_open_desc, nfs_open }, /* open */ 5853554Sheideman { &vop_close_desc, nfs_close }, /* close */ 5953806Smckusick { &vop_access_desc, nfs_access }, /* access */ 6053806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 6153806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 6253554Sheideman { &vop_read_desc, nfs_read }, /* read */ 6353554Sheideman { &vop_write_desc, nfs_write }, /* write */ 6453554Sheideman { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ 6553806Smckusick { &vop_select_desc, nfs_select }, /* select */ 6653554Sheideman { &vop_mmap_desc, nfs_mmap }, /* mmap */ 6753554Sheideman { &vop_fsync_desc, nfs_fsync }, /* fsync */ 6853554Sheideman { &vop_seek_desc, nfs_seek }, /* seek */ 6953806Smckusick { &vop_remove_desc, nfs_remove }, /* remove */ 7053554Sheideman { &vop_link_desc, nfs_link }, /* link */ 7153806Smckusick { &vop_rename_desc, nfs_rename }, /* rename */ 7253554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 7353554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 7453806Smckusick { &vop_symlink_desc, nfs_symlink }, /* symlink */ 7553806Smckusick { &vop_readdir_desc, nfs_readdir }, /* readdir */ 7653806Smckusick { &vop_readlink_desc, nfs_readlink }, /* readlink */ 7753806Smckusick { &vop_abortop_desc, nfs_abortop }, /* abortop */ 7853806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 7953806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 8053554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 8153806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 8253554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */ 8353806Smckusick { &vop_strategy_desc, nfs_strategy }, /* strategy */ 8453554Sheideman { &vop_print_desc, nfs_print }, /* print */ 8553806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 8653806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8753806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 8853806Smckusick { &vop_valloc_desc, nfs_valloc }, /* valloc */ 8953554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */ 9053806Smckusick { &vop_truncate_desc, nfs_truncate }, /* truncate */ 9153806Smckusick { &vop_update_desc, nfs_update }, /* update */ 9253582Sheideman { &vop_bwrite_desc, vn_bwrite }, 9353554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 9438414Smckusick }; 9553554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 9653554Sheideman { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 9738414Smckusick 9848054Smckusick /* 9948054Smckusick * Special device vnode ops 10048054Smckusick */ 10153554Sheideman int (**spec_nfsv2nodeop_p)(); 10253554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 10353554Sheideman { &vop_default_desc, vn_default_error }, 10453806Smckusick { &vop_lookup_desc, spec_lookup }, /* lookup */ 10553806Smckusick { &vop_create_desc, spec_create }, /* create */ 10653806Smckusick { &vop_mknod_desc, spec_mknod }, /* mknod */ 10753554Sheideman { &vop_open_desc, spec_open }, /* open */ 10853806Smckusick { &vop_close_desc, nfsspec_close }, /* close */ 10953806Smckusick { &vop_access_desc, nfs_access }, /* access */ 11053806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 11153806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 11253806Smckusick { &vop_read_desc, nfsspec_read }, /* read */ 11353806Smckusick { &vop_write_desc, nfsspec_write }, /* write */ 11453806Smckusick { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 11553806Smckusick { &vop_select_desc, spec_select }, /* select */ 11653554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 11754451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 11853554Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 11953806Smckusick { &vop_remove_desc, spec_remove }, /* remove */ 12053554Sheideman { &vop_link_desc, spec_link }, /* link */ 12153806Smckusick { &vop_rename_desc, spec_rename }, /* rename */ 12253806Smckusick { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 12353806Smckusick { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 12453806Smckusick { &vop_symlink_desc, spec_symlink }, /* symlink */ 12553806Smckusick { &vop_readdir_desc, spec_readdir }, /* readdir */ 12653806Smckusick { &vop_readlink_desc, spec_readlink }, /* readlink */ 12753806Smckusick { &vop_abortop_desc, spec_abortop }, /* abortop */ 12853806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 12953806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 13053554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 13153806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 13253554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 13353806Smckusick { &vop_strategy_desc, spec_strategy }, /* strategy */ 13453554Sheideman { &vop_print_desc, nfs_print }, /* print */ 13553806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 13653806Smckusick { &vop_advlock_desc, spec_advlock }, /* advlock */ 13753806Smckusick { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 13853806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */ 13953806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */ 14053806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */ 14153806Smckusick { &vop_update_desc, nfs_update }, /* update */ 14253582Sheideman { &vop_bwrite_desc, vn_bwrite }, 14353554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 14438414Smckusick }; 14553554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 14653554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 14738414Smckusick 14840294Smckusick #ifdef FIFO 14953554Sheideman int (**fifo_nfsv2nodeop_p)(); 15053554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 15153554Sheideman { &vop_default_desc, vn_default_error }, 15253806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15353806Smckusick { &vop_create_desc, fifo_create }, /* create */ 15453806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15553554Sheideman { &vop_open_desc, fifo_open }, /* open */ 15653806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 15753806Smckusick { &vop_access_desc, nfs_access }, /* access */ 15853806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 15953806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 16053806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 16153806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16253806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16353806Smckusick { &vop_select_desc, fifo_select }, /* select */ 16453554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16554451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 16653554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 16753806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */ 16853554Sheideman { &vop_link_desc, fifo_link }, /* link */ 16953806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */ 17053806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17153806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17253806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17353806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17453806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17553806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17653806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 17753806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 17853554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 17953806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18053554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18153806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */ 18253554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18353806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 18453806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18553806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 18653806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */ 18753806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */ 18853806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */ 18953806Smckusick { &vop_update_desc, nfs_update }, /* update */ 19053582Sheideman { &vop_bwrite_desc, vn_bwrite }, 19153554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 19240294Smckusick }; 19353554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 19453554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 19540294Smckusick #endif /* FIFO */ 19640294Smckusick 19748054Smckusick /* 19852196Smckusick * Global variables 19948054Smckusick */ 20038414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 20138414Smckusick extern u_long nfs_prog, nfs_vers; 20238414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20338884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 20441905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 20546988Smckusick int nfs_numasync = 0; 20654740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 20738414Smckusick 20838414Smckusick /* 20938414Smckusick * nfs null call from vfs. 21038414Smckusick */ 21152234Sheideman int 21252196Smckusick nfs_null(vp, cred, procp) 21338414Smckusick struct vnode *vp; 21438414Smckusick struct ucred *cred; 21552196Smckusick struct proc *procp; 21638414Smckusick { 21739488Smckusick caddr_t bpos, dpos; 21839488Smckusick int error = 0; 21939488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22038414Smckusick 22152196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22252196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 22338414Smckusick nfsm_reqdone; 22438414Smckusick return (error); 22538414Smckusick } 22638414Smckusick 22738414Smckusick /* 22838414Smckusick * nfs access vnode op. 22938414Smckusick * Essentially just get vattr and then imitate iaccess() 23038414Smckusick */ 23152234Sheideman int 23253806Smckusick nfs_access(ap) 23354668Smckusick struct vop_access_args /* { 23454668Smckusick struct vnode *a_vp; 23554668Smckusick int a_mode; 23654668Smckusick struct ucred *a_cred; 23754668Smckusick struct proc *a_p; 23854668Smckusick } */ *ap; 23938414Smckusick { 24038414Smckusick register struct vattr *vap; 24138414Smckusick register gid_t *gp; 24253806Smckusick register struct ucred *cred = ap->a_cred; 24353806Smckusick mode_t mode = ap->a_mode; 24438414Smckusick struct vattr vattr; 24538414Smckusick register int i; 24638414Smckusick int error; 24738414Smckusick 24838414Smckusick /* 24938414Smckusick * If you're the super-user, 25038414Smckusick * you always get access. 25138414Smckusick */ 25253806Smckusick if (cred->cr_uid == 0) 25338414Smckusick return (0); 25438414Smckusick vap = &vattr; 25553806Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 25638884Smacklem return (error); 25738414Smckusick /* 25838414Smckusick * Access check is based on only one of owner, group, public. 25938414Smckusick * If not owner, then check group. If not a member of the 26038414Smckusick * group, then check public access. 26138414Smckusick */ 26253806Smckusick if (cred->cr_uid != vap->va_uid) { 26353806Smckusick mode >>= 3; 26453806Smckusick gp = cred->cr_groups; 26553806Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 26638414Smckusick if (vap->va_gid == *gp) 26738414Smckusick goto found; 26853806Smckusick mode >>= 3; 26938414Smckusick found: 27038414Smckusick ; 27138414Smckusick } 27253806Smckusick if ((vap->va_mode & mode) != 0) 27338414Smckusick return (0); 27438414Smckusick return (EACCES); 27538414Smckusick } 27638414Smckusick 27738414Smckusick /* 27838414Smckusick * nfs open vnode op 27938414Smckusick * Just check to see if the type is ok 28052196Smckusick * and that deletion is not in progress. 28138414Smckusick */ 28239488Smckusick /* ARGSUSED */ 28352234Sheideman int 28453806Smckusick nfs_open(ap) 28554668Smckusick struct vop_open_args /* { 28654668Smckusick struct vnode *a_vp; 28754668Smckusick int a_mode; 28854668Smckusick struct ucred *a_cred; 28954668Smckusick struct proc *a_p; 29054668Smckusick } */ *ap; 29138414Smckusick { 29253806Smckusick register struct vnode *vp = ap->a_vp; 29338414Smckusick 29453806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 29538414Smckusick return (EACCES); 29653806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 29753806Smckusick VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */ 29852196Smckusick return (0); 29938414Smckusick } 30038414Smckusick 30138414Smckusick /* 30238414Smckusick * nfs close vnode op 30338884Smacklem * For reg files, invalidate any buffer cache entries. 30438414Smckusick */ 30539488Smckusick /* ARGSUSED */ 30652234Sheideman int 30753806Smckusick nfs_close(ap) 30854451Smckusick struct vop_close_args /* { 30954451Smckusick struct vnodeop_desc *a_desc; 31054451Smckusick struct vnode *a_vp; 31154451Smckusick int a_fflag; 31254451Smckusick struct ucred *a_cred; 31354451Smckusick struct proc *a_p; 31454451Smckusick } */ *ap; 31538414Smckusick { 31653806Smckusick register struct vnode *vp = ap->a_vp; 31753806Smckusick register struct nfsnode *np = VTONFS(vp); 31839341Smckusick int error = 0; 31938414Smckusick 32053806Smckusick if (vp->v_type == VREG) { 32153806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 32253629Smckusick (np->n_flag & NMODIFIED)) { 32354451Smckusick error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 32441905Smckusick np->n_flag &= ~NMODIFIED; 32541905Smckusick np->n_attrstamp = 0; 32653629Smckusick } 32753629Smckusick if (np->n_flag & NWRITEERR) { 32853629Smckusick np->n_flag &= ~NWRITEERR; 32953629Smckusick error = np->n_error; 33053629Smckusick } 33138884Smacklem } 33238414Smckusick return (error); 33338414Smckusick } 33438414Smckusick 33538414Smckusick /* 33638414Smckusick * nfs getattr call from vfs. 33738414Smckusick */ 33852234Sheideman int 33953805Smckusick nfs_getattr(ap) 34054668Smckusick struct vop_getattr_args /* { 34154668Smckusick struct vnode *a_vp; 34254668Smckusick struct vattr *a_vap; 34354668Smckusick struct ucred *a_cred; 34454668Smckusick struct proc *a_p; 34554668Smckusick } */ *ap; 34638414Smckusick { 34753805Smckusick register struct vnode *vp = ap->a_vp; 34853805Smckusick register struct nfsnode *np = VTONFS(vp); 34939488Smckusick register caddr_t cp; 35039488Smckusick caddr_t bpos, dpos; 35139488Smckusick int error = 0; 35239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 35338414Smckusick 35453805Smckusick /* 35553805Smckusick * Update local times for special files. 35653805Smckusick */ 35753805Smckusick if (np->n_flag & (NACC | NUPD)) { 35853805Smckusick if (np->n_flag & NACC) 35953805Smckusick np->n_atim = time; 36053805Smckusick if (np->n_flag & NUPD) 36153805Smckusick np->n_mtim = time; 36253805Smckusick np->n_flag |= NCHG; 36353805Smckusick } 36453805Smckusick /* 36553805Smckusick * First look in the cache. 36653805Smckusick */ 36753805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 36838414Smckusick return (0); 36938414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 37053805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 37153805Smckusick nfsm_fhtom(vp); 37253805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 37353805Smckusick nfsm_loadattr(vp, ap->a_vap); 37438414Smckusick nfsm_reqdone; 37538414Smckusick return (error); 37638414Smckusick } 37738414Smckusick 37838414Smckusick /* 37938414Smckusick * nfs setattr call. 38038414Smckusick */ 38152234Sheideman int 38253806Smckusick nfs_setattr(ap) 38354451Smckusick struct vop_setattr_args /* { 38454451Smckusick struct vnodeop_desc *a_desc; 38554451Smckusick struct vnode *a_vp; 38654451Smckusick struct vattr *a_vap; 38754451Smckusick struct ucred *a_cred; 38854451Smckusick struct proc *a_p; 38954451Smckusick } */ *ap; 39038414Smckusick { 39138884Smacklem register struct nfsv2_sattr *sp; 39239488Smckusick register caddr_t cp; 39339488Smckusick register long t1; 39452196Smckusick caddr_t bpos, dpos, cp2; 39552196Smckusick u_long *tl; 39639488Smckusick int error = 0; 39739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 39853806Smckusick register struct vnode *vp = ap->a_vp; 39953806Smckusick register struct nfsnode *np = VTONFS(vp); 40053806Smckusick register struct vattr *vap = ap->a_vap; 40152196Smckusick u_quad_t frev; 40238414Smckusick 40338414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 40453806Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR); 40553806Smckusick nfsm_fhtom(vp); 40638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 40753806Smckusick if (vap->va_mode == 0xffff) 40838884Smacklem sp->sa_mode = VNOVAL; 40938414Smckusick else 41053806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 41153806Smckusick if (vap->va_uid == 0xffff) 41238884Smacklem sp->sa_uid = VNOVAL; 41338414Smckusick else 41453806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 41553806Smckusick if (vap->va_gid == 0xffff) 41638884Smacklem sp->sa_gid = VNOVAL; 41738414Smckusick else 41853806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 41953806Smckusick sp->sa_size = txdr_unsigned(vap->va_size); 42054106Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.ts_sec); 42153806Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 42253806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 42354106Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || 42454106Smckusick vap->va_atime.ts_sec != VNOVAL) { 42539359Smckusick if (np->n_flag & NMODIFIED) { 42653806Smckusick if (vap->va_size == 0) 42754451Smckusick error = 42854451Smckusick vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p); 42946988Smckusick else 43054451Smckusick error = 43154451Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 43254451Smckusick np->n_flag &= ~NMODIFIED; 43339359Smckusick } 43439359Smckusick } 43553806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 43653806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 43753806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 43853806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 43952196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 44052196Smckusick fxdr_hyper(tl, &frev); 44154451Smckusick if (frev > np->n_brev) 44252196Smckusick np->n_brev = frev; 44352196Smckusick } 44438414Smckusick nfsm_reqdone; 44538414Smckusick return (error); 44638414Smckusick } 44738414Smckusick 44838414Smckusick /* 44938414Smckusick * nfs lookup call, one step at a time... 45038414Smckusick * First look in cache 45138414Smckusick * If not found, unlock the directory nfsnode and do the rpc 45238414Smckusick */ 45352234Sheideman int 45453806Smckusick nfs_lookup(ap) 45554451Smckusick struct vop_lookup_args /* { 45654451Smckusick struct vnodeop_desc *a_desc; 45754451Smckusick struct vnode *a_dvp; 45854451Smckusick struct vnode **a_vpp; 45954451Smckusick struct componentname *a_cnp; 46054451Smckusick } */ *ap; 46138414Smckusick { 46253806Smckusick register struct componentname *cnp = ap->a_cnp; 46353806Smckusick register struct vnode *dvp = ap->a_dvp; 46454668Smckusick register struct vnode **vpp = ap->a_vpp; 46538414Smckusick register struct vnode *vdp; 46648054Smckusick register u_long *tl; 46739488Smckusick register caddr_t cp; 46839488Smckusick register long t1, t2; 46952196Smckusick struct nfsmount *nmp; 47052196Smckusick struct nfsnode *tp; 47139488Smckusick caddr_t bpos, dpos, cp2; 47252196Smckusick time_t reqtime; 47339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 47438414Smckusick struct vnode *newvp; 47538414Smckusick long len; 47638414Smckusick nfsv2fh_t *fhp; 47738414Smckusick struct nfsnode *np; 47852234Sheideman int lockparent, wantparent, error = 0; 47952196Smckusick int nqlflag, cachable; 48052196Smckusick u_quad_t frev; 48138414Smckusick 48254668Smckusick *vpp = NULL; 48353806Smckusick if (dvp->v_type != VDIR) 48438414Smckusick return (ENOTDIR); 48553806Smckusick lockparent = cnp->cn_flags & LOCKPARENT; 48653806Smckusick wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 48753806Smckusick nmp = VFSTONFS(dvp->v_mount); 48853806Smckusick np = VTONFS(dvp); 48954668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 49038884Smacklem struct vattr vattr; 49138884Smacklem int vpid; 49238884Smacklem 49354668Smckusick vdp = *vpp; 49438884Smacklem vpid = vdp->v_id; 49538414Smckusick /* 49638884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 49738884Smacklem * for an explanation of the locking protocol 49838414Smckusick */ 49953806Smckusick if (dvp == vdp) { 50038425Smckusick VREF(vdp); 50139441Smckusick error = 0; 50252196Smckusick } else 50339441Smckusick error = vget(vdp); 50439441Smckusick if (!error) { 50540251Smckusick if (vpid == vdp->v_id) { 50652196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 50753806Smckusick if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 50854451Smckusick if (np->n_lrev != np->n_brev || 50952196Smckusick (np->n_flag & NMODIFIED)) { 51052196Smckusick np->n_direofoffset = 0; 51153806Smckusick cache_purge(dvp); 51254451Smckusick error = vinvalbuf(dvp, FALSE, 51354451Smckusick cnp->cn_cred, cnp->cn_proc); 51452196Smckusick np->n_flag &= ~NMODIFIED; 51552196Smckusick np->n_brev = np->n_lrev; 51652196Smckusick } else { 51752196Smckusick nfsstats.lookupcache_hits++; 51853806Smckusick if (cnp->cn_nameiop != LOOKUP && 51953806Smckusick (cnp->cn_flags&ISLASTCN)) 52053806Smckusick cnp->cn_flags |= SAVENAME; 52152196Smckusick return (0); 52252196Smckusick } 52352196Smckusick } 52453806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 52554106Smckusick vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { 52639441Smckusick nfsstats.lookupcache_hits++; 52753806Smckusick if (cnp->cn_nameiop != LOOKUP && 52853806Smckusick (cnp->cn_flags&ISLASTCN)) 52953806Smckusick cnp->cn_flags |= SAVENAME; 53039441Smckusick return (0); 53140251Smckusick } 53247289Smckusick cache_purge(vdp); 53339441Smckusick } 53452196Smckusick vrele(vdp); 53538884Smacklem } 53654668Smckusick *vpp = NULLVP; 53752196Smckusick } 53839341Smckusick error = 0; 53938414Smckusick nfsstats.lookupcache_misses++; 54038414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 54153806Smckusick len = cnp->cn_namelen; 54253806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 54352196Smckusick 54452196Smckusick /* 54552196Smckusick * For nqnfs optionally piggyback a getlease request for the name 54652196Smckusick * being looked up. 54752196Smckusick */ 54852196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 54952196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 55053806Smckusick ((cnp->cn_flags&MAKEENTRY) && 55153806Smckusick (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN)))) { 55252196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 55352196Smckusick *tl++ = txdr_unsigned(NQL_READ); 55452196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 55552196Smckusick } else { 55652196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 55752196Smckusick *tl = 0; 55852196Smckusick } 55952196Smckusick } 56053806Smckusick nfsm_fhtom(dvp); 56153806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 56252196Smckusick reqtime = time.tv_sec; 56353806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 56438414Smckusick nfsmout: 56538414Smckusick if (error) { 56653806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 56753806Smckusick (cnp->cn_flags & ISLASTCN) && error == ENOENT) 56852823Smckusick error = EJUSTRETURN; 56953806Smckusick if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 57053806Smckusick cnp->cn_flags |= SAVENAME; 57140483Smckusick return (error); 57238414Smckusick } 57352196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 57452196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 57552196Smckusick if (*tl) { 57652196Smckusick nqlflag = fxdr_unsigned(int, *tl); 57752196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 57852196Smckusick cachable = fxdr_unsigned(int, *tl++); 57952196Smckusick reqtime += fxdr_unsigned(int, *tl++); 58052196Smckusick fxdr_hyper(tl, &frev); 58152196Smckusick } else 58252196Smckusick nqlflag = 0; 58352196Smckusick } 58452196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 58538414Smckusick 58638414Smckusick /* 58752196Smckusick * Handle RENAME case... 58838414Smckusick */ 58953806Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (cnp->cn_flags&ISLASTCN)) { 59052196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 59138414Smckusick m_freem(mrep); 59238414Smckusick return (EISDIR); 59338414Smckusick } 59453806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 59538414Smckusick m_freem(mrep); 59638414Smckusick return (error); 59738414Smckusick } 59838414Smckusick newvp = NFSTOV(np); 59939459Smckusick if (error = 60039459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 60152196Smckusick vrele(newvp); 60238414Smckusick m_freem(mrep); 60338414Smckusick return (error); 60438414Smckusick } 60554668Smckusick *vpp = newvp; 60645037Smckusick m_freem(mrep); 60753806Smckusick cnp->cn_flags |= SAVENAME; 60838414Smckusick return (0); 60938414Smckusick } 61038414Smckusick 61152196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 61253806Smckusick VREF(dvp); 61353806Smckusick newvp = dvp; 61438414Smckusick } else { 61553806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 61638414Smckusick m_freem(mrep); 61738414Smckusick return (error); 61838414Smckusick } 61938414Smckusick newvp = NFSTOV(np); 62038414Smckusick } 62139459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 62252196Smckusick vrele(newvp); 62338414Smckusick m_freem(mrep); 62438414Smckusick return (error); 62538414Smckusick } 62638414Smckusick m_freem(mrep); 62754668Smckusick *vpp = newvp; 62853806Smckusick if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 62953806Smckusick cnp->cn_flags |= SAVENAME; 63053806Smckusick if ((cnp->cn_flags&MAKEENTRY) && 63153806Smckusick (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN))) { 63252196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 63354106Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec; 63452196Smckusick else if (nqlflag && reqtime > time.tv_sec) { 63552196Smckusick if (np->n_tnext) { 63652196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 63752196Smckusick nmp->nm_tprev = np->n_tprev; 63852196Smckusick else 63952196Smckusick np->n_tnext->n_tprev = np->n_tprev; 64052196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 64152196Smckusick nmp->nm_tnext = np->n_tnext; 64252196Smckusick else 64352196Smckusick np->n_tprev->n_tnext = np->n_tnext; 64452196Smckusick if (nqlflag == NQL_WRITE) 64552196Smckusick np->n_flag |= NQNFSWRITE; 64652196Smckusick } else if (nqlflag == NQL_READ) 64752196Smckusick np->n_flag &= ~NQNFSWRITE; 64852196Smckusick else 64952196Smckusick np->n_flag |= NQNFSWRITE; 65052196Smckusick if (cachable) 65152196Smckusick np->n_flag &= ~NQNFSNONCACHE; 65252196Smckusick else 65352196Smckusick np->n_flag |= NQNFSNONCACHE; 65452196Smckusick np->n_expiry = reqtime; 65552196Smckusick np->n_lrev = frev; 65652196Smckusick tp = nmp->nm_tprev; 65752196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 65852196Smckusick tp = tp->n_tprev; 65952196Smckusick if (tp == (struct nfsnode *)nmp) { 66052196Smckusick np->n_tnext = nmp->nm_tnext; 66152196Smckusick nmp->nm_tnext = np; 66252196Smckusick } else { 66352196Smckusick np->n_tnext = tp->n_tnext; 66452196Smckusick tp->n_tnext = np; 66552196Smckusick } 66652196Smckusick np->n_tprev = tp; 66752196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 66852196Smckusick nmp->nm_tprev = np; 66952196Smckusick else 67052196Smckusick np->n_tnext->n_tprev = np; 67152196Smckusick } 67254668Smckusick cache_enter(dvp, *vpp, cnp); 67340251Smckusick } 67452196Smckusick return (0); 67538414Smckusick } 67638414Smckusick 67738414Smckusick /* 67841905Smckusick * nfs read call. 67941905Smckusick * Just call nfs_bioread() to do the work. 68041905Smckusick */ 68152234Sheideman int 68253806Smckusick nfs_read(ap) 68354668Smckusick struct vop_read_args /* { 68454668Smckusick struct vnode *a_vp; 68554668Smckusick struct uio *a_uio; 68654668Smckusick int a_ioflag; 68754668Smckusick struct ucred *a_cred; 68854668Smckusick } */ *ap; 68941905Smckusick { 69053806Smckusick register struct vnode *vp = ap->a_vp; 69153806Smckusick 69253806Smckusick if (vp->v_type != VREG) 69341905Smckusick return (EPERM); 69453806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 69541905Smckusick } 69641905Smckusick 69741905Smckusick /* 69838414Smckusick * nfs readlink call 69938414Smckusick */ 70052234Sheideman int 70153806Smckusick nfs_readlink(ap) 70254668Smckusick struct vop_readlink_args /* { 70354668Smckusick struct vnode *a_vp; 70454668Smckusick struct uio *a_uio; 70554668Smckusick struct ucred *a_cred; 70654668Smckusick } */ *ap; 70741905Smckusick { 70853806Smckusick register struct vnode *vp = ap->a_vp; 70953806Smckusick 71053806Smckusick if (vp->v_type != VLNK) 71141905Smckusick return (EPERM); 71253806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 71341905Smckusick } 71441905Smckusick 71541905Smckusick /* 71641905Smckusick * Do a readlink rpc. 71741905Smckusick * Called by nfs_doio() from below the buffer cache. 71841905Smckusick */ 71952234Sheideman int 72048054Smckusick nfs_readlinkrpc(vp, uiop, cred) 72139488Smckusick register struct vnode *vp; 72238414Smckusick struct uio *uiop; 72338414Smckusick struct ucred *cred; 72438414Smckusick { 72548054Smckusick register u_long *tl; 72639488Smckusick register caddr_t cp; 72739488Smckusick register long t1; 72839488Smckusick caddr_t bpos, dpos, cp2; 72939488Smckusick int error = 0; 73039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73138414Smckusick long len; 73238414Smckusick 73338414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 73452196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 73538414Smckusick nfsm_fhtom(vp); 73652196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 73738414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 73838414Smckusick nfsm_mtouio(uiop, len); 73938414Smckusick nfsm_reqdone; 74038414Smckusick return (error); 74138414Smckusick } 74238414Smckusick 74338414Smckusick /* 74441905Smckusick * nfs read rpc call 74541905Smckusick * Ditto above 74638414Smckusick */ 74752234Sheideman int 74848054Smckusick nfs_readrpc(vp, uiop, cred) 74939488Smckusick register struct vnode *vp; 75038414Smckusick struct uio *uiop; 75138414Smckusick struct ucred *cred; 75238414Smckusick { 75348054Smckusick register u_long *tl; 75439488Smckusick register caddr_t cp; 75539488Smckusick register long t1; 75639488Smckusick caddr_t bpos, dpos, cp2; 75739488Smckusick int error = 0; 75839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 75938414Smckusick struct nfsmount *nmp; 76038414Smckusick long len, retlen, tsiz; 76138414Smckusick 76241398Smckusick nmp = VFSTONFS(vp->v_mount); 76338414Smckusick tsiz = uiop->uio_resid; 76438414Smckusick while (tsiz > 0) { 76538414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 76638414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 76752196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 76838414Smckusick nfsm_fhtom(vp); 76948054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 77048054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 77148054Smckusick *tl++ = txdr_unsigned(len); 77248054Smckusick *tl = 0; 77352196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 77438414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 77538414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 77638414Smckusick nfsm_mtouio(uiop, retlen); 77738414Smckusick m_freem(mrep); 77838414Smckusick if (retlen < len) 77938414Smckusick tsiz = 0; 78038414Smckusick else 78138414Smckusick tsiz -= len; 78238414Smckusick } 78338414Smckusick nfsmout: 78438414Smckusick return (error); 78538414Smckusick } 78638414Smckusick 78738414Smckusick /* 78838414Smckusick * nfs write call 78938414Smckusick */ 79052234Sheideman int 79148054Smckusick nfs_writerpc(vp, uiop, cred) 79239488Smckusick register struct vnode *vp; 79338414Smckusick struct uio *uiop; 79438414Smckusick struct ucred *cred; 79538414Smckusick { 79648054Smckusick register u_long *tl; 79739488Smckusick register caddr_t cp; 79839488Smckusick register long t1; 79952196Smckusick caddr_t bpos, dpos, cp2; 80039488Smckusick int error = 0; 80139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 80238414Smckusick struct nfsmount *nmp; 80352196Smckusick struct nfsnode *np = VTONFS(vp); 80452196Smckusick u_quad_t frev; 80538414Smckusick long len, tsiz; 80638414Smckusick 80741398Smckusick nmp = VFSTONFS(vp->v_mount); 80838414Smckusick tsiz = uiop->uio_resid; 80938414Smckusick while (tsiz > 0) { 81038414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 81138414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 81252196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 81352196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 81438414Smckusick nfsm_fhtom(vp); 81548054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 81648054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 81748054Smckusick *(tl+3) = txdr_unsigned(len); 81838414Smckusick nfsm_uiotom(uiop, len); 81952196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 82038414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 82152196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 82254106Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; 82352196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 82452196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 82552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 82652196Smckusick fxdr_hyper(tl, &frev); 82754451Smckusick if (frev > np->n_brev) 82852196Smckusick np->n_brev = frev; 82952196Smckusick } 83038414Smckusick m_freem(mrep); 83138414Smckusick tsiz -= len; 83238414Smckusick } 83338414Smckusick nfsmout: 83452196Smckusick if (error) 83552196Smckusick uiop->uio_resid = tsiz; 83638414Smckusick return (error); 83738414Smckusick } 83838414Smckusick 83938414Smckusick /* 84039459Smckusick * nfs mknod call 84142246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 84242246Smckusick * set to specify the file type and the size field for rdev. 84339459Smckusick */ 84439459Smckusick /* ARGSUSED */ 84552234Sheideman int 84653806Smckusick nfs_mknod(ap) 84754668Smckusick struct vop_mknod_args /* { 84854668Smckusick struct vnode *a_dvp; 84954668Smckusick struct vnode **a_vpp; 85054668Smckusick struct componentname *a_cnp; 85154668Smckusick struct vattr *a_vap; 85254668Smckusick } */ *ap; 85339459Smckusick { 85453806Smckusick register struct vnode *dvp = ap->a_dvp; 85553806Smckusick register struct vattr *vap = ap->a_vap; 85653806Smckusick register struct componentname *cnp = ap->a_cnp; 85742246Smckusick register struct nfsv2_sattr *sp; 85848054Smckusick register u_long *tl; 85942246Smckusick register caddr_t cp; 86052196Smckusick register long t2; 86142246Smckusick caddr_t bpos, dpos; 86242246Smckusick int error = 0; 86342246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 86442246Smckusick u_long rdev; 86539459Smckusick 86653806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 86753806Smckusick rdev = txdr_unsigned(vap->va_rdev); 86842246Smckusick #ifdef FIFO 86953806Smckusick else if (vap->va_type == VFIFO) 87042246Smckusick rdev = 0xffffffff; 87142246Smckusick #endif /* FIFO */ 87242246Smckusick else { 87353806Smckusick VOP_ABORTOP(dvp, cnp); 87453806Smckusick vput(dvp); 87542246Smckusick return (EOPNOTSUPP); 87642246Smckusick } 87742246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 87853806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 87953806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 88053806Smckusick nfsm_fhtom(dvp); 88153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 88242246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 88353806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 88453806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 88553806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 88642246Smckusick sp->sa_size = rdev; 88742246Smckusick /* or should these be VNOVAL ?? */ 88853806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 88953806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 89053806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 89142246Smckusick nfsm_reqdone; 89253806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 89353806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 89453806Smckusick vrele(dvp); 89542246Smckusick return (error); 89639459Smckusick } 89739459Smckusick 89839459Smckusick /* 89938414Smckusick * nfs file create call 90038414Smckusick */ 90152234Sheideman int 90253806Smckusick nfs_create(ap) 90354668Smckusick struct vop_create_args /* { 90454668Smckusick struct vnode *a_dvp; 90554668Smckusick struct vnode **a_vpp; 90654668Smckusick struct componentname *a_cnp; 90754668Smckusick struct vattr *a_vap; 90854668Smckusick } */ *ap; 90938414Smckusick { 91053806Smckusick register struct vnode *dvp = ap->a_dvp; 91153806Smckusick register struct vattr *vap = ap->a_vap; 91253806Smckusick register struct componentname *cnp = ap->a_cnp; 91338884Smacklem register struct nfsv2_sattr *sp; 91448054Smckusick register u_long *tl; 91539488Smckusick register caddr_t cp; 91639488Smckusick register long t1, t2; 91739488Smckusick caddr_t bpos, dpos, cp2; 91839488Smckusick int error = 0; 91939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92038414Smckusick 92138414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 92253806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 92353806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 92453806Smckusick nfsm_fhtom(dvp); 92553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 92638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 92753806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 92853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 92953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 93038884Smacklem sp->sa_size = txdr_unsigned(0); 93138414Smckusick /* or should these be VNOVAL ?? */ 93253806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 93353806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 93453806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 93553806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 93638414Smckusick nfsm_reqdone; 93753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 93853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 93953806Smckusick vrele(dvp); 94038414Smckusick return (error); 94138414Smckusick } 94238414Smckusick 94338414Smckusick /* 94438414Smckusick * nfs file remove call 94541905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 94641905Smckusick * other processes using the vnode is renamed instead of removed and then 94739341Smckusick * removed later on the last close. 94841905Smckusick * - If v_usecount > 1 94939341Smckusick * If a rename is not already in the works 95039341Smckusick * call nfs_sillyrename() to set it up 95139341Smckusick * else 95239341Smckusick * do the remove rpc 95338414Smckusick */ 95452234Sheideman int 95553806Smckusick nfs_remove(ap) 95654451Smckusick struct vop_remove_args /* { 95754451Smckusick struct vnodeop_desc *a_desc; 95854451Smckusick struct vnode * a_dvp; 95954451Smckusick struct vnode * a_vp; 96054451Smckusick struct componentname * a_cnp; 96154451Smckusick } */ *ap; 96238414Smckusick { 96353806Smckusick register struct vnode *vp = ap->a_vp; 96453806Smckusick register struct vnode *dvp = ap->a_dvp; 96553806Smckusick register struct componentname *cnp = ap->a_cnp; 96653806Smckusick register struct nfsnode *np = VTONFS(vp); 96748054Smckusick register u_long *tl; 96839488Smckusick register caddr_t cp; 96952196Smckusick register long t2; 97039488Smckusick caddr_t bpos, dpos; 97139488Smckusick int error = 0; 97239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97338414Smckusick 97453806Smckusick if (vp->v_usecount > 1) { 97539341Smckusick if (!np->n_sillyrename) 97653806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 97739341Smckusick } else { 97852196Smckusick /* 97952196Smckusick * Purge the name cache so that the chance of a lookup for 98052196Smckusick * the name succeeding while the remove is in progress is 98152196Smckusick * minimized. Without node locking it can still happen, such 98252196Smckusick * that an I/O op returns ESTALE, but since you get this if 98352196Smckusick * another host removes the file.. 98452196Smckusick */ 98553806Smckusick cache_purge(vp); 98652196Smckusick /* 98752196Smckusick * Throw away biocache buffers. Mainly to avoid 98852196Smckusick * unnecessary delayed writes. 98952196Smckusick */ 99054451Smckusick error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc); 99152196Smckusick /* Do the rpc */ 99238414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 99353806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 99453806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 99553806Smckusick nfsm_fhtom(dvp); 99653806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 99753806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 99838414Smckusick nfsm_reqdone; 99953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 100053806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 100139751Smckusick /* 100239751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 100339751Smckusick * the reply to the retransmitted request will be ENOENT 100439751Smckusick * since the file was in fact removed 100539751Smckusick * Therefore, we cheat and return success. 100639751Smckusick */ 100739751Smckusick if (error == ENOENT) 100839751Smckusick error = 0; 100938414Smckusick } 101040042Smckusick np->n_attrstamp = 0; 101153806Smckusick vrele(dvp); 101253806Smckusick vrele(vp); 101338414Smckusick return (error); 101438414Smckusick } 101538414Smckusick 101638414Smckusick /* 101738414Smckusick * nfs file remove rpc called from nfs_inactive 101838414Smckusick */ 101952234Sheideman int 102054451Smckusick nfs_removeit(sp) 102148364Smckusick register struct sillyrename *sp; 102238414Smckusick { 102348054Smckusick register u_long *tl; 102439488Smckusick register caddr_t cp; 102552196Smckusick register long t2; 102639488Smckusick caddr_t bpos, dpos; 102739488Smckusick int error = 0; 102839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 102938414Smckusick 103038414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 103152196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 103248364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 103348364Smckusick nfsm_fhtom(sp->s_dvp); 103448364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 103554451Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); 103638414Smckusick nfsm_reqdone; 103748364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 103838414Smckusick return (error); 103938414Smckusick } 104038414Smckusick 104138414Smckusick /* 104238414Smckusick * nfs file rename call 104338414Smckusick */ 104452234Sheideman int 104553806Smckusick nfs_rename(ap) 104654668Smckusick struct vop_rename_args /* { 104754668Smckusick struct vnode *a_fdvp; 104854668Smckusick struct vnode *a_fvp; 104954668Smckusick struct componentname *a_fcnp; 105054668Smckusick struct vnode *a_tdvp; 105154668Smckusick struct vnode *a_tvp; 105254668Smckusick struct componentname *a_tcnp; 105354668Smckusick } */ *ap; 105438414Smckusick { 105553806Smckusick register struct vnode *fvp = ap->a_fvp; 105653806Smckusick register struct vnode *tvp = ap->a_tvp; 105753806Smckusick register struct vnode *fdvp = ap->a_fdvp; 105853806Smckusick register struct vnode *tdvp = ap->a_tdvp; 105953806Smckusick register struct componentname *tcnp = ap->a_tcnp; 106053806Smckusick register struct componentname *fcnp = ap->a_fcnp; 106148054Smckusick register u_long *tl; 106239488Smckusick register caddr_t cp; 106352196Smckusick register long t2; 106439488Smckusick caddr_t bpos, dpos; 106539488Smckusick int error = 0; 106639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 106738414Smckusick 106853804Spendry /* Check for cross-device rename */ 106953806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 107053806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 107153804Spendry error = EXDEV; 107253804Spendry goto out; 107353804Spendry } 107453804Spendry 107553804Spendry 107638414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 107753806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 107853806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 107953806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 108053806Smckusick nfsm_fhtom(fdvp); 108153806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 108253806Smckusick nfsm_fhtom(tdvp); 108353806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 108453806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 108538414Smckusick nfsm_reqdone; 108653806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 108753806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 108853806Smckusick if (fvp->v_type == VDIR) { 108953806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 109053806Smckusick cache_purge(tdvp); 109153806Smckusick cache_purge(fdvp); 109238414Smckusick } 109353804Spendry out: 109453806Smckusick if (tdvp == tvp) 109553806Smckusick vrele(tdvp); 109643360Smckusick else 109753806Smckusick vput(tdvp); 109853806Smckusick if (tvp) 109953806Smckusick vput(tvp); 110053806Smckusick vrele(fdvp); 110153806Smckusick vrele(fvp); 110240112Smckusick /* 110340112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 110440112Smckusick */ 110540112Smckusick if (error == ENOENT) 110640112Smckusick error = 0; 110738414Smckusick return (error); 110838414Smckusick } 110938414Smckusick 111038414Smckusick /* 111141905Smckusick * nfs file rename rpc called from nfs_remove() above 111238414Smckusick */ 111352234Sheideman int 111452234Sheideman nfs_renameit(sdvp, scnp, sp) 111552234Sheideman struct vnode *sdvp; 111652234Sheideman struct componentname *scnp; 111748364Smckusick register struct sillyrename *sp; 111838414Smckusick { 111948054Smckusick register u_long *tl; 112039488Smckusick register caddr_t cp; 112152196Smckusick register long t2; 112239488Smckusick caddr_t bpos, dpos; 112339488Smckusick int error = 0; 112439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 112538414Smckusick 112638414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 112752234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 112852234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 112952196Smckusick nfsm_rndup(sp->s_namlen)); 113052234Sheideman nfsm_fhtom(sdvp); 113152234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 113252234Sheideman nfsm_fhtom(sdvp); 113348364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 113452234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 113538414Smckusick nfsm_reqdone; 113652234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 113752234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 113838414Smckusick return (error); 113938414Smckusick } 114038414Smckusick 114138414Smckusick /* 114238414Smckusick * nfs hard link create call 114338414Smckusick */ 114452234Sheideman int 114553806Smckusick nfs_link(ap) 114654668Smckusick struct vop_link_args /* { 114754668Smckusick struct vnode *a_vp; 114854668Smckusick struct vnode *a_tdvp; 114954668Smckusick struct componentname *a_cnp; 115054668Smckusick } */ *ap; 115138414Smckusick { 115253806Smckusick register struct vnode *vp = ap->a_vp; 115353806Smckusick register struct vnode *tdvp = ap->a_tdvp; 115453806Smckusick register struct componentname *cnp = ap->a_cnp; 115548054Smckusick register u_long *tl; 115639488Smckusick register caddr_t cp; 115752196Smckusick register long t2; 115839488Smckusick caddr_t bpos, dpos; 115939488Smckusick int error = 0; 116039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 116138414Smckusick 116253806Smckusick if (vp->v_mount != tdvp->v_mount) { 116353806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 116453806Smckusick if (tdvp == vp) 116553806Smckusick vrele(vp); 116653804Spendry else 116753806Smckusick vput(vp); 116853804Spendry return (EXDEV); 116953804Spendry } 117053804Spendry 117138414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 117253806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 117353806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 117453806Smckusick nfsm_fhtom(tdvp); 117553806Smckusick nfsm_fhtom(vp); 117653806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 117753806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 117838414Smckusick nfsm_reqdone; 117953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 118053806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 118153806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 118253806Smckusick vrele(vp); 118340112Smckusick /* 118440112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 118540112Smckusick */ 118640112Smckusick if (error == EEXIST) 118740112Smckusick error = 0; 118838414Smckusick return (error); 118938414Smckusick } 119038414Smckusick 119138414Smckusick /* 119238414Smckusick * nfs symbolic link create call 119338414Smckusick */ 119452234Sheideman /* start here */ 119552234Sheideman int 119653806Smckusick nfs_symlink(ap) 119754668Smckusick struct vop_symlink_args /* { 119854668Smckusick struct vnode *a_dvp; 119954668Smckusick struct vnode **a_vpp; 120054668Smckusick struct componentname *a_cnp; 120154668Smckusick struct vattr *a_vap; 120254668Smckusick char *a_target; 120354668Smckusick } */ *ap; 120438414Smckusick { 120553806Smckusick register struct vnode *dvp = ap->a_dvp; 120653806Smckusick register struct vattr *vap = ap->a_vap; 120753806Smckusick register struct componentname *cnp = ap->a_cnp; 120838884Smacklem register struct nfsv2_sattr *sp; 120948054Smckusick register u_long *tl; 121039488Smckusick register caddr_t cp; 121152196Smckusick register long t2; 121239488Smckusick caddr_t bpos, dpos; 121352196Smckusick int slen, error = 0; 121439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 121538414Smckusick 121638414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 121753600Sheideman slen = strlen(ap->a_target); 121853806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 121953806Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR); 122053806Smckusick nfsm_fhtom(dvp); 122153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 122253600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 122338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 122453806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 122553806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 122653806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 122738884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 122853806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 122953806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 123053806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 123138414Smckusick nfsm_reqdone; 123253806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 123353806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 123453806Smckusick vrele(dvp); 123540112Smckusick /* 123640112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 123740112Smckusick */ 123840112Smckusick if (error == EEXIST) 123940112Smckusick error = 0; 124038414Smckusick return (error); 124138414Smckusick } 124238414Smckusick 124338414Smckusick /* 124438414Smckusick * nfs make dir call 124538414Smckusick */ 124652234Sheideman int 124753806Smckusick nfs_mkdir(ap) 124854668Smckusick struct vop_mkdir_args /* { 124954668Smckusick struct vnode *a_dvp; 125054668Smckusick struct vnode **a_vpp; 125154668Smckusick struct componentname *a_cnp; 125254668Smckusick struct vattr *a_vap; 125354668Smckusick } */ *ap; 125438414Smckusick { 125553806Smckusick register struct vnode *dvp = ap->a_dvp; 125653806Smckusick register struct vattr *vap = ap->a_vap; 125753806Smckusick register struct componentname *cnp = ap->a_cnp; 125854668Smckusick register struct vnode **vpp = ap->a_vpp; 125938884Smacklem register struct nfsv2_sattr *sp; 126048054Smckusick register u_long *tl; 126139488Smckusick register caddr_t cp; 126239488Smckusick register long t1, t2; 126341905Smckusick register int len; 126439488Smckusick caddr_t bpos, dpos, cp2; 126541905Smckusick int error = 0, firsttry = 1; 126639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 126738414Smckusick 126853806Smckusick len = cnp->cn_namelen; 126938414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 127053806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 127141905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 127253806Smckusick nfsm_fhtom(dvp); 127353806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 127438884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 127553806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 127653806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 127753806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 127838884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 127953806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 128053806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 128153806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 128254668Smckusick nfsm_mtofh(dvp, *vpp); 128338414Smckusick nfsm_reqdone; 128453806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 128540112Smckusick /* 128641905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 128741905Smckusick * if we can succeed in looking up the directory. 128841905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 128941905Smckusick * is above the if on errors. (Ugh) 129040112Smckusick */ 129141905Smckusick if (error == EEXIST && firsttry) { 129241905Smckusick firsttry = 0; 129340112Smckusick error = 0; 129441905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 129554668Smckusick *vpp = NULL; 129653806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 129741905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 129853806Smckusick nfsm_fhtom(dvp); 129953806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 130053806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 130154668Smckusick nfsm_mtofh(dvp, *vpp); 130254668Smckusick if ((*vpp)->v_type != VDIR) { 130354668Smckusick vput(*vpp); 130441905Smckusick error = EEXIST; 130541905Smckusick } 130641905Smckusick m_freem(mrep); 130741905Smckusick } 130853806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 130953806Smckusick vrele(dvp); 131038414Smckusick return (error); 131138414Smckusick } 131238414Smckusick 131338414Smckusick /* 131438414Smckusick * nfs remove directory call 131538414Smckusick */ 131652234Sheideman int 131753806Smckusick nfs_rmdir(ap) 131854668Smckusick struct vop_rmdir_args /* { 131954668Smckusick struct vnode *a_dvp; 132054668Smckusick struct vnode *a_vp; 132154668Smckusick struct componentname *a_cnp; 132254668Smckusick } */ *ap; 132338414Smckusick { 132453806Smckusick register struct vnode *vp = ap->a_vp; 132553806Smckusick register struct vnode *dvp = ap->a_dvp; 132653806Smckusick register struct componentname *cnp = ap->a_cnp; 132748054Smckusick register u_long *tl; 132839488Smckusick register caddr_t cp; 132952196Smckusick register long t2; 133039488Smckusick caddr_t bpos, dpos; 133139488Smckusick int error = 0; 133239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 133338414Smckusick 133453806Smckusick if (dvp == vp) { 133553806Smckusick vrele(dvp); 133653806Smckusick vrele(dvp); 133753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 133838414Smckusick return (EINVAL); 133938414Smckusick } 134038414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 134153806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 134253806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 134353806Smckusick nfsm_fhtom(dvp); 134453806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 134553806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 134638414Smckusick nfsm_reqdone; 134753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 134853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 134953806Smckusick cache_purge(dvp); 135053806Smckusick cache_purge(vp); 135153806Smckusick vrele(vp); 135253806Smckusick vrele(dvp); 135340112Smckusick /* 135440112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 135540112Smckusick */ 135640112Smckusick if (error == ENOENT) 135740112Smckusick error = 0; 135838414Smckusick return (error); 135938414Smckusick } 136038414Smckusick 136138414Smckusick /* 136238414Smckusick * nfs readdir call 136338414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 136438414Smckusick * order so that it looks more sensible. This appears consistent with the 136538414Smckusick * Ultrix implementation of NFS. 136638414Smckusick */ 136752234Sheideman int 136853806Smckusick nfs_readdir(ap) 136954668Smckusick struct vop_readdir_args /* { 137054668Smckusick struct vnode *a_vp; 137154668Smckusick struct uio *a_uio; 137254668Smckusick struct ucred *a_cred; 137354668Smckusick } */ *ap; 137438414Smckusick { 137553806Smckusick register struct vnode *vp = ap->a_vp; 137653806Smckusick register struct nfsnode *np = VTONFS(vp); 137753806Smckusick register struct uio *uio = ap->a_uio; 137841905Smckusick int tresid, error; 137941905Smckusick struct vattr vattr; 138041905Smckusick 138153806Smckusick if (vp->v_type != VDIR) 138241905Smckusick return (EPERM); 138341905Smckusick /* 138441905Smckusick * First, check for hit on the EOF offset cache 138541905Smckusick */ 138653806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 138752196Smckusick (np->n_flag & NMODIFIED) == 0) { 138853806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 138953806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 139052196Smckusick nfsstats.direofcache_hits++; 139152196Smckusick return (0); 139252196Smckusick } 139353806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 139454106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) { 139552196Smckusick nfsstats.direofcache_hits++; 139652196Smckusick return (0); 139752196Smckusick } 139841905Smckusick } 139941905Smckusick 140041905Smckusick /* 140141905Smckusick * Call nfs_bioread() to do the real work. 140241905Smckusick */ 140353806Smckusick tresid = uio->uio_resid; 140453806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 140541905Smckusick 140654451Smckusick if (!error && uio->uio_resid == tresid) 140741905Smckusick nfsstats.direofcache_misses++; 140841905Smckusick return (error); 140941905Smckusick } 141041905Smckusick 141141905Smckusick /* 141241905Smckusick * Readdir rpc call. 141341905Smckusick * Called from below the buffer cache by nfs_doio(). 141441905Smckusick */ 141552234Sheideman int 141648054Smckusick nfs_readdirrpc(vp, uiop, cred) 141741905Smckusick register struct vnode *vp; 141841905Smckusick struct uio *uiop; 141941905Smckusick struct ucred *cred; 142041905Smckusick { 142138414Smckusick register long len; 142254740Smckusick register struct dirent *dp; 142348054Smckusick register u_long *tl; 142439488Smckusick register caddr_t cp; 142539488Smckusick register long t1; 142641905Smckusick long tlen, lastlen; 142739488Smckusick caddr_t bpos, dpos, cp2; 142839488Smckusick int error = 0; 142939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 143038414Smckusick struct mbuf *md2; 143138414Smckusick caddr_t dpos2; 143238414Smckusick int siz; 143340296Smckusick int more_dirs = 1; 143438414Smckusick off_t off, savoff; 143554740Smckusick struct dirent *savdp; 143640296Smckusick struct nfsmount *nmp; 143740296Smckusick struct nfsnode *np = VTONFS(vp); 143840296Smckusick long tresid; 143938414Smckusick 144041398Smckusick nmp = VFSTONFS(vp->v_mount); 144140296Smckusick tresid = uiop->uio_resid; 144240296Smckusick /* 144340296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 144448054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 144541905Smckusick * The stopping criteria is EOF or buffer full. 144640296Smckusick */ 144748054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 144840296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 144952196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 145052196Smckusick NFSX_FH+2*NFSX_UNSIGNED); 145140296Smckusick nfsm_fhtom(vp); 145248054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 145348054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 145448054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 145548054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 145652196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 145740296Smckusick siz = 0; 145852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 145948054Smckusick more_dirs = fxdr_unsigned(int, *tl); 146040296Smckusick 146140296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 146240296Smckusick dpos2 = dpos; 146340296Smckusick md2 = md; 146440296Smckusick 146540296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 146641905Smckusick off = uiop->uio_offset; 146742246Smckusick #ifdef lint 146854740Smckusick dp = (struct dirent *)0; 146942246Smckusick #endif /* lint */ 147040296Smckusick while (more_dirs && siz < uiop->uio_resid) { 147140296Smckusick savoff = off; /* Hold onto offset and dp */ 147240296Smckusick savdp = dp; 147352196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 147454740Smckusick dp = (struct dirent *)tl; 147554740Smckusick dp->d_fileno = fxdr_unsigned(u_long, *tl++); 147648054Smckusick len = fxdr_unsigned(int, *tl); 147740296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 147840296Smckusick error = EBADRPC; 147940296Smckusick m_freem(mrep); 148040296Smckusick goto nfsmout; 148140296Smckusick } 1482*54986Smckusick dp->d_namlen = (u_char)len; 1483*54986Smckusick dp->d_type = DT_UNKNOWN; 148440296Smckusick nfsm_adv(len); /* Point past name */ 148540296Smckusick tlen = nfsm_rndup(len); 148640296Smckusick /* 148740296Smckusick * This should not be necessary, but some servers have 148840296Smckusick * broken XDR such that these bytes are not null filled. 148940296Smckusick */ 149040296Smckusick if (tlen != len) { 149140296Smckusick *dpos = '\0'; /* Null-terminate */ 149240296Smckusick nfsm_adv(tlen - len); 149340296Smckusick len = tlen; 149440296Smckusick } 149552196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 1496*54986Smckusick off = fxdr_unsigned(u_long, *tl); 149748054Smckusick *tl++ = 0; /* Ensures null termination of name */ 149848054Smckusick more_dirs = fxdr_unsigned(int, *tl); 149940296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 150040296Smckusick siz += dp->d_reclen; 150140296Smckusick } 150240296Smckusick /* 150340296Smckusick * If at end of rpc data, get the eof boolean 150440296Smckusick */ 150540296Smckusick if (!more_dirs) { 150652196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 150748054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 150838414Smckusick 150940296Smckusick /* 151040296Smckusick * If at EOF, cache directory offset 151140296Smckusick */ 151241905Smckusick if (!more_dirs) 151340296Smckusick np->n_direofoffset = off; 151438414Smckusick } 151540296Smckusick /* 151640296Smckusick * If there is too much to fit in the data buffer, use savoff and 151740296Smckusick * savdp to trim off the last record. 151840296Smckusick * --> we are not at eof 151940296Smckusick */ 152040296Smckusick if (siz > uiop->uio_resid) { 152140296Smckusick off = savoff; 152240296Smckusick siz -= dp->d_reclen; 152340296Smckusick dp = savdp; 152440296Smckusick more_dirs = 0; /* Paranoia */ 152540113Smckusick } 152640296Smckusick if (siz > 0) { 152741905Smckusick lastlen = dp->d_reclen; 152840296Smckusick md = md2; 152940296Smckusick dpos = dpos2; 153040296Smckusick nfsm_mtouio(uiop, siz); 153140296Smckusick uiop->uio_offset = off; 153240296Smckusick } else 153340296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 153440296Smckusick m_freem(mrep); 153538414Smckusick } 153641905Smckusick /* 153748054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 153841905Smckusick * by increasing d_reclen for the last record. 153941905Smckusick */ 154041905Smckusick if (uiop->uio_resid < tresid) { 154148054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 154241905Smckusick if (len > 0) { 154354740Smckusick dp = (struct dirent *) 154441905Smckusick (uiop->uio_iov->iov_base - lastlen); 154541905Smckusick dp->d_reclen += len; 154641905Smckusick uiop->uio_iov->iov_base += len; 154741905Smckusick uiop->uio_iov->iov_len -= len; 154841905Smckusick uiop->uio_resid -= len; 154941905Smckusick } 155041905Smckusick } 155140296Smckusick nfsmout: 155238414Smckusick return (error); 155338414Smckusick } 155438414Smckusick 155552196Smckusick /* 155652196Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when 155752196Smckusick * the "rdirlook" mount option is specified. 155852196Smckusick */ 155952234Sheideman int 156052196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 156152196Smckusick struct vnode *vp; 156252196Smckusick register struct uio *uiop; 156352196Smckusick struct ucred *cred; 156452196Smckusick { 156552196Smckusick register int len; 156654740Smckusick register struct dirent *dp; 156752196Smckusick register u_long *tl; 156852196Smckusick register caddr_t cp; 156952196Smckusick register long t1; 157052196Smckusick caddr_t bpos, dpos, cp2; 157152196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 157252196Smckusick struct nameidata nami, *ndp = &nami; 157352317Sheideman struct componentname *cnp = &ndp->ni_cnd; 157452196Smckusick off_t off, endoff; 157552196Smckusick time_t reqtime, ltime; 157652196Smckusick struct nfsmount *nmp; 157752196Smckusick struct nfsnode *np, *tp; 157852196Smckusick struct vnode *newvp; 157952196Smckusick nfsv2fh_t *fhp; 158052196Smckusick u_long fileno; 158152196Smckusick u_quad_t frev; 158252196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 158352196Smckusick int cachable; 158452196Smckusick 158552196Smckusick if (uiop->uio_iovcnt != 1) 158652196Smckusick panic("nfs rdirlook"); 158752196Smckusick nmp = VFSTONFS(vp->v_mount); 158852196Smckusick tresid = uiop->uio_resid; 158952196Smckusick ndp->ni_dvp = vp; 159052196Smckusick newvp = NULLVP; 159152196Smckusick /* 159252196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 159352196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 159452196Smckusick * The stopping criteria is EOF or buffer full. 159552196Smckusick */ 159652196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 159752196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 159852196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 159952196Smckusick NFSX_FH+3*NFSX_UNSIGNED); 160052196Smckusick nfsm_fhtom(vp); 160152196Smckusick nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED); 160252196Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 160352196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 160452196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 160552196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 160652196Smckusick reqtime = time.tv_sec; 160752196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 160852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 160952196Smckusick more_dirs = fxdr_unsigned(int, *tl); 161052196Smckusick 161152196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 161252196Smckusick off = uiop->uio_offset; 161352196Smckusick bigenough = 1; 161452196Smckusick while (more_dirs && bigenough) { 161552196Smckusick doit = 1; 161652196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 161752196Smckusick cachable = fxdr_unsigned(int, *tl++); 161852196Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 161952196Smckusick fxdr_hyper(tl, &frev); 162052196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 162152196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 162252196Smckusick VREF(vp); 162352196Smckusick newvp = vp; 162452196Smckusick np = VTONFS(vp); 162552196Smckusick } else { 162652196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 162752196Smckusick doit = 0; 162852196Smckusick newvp = NFSTOV(np); 162952196Smckusick } 163052196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 163152196Smckusick (struct vattr *)0)) 163252196Smckusick doit = 0; 163352196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 163452196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 163552196Smckusick len = fxdr_unsigned(int, *tl); 163652196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 163752196Smckusick error = EBADRPC; 163852196Smckusick m_freem(mrep); 163952196Smckusick goto nfsmout; 164052196Smckusick } 164152196Smckusick tlen = (len + 4) & ~0x3; 164252196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 164352196Smckusick bigenough = 0; 164452196Smckusick if (bigenough && doit) { 164554740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base; 164654740Smckusick dp->d_fileno = fileno; 164752196Smckusick dp->d_namlen = len; 164852196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 1649*54986Smckusick dp->d_type = 1650*54986Smckusick IFTODT(VTTOIF(np->n_vattr.va_type)); 165152196Smckusick uiop->uio_resid -= DIRHDSIZ; 165252196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 165352196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 165452317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 165552317Sheideman cnp->cn_namelen = len; 165652196Smckusick ndp->ni_vp = newvp; 165752196Smckusick nfsm_mtouio(uiop, len); 165852196Smckusick cp = uiop->uio_iov->iov_base; 165952196Smckusick tlen -= len; 166052196Smckusick for (i = 0; i < tlen; i++) 166152196Smckusick *cp++ = '\0'; 166252196Smckusick uiop->uio_iov->iov_base += tlen; 166352196Smckusick uiop->uio_iov->iov_len -= tlen; 166452196Smckusick uiop->uio_resid -= tlen; 166552317Sheideman cnp->cn_hash = 0; 166652317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 166752317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 166852196Smckusick if (ltime > time.tv_sec) { 166952196Smckusick if (np->n_tnext) { 167052196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 167152196Smckusick nmp->nm_tprev = np->n_tprev; 167252196Smckusick else 167352196Smckusick np->n_tnext->n_tprev = np->n_tprev; 167452196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 167552196Smckusick nmp->nm_tnext = np->n_tnext; 167652196Smckusick else 167752196Smckusick np->n_tprev->n_tnext = np->n_tnext; 167852196Smckusick } else 167952196Smckusick np->n_flag &= ~NQNFSWRITE; 168052196Smckusick if (cachable) 168152196Smckusick np->n_flag &= ~NQNFSNONCACHE; 168252196Smckusick else 168352196Smckusick np->n_flag |= NQNFSNONCACHE; 168452196Smckusick np->n_expiry = ltime; 168552196Smckusick np->n_lrev = frev; 168652196Smckusick tp = nmp->nm_tprev; 168752196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 168852196Smckusick tp = tp->n_tprev; 168952196Smckusick if (tp == (struct nfsnode *)nmp) { 169052196Smckusick np->n_tnext = nmp->nm_tnext; 169152196Smckusick nmp->nm_tnext = np; 169252196Smckusick } else { 169352196Smckusick np->n_tnext = tp->n_tnext; 169452196Smckusick tp->n_tnext = np; 169552196Smckusick } 169652196Smckusick np->n_tprev = tp; 169752196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 169852196Smckusick nmp->nm_tprev = np; 169952196Smckusick else 170052196Smckusick np->n_tnext->n_tprev = np; 170152317Sheideman cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 170252196Smckusick } 170352196Smckusick } else { 170452196Smckusick nfsm_adv(nfsm_rndup(len)); 170552196Smckusick } 170652196Smckusick if (newvp != NULLVP) { 170752196Smckusick vrele(newvp); 170852196Smckusick newvp = NULLVP; 170952196Smckusick } 171052196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 171152196Smckusick if (bigenough) 171252196Smckusick endoff = off = fxdr_unsigned(off_t, *tl++); 171352196Smckusick else 171452196Smckusick endoff = fxdr_unsigned(off_t, *tl++); 171552196Smckusick more_dirs = fxdr_unsigned(int, *tl); 171652196Smckusick } 171752196Smckusick /* 171852196Smckusick * If at end of rpc data, get the eof boolean 171952196Smckusick */ 172052196Smckusick if (!more_dirs) { 172152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 172252196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 172352196Smckusick 172452196Smckusick /* 172552196Smckusick * If at EOF, cache directory offset 172652196Smckusick */ 172752196Smckusick if (!more_dirs) 172852196Smckusick VTONFS(vp)->n_direofoffset = endoff; 172952196Smckusick } 173052196Smckusick if (uiop->uio_resid < tresid) 173152196Smckusick uiop->uio_offset = off; 173252196Smckusick else 173352196Smckusick more_dirs = 0; 173452196Smckusick m_freem(mrep); 173552196Smckusick } 173652196Smckusick /* 173752196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 173852196Smckusick * by increasing d_reclen for the last record. 173952196Smckusick */ 174052196Smckusick if (uiop->uio_resid < tresid) { 174152196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 174252196Smckusick if (len > 0) { 174352196Smckusick dp->d_reclen += len; 174452196Smckusick uiop->uio_iov->iov_base += len; 174552196Smckusick uiop->uio_iov->iov_len -= len; 174652196Smckusick uiop->uio_resid -= len; 174752196Smckusick } 174852196Smckusick } 174952196Smckusick nfsmout: 175052196Smckusick if (newvp != NULLVP) 175152196Smckusick vrele(newvp); 175252196Smckusick return (error); 175352196Smckusick } 175439488Smckusick static char hextoasc[] = "0123456789abcdef"; 175538414Smckusick 175638414Smckusick /* 175738414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 175838414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 175938414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 176038414Smckusick * nfsnode. There is the potential for another process on a different client 176138414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 176238414Smckusick * nfs_rename() completes, but... 176338414Smckusick */ 176452234Sheideman int 176552317Sheideman nfs_sillyrename(dvp, vp, cnp) 176652234Sheideman struct vnode *dvp, *vp; 176752234Sheideman struct componentname *cnp; 176838414Smckusick { 176938414Smckusick register struct nfsnode *np; 177038414Smckusick register struct sillyrename *sp; 177138414Smckusick int error; 177238414Smckusick short pid; 177338414Smckusick 177452234Sheideman cache_purge(dvp); 177552234Sheideman np = VTONFS(vp); 177651986Smckusick #ifdef SILLYSEPARATE 177738414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 177848364Smckusick M_NFSREQ, M_WAITOK); 177951986Smckusick #else 178051986Smckusick sp = &np->n_silly; 178151986Smckusick #endif 178252234Sheideman sp->s_cred = crdup(cnp->cn_cred); 178352234Sheideman sp->s_dvp = dvp; 178452234Sheideman VREF(dvp); 178538414Smckusick 178638414Smckusick /* Fudge together a funny name */ 178752234Sheideman pid = cnp->cn_proc->p_pid; 178848364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 178948364Smckusick sp->s_namlen = 12; 179048364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 179148364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 179248364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 179348364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 179438414Smckusick 179538414Smckusick /* Try lookitups until we get one that isn't there */ 179652234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 179748364Smckusick sp->s_name[4]++; 179848364Smckusick if (sp->s_name[4] > 'z') { 179938414Smckusick error = EINVAL; 180038414Smckusick goto bad; 180138414Smckusick } 180238414Smckusick } 180352234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 180438414Smckusick goto bad; 180552234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 180638414Smckusick np->n_sillyrename = sp; 180738414Smckusick return (0); 180838414Smckusick bad: 180948364Smckusick vrele(sp->s_dvp); 181048364Smckusick crfree(sp->s_cred); 181151986Smckusick #ifdef SILLYSEPARATE 181248364Smckusick free((caddr_t)sp, M_NFSREQ); 181351986Smckusick #endif 181438414Smckusick return (error); 181538414Smckusick } 181638414Smckusick 181738414Smckusick /* 181838414Smckusick * Look up a file name for silly rename stuff. 181938414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 182038414Smckusick * into the nfsnode table. 182138414Smckusick * If fhp != NULL it copies the returned file handle out 182238414Smckusick */ 182352234Sheideman int 182452196Smckusick nfs_lookitup(sp, fhp, procp) 182548364Smckusick register struct sillyrename *sp; 182638414Smckusick nfsv2fh_t *fhp; 182752196Smckusick struct proc *procp; 182838414Smckusick { 182948364Smckusick register struct vnode *vp = sp->s_dvp; 183048054Smckusick register u_long *tl; 183139488Smckusick register caddr_t cp; 183239488Smckusick register long t1, t2; 183339488Smckusick caddr_t bpos, dpos, cp2; 183439488Smckusick u_long xid; 183539488Smckusick int error = 0; 183639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 183738414Smckusick long len; 183838414Smckusick 183938414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 184048364Smckusick len = sp->s_namlen; 184152196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 184238414Smckusick nfsm_fhtom(vp); 184348364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 184452196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 184538414Smckusick if (fhp != NULL) { 184652196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 184738414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 184838414Smckusick } 184938414Smckusick nfsm_reqdone; 185038414Smckusick return (error); 185138414Smckusick } 185238414Smckusick 185338414Smckusick /* 185438414Smckusick * Kludge City.. 185538414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 185641905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 185738414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 185838414Smckusick * nfsiobuf area. 185938414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 186038414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 186138414Smckusick * a lot more work than bcopy() and also it currently happens in the 186238414Smckusick * context of the swapper process (2). 186338414Smckusick */ 186452234Sheideman int 186553806Smckusick nfs_bmap(ap) 186654668Smckusick struct vop_bmap_args /* { 186754668Smckusick struct vnode *a_vp; 186854668Smckusick daddr_t a_bn; 186954668Smckusick struct vnode **a_vpp; 187054668Smckusick daddr_t *a_bnp; 187154668Smckusick } */ *ap; 187238414Smckusick { 187353806Smckusick register struct vnode *vp = ap->a_vp; 187453806Smckusick 187553600Sheideman if (ap->a_vpp != NULL) 187653806Smckusick *ap->a_vpp = vp; 187753600Sheideman if (ap->a_bnp != NULL) 187853806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 187938414Smckusick return (0); 188038414Smckusick } 188138414Smckusick 188238414Smckusick /* 188338884Smacklem * Strategy routine for phys. i/o 188438884Smacklem * If the biod's are running, queue a request 188538884Smacklem * otherwise just call nfs_doio() to get it done 188638414Smckusick */ 188752234Sheideman int 188853806Smckusick nfs_strategy(ap) 188954668Smckusick struct vop_strategy_args /* { 189054668Smckusick struct buf *a_bp; 189154668Smckusick } */ *ap; 189238414Smckusick { 189353806Smckusick register struct buf *bp = ap->a_bp; 189438884Smacklem register struct buf *dp; 189539341Smckusick register int i; 189638884Smacklem int error = 0; 189739341Smckusick int fnd = 0; 189838884Smacklem 189938884Smacklem /* 190041905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 190141905Smckusick * doesn't set it, I will. 190246450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 190341905Smckusick * be hanging about after the process terminates. 190441905Smckusick */ 190553806Smckusick if ((bp->b_flags & B_PHYS) == 0) { 190653806Smckusick if (bp->b_flags & B_ASYNC) 190753806Smckusick bp->b_proc = (struct proc *)0; 190846988Smckusick else 190953806Smckusick bp->b_proc = curproc; 191046988Smckusick } 191141905Smckusick /* 191246450Skarels * If the op is asynchronous and an i/o daemon is waiting 191338884Smacklem * queue the request, wake it up and wait for completion 191446450Skarels * otherwise just do it ourselves. 191538884Smacklem */ 191653806Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 191753806Smckusick return (nfs_doio(bp)); 191846988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 191946988Smckusick if (nfs_iodwant[i]) { 192039341Smckusick dp = &nfs_bqueue; 192139341Smckusick if (dp->b_actf == NULL) { 192253806Smckusick dp->b_actl = bp; 192353806Smckusick bp->b_actf = dp; 192439341Smckusick } else { 192553806Smckusick dp->b_actf->b_actl = bp; 192653806Smckusick bp->b_actf = dp->b_actf; 192739341Smckusick } 192853806Smckusick dp->b_actf = bp; 192953806Smckusick bp->b_actl = dp; 193039341Smckusick fnd++; 193139341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 193239341Smckusick break; 193338884Smacklem } 193439341Smckusick } 193539341Smckusick if (!fnd) 193653806Smckusick error = nfs_doio(bp); 193738884Smacklem return (error); 193838884Smacklem } 193938884Smacklem 194038884Smacklem /* 194138884Smacklem * Fun and games with i/o 194238884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 194338884Smacklem * mapping the data buffer into kernel virtual space and doing the 194438884Smacklem * nfs read or write rpc's from it. 194541905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 194641905Smckusick * otherwise it is called by the nfsiods to do what would normally be 194738884Smacklem * partially disk interrupt driven. 194838884Smacklem */ 194952234Sheideman int 195038884Smacklem nfs_doio(bp) 195138884Smacklem register struct buf *bp; 195238884Smacklem { 195338414Smckusick register struct uio *uiop; 195438414Smckusick register struct vnode *vp; 195539341Smckusick struct nfsnode *np; 195638884Smacklem struct ucred *cr; 195741539Smckusick int error; 195841539Smckusick struct uio uio; 195941539Smckusick struct iovec io; 196038414Smckusick 196138414Smckusick vp = bp->b_vp; 196240251Smckusick np = VTONFS(vp); 196338414Smckusick uiop = &uio; 196438414Smckusick uiop->uio_iov = &io; 196538414Smckusick uiop->uio_iovcnt = 1; 196638414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 196752196Smckusick uiop->uio_procp = bp->b_proc; 196839751Smckusick 196938414Smckusick /* 197038884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 197138884Smacklem * the Nfsiomap pte's 197238884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 197338884Smacklem * and a guess at a group 197438414Smckusick */ 197538884Smacklem if (bp->b_flags & B_PHYS) { 197648054Smckusick if (bp->b_flags & B_DIRTY) 197748054Smckusick uiop->uio_procp = pageproc; 197848054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 197941539Smckusick /* mapping was already done by vmapbuf */ 198041539Smckusick io.iov_base = bp->b_un.b_addr; 198139751Smckusick 198238884Smacklem /* 198339751Smckusick * And do the i/o rpc 198439751Smckusick */ 198539751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 198639823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 198739751Smckusick if (bp->b_flags & B_READ) { 198839751Smckusick uiop->uio_rw = UIO_READ; 198939751Smckusick nfsstats.read_physios++; 199048054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 199145717Smckusick (void) vnode_pager_uncache(vp); 199239751Smckusick } else { 199339751Smckusick uiop->uio_rw = UIO_WRITE; 199439751Smckusick nfsstats.write_physios++; 199548054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 199639341Smckusick } 199739751Smckusick 199839751Smckusick /* 199939751Smckusick * Finally, release pte's used by physical i/o 200039751Smckusick */ 200138884Smacklem crfree(cr); 200239751Smckusick } else { 200339751Smckusick if (bp->b_flags & B_READ) { 200439751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 200539751Smckusick io.iov_base = bp->b_un.b_addr; 200639751Smckusick uiop->uio_rw = UIO_READ; 200741905Smckusick switch (vp->v_type) { 200841905Smckusick case VREG: 200941905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 201041905Smckusick nfsstats.read_bios++; 201148054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 201241905Smckusick break; 201341905Smckusick case VLNK: 201441905Smckusick uiop->uio_offset = 0; 201541905Smckusick nfsstats.readlink_bios++; 201648054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 201741905Smckusick break; 201841905Smckusick case VDIR: 201941905Smckusick uiop->uio_offset = bp->b_lblkno; 202041905Smckusick nfsstats.readdir_bios++; 202152196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK) 202252196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 202352196Smckusick else 202452196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 202541905Smckusick /* 202641905Smckusick * Save offset cookie in b_blkno. 202741905Smckusick */ 202841905Smckusick bp->b_blkno = uiop->uio_offset; 202941905Smckusick break; 203041905Smckusick }; 203141905Smckusick bp->b_error = error; 203239751Smckusick } else { 203339751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 203439751Smckusick - bp->b_dirtyoff; 203539823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 203639751Smckusick + bp->b_dirtyoff; 203739751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 203839751Smckusick uiop->uio_rw = UIO_WRITE; 203939751Smckusick nfsstats.write_bios++; 204041905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 204148054Smckusick bp->b_wcred); 204239751Smckusick if (error) { 204339751Smckusick np->n_error = error; 204439751Smckusick np->n_flag |= NWRITEERR; 204539751Smckusick } 204639751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 204739751Smckusick } 204838884Smacklem } 204939751Smckusick if (error) 205039751Smckusick bp->b_flags |= B_ERROR; 205139751Smckusick bp->b_resid = uiop->uio_resid; 205238414Smckusick biodone(bp); 205338414Smckusick return (error); 205438414Smckusick } 205538884Smacklem 205638884Smacklem /* 205748054Smckusick * Mmap a file 205848054Smckusick * 205948054Smckusick * NB Currently unsupported. 206048054Smckusick */ 206148054Smckusick /* ARGSUSED */ 206252234Sheideman int 206353806Smckusick nfs_mmap(ap) 206454668Smckusick struct vop_mmap_args /* { 206554668Smckusick struct vnode *a_vp; 206654668Smckusick int a_fflags; 206754668Smckusick struct ucred *a_cred; 206854668Smckusick struct proc *a_p; 206954668Smckusick } */ *ap; 207048054Smckusick { 207148054Smckusick 207248054Smckusick return (EINVAL); 207348054Smckusick } 207448054Smckusick 207548054Smckusick /* 207638884Smacklem * Flush all the blocks associated with a vnode. 207738884Smacklem * Walk through the buffer pool and push any dirty pages 207838884Smacklem * associated with the vnode. 207938884Smacklem */ 208039488Smckusick /* ARGSUSED */ 208152234Sheideman int 208253806Smckusick nfs_fsync(ap) 208354451Smckusick struct vop_fsync_args /* { 208454451Smckusick struct vnodeop_desc *a_desc; 208554451Smckusick struct vnode * a_vp; 208654451Smckusick struct ucred * a_cred; 208754451Smckusick int a_waitfor; 208854451Smckusick struct proc * a_p; 208954451Smckusick } */ *ap; 209038884Smacklem { 209154451Smckusick register struct vnode *vp = ap->a_vp; 209254451Smckusick register struct nfsnode *np = VTONFS(vp); 209354451Smckusick register struct buf *bp; 209454451Smckusick struct buf *nbp; 209554451Smckusick int s, error = 0; 209638884Smacklem 209754451Smckusick loop: 209854451Smckusick s = splbio(); 209954451Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 210054451Smckusick nbp = bp->b_blockf; 210154451Smckusick if ((bp->b_flags & B_BUSY)) 210254451Smckusick continue; 210354451Smckusick if ((bp->b_flags & B_DELWRI) == 0) 210454451Smckusick panic("nfs_fsync: not dirty"); 210554451Smckusick bremfree(bp); 210654451Smckusick bp->b_flags |= B_BUSY; 210754451Smckusick splx(s); 210854451Smckusick error = bawrite(bp); 210954451Smckusick goto loop; 211038884Smacklem } 211154451Smckusick if (ap->a_waitfor == MNT_WAIT) { 211254451Smckusick while (vp->v_numoutput) { 211354451Smckusick vp->v_flag |= VBWAIT; 211454451Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 211554451Smckusick } 211654451Smckusick #ifdef DIAGNOSTIC 211754451Smckusick if (vp->v_dirtyblkhd) { 211854451Smckusick vprint("nfs_fsync: dirty", vp); 211954451Smckusick goto loop; 212054451Smckusick } 212154451Smckusick #endif 212254451Smckusick } 212354451Smckusick splx(s); 212454451Smckusick np->n_flag &= ~NMODIFIED; 212553629Smckusick if (np->n_flag & NWRITEERR) { 212639751Smckusick error = np->n_error; 212753629Smckusick np->n_flag &= ~NWRITEERR; 212853629Smckusick } 212938884Smacklem return (error); 213038884Smacklem } 213139672Smckusick 213239672Smckusick /* 213346201Smckusick * NFS advisory byte-level locks. 213446201Smckusick * Currently unsupported. 213546201Smckusick */ 213652234Sheideman int 213753806Smckusick nfs_advlock(ap) 213854668Smckusick struct vop_advlock_args /* { 213954668Smckusick struct vnode *a_vp; 214054668Smckusick caddr_t a_id; 214154668Smckusick int a_op; 214254668Smckusick struct flock *a_fl; 214354668Smckusick int a_flags; 214454668Smckusick } */ *ap; 214546201Smckusick { 214646201Smckusick 214746201Smckusick return (EOPNOTSUPP); 214846201Smckusick } 214946201Smckusick 215046201Smckusick /* 215139672Smckusick * Print out the contents of an nfsnode. 215239672Smckusick */ 215352234Sheideman int 215453806Smckusick nfs_print(ap) 215554668Smckusick struct vop_print_args /* { 215654668Smckusick struct vnode *a_vp; 215754668Smckusick } */ *ap; 215839672Smckusick { 215953806Smckusick register struct vnode *vp = ap->a_vp; 216053806Smckusick register struct nfsnode *np = VTONFS(vp); 216139672Smckusick 216240294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 216340294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 216440294Smckusick #ifdef FIFO 216553806Smckusick if (vp->v_type == VFIFO) 216653806Smckusick fifo_printinfo(vp); 216740294Smckusick #endif /* FIFO */ 216839914Smckusick printf("\n"); 216939672Smckusick } 217051573Smckusick 217151573Smckusick /* 217251573Smckusick * NFS directory offset lookup. 217351573Smckusick * Currently unsupported. 217451573Smckusick */ 217552234Sheideman int 217653806Smckusick nfs_blkatoff(ap) 217754668Smckusick struct vop_blkatoff_args /* { 217854668Smckusick struct vnode *a_vp; 217954668Smckusick off_t a_offset; 218054668Smckusick char **a_res; 218154668Smckusick struct buf **a_bpp; 218254668Smckusick } */ *ap; 218351573Smckusick { 218451573Smckusick 218551573Smckusick return (EOPNOTSUPP); 218651573Smckusick } 218751573Smckusick 218851573Smckusick /* 218951573Smckusick * NFS flat namespace allocation. 219051573Smckusick * Currently unsupported. 219151573Smckusick */ 219252234Sheideman int 219353806Smckusick nfs_valloc(ap) 219454668Smckusick struct vop_valloc_args /* { 219554668Smckusick struct vnode *a_pvp; 219654668Smckusick int a_mode; 219754668Smckusick struct ucred *a_cred; 219854668Smckusick struct vnode **a_vpp; 219954668Smckusick } */ *ap; 220051573Smckusick { 220151573Smckusick 220251573Smckusick return (EOPNOTSUPP); 220351573Smckusick } 220451573Smckusick 220551573Smckusick /* 220651573Smckusick * NFS flat namespace free. 220751573Smckusick * Currently unsupported. 220851573Smckusick */ 220953582Sheideman int 221053806Smckusick nfs_vfree(ap) 221154668Smckusick struct vop_vfree_args /* { 221254668Smckusick struct vnode *a_pvp; 221354668Smckusick ino_t a_ino; 221454668Smckusick int a_mode; 221554668Smckusick } */ *ap; 221651573Smckusick { 221751573Smckusick 221853582Sheideman return (EOPNOTSUPP); 221951573Smckusick } 222051573Smckusick 222151573Smckusick /* 222251573Smckusick * NFS file truncation. 222351573Smckusick */ 222452234Sheideman int 222553806Smckusick nfs_truncate(ap) 222654668Smckusick struct vop_truncate_args /* { 222754668Smckusick struct vnode *a_vp; 222854668Smckusick off_t a_length; 222954668Smckusick int a_flags; 223054668Smckusick struct ucred *a_cred; 223154668Smckusick struct proc *a_p; 223254668Smckusick } */ *ap; 223351573Smckusick { 223451573Smckusick 223551573Smckusick /* Use nfs_setattr */ 223651573Smckusick printf("nfs_truncate: need to implement!!"); 223751573Smckusick return (EOPNOTSUPP); 223851573Smckusick } 223951573Smckusick 224051573Smckusick /* 224151573Smckusick * NFS update. 224251573Smckusick */ 224352234Sheideman int 224453806Smckusick nfs_update(ap) 224554668Smckusick struct vop_update_args /* { 224654668Smckusick struct vnode *a_vp; 224754668Smckusick struct timeval *a_ta; 224854668Smckusick struct timeval *a_tm; 224954668Smckusick int a_waitfor; 225054668Smckusick } */ *ap; 225151573Smckusick { 225251573Smckusick 225351573Smckusick /* Use nfs_setattr */ 225451573Smckusick printf("nfs_update: need to implement!!"); 225551573Smckusick return (EOPNOTSUPP); 225651573Smckusick } 225753629Smckusick 225853629Smckusick /* 225953629Smckusick * Read wrapper for special devices. 226053629Smckusick */ 226153629Smckusick int 226253629Smckusick nfsspec_read(ap) 226354668Smckusick struct vop_read_args /* { 226454668Smckusick struct vnode *a_vp; 226554668Smckusick struct uio *a_uio; 226654668Smckusick int a_ioflag; 226754668Smckusick struct ucred *a_cred; 226854668Smckusick } */ *ap; 226953629Smckusick { 227053629Smckusick extern int (**spec_vnodeop_p)(); 227154032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 227253629Smckusick 227353629Smckusick /* 227453629Smckusick * Set access flag. 227553629Smckusick */ 227654032Smckusick np->n_flag |= NACC; 227754032Smckusick np->n_atim = time; 227853629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 227953629Smckusick } 228053629Smckusick 228153629Smckusick /* 228253629Smckusick * Write wrapper for special devices. 228353629Smckusick */ 228453629Smckusick int 228553629Smckusick nfsspec_write(ap) 228654668Smckusick struct vop_write_args /* { 228754668Smckusick struct vnode *a_vp; 228854668Smckusick struct uio *a_uio; 228954668Smckusick int a_ioflag; 229054668Smckusick struct ucred *a_cred; 229154668Smckusick } */ *ap; 229253629Smckusick { 229353629Smckusick extern int (**spec_vnodeop_p)(); 229454032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 229553629Smckusick 229653629Smckusick /* 229754032Smckusick * Set update flag. 229853629Smckusick */ 229954032Smckusick np->n_flag |= NUPD; 230054032Smckusick np->n_mtim = time; 230153629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 230253629Smckusick } 230353629Smckusick 230453629Smckusick /* 230553629Smckusick * Close wrapper for special devices. 230653629Smckusick * 230753629Smckusick * Update the times on the nfsnode then do device close. 230853629Smckusick */ 230953629Smckusick int 231053629Smckusick nfsspec_close(ap) 231154668Smckusick struct vop_close_args /* { 231254668Smckusick struct vnode *a_vp; 231354668Smckusick int a_fflag; 231454668Smckusick struct ucred *a_cred; 231554668Smckusick struct proc *a_p; 231654668Smckusick } */ *ap; 231753629Smckusick { 231853806Smckusick register struct vnode *vp = ap->a_vp; 231953806Smckusick register struct nfsnode *np = VTONFS(vp); 232053629Smckusick struct vattr vattr; 232153629Smckusick extern int (**spec_vnodeop_p)(); 232253629Smckusick 232353629Smckusick if (np->n_flag & (NACC | NUPD)) { 232453629Smckusick if (np->n_flag & NACC) 232553629Smckusick np->n_atim = time; 232653629Smckusick if (np->n_flag & NUPD) 232753629Smckusick np->n_mtim = time; 232853629Smckusick np->n_flag |= NCHG; 232953806Smckusick if (vp->v_usecount == 1 && 233053806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 233153629Smckusick VATTR_NULL(&vattr); 233254106Smckusick if (np->n_flag & NACC) { 233354106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 233454106Smckusick vattr.va_atime.ts_nsec = 233554106Smckusick np->n_atim.tv_usec * 1000; 233654106Smckusick } 233754106Smckusick if (np->n_flag & NUPD) { 233854106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 233954106Smckusick vattr.va_mtime.ts_nsec = 234054106Smckusick np->n_mtim.tv_usec * 1000; 234154106Smckusick } 234253806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 234353629Smckusick } 234453629Smckusick } 234553629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 234653629Smckusick } 234753629Smckusick 234853629Smckusick #ifdef FIFO 234953629Smckusick /* 235053629Smckusick * Read wrapper for fifos. 235153629Smckusick */ 235253629Smckusick int 235353629Smckusick nfsfifo_read(ap) 235454668Smckusick struct vop_read_args /* { 235554668Smckusick struct vnode *a_vp; 235654668Smckusick struct uio *a_uio; 235754668Smckusick int a_ioflag; 235854668Smckusick struct ucred *a_cred; 235954668Smckusick } */ *ap; 236053629Smckusick { 236153629Smckusick extern int (**fifo_vnodeop_p)(); 236254032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 236353629Smckusick 236453629Smckusick /* 236553629Smckusick * Set access flag. 236653629Smckusick */ 236754032Smckusick np->n_flag |= NACC; 236854032Smckusick np->n_atim = time; 236953629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 237053629Smckusick } 237153629Smckusick 237253629Smckusick /* 237353629Smckusick * Write wrapper for fifos. 237453629Smckusick */ 237553629Smckusick int 237653629Smckusick nfsfifo_write(ap) 237754668Smckusick struct vop_write_args /* { 237854668Smckusick struct vnode *a_vp; 237954668Smckusick struct uio *a_uio; 238054668Smckusick int a_ioflag; 238154668Smckusick struct ucred *a_cred; 238254668Smckusick } */ *ap; 238353629Smckusick { 238453629Smckusick extern int (**fifo_vnodeop_p)(); 238554032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 238653629Smckusick 238753629Smckusick /* 238853629Smckusick * Set update flag. 238953629Smckusick */ 239054032Smckusick np->n_flag |= NUPD; 239154032Smckusick np->n_mtim = time; 239253629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 239353629Smckusick } 239453629Smckusick 239553629Smckusick /* 239653629Smckusick * Close wrapper for fifos. 239753629Smckusick * 239853629Smckusick * Update the times on the nfsnode then do fifo close. 239953629Smckusick */ 240053629Smckusick int 240153629Smckusick nfsfifo_close(ap) 240254668Smckusick struct vop_close_args /* { 240354668Smckusick struct vnode *a_vp; 240454668Smckusick int a_fflag; 240554668Smckusick struct ucred *a_cred; 240654668Smckusick struct proc *a_p; 240754668Smckusick } */ *ap; 240853629Smckusick { 240953806Smckusick register struct vnode *vp = ap->a_vp; 241053806Smckusick register struct nfsnode *np = VTONFS(vp); 241153629Smckusick struct vattr vattr; 241253629Smckusick extern int (**fifo_vnodeop_p)(); 241353629Smckusick 241453629Smckusick if (np->n_flag & (NACC | NUPD)) { 241553629Smckusick if (np->n_flag & NACC) 241653629Smckusick np->n_atim = time; 241753629Smckusick if (np->n_flag & NUPD) 241853629Smckusick np->n_mtim = time; 241953629Smckusick np->n_flag |= NCHG; 242053806Smckusick if (vp->v_usecount == 1 && 242153806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 242253629Smckusick VATTR_NULL(&vattr); 242354106Smckusick if (np->n_flag & NACC) { 242454106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 242554106Smckusick vattr.va_atime.ts_nsec = 242654106Smckusick np->n_atim.tv_usec * 1000; 242754106Smckusick } 242854106Smckusick if (np->n_flag & NUPD) { 242954106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 243054106Smckusick vattr.va_mtime.ts_nsec = 243154106Smckusick np->n_mtim.tv_usec * 1000; 243254106Smckusick } 243353806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 243453629Smckusick } 243553629Smckusick } 243653629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 243753629Smckusick } 243853629Smckusick #endif /* FIFO */ 2439