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*53629Smckusick * @(#)nfs_vnops.c 7.77 (Berkeley) 05/20/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 }, 5353554Sheideman { &vop_lookup_desc, nfs_lookup }, /* lookup */ 5453554Sheideman { &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 */ 5853554Sheideman { &vop_access_desc, nfs_access }, /* access */ 5953554Sheideman { &vop_getattr_desc, nfs_getattr }, /* getattr */ 6053554Sheideman { &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 */ 6453554Sheideman { &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 */ 6853554Sheideman { &vop_remove_desc, nfs_remove }, /* remove */ 6953554Sheideman { &vop_link_desc, nfs_link }, /* link */ 7053554Sheideman { &vop_rename_desc, nfs_rename }, /* rename */ 7153554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 7253554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 7353554Sheideman { &vop_symlink_desc, nfs_symlink }, /* symlink */ 7453554Sheideman { &vop_readdir_desc, nfs_readdir }, /* readdir */ 7553554Sheideman { &vop_readlink_desc, nfs_readlink }, /* readlink */ 7653554Sheideman { &vop_abortop_desc, nfs_abortop }, /* abortop */ 7753554Sheideman { &vop_inactive_desc, nfs_inactive }, /* inactive */ 7853554Sheideman { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 7953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 8053554Sheideman { &vop_unlock_desc, nfs_unlock }, /* unlock */ 8153554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */ 8253554Sheideman { &vop_strategy_desc, nfs_strategy }, /* strategy */ 8353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 8453554Sheideman { &vop_islocked_desc, nfs_islocked }, /* islocked */ 8553554Sheideman { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8653554Sheideman { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 8753554Sheideman { &vop_vget_desc, nfs_vget }, /* vget */ 8853554Sheideman { &vop_valloc_desc, nfs_valloc }, /* valloc */ 8953554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */ 9053554Sheideman { &vop_truncate_desc, nfs_truncate }, /* truncate */ 9153554Sheideman { &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 }, 10453554Sheideman { &vop_lookup_desc, spec_lookup }, /* lookup */ 10553554Sheideman { &vop_create_desc, spec_create }, /* create */ 10653554Sheideman { &vop_mknod_desc, spec_mknod }, /* mknod */ 10753554Sheideman { &vop_open_desc, spec_open }, /* open */ 108*53629Smckusick { &vop_close_desc, nfsspec_close }, /* close */ 10953554Sheideman { &vop_access_desc, nfs_access }, /* access */ 11053554Sheideman { &vop_getattr_desc, nfs_getattr }, /* getattr */ 11153554Sheideman { &vop_setattr_desc, nfs_setattr }, /* setattr */ 112*53629Smckusick { &vop_read_desc, nfsspec_read }, /* read */ 113*53629Smckusick { &vop_write_desc, nfsspec_write }, /* write */ 11453554Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 11553554Sheideman { &vop_select_desc, spec_select }, /* select */ 11653554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 11753554Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 11853554Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 11953554Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 12053554Sheideman { &vop_link_desc, spec_link }, /* link */ 12153554Sheideman { &vop_rename_desc, spec_rename }, /* rename */ 12253554Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 12353554Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 12453554Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */ 12553554Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */ 12653554Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */ 12753554Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */ 12853554Sheideman { &vop_inactive_desc, nfs_inactive }, /* inactive */ 12953554Sheideman { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 13053554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 13153554Sheideman { &vop_unlock_desc, nfs_unlock }, /* unlock */ 13253554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 13353554Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */ 13453554Sheideman { &vop_print_desc, nfs_print }, /* print */ 13553554Sheideman { &vop_islocked_desc, nfs_islocked }, /* islocked */ 13653554Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 13753554Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 13853554Sheideman { &vop_vget_desc, spec_vget }, /* vget */ 13953554Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 14053554Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */ 14153554Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */ 14253554Sheideman { &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 }, 15353554Sheideman { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15453554Sheideman { &vop_create_desc, fifo_create }, /* create */ 15553554Sheideman { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15653554Sheideman { &vop_open_desc, fifo_open }, /* open */ 157*53629Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 15853554Sheideman { &vop_access_desc, nfs_access }, /* access */ 15953554Sheideman { &vop_getattr_desc, nfs_getattr }, /* getattr */ 16053554Sheideman { &vop_setattr_desc, nfs_setattr }, /* setattr */ 161*53629Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 162*53629Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16353554Sheideman { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16453554Sheideman { &vop_select_desc, fifo_select }, /* select */ 16553554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16653554Sheideman { &vop_fsync_desc, fifo_fsync }, /* fsync */ 16753554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 16853554Sheideman { &vop_remove_desc, fifo_remove }, /* remove */ 16953554Sheideman { &vop_link_desc, fifo_link }, /* link */ 17053554Sheideman { &vop_rename_desc, fifo_rename }, /* rename */ 17153554Sheideman { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17253554Sheideman { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17353554Sheideman { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17453554Sheideman { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17553554Sheideman { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17653554Sheideman { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17753554Sheideman { &vop_inactive_desc, nfs_inactive }, /* inactive */ 17853554Sheideman { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 17953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 18053554Sheideman { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18153554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18253554Sheideman { &vop_strategy_desc, fifo_badop }, /* strategy */ 18353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18453554Sheideman { &vop_islocked_desc, nfs_islocked }, /* islocked */ 18553554Sheideman { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18653554Sheideman { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 18753554Sheideman { &vop_vget_desc, fifo_vget }, /* vget */ 18853554Sheideman { &vop_valloc_desc, fifo_valloc }, /* valloc */ 18953554Sheideman { &vop_vfree_desc, fifo_vfree }, /* vfree */ 19053554Sheideman { &vop_truncate_desc, fifo_truncate }, /* truncate */ 19153554Sheideman { &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 23453554Sheideman nfs_access (ap) 23553554Sheideman struct vop_access_args *ap; 23638414Smckusick { 23753554Sheideman USES_VOP_GETATTR; 23838414Smckusick register struct vattr *vap; 23938414Smckusick register gid_t *gp; 24038414Smckusick struct vattr vattr; 24138414Smckusick register int i; 24238414Smckusick int error; 24338414Smckusick 24438414Smckusick /* 24538414Smckusick * If you're the super-user, 24638414Smckusick * you always get access. 24738414Smckusick */ 24853600Sheideman if (ap->a_cred->cr_uid == 0) 24938414Smckusick return (0); 25038414Smckusick vap = &vattr; 25153600Sheideman if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 25238884Smacklem return (error); 25338414Smckusick /* 25438414Smckusick * Access check is based on only one of owner, group, public. 25538414Smckusick * If not owner, then check group. If not a member of the 25638414Smckusick * group, then check public access. 25738414Smckusick */ 25853600Sheideman if (ap->a_cred->cr_uid != vap->va_uid) { 25953600Sheideman ap->a_mode >>= 3; 26053600Sheideman gp = ap->a_cred->cr_groups; 26153600Sheideman for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 26238414Smckusick if (vap->va_gid == *gp) 26338414Smckusick goto found; 26453600Sheideman ap->a_mode >>= 3; 26538414Smckusick found: 26638414Smckusick ; 26738414Smckusick } 26853600Sheideman if ((vap->va_mode & ap->a_mode) != 0) 26938414Smckusick return (0); 27038414Smckusick return (EACCES); 27138414Smckusick } 27238414Smckusick 27338414Smckusick /* 27438414Smckusick * nfs open vnode op 27538414Smckusick * Just check to see if the type is ok 27652196Smckusick * and that deletion is not in progress. 27738414Smckusick */ 27839488Smckusick /* ARGSUSED */ 27952234Sheideman int 28053554Sheideman nfs_open (ap) 28153554Sheideman struct vop_open_args *ap; 28238414Smckusick { 28338414Smckusick 28453600Sheideman if (ap->a_vp->v_type != VREG && ap->a_vp->v_type != VDIR && ap->a_vp->v_type != VLNK) 28538414Smckusick return (EACCES); 28653600Sheideman if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 28753600Sheideman VTONFS(ap->a_vp)->n_attrstamp = 0; /* For Open/Close consistency */ 28852196Smckusick return (0); 28938414Smckusick } 29038414Smckusick 29138414Smckusick /* 29238414Smckusick * nfs close vnode op 29338884Smacklem * For reg files, invalidate any buffer cache entries. 29438414Smckusick */ 29539488Smckusick /* ARGSUSED */ 29652234Sheideman int 29753554Sheideman nfs_close (ap) 29853554Sheideman struct vop_close_args *ap; 29938414Smckusick { 30053600Sheideman register struct nfsnode *np = VTONFS(ap->a_vp); 30139341Smckusick int error = 0; 30238414Smckusick 303*53629Smckusick if (ap->a_vp->v_type == VREG) { 304*53629Smckusick if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 305*53629Smckusick (np->n_flag & NMODIFIED)) { 30641905Smckusick np->n_flag &= ~NMODIFIED; 30753600Sheideman vinvalbuf(ap->a_vp, TRUE); 30841905Smckusick np->n_attrstamp = 0; 309*53629Smckusick } 310*53629Smckusick if (np->n_flag & NWRITEERR) { 311*53629Smckusick np->n_flag &= ~NWRITEERR; 312*53629Smckusick error = np->n_error; 313*53629Smckusick } 31438884Smacklem } 31538414Smckusick return (error); 31638414Smckusick } 31738414Smckusick 31838414Smckusick /* 31938414Smckusick * nfs getattr call from vfs. 32038414Smckusick */ 32152234Sheideman int 32253554Sheideman nfs_getattr (ap) 32353554Sheideman struct vop_getattr_args *ap; 32438414Smckusick { 32539488Smckusick register caddr_t cp; 32639488Smckusick caddr_t bpos, dpos; 32739488Smckusick int error = 0; 32839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 32938414Smckusick 33038414Smckusick /* First look in the cache.. */ 33153600Sheideman if (nfs_getattrcache(ap->a_vp, ap->a_vap) == 0) 33238414Smckusick return (0); 33338414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 33453600Sheideman nfsm_reqhead(ap->a_vp, NFSPROC_GETATTR, NFSX_FH); 33553600Sheideman nfsm_fhtom(ap->a_vp); 33653600Sheideman nfsm_request(ap->a_vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 33753600Sheideman nfsm_loadattr(ap->a_vp, ap->a_vap); 33838414Smckusick nfsm_reqdone; 33938414Smckusick return (error); 34038414Smckusick } 34138414Smckusick 34238414Smckusick /* 34338414Smckusick * nfs setattr call. 34438414Smckusick */ 34552234Sheideman int 34653554Sheideman nfs_setattr (ap) 34753554Sheideman struct vop_setattr_args *ap; 34838414Smckusick { 34938884Smacklem register struct nfsv2_sattr *sp; 35039488Smckusick register caddr_t cp; 35139488Smckusick register long t1; 35252196Smckusick caddr_t bpos, dpos, cp2; 35352196Smckusick u_long *tl; 35439488Smckusick int error = 0; 35539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 35653600Sheideman struct nfsnode *np = VTONFS(ap->a_vp); 35752196Smckusick u_quad_t frev; 35838414Smckusick 35938414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 36053600Sheideman nfsm_reqhead(ap->a_vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR); 36153600Sheideman nfsm_fhtom(ap->a_vp); 36238884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 36353600Sheideman if (ap->a_vap->va_mode == 0xffff) 36438884Smacklem sp->sa_mode = VNOVAL; 36538414Smckusick else 36653600Sheideman sp->sa_mode = vtonfs_mode(ap->a_vp->v_type, ap->a_vap->va_mode); 36753600Sheideman if (ap->a_vap->va_uid == 0xffff) 36838884Smacklem sp->sa_uid = VNOVAL; 36938414Smckusick else 37053600Sheideman sp->sa_uid = txdr_unsigned(ap->a_vap->va_uid); 37153600Sheideman if (ap->a_vap->va_gid == 0xffff) 37238884Smacklem sp->sa_gid = VNOVAL; 37338414Smckusick else 37453600Sheideman sp->sa_gid = txdr_unsigned(ap->a_vap->va_gid); 37553600Sheideman sp->sa_size = txdr_unsigned(ap->a_vap->va_size); 37653600Sheideman sp->sa_atime.tv_sec = txdr_unsigned(ap->a_vap->va_atime.tv_sec); 37753600Sheideman sp->sa_atime.tv_usec = txdr_unsigned(ap->a_vap->va_flags); 37853600Sheideman txdr_time(&ap->a_vap->va_mtime, &sp->sa_mtime); 37953600Sheideman if (ap->a_vap->va_size != VNOVAL || ap->a_vap->va_mtime.tv_sec != VNOVAL || 38053600Sheideman ap->a_vap->va_atime.tv_sec != VNOVAL) { 38139359Smckusick if (np->n_flag & NMODIFIED) { 38239359Smckusick np->n_flag &= ~NMODIFIED; 38353600Sheideman if (ap->a_vap->va_size == 0) 38453600Sheideman vinvalbuf(ap->a_vp, FALSE); 38546988Smckusick else 38653600Sheideman vinvalbuf(ap->a_vp, TRUE); 38739359Smckusick } 38839359Smckusick } 38953600Sheideman nfsm_request(ap->a_vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 39053600Sheideman nfsm_loadattr(ap->a_vp, (struct vattr *)0); 39153600Sheideman if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 39253600Sheideman NQNFS_CKCACHABLE(ap->a_vp, NQL_WRITE)) { 39352196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 39452196Smckusick fxdr_hyper(tl, &frev); 39552196Smckusick if (QUADGT(frev, np->n_brev)) 39652196Smckusick np->n_brev = frev; 39752196Smckusick } 39838414Smckusick nfsm_reqdone; 39938414Smckusick return (error); 40038414Smckusick } 40138414Smckusick 40238414Smckusick /* 40338414Smckusick * nfs lookup call, one step at a time... 40438414Smckusick * First look in cache 40538414Smckusick * If not found, unlock the directory nfsnode and do the rpc 40638414Smckusick */ 40752234Sheideman int 40853554Sheideman nfs_lookup (ap) 40953554Sheideman struct vop_lookup_args *ap; 41038414Smckusick { 41153554Sheideman USES_VOP_GETATTR; 41238414Smckusick register struct vnode *vdp; 41348054Smckusick register u_long *tl; 41439488Smckusick register caddr_t cp; 41539488Smckusick register long t1, t2; 41652196Smckusick struct nfsmount *nmp; 41752196Smckusick struct nfsnode *tp; 41839488Smckusick caddr_t bpos, dpos, cp2; 41952196Smckusick time_t reqtime; 42039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 42138414Smckusick struct vnode *newvp; 42238414Smckusick long len; 42338414Smckusick nfsv2fh_t *fhp; 42438414Smckusick struct nfsnode *np; 42552234Sheideman int lockparent, wantparent, error = 0; 42652196Smckusick int nqlflag, cachable; 42752196Smckusick u_quad_t frev; 42838414Smckusick 42953600Sheideman *ap->a_vpp = NULL; 43053600Sheideman if (ap->a_dvp->v_type != VDIR) 43138414Smckusick return (ENOTDIR); 43253600Sheideman lockparent = ap->a_cnp->cn_flags & LOCKPARENT; 43353600Sheideman wantparent = ap->a_cnp->cn_flags & (LOCKPARENT|WANTPARENT); 43453600Sheideman nmp = VFSTONFS(ap->a_dvp->v_mount); 43553600Sheideman np = VTONFS(ap->a_dvp); 43653600Sheideman if ((error = cache_lookup(ap->a_dvp, ap->a_vpp, ap->a_cnp)) && error != ENOENT) { 43738884Smacklem struct vattr vattr; 43838884Smacklem int vpid; 43938884Smacklem 44053600Sheideman vdp = *ap->a_vpp; 44138884Smacklem vpid = vdp->v_id; 44238414Smckusick /* 44338884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 44438884Smacklem * for an explanation of the locking protocol 44538414Smckusick */ 44653600Sheideman if (ap->a_dvp == vdp) { 44738425Smckusick VREF(vdp); 44839441Smckusick error = 0; 44952196Smckusick } else 45039441Smckusick error = vget(vdp); 45139441Smckusick if (!error) { 45240251Smckusick if (vpid == vdp->v_id) { 45352196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 45453600Sheideman if (NQNFS_CKCACHABLE(ap->a_dvp, NQL_READ)) { 45552196Smckusick if (QUADNE(np->n_lrev, np->n_brev) || 45652196Smckusick (np->n_flag & NMODIFIED)) { 45752196Smckusick np->n_direofoffset = 0; 45853600Sheideman cache_purge(ap->a_dvp); 45952196Smckusick np->n_flag &= ~NMODIFIED; 46053600Sheideman vinvalbuf(ap->a_dvp, FALSE); 46152196Smckusick np->n_brev = np->n_lrev; 46252196Smckusick } else { 46352196Smckusick nfsstats.lookupcache_hits++; 46453600Sheideman if (ap->a_cnp->cn_nameiop != LOOKUP && 46553600Sheideman (ap->a_cnp->cn_flags&ISLASTCN)) 46653600Sheideman ap->a_cnp->cn_flags |= SAVENAME; 46752196Smckusick return (0); 46852196Smckusick } 46952196Smckusick } 47053600Sheideman } else if (!VOP_GETATTR(vdp, &vattr, ap->a_cnp->cn_cred, ap->a_cnp->cn_proc) && 47140251Smckusick vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) { 47239441Smckusick nfsstats.lookupcache_hits++; 47353600Sheideman if (ap->a_cnp->cn_nameiop != LOOKUP && (ap->a_cnp->cn_flags&ISLASTCN)) 47453600Sheideman ap->a_cnp->cn_flags |= SAVENAME; 47539441Smckusick return (0); 47640251Smckusick } 47747289Smckusick cache_purge(vdp); 47839441Smckusick } 47952196Smckusick vrele(vdp); 48038884Smacklem } 48153600Sheideman *ap->a_vpp = NULLVP; 48252196Smckusick } 48339341Smckusick error = 0; 48438414Smckusick nfsstats.lookupcache_misses++; 48538414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 48653600Sheideman len = ap->a_cnp->cn_namelen; 48753600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 48852196Smckusick 48952196Smckusick /* 49052196Smckusick * For nqnfs optionally piggyback a getlease request for the name 49152196Smckusick * being looked up. 49252196Smckusick */ 49352196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 49452196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 49553600Sheideman ((ap->a_cnp->cn_flags&MAKEENTRY) && (ap->a_cnp->cn_nameiop != DELETE || !(ap->a_cnp->cn_flags&ISLASTCN)))) { 49652196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 49752196Smckusick *tl++ = txdr_unsigned(NQL_READ); 49852196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 49952196Smckusick } else { 50052196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 50152196Smckusick *tl = 0; 50252196Smckusick } 50352196Smckusick } 50453600Sheideman nfsm_fhtom(ap->a_dvp); 50553600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, len, NFS_MAXNAMLEN); 50652196Smckusick reqtime = time.tv_sec; 50753600Sheideman nfsm_request(ap->a_dvp, NFSPROC_LOOKUP, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 50838414Smckusick nfsmout: 50938414Smckusick if (error) { 51053600Sheideman if ((ap->a_cnp->cn_nameiop == CREATE || ap->a_cnp->cn_nameiop == RENAME) && 51153600Sheideman (ap->a_cnp->cn_flags & ISLASTCN) && error == ENOENT) 51252823Smckusick error = EJUSTRETURN; 51353600Sheideman if (ap->a_cnp->cn_nameiop != LOOKUP && (ap->a_cnp->cn_flags&ISLASTCN)) 51453600Sheideman ap->a_cnp->cn_flags |= SAVENAME; 51540483Smckusick return (error); 51638414Smckusick } 51752196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 51852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 51952196Smckusick if (*tl) { 52052196Smckusick nqlflag = fxdr_unsigned(int, *tl); 52152196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 52252196Smckusick cachable = fxdr_unsigned(int, *tl++); 52352196Smckusick reqtime += fxdr_unsigned(int, *tl++); 52452196Smckusick fxdr_hyper(tl, &frev); 52552196Smckusick } else 52652196Smckusick nqlflag = 0; 52752196Smckusick } 52852196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 52938414Smckusick 53038414Smckusick /* 53152196Smckusick * Handle RENAME case... 53238414Smckusick */ 53353600Sheideman if (ap->a_cnp->cn_nameiop == RENAME && wantparent && (ap->a_cnp->cn_flags&ISLASTCN)) { 53452196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 53538414Smckusick m_freem(mrep); 53638414Smckusick return (EISDIR); 53738414Smckusick } 53853600Sheideman if (error = nfs_nget(ap->a_dvp->v_mount, fhp, &np)) { 53938414Smckusick m_freem(mrep); 54038414Smckusick return (error); 54138414Smckusick } 54238414Smckusick newvp = NFSTOV(np); 54339459Smckusick if (error = 54439459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 54552196Smckusick vrele(newvp); 54638414Smckusick m_freem(mrep); 54738414Smckusick return (error); 54838414Smckusick } 54953600Sheideman *ap->a_vpp = newvp; 55045037Smckusick m_freem(mrep); 55153600Sheideman ap->a_cnp->cn_flags |= SAVENAME; 55238414Smckusick return (0); 55338414Smckusick } 55438414Smckusick 55552196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 55653600Sheideman VREF(ap->a_dvp); 55753600Sheideman newvp = ap->a_dvp; 55838414Smckusick } else { 55953600Sheideman if (error = nfs_nget(ap->a_dvp->v_mount, fhp, &np)) { 56038414Smckusick m_freem(mrep); 56138414Smckusick return (error); 56238414Smckusick } 56338414Smckusick newvp = NFSTOV(np); 56438414Smckusick } 56539459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 56652196Smckusick vrele(newvp); 56738414Smckusick m_freem(mrep); 56838414Smckusick return (error); 56938414Smckusick } 57038414Smckusick m_freem(mrep); 57153600Sheideman *ap->a_vpp = newvp; 57253600Sheideman if (ap->a_cnp->cn_nameiop != LOOKUP && (ap->a_cnp->cn_flags&ISLASTCN)) 57353600Sheideman ap->a_cnp->cn_flags |= SAVENAME; 57453600Sheideman if ((ap->a_cnp->cn_flags&MAKEENTRY) && (ap->a_cnp->cn_nameiop != DELETE || !(ap->a_cnp->cn_flags&ISLASTCN))) { 57552196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 57652196Smckusick np->n_ctime = np->n_vattr.va_ctime.tv_sec; 57752196Smckusick else if (nqlflag && reqtime > time.tv_sec) { 57852196Smckusick if (np->n_tnext) { 57952196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 58052196Smckusick nmp->nm_tprev = np->n_tprev; 58152196Smckusick else 58252196Smckusick np->n_tnext->n_tprev = np->n_tprev; 58352196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 58452196Smckusick nmp->nm_tnext = np->n_tnext; 58552196Smckusick else 58652196Smckusick np->n_tprev->n_tnext = np->n_tnext; 58752196Smckusick if (nqlflag == NQL_WRITE) 58852196Smckusick np->n_flag |= NQNFSWRITE; 58952196Smckusick } else if (nqlflag == NQL_READ) 59052196Smckusick np->n_flag &= ~NQNFSWRITE; 59152196Smckusick else 59252196Smckusick np->n_flag |= NQNFSWRITE; 59352196Smckusick if (cachable) 59452196Smckusick np->n_flag &= ~NQNFSNONCACHE; 59552196Smckusick else 59652196Smckusick np->n_flag |= NQNFSNONCACHE; 59752196Smckusick np->n_expiry = reqtime; 59852196Smckusick np->n_lrev = frev; 59952196Smckusick tp = nmp->nm_tprev; 60052196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 60152196Smckusick tp = tp->n_tprev; 60252196Smckusick if (tp == (struct nfsnode *)nmp) { 60352196Smckusick np->n_tnext = nmp->nm_tnext; 60452196Smckusick nmp->nm_tnext = np; 60552196Smckusick } else { 60652196Smckusick np->n_tnext = tp->n_tnext; 60752196Smckusick tp->n_tnext = np; 60852196Smckusick } 60952196Smckusick np->n_tprev = tp; 61052196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 61152196Smckusick nmp->nm_tprev = np; 61252196Smckusick else 61352196Smckusick np->n_tnext->n_tprev = np; 61452196Smckusick } 61553600Sheideman cache_enter(ap->a_dvp, *ap->a_vpp, ap->a_cnp); 61640251Smckusick } 61752196Smckusick return (0); 61838414Smckusick } 61938414Smckusick 62038414Smckusick /* 62141905Smckusick * nfs read call. 62241905Smckusick * Just call nfs_bioread() to do the work. 62341905Smckusick */ 62452234Sheideman int 62553554Sheideman nfs_read (ap) 62653554Sheideman struct vop_read_args *ap; 62741905Smckusick { 62853600Sheideman if (ap->a_vp->v_type != VREG) 62941905Smckusick return (EPERM); 63053600Sheideman return (nfs_bioread(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 63141905Smckusick } 63241905Smckusick 63341905Smckusick /* 63438414Smckusick * nfs readlink call 63538414Smckusick */ 63652234Sheideman int 63753554Sheideman nfs_readlink (ap) 63853554Sheideman struct vop_readlink_args *ap; 63941905Smckusick { 64053600Sheideman if (ap->a_vp->v_type != VLNK) 64141905Smckusick return (EPERM); 64253600Sheideman return (nfs_bioread(ap->a_vp, ap->a_uio, 0, ap->a_cred)); 64341905Smckusick } 64441905Smckusick 64541905Smckusick /* 64641905Smckusick * Do a readlink rpc. 64741905Smckusick * Called by nfs_doio() from below the buffer cache. 64841905Smckusick */ 64952234Sheideman int 65048054Smckusick nfs_readlinkrpc(vp, uiop, cred) 65139488Smckusick register struct vnode *vp; 65238414Smckusick struct uio *uiop; 65338414Smckusick struct ucred *cred; 65438414Smckusick { 65548054Smckusick register u_long *tl; 65639488Smckusick register caddr_t cp; 65739488Smckusick register long t1; 65839488Smckusick caddr_t bpos, dpos, cp2; 65939488Smckusick int error = 0; 66039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 66138414Smckusick long len; 66238414Smckusick 66338414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 66452196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 66538414Smckusick nfsm_fhtom(vp); 66652196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 66738414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 66838414Smckusick nfsm_mtouio(uiop, len); 66938414Smckusick nfsm_reqdone; 67038414Smckusick return (error); 67138414Smckusick } 67238414Smckusick 67338414Smckusick /* 67441905Smckusick * nfs read rpc call 67541905Smckusick * Ditto above 67638414Smckusick */ 67752234Sheideman int 67848054Smckusick nfs_readrpc(vp, uiop, cred) 67939488Smckusick register struct vnode *vp; 68038414Smckusick struct uio *uiop; 68138414Smckusick struct ucred *cred; 68238414Smckusick { 68348054Smckusick register u_long *tl; 68439488Smckusick register caddr_t cp; 68539488Smckusick register long t1; 68639488Smckusick caddr_t bpos, dpos, cp2; 68739488Smckusick int error = 0; 68839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 68938414Smckusick struct nfsmount *nmp; 69038414Smckusick long len, retlen, tsiz; 69138414Smckusick 69241398Smckusick nmp = VFSTONFS(vp->v_mount); 69338414Smckusick tsiz = uiop->uio_resid; 69438414Smckusick while (tsiz > 0) { 69538414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 69638414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 69752196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 69838414Smckusick nfsm_fhtom(vp); 69948054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 70048054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 70148054Smckusick *tl++ = txdr_unsigned(len); 70248054Smckusick *tl = 0; 70352196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 70438414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 70538414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 70638414Smckusick nfsm_mtouio(uiop, retlen); 70738414Smckusick m_freem(mrep); 70838414Smckusick if (retlen < len) 70938414Smckusick tsiz = 0; 71038414Smckusick else 71138414Smckusick tsiz -= len; 71238414Smckusick } 71338414Smckusick nfsmout: 71438414Smckusick return (error); 71538414Smckusick } 71638414Smckusick 71738414Smckusick /* 71838414Smckusick * nfs write call 71938414Smckusick */ 72052234Sheideman int 72148054Smckusick nfs_writerpc(vp, uiop, cred) 72239488Smckusick register struct vnode *vp; 72338414Smckusick struct uio *uiop; 72438414Smckusick struct ucred *cred; 72538414Smckusick { 72648054Smckusick register u_long *tl; 72739488Smckusick register caddr_t cp; 72839488Smckusick register long t1; 72952196Smckusick caddr_t bpos, dpos, cp2; 73039488Smckusick int error = 0; 73139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 73238414Smckusick struct nfsmount *nmp; 73352196Smckusick struct nfsnode *np = VTONFS(vp); 73452196Smckusick u_quad_t frev; 73538414Smckusick long len, tsiz; 73638414Smckusick 73741398Smckusick nmp = VFSTONFS(vp->v_mount); 73838414Smckusick tsiz = uiop->uio_resid; 73938414Smckusick while (tsiz > 0) { 74038414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 74138414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 74252196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 74352196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 74438414Smckusick nfsm_fhtom(vp); 74548054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*4); 74648054Smckusick *(tl+1) = txdr_unsigned(uiop->uio_offset); 74748054Smckusick *(tl+3) = txdr_unsigned(len); 74838414Smckusick nfsm_uiotom(uiop, len); 74952196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 75038414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 75152196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 75252196Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec; 75352196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 75452196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 75552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 75652196Smckusick fxdr_hyper(tl, &frev); 75752196Smckusick if (QUADGT(frev, np->n_brev)) 75852196Smckusick np->n_brev = frev; 75952196Smckusick } 76038414Smckusick m_freem(mrep); 76138414Smckusick tsiz -= len; 76238414Smckusick } 76338414Smckusick nfsmout: 76452196Smckusick if (error) 76552196Smckusick uiop->uio_resid = tsiz; 76638414Smckusick return (error); 76738414Smckusick } 76838414Smckusick 76938414Smckusick /* 77039459Smckusick * nfs mknod call 77142246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 77242246Smckusick * set to specify the file type and the size field for rdev. 77339459Smckusick */ 77439459Smckusick /* ARGSUSED */ 77552234Sheideman int 77653554Sheideman nfs_mknod (ap) 77753554Sheideman struct vop_mknod_args *ap; 77839459Smckusick { 77953554Sheideman USES_VOP_ABORTOP; 78042246Smckusick register struct nfsv2_sattr *sp; 78148054Smckusick register u_long *tl; 78242246Smckusick register caddr_t cp; 78352196Smckusick register long t2; 78442246Smckusick caddr_t bpos, dpos; 78542246Smckusick int error = 0; 78642246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 78742246Smckusick u_long rdev; 78839459Smckusick 78953600Sheideman if (ap->a_vap->va_type == VCHR || ap->a_vap->va_type == VBLK) 79053600Sheideman rdev = txdr_unsigned(ap->a_vap->va_rdev); 79142246Smckusick #ifdef FIFO 79253600Sheideman else if (ap->a_vap->va_type == VFIFO) 79342246Smckusick rdev = 0xffffffff; 79442246Smckusick #endif /* FIFO */ 79542246Smckusick else { 79653600Sheideman VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 79753600Sheideman vput(ap->a_dvp); 79842246Smckusick return (EOPNOTSUPP); 79942246Smckusick } 80042246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 80153600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_CREATE, 80253600Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ap->a_cnp->cn_namelen)+NFSX_SATTR); 80353600Sheideman nfsm_fhtom(ap->a_dvp); 80453600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, NFS_MAXNAMLEN); 80542246Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 80653600Sheideman sp->sa_mode = vtonfs_mode(ap->a_vap->va_type, ap->a_vap->va_mode); 80753600Sheideman sp->sa_uid = txdr_unsigned(ap->a_cnp->cn_cred->cr_uid); 80853600Sheideman sp->sa_gid = txdr_unsigned(ap->a_cnp->cn_cred->cr_gid); 80942246Smckusick sp->sa_size = rdev; 81042246Smckusick /* or should these be VNOVAL ?? */ 81153600Sheideman txdr_time(&ap->a_vap->va_atime, &sp->sa_atime); 81253600Sheideman txdr_time(&ap->a_vap->va_mtime, &sp->sa_mtime); 81353600Sheideman nfsm_request(ap->a_dvp, NFSPROC_CREATE, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 81442246Smckusick nfsm_reqdone; 81553600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 81653600Sheideman VTONFS(ap->a_dvp)->n_flag |= NMODIFIED; 81753600Sheideman vrele(ap->a_dvp); 81842246Smckusick return (error); 81939459Smckusick } 82039459Smckusick 82139459Smckusick /* 82238414Smckusick * nfs file create call 82338414Smckusick */ 82452234Sheideman int 82553554Sheideman nfs_create (ap) 82653554Sheideman struct vop_create_args *ap; 82738414Smckusick { 82838884Smacklem register struct nfsv2_sattr *sp; 82948054Smckusick register u_long *tl; 83039488Smckusick register caddr_t cp; 83139488Smckusick register long t1, t2; 83239488Smckusick caddr_t bpos, dpos, cp2; 83339488Smckusick int error = 0; 83439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 83538414Smckusick 83638414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 83753600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_CREATE, 83853600Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ap->a_cnp->cn_namelen)+NFSX_SATTR); 83953600Sheideman nfsm_fhtom(ap->a_dvp); 84053600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, NFS_MAXNAMLEN); 84138884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 84253600Sheideman sp->sa_mode = vtonfs_mode(ap->a_vap->va_type, ap->a_vap->va_mode); 84353600Sheideman sp->sa_uid = txdr_unsigned(ap->a_cnp->cn_cred->cr_uid); 84453600Sheideman sp->sa_gid = txdr_unsigned(ap->a_cnp->cn_cred->cr_gid); 84538884Smacklem sp->sa_size = txdr_unsigned(0); 84638414Smckusick /* or should these be VNOVAL ?? */ 84753600Sheideman txdr_time(&ap->a_vap->va_atime, &sp->sa_atime); 84853600Sheideman txdr_time(&ap->a_vap->va_mtime, &sp->sa_mtime); 84953600Sheideman nfsm_request(ap->a_dvp, NFSPROC_CREATE, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 85053600Sheideman nfsm_mtofh(ap->a_dvp, *ap->a_vpp); 85138414Smckusick nfsm_reqdone; 85253600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 85353600Sheideman VTONFS(ap->a_dvp)->n_flag |= NMODIFIED; 85453600Sheideman vrele(ap->a_dvp); 85538414Smckusick return (error); 85638414Smckusick } 85738414Smckusick 85838414Smckusick /* 85938414Smckusick * nfs file remove call 86041905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 86141905Smckusick * other processes using the vnode is renamed instead of removed and then 86239341Smckusick * removed later on the last close. 86341905Smckusick * - If v_usecount > 1 86439341Smckusick * If a rename is not already in the works 86539341Smckusick * call nfs_sillyrename() to set it up 86639341Smckusick * else 86739341Smckusick * do the remove rpc 86838414Smckusick */ 86952234Sheideman int 87053554Sheideman nfs_remove (ap) 87153554Sheideman struct vop_remove_args *ap; 87238414Smckusick { 87353600Sheideman register struct nfsnode *np = VTONFS(ap->a_vp); 87448054Smckusick register u_long *tl; 87539488Smckusick register caddr_t cp; 87652196Smckusick register long t2; 87739488Smckusick caddr_t bpos, dpos; 87839488Smckusick int error = 0; 87939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 88038414Smckusick 88153600Sheideman if (ap->a_vp->v_usecount > 1) { 88239341Smckusick if (!np->n_sillyrename) 88353600Sheideman error = nfs_sillyrename(ap->a_dvp, ap->a_vp, ap->a_cnp); 88439341Smckusick } else { 88552196Smckusick /* 88652196Smckusick * Purge the name cache so that the chance of a lookup for 88752196Smckusick * the name succeeding while the remove is in progress is 88852196Smckusick * minimized. Without node locking it can still happen, such 88952196Smckusick * that an I/O op returns ESTALE, but since you get this if 89052196Smckusick * another host removes the file.. 89152196Smckusick */ 89253600Sheideman cache_purge(ap->a_vp); 89352196Smckusick /* 89452196Smckusick * Throw away biocache buffers. Mainly to avoid 89552196Smckusick * unnecessary delayed writes. 89652196Smckusick */ 89753600Sheideman vinvalbuf(ap->a_vp, FALSE); 89852196Smckusick /* Do the rpc */ 89938414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 90053600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_REMOVE, 90153600Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ap->a_cnp->cn_namelen)); 90253600Sheideman nfsm_fhtom(ap->a_dvp); 90353600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, NFS_MAXNAMLEN); 90453600Sheideman nfsm_request(ap->a_dvp, NFSPROC_REMOVE, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 90538414Smckusick nfsm_reqdone; 90653600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 90753600Sheideman VTONFS(ap->a_dvp)->n_flag |= NMODIFIED; 90839751Smckusick /* 90939751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 91039751Smckusick * the reply to the retransmitted request will be ENOENT 91139751Smckusick * since the file was in fact removed 91239751Smckusick * Therefore, we cheat and return success. 91339751Smckusick */ 91439751Smckusick if (error == ENOENT) 91539751Smckusick error = 0; 91638414Smckusick } 91740042Smckusick np->n_attrstamp = 0; 91853600Sheideman vrele(ap->a_dvp); 91953600Sheideman vrele(ap->a_vp); 92038414Smckusick return (error); 92138414Smckusick } 92238414Smckusick 92338414Smckusick /* 92438414Smckusick * nfs file remove rpc called from nfs_inactive 92538414Smckusick */ 92652234Sheideman int 92752196Smckusick nfs_removeit(sp, procp) 92848364Smckusick register struct sillyrename *sp; 92952196Smckusick struct proc *procp; 93038414Smckusick { 93148054Smckusick register u_long *tl; 93239488Smckusick register caddr_t cp; 93352196Smckusick register long t2; 93439488Smckusick caddr_t bpos, dpos; 93539488Smckusick int error = 0; 93639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 93738414Smckusick 93838414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 93952196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 94048364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 94148364Smckusick nfsm_fhtom(sp->s_dvp); 94248364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 94352196Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, procp, sp->s_cred); 94438414Smckusick nfsm_reqdone; 94548364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 94638414Smckusick return (error); 94738414Smckusick } 94838414Smckusick 94938414Smckusick /* 95038414Smckusick * nfs file rename call 95138414Smckusick */ 95252234Sheideman int 95353554Sheideman nfs_rename (ap) 95453554Sheideman struct vop_rename_args *ap; 95538414Smckusick { 95648054Smckusick register u_long *tl; 95739488Smckusick register caddr_t cp; 95852196Smckusick register long t2; 95939488Smckusick caddr_t bpos, dpos; 96039488Smckusick int error = 0; 96139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 96238414Smckusick 96338414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 96453600Sheideman nfsm_reqhead(ap->a_fdvp, NFSPROC_RENAME, 96553600Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(ap->a_fcnp->cn_namelen)+ 96653600Sheideman nfsm_rndup(ap->a_fcnp->cn_namelen)); /* or ap->a_fcnp->cn_cred?*/ 96753600Sheideman nfsm_fhtom(ap->a_fdvp); 96853600Sheideman nfsm_strtom(ap->a_fcnp->cn_nameptr, ap->a_fcnp->cn_namelen, NFS_MAXNAMLEN); 96953600Sheideman nfsm_fhtom(ap->a_tdvp); 97053600Sheideman nfsm_strtom(ap->a_tcnp->cn_nameptr, ap->a_tcnp->cn_namelen, NFS_MAXNAMLEN); 97153600Sheideman nfsm_request(ap->a_fdvp, NFSPROC_RENAME, ap->a_tcnp->cn_proc, ap->a_tcnp->cn_cred); 97238414Smckusick nfsm_reqdone; 97353600Sheideman VTONFS(ap->a_fdvp)->n_flag |= NMODIFIED; 97453600Sheideman VTONFS(ap->a_tdvp)->n_flag |= NMODIFIED; 97553600Sheideman if (ap->a_fvp->v_type == VDIR) { 97653600Sheideman if (ap->a_tvp != NULL && ap->a_tvp->v_type == VDIR) 97753600Sheideman cache_purge(ap->a_tdvp); 97853600Sheideman cache_purge(ap->a_fdvp); 97938414Smckusick } 98053600Sheideman if (ap->a_tdvp == ap->a_tvp) 98153600Sheideman vrele(ap->a_tdvp); 98243360Smckusick else 98353600Sheideman vput(ap->a_tdvp); 98453600Sheideman if (ap->a_tvp) 98553600Sheideman vput(ap->a_tvp); 98653600Sheideman vrele(ap->a_fdvp); 98753600Sheideman vrele(ap->a_fvp); 98840112Smckusick /* 98940112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 99040112Smckusick */ 99140112Smckusick if (error == ENOENT) 99240112Smckusick error = 0; 99338414Smckusick return (error); 99438414Smckusick } 99538414Smckusick 99638414Smckusick /* 99741905Smckusick * nfs file rename rpc called from nfs_remove() above 99838414Smckusick */ 99952234Sheideman int 100052234Sheideman nfs_renameit(sdvp, scnp, sp) 100152234Sheideman struct vnode *sdvp; 100252234Sheideman struct componentname *scnp; 100348364Smckusick register struct sillyrename *sp; 100438414Smckusick { 100548054Smckusick register u_long *tl; 100639488Smckusick register caddr_t cp; 100752196Smckusick register long t2; 100839488Smckusick caddr_t bpos, dpos; 100939488Smckusick int error = 0; 101039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 101138414Smckusick 101238414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 101352234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 101452234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 101552196Smckusick nfsm_rndup(sp->s_namlen)); 101652234Sheideman nfsm_fhtom(sdvp); 101752234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 101852234Sheideman nfsm_fhtom(sdvp); 101948364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 102052234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 102138414Smckusick nfsm_reqdone; 102252234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 102352234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 102438414Smckusick return (error); 102538414Smckusick } 102638414Smckusick 102738414Smckusick /* 102838414Smckusick * nfs hard link create call 102938414Smckusick */ 103052234Sheideman int 103153554Sheideman nfs_link (ap) 103253554Sheideman struct vop_link_args *ap; 103338414Smckusick { 103448054Smckusick register u_long *tl; 103539488Smckusick register caddr_t cp; 103652196Smckusick register long t2; 103739488Smckusick caddr_t bpos, dpos; 103839488Smckusick int error = 0; 103939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 104038414Smckusick 104138414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 104253600Sheideman nfsm_reqhead(ap->a_tdvp, NFSPROC_LINK, 104353600Sheideman NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ap->a_cnp->cn_namelen)); 104453600Sheideman nfsm_fhtom(ap->a_tdvp); 104553600Sheideman nfsm_fhtom(ap->a_vp); 104653600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, NFS_MAXNAMLEN); 104753600Sheideman nfsm_request(ap->a_tdvp, NFSPROC_LINK, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 104838414Smckusick nfsm_reqdone; 104953600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 105053600Sheideman VTONFS(ap->a_tdvp)->n_attrstamp = 0; 105153600Sheideman VTONFS(ap->a_vp)->n_flag |= NMODIFIED; 105253600Sheideman vrele(ap->a_vp); 105340112Smckusick /* 105440112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 105540112Smckusick */ 105640112Smckusick if (error == EEXIST) 105740112Smckusick error = 0; 105838414Smckusick return (error); 105938414Smckusick } 106038414Smckusick 106138414Smckusick /* 106238414Smckusick * nfs symbolic link create call 106338414Smckusick */ 106452234Sheideman /* start here */ 106552234Sheideman int 106653554Sheideman nfs_symlink (ap) 106753554Sheideman struct vop_symlink_args *ap; 106838414Smckusick { 106938884Smacklem register struct nfsv2_sattr *sp; 107048054Smckusick register u_long *tl; 107139488Smckusick register caddr_t cp; 107252196Smckusick register long t2; 107339488Smckusick caddr_t bpos, dpos; 107452196Smckusick int slen, error = 0; 107539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 107638414Smckusick 107738414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 107853600Sheideman slen = strlen(ap->a_target); 107953600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_SYMLINK, 108053600Sheideman NFSX_FH+2*NFSX_UNSIGNED+nfsm_rndup(ap->a_cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR); 108153600Sheideman nfsm_fhtom(ap->a_dvp); 108253600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, NFS_MAXNAMLEN); 108353600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 108438884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 108553600Sheideman sp->sa_mode = vtonfs_mode(VLNK, ap->a_vap->va_mode); 108653600Sheideman sp->sa_uid = txdr_unsigned(ap->a_cnp->cn_cred->cr_uid); 108753600Sheideman sp->sa_gid = txdr_unsigned(ap->a_cnp->cn_cred->cr_gid); 108838884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 108953600Sheideman txdr_time(&ap->a_vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 109053600Sheideman txdr_time(&ap->a_vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 109153600Sheideman nfsm_request(ap->a_dvp, NFSPROC_SYMLINK, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 109238414Smckusick nfsm_reqdone; 109353600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 109453600Sheideman VTONFS(ap->a_dvp)->n_flag |= NMODIFIED; 109553600Sheideman vrele(ap->a_dvp); 109640112Smckusick /* 109740112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 109840112Smckusick */ 109940112Smckusick if (error == EEXIST) 110040112Smckusick error = 0; 110138414Smckusick return (error); 110238414Smckusick } 110338414Smckusick 110438414Smckusick /* 110538414Smckusick * nfs make dir call 110638414Smckusick */ 110752234Sheideman int 110853554Sheideman nfs_mkdir (ap) 110953554Sheideman struct vop_mkdir_args *ap; 111038414Smckusick { 111138884Smacklem register struct nfsv2_sattr *sp; 111248054Smckusick register u_long *tl; 111339488Smckusick register caddr_t cp; 111439488Smckusick register long t1, t2; 111541905Smckusick register int len; 111639488Smckusick caddr_t bpos, dpos, cp2; 111741905Smckusick int error = 0, firsttry = 1; 111839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 111938414Smckusick 112053600Sheideman len = ap->a_cnp->cn_namelen; 112138414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 112253600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_MKDIR, 112341905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR); 112453600Sheideman nfsm_fhtom(ap->a_dvp); 112553600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, len, NFS_MAXNAMLEN); 112638884Smacklem nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR); 112753600Sheideman sp->sa_mode = vtonfs_mode(VDIR, ap->a_vap->va_mode); 112853600Sheideman sp->sa_uid = txdr_unsigned(ap->a_cnp->cn_cred->cr_uid); 112953600Sheideman sp->sa_gid = txdr_unsigned(ap->a_cnp->cn_cred->cr_gid); 113038884Smacklem sp->sa_size = txdr_unsigned(VNOVAL); 113153600Sheideman txdr_time(&ap->a_vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */ 113253600Sheideman txdr_time(&ap->a_vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */ 113353600Sheideman nfsm_request(ap->a_dvp, NFSPROC_MKDIR, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 113453600Sheideman nfsm_mtofh(ap->a_dvp, *ap->a_vpp); 113538414Smckusick nfsm_reqdone; 113653600Sheideman VTONFS(ap->a_dvp)->n_flag |= NMODIFIED; 113740112Smckusick /* 113841905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 113941905Smckusick * if we can succeed in looking up the directory. 114041905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 114141905Smckusick * is above the if on errors. (Ugh) 114240112Smckusick */ 114341905Smckusick if (error == EEXIST && firsttry) { 114441905Smckusick firsttry = 0; 114540112Smckusick error = 0; 114641905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 114753600Sheideman *ap->a_vpp = NULL; 114853600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_LOOKUP, 114941905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 115053600Sheideman nfsm_fhtom(ap->a_dvp); 115153600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, len, NFS_MAXNAMLEN); 115253600Sheideman nfsm_request(ap->a_dvp, NFSPROC_LOOKUP, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 115353600Sheideman nfsm_mtofh(ap->a_dvp, *ap->a_vpp); 115453600Sheideman if ((*ap->a_vpp)->v_type != VDIR) { 115553600Sheideman vput(*ap->a_vpp); 115641905Smckusick error = EEXIST; 115741905Smckusick } 115841905Smckusick m_freem(mrep); 115941905Smckusick } 116053600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 116153600Sheideman vrele(ap->a_dvp); 116238414Smckusick return (error); 116338414Smckusick } 116438414Smckusick 116538414Smckusick /* 116638414Smckusick * nfs remove directory call 116738414Smckusick */ 116852234Sheideman int 116953554Sheideman nfs_rmdir (ap) 117053554Sheideman struct vop_rmdir_args *ap; 117138414Smckusick { 117248054Smckusick register u_long *tl; 117339488Smckusick register caddr_t cp; 117452196Smckusick register long t2; 117539488Smckusick caddr_t bpos, dpos; 117639488Smckusick int error = 0; 117739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 117838414Smckusick 117953600Sheideman if (ap->a_dvp == ap->a_vp) { 118053600Sheideman vrele(ap->a_dvp); 118153600Sheideman vrele(ap->a_dvp); 118253600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 118338414Smckusick return (EINVAL); 118438414Smckusick } 118538414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 118653600Sheideman nfsm_reqhead(ap->a_dvp, NFSPROC_RMDIR, 118753600Sheideman NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ap->a_cnp->cn_namelen)); 118853600Sheideman nfsm_fhtom(ap->a_dvp); 118953600Sheideman nfsm_strtom(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, NFS_MAXNAMLEN); 119053600Sheideman nfsm_request(ap->a_dvp, NFSPROC_RMDIR, ap->a_cnp->cn_proc, ap->a_cnp->cn_cred); 119138414Smckusick nfsm_reqdone; 119253600Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 119353600Sheideman VTONFS(ap->a_dvp)->n_flag |= NMODIFIED; 119453600Sheideman cache_purge(ap->a_dvp); 119553600Sheideman cache_purge(ap->a_vp); 119653600Sheideman vrele(ap->a_vp); 119753600Sheideman vrele(ap->a_dvp); 119840112Smckusick /* 119940112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 120040112Smckusick */ 120140112Smckusick if (error == ENOENT) 120240112Smckusick error = 0; 120338414Smckusick return (error); 120438414Smckusick } 120538414Smckusick 120638414Smckusick /* 120738414Smckusick * nfs readdir call 120838414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 120938414Smckusick * order so that it looks more sensible. This appears consistent with the 121038414Smckusick * Ultrix implementation of NFS. 121138414Smckusick */ 121252234Sheideman int 121353554Sheideman nfs_readdir (ap) 121453554Sheideman struct vop_readdir_args *ap; 121538414Smckusick { 121653554Sheideman USES_VOP_GETATTR; 121753600Sheideman register struct nfsnode *np = VTONFS(ap->a_vp); 121841905Smckusick int tresid, error; 121941905Smckusick struct vattr vattr; 122041905Smckusick 122153600Sheideman if (ap->a_vp->v_type != VDIR) 122241905Smckusick return (EPERM); 122341905Smckusick /* 122441905Smckusick * First, check for hit on the EOF offset cache 122541905Smckusick */ 122653600Sheideman if (ap->a_uio->uio_offset != 0 && ap->a_uio->uio_offset == np->n_direofoffset && 122752196Smckusick (np->n_flag & NMODIFIED) == 0) { 122853600Sheideman if (VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 122953600Sheideman if (NQNFS_CKCACHABLE(ap->a_vp, NQL_READ)) { 123053600Sheideman *ap->a_eofflagp = 1; 123152196Smckusick nfsstats.direofcache_hits++; 123252196Smckusick return (0); 123352196Smckusick } 123453600Sheideman } else if (VOP_GETATTR(ap->a_vp, &vattr, ap->a_cred, ap->a_uio->uio_procp) == 0 && 123552196Smckusick np->n_mtime == vattr.va_mtime.tv_sec) { 123653600Sheideman *ap->a_eofflagp = 1; 123752196Smckusick nfsstats.direofcache_hits++; 123852196Smckusick return (0); 123952196Smckusick } 124041905Smckusick } 124141905Smckusick 124241905Smckusick /* 124341905Smckusick * Call nfs_bioread() to do the real work. 124441905Smckusick */ 124553600Sheideman tresid = ap->a_uio->uio_resid; 124653600Sheideman error = nfs_bioread(ap->a_vp, ap->a_uio, 0, ap->a_cred); 124741905Smckusick 124853600Sheideman if (!error && ap->a_uio->uio_resid == tresid) { 124953600Sheideman *ap->a_eofflagp = 1; 125041905Smckusick nfsstats.direofcache_misses++; 125141905Smckusick } else 125253600Sheideman *ap->a_eofflagp = 0; 125341905Smckusick return (error); 125441905Smckusick } 125541905Smckusick 125641905Smckusick /* 125741905Smckusick * Readdir rpc call. 125841905Smckusick * Called from below the buffer cache by nfs_doio(). 125941905Smckusick */ 126052234Sheideman int 126148054Smckusick nfs_readdirrpc(vp, uiop, cred) 126241905Smckusick register struct vnode *vp; 126341905Smckusick struct uio *uiop; 126441905Smckusick struct ucred *cred; 126541905Smckusick { 126638414Smckusick register long len; 126752436Smckusick register struct readdir *dp; 126848054Smckusick register u_long *tl; 126939488Smckusick register caddr_t cp; 127039488Smckusick register long t1; 127141905Smckusick long tlen, lastlen; 127239488Smckusick caddr_t bpos, dpos, cp2; 127339488Smckusick int error = 0; 127439488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 127538414Smckusick struct mbuf *md2; 127638414Smckusick caddr_t dpos2; 127738414Smckusick int siz; 127840296Smckusick int more_dirs = 1; 127938414Smckusick off_t off, savoff; 128052436Smckusick struct readdir *savdp; 128140296Smckusick struct nfsmount *nmp; 128240296Smckusick struct nfsnode *np = VTONFS(vp); 128340296Smckusick long tresid; 128438414Smckusick 128541398Smckusick nmp = VFSTONFS(vp->v_mount); 128640296Smckusick tresid = uiop->uio_resid; 128740296Smckusick /* 128840296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 128948054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 129041905Smckusick * The stopping criteria is EOF or buffer full. 129140296Smckusick */ 129248054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 129340296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 129452196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 129552196Smckusick NFSX_FH+2*NFSX_UNSIGNED); 129640296Smckusick nfsm_fhtom(vp); 129748054Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 129848054Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 129948054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 130048054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 130152196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 130240296Smckusick siz = 0; 130352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 130448054Smckusick more_dirs = fxdr_unsigned(int, *tl); 130540296Smckusick 130640296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 130740296Smckusick dpos2 = dpos; 130840296Smckusick md2 = md; 130940296Smckusick 131040296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 131141905Smckusick off = uiop->uio_offset; 131242246Smckusick #ifdef lint 131352436Smckusick dp = (struct readdir *)0; 131442246Smckusick #endif /* lint */ 131540296Smckusick while (more_dirs && siz < uiop->uio_resid) { 131640296Smckusick savoff = off; /* Hold onto offset and dp */ 131740296Smckusick savdp = dp; 131852196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 131952436Smckusick dp = (struct readdir *)tl; 132048054Smckusick dp->d_ino = fxdr_unsigned(u_long, *tl++); 132148054Smckusick len = fxdr_unsigned(int, *tl); 132240296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 132340296Smckusick error = EBADRPC; 132440296Smckusick m_freem(mrep); 132540296Smckusick goto nfsmout; 132640296Smckusick } 132740296Smckusick dp->d_namlen = (u_short)len; 132840296Smckusick nfsm_adv(len); /* Point past name */ 132940296Smckusick tlen = nfsm_rndup(len); 133040296Smckusick /* 133140296Smckusick * This should not be necessary, but some servers have 133240296Smckusick * broken XDR such that these bytes are not null filled. 133340296Smckusick */ 133440296Smckusick if (tlen != len) { 133540296Smckusick *dpos = '\0'; /* Null-terminate */ 133640296Smckusick nfsm_adv(tlen - len); 133740296Smckusick len = tlen; 133840296Smckusick } 133952196Smckusick nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED); 134048054Smckusick off = fxdr_unsigned(off_t, *tl); 134148054Smckusick *tl++ = 0; /* Ensures null termination of name */ 134248054Smckusick more_dirs = fxdr_unsigned(int, *tl); 134340296Smckusick dp->d_reclen = len+4*NFSX_UNSIGNED; 134440296Smckusick siz += dp->d_reclen; 134540296Smckusick } 134640296Smckusick /* 134740296Smckusick * If at end of rpc data, get the eof boolean 134840296Smckusick */ 134940296Smckusick if (!more_dirs) { 135052196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 135148054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 135238414Smckusick 135340296Smckusick /* 135440296Smckusick * If at EOF, cache directory offset 135540296Smckusick */ 135641905Smckusick if (!more_dirs) 135740296Smckusick np->n_direofoffset = off; 135838414Smckusick } 135940296Smckusick /* 136040296Smckusick * If there is too much to fit in the data buffer, use savoff and 136140296Smckusick * savdp to trim off the last record. 136240296Smckusick * --> we are not at eof 136340296Smckusick */ 136440296Smckusick if (siz > uiop->uio_resid) { 136540296Smckusick off = savoff; 136640296Smckusick siz -= dp->d_reclen; 136740296Smckusick dp = savdp; 136840296Smckusick more_dirs = 0; /* Paranoia */ 136940113Smckusick } 137040296Smckusick if (siz > 0) { 137141905Smckusick lastlen = dp->d_reclen; 137240296Smckusick md = md2; 137340296Smckusick dpos = dpos2; 137440296Smckusick nfsm_mtouio(uiop, siz); 137540296Smckusick uiop->uio_offset = off; 137640296Smckusick } else 137740296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 137840296Smckusick m_freem(mrep); 137938414Smckusick } 138041905Smckusick /* 138148054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 138241905Smckusick * by increasing d_reclen for the last record. 138341905Smckusick */ 138441905Smckusick if (uiop->uio_resid < tresid) { 138548054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 138641905Smckusick if (len > 0) { 138752436Smckusick dp = (struct readdir *) 138841905Smckusick (uiop->uio_iov->iov_base - lastlen); 138941905Smckusick dp->d_reclen += len; 139041905Smckusick uiop->uio_iov->iov_base += len; 139141905Smckusick uiop->uio_iov->iov_len -= len; 139241905Smckusick uiop->uio_resid -= len; 139341905Smckusick } 139441905Smckusick } 139540296Smckusick nfsmout: 139638414Smckusick return (error); 139738414Smckusick } 139838414Smckusick 139952196Smckusick /* 140052196Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when 140152196Smckusick * the "rdirlook" mount option is specified. 140252196Smckusick */ 140352234Sheideman int 140452196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 140552196Smckusick struct vnode *vp; 140652196Smckusick register struct uio *uiop; 140752196Smckusick struct ucred *cred; 140852196Smckusick { 140952196Smckusick register int len; 141052436Smckusick register struct readdir *dp; 141152196Smckusick register u_long *tl; 141252196Smckusick register caddr_t cp; 141352196Smckusick register long t1; 141452196Smckusick caddr_t bpos, dpos, cp2; 141552196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 141652196Smckusick struct nameidata nami, *ndp = &nami; 141752317Sheideman struct componentname *cnp = &ndp->ni_cnd; 141852196Smckusick off_t off, endoff; 141952196Smckusick time_t reqtime, ltime; 142052196Smckusick struct nfsmount *nmp; 142152196Smckusick struct nfsnode *np, *tp; 142252196Smckusick struct vnode *newvp; 142352196Smckusick nfsv2fh_t *fhp; 142452196Smckusick u_long fileno; 142552196Smckusick u_quad_t frev; 142652196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 142752196Smckusick int cachable; 142852196Smckusick 142952196Smckusick if (uiop->uio_iovcnt != 1) 143052196Smckusick panic("nfs rdirlook"); 143152196Smckusick nmp = VFSTONFS(vp->v_mount); 143252196Smckusick tresid = uiop->uio_resid; 143352196Smckusick ndp->ni_dvp = vp; 143452196Smckusick newvp = NULLVP; 143552196Smckusick /* 143652196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 143752196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 143852196Smckusick * The stopping criteria is EOF or buffer full. 143952196Smckusick */ 144052196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 144152196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 144252196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 144352196Smckusick NFSX_FH+3*NFSX_UNSIGNED); 144452196Smckusick nfsm_fhtom(vp); 144552196Smckusick nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED); 144652196Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 144752196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 144852196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 144952196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 145052196Smckusick reqtime = time.tv_sec; 145152196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 145252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 145352196Smckusick more_dirs = fxdr_unsigned(int, *tl); 145452196Smckusick 145552196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 145652196Smckusick off = uiop->uio_offset; 145752196Smckusick bigenough = 1; 145852196Smckusick while (more_dirs && bigenough) { 145952196Smckusick doit = 1; 146052196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 146152196Smckusick cachable = fxdr_unsigned(int, *tl++); 146252196Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 146352196Smckusick fxdr_hyper(tl, &frev); 146452196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 146552196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 146652196Smckusick VREF(vp); 146752196Smckusick newvp = vp; 146852196Smckusick np = VTONFS(vp); 146952196Smckusick } else { 147052196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 147152196Smckusick doit = 0; 147252196Smckusick newvp = NFSTOV(np); 147352196Smckusick } 147452196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 147552196Smckusick (struct vattr *)0)) 147652196Smckusick doit = 0; 147752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 147852196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 147952196Smckusick len = fxdr_unsigned(int, *tl); 148052196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 148152196Smckusick error = EBADRPC; 148252196Smckusick m_freem(mrep); 148352196Smckusick goto nfsmout; 148452196Smckusick } 148552196Smckusick tlen = (len + 4) & ~0x3; 148652196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 148752196Smckusick bigenough = 0; 148852196Smckusick if (bigenough && doit) { 148952436Smckusick dp = (struct readdir *)uiop->uio_iov->iov_base; 149052196Smckusick dp->d_ino = fileno; 149152196Smckusick dp->d_namlen = len; 149252196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 149352196Smckusick uiop->uio_resid -= DIRHDSIZ; 149452196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 149552196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 149652317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 149752317Sheideman cnp->cn_namelen = len; 149852196Smckusick ndp->ni_vp = newvp; 149952196Smckusick nfsm_mtouio(uiop, len); 150052196Smckusick cp = uiop->uio_iov->iov_base; 150152196Smckusick tlen -= len; 150252196Smckusick for (i = 0; i < tlen; i++) 150352196Smckusick *cp++ = '\0'; 150452196Smckusick uiop->uio_iov->iov_base += tlen; 150552196Smckusick uiop->uio_iov->iov_len -= tlen; 150652196Smckusick uiop->uio_resid -= tlen; 150752317Sheideman cnp->cn_hash = 0; 150852317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 150952317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 151052196Smckusick if (ltime > time.tv_sec) { 151152196Smckusick if (np->n_tnext) { 151252196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 151352196Smckusick nmp->nm_tprev = np->n_tprev; 151452196Smckusick else 151552196Smckusick np->n_tnext->n_tprev = np->n_tprev; 151652196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 151752196Smckusick nmp->nm_tnext = np->n_tnext; 151852196Smckusick else 151952196Smckusick np->n_tprev->n_tnext = np->n_tnext; 152052196Smckusick } else 152152196Smckusick np->n_flag &= ~NQNFSWRITE; 152252196Smckusick if (cachable) 152352196Smckusick np->n_flag &= ~NQNFSNONCACHE; 152452196Smckusick else 152552196Smckusick np->n_flag |= NQNFSNONCACHE; 152652196Smckusick np->n_expiry = ltime; 152752196Smckusick np->n_lrev = frev; 152852196Smckusick tp = nmp->nm_tprev; 152952196Smckusick while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 153052196Smckusick tp = tp->n_tprev; 153152196Smckusick if (tp == (struct nfsnode *)nmp) { 153252196Smckusick np->n_tnext = nmp->nm_tnext; 153352196Smckusick nmp->nm_tnext = np; 153452196Smckusick } else { 153552196Smckusick np->n_tnext = tp->n_tnext; 153652196Smckusick tp->n_tnext = np; 153752196Smckusick } 153852196Smckusick np->n_tprev = tp; 153952196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 154052196Smckusick nmp->nm_tprev = np; 154152196Smckusick else 154252196Smckusick np->n_tnext->n_tprev = np; 154352317Sheideman cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 154452196Smckusick } 154552196Smckusick } else { 154652196Smckusick nfsm_adv(nfsm_rndup(len)); 154752196Smckusick } 154852196Smckusick if (newvp != NULLVP) { 154952196Smckusick vrele(newvp); 155052196Smckusick newvp = NULLVP; 155152196Smckusick } 155252196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 155352196Smckusick if (bigenough) 155452196Smckusick endoff = off = fxdr_unsigned(off_t, *tl++); 155552196Smckusick else 155652196Smckusick endoff = fxdr_unsigned(off_t, *tl++); 155752196Smckusick more_dirs = fxdr_unsigned(int, *tl); 155852196Smckusick } 155952196Smckusick /* 156052196Smckusick * If at end of rpc data, get the eof boolean 156152196Smckusick */ 156252196Smckusick if (!more_dirs) { 156352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 156452196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 156552196Smckusick 156652196Smckusick /* 156752196Smckusick * If at EOF, cache directory offset 156852196Smckusick */ 156952196Smckusick if (!more_dirs) 157052196Smckusick VTONFS(vp)->n_direofoffset = endoff; 157152196Smckusick } 157252196Smckusick if (uiop->uio_resid < tresid) 157352196Smckusick uiop->uio_offset = off; 157452196Smckusick else 157552196Smckusick more_dirs = 0; 157652196Smckusick m_freem(mrep); 157752196Smckusick } 157852196Smckusick /* 157952196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 158052196Smckusick * by increasing d_reclen for the last record. 158152196Smckusick */ 158252196Smckusick if (uiop->uio_resid < tresid) { 158352196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 158452196Smckusick if (len > 0) { 158552196Smckusick dp->d_reclen += len; 158652196Smckusick uiop->uio_iov->iov_base += len; 158752196Smckusick uiop->uio_iov->iov_len -= len; 158852196Smckusick uiop->uio_resid -= len; 158952196Smckusick } 159052196Smckusick } 159152196Smckusick nfsmout: 159252196Smckusick if (newvp != NULLVP) 159352196Smckusick vrele(newvp); 159452196Smckusick return (error); 159552196Smckusick } 159639488Smckusick static char hextoasc[] = "0123456789abcdef"; 159738414Smckusick 159838414Smckusick /* 159938414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 160038414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 160138414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 160238414Smckusick * nfsnode. There is the potential for another process on a different client 160338414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 160438414Smckusick * nfs_rename() completes, but... 160538414Smckusick */ 160652234Sheideman int 160752317Sheideman nfs_sillyrename(dvp, vp, cnp) 160852234Sheideman struct vnode *dvp, *vp; 160952234Sheideman struct componentname *cnp; 161038414Smckusick { 161138414Smckusick register struct nfsnode *np; 161238414Smckusick register struct sillyrename *sp; 161338414Smckusick int error; 161438414Smckusick short pid; 161538414Smckusick 161652234Sheideman cache_purge(dvp); 161752234Sheideman np = VTONFS(vp); 161851986Smckusick #ifdef SILLYSEPARATE 161938414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 162048364Smckusick M_NFSREQ, M_WAITOK); 162151986Smckusick #else 162251986Smckusick sp = &np->n_silly; 162351986Smckusick #endif 162452234Sheideman sp->s_cred = crdup(cnp->cn_cred); 162552234Sheideman sp->s_dvp = dvp; 162652234Sheideman VREF(dvp); 162738414Smckusick 162838414Smckusick /* Fudge together a funny name */ 162952234Sheideman pid = cnp->cn_proc->p_pid; 163048364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 163148364Smckusick sp->s_namlen = 12; 163248364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 163348364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 163448364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 163548364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 163638414Smckusick 163738414Smckusick /* Try lookitups until we get one that isn't there */ 163852234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 163948364Smckusick sp->s_name[4]++; 164048364Smckusick if (sp->s_name[4] > 'z') { 164138414Smckusick error = EINVAL; 164238414Smckusick goto bad; 164338414Smckusick } 164438414Smckusick } 164552234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 164638414Smckusick goto bad; 164752234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 164838414Smckusick np->n_sillyrename = sp; 164938414Smckusick return (0); 165038414Smckusick bad: 165148364Smckusick vrele(sp->s_dvp); 165248364Smckusick crfree(sp->s_cred); 165351986Smckusick #ifdef SILLYSEPARATE 165448364Smckusick free((caddr_t)sp, M_NFSREQ); 165551986Smckusick #endif 165638414Smckusick return (error); 165738414Smckusick } 165838414Smckusick 165938414Smckusick /* 166038414Smckusick * Look up a file name for silly rename stuff. 166138414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 166238414Smckusick * into the nfsnode table. 166338414Smckusick * If fhp != NULL it copies the returned file handle out 166438414Smckusick */ 166552234Sheideman int 166652196Smckusick nfs_lookitup(sp, fhp, procp) 166748364Smckusick register struct sillyrename *sp; 166838414Smckusick nfsv2fh_t *fhp; 166952196Smckusick struct proc *procp; 167038414Smckusick { 167148364Smckusick register struct vnode *vp = sp->s_dvp; 167248054Smckusick register u_long *tl; 167339488Smckusick register caddr_t cp; 167439488Smckusick register long t1, t2; 167539488Smckusick caddr_t bpos, dpos, cp2; 167639488Smckusick u_long xid; 167739488Smckusick int error = 0; 167839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 167938414Smckusick long len; 168038414Smckusick 168138414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 168248364Smckusick len = sp->s_namlen; 168352196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 168438414Smckusick nfsm_fhtom(vp); 168548364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 168652196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 168738414Smckusick if (fhp != NULL) { 168852196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 168938414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 169038414Smckusick } 169138414Smckusick nfsm_reqdone; 169238414Smckusick return (error); 169338414Smckusick } 169438414Smckusick 169538414Smckusick /* 169638414Smckusick * Kludge City.. 169738414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 169841905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 169938414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 170038414Smckusick * nfsiobuf area. 170138414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 170238414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 170338414Smckusick * a lot more work than bcopy() and also it currently happens in the 170438414Smckusick * context of the swapper process (2). 170538414Smckusick */ 170652234Sheideman int 170753554Sheideman nfs_bmap (ap) 170853554Sheideman struct vop_bmap_args *ap; 170938414Smckusick { 171053600Sheideman if (ap->a_vpp != NULL) 171153600Sheideman *ap->a_vpp = ap->a_vp; 171253600Sheideman if (ap->a_bnp != NULL) 171353600Sheideman *ap->a_bnp = ap->a_bn * btodb(ap->a_vp->v_mount->mnt_stat.f_iosize); 171438414Smckusick return (0); 171538414Smckusick } 171638414Smckusick 171738414Smckusick /* 171838884Smacklem * Strategy routine for phys. i/o 171938884Smacklem * If the biod's are running, queue a request 172038884Smacklem * otherwise just call nfs_doio() to get it done 172138414Smckusick */ 172252234Sheideman int 172353554Sheideman nfs_strategy (ap) 172453554Sheideman struct vop_strategy_args *ap; 172538414Smckusick { 172638884Smacklem register struct buf *dp; 172739341Smckusick register int i; 172838884Smacklem int error = 0; 172939341Smckusick int fnd = 0; 173038884Smacklem 173138884Smacklem /* 173241905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 173341905Smckusick * doesn't set it, I will. 173446450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 173541905Smckusick * be hanging about after the process terminates. 173641905Smckusick */ 173753600Sheideman if ((ap->a_bp->b_flags & B_PHYS) == 0) { 173853600Sheideman if (ap->a_bp->b_flags & B_ASYNC) 173953600Sheideman ap->a_bp->b_proc = (struct proc *)0; 174046988Smckusick else 174153600Sheideman ap->a_bp->b_proc = curproc; 174246988Smckusick } 174341905Smckusick /* 174446450Skarels * If the op is asynchronous and an i/o daemon is waiting 174538884Smacklem * queue the request, wake it up and wait for completion 174646450Skarels * otherwise just do it ourselves. 174738884Smacklem */ 174853600Sheideman if ((ap->a_bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 174953600Sheideman return (nfs_doio(ap->a_bp)); 175046988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 175146988Smckusick if (nfs_iodwant[i]) { 175239341Smckusick dp = &nfs_bqueue; 175339341Smckusick if (dp->b_actf == NULL) { 175453600Sheideman dp->b_actl = ap->a_bp; 175553600Sheideman ap->a_bp->b_actf = dp; 175639341Smckusick } else { 175753600Sheideman dp->b_actf->b_actl = ap->a_bp; 175853600Sheideman ap->a_bp->b_actf = dp->b_actf; 175939341Smckusick } 176053600Sheideman dp->b_actf = ap->a_bp; 176153600Sheideman ap->a_bp->b_actl = dp; 176239341Smckusick fnd++; 176339341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 176439341Smckusick break; 176538884Smacklem } 176639341Smckusick } 176739341Smckusick if (!fnd) 176853600Sheideman error = nfs_doio(ap->a_bp); 176938884Smacklem return (error); 177038884Smacklem } 177138884Smacklem 177238884Smacklem /* 177338884Smacklem * Fun and games with i/o 177438884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 177538884Smacklem * mapping the data buffer into kernel virtual space and doing the 177638884Smacklem * nfs read or write rpc's from it. 177741905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 177841905Smckusick * otherwise it is called by the nfsiods to do what would normally be 177938884Smacklem * partially disk interrupt driven. 178038884Smacklem */ 178152234Sheideman int 178238884Smacklem nfs_doio(bp) 178338884Smacklem register struct buf *bp; 178438884Smacklem { 178538414Smckusick register struct uio *uiop; 178638414Smckusick register struct vnode *vp; 178739341Smckusick struct nfsnode *np; 178838884Smacklem struct ucred *cr; 178941539Smckusick int error; 179041539Smckusick struct uio uio; 179141539Smckusick struct iovec io; 179238414Smckusick 179338414Smckusick vp = bp->b_vp; 179440251Smckusick np = VTONFS(vp); 179538414Smckusick uiop = &uio; 179638414Smckusick uiop->uio_iov = &io; 179738414Smckusick uiop->uio_iovcnt = 1; 179838414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 179952196Smckusick uiop->uio_procp = bp->b_proc; 180039751Smckusick 180138414Smckusick /* 180238884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 180338884Smacklem * the Nfsiomap pte's 180438884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 180538884Smacklem * and a guess at a group 180638414Smckusick */ 180738884Smacklem if (bp->b_flags & B_PHYS) { 180848054Smckusick if (bp->b_flags & B_DIRTY) 180948054Smckusick uiop->uio_procp = pageproc; 181048054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 181141539Smckusick /* mapping was already done by vmapbuf */ 181241539Smckusick io.iov_base = bp->b_un.b_addr; 181339751Smckusick 181438884Smacklem /* 181539751Smckusick * And do the i/o rpc 181639751Smckusick */ 181739751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 181839823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 181939751Smckusick if (bp->b_flags & B_READ) { 182039751Smckusick uiop->uio_rw = UIO_READ; 182139751Smckusick nfsstats.read_physios++; 182248054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 182345717Smckusick (void) vnode_pager_uncache(vp); 182439751Smckusick } else { 182539751Smckusick uiop->uio_rw = UIO_WRITE; 182639751Smckusick nfsstats.write_physios++; 182748054Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr); 182839341Smckusick } 182939751Smckusick 183039751Smckusick /* 183139751Smckusick * Finally, release pte's used by physical i/o 183239751Smckusick */ 183338884Smacklem crfree(cr); 183439751Smckusick } else { 183539751Smckusick if (bp->b_flags & B_READ) { 183639751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 183739751Smckusick io.iov_base = bp->b_un.b_addr; 183839751Smckusick uiop->uio_rw = UIO_READ; 183941905Smckusick switch (vp->v_type) { 184041905Smckusick case VREG: 184141905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 184241905Smckusick nfsstats.read_bios++; 184348054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 184441905Smckusick break; 184541905Smckusick case VLNK: 184641905Smckusick uiop->uio_offset = 0; 184741905Smckusick nfsstats.readlink_bios++; 184848054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 184941905Smckusick break; 185041905Smckusick case VDIR: 185141905Smckusick uiop->uio_offset = bp->b_lblkno; 185241905Smckusick nfsstats.readdir_bios++; 185352196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK) 185452196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 185552196Smckusick else 185652196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 185741905Smckusick /* 185841905Smckusick * Save offset cookie in b_blkno. 185941905Smckusick */ 186041905Smckusick bp->b_blkno = uiop->uio_offset; 186141905Smckusick break; 186241905Smckusick }; 186341905Smckusick bp->b_error = error; 186439751Smckusick } else { 186539751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 186639751Smckusick - bp->b_dirtyoff; 186739823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 186839751Smckusick + bp->b_dirtyoff; 186939751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 187039751Smckusick uiop->uio_rw = UIO_WRITE; 187139751Smckusick nfsstats.write_bios++; 187241905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 187348054Smckusick bp->b_wcred); 187439751Smckusick if (error) { 187539751Smckusick np->n_error = error; 187639751Smckusick np->n_flag |= NWRITEERR; 187739751Smckusick } 187839751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 187939751Smckusick } 188038884Smacklem } 188139751Smckusick if (error) 188239751Smckusick bp->b_flags |= B_ERROR; 188339751Smckusick bp->b_resid = uiop->uio_resid; 188438414Smckusick biodone(bp); 188538414Smckusick return (error); 188638414Smckusick } 188738884Smacklem 188838884Smacklem /* 188948054Smckusick * Mmap a file 189048054Smckusick * 189148054Smckusick * NB Currently unsupported. 189248054Smckusick */ 189348054Smckusick /* ARGSUSED */ 189452234Sheideman int 189553554Sheideman nfs_mmap (ap) 189653554Sheideman struct vop_mmap_args *ap; 189748054Smckusick { 189848054Smckusick 189948054Smckusick return (EINVAL); 190048054Smckusick } 190148054Smckusick 190248054Smckusick /* 190338884Smacklem * Flush all the blocks associated with a vnode. 190438884Smacklem * Walk through the buffer pool and push any dirty pages 190538884Smacklem * associated with the vnode. 190638884Smacklem */ 190739488Smckusick /* ARGSUSED */ 190852234Sheideman int 190953554Sheideman nfs_fsync (ap) 191053554Sheideman struct vop_fsync_args *ap; 191138884Smacklem { 191253600Sheideman register struct nfsnode *np = VTONFS(ap->a_vp); 191339751Smckusick int error = 0; 191438884Smacklem 191538884Smacklem if (np->n_flag & NMODIFIED) { 191638884Smacklem np->n_flag &= ~NMODIFIED; 191753600Sheideman vflushbuf(ap->a_vp, ap->a_waitfor == MNT_WAIT ? B_SYNC : 0); 191838884Smacklem } 1919*53629Smckusick if (np->n_flag & NWRITEERR) { 192039751Smckusick error = np->n_error; 1921*53629Smckusick np->n_flag &= ~NWRITEERR; 1922*53629Smckusick } 192338884Smacklem return (error); 192438884Smacklem } 192539672Smckusick 192639672Smckusick /* 192746201Smckusick * NFS advisory byte-level locks. 192846201Smckusick * Currently unsupported. 192946201Smckusick */ 193052234Sheideman int 193153554Sheideman nfs_advlock (ap) 193253554Sheideman struct vop_advlock_args *ap; 193346201Smckusick { 193446201Smckusick 193546201Smckusick return (EOPNOTSUPP); 193646201Smckusick } 193746201Smckusick 193846201Smckusick /* 193939672Smckusick * Print out the contents of an nfsnode. 194039672Smckusick */ 194152234Sheideman int 194253554Sheideman nfs_print (ap) 194353554Sheideman struct vop_print_args *ap; 194439672Smckusick { 194553600Sheideman register struct nfsnode *np = VTONFS(ap->a_vp); 194639672Smckusick 194740294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 194840294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 194940294Smckusick #ifdef FIFO 195053600Sheideman if (ap->a_vp->v_type == VFIFO) 195153600Sheideman fifo_printinfo(ap->a_vp); 195240294Smckusick #endif /* FIFO */ 195339914Smckusick printf("\n"); 195439672Smckusick } 195551573Smckusick 195651573Smckusick /* 195751573Smckusick * NFS directory offset lookup. 195851573Smckusick * Currently unsupported. 195951573Smckusick */ 196052234Sheideman int 196153554Sheideman nfs_blkatoff (ap) 196253554Sheideman struct vop_blkatoff_args *ap; 196351573Smckusick { 196451573Smckusick 196551573Smckusick return (EOPNOTSUPP); 196651573Smckusick } 196751573Smckusick 196851573Smckusick /* 196951573Smckusick * NFS flat namespace lookup. 197051573Smckusick * Currently unsupported. 197151573Smckusick */ 197252234Sheideman int 197353554Sheideman nfs_vget (ap) 197453554Sheideman struct vop_vget_args *ap; 197551573Smckusick { 197651573Smckusick 197751573Smckusick return (EOPNOTSUPP); 197851573Smckusick } 197951573Smckusick 198051573Smckusick /* 198151573Smckusick * NFS flat namespace allocation. 198251573Smckusick * Currently unsupported. 198351573Smckusick */ 198452234Sheideman int 198553554Sheideman nfs_valloc (ap) 198653554Sheideman struct vop_valloc_args *ap; 198751573Smckusick { 198851573Smckusick 198951573Smckusick return (EOPNOTSUPP); 199051573Smckusick } 199151573Smckusick 199251573Smckusick /* 199351573Smckusick * NFS flat namespace free. 199451573Smckusick * Currently unsupported. 199551573Smckusick */ 199653582Sheideman int 199753554Sheideman nfs_vfree (ap) 199853554Sheideman struct vop_vfree_args *ap; 199951573Smckusick { 200051573Smckusick 200153582Sheideman return (EOPNOTSUPP); 200251573Smckusick } 200351573Smckusick 200451573Smckusick /* 200551573Smckusick * NFS file truncation. 200651573Smckusick */ 200752234Sheideman int 200853554Sheideman nfs_truncate (ap) 200953554Sheideman struct vop_truncate_args *ap; 201051573Smckusick { 201151573Smckusick 201251573Smckusick /* Use nfs_setattr */ 201351573Smckusick printf("nfs_truncate: need to implement!!"); 201451573Smckusick return (EOPNOTSUPP); 201551573Smckusick } 201651573Smckusick 201751573Smckusick /* 201851573Smckusick * NFS update. 201951573Smckusick */ 202052234Sheideman int 202153554Sheideman nfs_update (ap) 202253554Sheideman struct vop_update_args *ap; 202351573Smckusick { 202451573Smckusick 202551573Smckusick /* Use nfs_setattr */ 202651573Smckusick printf("nfs_update: need to implement!!"); 202751573Smckusick return (EOPNOTSUPP); 202851573Smckusick } 2029*53629Smckusick 2030*53629Smckusick /* 2031*53629Smckusick * Read wrapper for special devices. 2032*53629Smckusick */ 2033*53629Smckusick int 2034*53629Smckusick nfsspec_read(ap) 2035*53629Smckusick struct vop_read_args *ap; 2036*53629Smckusick { 2037*53629Smckusick extern int (**spec_vnodeop_p)(); 2038*53629Smckusick 2039*53629Smckusick /* 2040*53629Smckusick * Set access flag. 2041*53629Smckusick */ 2042*53629Smckusick VTONFS(ap->a_vp)->n_flag |= NACC; 2043*53629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 2044*53629Smckusick } 2045*53629Smckusick 2046*53629Smckusick /* 2047*53629Smckusick * Write wrapper for special devices. 2048*53629Smckusick */ 2049*53629Smckusick int 2050*53629Smckusick nfsspec_write(ap) 2051*53629Smckusick struct vop_write_args *ap; 2052*53629Smckusick { 2053*53629Smckusick extern int (**spec_vnodeop_p)(); 2054*53629Smckusick 2055*53629Smckusick /* 2056*53629Smckusick * Set update flags. 2057*53629Smckusick */ 2058*53629Smckusick VTONFS(ap->a_vp)->n_flag |= NUPD; 2059*53629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 2060*53629Smckusick } 2061*53629Smckusick 2062*53629Smckusick /* 2063*53629Smckusick * Close wrapper for special devices. 2064*53629Smckusick * 2065*53629Smckusick * Update the times on the nfsnode then do device close. 2066*53629Smckusick */ 2067*53629Smckusick int 2068*53629Smckusick nfsspec_close(ap) 2069*53629Smckusick struct vop_close_args *ap; 2070*53629Smckusick { 2071*53629Smckusick USES_VOP_SETATTR; 2072*53629Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 2073*53629Smckusick struct vattr vattr; 2074*53629Smckusick extern int (**spec_vnodeop_p)(); 2075*53629Smckusick 2076*53629Smckusick if (np->n_flag & (NACC | NUPD)) { 2077*53629Smckusick if (np->n_flag & NACC) 2078*53629Smckusick np->n_atim = time; 2079*53629Smckusick if (np->n_flag & NUPD) 2080*53629Smckusick np->n_mtim = time; 2081*53629Smckusick np->n_flag |= NCHG; 2082*53629Smckusick if (ap->a_vp->v_usecount == 1 && 2083*53629Smckusick (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 2084*53629Smckusick VATTR_NULL(&vattr); 2085*53629Smckusick if (np->n_flag & NACC) 2086*53629Smckusick vattr.va_atime = np->n_atim; 2087*53629Smckusick if (np->n_flag & NUPD) 2088*53629Smckusick vattr.va_mtime = np->n_mtim; 2089*53629Smckusick (void)VOP_SETATTR(ap->a_vp, &vattr, ap->a_cred, 2090*53629Smckusick ap->a_p); 2091*53629Smckusick } 2092*53629Smckusick } 2093*53629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 2094*53629Smckusick } 2095*53629Smckusick 2096*53629Smckusick #ifdef FIFO 2097*53629Smckusick /* 2098*53629Smckusick * Read wrapper for fifos. 2099*53629Smckusick */ 2100*53629Smckusick int 2101*53629Smckusick nfsfifo_read(ap) 2102*53629Smckusick struct vop_read_args *ap; 2103*53629Smckusick { 2104*53629Smckusick extern int (**fifo_vnodeop_p)(); 2105*53629Smckusick 2106*53629Smckusick /* 2107*53629Smckusick * Set access flag. 2108*53629Smckusick */ 2109*53629Smckusick VTONFS(ap->a_vp)->n_flag |= NACC; 2110*53629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 2111*53629Smckusick } 2112*53629Smckusick 2113*53629Smckusick /* 2114*53629Smckusick * Write wrapper for fifos. 2115*53629Smckusick */ 2116*53629Smckusick int 2117*53629Smckusick nfsfifo_write(ap) 2118*53629Smckusick struct vop_write_args *ap; 2119*53629Smckusick { 2120*53629Smckusick extern int (**fifo_vnodeop_p)(); 2121*53629Smckusick 2122*53629Smckusick /* 2123*53629Smckusick * Set update flag. 2124*53629Smckusick */ 2125*53629Smckusick VTONFS(ap->a_vp)->n_flag |= NUPD; 2126*53629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 2127*53629Smckusick } 2128*53629Smckusick 2129*53629Smckusick /* 2130*53629Smckusick * Close wrapper for fifos. 2131*53629Smckusick * 2132*53629Smckusick * Update the times on the nfsnode then do fifo close. 2133*53629Smckusick */ 2134*53629Smckusick int 2135*53629Smckusick nfsfifo_close(ap) 2136*53629Smckusick struct vop_close_args *ap; 2137*53629Smckusick { 2138*53629Smckusick USES_VOP_SETATTR; 2139*53629Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 2140*53629Smckusick struct vattr vattr; 2141*53629Smckusick extern int (**fifo_vnodeop_p)(); 2142*53629Smckusick 2143*53629Smckusick if (np->n_flag & (NACC | NUPD)) { 2144*53629Smckusick if (np->n_flag & NACC) 2145*53629Smckusick np->n_atim = time; 2146*53629Smckusick if (np->n_flag & NUPD) 2147*53629Smckusick np->n_mtim = time; 2148*53629Smckusick np->n_flag |= NCHG; 2149*53629Smckusick if (ap->a_vp->v_usecount == 1 && 2150*53629Smckusick (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 2151*53629Smckusick VATTR_NULL(&vattr); 2152*53629Smckusick if (np->n_flag & NACC) 2153*53629Smckusick vattr.va_atime = np->n_atim; 2154*53629Smckusick if (np->n_flag & NUPD) 2155*53629Smckusick vattr.va_mtime = np->n_mtim; 2156*53629Smckusick (void)VOP_SETATTR(ap->a_vp, &vattr, ap->a_cred, 2157*53629Smckusick ap->a_p); 2158*53629Smckusick } 2159*53629Smckusick } 2160*53629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 2161*53629Smckusick } 2162*53629Smckusick #endif /* FIFO */ 2163