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*57791Smckusick * @(#)nfs_vnops.c 7.102 (Berkeley) 02/02/93 1138414Smckusick */ 1238414Smckusick 1338414Smckusick /* 1438414Smckusick * vnode op calls for sun nfs version 2 1538414Smckusick */ 1638414Smckusick 1753322Smckusick #include <sys/param.h> 1853322Smckusick #include <sys/proc.h> 1953322Smckusick #include <sys/kernel.h> 2053322Smckusick #include <sys/systm.h> 2153322Smckusick #include <sys/mount.h> 2253322Smckusick #include <sys/buf.h> 2353322Smckusick #include <sys/malloc.h> 2453322Smckusick #include <sys/mbuf.h> 2553322Smckusick #include <sys/conf.h> 2653322Smckusick #include <sys/namei.h> 2753322Smckusick #include <sys/vnode.h> 2853322Smckusick #include <sys/map.h> 2954740Smckusick #include <sys/dirent.h> 3047573Skarels 3153322Smckusick #include <vm/vm.h> 3238414Smckusick 3355041Smckusick #include <miscfs/specfs/specdev.h> 3455041Smckusick #include <miscfs/fifofs/fifo.h> 3555041Smckusick 3653322Smckusick #include <nfs/rpcv2.h> 3753322Smckusick #include <nfs/nfsv2.h> 3853322Smckusick #include <nfs/nfs.h> 3953322Smckusick #include <nfs/nfsnode.h> 4053322Smckusick #include <nfs/nfsmount.h> 4153322Smckusick #include <nfs/xdr_subs.h> 4253322Smckusick #include <nfs/nfsm_subs.h> 4353322Smckusick #include <nfs/nqnfs.h> 4453322Smckusick 4538414Smckusick /* Defs */ 4638414Smckusick #define TRUE 1 4738414Smckusick #define FALSE 0 4838414Smckusick 4948054Smckusick /* 5048054Smckusick * Global vfs data structures for nfs 5148054Smckusick */ 5253554Sheideman int (**nfsv2_vnodeop_p)(); 5353554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 5453554Sheideman { &vop_default_desc, vn_default_error }, 5553806Smckusick { &vop_lookup_desc, nfs_lookup }, /* lookup */ 5653806Smckusick { &vop_create_desc, nfs_create }, /* create */ 5753554Sheideman { &vop_mknod_desc, nfs_mknod }, /* mknod */ 5853554Sheideman { &vop_open_desc, nfs_open }, /* open */ 5953554Sheideman { &vop_close_desc, nfs_close }, /* close */ 6053806Smckusick { &vop_access_desc, nfs_access }, /* access */ 6153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 6253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 6353554Sheideman { &vop_read_desc, nfs_read }, /* read */ 6453554Sheideman { &vop_write_desc, nfs_write }, /* write */ 6553554Sheideman { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ 6653806Smckusick { &vop_select_desc, nfs_select }, /* select */ 6753554Sheideman { &vop_mmap_desc, nfs_mmap }, /* mmap */ 6853554Sheideman { &vop_fsync_desc, nfs_fsync }, /* fsync */ 6953554Sheideman { &vop_seek_desc, nfs_seek }, /* seek */ 7053806Smckusick { &vop_remove_desc, nfs_remove }, /* remove */ 7153554Sheideman { &vop_link_desc, nfs_link }, /* link */ 7253806Smckusick { &vop_rename_desc, nfs_rename }, /* rename */ 7353554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 7453554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 7553806Smckusick { &vop_symlink_desc, nfs_symlink }, /* symlink */ 7653806Smckusick { &vop_readdir_desc, nfs_readdir }, /* readdir */ 7753806Smckusick { &vop_readlink_desc, nfs_readlink }, /* readlink */ 7853806Smckusick { &vop_abortop_desc, nfs_abortop }, /* abortop */ 7953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 8053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 8153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 8253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 8353554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */ 8453806Smckusick { &vop_strategy_desc, nfs_strategy }, /* strategy */ 8553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 8653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 8753806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8853806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 8953806Smckusick { &vop_valloc_desc, nfs_valloc }, /* valloc */ 9053554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */ 9153806Smckusick { &vop_truncate_desc, nfs_truncate }, /* truncate */ 9253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 93*57791Smckusick { &vop_bwrite_desc, nfs_bwrite }, 9453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 9538414Smckusick }; 9653554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 9753554Sheideman { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 9838414Smckusick 9948054Smckusick /* 10048054Smckusick * Special device vnode ops 10148054Smckusick */ 10253554Sheideman int (**spec_nfsv2nodeop_p)(); 10353554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 10453554Sheideman { &vop_default_desc, vn_default_error }, 10553806Smckusick { &vop_lookup_desc, spec_lookup }, /* lookup */ 10653806Smckusick { &vop_create_desc, spec_create }, /* create */ 10753806Smckusick { &vop_mknod_desc, spec_mknod }, /* mknod */ 10853554Sheideman { &vop_open_desc, spec_open }, /* open */ 10953806Smckusick { &vop_close_desc, nfsspec_close }, /* close */ 11056364Smckusick { &vop_access_desc, nfsspec_access }, /* access */ 11153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 11253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 11353806Smckusick { &vop_read_desc, nfsspec_read }, /* read */ 11453806Smckusick { &vop_write_desc, nfsspec_write }, /* write */ 11553806Smckusick { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 11653806Smckusick { &vop_select_desc, spec_select }, /* select */ 11753554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 11854451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 11953554Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 12053806Smckusick { &vop_remove_desc, spec_remove }, /* remove */ 12153554Sheideman { &vop_link_desc, spec_link }, /* link */ 12253806Smckusick { &vop_rename_desc, spec_rename }, /* rename */ 12353806Smckusick { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 12453806Smckusick { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 12553806Smckusick { &vop_symlink_desc, spec_symlink }, /* symlink */ 12653806Smckusick { &vop_readdir_desc, spec_readdir }, /* readdir */ 12753806Smckusick { &vop_readlink_desc, spec_readlink }, /* readlink */ 12853806Smckusick { &vop_abortop_desc, spec_abortop }, /* abortop */ 12953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 13053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 13153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 13253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 13353554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 13453806Smckusick { &vop_strategy_desc, spec_strategy }, /* strategy */ 13553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 13653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 13753806Smckusick { &vop_advlock_desc, spec_advlock }, /* advlock */ 13853806Smckusick { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 13953806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */ 14053806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */ 14153806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */ 14253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 143*57791Smckusick { &vop_bwrite_desc, nfs_bwrite }, 14453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 14538414Smckusick }; 14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 14753554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 14838414Smckusick 14940294Smckusick #ifdef FIFO 15053554Sheideman int (**fifo_nfsv2nodeop_p)(); 15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 15253554Sheideman { &vop_default_desc, vn_default_error }, 15353806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15453806Smckusick { &vop_create_desc, fifo_create }, /* create */ 15553806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15653554Sheideman { &vop_open_desc, fifo_open }, /* open */ 15753806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 15856364Smckusick { &vop_access_desc, nfsspec_access }, /* access */ 15953806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 16053806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 16153806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 16253806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16353806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16453806Smckusick { &vop_select_desc, fifo_select }, /* select */ 16553554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16654451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 16753554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 16853806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */ 16953554Sheideman { &vop_link_desc, fifo_link }, /* link */ 17053806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */ 17153806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17253806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17353806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17453806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17553806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17653806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17753806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 17853806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 17953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 18053806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18153554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18253806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */ 18353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18453806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 18553806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18653806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 18753806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */ 18853806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */ 18953806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */ 19053806Smckusick { &vop_update_desc, nfs_update }, /* update */ 191*57791Smckusick { &vop_bwrite_desc, nfs_bwrite }, 19253554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 19340294Smckusick }; 19453554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 19553554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 19640294Smckusick #endif /* FIFO */ 19740294Smckusick 19856289Smckusick void nqnfs_clientlease(); 19956289Smckusick 20048054Smckusick /* 20152196Smckusick * Global variables 20248054Smckusick */ 20338414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 20456364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false; 20538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20641905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 20746988Smckusick int nfs_numasync = 0; 20856390Smckusick /* Queue head for nfsiod's */ 20956468Smckusick struct queue_entry nfs_bufq; 21054740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 21138414Smckusick 21238414Smckusick /* 21338414Smckusick * nfs null call from vfs. 21438414Smckusick */ 21552234Sheideman int 21652196Smckusick nfs_null(vp, cred, procp) 21738414Smckusick struct vnode *vp; 21838414Smckusick struct ucred *cred; 21952196Smckusick struct proc *procp; 22038414Smckusick { 22139488Smckusick caddr_t bpos, dpos; 22239488Smckusick int error = 0; 22339488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22438414Smckusick 22552196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22652196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 22738414Smckusick nfsm_reqdone; 22838414Smckusick return (error); 22938414Smckusick } 23038414Smckusick 23138414Smckusick /* 23238414Smckusick * nfs access vnode op. 23356364Smckusick * For nfs, just return ok. File accesses may fail later. 23456364Smckusick * For nqnfs, use the access rpc to check accessibility. If file modes are 23556364Smckusick * changed on the server, accesses might still fail later. 23638414Smckusick */ 23752234Sheideman int 23853806Smckusick nfs_access(ap) 23954668Smckusick struct vop_access_args /* { 24054668Smckusick struct vnode *a_vp; 24154668Smckusick int a_mode; 24254668Smckusick struct ucred *a_cred; 24354668Smckusick struct proc *a_p; 24454668Smckusick } */ *ap; 24538414Smckusick { 24656364Smckusick register struct vnode *vp = ap->a_vp; 24756364Smckusick register u_long *tl; 24856364Smckusick register caddr_t cp; 24956364Smckusick caddr_t bpos, dpos; 25056364Smckusick int error = 0; 25156364Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 25238414Smckusick 25338414Smckusick /* 25456708Smckusick * For nqnfs, do an access rpc, otherwise you are stuck emulating 25556708Smckusick * ufs_access() locally using the vattr. This may not be correct, 25656708Smckusick * since the server may apply other access criteria such as 25756708Smckusick * client uid-->server uid mapping that we do not know about, but 25856708Smckusick * this is better than just returning anything that is lying about 25956708Smckusick * in the cache. 26038414Smckusick */ 26156364Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 26256364Smckusick nfsstats.rpccnt[NQNFSPROC_ACCESS]++; 26356364Smckusick nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED); 26456364Smckusick nfsm_fhtom(vp); 26556364Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 26656364Smckusick if (ap->a_mode & VREAD) 26756364Smckusick *tl++ = nfs_true; 26856364Smckusick else 26956364Smckusick *tl++ = nfs_false; 27056364Smckusick if (ap->a_mode & VWRITE) 27156364Smckusick *tl++ = nfs_true; 27256364Smckusick else 27356364Smckusick *tl++ = nfs_false; 27456364Smckusick if (ap->a_mode & VEXEC) 27556364Smckusick *tl = nfs_true; 27656364Smckusick else 27756364Smckusick *tl = nfs_false; 27856364Smckusick nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred); 27956364Smckusick nfsm_reqdone; 28038884Smacklem return (error); 28156364Smckusick } else 28256708Smckusick return (nfsspec_access(ap)); 28338414Smckusick } 28438414Smckusick 28538414Smckusick /* 28638414Smckusick * nfs open vnode op 28756289Smckusick * Check to see if the type is ok 28852196Smckusick * and that deletion is not in progress. 28956289Smckusick * For paged in text files, you will need to flush the page cache 29056289Smckusick * if consistency is lost. 29138414Smckusick */ 29239488Smckusick /* ARGSUSED */ 29352234Sheideman int 29453806Smckusick nfs_open(ap) 29554668Smckusick struct vop_open_args /* { 29654668Smckusick struct vnode *a_vp; 29754668Smckusick int a_mode; 29854668Smckusick struct ucred *a_cred; 29954668Smckusick struct proc *a_p; 30054668Smckusick } */ *ap; 30138414Smckusick { 30253806Smckusick register struct vnode *vp = ap->a_vp; 30356289Smckusick struct nfsnode *np = VTONFS(vp); 30456289Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount); 30556289Smckusick struct vattr vattr; 30656289Smckusick int error; 30738414Smckusick 30853806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 30938414Smckusick return (EACCES); 31056289Smckusick if (vp->v_flag & VTEXT) { 31156289Smckusick /* 31256289Smckusick * Get a valid lease. If cached data is stale, flush it. 31356289Smckusick */ 31456289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 31556289Smckusick if (NQNFS_CKINVALID(vp, np, NQL_READ)) { 31656289Smckusick do { 31756289Smckusick error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p); 31856289Smckusick } while (error == NQNFS_EXPIRED); 31956289Smckusick if (error) 32056289Smckusick return (error); 32156289Smckusick if (np->n_lrev != np->n_brev) { 322*57791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 323*57791Smckusick ap->a_p, 1)) == EINTR) 324*57791Smckusick return (error); 32556289Smckusick (void) vnode_pager_uncache(vp); 32656289Smckusick np->n_brev = np->n_lrev; 32756289Smckusick } 32856289Smckusick } 32956289Smckusick } else { 33056289Smckusick if (np->n_flag & NMODIFIED) { 331*57791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 332*57791Smckusick ap->a_p, 1)) == EINTR) 333*57791Smckusick return (error); 33456289Smckusick (void) vnode_pager_uncache(vp); 33556289Smckusick np->n_attrstamp = 0; 33656289Smckusick np->n_direofoffset = 0; 33756289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 33856289Smckusick return (error); 33956289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 34056289Smckusick } else { 34156289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 34256289Smckusick return (error); 34356289Smckusick if (np->n_mtime != vattr.va_mtime.ts_sec) { 34456289Smckusick np->n_direofoffset = 0; 345*57791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, 346*57791Smckusick ap->a_cred, ap->a_p, 1)) == EINTR) 347*57791Smckusick return (error); 34856289Smckusick (void) vnode_pager_uncache(vp); 34956289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 35056289Smckusick } 35156289Smckusick } 35256289Smckusick } 35356289Smckusick } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 35456289Smckusick np->n_attrstamp = 0; /* For Open/Close consistency */ 35552196Smckusick return (0); 35638414Smckusick } 35738414Smckusick 35838414Smckusick /* 35938414Smckusick * nfs close vnode op 36038884Smacklem * For reg files, invalidate any buffer cache entries. 36138414Smckusick */ 36239488Smckusick /* ARGSUSED */ 36352234Sheideman int 36453806Smckusick nfs_close(ap) 36554451Smckusick struct vop_close_args /* { 36654451Smckusick struct vnodeop_desc *a_desc; 36754451Smckusick struct vnode *a_vp; 36854451Smckusick int a_fflag; 36954451Smckusick struct ucred *a_cred; 37054451Smckusick struct proc *a_p; 37154451Smckusick } */ *ap; 37238414Smckusick { 37353806Smckusick register struct vnode *vp = ap->a_vp; 37453806Smckusick register struct nfsnode *np = VTONFS(vp); 37539341Smckusick int error = 0; 37638414Smckusick 37753806Smckusick if (vp->v_type == VREG) { 37853806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 37953629Smckusick (np->n_flag & NMODIFIED)) { 380*57791Smckusick error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); 38141905Smckusick np->n_attrstamp = 0; 38253629Smckusick } 38353629Smckusick if (np->n_flag & NWRITEERR) { 38453629Smckusick np->n_flag &= ~NWRITEERR; 38553629Smckusick error = np->n_error; 38653629Smckusick } 38738884Smacklem } 38838414Smckusick return (error); 38938414Smckusick } 39038414Smckusick 39138414Smckusick /* 39238414Smckusick * nfs getattr call from vfs. 39338414Smckusick */ 39452234Sheideman int 39553805Smckusick nfs_getattr(ap) 39654668Smckusick struct vop_getattr_args /* { 39754668Smckusick struct vnode *a_vp; 39854668Smckusick struct vattr *a_vap; 39954668Smckusick struct ucred *a_cred; 40054668Smckusick struct proc *a_p; 40154668Smckusick } */ *ap; 40238414Smckusick { 40353805Smckusick register struct vnode *vp = ap->a_vp; 40453805Smckusick register struct nfsnode *np = VTONFS(vp); 40539488Smckusick register caddr_t cp; 40639488Smckusick caddr_t bpos, dpos; 40739488Smckusick int error = 0; 40839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 40938414Smckusick 41053805Smckusick /* 41153805Smckusick * Update local times for special files. 41253805Smckusick */ 41356329Smckusick if (np->n_flag & (NACC | NUPD)) 41453805Smckusick np->n_flag |= NCHG; 41553805Smckusick /* 41653805Smckusick * First look in the cache. 41753805Smckusick */ 41853805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 41938414Smckusick return (0); 42038414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 42153805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 42253805Smckusick nfsm_fhtom(vp); 42353805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 42453805Smckusick nfsm_loadattr(vp, ap->a_vap); 42538414Smckusick nfsm_reqdone; 42638414Smckusick return (error); 42738414Smckusick } 42838414Smckusick 42938414Smckusick /* 43038414Smckusick * nfs setattr call. 43138414Smckusick */ 43252234Sheideman int 43353806Smckusick nfs_setattr(ap) 43454451Smckusick struct vop_setattr_args /* { 43554451Smckusick struct vnodeop_desc *a_desc; 43654451Smckusick struct vnode *a_vp; 43754451Smckusick struct vattr *a_vap; 43854451Smckusick struct ucred *a_cred; 43954451Smckusick struct proc *a_p; 44054451Smckusick } */ *ap; 44138414Smckusick { 44238884Smacklem register struct nfsv2_sattr *sp; 44339488Smckusick register caddr_t cp; 44439488Smckusick register long t1; 44552196Smckusick caddr_t bpos, dpos, cp2; 44652196Smckusick u_long *tl; 44756289Smckusick int error = 0, isnq; 44839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 44953806Smckusick register struct vnode *vp = ap->a_vp; 45053806Smckusick register struct nfsnode *np = VTONFS(vp); 45153806Smckusick register struct vattr *vap = ap->a_vap; 45252196Smckusick u_quad_t frev; 45338414Smckusick 454*57791Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || 455*57791Smckusick vap->va_atime.ts_sec != VNOVAL) { 456*57791Smckusick if (vap->va_size != VNOVAL) { 457*57791Smckusick if (np->n_flag & NMODIFIED) { 458*57791Smckusick if (vap->va_size == 0) 459*57791Smckusick error = nfs_vinvalbuf(vp, 0, ap->a_cred, 460*57791Smckusick ap->a_p, 1); 461*57791Smckusick else 462*57791Smckusick error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 463*57791Smckusick ap->a_p, 1); 464*57791Smckusick if (error) 465*57791Smckusick return (error); 466*57791Smckusick } 467*57791Smckusick np->n_size = np->n_vattr.va_size = vap->va_size; 468*57791Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 469*57791Smckusick } else if ((np->n_flag & NMODIFIED) && 470*57791Smckusick (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 471*57791Smckusick ap->a_p, 1)) == EINTR) 472*57791Smckusick return (error); 473*57791Smckusick } 47438414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 47556289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 47656289Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq)); 47753806Smckusick nfsm_fhtom(vp); 47856289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 47956289Smckusick if (vap->va_mode == (u_short)-1) 48038884Smacklem sp->sa_mode = VNOVAL; 48138414Smckusick else 48253806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 48356289Smckusick if (vap->va_uid == (uid_t)-1) 48438884Smacklem sp->sa_uid = VNOVAL; 48538414Smckusick else 48653806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 48756289Smckusick if (vap->va_gid == (gid_t)-1) 48838884Smacklem sp->sa_gid = VNOVAL; 48938414Smckusick else 49053806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 49156289Smckusick if (isnq) { 49256289Smckusick txdr_hyper(&vap->va_size, &sp->sa_nqsize); 49356289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 49456289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 49556289Smckusick sp->sa_nqflags = txdr_unsigned(vap->va_flags); 49656289Smckusick sp->sa_nqrdev = VNOVAL; 49756289Smckusick } else { 49856289Smckusick sp->sa_nfssize = txdr_unsigned(vap->va_size); 49956289Smckusick sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec); 50056289Smckusick sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags); 50156289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 50256289Smckusick } 50353806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 50453806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 50553806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 50653806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 50752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 50852196Smckusick fxdr_hyper(tl, &frev); 50954451Smckusick if (frev > np->n_brev) 51052196Smckusick np->n_brev = frev; 51152196Smckusick } 51238414Smckusick nfsm_reqdone; 51338414Smckusick return (error); 51438414Smckusick } 51538414Smckusick 51638414Smckusick /* 51738414Smckusick * nfs lookup call, one step at a time... 51838414Smckusick * First look in cache 51938414Smckusick * If not found, unlock the directory nfsnode and do the rpc 52038414Smckusick */ 52152234Sheideman int 52253806Smckusick nfs_lookup(ap) 52354451Smckusick struct vop_lookup_args /* { 52454451Smckusick struct vnodeop_desc *a_desc; 52554451Smckusick struct vnode *a_dvp; 52654451Smckusick struct vnode **a_vpp; 52754451Smckusick struct componentname *a_cnp; 52854451Smckusick } */ *ap; 52938414Smckusick { 53053806Smckusick register struct componentname *cnp = ap->a_cnp; 53153806Smckusick register struct vnode *dvp = ap->a_dvp; 53254668Smckusick register struct vnode **vpp = ap->a_vpp; 53355184Smckusick register int flags = cnp->cn_flags; 53438414Smckusick register struct vnode *vdp; 53548054Smckusick register u_long *tl; 53639488Smckusick register caddr_t cp; 53739488Smckusick register long t1, t2; 53852196Smckusick struct nfsmount *nmp; 53952196Smckusick struct nfsnode *tp; 54039488Smckusick caddr_t bpos, dpos, cp2; 54152196Smckusick time_t reqtime; 54239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 54338414Smckusick struct vnode *newvp; 54438414Smckusick long len; 54538414Smckusick nfsv2fh_t *fhp; 54638414Smckusick struct nfsnode *np; 54752234Sheideman int lockparent, wantparent, error = 0; 54852196Smckusick int nqlflag, cachable; 54952196Smckusick u_quad_t frev; 55038414Smckusick 55154668Smckusick *vpp = NULL; 55253806Smckusick if (dvp->v_type != VDIR) 55338414Smckusick return (ENOTDIR); 55455184Smckusick lockparent = flags & LOCKPARENT; 55555184Smckusick wantparent = flags & (LOCKPARENT|WANTPARENT); 55653806Smckusick nmp = VFSTONFS(dvp->v_mount); 55753806Smckusick np = VTONFS(dvp); 55854668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 55938884Smacklem struct vattr vattr; 56038884Smacklem int vpid; 56138884Smacklem 56254668Smckusick vdp = *vpp; 56338884Smacklem vpid = vdp->v_id; 56438414Smckusick /* 56538884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 56638884Smacklem * for an explanation of the locking protocol 56738414Smckusick */ 56853806Smckusick if (dvp == vdp) { 56938425Smckusick VREF(vdp); 57039441Smckusick error = 0; 57152196Smckusick } else 57239441Smckusick error = vget(vdp); 57339441Smckusick if (!error) { 57440251Smckusick if (vpid == vdp->v_id) { 57552196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 57656289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) { 57756289Smckusick nfsstats.lookupcache_hits++; 57856289Smckusick if (cnp->cn_nameiop != LOOKUP && 57956289Smckusick (flags & ISLASTCN)) 58056289Smckusick cnp->cn_flags |= SAVENAME; 58156289Smckusick return (0); 58256289Smckusick } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 58354451Smckusick if (np->n_lrev != np->n_brev || 58452196Smckusick (np->n_flag & NMODIFIED)) { 58552196Smckusick np->n_direofoffset = 0; 58653806Smckusick cache_purge(dvp); 587*57791Smckusick error = nfs_vinvalbuf(dvp, 0, 58856660Smckusick cnp->cn_cred, cnp->cn_proc, 589*57791Smckusick 1); 590*57791Smckusick if (error == EINTR) 591*57791Smckusick return (error); 59252196Smckusick np->n_brev = np->n_lrev; 59352196Smckusick } else { 59452196Smckusick nfsstats.lookupcache_hits++; 59553806Smckusick if (cnp->cn_nameiop != LOOKUP && 59655184Smckusick (flags & ISLASTCN)) 59753806Smckusick cnp->cn_flags |= SAVENAME; 59852196Smckusick return (0); 59952196Smckusick } 60052196Smckusick } 60153806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 60254106Smckusick vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { 60339441Smckusick nfsstats.lookupcache_hits++; 60453806Smckusick if (cnp->cn_nameiop != LOOKUP && 60555184Smckusick (flags & ISLASTCN)) 60653806Smckusick cnp->cn_flags |= SAVENAME; 60739441Smckusick return (0); 60840251Smckusick } 60947289Smckusick cache_purge(vdp); 61039441Smckusick } 61152196Smckusick vrele(vdp); 61238884Smacklem } 61354668Smckusick *vpp = NULLVP; 61452196Smckusick } 61539341Smckusick error = 0; 61638414Smckusick nfsstats.lookupcache_misses++; 61738414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 61853806Smckusick len = cnp->cn_namelen; 61953806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 62052196Smckusick 62152196Smckusick /* 62252196Smckusick * For nqnfs optionally piggyback a getlease request for the name 62352196Smckusick * being looked up. 62452196Smckusick */ 62552196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 62656289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 62752196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 62855184Smckusick ((cnp->cn_flags & MAKEENTRY) && 62956289Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) 63052196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 63156289Smckusick else 63252196Smckusick *tl = 0; 63352196Smckusick } 63453806Smckusick nfsm_fhtom(dvp); 63553806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 63652196Smckusick reqtime = time.tv_sec; 63753806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 63838414Smckusick nfsmout: 63938414Smckusick if (error) { 64053806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 64155184Smckusick (flags & ISLASTCN) && error == ENOENT) 64252823Smckusick error = EJUSTRETURN; 64355184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 64453806Smckusick cnp->cn_flags |= SAVENAME; 64540483Smckusick return (error); 64638414Smckusick } 64752196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 64852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 64952196Smckusick if (*tl) { 65052196Smckusick nqlflag = fxdr_unsigned(int, *tl); 65152196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 65252196Smckusick cachable = fxdr_unsigned(int, *tl++); 65352196Smckusick reqtime += fxdr_unsigned(int, *tl++); 65452196Smckusick fxdr_hyper(tl, &frev); 65552196Smckusick } else 65652196Smckusick nqlflag = 0; 65752196Smckusick } 65852196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 65938414Smckusick 66038414Smckusick /* 66152196Smckusick * Handle RENAME case... 66238414Smckusick */ 66355184Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 66452196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 66538414Smckusick m_freem(mrep); 66638414Smckusick return (EISDIR); 66738414Smckusick } 66853806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 66938414Smckusick m_freem(mrep); 67038414Smckusick return (error); 67138414Smckusick } 67238414Smckusick newvp = NFSTOV(np); 67339459Smckusick if (error = 67439459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 67552196Smckusick vrele(newvp); 67638414Smckusick m_freem(mrep); 67738414Smckusick return (error); 67838414Smckusick } 67954668Smckusick *vpp = newvp; 68045037Smckusick m_freem(mrep); 68153806Smckusick cnp->cn_flags |= SAVENAME; 68238414Smckusick return (0); 68338414Smckusick } 68438414Smckusick 68552196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 68653806Smckusick VREF(dvp); 68753806Smckusick newvp = dvp; 68838414Smckusick } else { 68953806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 69038414Smckusick m_freem(mrep); 69138414Smckusick return (error); 69238414Smckusick } 69338414Smckusick newvp = NFSTOV(np); 69438414Smckusick } 69539459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 69652196Smckusick vrele(newvp); 69738414Smckusick m_freem(mrep); 69838414Smckusick return (error); 69938414Smckusick } 70038414Smckusick m_freem(mrep); 70154668Smckusick *vpp = newvp; 70255184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 70353806Smckusick cnp->cn_flags |= SAVENAME; 70455184Smckusick if ((cnp->cn_flags & MAKEENTRY) && 70555184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { 70652196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 70754106Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec; 70856289Smckusick else if (nqlflag && reqtime > time.tv_sec) 70956289Smckusick nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime, 71056289Smckusick frev); 71154668Smckusick cache_enter(dvp, *vpp, cnp); 71240251Smckusick } 71352196Smckusick return (0); 71438414Smckusick } 71538414Smckusick 71638414Smckusick /* 71741905Smckusick * nfs read call. 71841905Smckusick * Just call nfs_bioread() to do the work. 71941905Smckusick */ 72052234Sheideman int 72153806Smckusick nfs_read(ap) 72254668Smckusick struct vop_read_args /* { 72354668Smckusick struct vnode *a_vp; 72454668Smckusick struct uio *a_uio; 72554668Smckusick int a_ioflag; 72654668Smckusick struct ucred *a_cred; 72754668Smckusick } */ *ap; 72841905Smckusick { 72953806Smckusick register struct vnode *vp = ap->a_vp; 73053806Smckusick 73153806Smckusick if (vp->v_type != VREG) 73241905Smckusick return (EPERM); 73353806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 73441905Smckusick } 73541905Smckusick 73641905Smckusick /* 73738414Smckusick * nfs readlink call 73838414Smckusick */ 73952234Sheideman int 74053806Smckusick nfs_readlink(ap) 74154668Smckusick struct vop_readlink_args /* { 74254668Smckusick struct vnode *a_vp; 74354668Smckusick struct uio *a_uio; 74454668Smckusick struct ucred *a_cred; 74554668Smckusick } */ *ap; 74641905Smckusick { 74753806Smckusick register struct vnode *vp = ap->a_vp; 74853806Smckusick 74953806Smckusick if (vp->v_type != VLNK) 75041905Smckusick return (EPERM); 75153806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 75241905Smckusick } 75341905Smckusick 75441905Smckusick /* 75541905Smckusick * Do a readlink rpc. 75641905Smckusick * Called by nfs_doio() from below the buffer cache. 75741905Smckusick */ 75852234Sheideman int 75948054Smckusick nfs_readlinkrpc(vp, uiop, cred) 76039488Smckusick register struct vnode *vp; 76138414Smckusick struct uio *uiop; 76238414Smckusick struct ucred *cred; 76338414Smckusick { 76448054Smckusick register u_long *tl; 76539488Smckusick register caddr_t cp; 76639488Smckusick register long t1; 76739488Smckusick caddr_t bpos, dpos, cp2; 76839488Smckusick int error = 0; 76939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 77038414Smckusick long len; 77138414Smckusick 77238414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 77352196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 77438414Smckusick nfsm_fhtom(vp); 77552196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 77638414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 77738414Smckusick nfsm_mtouio(uiop, len); 77838414Smckusick nfsm_reqdone; 77938414Smckusick return (error); 78038414Smckusick } 78138414Smckusick 78238414Smckusick /* 78341905Smckusick * nfs read rpc call 78441905Smckusick * Ditto above 78538414Smckusick */ 78652234Sheideman int 78748054Smckusick nfs_readrpc(vp, uiop, cred) 78839488Smckusick register struct vnode *vp; 78938414Smckusick struct uio *uiop; 79038414Smckusick struct ucred *cred; 79138414Smckusick { 79248054Smckusick register u_long *tl; 79339488Smckusick register caddr_t cp; 79439488Smckusick register long t1; 79539488Smckusick caddr_t bpos, dpos, cp2; 79639488Smckusick int error = 0; 79739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 79838414Smckusick struct nfsmount *nmp; 79938414Smckusick long len, retlen, tsiz; 80038414Smckusick 80141398Smckusick nmp = VFSTONFS(vp->v_mount); 80238414Smckusick tsiz = uiop->uio_resid; 80356289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 80456289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 80556289Smckusick return (EFBIG); 80638414Smckusick while (tsiz > 0) { 80738414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 80838414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 80952196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 81038414Smckusick nfsm_fhtom(vp); 81148054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 81256289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 81356289Smckusick txdr_hyper(&uiop->uio_offset, tl); 81456289Smckusick *(tl + 2) = txdr_unsigned(len); 81556289Smckusick } else { 81656289Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 81756289Smckusick *tl++ = txdr_unsigned(len); 81856289Smckusick *tl = 0; 81956289Smckusick } 82052196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 82138414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 82238414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 82338414Smckusick nfsm_mtouio(uiop, retlen); 82438414Smckusick m_freem(mrep); 82538414Smckusick if (retlen < len) 82638414Smckusick tsiz = 0; 82738414Smckusick else 82838414Smckusick tsiz -= len; 82938414Smckusick } 83038414Smckusick nfsmout: 83138414Smckusick return (error); 83238414Smckusick } 83338414Smckusick 83438414Smckusick /* 83538414Smckusick * nfs write call 83638414Smckusick */ 83752234Sheideman int 83856289Smckusick nfs_writerpc(vp, uiop, cred, ioflags) 83939488Smckusick register struct vnode *vp; 84038414Smckusick struct uio *uiop; 84138414Smckusick struct ucred *cred; 84256289Smckusick int ioflags; 84338414Smckusick { 84448054Smckusick register u_long *tl; 84539488Smckusick register caddr_t cp; 84639488Smckusick register long t1; 84752196Smckusick caddr_t bpos, dpos, cp2; 84839488Smckusick int error = 0; 84939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 85038414Smckusick struct nfsmount *nmp; 85152196Smckusick struct nfsnode *np = VTONFS(vp); 85252196Smckusick u_quad_t frev; 85338414Smckusick long len, tsiz; 85438414Smckusick 85541398Smckusick nmp = VFSTONFS(vp->v_mount); 85638414Smckusick tsiz = uiop->uio_resid; 85756289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 85856289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 85956289Smckusick return (EFBIG); 86038414Smckusick while (tsiz > 0) { 86138414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 86238414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 86352196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 86452196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 86538414Smckusick nfsm_fhtom(vp); 86656289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4); 86756289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 86856289Smckusick txdr_hyper(&uiop->uio_offset, tl); 86956289Smckusick tl += 2; 87056289Smckusick if (ioflags & IO_APPEND) 87156289Smckusick *tl++ = txdr_unsigned(1); 87256289Smckusick else 87356289Smckusick *tl++ = 0; 87456289Smckusick } else { 87556289Smckusick *++tl = txdr_unsigned(uiop->uio_offset); 87656289Smckusick tl += 2; 87756289Smckusick } 87856289Smckusick *tl = txdr_unsigned(len); 87938414Smckusick nfsm_uiotom(uiop, len); 88052196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 88138414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 88252196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 88354106Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; 88452196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 88552196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 88652196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 88752196Smckusick fxdr_hyper(tl, &frev); 88854451Smckusick if (frev > np->n_brev) 88952196Smckusick np->n_brev = frev; 89052196Smckusick } 89138414Smckusick m_freem(mrep); 89238414Smckusick tsiz -= len; 89338414Smckusick } 89438414Smckusick nfsmout: 89552196Smckusick if (error) 89652196Smckusick uiop->uio_resid = tsiz; 89738414Smckusick return (error); 89838414Smckusick } 89938414Smckusick 90038414Smckusick /* 90139459Smckusick * nfs mknod call 90242246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 90342246Smckusick * set to specify the file type and the size field for rdev. 90439459Smckusick */ 90539459Smckusick /* ARGSUSED */ 90652234Sheideman int 90753806Smckusick nfs_mknod(ap) 90854668Smckusick struct vop_mknod_args /* { 90954668Smckusick struct vnode *a_dvp; 91054668Smckusick struct vnode **a_vpp; 91154668Smckusick struct componentname *a_cnp; 91254668Smckusick struct vattr *a_vap; 91354668Smckusick } */ *ap; 91439459Smckusick { 91553806Smckusick register struct vnode *dvp = ap->a_dvp; 91653806Smckusick register struct vattr *vap = ap->a_vap; 91753806Smckusick register struct componentname *cnp = ap->a_cnp; 91842246Smckusick register struct nfsv2_sattr *sp; 91948054Smckusick register u_long *tl; 92042246Smckusick register caddr_t cp; 92156289Smckusick register long t1, t2; 92256289Smckusick struct vnode *newvp; 92356289Smckusick char *cp2; 92442246Smckusick caddr_t bpos, dpos; 92556289Smckusick int error = 0, isnq; 92642246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92742246Smckusick u_long rdev; 92839459Smckusick 92956289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 93053806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 93153806Smckusick rdev = txdr_unsigned(vap->va_rdev); 93242246Smckusick #ifdef FIFO 93353806Smckusick else if (vap->va_type == VFIFO) 93442246Smckusick rdev = 0xffffffff; 93542246Smckusick #endif /* FIFO */ 93642246Smckusick else { 93753806Smckusick VOP_ABORTOP(dvp, cnp); 93853806Smckusick vput(dvp); 93942246Smckusick return (EOPNOTSUPP); 94042246Smckusick } 94142246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 94253806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 94356289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 94453806Smckusick nfsm_fhtom(dvp); 94553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 94656289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 94753806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 94853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 94953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 95056289Smckusick if (isnq) { 95156289Smckusick sp->sa_nqrdev = rdev; 95256289Smckusick sp->sa_nqflags = 0; 95356289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 95456289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 95556289Smckusick } else { 95656289Smckusick sp->sa_nfssize = rdev; 95756289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 95856289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 95956289Smckusick } 96053806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 96156289Smckusick nfsm_mtofh(dvp, newvp); 96242246Smckusick nfsm_reqdone; 96356927Smckusick if (!error && (cnp->cn_flags & MAKEENTRY)) 96456289Smckusick cache_enter(dvp, newvp, cnp); 96553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 96653806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 96753806Smckusick vrele(dvp); 96842246Smckusick return (error); 96939459Smckusick } 97039459Smckusick 97139459Smckusick /* 97238414Smckusick * nfs file create call 97338414Smckusick */ 97452234Sheideman int 97553806Smckusick nfs_create(ap) 97654668Smckusick struct vop_create_args /* { 97754668Smckusick struct vnode *a_dvp; 97854668Smckusick struct vnode **a_vpp; 97954668Smckusick struct componentname *a_cnp; 98054668Smckusick struct vattr *a_vap; 98154668Smckusick } */ *ap; 98238414Smckusick { 98353806Smckusick register struct vnode *dvp = ap->a_dvp; 98453806Smckusick register struct vattr *vap = ap->a_vap; 98553806Smckusick register struct componentname *cnp = ap->a_cnp; 98638884Smacklem register struct nfsv2_sattr *sp; 98748054Smckusick register u_long *tl; 98839488Smckusick register caddr_t cp; 98939488Smckusick register long t1, t2; 99039488Smckusick caddr_t bpos, dpos, cp2; 99156289Smckusick int error = 0, isnq; 99239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 99338414Smckusick 99438414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 99556289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 99653806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 99756289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 99853806Smckusick nfsm_fhtom(dvp); 99953806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 100056289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 100153806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 100253806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 100353806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 100456289Smckusick if (isnq) { 100556289Smckusick u_quad_t qval = 0; 100656289Smckusick 100756289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 100856289Smckusick sp->sa_nqflags = 0; 100956289Smckusick sp->sa_nqrdev = -1; 101056289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 101156289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 101256289Smckusick } else { 101356289Smckusick sp->sa_nfssize = 0; 101456289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 101556289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 101656289Smckusick } 101753806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 101853806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 101938414Smckusick nfsm_reqdone; 102056927Smckusick if (!error && (cnp->cn_flags & MAKEENTRY)) 102156289Smckusick cache_enter(dvp, *ap->a_vpp, cnp); 102253806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 102353806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 102453806Smckusick vrele(dvp); 102538414Smckusick return (error); 102638414Smckusick } 102738414Smckusick 102838414Smckusick /* 102938414Smckusick * nfs file remove call 103041905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 103141905Smckusick * other processes using the vnode is renamed instead of removed and then 103239341Smckusick * removed later on the last close. 103341905Smckusick * - If v_usecount > 1 103439341Smckusick * If a rename is not already in the works 103539341Smckusick * call nfs_sillyrename() to set it up 103639341Smckusick * else 103739341Smckusick * do the remove rpc 103838414Smckusick */ 103952234Sheideman int 104053806Smckusick nfs_remove(ap) 104154451Smckusick struct vop_remove_args /* { 104254451Smckusick struct vnodeop_desc *a_desc; 104354451Smckusick struct vnode * a_dvp; 104454451Smckusick struct vnode * a_vp; 104554451Smckusick struct componentname * a_cnp; 104654451Smckusick } */ *ap; 104738414Smckusick { 104853806Smckusick register struct vnode *vp = ap->a_vp; 104953806Smckusick register struct vnode *dvp = ap->a_dvp; 105053806Smckusick register struct componentname *cnp = ap->a_cnp; 105153806Smckusick register struct nfsnode *np = VTONFS(vp); 105248054Smckusick register u_long *tl; 105339488Smckusick register caddr_t cp; 105452196Smckusick register long t2; 105539488Smckusick caddr_t bpos, dpos; 105639488Smckusick int error = 0; 105739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 105838414Smckusick 105953806Smckusick if (vp->v_usecount > 1) { 106039341Smckusick if (!np->n_sillyrename) 106153806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 106239341Smckusick } else { 106352196Smckusick /* 106452196Smckusick * Purge the name cache so that the chance of a lookup for 106552196Smckusick * the name succeeding while the remove is in progress is 106652196Smckusick * minimized. Without node locking it can still happen, such 106752196Smckusick * that an I/O op returns ESTALE, but since you get this if 106852196Smckusick * another host removes the file.. 106952196Smckusick */ 107053806Smckusick cache_purge(vp); 107152196Smckusick /* 107252196Smckusick * Throw away biocache buffers. Mainly to avoid 107352196Smckusick * unnecessary delayed writes. 107452196Smckusick */ 1075*57791Smckusick error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1); 1076*57791Smckusick if (error == EINTR) 1077*57791Smckusick return (error); 107852196Smckusick /* Do the rpc */ 107938414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 108053806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 108153806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 108253806Smckusick nfsm_fhtom(dvp); 108353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 108453806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 108538414Smckusick nfsm_reqdone; 108653806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 108753806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 108839751Smckusick /* 108939751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 109039751Smckusick * the reply to the retransmitted request will be ENOENT 109139751Smckusick * since the file was in fact removed 109239751Smckusick * Therefore, we cheat and return success. 109339751Smckusick */ 109439751Smckusick if (error == ENOENT) 109539751Smckusick error = 0; 109638414Smckusick } 109740042Smckusick np->n_attrstamp = 0; 109853806Smckusick vrele(dvp); 109953806Smckusick vrele(vp); 110038414Smckusick return (error); 110138414Smckusick } 110238414Smckusick 110338414Smckusick /* 110438414Smckusick * nfs file remove rpc called from nfs_inactive 110538414Smckusick */ 110652234Sheideman int 110754451Smckusick nfs_removeit(sp) 110848364Smckusick register struct sillyrename *sp; 110938414Smckusick { 111048054Smckusick register u_long *tl; 111139488Smckusick register caddr_t cp; 111252196Smckusick register long t2; 111339488Smckusick caddr_t bpos, dpos; 111439488Smckusick int error = 0; 111539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 111638414Smckusick 111738414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 111852196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 111948364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 112048364Smckusick nfsm_fhtom(sp->s_dvp); 112148364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 112254451Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); 112338414Smckusick nfsm_reqdone; 112448364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 112538414Smckusick return (error); 112638414Smckusick } 112738414Smckusick 112838414Smckusick /* 112938414Smckusick * nfs file rename call 113038414Smckusick */ 113152234Sheideman int 113253806Smckusick nfs_rename(ap) 113354668Smckusick struct vop_rename_args /* { 113454668Smckusick struct vnode *a_fdvp; 113554668Smckusick struct vnode *a_fvp; 113654668Smckusick struct componentname *a_fcnp; 113754668Smckusick struct vnode *a_tdvp; 113854668Smckusick struct vnode *a_tvp; 113954668Smckusick struct componentname *a_tcnp; 114054668Smckusick } */ *ap; 114138414Smckusick { 114253806Smckusick register struct vnode *fvp = ap->a_fvp; 114353806Smckusick register struct vnode *tvp = ap->a_tvp; 114453806Smckusick register struct vnode *fdvp = ap->a_fdvp; 114553806Smckusick register struct vnode *tdvp = ap->a_tdvp; 114653806Smckusick register struct componentname *tcnp = ap->a_tcnp; 114753806Smckusick register struct componentname *fcnp = ap->a_fcnp; 114848054Smckusick register u_long *tl; 114939488Smckusick register caddr_t cp; 115052196Smckusick register long t2; 115139488Smckusick caddr_t bpos, dpos; 115239488Smckusick int error = 0; 115339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 115438414Smckusick 115553804Spendry /* Check for cross-device rename */ 115653806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 115753806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 115853804Spendry error = EXDEV; 115953804Spendry goto out; 116053804Spendry } 116153804Spendry 116253804Spendry 116338414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 116453806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 116553806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 116653806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 116753806Smckusick nfsm_fhtom(fdvp); 116853806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 116953806Smckusick nfsm_fhtom(tdvp); 117053806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 117153806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 117238414Smckusick nfsm_reqdone; 117353806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 117453806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 117553806Smckusick if (fvp->v_type == VDIR) { 117653806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 117753806Smckusick cache_purge(tdvp); 117853806Smckusick cache_purge(fdvp); 117938414Smckusick } 118053804Spendry out: 118153806Smckusick if (tdvp == tvp) 118253806Smckusick vrele(tdvp); 118343360Smckusick else 118453806Smckusick vput(tdvp); 118553806Smckusick if (tvp) 118653806Smckusick vput(tvp); 118753806Smckusick vrele(fdvp); 118853806Smckusick vrele(fvp); 118940112Smckusick /* 119040112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 119140112Smckusick */ 119240112Smckusick if (error == ENOENT) 119340112Smckusick error = 0; 119438414Smckusick return (error); 119538414Smckusick } 119638414Smckusick 119738414Smckusick /* 119841905Smckusick * nfs file rename rpc called from nfs_remove() above 119938414Smckusick */ 120052234Sheideman int 120152234Sheideman nfs_renameit(sdvp, scnp, sp) 120252234Sheideman struct vnode *sdvp; 120352234Sheideman struct componentname *scnp; 120448364Smckusick register struct sillyrename *sp; 120538414Smckusick { 120648054Smckusick register u_long *tl; 120739488Smckusick register caddr_t cp; 120852196Smckusick register long t2; 120939488Smckusick caddr_t bpos, dpos; 121039488Smckusick int error = 0; 121139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 121238414Smckusick 121338414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 121452234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 121552234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 121652196Smckusick nfsm_rndup(sp->s_namlen)); 121752234Sheideman nfsm_fhtom(sdvp); 121852234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 121952234Sheideman nfsm_fhtom(sdvp); 122048364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 122152234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 122238414Smckusick nfsm_reqdone; 122352234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 122452234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 122538414Smckusick return (error); 122638414Smckusick } 122738414Smckusick 122838414Smckusick /* 122938414Smckusick * nfs hard link create call 123038414Smckusick */ 123152234Sheideman int 123253806Smckusick nfs_link(ap) 123354668Smckusick struct vop_link_args /* { 123454668Smckusick struct vnode *a_vp; 123554668Smckusick struct vnode *a_tdvp; 123654668Smckusick struct componentname *a_cnp; 123754668Smckusick } */ *ap; 123838414Smckusick { 123953806Smckusick register struct vnode *vp = ap->a_vp; 124053806Smckusick register struct vnode *tdvp = ap->a_tdvp; 124153806Smckusick register struct componentname *cnp = ap->a_cnp; 124248054Smckusick register u_long *tl; 124339488Smckusick register caddr_t cp; 124452196Smckusick register long t2; 124539488Smckusick caddr_t bpos, dpos; 124639488Smckusick int error = 0; 124739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 124838414Smckusick 124953806Smckusick if (vp->v_mount != tdvp->v_mount) { 125053806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 125153806Smckusick if (tdvp == vp) 125253806Smckusick vrele(vp); 125353804Spendry else 125453806Smckusick vput(vp); 125553804Spendry return (EXDEV); 125653804Spendry } 125753804Spendry 125838414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 125953806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 126053806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 126153806Smckusick nfsm_fhtom(tdvp); 126253806Smckusick nfsm_fhtom(vp); 126353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 126453806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 126538414Smckusick nfsm_reqdone; 126653806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 126753806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 126853806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 126953806Smckusick vrele(vp); 127040112Smckusick /* 127140112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 127240112Smckusick */ 127340112Smckusick if (error == EEXIST) 127440112Smckusick error = 0; 127538414Smckusick return (error); 127638414Smckusick } 127738414Smckusick 127838414Smckusick /* 127938414Smckusick * nfs symbolic link create call 128038414Smckusick */ 128152234Sheideman /* start here */ 128252234Sheideman int 128353806Smckusick nfs_symlink(ap) 128454668Smckusick struct vop_symlink_args /* { 128554668Smckusick struct vnode *a_dvp; 128654668Smckusick struct vnode **a_vpp; 128754668Smckusick struct componentname *a_cnp; 128854668Smckusick struct vattr *a_vap; 128954668Smckusick char *a_target; 129054668Smckusick } */ *ap; 129138414Smckusick { 129253806Smckusick register struct vnode *dvp = ap->a_dvp; 129353806Smckusick register struct vattr *vap = ap->a_vap; 129453806Smckusick register struct componentname *cnp = ap->a_cnp; 129538884Smacklem register struct nfsv2_sattr *sp; 129648054Smckusick register u_long *tl; 129739488Smckusick register caddr_t cp; 129852196Smckusick register long t2; 129939488Smckusick caddr_t bpos, dpos; 130056289Smckusick int slen, error = 0, isnq; 130139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 130238414Smckusick 130338414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 130453600Sheideman slen = strlen(ap->a_target); 130556289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 130653806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 130756289Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq)); 130853806Smckusick nfsm_fhtom(dvp); 130953806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 131053600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 131156289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 131253806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 131353806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 131453806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 131556289Smckusick if (isnq) { 131656289Smckusick quad_t qval = -1; 131756289Smckusick 131856289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 131956289Smckusick sp->sa_nqflags = 0; 132056289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 132156289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 132256289Smckusick } else { 132356289Smckusick sp->sa_nfssize = -1; 132456289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 132556289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 132656289Smckusick } 132753806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 132838414Smckusick nfsm_reqdone; 132953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 133053806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 133153806Smckusick vrele(dvp); 133240112Smckusick /* 133340112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 133440112Smckusick */ 133540112Smckusick if (error == EEXIST) 133640112Smckusick error = 0; 133738414Smckusick return (error); 133838414Smckusick } 133938414Smckusick 134038414Smckusick /* 134138414Smckusick * nfs make dir call 134238414Smckusick */ 134352234Sheideman int 134453806Smckusick nfs_mkdir(ap) 134554668Smckusick struct vop_mkdir_args /* { 134654668Smckusick struct vnode *a_dvp; 134754668Smckusick struct vnode **a_vpp; 134854668Smckusick struct componentname *a_cnp; 134954668Smckusick struct vattr *a_vap; 135054668Smckusick } */ *ap; 135138414Smckusick { 135253806Smckusick register struct vnode *dvp = ap->a_dvp; 135353806Smckusick register struct vattr *vap = ap->a_vap; 135453806Smckusick register struct componentname *cnp = ap->a_cnp; 135554668Smckusick register struct vnode **vpp = ap->a_vpp; 135638884Smacklem register struct nfsv2_sattr *sp; 135748054Smckusick register u_long *tl; 135839488Smckusick register caddr_t cp; 135939488Smckusick register long t1, t2; 136041905Smckusick register int len; 136139488Smckusick caddr_t bpos, dpos, cp2; 136256289Smckusick int error = 0, firsttry = 1, isnq; 136339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 136438414Smckusick 136553806Smckusick len = cnp->cn_namelen; 136656289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 136738414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 136853806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 136956289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq)); 137053806Smckusick nfsm_fhtom(dvp); 137153806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 137256289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 137353806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 137453806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 137553806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 137656289Smckusick if (isnq) { 137756289Smckusick quad_t qval = -1; 137856289Smckusick 137956289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 138056289Smckusick sp->sa_nqflags = 0; 138156289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 138256289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 138356289Smckusick } else { 138456289Smckusick sp->sa_nfssize = -1; 138556289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 138656289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 138756289Smckusick } 138853806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 138954668Smckusick nfsm_mtofh(dvp, *vpp); 139038414Smckusick nfsm_reqdone; 139153806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 139240112Smckusick /* 139341905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 139441905Smckusick * if we can succeed in looking up the directory. 139541905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 139641905Smckusick * is above the if on errors. (Ugh) 139740112Smckusick */ 139841905Smckusick if (error == EEXIST && firsttry) { 139941905Smckusick firsttry = 0; 140040112Smckusick error = 0; 140141905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 140254668Smckusick *vpp = NULL; 140353806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 140441905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 140553806Smckusick nfsm_fhtom(dvp); 140653806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 140753806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 140854668Smckusick nfsm_mtofh(dvp, *vpp); 140954668Smckusick if ((*vpp)->v_type != VDIR) { 141054668Smckusick vput(*vpp); 141141905Smckusick error = EEXIST; 141241905Smckusick } 141341905Smckusick m_freem(mrep); 141441905Smckusick } 141553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 141653806Smckusick vrele(dvp); 141738414Smckusick return (error); 141838414Smckusick } 141938414Smckusick 142038414Smckusick /* 142138414Smckusick * nfs remove directory call 142238414Smckusick */ 142352234Sheideman int 142453806Smckusick nfs_rmdir(ap) 142554668Smckusick struct vop_rmdir_args /* { 142654668Smckusick struct vnode *a_dvp; 142754668Smckusick struct vnode *a_vp; 142854668Smckusick struct componentname *a_cnp; 142954668Smckusick } */ *ap; 143038414Smckusick { 143153806Smckusick register struct vnode *vp = ap->a_vp; 143253806Smckusick register struct vnode *dvp = ap->a_dvp; 143353806Smckusick register struct componentname *cnp = ap->a_cnp; 143448054Smckusick register u_long *tl; 143539488Smckusick register caddr_t cp; 143652196Smckusick register long t2; 143739488Smckusick caddr_t bpos, dpos; 143839488Smckusick int error = 0; 143939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 144038414Smckusick 144153806Smckusick if (dvp == vp) { 144253806Smckusick vrele(dvp); 144353806Smckusick vrele(dvp); 144453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 144538414Smckusick return (EINVAL); 144638414Smckusick } 144738414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 144853806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 144953806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 145053806Smckusick nfsm_fhtom(dvp); 145153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 145253806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 145338414Smckusick nfsm_reqdone; 145453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 145553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 145653806Smckusick cache_purge(dvp); 145753806Smckusick cache_purge(vp); 145853806Smckusick vrele(vp); 145953806Smckusick vrele(dvp); 146040112Smckusick /* 146140112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 146240112Smckusick */ 146340112Smckusick if (error == ENOENT) 146440112Smckusick error = 0; 146538414Smckusick return (error); 146638414Smckusick } 146738414Smckusick 146838414Smckusick /* 146938414Smckusick * nfs readdir call 147038414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 147138414Smckusick * order so that it looks more sensible. This appears consistent with the 147238414Smckusick * Ultrix implementation of NFS. 147338414Smckusick */ 147452234Sheideman int 147553806Smckusick nfs_readdir(ap) 147654668Smckusick struct vop_readdir_args /* { 147754668Smckusick struct vnode *a_vp; 147854668Smckusick struct uio *a_uio; 147954668Smckusick struct ucred *a_cred; 148054668Smckusick } */ *ap; 148138414Smckusick { 148253806Smckusick register struct vnode *vp = ap->a_vp; 148353806Smckusick register struct nfsnode *np = VTONFS(vp); 148453806Smckusick register struct uio *uio = ap->a_uio; 148541905Smckusick int tresid, error; 148641905Smckusick struct vattr vattr; 148741905Smckusick 148853806Smckusick if (vp->v_type != VDIR) 148941905Smckusick return (EPERM); 149041905Smckusick /* 149141905Smckusick * First, check for hit on the EOF offset cache 149241905Smckusick */ 149353806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 149452196Smckusick (np->n_flag & NMODIFIED) == 0) { 149553806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 149653806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 149752196Smckusick nfsstats.direofcache_hits++; 149852196Smckusick return (0); 149952196Smckusick } 150053806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 150154106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) { 150252196Smckusick nfsstats.direofcache_hits++; 150352196Smckusick return (0); 150452196Smckusick } 150541905Smckusick } 150641905Smckusick 150741905Smckusick /* 150841905Smckusick * Call nfs_bioread() to do the real work. 150941905Smckusick */ 151053806Smckusick tresid = uio->uio_resid; 151153806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 151241905Smckusick 151354451Smckusick if (!error && uio->uio_resid == tresid) 151441905Smckusick nfsstats.direofcache_misses++; 151541905Smckusick return (error); 151641905Smckusick } 151741905Smckusick 151841905Smckusick /* 151941905Smckusick * Readdir rpc call. 152041905Smckusick * Called from below the buffer cache by nfs_doio(). 152141905Smckusick */ 152252234Sheideman int 152348054Smckusick nfs_readdirrpc(vp, uiop, cred) 152441905Smckusick register struct vnode *vp; 152541905Smckusick struct uio *uiop; 152641905Smckusick struct ucred *cred; 152741905Smckusick { 152838414Smckusick register long len; 152954740Smckusick register struct dirent *dp; 153048054Smckusick register u_long *tl; 153139488Smckusick register caddr_t cp; 153239488Smckusick register long t1; 153341905Smckusick long tlen, lastlen; 153439488Smckusick caddr_t bpos, dpos, cp2; 153539488Smckusick int error = 0; 153639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 153738414Smckusick struct mbuf *md2; 153838414Smckusick caddr_t dpos2; 153938414Smckusick int siz; 154040296Smckusick int more_dirs = 1; 154156289Smckusick u_long off, savoff; 154254740Smckusick struct dirent *savdp; 154340296Smckusick struct nfsmount *nmp; 154440296Smckusick struct nfsnode *np = VTONFS(vp); 154540296Smckusick long tresid; 154638414Smckusick 154741398Smckusick nmp = VFSTONFS(vp->v_mount); 154840296Smckusick tresid = uiop->uio_resid; 154940296Smckusick /* 155040296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 155148054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 155241905Smckusick * The stopping criteria is EOF or buffer full. 155340296Smckusick */ 155448054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 155540296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 155652196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 155756289Smckusick NFSX_FH + 2 * NFSX_UNSIGNED); 155840296Smckusick nfsm_fhtom(vp); 155956289Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 156056289Smckusick off = (u_long)uiop->uio_offset; 156156289Smckusick *tl++ = txdr_unsigned(off); 156248054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 156348054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 156452196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 156540296Smckusick siz = 0; 156652196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 156748054Smckusick more_dirs = fxdr_unsigned(int, *tl); 156840296Smckusick 156940296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 157040296Smckusick dpos2 = dpos; 157140296Smckusick md2 = md; 157240296Smckusick 157340296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 157442246Smckusick #ifdef lint 157554740Smckusick dp = (struct dirent *)0; 157642246Smckusick #endif /* lint */ 157740296Smckusick while (more_dirs && siz < uiop->uio_resid) { 157840296Smckusick savoff = off; /* Hold onto offset and dp */ 157940296Smckusick savdp = dp; 158056289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 158154740Smckusick dp = (struct dirent *)tl; 158254740Smckusick dp->d_fileno = fxdr_unsigned(u_long, *tl++); 158348054Smckusick len = fxdr_unsigned(int, *tl); 158440296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 158540296Smckusick error = EBADRPC; 158640296Smckusick m_freem(mrep); 158740296Smckusick goto nfsmout; 158840296Smckusick } 158954986Smckusick dp->d_namlen = (u_char)len; 159054986Smckusick dp->d_type = DT_UNKNOWN; 159140296Smckusick nfsm_adv(len); /* Point past name */ 159240296Smckusick tlen = nfsm_rndup(len); 159340296Smckusick /* 159440296Smckusick * This should not be necessary, but some servers have 159540296Smckusick * broken XDR such that these bytes are not null filled. 159640296Smckusick */ 159740296Smckusick if (tlen != len) { 159840296Smckusick *dpos = '\0'; /* Null-terminate */ 159940296Smckusick nfsm_adv(tlen - len); 160040296Smckusick len = tlen; 160140296Smckusick } 160256289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 160354986Smckusick off = fxdr_unsigned(u_long, *tl); 160448054Smckusick *tl++ = 0; /* Ensures null termination of name */ 160548054Smckusick more_dirs = fxdr_unsigned(int, *tl); 160656289Smckusick dp->d_reclen = len + 4 * NFSX_UNSIGNED; 160740296Smckusick siz += dp->d_reclen; 160840296Smckusick } 160940296Smckusick /* 161040296Smckusick * If at end of rpc data, get the eof boolean 161140296Smckusick */ 161240296Smckusick if (!more_dirs) { 161352196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 161448054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 161538414Smckusick 161640296Smckusick /* 161740296Smckusick * If at EOF, cache directory offset 161840296Smckusick */ 161941905Smckusick if (!more_dirs) 162040296Smckusick np->n_direofoffset = off; 162138414Smckusick } 162240296Smckusick /* 162340296Smckusick * If there is too much to fit in the data buffer, use savoff and 162440296Smckusick * savdp to trim off the last record. 162540296Smckusick * --> we are not at eof 162640296Smckusick */ 162740296Smckusick if (siz > uiop->uio_resid) { 162840296Smckusick off = savoff; 162940296Smckusick siz -= dp->d_reclen; 163040296Smckusick dp = savdp; 163140296Smckusick more_dirs = 0; /* Paranoia */ 163240113Smckusick } 163340296Smckusick if (siz > 0) { 163441905Smckusick lastlen = dp->d_reclen; 163540296Smckusick md = md2; 163640296Smckusick dpos = dpos2; 163740296Smckusick nfsm_mtouio(uiop, siz); 163856289Smckusick uiop->uio_offset = (off_t)off; 163940296Smckusick } else 164040296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 164140296Smckusick m_freem(mrep); 164238414Smckusick } 164341905Smckusick /* 164448054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 164541905Smckusick * by increasing d_reclen for the last record. 164641905Smckusick */ 164741905Smckusick if (uiop->uio_resid < tresid) { 164848054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 164941905Smckusick if (len > 0) { 165054740Smckusick dp = (struct dirent *) 165141905Smckusick (uiop->uio_iov->iov_base - lastlen); 165241905Smckusick dp->d_reclen += len; 165341905Smckusick uiop->uio_iov->iov_base += len; 165441905Smckusick uiop->uio_iov->iov_len -= len; 165541905Smckusick uiop->uio_resid -= len; 165641905Smckusick } 165741905Smckusick } 165840296Smckusick nfsmout: 165938414Smckusick return (error); 166038414Smckusick } 166138414Smckusick 166252196Smckusick /* 166356289Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc(). 166452196Smckusick */ 166552234Sheideman int 166652196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 166752196Smckusick struct vnode *vp; 166852196Smckusick register struct uio *uiop; 166952196Smckusick struct ucred *cred; 167052196Smckusick { 167152196Smckusick register int len; 167254740Smckusick register struct dirent *dp; 167352196Smckusick register u_long *tl; 167452196Smckusick register caddr_t cp; 167552196Smckusick register long t1; 167652196Smckusick caddr_t bpos, dpos, cp2; 167752196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 167852196Smckusick struct nameidata nami, *ndp = &nami; 167952317Sheideman struct componentname *cnp = &ndp->ni_cnd; 168056289Smckusick u_long off, endoff, fileno; 168152196Smckusick time_t reqtime, ltime; 168252196Smckusick struct nfsmount *nmp; 168352196Smckusick struct nfsnode *np, *tp; 168452196Smckusick struct vnode *newvp; 168552196Smckusick nfsv2fh_t *fhp; 168652196Smckusick u_quad_t frev; 168752196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 168852196Smckusick int cachable; 168952196Smckusick 169052196Smckusick if (uiop->uio_iovcnt != 1) 169152196Smckusick panic("nfs rdirlook"); 169252196Smckusick nmp = VFSTONFS(vp->v_mount); 169352196Smckusick tresid = uiop->uio_resid; 169452196Smckusick ndp->ni_dvp = vp; 169552196Smckusick newvp = NULLVP; 169652196Smckusick /* 169752196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 169852196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 169952196Smckusick * The stopping criteria is EOF or buffer full. 170052196Smckusick */ 170152196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 170252196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 170352196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 170456289Smckusick NFSX_FH + 3 * NFSX_UNSIGNED); 170552196Smckusick nfsm_fhtom(vp); 170656289Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 170756289Smckusick off = (u_long)uiop->uio_offset; 170856289Smckusick *tl++ = txdr_unsigned(off); 170952196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 171052196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 171156289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) 171256289Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 171356289Smckusick else 171456289Smckusick *tl = 0; 171552196Smckusick reqtime = time.tv_sec; 171652196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 171752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 171852196Smckusick more_dirs = fxdr_unsigned(int, *tl); 171952196Smckusick 172052196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 172152196Smckusick bigenough = 1; 172252196Smckusick while (more_dirs && bigenough) { 172352196Smckusick doit = 1; 172456289Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 172556289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) { 172656289Smckusick cachable = fxdr_unsigned(int, *tl++); 172756289Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 172856289Smckusick fxdr_hyper(tl, &frev); 172956289Smckusick } 173052196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 173152196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 173252196Smckusick VREF(vp); 173352196Smckusick newvp = vp; 173452196Smckusick np = VTONFS(vp); 173552196Smckusick } else { 173652196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 173752196Smckusick doit = 0; 173852196Smckusick newvp = NFSTOV(np); 173952196Smckusick } 174052196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 174152196Smckusick (struct vattr *)0)) 174252196Smckusick doit = 0; 174356289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 174452196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 174552196Smckusick len = fxdr_unsigned(int, *tl); 174652196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 174752196Smckusick error = EBADRPC; 174852196Smckusick m_freem(mrep); 174952196Smckusick goto nfsmout; 175052196Smckusick } 175152196Smckusick tlen = (len + 4) & ~0x3; 175252196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 175352196Smckusick bigenough = 0; 175452196Smckusick if (bigenough && doit) { 175554740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base; 175654740Smckusick dp->d_fileno = fileno; 175752196Smckusick dp->d_namlen = len; 175852196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 175954986Smckusick dp->d_type = 176054986Smckusick IFTODT(VTTOIF(np->n_vattr.va_type)); 176152196Smckusick uiop->uio_resid -= DIRHDSIZ; 176252196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 176352196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 176452317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 176552317Sheideman cnp->cn_namelen = len; 176652196Smckusick ndp->ni_vp = newvp; 176752196Smckusick nfsm_mtouio(uiop, len); 176852196Smckusick cp = uiop->uio_iov->iov_base; 176952196Smckusick tlen -= len; 177052196Smckusick for (i = 0; i < tlen; i++) 177152196Smckusick *cp++ = '\0'; 177252196Smckusick uiop->uio_iov->iov_base += tlen; 177352196Smckusick uiop->uio_iov->iov_len -= tlen; 177452196Smckusick uiop->uio_resid -= tlen; 177552317Sheideman cnp->cn_hash = 0; 177652317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 177752317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 177856289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 177956289Smckusick ltime > time.tv_sec) 178056289Smckusick nqnfs_clientlease(nmp, np, NQL_READ, 178156289Smckusick cachable, ltime, frev); 178256927Smckusick if (cnp->cn_namelen <= NCHNAMLEN) 1783*57791Smckusick cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 178452196Smckusick } else { 178552196Smckusick nfsm_adv(nfsm_rndup(len)); 178652196Smckusick } 178752196Smckusick if (newvp != NULLVP) { 178852196Smckusick vrele(newvp); 178952196Smckusick newvp = NULLVP; 179052196Smckusick } 179156289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 179252196Smckusick if (bigenough) 179356289Smckusick endoff = off = fxdr_unsigned(u_long, *tl++); 179452196Smckusick else 179556289Smckusick endoff = fxdr_unsigned(u_long, *tl++); 179652196Smckusick more_dirs = fxdr_unsigned(int, *tl); 179752196Smckusick } 179852196Smckusick /* 179952196Smckusick * If at end of rpc data, get the eof boolean 180052196Smckusick */ 180152196Smckusick if (!more_dirs) { 180252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 180352196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 180452196Smckusick 180552196Smckusick /* 180652196Smckusick * If at EOF, cache directory offset 180752196Smckusick */ 180852196Smckusick if (!more_dirs) 180952196Smckusick VTONFS(vp)->n_direofoffset = endoff; 181052196Smckusick } 181152196Smckusick if (uiop->uio_resid < tresid) 181256289Smckusick uiop->uio_offset = (off_t)off; 181352196Smckusick else 181452196Smckusick more_dirs = 0; 181552196Smckusick m_freem(mrep); 181652196Smckusick } 181752196Smckusick /* 181852196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 181952196Smckusick * by increasing d_reclen for the last record. 182052196Smckusick */ 182152196Smckusick if (uiop->uio_resid < tresid) { 182252196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 182352196Smckusick if (len > 0) { 182452196Smckusick dp->d_reclen += len; 182552196Smckusick uiop->uio_iov->iov_base += len; 182652196Smckusick uiop->uio_iov->iov_len -= len; 182752196Smckusick uiop->uio_resid -= len; 182852196Smckusick } 182952196Smckusick } 183052196Smckusick nfsmout: 183152196Smckusick if (newvp != NULLVP) 183252196Smckusick vrele(newvp); 183352196Smckusick return (error); 183452196Smckusick } 183539488Smckusick static char hextoasc[] = "0123456789abcdef"; 183638414Smckusick 183738414Smckusick /* 183838414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 183938414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 184038414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 184138414Smckusick * nfsnode. There is the potential for another process on a different client 184238414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 184338414Smckusick * nfs_rename() completes, but... 184438414Smckusick */ 184552234Sheideman int 184652317Sheideman nfs_sillyrename(dvp, vp, cnp) 184752234Sheideman struct vnode *dvp, *vp; 184852234Sheideman struct componentname *cnp; 184938414Smckusick { 185038414Smckusick register struct nfsnode *np; 185138414Smckusick register struct sillyrename *sp; 185238414Smckusick int error; 185338414Smckusick short pid; 185438414Smckusick 185552234Sheideman cache_purge(dvp); 185652234Sheideman np = VTONFS(vp); 185751986Smckusick #ifdef SILLYSEPARATE 185838414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 185948364Smckusick M_NFSREQ, M_WAITOK); 186051986Smckusick #else 186151986Smckusick sp = &np->n_silly; 186251986Smckusick #endif 186352234Sheideman sp->s_cred = crdup(cnp->cn_cred); 186452234Sheideman sp->s_dvp = dvp; 186552234Sheideman VREF(dvp); 186638414Smckusick 186738414Smckusick /* Fudge together a funny name */ 186852234Sheideman pid = cnp->cn_proc->p_pid; 186948364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 187048364Smckusick sp->s_namlen = 12; 187148364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 187248364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 187348364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 187448364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 187538414Smckusick 187638414Smckusick /* Try lookitups until we get one that isn't there */ 187752234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 187848364Smckusick sp->s_name[4]++; 187948364Smckusick if (sp->s_name[4] > 'z') { 188038414Smckusick error = EINVAL; 188138414Smckusick goto bad; 188238414Smckusick } 188338414Smckusick } 188452234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 188538414Smckusick goto bad; 188652234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 188738414Smckusick np->n_sillyrename = sp; 188838414Smckusick return (0); 188938414Smckusick bad: 189048364Smckusick vrele(sp->s_dvp); 189148364Smckusick crfree(sp->s_cred); 189251986Smckusick #ifdef SILLYSEPARATE 189348364Smckusick free((caddr_t)sp, M_NFSREQ); 189451986Smckusick #endif 189538414Smckusick return (error); 189638414Smckusick } 189738414Smckusick 189838414Smckusick /* 189938414Smckusick * Look up a file name for silly rename stuff. 190038414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 190138414Smckusick * into the nfsnode table. 190238414Smckusick * If fhp != NULL it copies the returned file handle out 190338414Smckusick */ 190452234Sheideman int 190552196Smckusick nfs_lookitup(sp, fhp, procp) 190648364Smckusick register struct sillyrename *sp; 190738414Smckusick nfsv2fh_t *fhp; 190852196Smckusick struct proc *procp; 190938414Smckusick { 191048364Smckusick register struct vnode *vp = sp->s_dvp; 191148054Smckusick register u_long *tl; 191239488Smckusick register caddr_t cp; 191339488Smckusick register long t1, t2; 191439488Smckusick caddr_t bpos, dpos, cp2; 191539488Smckusick u_long xid; 191656289Smckusick int error = 0, isnq; 191739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 191838414Smckusick long len; 191938414Smckusick 192056289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 192138414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 192248364Smckusick len = sp->s_namlen; 192352196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 192456289Smckusick if (isnq) { 192556289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 192656289Smckusick *tl = 0; 192756289Smckusick } 192838414Smckusick nfsm_fhtom(vp); 192948364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 193052196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 193138414Smckusick if (fhp != NULL) { 193256289Smckusick if (isnq) 193356289Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 193452196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 193538414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 193638414Smckusick } 193738414Smckusick nfsm_reqdone; 193838414Smckusick return (error); 193938414Smckusick } 194038414Smckusick 194138414Smckusick /* 194238414Smckusick * Kludge City.. 194338414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 194441905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 194538414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 194638414Smckusick * nfsiobuf area. 194738414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 194838414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 194938414Smckusick * a lot more work than bcopy() and also it currently happens in the 195038414Smckusick * context of the swapper process (2). 195138414Smckusick */ 195252234Sheideman int 195353806Smckusick nfs_bmap(ap) 195454668Smckusick struct vop_bmap_args /* { 195554668Smckusick struct vnode *a_vp; 195654668Smckusick daddr_t a_bn; 195754668Smckusick struct vnode **a_vpp; 195854668Smckusick daddr_t *a_bnp; 195956452Smargo int *a_runp; 196054668Smckusick } */ *ap; 196138414Smckusick { 196253806Smckusick register struct vnode *vp = ap->a_vp; 196353806Smckusick 196453600Sheideman if (ap->a_vpp != NULL) 196553806Smckusick *ap->a_vpp = vp; 196653600Sheideman if (ap->a_bnp != NULL) 196753806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 196838414Smckusick return (0); 196938414Smckusick } 197038414Smckusick 197138414Smckusick /* 1972*57791Smckusick * Strategy routine. 1973*57791Smckusick * For async requests when nfsiod(s) are running, queue the request by 1974*57791Smckusick * calling nfs_asyncio(), otherwise just all nfs_doio() to do the 1975*57791Smckusick * request. 197638414Smckusick */ 197752234Sheideman int 197853806Smckusick nfs_strategy(ap) 1979*57791Smckusick struct vop_strategy_args *ap; 198038414Smckusick { 198153806Smckusick register struct buf *bp = ap->a_bp; 1982*57791Smckusick struct ucred *cr; 1983*57791Smckusick struct proc *p; 198438884Smacklem int error = 0; 198538884Smacklem 1986*57791Smckusick if (bp->b_flags & B_PHYS) 1987*57791Smckusick panic("nfs physio"); 1988*57791Smckusick if (bp->b_flags & B_ASYNC) 1989*57791Smckusick p = (struct proc *)0; 1990*57791Smckusick else 1991*57791Smckusick p = curproc; /* XXX */ 1992*57791Smckusick if (bp->b_flags & B_READ) 1993*57791Smckusick cr = bp->b_rcred; 1994*57791Smckusick else 1995*57791Smckusick cr = bp->b_wcred; 199638884Smacklem /* 199746450Skarels * If the op is asynchronous and an i/o daemon is waiting 199838884Smacklem * queue the request, wake it up and wait for completion 199946450Skarels * otherwise just do it ourselves. 200038884Smacklem */ 2001*57791Smckusick if ((bp->b_flags & B_ASYNC) == 0 || 2002*57791Smckusick nfs_asyncio(bp, NOCRED)) 2003*57791Smckusick error = nfs_doio(bp, cr, p); 200438884Smacklem return (error); 200538884Smacklem } 200638884Smacklem 200738884Smacklem /* 200848054Smckusick * Mmap a file 200948054Smckusick * 201048054Smckusick * NB Currently unsupported. 201148054Smckusick */ 201248054Smckusick /* ARGSUSED */ 201352234Sheideman int 201453806Smckusick nfs_mmap(ap) 201554668Smckusick struct vop_mmap_args /* { 201654668Smckusick struct vnode *a_vp; 201754668Smckusick int a_fflags; 201854668Smckusick struct ucred *a_cred; 201954668Smckusick struct proc *a_p; 202054668Smckusick } */ *ap; 202148054Smckusick { 202248054Smckusick 202348054Smckusick return (EINVAL); 202448054Smckusick } 202548054Smckusick 202648054Smckusick /* 202738884Smacklem * Flush all the blocks associated with a vnode. 202838884Smacklem * Walk through the buffer pool and push any dirty pages 202938884Smacklem * associated with the vnode. 203038884Smacklem */ 203139488Smckusick /* ARGSUSED */ 203252234Sheideman int 203353806Smckusick nfs_fsync(ap) 203454451Smckusick struct vop_fsync_args /* { 203554451Smckusick struct vnodeop_desc *a_desc; 203654451Smckusick struct vnode * a_vp; 203754451Smckusick struct ucred * a_cred; 203854451Smckusick int a_waitfor; 203954451Smckusick struct proc * a_p; 204054451Smckusick } */ *ap; 204138884Smacklem { 204254451Smckusick register struct vnode *vp = ap->a_vp; 204354451Smckusick register struct nfsnode *np = VTONFS(vp); 204454451Smckusick register struct buf *bp; 204554451Smckusick struct buf *nbp; 2046*57791Smckusick struct nfsmount *nmp; 2047*57791Smckusick int s, error = 0, slptimeo = 0, slpflag = 0; 204838884Smacklem 2049*57791Smckusick nmp = VFSTONFS(vp->v_mount); 2050*57791Smckusick if (nmp->nm_flag & NFSMNT_INT) 2051*57791Smckusick slpflag = PCATCH; 205254451Smckusick loop: 205354451Smckusick s = splbio(); 205456468Smckusick for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) { 205556468Smckusick nbp = bp->b_vnbufs.qe_next; 2056*57791Smckusick if (bp->b_flags & B_BUSY) { 2057*57791Smckusick if (ap->a_waitfor != MNT_WAIT) 2058*57791Smckusick continue; 2059*57791Smckusick bp->b_flags |= B_WANTED; 2060*57791Smckusick error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), 2061*57791Smckusick "nfsfsync", slptimeo); 2062*57791Smckusick splx(s); 2063*57791Smckusick if (error) { 2064*57791Smckusick if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p)) 2065*57791Smckusick return (EINTR); 2066*57791Smckusick if (slpflag == PCATCH) { 2067*57791Smckusick slpflag = 0; 2068*57791Smckusick slptimeo = 2 * hz; 2069*57791Smckusick } 2070*57791Smckusick } 2071*57791Smckusick goto loop; 2072*57791Smckusick } 207354451Smckusick if ((bp->b_flags & B_DELWRI) == 0) 207454451Smckusick panic("nfs_fsync: not dirty"); 207554451Smckusick bremfree(bp); 207654451Smckusick bp->b_flags |= B_BUSY; 207754451Smckusick splx(s); 2078*57791Smckusick bp->b_flags |= B_ASYNC; 2079*57791Smckusick VOP_BWRITE(bp); 208054451Smckusick goto loop; 208138884Smacklem } 2082*57791Smckusick splx(s); 208354451Smckusick if (ap->a_waitfor == MNT_WAIT) { 208454451Smckusick while (vp->v_numoutput) { 208554451Smckusick vp->v_flag |= VBWAIT; 2086*57791Smckusick error = tsleep((caddr_t)&vp->v_numoutput, 2087*57791Smckusick slpflag | (PRIBIO + 1), "nfsfsync", slptimeo); 2088*57791Smckusick if (error) { 2089*57791Smckusick if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p)) 2090*57791Smckusick return (EINTR); 2091*57791Smckusick if (slpflag == PCATCH) { 2092*57791Smckusick slpflag = 0; 2093*57791Smckusick slptimeo = 2 * hz; 2094*57791Smckusick } 2095*57791Smckusick } 209654451Smckusick } 2097*57791Smckusick if (vp->v_dirtyblkhd.le_next) { 209854451Smckusick #ifdef DIAGNOSTIC 209954451Smckusick vprint("nfs_fsync: dirty", vp); 2100*57791Smckusick #endif 210154451Smckusick goto loop; 210254451Smckusick } 210354451Smckusick } 210453629Smckusick if (np->n_flag & NWRITEERR) { 210539751Smckusick error = np->n_error; 210653629Smckusick np->n_flag &= ~NWRITEERR; 210753629Smckusick } 210838884Smacklem return (error); 210938884Smacklem } 211039672Smckusick 211139672Smckusick /* 211246201Smckusick * NFS advisory byte-level locks. 211346201Smckusick * Currently unsupported. 211446201Smckusick */ 211552234Sheideman int 211653806Smckusick nfs_advlock(ap) 211754668Smckusick struct vop_advlock_args /* { 211854668Smckusick struct vnode *a_vp; 211954668Smckusick caddr_t a_id; 212054668Smckusick int a_op; 212154668Smckusick struct flock *a_fl; 212254668Smckusick int a_flags; 212354668Smckusick } */ *ap; 212446201Smckusick { 212546201Smckusick 212646201Smckusick return (EOPNOTSUPP); 212746201Smckusick } 212846201Smckusick 212946201Smckusick /* 213039672Smckusick * Print out the contents of an nfsnode. 213139672Smckusick */ 213252234Sheideman int 213353806Smckusick nfs_print(ap) 213454668Smckusick struct vop_print_args /* { 213554668Smckusick struct vnode *a_vp; 213654668Smckusick } */ *ap; 213739672Smckusick { 213853806Smckusick register struct vnode *vp = ap->a_vp; 213953806Smckusick register struct nfsnode *np = VTONFS(vp); 214039672Smckusick 214140294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 214240294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 214340294Smckusick #ifdef FIFO 214453806Smckusick if (vp->v_type == VFIFO) 214553806Smckusick fifo_printinfo(vp); 214640294Smckusick #endif /* FIFO */ 214739914Smckusick printf("\n"); 214839672Smckusick } 214951573Smckusick 215051573Smckusick /* 215151573Smckusick * NFS directory offset lookup. 215251573Smckusick * Currently unsupported. 215351573Smckusick */ 215452234Sheideman int 215553806Smckusick nfs_blkatoff(ap) 215654668Smckusick struct vop_blkatoff_args /* { 215754668Smckusick struct vnode *a_vp; 215854668Smckusick off_t a_offset; 215954668Smckusick char **a_res; 216054668Smckusick struct buf **a_bpp; 216154668Smckusick } */ *ap; 216251573Smckusick { 216351573Smckusick 216451573Smckusick return (EOPNOTSUPP); 216551573Smckusick } 216651573Smckusick 216751573Smckusick /* 216851573Smckusick * NFS flat namespace allocation. 216951573Smckusick * Currently unsupported. 217051573Smckusick */ 217152234Sheideman int 217253806Smckusick nfs_valloc(ap) 217354668Smckusick struct vop_valloc_args /* { 217454668Smckusick struct vnode *a_pvp; 217554668Smckusick int a_mode; 217654668Smckusick struct ucred *a_cred; 217754668Smckusick struct vnode **a_vpp; 217854668Smckusick } */ *ap; 217951573Smckusick { 218051573Smckusick 218151573Smckusick return (EOPNOTSUPP); 218251573Smckusick } 218351573Smckusick 218451573Smckusick /* 218551573Smckusick * NFS flat namespace free. 218651573Smckusick * Currently unsupported. 218751573Smckusick */ 218853582Sheideman int 218953806Smckusick nfs_vfree(ap) 219054668Smckusick struct vop_vfree_args /* { 219154668Smckusick struct vnode *a_pvp; 219254668Smckusick ino_t a_ino; 219354668Smckusick int a_mode; 219454668Smckusick } */ *ap; 219551573Smckusick { 219651573Smckusick 219753582Sheideman return (EOPNOTSUPP); 219851573Smckusick } 219951573Smckusick 220051573Smckusick /* 220151573Smckusick * NFS file truncation. 220251573Smckusick */ 220352234Sheideman int 220453806Smckusick nfs_truncate(ap) 220554668Smckusick struct vop_truncate_args /* { 220654668Smckusick struct vnode *a_vp; 220754668Smckusick off_t a_length; 220854668Smckusick int a_flags; 220954668Smckusick struct ucred *a_cred; 221054668Smckusick struct proc *a_p; 221154668Smckusick } */ *ap; 221251573Smckusick { 221351573Smckusick 221451573Smckusick /* Use nfs_setattr */ 221551573Smckusick printf("nfs_truncate: need to implement!!"); 221651573Smckusick return (EOPNOTSUPP); 221751573Smckusick } 221851573Smckusick 221951573Smckusick /* 222051573Smckusick * NFS update. 222151573Smckusick */ 222252234Sheideman int 222353806Smckusick nfs_update(ap) 222454668Smckusick struct vop_update_args /* { 222554668Smckusick struct vnode *a_vp; 222654668Smckusick struct timeval *a_ta; 222754668Smckusick struct timeval *a_tm; 222854668Smckusick int a_waitfor; 222954668Smckusick } */ *ap; 223051573Smckusick { 223151573Smckusick 223251573Smckusick /* Use nfs_setattr */ 223351573Smckusick printf("nfs_update: need to implement!!"); 223451573Smckusick return (EOPNOTSUPP); 223551573Smckusick } 223653629Smckusick 223753629Smckusick /* 223856364Smckusick * nfs special file access vnode op. 223956364Smckusick * Essentially just get vattr and then imitate iaccess() since the device is 224056364Smckusick * local to the client. 224156364Smckusick */ 224256364Smckusick int 224356364Smckusick nfsspec_access(ap) 224456364Smckusick struct vop_access_args /* { 224556364Smckusick struct vnode *a_vp; 224656364Smckusick int a_mode; 224756364Smckusick struct ucred *a_cred; 224856364Smckusick struct proc *a_p; 224956364Smckusick } */ *ap; 225056364Smckusick { 225156364Smckusick register struct vattr *vap; 225256364Smckusick register gid_t *gp; 225356364Smckusick register struct ucred *cred = ap->a_cred; 225456364Smckusick mode_t mode = ap->a_mode; 225556364Smckusick struct vattr vattr; 225656364Smckusick register int i; 225756364Smckusick int error; 225856364Smckusick 225956364Smckusick /* 226056364Smckusick * If you're the super-user, 226156364Smckusick * you always get access. 226256364Smckusick */ 226356364Smckusick if (cred->cr_uid == 0) 226456364Smckusick return (0); 226556364Smckusick vap = &vattr; 226656364Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 226756364Smckusick return (error); 226856364Smckusick /* 226956364Smckusick * Access check is based on only one of owner, group, public. 227056364Smckusick * If not owner, then check group. If not a member of the 227156364Smckusick * group, then check public access. 227256364Smckusick */ 227356364Smckusick if (cred->cr_uid != vap->va_uid) { 227456364Smckusick mode >>= 3; 227556364Smckusick gp = cred->cr_groups; 227656364Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 227756364Smckusick if (vap->va_gid == *gp) 227856364Smckusick goto found; 227956364Smckusick mode >>= 3; 228056364Smckusick found: 228156364Smckusick ; 228256364Smckusick } 228356708Smckusick return ((vap->va_mode & mode) == mode ? 0 : EACCES); 228456364Smckusick } 228556364Smckusick 228656364Smckusick /* 228753629Smckusick * Read wrapper for special devices. 228853629Smckusick */ 228953629Smckusick int 229053629Smckusick nfsspec_read(ap) 229154668Smckusick struct vop_read_args /* { 229254668Smckusick struct vnode *a_vp; 229354668Smckusick struct uio *a_uio; 229454668Smckusick int a_ioflag; 229554668Smckusick struct ucred *a_cred; 229654668Smckusick } */ *ap; 229753629Smckusick { 229854032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 229953629Smckusick 230053629Smckusick /* 230153629Smckusick * Set access flag. 230253629Smckusick */ 230354032Smckusick np->n_flag |= NACC; 230454032Smckusick np->n_atim = time; 230553629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 230653629Smckusick } 230753629Smckusick 230853629Smckusick /* 230953629Smckusick * Write wrapper for special devices. 231053629Smckusick */ 231153629Smckusick int 231253629Smckusick nfsspec_write(ap) 231354668Smckusick struct vop_write_args /* { 231454668Smckusick struct vnode *a_vp; 231554668Smckusick struct uio *a_uio; 231654668Smckusick int a_ioflag; 231754668Smckusick struct ucred *a_cred; 231854668Smckusick } */ *ap; 231953629Smckusick { 232054032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 232153629Smckusick 232253629Smckusick /* 232354032Smckusick * Set update flag. 232453629Smckusick */ 232554032Smckusick np->n_flag |= NUPD; 232654032Smckusick np->n_mtim = time; 232753629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 232853629Smckusick } 232953629Smckusick 233053629Smckusick /* 233153629Smckusick * Close wrapper for special devices. 233253629Smckusick * 233353629Smckusick * Update the times on the nfsnode then do device close. 233453629Smckusick */ 233553629Smckusick int 233653629Smckusick nfsspec_close(ap) 233754668Smckusick struct vop_close_args /* { 233854668Smckusick struct vnode *a_vp; 233954668Smckusick int a_fflag; 234054668Smckusick struct ucred *a_cred; 234154668Smckusick struct proc *a_p; 234254668Smckusick } */ *ap; 234353629Smckusick { 234453806Smckusick register struct vnode *vp = ap->a_vp; 234553806Smckusick register struct nfsnode *np = VTONFS(vp); 234653629Smckusick struct vattr vattr; 234753629Smckusick 234853629Smckusick if (np->n_flag & (NACC | NUPD)) { 234953629Smckusick np->n_flag |= NCHG; 235053806Smckusick if (vp->v_usecount == 1 && 235153806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 235253629Smckusick VATTR_NULL(&vattr); 235354106Smckusick if (np->n_flag & NACC) { 235454106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 235554106Smckusick vattr.va_atime.ts_nsec = 235654106Smckusick np->n_atim.tv_usec * 1000; 235754106Smckusick } 235854106Smckusick if (np->n_flag & NUPD) { 235954106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 236054106Smckusick vattr.va_mtime.ts_nsec = 236154106Smckusick np->n_mtim.tv_usec * 1000; 236254106Smckusick } 236353806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 236453629Smckusick } 236553629Smckusick } 236653629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 236753629Smckusick } 236853629Smckusick 236953629Smckusick #ifdef FIFO 237053629Smckusick /* 237153629Smckusick * Read wrapper for fifos. 237253629Smckusick */ 237353629Smckusick int 237453629Smckusick nfsfifo_read(ap) 237554668Smckusick struct vop_read_args /* { 237654668Smckusick struct vnode *a_vp; 237754668Smckusick struct uio *a_uio; 237854668Smckusick int a_ioflag; 237954668Smckusick struct ucred *a_cred; 238054668Smckusick } */ *ap; 238153629Smckusick { 238253629Smckusick extern int (**fifo_vnodeop_p)(); 238354032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 238453629Smckusick 238553629Smckusick /* 238653629Smckusick * Set access flag. 238753629Smckusick */ 238854032Smckusick np->n_flag |= NACC; 238954032Smckusick np->n_atim = time; 239053629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 239153629Smckusick } 239253629Smckusick 239353629Smckusick /* 239453629Smckusick * Write wrapper for fifos. 239553629Smckusick */ 239653629Smckusick int 239753629Smckusick nfsfifo_write(ap) 239854668Smckusick struct vop_write_args /* { 239954668Smckusick struct vnode *a_vp; 240054668Smckusick struct uio *a_uio; 240154668Smckusick int a_ioflag; 240254668Smckusick struct ucred *a_cred; 240354668Smckusick } */ *ap; 240453629Smckusick { 240553629Smckusick extern int (**fifo_vnodeop_p)(); 240654032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 240753629Smckusick 240853629Smckusick /* 240953629Smckusick * Set update flag. 241053629Smckusick */ 241154032Smckusick np->n_flag |= NUPD; 241254032Smckusick np->n_mtim = time; 241353629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 241453629Smckusick } 241553629Smckusick 241653629Smckusick /* 241753629Smckusick * Close wrapper for fifos. 241853629Smckusick * 241953629Smckusick * Update the times on the nfsnode then do fifo close. 242053629Smckusick */ 242153629Smckusick int 242253629Smckusick nfsfifo_close(ap) 242354668Smckusick struct vop_close_args /* { 242454668Smckusick struct vnode *a_vp; 242554668Smckusick int a_fflag; 242654668Smckusick struct ucred *a_cred; 242754668Smckusick struct proc *a_p; 242854668Smckusick } */ *ap; 242953629Smckusick { 243053806Smckusick register struct vnode *vp = ap->a_vp; 243153806Smckusick register struct nfsnode *np = VTONFS(vp); 243253629Smckusick struct vattr vattr; 243353629Smckusick extern int (**fifo_vnodeop_p)(); 243453629Smckusick 243553629Smckusick if (np->n_flag & (NACC | NUPD)) { 243653629Smckusick if (np->n_flag & NACC) 243753629Smckusick np->n_atim = time; 243853629Smckusick if (np->n_flag & NUPD) 243953629Smckusick np->n_mtim = time; 244053629Smckusick np->n_flag |= NCHG; 244153806Smckusick if (vp->v_usecount == 1 && 244253806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 244353629Smckusick VATTR_NULL(&vattr); 244454106Smckusick if (np->n_flag & NACC) { 244554106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 244654106Smckusick vattr.va_atime.ts_nsec = 244754106Smckusick np->n_atim.tv_usec * 1000; 244854106Smckusick } 244954106Smckusick if (np->n_flag & NUPD) { 245054106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 245154106Smckusick vattr.va_mtime.ts_nsec = 245254106Smckusick np->n_mtim.tv_usec * 1000; 245354106Smckusick } 245453806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 245553629Smckusick } 245653629Smckusick } 245753629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 245853629Smckusick } 245953629Smckusick #endif /* FIFO */ 2460