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*54032Smckusick * @(#)nfs_vnops.c 7.81 (Berkeley) 06/17/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> 3147573Skarels 3253322Smckusick #include <vm/vm.h> 3338414Smckusick 3453322Smckusick #include <nfs/rpcv2.h> 3553322Smckusick #include <nfs/nfsv2.h> 3653322Smckusick #include <nfs/nfs.h> 3753322Smckusick #include <nfs/nfsnode.h> 3853322Smckusick #include <nfs/nfsmount.h> 3953322Smckusick #include <nfs/xdr_subs.h> 4053322Smckusick #include <nfs/nfsm_subs.h> 4153322Smckusick #include <nfs/nqnfs.h> 4253322Smckusick 4338414Smckusick /* Defs */ 4438414Smckusick #define TRUE 1 4538414Smckusick #define FALSE 0 4638414Smckusick 4748054Smckusick /* 4848054Smckusick * Global vfs data structures for nfs 4948054Smckusick */ 5053554Sheideman int (**nfsv2_vnodeop_p)(); 5153554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 5253554Sheideman { &vop_default_desc, vn_default_error }, 5353806Smckusick { &vop_lookup_desc, nfs_lookup }, /* lookup */ 5453806Smckusick { &vop_create_desc, nfs_create }, /* create */ 5553554Sheideman { &vop_mknod_desc, nfs_mknod }, /* mknod */ 5653554Sheideman { &vop_open_desc, nfs_open }, /* open */ 5753554Sheideman { &vop_close_desc, nfs_close }, /* close */ 5853806Smckusick { &vop_access_desc, nfs_access }, /* access */ 5953806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 6053806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 6153554Sheideman { &vop_read_desc, nfs_read }, /* read */ 6253554Sheideman { &vop_write_desc, nfs_write }, /* write */ 6353554Sheideman { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ 6453806Smckusick { &vop_select_desc, nfs_select }, /* select */ 6553554Sheideman { &vop_mmap_desc, nfs_mmap }, /* mmap */ 6653554Sheideman { &vop_fsync_desc, nfs_fsync }, /* fsync */ 6753554Sheideman { &vop_seek_desc, nfs_seek }, /* seek */ 6853806Smckusick { &vop_remove_desc, nfs_remove }, /* remove */ 6953554Sheideman { &vop_link_desc, nfs_link }, /* link */ 7053806Smckusick { &vop_rename_desc, nfs_rename }, /* rename */ 7153554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 7253554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 7353806Smckusick { &vop_symlink_desc, nfs_symlink }, /* symlink */ 7453806Smckusick { &vop_readdir_desc, nfs_readdir }, /* readdir */ 7553806Smckusick { &vop_readlink_desc, nfs_readlink }, /* readlink */ 7653806Smckusick { &vop_abortop_desc, nfs_abortop }, /* abortop */ 7753806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 7853806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 7953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 8053806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 8153554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */ 8253806Smckusick { &vop_strategy_desc, nfs_strategy }, /* strategy */ 8353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 8453806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 8553806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8653806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 8753554Sheideman { &vop_vget_desc, nfs_vget }, /* vget */ 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 */ 11753806Smckusick { &vop_fsync_desc, spec_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 */ 13853554Sheideman { &vop_vget_desc, spec_vget }, /* vget */ 13953806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */ 14053806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */ 14153806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */ 14253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 14353582Sheideman { &vop_bwrite_desc, vn_bwrite }, 14453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 14538414Smckusick }; 14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 14753554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 14838414Smckusick 14940294Smckusick #ifdef FIFO 15053554Sheideman int (**fifo_nfsv2nodeop_p)(); 15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 15253554Sheideman { &vop_default_desc, vn_default_error }, 15353806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15453806Smckusick { &vop_create_desc, fifo_create }, /* create */ 15553806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15653554Sheideman { &vop_open_desc, fifo_open }, /* open */ 15753806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 15853806Smckusick { &vop_access_desc, nfs_access }, /* access */ 15953806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 16053806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 16153806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 16253806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16353806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16453806Smckusick { &vop_select_desc, fifo_select }, /* select */ 16553554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16653806Smckusick { &vop_fsync_desc, fifo_fsync }, /* fsync */ 16753554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 16853806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */ 16953554Sheideman { &vop_link_desc, fifo_link }, /* link */ 17053806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */ 17153806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17253806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17353806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17453806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17553806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17653806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17753806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 17853806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 17953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 18053806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18153554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18253806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */ 18353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18453806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 18553806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18653806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 18753554Sheideman { &vop_vget_desc, fifo_vget }, /* vget */ 18853806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */ 18953806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */ 19053806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */ 19153806Smckusick { &vop_update_desc, nfs_update }, /* update */ 19253582Sheideman { &vop_bwrite_desc, vn_bwrite }, 19353554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 19440294Smckusick }; 19553554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 19653554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 19740294Smckusick #endif /* FIFO */ 19840294Smckusick 19948054Smckusick /* 20052196Smckusick * Global variables 20148054Smckusick */ 20238414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 20338414Smckusick extern u_long nfs_prog, nfs_vers; 20438414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20538884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 20641905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 20746988Smckusick int nfs_numasync = 0; 20852436Smckusick #define DIRHDSIZ (sizeof (struct readdir) - (MAXNAMLEN + 1)) 20938414Smckusick 21038414Smckusick /* 21138414Smckusick * nfs null call from vfs. 21238414Smckusick */ 21352234Sheideman int 21452196Smckusick nfs_null(vp, cred, procp) 21538414Smckusick struct vnode *vp; 21638414Smckusick struct ucred *cred; 21752196Smckusick struct proc *procp; 21838414Smckusick { 21939488Smckusick caddr_t bpos, dpos; 22039488Smckusick int error = 0; 22139488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22238414Smckusick 22352196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22452196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 22538414Smckusick nfsm_reqdone; 22638414Smckusick return (error); 22738414Smckusick } 22838414Smckusick 22938414Smckusick /* 23038414Smckusick * nfs access vnode op. 23138414Smckusick * Essentially just get vattr and then imitate iaccess() 23238414Smckusick */ 23352234Sheideman int 23453806Smckusick nfs_access(ap) 23553554Sheideman struct vop_access_args *ap; 23638414Smckusick { 23753554Sheideman USES_VOP_GETATTR; 23838414Smckusick register struct vattr *vap; 23938414Smckusick register gid_t *gp; 24053806Smckusick register struct ucred *cred = ap->a_cred; 24153806Smckusick mode_t mode = ap->a_mode; 24238414Smckusick struct vattr vattr; 24338414Smckusick register int i; 24438414Smckusick int error; 24538414Smckusick 24638414Smckusick /* 24738414Smckusick * If you're the super-user, 24838414Smckusick * you always get access. 24938414Smckusick */ 25053806Smckusick if (cred->cr_uid == 0) 25138414Smckusick return (0); 25238414Smckusick vap = &vattr; 25353806Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 25438884Smacklem return (error); 25538414Smckusick /* 25638414Smckusick * Access check is based on only one of owner, group, public. 25738414Smckusick * If not owner, then check group. If not a member of the 25838414Smckusick * group, then check public access. 25938414Smckusick */ 26053806Smckusick if (cred->cr_uid != vap->va_uid) { 26153806Smckusick mode >>= 3; 26253806Smckusick gp = cred->cr_groups; 26353806Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 26438414Smckusick if (vap->va_gid == *gp) 26538414Smckusick goto found; 26653806Smckusick mode >>= 3; 26738414Smckusick found: 26838414Smckusick ; 26938414Smckusick } 27053806Smckusick if ((vap->va_mode & mode) != 0) 27138414Smckusick return (0); 27238414Smckusick return (EACCES); 27338414Smckusick } 27438414Smckusick 27538414Smckusick /* 27638414Smckusick * nfs open vnode op 27738414Smckusick * Just check to see if the type is ok 27852196Smckusick * and that deletion is not in progress. 27938414Smckusick */ 28039488Smckusick /* ARGSUSED */ 28152234Sheideman int 28253806Smckusick nfs_open(ap) 28353554Sheideman struct vop_open_args *ap; 28438414Smckusick { 28553806Smckusick register struct vnode *vp = ap->a_vp; 28638414Smckusick 28753806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 28838414Smckusick return (EACCES); 28953806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 29053806Smckusick VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */ 29152196Smckusick return (0); 29238414Smckusick } 29338414Smckusick 29438414Smckusick /* 29538414Smckusick * nfs close vnode op 29638884Smacklem * For reg files, invalidate any buffer cache entries. 29738414Smckusick */ 29839488Smckusick /* ARGSUSED */ 29952234Sheideman int 30053806Smckusick nfs_close(ap) 30153554Sheideman struct vop_close_args *ap; 30238414Smckusick { 30353806Smckusick register struct vnode *vp = ap->a_vp; 30453806Smckusick register struct nfsnode *np = VTONFS(vp); 30539341Smckusick int error = 0; 30638414Smckusick 30753806Smckusick if (vp->v_type == VREG) { 30853806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 30953629Smckusick (np->n_flag & NMODIFIED)) { 31041905Smckusick np->n_flag &= ~NMODIFIED; 31153806Smckusick vinvalbuf(vp, TRUE); 31241905Smckusick np->n_attrstamp = 0; 31353629Smckusick } 31453629Smckusick if (np->n_flag & NWRITEERR) { 31553629Smckusick np->n_flag &= ~NWRITEERR; 31653629Smckusick error = np->n_error; 31753629Smckusick } 31838884Smacklem } 31938414Smckusick return (error); 32038414Smckusick } 32138414Smckusick 32238414Smckusick /* 32338414Smckusick * nfs getattr call from vfs. 32438414Smckusick */ 32552234Sheideman int 32653805Smckusick nfs_getattr(ap) 32753554Sheideman struct vop_getattr_args *ap; 32838414Smckusick { 32953805Smckusick register struct vnode *vp = ap->a_vp; 33053805Smckusick register struct nfsnode *np = VTONFS(vp); 33139488Smckusick register caddr_t cp; 33239488Smckusick caddr_t bpos, dpos; 33339488Smckusick int error = 0; 33439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 33538414Smckusick 33653805Smckusick /* 33753805Smckusick * Update local times for special files. 33853805Smckusick */ 33953805Smckusick if (np->n_flag & (NACC | NUPD)) { 34053805Smckusick if (np->n_flag & NACC) 34153805Smckusick np->n_atim = time; 34253805Smckusick if (np->n_flag & NUPD) 34353805Smckusick np->n_mtim = time; 34453805Smckusick np->n_flag |= NCHG; 34553805Smckusick } 34653805Smckusick /* 34753805Smckusick * First look in the cache. 34853805Smckusick */ 34953805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 35038414Smckusick return (0); 35138414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 35253805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 35353805Smckusick nfsm_fhtom(vp); 35453805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 35553805Smckusick nfsm_loadattr(vp, ap->a_vap); 35638414Smckusick nfsm_reqdone; 35738414Smckusick return (error); 35838414Smckusick } 35938414Smckusick 36038414Smckusick /* 36138414Smckusick * nfs setattr call. 36238414Smckusick */ 36352234Sheideman int 36453806Smckusick nfs_setattr(ap) 36553554Sheideman struct vop_setattr_args *ap; 36638414Smckusick { 36738884Smacklem register struct nfsv2_sattr *sp; 36839488Smckusick register caddr_t cp; 36939488Smckusick register long t1; 37052196Smckusick caddr_t bpos, dpos, cp2; 37152196Smckusick u_long *tl; 37239488Smckusick int error = 0; 37339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 37453806Smckusick register struct vnode *vp = ap->a_vp; 37553806Smckusick register struct nfsnode *np = VTONFS(vp); 37653806Smckusick register struct vattr *vap = ap->a_vap; 37752196Smckusick u_quad_t frev; 37838414Smckusick 37938414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 38053806Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR); 38153806Smckusick nfsm_fhtom(vp); 38238884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 38353806Smckusick if (vap->va_mode == 0xffff) 38438884Smacklem sp->sa_mode = VNOVAL; 38538414Smckusick else 38653806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 38753806Smckusick if (vap->va_uid == 0xffff) 38838884Smacklem sp->sa_uid = VNOVAL; 38938414Smckusick else 39053806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 39153806Smckusick if (vap->va_gid == 0xffff) 39238884Smacklem sp->sa_gid = VNOVAL; 39338414Smckusick else 39453806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 39553806Smckusick sp->sa_size = txdr_unsigned(vap->va_size); 39653806Smckusick sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec); 39753806Smckusick sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags); 39853806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 39953806Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 40053806Smckusick vap->va_atime.tv_sec != VNOVAL) { 40139359Smckusick if (np->n_flag & NMODIFIED) { 40239359Smckusick np->n_flag &= ~NMODIFIED; 40353806Smckusick if (vap->va_size == 0) 40453806Smckusick vinvalbuf(vp, FALSE); 40546988Smckusick else 40653806Smckusick vinvalbuf(vp, TRUE); 40739359Smckusick } 40839359Smckusick } 40953806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 41053806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 41153806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 41253806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 41352196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 41452196Smckusick fxdr_hyper(tl, &frev); 41552196Smckusick if (QUADGT(frev, np->n_brev)) 41652196Smckusick np->n_brev = frev; 41752196Smckusick } 41838414Smckusick nfsm_reqdone; 41938414Smckusick return (error); 42038414Smckusick } 42138414Smckusick 42238414Smckusick /* 42338414Smckusick * nfs lookup call, one step at a time... 42438414Smckusick * First look in cache 42538414Smckusick * If not found, unlock the directory nfsnode and do the rpc 42638414Smckusick */ 42752234Sheideman int 42853806Smckusick nfs_lookup(ap) 42953554Sheideman struct vop_lookup_args *ap; 43038414Smckusick { 43153554Sheideman USES_VOP_GETATTR; 43253806Smckusick register struct componentname *cnp = ap->a_cnp; 43353806Smckusick register struct vnode *dvp = ap->a_dvp; 43438414Smckusick register struct vnode *vdp; 43548054Smckusick register u_long *tl; 43639488Smckusick register caddr_t cp; 43739488Smckusick register long t1, t2; 43852196Smckusick struct nfsmount *nmp; 43952196Smckusick struct nfsnode *tp; 44039488Smckusick caddr_t bpos, dpos, cp2; 44152196Smckusick time_t reqtime; 44239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 44338414Smckusick struct vnode *newvp; 44438414Smckusick long len; 44538414Smckusick nfsv2fh_t *fhp; 44638414Smckusick struct nfsnode *np; 44752234Sheideman int lockparent, wantparent, error = 0; 44852196Smckusick int nqlflag, cachable; 44952196Smckusick u_quad_t frev; 45038414Smckusick 45153600Sheideman *ap->a_vpp = NULL; 45253806Smckusick if (dvp->v_type != VDIR) 45338414Smckusick return (ENOTDIR); 45453806Smckusick lockparent = cnp->cn_flags & LOCKPARENT; 45553806Smckusick wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 45653806Smckusick nmp = VFSTONFS(dvp->v_mount); 45753806Smckusick np = VTONFS(dvp); 45853806Smckusick if ((error = cache_lookup(dvp, ap->a_vpp, cnp)) && error != ENOENT) { 45938884Smacklem struct vattr vattr; 46038884Smacklem int vpid; 46138884Smacklem 46253600Sheideman vdp = *ap->a_vpp; 46338884Smacklem vpid = vdp->v_id; 46438414Smckusick /* 46538884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 46638884Smacklem * for an explanation of the locking protocol 46738414Smckusick */ 46853806Smckusick if (dvp == vdp) { 46938425Smckusick VREF(vdp); 47039441Smckusick error = 0; 47152196Smckusick } else 47239441Smckusick error = vget(vdp); 47339441Smckusick if (!error) { 47440251Smckusick if (vpid == vdp->v_id) { 47552196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 47653806Smckusick if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 47752196Smckusick if (QUADNE(np->n_lrev, np->n_brev) || 47852196Smckusick (np->n_flag & NMODIFIED)) { 47952196Smckusick np->n_direofoffset = 0; 48053806Smckusick cache_purge(dvp); 48152196Smckusick np->n_flag &= ~NMODIFIED; 48253806Smckusick vinvalbuf(dvp, FALSE); 48352196Smckusick np->n_brev = np->n_lrev; 48452196Smckusick } else { 48552196Smckusick nfsstats.lookupcache_hits++; 48653806Smckusick if (cnp->cn_nameiop != LOOKUP && 48753806Smckusick (cnp->cn_flags&ISLASTCN)) 48853806Smckusick cnp->cn_flags |= SAVENAME; 48952196Smckusick return (0); 49052196Smckusick } 49152196Smckusick } 49253806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 49340251Smckusick vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) { 49439441Smckusick nfsstats.lookupcache_hits++; 49553806Smckusick if (cnp->cn_nameiop != LOOKUP && 49653806Smckusick (cnp->cn_flags&ISLASTCN)) 49753806Smckusick cnp->cn_flags |= SAVENAME; 49839441Smckusick return (0); 49940251Smckusick } 50047289Smckusick cache_purge(vdp); 50139441Smckusick } 50252196Smckusick vrele(vdp); 50338884Smacklem } 50453600Sheideman *ap->a_vpp = NULLVP; 50552196Smckusick } 50639341Smckusick error = 0; 50738414Smckusick nfsstats.lookupcache_misses++; 50838414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 50953806Smckusick len = cnp->cn_namelen; 51053806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 51152196Smckusick 51252196Smckusick /* 51352196Smckusick * For nqnfs optionally piggyback a getlease request for the name 51452196Smckusick * being looked up. 51552196Smckusick */ 51652196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 51752196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 51853806Smckusick ((cnp->cn_flags&MAKEENTRY) && 51953806Smckusick (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN)))) { 52052196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 52152196Smckusick *tl++ = txdr_unsigned(NQL_READ); 52252196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 52352196Smckusick } else { 52452196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 52552196Smckusick *tl = 0; 52652196Smckusick } 52752196Smckusick } 52853806Smckusick nfsm_fhtom(dvp); 52953806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 53052196Smckusick reqtime = time.tv_sec; 53153806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 53238414Smckusick nfsmout: 53338414Smckusick if (error) { 53453806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 53553806Smckusick (cnp->cn_flags & ISLASTCN) && error == ENOENT) 53652823Smckusick error = EJUSTRETURN; 53753806Smckusick if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 53853806Smckusick cnp->cn_flags |= SAVENAME; 53940483Smckusick return (error); 54038414Smckusick } 54152196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 54252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 54352196Smckusick if (*tl) { 54452196Smckusick nqlflag = fxdr_unsigned(int, *tl); 54552196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 54652196Smckusick cachable = fxdr_unsigned(int, *tl++); 54752196Smckusick reqtime += fxdr_unsigned(int, *tl++); 54852196Smckusick fxdr_hyper(tl, &frev); 54952196Smckusick } else 55052196Smckusick nqlflag = 0; 55152196Smckusick } 55252196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 55338414Smckusick 55438414Smckusick /* 55552196Smckusick * Handle RENAME case... 55638414Smckusick */ 55753806Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (cnp->cn_flags&ISLASTCN)) { 55852196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 55938414Smckusick m_freem(mrep); 56038414Smckusick return (EISDIR); 56138414Smckusick } 56253806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 56338414Smckusick m_freem(mrep); 56438414Smckusick return (error); 56538414Smckusick } 56638414Smckusick newvp = NFSTOV(np); 56739459Smckusick if (error = 56839459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 56952196Smckusick vrele(newvp); 57038414Smckusick m_freem(mrep); 57138414Smckusick return (error); 57238414Smckusick } 57353600Sheideman *ap->a_vpp = newvp; 57445037Smckusick m_freem(mrep); 57553806Smckusick cnp->cn_flags |= SAVENAME; 57638414Smckusick return (0); 57738414Smckusick } 57838414Smckusick 57952196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 58053806Smckusick VREF(dvp); 58153806Smckusick newvp = dvp; 58238414Smckusick } else { 58353806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 58438414Smckusick m_freem(mrep); 58538414Smckusick return (error); 58638414Smckusick } 58738414Smckusick newvp = NFSTOV(np); 58838414Smckusick } 58939459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 59052196Smckusick vrele(newvp); 59138414Smckusick m_freem(mrep); 59238414Smckusick return (error); 59338414Smckusick } 59438414Smckusick m_freem(mrep); 59553600Sheideman *ap->a_vpp = newvp; 59653806Smckusick if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN)) 59753806Smckusick cnp->cn_flags |= SAVENAME; 59853806Smckusick if ((cnp->cn_flags&MAKEENTRY) && 59953806Smckusick (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN))) { 60052196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 60152196Smckusick np->n_ctime = np->n_vattr.va_ctime.tv_sec; 60252196Smckusick else if (nqlflag && reqtime > time.tv_sec) { 60352196Smckusick if (np->n_tnext) { 60452196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 60552196Smckusick nmp->nm_tprev = np->n_tprev; 60652196Smckusick else 60752196Smckusick np->n_tnext->n_tprev = np->n_tprev; 60852196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 60952196Smckusick nmp->nm_tnext = np->n_tnext; 61052196Smckusick else 61152196Smckusick np->n_tprev->n_tnext = np->n_tnext; 61252196Smckusick if (nqlflag == NQL_WRITE) 61352196Smckusick np->n_flag |= NQNFSWRITE; 61452196Smckusick } else if (nqlflag == NQL_READ) 61552196Smckusick np->n_flag &= ~NQNFSWRITE; 61652196Smckusick else 61752196Smckusick np->n_flag |= NQNFSWRITE; 61852196Smckusick if (cachable) 61952196Smckusick np->n_flag &= ~NQNFSNONCACHE; 62052196Smckusick else 62152196Smckusick np->n_flag |= NQNFSNONCACHE; 62252196Smckusick np->n_expiry = reqtime; 62352196Smckusick np->n_lrev = frev; 62452196Smckusick tp = nmp->nm_tprev; 62552196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 62652196Smckusick tp = tp->n_tprev; 62752196Smckusick if (tp == (struct nfsnode *)nmp) { 62852196Smckusick np->n_tnext = nmp->nm_tnext; 62952196Smckusick nmp->nm_tnext = np; 63052196Smckusick } else { 63152196Smckusick np->n_tnext = tp->n_tnext; 63252196Smckusick tp->n_tnext = np; 63352196Smckusick } 63452196Smckusick np->n_tprev = tp; 63552196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 63652196Smckusick nmp->nm_tprev = np; 63752196Smckusick else 63852196Smckusick np->n_tnext->n_tprev = np; 63952196Smckusick } 64053806Smckusick cache_enter(dvp, *ap->a_vpp, cnp); 64140251Smckusick } 64252196Smckusick return (0); 64338414Smckusick } 64438414Smckusick 64538414Smckusick /* 64641905Smckusick * nfs read call. 64741905Smckusick * Just call nfs_bioread() to do the work. 64841905Smckusick */ 64952234Sheideman int 65053806Smckusick nfs_read(ap) 65153554Sheideman struct vop_read_args *ap; 65241905Smckusick { 65353806Smckusick register struct vnode *vp = ap->a_vp; 65453806Smckusick 65553806Smckusick if (vp->v_type != VREG) 65641905Smckusick return (EPERM); 65753806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 65841905Smckusick } 65941905Smckusick 66041905Smckusick /* 66138414Smckusick * nfs readlink call 66238414Smckusick */ 66352234Sheideman int 66453806Smckusick nfs_readlink(ap) 66553554Sheideman struct vop_readlink_args *ap; 66641905Smckusick { 66753806Smckusick register struct vnode *vp = ap->a_vp; 66853806Smckusick 66953806Smckusick if (vp->v_type != VLNK) 67041905Smckusick return (EPERM); 67153806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 67241905Smckusick } 67341905Smckusick 67441905Smckusick /* 67541905Smckusick * Do a readlink rpc. 67641905Smckusick * Called by nfs_doio() from below the buffer cache. 67741905Smckusick */ 67852234Sheideman int 67948054Smckusick nfs_readlinkrpc(vp, uiop, cred) 68039488Smckusick register struct vnode *vp; 68138414Smckusick struct uio *uiop; 68238414Smckusick struct ucred *cred; 68338414Smckusick { 68448054Smckusick register u_long *tl; 68539488Smckusick register caddr_t cp; 68639488Smckusick register long t1; 68739488Smckusick caddr_t bpos, dpos, cp2; 68839488Smckusick int error = 0; 68939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 69038414Smckusick long len; 69138414Smckusick 69238414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 69352196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 69438414Smckusick nfsm_fhtom(vp); 69552196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 69638414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 69738414Smckusick nfsm_mtouio(uiop, len); 69838414Smckusick nfsm_reqdone; 69938414Smckusick return (error); 70038414Smckusick } 70138414Smckusick 70238414Smckusick /* 70341905Smckusick * nfs read rpc call 70441905Smckusick * Ditto above 70538414Smckusick */ 70652234Sheideman int 70748054Smckusick nfs_readrpc(vp, uiop, cred) 70839488Smckusick register struct vnode *vp; 70938414Smckusick struct uio *uiop; 71038414Smckusick struct ucred *cred; 71138414Smckusick { 71248054Smckusick register u_long *tl; 71339488Smckusick register caddr_t cp; 71439488Smckusick register long t1; 71539488Smckusick caddr_t bpos, dpos, cp2; 71639488Smckusick int error = 0; 71739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 71838414Smckusick struct nfsmount *nmp; 71938414Smckusick long len, retlen, tsiz; 72038414Smckusick 72141398Smckusick nmp = VFSTONFS(vp->v_mount); 72238414Smckusick tsiz = uiop->uio_resid; 72338414Smckusick while (tsiz > 0) { 72438414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 72538414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 72652196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 72738414Smckusick nfsm_fhtom(vp); 72848054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 72948054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 73048054Smckusick *tl++ = txdr_unsigned(len); 73148054Smckusick *tl = 0; 73252196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 73338414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 73438414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 73538414Smckusick nfsm_mtouio(uiop, retlen); 73638414Smckusick m_freem(mrep); 73738414Smckusick if (retlen < len) 73838414Smckusick tsiz = 0; 73938414Smckusick else 74038414Smckusick tsiz -= len; 74138414Smckusick } 74238414Smckusick nfsmout: 74338414Smckusick return (error); 74438414Smckusick } 74538414Smckusick 74638414Smckusick /* 74738414Smckusick * nfs write call 74838414Smckusick */ 74952234Sheideman int 75048054Smckusick nfs_writerpc(vp, uiop, cred) 75139488Smckusick register struct vnode *vp; 75238414Smckusick struct uio *uiop; 75338414Smckusick struct ucred *cred; 75438414Smckusick { 75548054Smckusick register u_long *tl; 75639488Smckusick register caddr_t cp; 75739488Smckusick register long t1; 75852196Smckusick caddr_t bpos, dpos, cp2; 75939488Smckusick int error = 0; 76039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 76138414Smckusick struct nfsmount *nmp; 76252196Smckusick struct nfsnode *np = VTONFS(vp); 76352196Smckusick u_quad_t frev; 76438414Smckusick long len, tsiz; 76538414Smckusick 76641398Smckusick nmp = VFSTONFS(vp->v_mount); 76738414Smckusick tsiz = uiop->uio_resid; 76838414Smckusick while (tsiz > 0) { 76938414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 77038414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 77152196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 77252196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 77338414Smckusick nfsm_fhtom(vp); 77448054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 77548054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 77648054Smckusick *(tl+3) = txdr_unsigned(len); 77738414Smckusick nfsm_uiotom(uiop, len); 77852196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 77938414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 78052196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 78152196Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec; 78252196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 78352196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 78452196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 78552196Smckusick fxdr_hyper(tl, &frev); 78652196Smckusick if (QUADGT(frev, np->n_brev)) 78752196Smckusick np->n_brev = frev; 78852196Smckusick } 78938414Smckusick m_freem(mrep); 79038414Smckusick tsiz -= len; 79138414Smckusick } 79238414Smckusick nfsmout: 79352196Smckusick if (error) 79452196Smckusick uiop->uio_resid = tsiz; 79538414Smckusick return (error); 79638414Smckusick } 79738414Smckusick 79838414Smckusick /* 79939459Smckusick * nfs mknod call 80042246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 80142246Smckusick * set to specify the file type and the size field for rdev. 80239459Smckusick */ 80339459Smckusick /* ARGSUSED */ 80452234Sheideman int 80553806Smckusick nfs_mknod(ap) 80653554Sheideman struct vop_mknod_args *ap; 80739459Smckusick { 80853554Sheideman USES_VOP_ABORTOP; 80953806Smckusick register struct vnode *dvp = ap->a_dvp; 81053806Smckusick register struct vattr *vap = ap->a_vap; 81153806Smckusick register struct componentname *cnp = ap->a_cnp; 81242246Smckusick register struct nfsv2_sattr *sp; 81348054Smckusick register u_long *tl; 81442246Smckusick register caddr_t cp; 81552196Smckusick register long t2; 81642246Smckusick caddr_t bpos, dpos; 81742246Smckusick int error = 0; 81842246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 81942246Smckusick u_long rdev; 82039459Smckusick 82153806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 82253806Smckusick rdev = txdr_unsigned(vap->va_rdev); 82342246Smckusick #ifdef FIFO 82453806Smckusick else if (vap->va_type == VFIFO) 82542246Smckusick rdev = 0xffffffff; 82642246Smckusick #endif /* FIFO */ 82742246Smckusick else { 82853806Smckusick VOP_ABORTOP(dvp, cnp); 82953806Smckusick vput(dvp); 83042246Smckusick return (EOPNOTSUPP); 83142246Smckusick } 83242246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 83353806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 83453806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 83553806Smckusick nfsm_fhtom(dvp); 83653806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 83742246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 83853806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 83953806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 84053806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 84142246Smckusick sp->sa_size = rdev; 84242246Smckusick /* or should these be VNOVAL ?? */ 84353806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 84453806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 84553806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 84642246Smckusick nfsm_reqdone; 84753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 84853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 84953806Smckusick vrele(dvp); 85042246Smckusick return (error); 85139459Smckusick } 85239459Smckusick 85339459Smckusick /* 85438414Smckusick * nfs file create call 85538414Smckusick */ 85652234Sheideman int 85753806Smckusick nfs_create(ap) 85853554Sheideman struct vop_create_args *ap; 85938414Smckusick { 86053806Smckusick register struct vnode *dvp = ap->a_dvp; 86153806Smckusick register struct vattr *vap = ap->a_vap; 86253806Smckusick register struct componentname *cnp = ap->a_cnp; 86338884Smacklem register struct nfsv2_sattr *sp; 86448054Smckusick register u_long *tl; 86539488Smckusick register caddr_t cp; 86639488Smckusick register long t1, t2; 86739488Smckusick caddr_t bpos, dpos, cp2; 86839488Smckusick int error = 0; 86939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 87038414Smckusick 87138414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 87253806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 87353806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR); 87453806Smckusick nfsm_fhtom(dvp); 87553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 87638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 87753806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 87853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 87953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 88038884Smacklem sp->sa_size = txdr_unsigned(0); 88138414Smckusick /* or should these be VNOVAL ?? */ 88253806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); 88353806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); 88453806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 88553806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 88638414Smckusick nfsm_reqdone; 88753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 88853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 88953806Smckusick vrele(dvp); 89038414Smckusick return (error); 89138414Smckusick } 89238414Smckusick 89338414Smckusick /* 89438414Smckusick * nfs file remove call 89541905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 89641905Smckusick * other processes using the vnode is renamed instead of removed and then 89739341Smckusick * removed later on the last close. 89841905Smckusick * - If v_usecount > 1 89939341Smckusick * If a rename is not already in the works 90039341Smckusick * call nfs_sillyrename() to set it up 90139341Smckusick * else 90239341Smckusick * do the remove rpc 90338414Smckusick */ 90452234Sheideman int 90553806Smckusick nfs_remove(ap) 90653554Sheideman struct vop_remove_args *ap; 90738414Smckusick { 90853806Smckusick register struct vnode *vp = ap->a_vp; 90953806Smckusick register struct vnode *dvp = ap->a_dvp; 91053806Smckusick register struct componentname *cnp = ap->a_cnp; 91153806Smckusick register struct nfsnode *np = VTONFS(vp); 91248054Smckusick register u_long *tl; 91339488Smckusick register caddr_t cp; 91452196Smckusick register long t2; 91539488Smckusick caddr_t bpos, dpos; 91639488Smckusick int error = 0; 91739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 91838414Smckusick 91953806Smckusick if (vp->v_usecount > 1) { 92039341Smckusick if (!np->n_sillyrename) 92153806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 92239341Smckusick } else { 92352196Smckusick /* 92452196Smckusick * Purge the name cache so that the chance of a lookup for 92552196Smckusick * the name succeeding while the remove is in progress is 92652196Smckusick * minimized. Without node locking it can still happen, such 92752196Smckusick * that an I/O op returns ESTALE, but since you get this if 92852196Smckusick * another host removes the file.. 92952196Smckusick */ 93053806Smckusick cache_purge(vp); 93152196Smckusick /* 93252196Smckusick * Throw away biocache buffers. Mainly to avoid 93352196Smckusick * unnecessary delayed writes. 93452196Smckusick */ 93553806Smckusick vinvalbuf(vp, FALSE); 93652196Smckusick /* Do the rpc */ 93738414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 93853806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 93953806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 94053806Smckusick nfsm_fhtom(dvp); 94153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 94253806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 94338414Smckusick nfsm_reqdone; 94453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 94553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 94639751Smckusick /* 94739751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 94839751Smckusick * the reply to the retransmitted request will be ENOENT 94939751Smckusick * since the file was in fact removed 95039751Smckusick * Therefore, we cheat and return success. 95139751Smckusick */ 95239751Smckusick if (error == ENOENT) 95339751Smckusick error = 0; 95438414Smckusick } 95540042Smckusick np->n_attrstamp = 0; 95653806Smckusick vrele(dvp); 95753806Smckusick vrele(vp); 95838414Smckusick return (error); 95938414Smckusick } 96038414Smckusick 96138414Smckusick /* 96238414Smckusick * nfs file remove rpc called from nfs_inactive 96338414Smckusick */ 96452234Sheideman int 96552196Smckusick nfs_removeit(sp, procp) 96648364Smckusick register struct sillyrename *sp; 96752196Smckusick struct proc *procp; 96838414Smckusick { 96948054Smckusick register u_long *tl; 97039488Smckusick register caddr_t cp; 97152196Smckusick register long t2; 97239488Smckusick caddr_t bpos, dpos; 97339488Smckusick int error = 0; 97439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97538414Smckusick 97638414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 97752196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 97848364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 97948364Smckusick nfsm_fhtom(sp->s_dvp); 98048364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 98152196Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, procp, sp->s_cred); 98238414Smckusick nfsm_reqdone; 98348364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 98438414Smckusick return (error); 98538414Smckusick } 98638414Smckusick 98738414Smckusick /* 98838414Smckusick * nfs file rename call 98938414Smckusick */ 99052234Sheideman int 99153806Smckusick nfs_rename(ap) 99253554Sheideman struct vop_rename_args *ap; 99338414Smckusick { 99453806Smckusick register struct vnode *fvp = ap->a_fvp; 99553806Smckusick register struct vnode *tvp = ap->a_tvp; 99653806Smckusick register struct vnode *fdvp = ap->a_fdvp; 99753806Smckusick register struct vnode *tdvp = ap->a_tdvp; 99853806Smckusick register struct componentname *tcnp = ap->a_tcnp; 99953806Smckusick register struct componentname *fcnp = ap->a_fcnp; 100048054Smckusick register u_long *tl; 100139488Smckusick register caddr_t cp; 100252196Smckusick register long t2; 100339488Smckusick caddr_t bpos, dpos; 100439488Smckusick int error = 0; 100539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 100638414Smckusick 100753804Spendry /* Check for cross-device rename */ 100853806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 100953806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 101053804Spendry error = EXDEV; 101153804Spendry goto out; 101253804Spendry } 101353804Spendry 101453804Spendry 101538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 101653806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 101753806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 101853806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 101953806Smckusick nfsm_fhtom(fdvp); 102053806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 102153806Smckusick nfsm_fhtom(tdvp); 102253806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 102353806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 102438414Smckusick nfsm_reqdone; 102553806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 102653806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 102753806Smckusick if (fvp->v_type == VDIR) { 102853806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 102953806Smckusick cache_purge(tdvp); 103053806Smckusick cache_purge(fdvp); 103138414Smckusick } 103253804Spendry out: 103353806Smckusick if (tdvp == tvp) 103453806Smckusick vrele(tdvp); 103543360Smckusick else 103653806Smckusick vput(tdvp); 103753806Smckusick if (tvp) 103853806Smckusick vput(tvp); 103953806Smckusick vrele(fdvp); 104053806Smckusick vrele(fvp); 104140112Smckusick /* 104240112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 104340112Smckusick */ 104440112Smckusick if (error == ENOENT) 104540112Smckusick error = 0; 104638414Smckusick return (error); 104738414Smckusick } 104838414Smckusick 104938414Smckusick /* 105041905Smckusick * nfs file rename rpc called from nfs_remove() above 105138414Smckusick */ 105252234Sheideman int 105352234Sheideman nfs_renameit(sdvp, scnp, sp) 105452234Sheideman struct vnode *sdvp; 105552234Sheideman struct componentname *scnp; 105648364Smckusick register struct sillyrename *sp; 105738414Smckusick { 105848054Smckusick register u_long *tl; 105939488Smckusick register caddr_t cp; 106052196Smckusick register long t2; 106139488Smckusick caddr_t bpos, dpos; 106239488Smckusick int error = 0; 106339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 106438414Smckusick 106538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 106652234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 106752234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 106852196Smckusick nfsm_rndup(sp->s_namlen)); 106952234Sheideman nfsm_fhtom(sdvp); 107052234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 107152234Sheideman nfsm_fhtom(sdvp); 107248364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 107352234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 107438414Smckusick nfsm_reqdone; 107552234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 107652234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 107738414Smckusick return (error); 107838414Smckusick } 107938414Smckusick 108038414Smckusick /* 108138414Smckusick * nfs hard link create call 108238414Smckusick */ 108352234Sheideman int 108453806Smckusick nfs_link(ap) 108553554Sheideman struct vop_link_args *ap; 108638414Smckusick { 108753806Smckusick register struct vnode *vp = ap->a_vp; 108853806Smckusick register struct vnode *tdvp = ap->a_tdvp; 108953806Smckusick register struct componentname *cnp = ap->a_cnp; 109048054Smckusick register u_long *tl; 109139488Smckusick register caddr_t cp; 109252196Smckusick register long t2; 109339488Smckusick caddr_t bpos, dpos; 109439488Smckusick int error = 0; 109539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 109638414Smckusick 109753806Smckusick if (vp->v_mount != tdvp->v_mount) { 109853806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 109953806Smckusick if (tdvp == vp) 110053806Smckusick vrele(vp); 110153804Spendry else 110253806Smckusick vput(vp); 110353806Smckusick vrele(tdvp); 110453804Spendry return (EXDEV); 110553804Spendry } 110653804Spendry 110738414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 110853806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 110953806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 111053806Smckusick nfsm_fhtom(tdvp); 111153806Smckusick nfsm_fhtom(vp); 111253806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 111353806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 111438414Smckusick nfsm_reqdone; 111553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 111653806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 111753806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 111853806Smckusick vrele(vp); 111940112Smckusick /* 112040112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 112140112Smckusick */ 112240112Smckusick if (error == EEXIST) 112340112Smckusick error = 0; 112438414Smckusick return (error); 112538414Smckusick } 112638414Smckusick 112738414Smckusick /* 112838414Smckusick * nfs symbolic link create call 112938414Smckusick */ 113052234Sheideman /* start here */ 113152234Sheideman int 113253806Smckusick nfs_symlink(ap) 113353554Sheideman struct vop_symlink_args *ap; 113438414Smckusick { 113553806Smckusick register struct vnode *dvp = ap->a_dvp; 113653806Smckusick register struct vattr *vap = ap->a_vap; 113753806Smckusick register struct componentname *cnp = ap->a_cnp; 113838884Smacklem register struct nfsv2_sattr *sp; 113948054Smckusick register u_long *tl; 114039488Smckusick register caddr_t cp; 114152196Smckusick register long t2; 114239488Smckusick caddr_t bpos, dpos; 114352196Smckusick int slen, error = 0; 114439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 114538414Smckusick 114638414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 114753600Sheideman slen = strlen(ap->a_target); 114853806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 114953806Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR); 115053806Smckusick nfsm_fhtom(dvp); 115153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 115253600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 115338884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 115453806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 115553806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 115653806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 115738884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 115853806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 115953806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 116053806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 116138414Smckusick nfsm_reqdone; 116253806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 116353806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 116453806Smckusick vrele(dvp); 116540112Smckusick /* 116640112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 116740112Smckusick */ 116840112Smckusick if (error == EEXIST) 116940112Smckusick error = 0; 117038414Smckusick return (error); 117138414Smckusick } 117238414Smckusick 117338414Smckusick /* 117438414Smckusick * nfs make dir call 117538414Smckusick */ 117652234Sheideman int 117753806Smckusick nfs_mkdir(ap) 117853554Sheideman struct vop_mkdir_args *ap; 117938414Smckusick { 118053806Smckusick register struct vnode *dvp = ap->a_dvp; 118153806Smckusick register struct vattr *vap = ap->a_vap; 118253806Smckusick register struct componentname *cnp = ap->a_cnp; 118338884Smacklem register struct nfsv2_sattr *sp; 118448054Smckusick register u_long *tl; 118539488Smckusick register caddr_t cp; 118639488Smckusick register long t1, t2; 118741905Smckusick register int len; 118839488Smckusick caddr_t bpos, dpos, cp2; 118941905Smckusick int error = 0, firsttry = 1; 119039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 119138414Smckusick 119253806Smckusick len = cnp->cn_namelen; 119338414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 119453806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 119541905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 119653806Smckusick nfsm_fhtom(dvp); 119753806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 119838884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 119953806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 120053806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 120153806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 120238884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 120353806Smckusick txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 120453806Smckusick txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 120553806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 120653806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 120738414Smckusick nfsm_reqdone; 120853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 120940112Smckusick /* 121041905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 121141905Smckusick * if we can succeed in looking up the directory. 121241905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 121341905Smckusick * is above the if on errors. (Ugh) 121440112Smckusick */ 121541905Smckusick if (error == EEXIST && firsttry) { 121641905Smckusick firsttry = 0; 121740112Smckusick error = 0; 121841905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 121953600Sheideman *ap->a_vpp = NULL; 122053806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 122141905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 122253806Smckusick nfsm_fhtom(dvp); 122353806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 122453806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 122553806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 122653600Sheideman if ((*ap->a_vpp)->v_type != VDIR) { 122753600Sheideman vput(*ap->a_vpp); 122841905Smckusick error = EEXIST; 122941905Smckusick } 123041905Smckusick m_freem(mrep); 123141905Smckusick } 123253806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 123353806Smckusick vrele(dvp); 123438414Smckusick return (error); 123538414Smckusick } 123638414Smckusick 123738414Smckusick /* 123838414Smckusick * nfs remove directory call 123938414Smckusick */ 124052234Sheideman int 124153806Smckusick nfs_rmdir(ap) 124253554Sheideman struct vop_rmdir_args *ap; 124338414Smckusick { 124453806Smckusick register struct vnode *vp = ap->a_vp; 124553806Smckusick register struct vnode *dvp = ap->a_dvp; 124653806Smckusick register struct componentname *cnp = ap->a_cnp; 124748054Smckusick register u_long *tl; 124839488Smckusick register caddr_t cp; 124952196Smckusick register long t2; 125039488Smckusick caddr_t bpos, dpos; 125139488Smckusick int error = 0; 125239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 125338414Smckusick 125453806Smckusick if (dvp == vp) { 125553806Smckusick vrele(dvp); 125653806Smckusick vrele(dvp); 125753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 125838414Smckusick return (EINVAL); 125938414Smckusick } 126038414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 126153806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 126253806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 126353806Smckusick nfsm_fhtom(dvp); 126453806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 126553806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 126638414Smckusick nfsm_reqdone; 126753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 126853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 126953806Smckusick cache_purge(dvp); 127053806Smckusick cache_purge(vp); 127153806Smckusick vrele(vp); 127253806Smckusick vrele(dvp); 127340112Smckusick /* 127440112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 127540112Smckusick */ 127640112Smckusick if (error == ENOENT) 127740112Smckusick error = 0; 127838414Smckusick return (error); 127938414Smckusick } 128038414Smckusick 128138414Smckusick /* 128238414Smckusick * nfs readdir call 128338414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 128438414Smckusick * order so that it looks more sensible. This appears consistent with the 128538414Smckusick * Ultrix implementation of NFS. 128638414Smckusick */ 128752234Sheideman int 128853806Smckusick nfs_readdir(ap) 128953554Sheideman struct vop_readdir_args *ap; 129038414Smckusick { 129153554Sheideman USES_VOP_GETATTR; 129253806Smckusick register struct vnode *vp = ap->a_vp; 129353806Smckusick register struct nfsnode *np = VTONFS(vp); 129453806Smckusick register struct uio *uio = ap->a_uio; 129553806Smckusick register int *eofflagp = ap->a_eofflagp; 129641905Smckusick int tresid, error; 129741905Smckusick struct vattr vattr; 129841905Smckusick 129953806Smckusick if (vp->v_type != VDIR) 130041905Smckusick return (EPERM); 130141905Smckusick /* 130241905Smckusick * First, check for hit on the EOF offset cache 130341905Smckusick */ 130453806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 130552196Smckusick (np->n_flag & NMODIFIED) == 0) { 130653806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 130753806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 130853806Smckusick *eofflagp = 1; 130952196Smckusick nfsstats.direofcache_hits++; 131052196Smckusick return (0); 131152196Smckusick } 131253806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 131352196Smckusick np->n_mtime == vattr.va_mtime.tv_sec) { 131453806Smckusick *eofflagp = 1; 131552196Smckusick nfsstats.direofcache_hits++; 131652196Smckusick return (0); 131752196Smckusick } 131841905Smckusick } 131941905Smckusick 132041905Smckusick /* 132141905Smckusick * Call nfs_bioread() to do the real work. 132241905Smckusick */ 132353806Smckusick tresid = uio->uio_resid; 132453806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 132541905Smckusick 132653806Smckusick if (!error && uio->uio_resid == tresid) { 132753806Smckusick *eofflagp = 1; 132841905Smckusick nfsstats.direofcache_misses++; 132941905Smckusick } else 133053806Smckusick *eofflagp = 0; 133141905Smckusick return (error); 133241905Smckusick } 133341905Smckusick 133441905Smckusick /* 133541905Smckusick * Readdir rpc call. 133641905Smckusick * Called from below the buffer cache by nfs_doio(). 133741905Smckusick */ 133852234Sheideman int 133948054Smckusick nfs_readdirrpc(vp, uiop, cred) 134041905Smckusick register struct vnode *vp; 134141905Smckusick struct uio *uiop; 134241905Smckusick struct ucred *cred; 134341905Smckusick { 134438414Smckusick register long len; 134552436Smckusick register struct readdir *dp; 134648054Smckusick register u_long *tl; 134739488Smckusick register caddr_t cp; 134839488Smckusick register long t1; 134941905Smckusick long tlen, lastlen; 135039488Smckusick caddr_t bpos, dpos, cp2; 135139488Smckusick int error = 0; 135239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 135338414Smckusick struct mbuf *md2; 135438414Smckusick caddr_t dpos2; 135538414Smckusick int siz; 135640296Smckusick int more_dirs = 1; 135738414Smckusick off_t off, savoff; 135852436Smckusick struct readdir *savdp; 135940296Smckusick struct nfsmount *nmp; 136040296Smckusick struct nfsnode *np = VTONFS(vp); 136140296Smckusick long tresid; 136238414Smckusick 136341398Smckusick nmp = VFSTONFS(vp->v_mount); 136440296Smckusick tresid = uiop->uio_resid; 136540296Smckusick /* 136640296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 136748054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 136841905Smckusick * The stopping criteria is EOF or buffer full. 136940296Smckusick */ 137048054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 137140296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 137252196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 137352196Smckusick NFSX_FH+2*NFSX_UNSIGNED); 137440296Smckusick nfsm_fhtom(vp); 137548054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 137648054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 137748054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 137848054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 137952196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 138040296Smckusick siz = 0; 138152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 138248054Smckusick more_dirs = fxdr_unsigned(int, *tl); 138340296Smckusick 138440296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 138540296Smckusick dpos2 = dpos; 138640296Smckusick md2 = md; 138740296Smckusick 138840296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 138941905Smckusick off = uiop->uio_offset; 139042246Smckusick #ifdef lint 139152436Smckusick dp = (struct readdir *)0; 139242246Smckusick #endif /* lint */ 139340296Smckusick while (more_dirs && siz < uiop->uio_resid) { 139440296Smckusick savoff = off; /* Hold onto offset and dp */ 139540296Smckusick savdp = dp; 139652196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 139752436Smckusick dp = (struct readdir *)tl; 139848054Smckusick dp->d_ino = fxdr_unsigned(u_long, *tl++); 139948054Smckusick len = fxdr_unsigned(int, *tl); 140040296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 140140296Smckusick error = EBADRPC; 140240296Smckusick m_freem(mrep); 140340296Smckusick goto nfsmout; 140440296Smckusick } 140540296Smckusick dp->d_namlen = (u_short)len; 140640296Smckusick nfsm_adv(len); /* Point past name */ 140740296Smckusick tlen = nfsm_rndup(len); 140840296Smckusick /* 140940296Smckusick * This should not be necessary, but some servers have 141040296Smckusick * broken XDR such that these bytes are not null filled. 141140296Smckusick */ 141240296Smckusick if (tlen != len) { 141340296Smckusick *dpos = '\0'; /* Null-terminate */ 141440296Smckusick nfsm_adv(tlen - len); 141540296Smckusick len = tlen; 141640296Smckusick } 141752196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 141848054Smckusick off = fxdr_unsigned(off_t, *tl); 141948054Smckusick *tl++ = 0; /* Ensures null termination of name */ 142048054Smckusick more_dirs = fxdr_unsigned(int, *tl); 142140296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 142240296Smckusick siz += dp->d_reclen; 142340296Smckusick } 142440296Smckusick /* 142540296Smckusick * If at end of rpc data, get the eof boolean 142640296Smckusick */ 142740296Smckusick if (!more_dirs) { 142852196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 142948054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 143038414Smckusick 143140296Smckusick /* 143240296Smckusick * If at EOF, cache directory offset 143340296Smckusick */ 143441905Smckusick if (!more_dirs) 143540296Smckusick np->n_direofoffset = off; 143638414Smckusick } 143740296Smckusick /* 143840296Smckusick * If there is too much to fit in the data buffer, use savoff and 143940296Smckusick * savdp to trim off the last record. 144040296Smckusick * --> we are not at eof 144140296Smckusick */ 144240296Smckusick if (siz > uiop->uio_resid) { 144340296Smckusick off = savoff; 144440296Smckusick siz -= dp->d_reclen; 144540296Smckusick dp = savdp; 144640296Smckusick more_dirs = 0; /* Paranoia */ 144740113Smckusick } 144840296Smckusick if (siz > 0) { 144941905Smckusick lastlen = dp->d_reclen; 145040296Smckusick md = md2; 145140296Smckusick dpos = dpos2; 145240296Smckusick nfsm_mtouio(uiop, siz); 145340296Smckusick uiop->uio_offset = off; 145440296Smckusick } else 145540296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 145640296Smckusick m_freem(mrep); 145738414Smckusick } 145841905Smckusick /* 145948054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 146041905Smckusick * by increasing d_reclen for the last record. 146141905Smckusick */ 146241905Smckusick if (uiop->uio_resid < tresid) { 146348054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 146441905Smckusick if (len > 0) { 146552436Smckusick dp = (struct readdir *) 146641905Smckusick (uiop->uio_iov->iov_base - lastlen); 146741905Smckusick dp->d_reclen += len; 146841905Smckusick uiop->uio_iov->iov_base += len; 146941905Smckusick uiop->uio_iov->iov_len -= len; 147041905Smckusick uiop->uio_resid -= len; 147141905Smckusick } 147241905Smckusick } 147340296Smckusick nfsmout: 147438414Smckusick return (error); 147538414Smckusick } 147638414Smckusick 147752196Smckusick /* 147852196Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when 147952196Smckusick * the "rdirlook" mount option is specified. 148052196Smckusick */ 148152234Sheideman int 148252196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 148352196Smckusick struct vnode *vp; 148452196Smckusick register struct uio *uiop; 148552196Smckusick struct ucred *cred; 148652196Smckusick { 148752196Smckusick register int len; 148852436Smckusick register struct readdir *dp; 148952196Smckusick register u_long *tl; 149052196Smckusick register caddr_t cp; 149152196Smckusick register long t1; 149252196Smckusick caddr_t bpos, dpos, cp2; 149352196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 149452196Smckusick struct nameidata nami, *ndp = &nami; 149552317Sheideman struct componentname *cnp = &ndp->ni_cnd; 149652196Smckusick off_t off, endoff; 149752196Smckusick time_t reqtime, ltime; 149852196Smckusick struct nfsmount *nmp; 149952196Smckusick struct nfsnode *np, *tp; 150052196Smckusick struct vnode *newvp; 150152196Smckusick nfsv2fh_t *fhp; 150252196Smckusick u_long fileno; 150352196Smckusick u_quad_t frev; 150452196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 150552196Smckusick int cachable; 150652196Smckusick 150752196Smckusick if (uiop->uio_iovcnt != 1) 150852196Smckusick panic("nfs rdirlook"); 150952196Smckusick nmp = VFSTONFS(vp->v_mount); 151052196Smckusick tresid = uiop->uio_resid; 151152196Smckusick ndp->ni_dvp = vp; 151252196Smckusick newvp = NULLVP; 151352196Smckusick /* 151452196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 151552196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 151652196Smckusick * The stopping criteria is EOF or buffer full. 151752196Smckusick */ 151852196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 151952196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 152052196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 152152196Smckusick NFSX_FH+3*NFSX_UNSIGNED); 152252196Smckusick nfsm_fhtom(vp); 152352196Smckusick nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED); 152452196Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 152552196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 152652196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 152752196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 152852196Smckusick reqtime = time.tv_sec; 152952196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 153052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 153152196Smckusick more_dirs = fxdr_unsigned(int, *tl); 153252196Smckusick 153352196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 153452196Smckusick off = uiop->uio_offset; 153552196Smckusick bigenough = 1; 153652196Smckusick while (more_dirs && bigenough) { 153752196Smckusick doit = 1; 153852196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 153952196Smckusick cachable = fxdr_unsigned(int, *tl++); 154052196Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 154152196Smckusick fxdr_hyper(tl, &frev); 154252196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 154352196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 154452196Smckusick VREF(vp); 154552196Smckusick newvp = vp; 154652196Smckusick np = VTONFS(vp); 154752196Smckusick } else { 154852196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 154952196Smckusick doit = 0; 155052196Smckusick newvp = NFSTOV(np); 155152196Smckusick } 155252196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 155352196Smckusick (struct vattr *)0)) 155452196Smckusick doit = 0; 155552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 155652196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 155752196Smckusick len = fxdr_unsigned(int, *tl); 155852196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 155952196Smckusick error = EBADRPC; 156052196Smckusick m_freem(mrep); 156152196Smckusick goto nfsmout; 156252196Smckusick } 156352196Smckusick tlen = (len + 4) & ~0x3; 156452196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 156552196Smckusick bigenough = 0; 156652196Smckusick if (bigenough && doit) { 156752436Smckusick dp = (struct readdir *)uiop->uio_iov->iov_base; 156852196Smckusick dp->d_ino = fileno; 156952196Smckusick dp->d_namlen = len; 157052196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 157152196Smckusick uiop->uio_resid -= DIRHDSIZ; 157252196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 157352196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 157452317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 157552317Sheideman cnp->cn_namelen = len; 157652196Smckusick ndp->ni_vp = newvp; 157752196Smckusick nfsm_mtouio(uiop, len); 157852196Smckusick cp = uiop->uio_iov->iov_base; 157952196Smckusick tlen -= len; 158052196Smckusick for (i = 0; i < tlen; i++) 158152196Smckusick *cp++ = '\0'; 158252196Smckusick uiop->uio_iov->iov_base += tlen; 158352196Smckusick uiop->uio_iov->iov_len -= tlen; 158452196Smckusick uiop->uio_resid -= tlen; 158552317Sheideman cnp->cn_hash = 0; 158652317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 158752317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 158852196Smckusick if (ltime > time.tv_sec) { 158952196Smckusick if (np->n_tnext) { 159052196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 159152196Smckusick nmp->nm_tprev = np->n_tprev; 159252196Smckusick else 159352196Smckusick np->n_tnext->n_tprev = np->n_tprev; 159452196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 159552196Smckusick nmp->nm_tnext = np->n_tnext; 159652196Smckusick else 159752196Smckusick np->n_tprev->n_tnext = np->n_tnext; 159852196Smckusick } else 159952196Smckusick np->n_flag &= ~NQNFSWRITE; 160052196Smckusick if (cachable) 160152196Smckusick np->n_flag &= ~NQNFSNONCACHE; 160252196Smckusick else 160352196Smckusick np->n_flag |= NQNFSNONCACHE; 160452196Smckusick np->n_expiry = ltime; 160552196Smckusick np->n_lrev = frev; 160652196Smckusick tp = nmp->nm_tprev; 160752196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 160852196Smckusick tp = tp->n_tprev; 160952196Smckusick if (tp == (struct nfsnode *)nmp) { 161052196Smckusick np->n_tnext = nmp->nm_tnext; 161152196Smckusick nmp->nm_tnext = np; 161252196Smckusick } else { 161352196Smckusick np->n_tnext = tp->n_tnext; 161452196Smckusick tp->n_tnext = np; 161552196Smckusick } 161652196Smckusick np->n_tprev = tp; 161752196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 161852196Smckusick nmp->nm_tprev = np; 161952196Smckusick else 162052196Smckusick np->n_tnext->n_tprev = np; 162152317Sheideman cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 162252196Smckusick } 162352196Smckusick } else { 162452196Smckusick nfsm_adv(nfsm_rndup(len)); 162552196Smckusick } 162652196Smckusick if (newvp != NULLVP) { 162752196Smckusick vrele(newvp); 162852196Smckusick newvp = NULLVP; 162952196Smckusick } 163052196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 163152196Smckusick if (bigenough) 163252196Smckusick endoff = off = fxdr_unsigned(off_t, *tl++); 163352196Smckusick else 163452196Smckusick endoff = fxdr_unsigned(off_t, *tl++); 163552196Smckusick more_dirs = fxdr_unsigned(int, *tl); 163652196Smckusick } 163752196Smckusick /* 163852196Smckusick * If at end of rpc data, get the eof boolean 163952196Smckusick */ 164052196Smckusick if (!more_dirs) { 164152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 164252196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 164352196Smckusick 164452196Smckusick /* 164552196Smckusick * If at EOF, cache directory offset 164652196Smckusick */ 164752196Smckusick if (!more_dirs) 164852196Smckusick VTONFS(vp)->n_direofoffset = endoff; 164952196Smckusick } 165052196Smckusick if (uiop->uio_resid < tresid) 165152196Smckusick uiop->uio_offset = off; 165252196Smckusick else 165352196Smckusick more_dirs = 0; 165452196Smckusick m_freem(mrep); 165552196Smckusick } 165652196Smckusick /* 165752196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 165852196Smckusick * by increasing d_reclen for the last record. 165952196Smckusick */ 166052196Smckusick if (uiop->uio_resid < tresid) { 166152196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 166252196Smckusick if (len > 0) { 166352196Smckusick dp->d_reclen += len; 166452196Smckusick uiop->uio_iov->iov_base += len; 166552196Smckusick uiop->uio_iov->iov_len -= len; 166652196Smckusick uiop->uio_resid -= len; 166752196Smckusick } 166852196Smckusick } 166952196Smckusick nfsmout: 167052196Smckusick if (newvp != NULLVP) 167152196Smckusick vrele(newvp); 167252196Smckusick return (error); 167352196Smckusick } 167439488Smckusick static char hextoasc[] = "0123456789abcdef"; 167538414Smckusick 167638414Smckusick /* 167738414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 167838414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 167938414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 168038414Smckusick * nfsnode. There is the potential for another process on a different client 168138414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 168238414Smckusick * nfs_rename() completes, but... 168338414Smckusick */ 168452234Sheideman int 168552317Sheideman nfs_sillyrename(dvp, vp, cnp) 168652234Sheideman struct vnode *dvp, *vp; 168752234Sheideman struct componentname *cnp; 168838414Smckusick { 168938414Smckusick register struct nfsnode *np; 169038414Smckusick register struct sillyrename *sp; 169138414Smckusick int error; 169238414Smckusick short pid; 169338414Smckusick 169452234Sheideman cache_purge(dvp); 169552234Sheideman np = VTONFS(vp); 169651986Smckusick #ifdef SILLYSEPARATE 169738414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 169848364Smckusick M_NFSREQ, M_WAITOK); 169951986Smckusick #else 170051986Smckusick sp = &np->n_silly; 170151986Smckusick #endif 170252234Sheideman sp->s_cred = crdup(cnp->cn_cred); 170352234Sheideman sp->s_dvp = dvp; 170452234Sheideman VREF(dvp); 170538414Smckusick 170638414Smckusick /* Fudge together a funny name */ 170752234Sheideman pid = cnp->cn_proc->p_pid; 170848364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 170948364Smckusick sp->s_namlen = 12; 171048364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 171148364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 171248364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 171348364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 171438414Smckusick 171538414Smckusick /* Try lookitups until we get one that isn't there */ 171652234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 171748364Smckusick sp->s_name[4]++; 171848364Smckusick if (sp->s_name[4] > 'z') { 171938414Smckusick error = EINVAL; 172038414Smckusick goto bad; 172138414Smckusick } 172238414Smckusick } 172352234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 172438414Smckusick goto bad; 172552234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 172638414Smckusick np->n_sillyrename = sp; 172738414Smckusick return (0); 172838414Smckusick bad: 172948364Smckusick vrele(sp->s_dvp); 173048364Smckusick crfree(sp->s_cred); 173151986Smckusick #ifdef SILLYSEPARATE 173248364Smckusick free((caddr_t)sp, M_NFSREQ); 173351986Smckusick #endif 173438414Smckusick return (error); 173538414Smckusick } 173638414Smckusick 173738414Smckusick /* 173838414Smckusick * Look up a file name for silly rename stuff. 173938414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 174038414Smckusick * into the nfsnode table. 174138414Smckusick * If fhp != NULL it copies the returned file handle out 174238414Smckusick */ 174352234Sheideman int 174452196Smckusick nfs_lookitup(sp, fhp, procp) 174548364Smckusick register struct sillyrename *sp; 174638414Smckusick nfsv2fh_t *fhp; 174752196Smckusick struct proc *procp; 174838414Smckusick { 174948364Smckusick register struct vnode *vp = sp->s_dvp; 175048054Smckusick register u_long *tl; 175139488Smckusick register caddr_t cp; 175239488Smckusick register long t1, t2; 175339488Smckusick caddr_t bpos, dpos, cp2; 175439488Smckusick u_long xid; 175539488Smckusick int error = 0; 175639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 175738414Smckusick long len; 175838414Smckusick 175938414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 176048364Smckusick len = sp->s_namlen; 176152196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 176238414Smckusick nfsm_fhtom(vp); 176348364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 176452196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 176538414Smckusick if (fhp != NULL) { 176652196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 176738414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 176838414Smckusick } 176938414Smckusick nfsm_reqdone; 177038414Smckusick return (error); 177138414Smckusick } 177238414Smckusick 177338414Smckusick /* 177438414Smckusick * Kludge City.. 177538414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 177641905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 177738414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 177838414Smckusick * nfsiobuf area. 177938414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 178038414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 178138414Smckusick * a lot more work than bcopy() and also it currently happens in the 178238414Smckusick * context of the swapper process (2). 178338414Smckusick */ 178452234Sheideman int 178553806Smckusick nfs_bmap(ap) 178653554Sheideman struct vop_bmap_args *ap; 178738414Smckusick { 178853806Smckusick register struct vnode *vp = ap->a_vp; 178953806Smckusick 179053600Sheideman if (ap->a_vpp != NULL) 179153806Smckusick *ap->a_vpp = vp; 179253600Sheideman if (ap->a_bnp != NULL) 179353806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 179438414Smckusick return (0); 179538414Smckusick } 179638414Smckusick 179738414Smckusick /* 179838884Smacklem * Strategy routine for phys. i/o 179938884Smacklem * If the biod's are running, queue a request 180038884Smacklem * otherwise just call nfs_doio() to get it done 180138414Smckusick */ 180252234Sheideman int 180353806Smckusick nfs_strategy(ap) 180453554Sheideman struct vop_strategy_args *ap; 180538414Smckusick { 180653806Smckusick register struct buf *bp = ap->a_bp; 180738884Smacklem register struct buf *dp; 180839341Smckusick register int i; 180938884Smacklem int error = 0; 181039341Smckusick int fnd = 0; 181138884Smacklem 181238884Smacklem /* 181341905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 181441905Smckusick * doesn't set it, I will. 181546450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 181641905Smckusick * be hanging about after the process terminates. 181741905Smckusick */ 181853806Smckusick if ((bp->b_flags & B_PHYS) == 0) { 181953806Smckusick if (bp->b_flags & B_ASYNC) 182053806Smckusick bp->b_proc = (struct proc *)0; 182146988Smckusick else 182253806Smckusick bp->b_proc = curproc; 182346988Smckusick } 182441905Smckusick /* 182546450Skarels * If the op is asynchronous and an i/o daemon is waiting 182638884Smacklem * queue the request, wake it up and wait for completion 182746450Skarels * otherwise just do it ourselves. 182838884Smacklem */ 182953806Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 183053806Smckusick return (nfs_doio(bp)); 183146988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 183246988Smckusick if (nfs_iodwant[i]) { 183339341Smckusick dp = &nfs_bqueue; 183439341Smckusick if (dp->b_actf == NULL) { 183553806Smckusick dp->b_actl = bp; 183653806Smckusick bp->b_actf = dp; 183739341Smckusick } else { 183853806Smckusick dp->b_actf->b_actl = bp; 183953806Smckusick bp->b_actf = dp->b_actf; 184039341Smckusick } 184153806Smckusick dp->b_actf = bp; 184253806Smckusick bp->b_actl = dp; 184339341Smckusick fnd++; 184439341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 184539341Smckusick break; 184638884Smacklem } 184739341Smckusick } 184839341Smckusick if (!fnd) 184953806Smckusick error = nfs_doio(bp); 185038884Smacklem return (error); 185138884Smacklem } 185238884Smacklem 185338884Smacklem /* 185438884Smacklem * Fun and games with i/o 185538884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 185638884Smacklem * mapping the data buffer into kernel virtual space and doing the 185738884Smacklem * nfs read or write rpc's from it. 185841905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 185941905Smckusick * otherwise it is called by the nfsiods to do what would normally be 186038884Smacklem * partially disk interrupt driven. 186138884Smacklem */ 186252234Sheideman int 186338884Smacklem nfs_doio(bp) 186438884Smacklem register struct buf *bp; 186538884Smacklem { 186638414Smckusick register struct uio *uiop; 186738414Smckusick register struct vnode *vp; 186839341Smckusick struct nfsnode *np; 186938884Smacklem struct ucred *cr; 187041539Smckusick int error; 187141539Smckusick struct uio uio; 187241539Smckusick struct iovec io; 187338414Smckusick 187438414Smckusick vp = bp->b_vp; 187540251Smckusick np = VTONFS(vp); 187638414Smckusick uiop = &uio; 187738414Smckusick uiop->uio_iov = &io; 187838414Smckusick uiop->uio_iovcnt = 1; 187938414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 188052196Smckusick uiop->uio_procp = bp->b_proc; 188139751Smckusick 188238414Smckusick /* 188338884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 188438884Smacklem * the Nfsiomap pte's 188538884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 188638884Smacklem * and a guess at a group 188738414Smckusick */ 188838884Smacklem if (bp->b_flags & B_PHYS) { 188948054Smckusick if (bp->b_flags & B_DIRTY) 189048054Smckusick uiop->uio_procp = pageproc; 189148054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 189241539Smckusick /* mapping was already done by vmapbuf */ 189341539Smckusick io.iov_base = bp->b_un.b_addr; 189439751Smckusick 189538884Smacklem /* 189639751Smckusick * And do the i/o rpc 189739751Smckusick */ 189839751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 189939823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 190039751Smckusick if (bp->b_flags & B_READ) { 190139751Smckusick uiop->uio_rw = UIO_READ; 190239751Smckusick nfsstats.read_physios++; 190348054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 190445717Smckusick (void) vnode_pager_uncache(vp); 190539751Smckusick } else { 190639751Smckusick uiop->uio_rw = UIO_WRITE; 190739751Smckusick nfsstats.write_physios++; 190848054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 190939341Smckusick } 191039751Smckusick 191139751Smckusick /* 191239751Smckusick * Finally, release pte's used by physical i/o 191339751Smckusick */ 191438884Smacklem crfree(cr); 191539751Smckusick } else { 191639751Smckusick if (bp->b_flags & B_READ) { 191739751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 191839751Smckusick io.iov_base = bp->b_un.b_addr; 191939751Smckusick uiop->uio_rw = UIO_READ; 192041905Smckusick switch (vp->v_type) { 192141905Smckusick case VREG: 192241905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 192341905Smckusick nfsstats.read_bios++; 192448054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 192541905Smckusick break; 192641905Smckusick case VLNK: 192741905Smckusick uiop->uio_offset = 0; 192841905Smckusick nfsstats.readlink_bios++; 192948054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 193041905Smckusick break; 193141905Smckusick case VDIR: 193241905Smckusick uiop->uio_offset = bp->b_lblkno; 193341905Smckusick nfsstats.readdir_bios++; 193452196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK) 193552196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 193652196Smckusick else 193752196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 193841905Smckusick /* 193941905Smckusick * Save offset cookie in b_blkno. 194041905Smckusick */ 194141905Smckusick bp->b_blkno = uiop->uio_offset; 194241905Smckusick break; 194341905Smckusick }; 194441905Smckusick bp->b_error = error; 194539751Smckusick } else { 194639751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 194739751Smckusick - bp->b_dirtyoff; 194839823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 194939751Smckusick + bp->b_dirtyoff; 195039751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 195139751Smckusick uiop->uio_rw = UIO_WRITE; 195239751Smckusick nfsstats.write_bios++; 195341905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 195448054Smckusick bp->b_wcred); 195539751Smckusick if (error) { 195639751Smckusick np->n_error = error; 195739751Smckusick np->n_flag |= NWRITEERR; 195839751Smckusick } 195939751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 196039751Smckusick } 196138884Smacklem } 196239751Smckusick if (error) 196339751Smckusick bp->b_flags |= B_ERROR; 196439751Smckusick bp->b_resid = uiop->uio_resid; 196538414Smckusick biodone(bp); 196638414Smckusick return (error); 196738414Smckusick } 196838884Smacklem 196938884Smacklem /* 197048054Smckusick * Mmap a file 197148054Smckusick * 197248054Smckusick * NB Currently unsupported. 197348054Smckusick */ 197448054Smckusick /* ARGSUSED */ 197552234Sheideman int 197653806Smckusick nfs_mmap(ap) 197753554Sheideman struct vop_mmap_args *ap; 197848054Smckusick { 197948054Smckusick 198048054Smckusick return (EINVAL); 198148054Smckusick } 198248054Smckusick 198348054Smckusick /* 198438884Smacklem * Flush all the blocks associated with a vnode. 198538884Smacklem * Walk through the buffer pool and push any dirty pages 198638884Smacklem * associated with the vnode. 198738884Smacklem */ 198839488Smckusick /* ARGSUSED */ 198952234Sheideman int 199053806Smckusick nfs_fsync(ap) 199153554Sheideman struct vop_fsync_args *ap; 199238884Smacklem { 199353600Sheideman register struct nfsnode *np = VTONFS(ap->a_vp); 199439751Smckusick int error = 0; 199538884Smacklem 199638884Smacklem if (np->n_flag & NMODIFIED) { 199738884Smacklem np->n_flag &= ~NMODIFIED; 199853600Sheideman vflushbuf(ap->a_vp, ap->a_waitfor == MNT_WAIT ? B_SYNC : 0); 199938884Smacklem } 200053629Smckusick if (np->n_flag & NWRITEERR) { 200139751Smckusick error = np->n_error; 200253629Smckusick np->n_flag &= ~NWRITEERR; 200353629Smckusick } 200438884Smacklem return (error); 200538884Smacklem } 200639672Smckusick 200739672Smckusick /* 200846201Smckusick * NFS advisory byte-level locks. 200946201Smckusick * Currently unsupported. 201046201Smckusick */ 201152234Sheideman int 201253806Smckusick nfs_advlock(ap) 201353554Sheideman struct vop_advlock_args *ap; 201446201Smckusick { 201546201Smckusick 201646201Smckusick return (EOPNOTSUPP); 201746201Smckusick } 201846201Smckusick 201946201Smckusick /* 202039672Smckusick * Print out the contents of an nfsnode. 202139672Smckusick */ 202252234Sheideman int 202353806Smckusick nfs_print(ap) 202453554Sheideman struct vop_print_args *ap; 202539672Smckusick { 202653806Smckusick register struct vnode *vp = ap->a_vp; 202753806Smckusick register struct nfsnode *np = VTONFS(vp); 202839672Smckusick 202940294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 203040294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 203140294Smckusick #ifdef FIFO 203253806Smckusick if (vp->v_type == VFIFO) 203353806Smckusick fifo_printinfo(vp); 203440294Smckusick #endif /* FIFO */ 203539914Smckusick printf("\n"); 203639672Smckusick } 203751573Smckusick 203851573Smckusick /* 203951573Smckusick * NFS directory offset lookup. 204051573Smckusick * Currently unsupported. 204151573Smckusick */ 204252234Sheideman int 204353806Smckusick nfs_blkatoff(ap) 204453554Sheideman struct vop_blkatoff_args *ap; 204551573Smckusick { 204651573Smckusick 204751573Smckusick return (EOPNOTSUPP); 204851573Smckusick } 204951573Smckusick 205051573Smckusick /* 205151573Smckusick * NFS flat namespace lookup. 205251573Smckusick * Currently unsupported. 205351573Smckusick */ 205452234Sheideman int 205553806Smckusick nfs_vget(ap) 205653554Sheideman struct vop_vget_args *ap; 205751573Smckusick { 205851573Smckusick 205951573Smckusick return (EOPNOTSUPP); 206051573Smckusick } 206151573Smckusick 206251573Smckusick /* 206351573Smckusick * NFS flat namespace allocation. 206451573Smckusick * Currently unsupported. 206551573Smckusick */ 206652234Sheideman int 206753806Smckusick nfs_valloc(ap) 206853554Sheideman struct vop_valloc_args *ap; 206951573Smckusick { 207051573Smckusick 207151573Smckusick return (EOPNOTSUPP); 207251573Smckusick } 207351573Smckusick 207451573Smckusick /* 207551573Smckusick * NFS flat namespace free. 207651573Smckusick * Currently unsupported. 207751573Smckusick */ 207853582Sheideman int 207953806Smckusick nfs_vfree(ap) 208053554Sheideman struct vop_vfree_args *ap; 208151573Smckusick { 208251573Smckusick 208353582Sheideman return (EOPNOTSUPP); 208451573Smckusick } 208551573Smckusick 208651573Smckusick /* 208751573Smckusick * NFS file truncation. 208851573Smckusick */ 208952234Sheideman int 209053806Smckusick nfs_truncate(ap) 209153554Sheideman struct vop_truncate_args *ap; 209251573Smckusick { 209351573Smckusick 209451573Smckusick /* Use nfs_setattr */ 209551573Smckusick printf("nfs_truncate: need to implement!!"); 209651573Smckusick return (EOPNOTSUPP); 209751573Smckusick } 209851573Smckusick 209951573Smckusick /* 210051573Smckusick * NFS update. 210151573Smckusick */ 210252234Sheideman int 210353806Smckusick nfs_update(ap) 210453554Sheideman struct vop_update_args *ap; 210551573Smckusick { 210651573Smckusick 210751573Smckusick /* Use nfs_setattr */ 210851573Smckusick printf("nfs_update: need to implement!!"); 210951573Smckusick return (EOPNOTSUPP); 211051573Smckusick } 211153629Smckusick 211253629Smckusick /* 211353629Smckusick * Read wrapper for special devices. 211453629Smckusick */ 211553629Smckusick int 211653629Smckusick nfsspec_read(ap) 211753629Smckusick struct vop_read_args *ap; 211853629Smckusick { 211953629Smckusick extern int (**spec_vnodeop_p)(); 2120*54032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 212153629Smckusick 212253629Smckusick /* 212353629Smckusick * Set access flag. 212453629Smckusick */ 2125*54032Smckusick np->n_flag |= NACC; 2126*54032Smckusick np->n_atim = time; 212753629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 212853629Smckusick } 212953629Smckusick 213053629Smckusick /* 213153629Smckusick * Write wrapper for special devices. 213253629Smckusick */ 213353629Smckusick int 213453629Smckusick nfsspec_write(ap) 213553629Smckusick struct vop_write_args *ap; 213653629Smckusick { 213753629Smckusick extern int (**spec_vnodeop_p)(); 2138*54032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 213953629Smckusick 214053629Smckusick /* 2141*54032Smckusick * Set update flag. 214253629Smckusick */ 2143*54032Smckusick np->n_flag |= NUPD; 2144*54032Smckusick np->n_mtim = time; 214553629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 214653629Smckusick } 214753629Smckusick 214853629Smckusick /* 214953629Smckusick * Close wrapper for special devices. 215053629Smckusick * 215153629Smckusick * Update the times on the nfsnode then do device close. 215253629Smckusick */ 215353629Smckusick int 215453629Smckusick nfsspec_close(ap) 215553629Smckusick struct vop_close_args *ap; 215653629Smckusick { 215753629Smckusick USES_VOP_SETATTR; 215853806Smckusick register struct vnode *vp = ap->a_vp; 215953806Smckusick register struct nfsnode *np = VTONFS(vp); 216053629Smckusick struct vattr vattr; 216153629Smckusick extern int (**spec_vnodeop_p)(); 216253629Smckusick 216353629Smckusick if (np->n_flag & (NACC | NUPD)) { 216453629Smckusick if (np->n_flag & NACC) 216553629Smckusick np->n_atim = time; 216653629Smckusick if (np->n_flag & NUPD) 216753629Smckusick np->n_mtim = time; 216853629Smckusick np->n_flag |= NCHG; 216953806Smckusick if (vp->v_usecount == 1 && 217053806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 217153629Smckusick VATTR_NULL(&vattr); 217253629Smckusick if (np->n_flag & NACC) 217353629Smckusick vattr.va_atime = np->n_atim; 217453629Smckusick if (np->n_flag & NUPD) 217553629Smckusick vattr.va_mtime = np->n_mtim; 217653806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 217753629Smckusick } 217853629Smckusick } 217953629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 218053629Smckusick } 218153629Smckusick 218253629Smckusick #ifdef FIFO 218353629Smckusick /* 218453629Smckusick * Read wrapper for fifos. 218553629Smckusick */ 218653629Smckusick int 218753629Smckusick nfsfifo_read(ap) 218853629Smckusick struct vop_read_args *ap; 218953629Smckusick { 219053629Smckusick extern int (**fifo_vnodeop_p)(); 2191*54032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 219253629Smckusick 219353629Smckusick /* 219453629Smckusick * Set access flag. 219553629Smckusick */ 2196*54032Smckusick np->n_flag |= NACC; 2197*54032Smckusick np->n_atim = time; 219853629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 219953629Smckusick } 220053629Smckusick 220153629Smckusick /* 220253629Smckusick * Write wrapper for fifos. 220353629Smckusick */ 220453629Smckusick int 220553629Smckusick nfsfifo_write(ap) 220653629Smckusick struct vop_write_args *ap; 220753629Smckusick { 220853629Smckusick extern int (**fifo_vnodeop_p)(); 2209*54032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 221053629Smckusick 221153629Smckusick /* 221253629Smckusick * Set update flag. 221353629Smckusick */ 2214*54032Smckusick np->n_flag |= NUPD; 2215*54032Smckusick np->n_mtim = time; 221653629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 221753629Smckusick } 221853629Smckusick 221953629Smckusick /* 222053629Smckusick * Close wrapper for fifos. 222153629Smckusick * 222253629Smckusick * Update the times on the nfsnode then do fifo close. 222353629Smckusick */ 222453629Smckusick int 222553629Smckusick nfsfifo_close(ap) 222653629Smckusick struct vop_close_args *ap; 222753629Smckusick { 222853629Smckusick USES_VOP_SETATTR; 222953806Smckusick register struct vnode *vp = ap->a_vp; 223053806Smckusick register struct nfsnode *np = VTONFS(vp); 223153629Smckusick struct vattr vattr; 223253629Smckusick extern int (**fifo_vnodeop_p)(); 223353629Smckusick 223453629Smckusick if (np->n_flag & (NACC | NUPD)) { 223553629Smckusick if (np->n_flag & NACC) 223653629Smckusick np->n_atim = time; 223753629Smckusick if (np->n_flag & NUPD) 223853629Smckusick np->n_mtim = time; 223953629Smckusick np->n_flag |= NCHG; 224053806Smckusick if (vp->v_usecount == 1 && 224153806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 224253629Smckusick VATTR_NULL(&vattr); 224353629Smckusick if (np->n_flag & NACC) 224453629Smckusick vattr.va_atime = np->n_atim; 224553629Smckusick if (np->n_flag & NUPD) 224653629Smckusick vattr.va_mtime = np->n_mtim; 224753806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 224853629Smckusick } 224953629Smckusick } 225053629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 225153629Smckusick } 225253629Smckusick #endif /* FIFO */ 2253