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*60400Smckusick * @(#)nfs_vnops.c 7.107 (Berkeley) 05/25/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 */ 87*60400Smckusick { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */ 8853806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8953806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 9053806Smckusick { &vop_valloc_desc, nfs_valloc }, /* valloc */ 9153554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */ 9253806Smckusick { &vop_truncate_desc, nfs_truncate }, /* truncate */ 9353806Smckusick { &vop_update_desc, nfs_update }, /* update */ 9457809Smckusick { &vop_bwrite_desc, vn_bwrite }, 9553554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 9638414Smckusick }; 9753554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 9853554Sheideman { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 9938414Smckusick 10048054Smckusick /* 10148054Smckusick * Special device vnode ops 10248054Smckusick */ 10353554Sheideman int (**spec_nfsv2nodeop_p)(); 10453554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 10553554Sheideman { &vop_default_desc, vn_default_error }, 10653806Smckusick { &vop_lookup_desc, spec_lookup }, /* lookup */ 10753806Smckusick { &vop_create_desc, spec_create }, /* create */ 10853806Smckusick { &vop_mknod_desc, spec_mknod }, /* mknod */ 10953554Sheideman { &vop_open_desc, spec_open }, /* open */ 11053806Smckusick { &vop_close_desc, nfsspec_close }, /* close */ 11156364Smckusick { &vop_access_desc, nfsspec_access }, /* access */ 11253806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 11353806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 11453806Smckusick { &vop_read_desc, nfsspec_read }, /* read */ 11553806Smckusick { &vop_write_desc, nfsspec_write }, /* write */ 11653806Smckusick { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 11753806Smckusick { &vop_select_desc, spec_select }, /* select */ 11853554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 11954451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 12053554Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 12153806Smckusick { &vop_remove_desc, spec_remove }, /* remove */ 12253554Sheideman { &vop_link_desc, spec_link }, /* link */ 12353806Smckusick { &vop_rename_desc, spec_rename }, /* rename */ 12453806Smckusick { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 12553806Smckusick { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 12653806Smckusick { &vop_symlink_desc, spec_symlink }, /* symlink */ 12753806Smckusick { &vop_readdir_desc, spec_readdir }, /* readdir */ 12853806Smckusick { &vop_readlink_desc, spec_readlink }, /* readlink */ 12953806Smckusick { &vop_abortop_desc, spec_abortop }, /* abortop */ 13053806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 13153806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 13253554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 13353806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 13453554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 13553806Smckusick { &vop_strategy_desc, spec_strategy }, /* strategy */ 13653554Sheideman { &vop_print_desc, nfs_print }, /* print */ 13753806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 138*60400Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 13953806Smckusick { &vop_advlock_desc, spec_advlock }, /* advlock */ 14053806Smckusick { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 14153806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */ 14253806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */ 14353806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */ 14453806Smckusick { &vop_update_desc, nfs_update }, /* update */ 14557809Smckusick { &vop_bwrite_desc, vn_bwrite }, 14653554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 14738414Smckusick }; 14853554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 14953554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 15038414Smckusick 15140294Smckusick #ifdef FIFO 15253554Sheideman int (**fifo_nfsv2nodeop_p)(); 15353554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 15453554Sheideman { &vop_default_desc, vn_default_error }, 15553806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15653806Smckusick { &vop_create_desc, fifo_create }, /* create */ 15753806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15853554Sheideman { &vop_open_desc, fifo_open }, /* open */ 15953806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 16056364Smckusick { &vop_access_desc, nfsspec_access }, /* access */ 16153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 16253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 16353806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 16453806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16553806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16653806Smckusick { &vop_select_desc, fifo_select }, /* select */ 16753554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16854451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 16953554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 17053806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */ 17153554Sheideman { &vop_link_desc, fifo_link }, /* link */ 17253806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */ 17353806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17453806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17553806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17653806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17753806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17853806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 18053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 18153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 18253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18353554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18453806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */ 18553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 187*60400Smckusick { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 18853806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18953806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 19053806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */ 19153806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */ 19253806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */ 19353806Smckusick { &vop_update_desc, nfs_update }, /* update */ 19457809Smckusick { &vop_bwrite_desc, vn_bwrite }, 19553554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 19640294Smckusick }; 19753554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 19853554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 19940294Smckusick #endif /* FIFO */ 20040294Smckusick 20156289Smckusick void nqnfs_clientlease(); 20256289Smckusick 20348054Smckusick /* 20452196Smckusick * Global variables 20548054Smckusick */ 20638414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 20756364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false; 20838414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20941905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 21046988Smckusick int nfs_numasync = 0; 21156390Smckusick /* Queue head for nfsiod's */ 21256468Smckusick struct queue_entry nfs_bufq; 21354740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 21438414Smckusick 21538414Smckusick /* 21638414Smckusick * nfs null call from vfs. 21738414Smckusick */ 21852234Sheideman int 21952196Smckusick nfs_null(vp, cred, procp) 22038414Smckusick struct vnode *vp; 22138414Smckusick struct ucred *cred; 22252196Smckusick struct proc *procp; 22338414Smckusick { 22439488Smckusick caddr_t bpos, dpos; 22539488Smckusick int error = 0; 22639488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22738414Smckusick 22852196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22952196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 23038414Smckusick nfsm_reqdone; 23138414Smckusick return (error); 23238414Smckusick } 23338414Smckusick 23438414Smckusick /* 23538414Smckusick * nfs access vnode op. 23656364Smckusick * For nfs, just return ok. File accesses may fail later. 23756364Smckusick * For nqnfs, use the access rpc to check accessibility. If file modes are 23856364Smckusick * changed on the server, accesses might still fail later. 23938414Smckusick */ 24052234Sheideman int 24153806Smckusick nfs_access(ap) 24254668Smckusick struct vop_access_args /* { 24354668Smckusick struct vnode *a_vp; 24454668Smckusick int a_mode; 24554668Smckusick struct ucred *a_cred; 24654668Smckusick struct proc *a_p; 24754668Smckusick } */ *ap; 24838414Smckusick { 24956364Smckusick register struct vnode *vp = ap->a_vp; 25056364Smckusick register u_long *tl; 25156364Smckusick register caddr_t cp; 25256364Smckusick caddr_t bpos, dpos; 25356364Smckusick int error = 0; 25456364Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 25538414Smckusick 25638414Smckusick /* 25756708Smckusick * For nqnfs, do an access rpc, otherwise you are stuck emulating 25856708Smckusick * ufs_access() locally using the vattr. This may not be correct, 25956708Smckusick * since the server may apply other access criteria such as 26056708Smckusick * client uid-->server uid mapping that we do not know about, but 26156708Smckusick * this is better than just returning anything that is lying about 26256708Smckusick * in the cache. 26338414Smckusick */ 26456364Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 26556364Smckusick nfsstats.rpccnt[NQNFSPROC_ACCESS]++; 26656364Smckusick nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED); 26756364Smckusick nfsm_fhtom(vp); 26856364Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 26956364Smckusick if (ap->a_mode & VREAD) 27056364Smckusick *tl++ = nfs_true; 27156364Smckusick else 27256364Smckusick *tl++ = nfs_false; 27356364Smckusick if (ap->a_mode & VWRITE) 27456364Smckusick *tl++ = nfs_true; 27556364Smckusick else 27656364Smckusick *tl++ = nfs_false; 27756364Smckusick if (ap->a_mode & VEXEC) 27856364Smckusick *tl = nfs_true; 27956364Smckusick else 28056364Smckusick *tl = nfs_false; 28156364Smckusick nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred); 28256364Smckusick nfsm_reqdone; 28338884Smacklem return (error); 28456364Smckusick } else 28556708Smckusick return (nfsspec_access(ap)); 28638414Smckusick } 28738414Smckusick 28838414Smckusick /* 28938414Smckusick * nfs open vnode op 29056289Smckusick * Check to see if the type is ok 29152196Smckusick * and that deletion is not in progress. 29256289Smckusick * For paged in text files, you will need to flush the page cache 29356289Smckusick * if consistency is lost. 29438414Smckusick */ 29539488Smckusick /* ARGSUSED */ 29652234Sheideman int 29753806Smckusick nfs_open(ap) 29854668Smckusick struct vop_open_args /* { 29954668Smckusick struct vnode *a_vp; 30054668Smckusick int a_mode; 30154668Smckusick struct ucred *a_cred; 30254668Smckusick struct proc *a_p; 30354668Smckusick } */ *ap; 30438414Smckusick { 30553806Smckusick register struct vnode *vp = ap->a_vp; 30656289Smckusick struct nfsnode *np = VTONFS(vp); 30756289Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount); 30856289Smckusick struct vattr vattr; 30956289Smckusick int error; 31038414Smckusick 31153806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 31238414Smckusick return (EACCES); 31356289Smckusick if (vp->v_flag & VTEXT) { 31456289Smckusick /* 31556289Smckusick * Get a valid lease. If cached data is stale, flush it. 31656289Smckusick */ 31756289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 31856289Smckusick if (NQNFS_CKINVALID(vp, np, NQL_READ)) { 31956289Smckusick do { 32056289Smckusick error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p); 32156289Smckusick } while (error == NQNFS_EXPIRED); 32256289Smckusick if (error) 32356289Smckusick return (error); 32459706Smckusick if (np->n_lrev != np->n_brev || 32559706Smckusick (np->n_flag & NQNFSNONCACHE)) { 32657791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 32757791Smckusick ap->a_p, 1)) == EINTR) 32857791Smckusick return (error); 32956289Smckusick (void) vnode_pager_uncache(vp); 33056289Smckusick np->n_brev = np->n_lrev; 33156289Smckusick } 33256289Smckusick } 33356289Smckusick } else { 33456289Smckusick if (np->n_flag & NMODIFIED) { 33557791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 33657791Smckusick ap->a_p, 1)) == EINTR) 33757791Smckusick return (error); 33856289Smckusick (void) vnode_pager_uncache(vp); 33956289Smckusick np->n_attrstamp = 0; 34056289Smckusick np->n_direofoffset = 0; 34156289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 34256289Smckusick return (error); 34356289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 34456289Smckusick } else { 34556289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 34656289Smckusick return (error); 34756289Smckusick if (np->n_mtime != vattr.va_mtime.ts_sec) { 34856289Smckusick np->n_direofoffset = 0; 34957791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, 35057791Smckusick ap->a_cred, ap->a_p, 1)) == EINTR) 35157791Smckusick return (error); 35256289Smckusick (void) vnode_pager_uncache(vp); 35356289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 35456289Smckusick } 35556289Smckusick } 35656289Smckusick } 35756289Smckusick } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 35856289Smckusick np->n_attrstamp = 0; /* For Open/Close consistency */ 35952196Smckusick return (0); 36038414Smckusick } 36138414Smckusick 36238414Smckusick /* 36338414Smckusick * nfs close vnode op 36438884Smacklem * For reg files, invalidate any buffer cache entries. 36538414Smckusick */ 36639488Smckusick /* ARGSUSED */ 36752234Sheideman int 36853806Smckusick nfs_close(ap) 36954451Smckusick struct vop_close_args /* { 37054451Smckusick struct vnodeop_desc *a_desc; 37154451Smckusick struct vnode *a_vp; 37254451Smckusick int a_fflag; 37354451Smckusick struct ucred *a_cred; 37454451Smckusick struct proc *a_p; 37554451Smckusick } */ *ap; 37638414Smckusick { 37753806Smckusick register struct vnode *vp = ap->a_vp; 37853806Smckusick register struct nfsnode *np = VTONFS(vp); 37939341Smckusick int error = 0; 38038414Smckusick 38153806Smckusick if (vp->v_type == VREG) { 38253806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 38353629Smckusick (np->n_flag & NMODIFIED)) { 38457791Smckusick error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); 38541905Smckusick np->n_attrstamp = 0; 38653629Smckusick } 38753629Smckusick if (np->n_flag & NWRITEERR) { 38853629Smckusick np->n_flag &= ~NWRITEERR; 38953629Smckusick error = np->n_error; 39053629Smckusick } 39138884Smacklem } 39238414Smckusick return (error); 39338414Smckusick } 39438414Smckusick 39538414Smckusick /* 39638414Smckusick * nfs getattr call from vfs. 39738414Smckusick */ 39852234Sheideman int 39953805Smckusick nfs_getattr(ap) 40054668Smckusick struct vop_getattr_args /* { 40154668Smckusick struct vnode *a_vp; 40254668Smckusick struct vattr *a_vap; 40354668Smckusick struct ucred *a_cred; 40454668Smckusick struct proc *a_p; 40554668Smckusick } */ *ap; 40638414Smckusick { 40753805Smckusick register struct vnode *vp = ap->a_vp; 40853805Smckusick register struct nfsnode *np = VTONFS(vp); 40939488Smckusick register caddr_t cp; 41039488Smckusick caddr_t bpos, dpos; 41139488Smckusick int error = 0; 41239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 41338414Smckusick 41453805Smckusick /* 41553805Smckusick * Update local times for special files. 41653805Smckusick */ 41756329Smckusick if (np->n_flag & (NACC | NUPD)) 41853805Smckusick np->n_flag |= NCHG; 41953805Smckusick /* 42053805Smckusick * First look in the cache. 42153805Smckusick */ 42253805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 42338414Smckusick return (0); 42438414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 42553805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 42653805Smckusick nfsm_fhtom(vp); 42753805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 42853805Smckusick nfsm_loadattr(vp, ap->a_vap); 42938414Smckusick nfsm_reqdone; 43038414Smckusick return (error); 43138414Smckusick } 43238414Smckusick 43338414Smckusick /* 43438414Smckusick * nfs setattr call. 43538414Smckusick */ 43652234Sheideman int 43753806Smckusick nfs_setattr(ap) 43854451Smckusick struct vop_setattr_args /* { 43954451Smckusick struct vnodeop_desc *a_desc; 44054451Smckusick struct vnode *a_vp; 44154451Smckusick struct vattr *a_vap; 44254451Smckusick struct ucred *a_cred; 44354451Smckusick struct proc *a_p; 44454451Smckusick } */ *ap; 44538414Smckusick { 44638884Smacklem register struct nfsv2_sattr *sp; 44739488Smckusick register caddr_t cp; 44839488Smckusick register long t1; 44952196Smckusick caddr_t bpos, dpos, cp2; 45052196Smckusick u_long *tl; 45156289Smckusick int error = 0, isnq; 45239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 45353806Smckusick register struct vnode *vp = ap->a_vp; 45453806Smckusick register struct nfsnode *np = VTONFS(vp); 45553806Smckusick register struct vattr *vap = ap->a_vap; 45652196Smckusick u_quad_t frev; 45738414Smckusick 45857791Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || 45957791Smckusick vap->va_atime.ts_sec != VNOVAL) { 46057791Smckusick if (vap->va_size != VNOVAL) { 46157791Smckusick if (np->n_flag & NMODIFIED) { 46257791Smckusick if (vap->va_size == 0) 46357791Smckusick error = nfs_vinvalbuf(vp, 0, ap->a_cred, 46457791Smckusick ap->a_p, 1); 46557791Smckusick else 46657791Smckusick error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 46757791Smckusick ap->a_p, 1); 46857791Smckusick if (error) 46957791Smckusick return (error); 47057791Smckusick } 47157791Smckusick np->n_size = np->n_vattr.va_size = vap->va_size; 47257791Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 47357791Smckusick } else if ((np->n_flag & NMODIFIED) && 47457791Smckusick (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 47557791Smckusick ap->a_p, 1)) == EINTR) 47657791Smckusick return (error); 47757791Smckusick } 47838414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 47956289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 48056289Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq)); 48153806Smckusick nfsm_fhtom(vp); 48256289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 48356289Smckusick if (vap->va_mode == (u_short)-1) 48438884Smacklem sp->sa_mode = VNOVAL; 48538414Smckusick else 48653806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 48756289Smckusick if (vap->va_uid == (uid_t)-1) 48838884Smacklem sp->sa_uid = VNOVAL; 48938414Smckusick else 49053806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 49156289Smckusick if (vap->va_gid == (gid_t)-1) 49238884Smacklem sp->sa_gid = VNOVAL; 49338414Smckusick else 49453806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 49556289Smckusick if (isnq) { 49656289Smckusick txdr_hyper(&vap->va_size, &sp->sa_nqsize); 49756289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 49856289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 49956289Smckusick sp->sa_nqflags = txdr_unsigned(vap->va_flags); 50056289Smckusick sp->sa_nqrdev = VNOVAL; 50156289Smckusick } else { 50256289Smckusick sp->sa_nfssize = txdr_unsigned(vap->va_size); 50358882Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 50456289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 50556289Smckusick } 50653806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 50753806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 50853806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 50953806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 51052196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 51152196Smckusick fxdr_hyper(tl, &frev); 51254451Smckusick if (frev > np->n_brev) 51352196Smckusick np->n_brev = frev; 51452196Smckusick } 51538414Smckusick nfsm_reqdone; 51638414Smckusick return (error); 51738414Smckusick } 51838414Smckusick 51938414Smckusick /* 52038414Smckusick * nfs lookup call, one step at a time... 52138414Smckusick * First look in cache 52238414Smckusick * If not found, unlock the directory nfsnode and do the rpc 52338414Smckusick */ 52452234Sheideman int 52553806Smckusick nfs_lookup(ap) 52654451Smckusick struct vop_lookup_args /* { 52754451Smckusick struct vnodeop_desc *a_desc; 52854451Smckusick struct vnode *a_dvp; 52954451Smckusick struct vnode **a_vpp; 53054451Smckusick struct componentname *a_cnp; 53154451Smckusick } */ *ap; 53238414Smckusick { 53353806Smckusick register struct componentname *cnp = ap->a_cnp; 53453806Smckusick register struct vnode *dvp = ap->a_dvp; 53554668Smckusick register struct vnode **vpp = ap->a_vpp; 53655184Smckusick register int flags = cnp->cn_flags; 53738414Smckusick register struct vnode *vdp; 53848054Smckusick register u_long *tl; 53939488Smckusick register caddr_t cp; 54039488Smckusick register long t1, t2; 54152196Smckusick struct nfsmount *nmp; 54252196Smckusick struct nfsnode *tp; 54339488Smckusick caddr_t bpos, dpos, cp2; 54452196Smckusick time_t reqtime; 54539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 54638414Smckusick struct vnode *newvp; 54738414Smckusick long len; 54838414Smckusick nfsv2fh_t *fhp; 54938414Smckusick struct nfsnode *np; 55052234Sheideman int lockparent, wantparent, error = 0; 55152196Smckusick int nqlflag, cachable; 55252196Smckusick u_quad_t frev; 55338414Smckusick 55454668Smckusick *vpp = NULL; 55553806Smckusick if (dvp->v_type != VDIR) 55638414Smckusick return (ENOTDIR); 55755184Smckusick lockparent = flags & LOCKPARENT; 55855184Smckusick wantparent = flags & (LOCKPARENT|WANTPARENT); 55953806Smckusick nmp = VFSTONFS(dvp->v_mount); 56053806Smckusick np = VTONFS(dvp); 56154668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 56238884Smacklem struct vattr vattr; 56338884Smacklem int vpid; 56438884Smacklem 56554668Smckusick vdp = *vpp; 56638884Smacklem vpid = vdp->v_id; 56738414Smckusick /* 56838884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 56938884Smacklem * for an explanation of the locking protocol 57038414Smckusick */ 57153806Smckusick if (dvp == vdp) { 57238425Smckusick VREF(vdp); 57339441Smckusick error = 0; 57452196Smckusick } else 57539441Smckusick error = vget(vdp); 57639441Smckusick if (!error) { 57740251Smckusick if (vpid == vdp->v_id) { 57852196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 57956289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) { 58056289Smckusick nfsstats.lookupcache_hits++; 58156289Smckusick if (cnp->cn_nameiop != LOOKUP && 58256289Smckusick (flags & ISLASTCN)) 58356289Smckusick cnp->cn_flags |= SAVENAME; 58456289Smckusick return (0); 58556289Smckusick } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 58654451Smckusick if (np->n_lrev != np->n_brev || 58752196Smckusick (np->n_flag & NMODIFIED)) { 58852196Smckusick np->n_direofoffset = 0; 58953806Smckusick cache_purge(dvp); 59057791Smckusick error = nfs_vinvalbuf(dvp, 0, 59156660Smckusick cnp->cn_cred, cnp->cn_proc, 59257791Smckusick 1); 59357791Smckusick if (error == EINTR) 59457791Smckusick return (error); 59552196Smckusick np->n_brev = np->n_lrev; 59652196Smckusick } else { 59752196Smckusick nfsstats.lookupcache_hits++; 59853806Smckusick if (cnp->cn_nameiop != LOOKUP && 59955184Smckusick (flags & ISLASTCN)) 60053806Smckusick cnp->cn_flags |= SAVENAME; 60152196Smckusick return (0); 60252196Smckusick } 60352196Smckusick } 60453806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 60554106Smckusick vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { 60639441Smckusick nfsstats.lookupcache_hits++; 60753806Smckusick if (cnp->cn_nameiop != LOOKUP && 60855184Smckusick (flags & ISLASTCN)) 60953806Smckusick cnp->cn_flags |= SAVENAME; 61039441Smckusick return (0); 61140251Smckusick } 61247289Smckusick cache_purge(vdp); 61339441Smckusick } 61452196Smckusick vrele(vdp); 61538884Smacklem } 61654668Smckusick *vpp = NULLVP; 61752196Smckusick } 61839341Smckusick error = 0; 61938414Smckusick nfsstats.lookupcache_misses++; 62038414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 62153806Smckusick len = cnp->cn_namelen; 62253806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 62352196Smckusick 62452196Smckusick /* 62552196Smckusick * For nqnfs optionally piggyback a getlease request for the name 62652196Smckusick * being looked up. 62752196Smckusick */ 62852196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 62956289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 63052196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 63155184Smckusick ((cnp->cn_flags & MAKEENTRY) && 63256289Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) 63352196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 63456289Smckusick else 63552196Smckusick *tl = 0; 63652196Smckusick } 63753806Smckusick nfsm_fhtom(dvp); 63853806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 63952196Smckusick reqtime = time.tv_sec; 64053806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 64138414Smckusick nfsmout: 64238414Smckusick if (error) { 64353806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 64455184Smckusick (flags & ISLASTCN) && error == ENOENT) 64552823Smckusick error = EJUSTRETURN; 64655184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 64753806Smckusick cnp->cn_flags |= SAVENAME; 64840483Smckusick return (error); 64938414Smckusick } 65052196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 65152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 65252196Smckusick if (*tl) { 65352196Smckusick nqlflag = fxdr_unsigned(int, *tl); 65452196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 65552196Smckusick cachable = fxdr_unsigned(int, *tl++); 65652196Smckusick reqtime += fxdr_unsigned(int, *tl++); 65752196Smckusick fxdr_hyper(tl, &frev); 65852196Smckusick } else 65952196Smckusick nqlflag = 0; 66052196Smckusick } 66152196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 66238414Smckusick 66338414Smckusick /* 66452196Smckusick * Handle RENAME case... 66538414Smckusick */ 66655184Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 66752196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 66838414Smckusick m_freem(mrep); 66938414Smckusick return (EISDIR); 67038414Smckusick } 67153806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 67238414Smckusick m_freem(mrep); 67338414Smckusick return (error); 67438414Smckusick } 67538414Smckusick newvp = NFSTOV(np); 67639459Smckusick if (error = 67739459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 67852196Smckusick vrele(newvp); 67938414Smckusick m_freem(mrep); 68038414Smckusick return (error); 68138414Smckusick } 68254668Smckusick *vpp = newvp; 68345037Smckusick m_freem(mrep); 68453806Smckusick cnp->cn_flags |= SAVENAME; 68538414Smckusick return (0); 68638414Smckusick } 68738414Smckusick 68852196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 68953806Smckusick VREF(dvp); 69053806Smckusick newvp = dvp; 69138414Smckusick } else { 69253806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 69338414Smckusick m_freem(mrep); 69438414Smckusick return (error); 69538414Smckusick } 69638414Smckusick newvp = NFSTOV(np); 69738414Smckusick } 69839459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 69952196Smckusick vrele(newvp); 70038414Smckusick m_freem(mrep); 70138414Smckusick return (error); 70238414Smckusick } 70338414Smckusick m_freem(mrep); 70454668Smckusick *vpp = newvp; 70555184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 70653806Smckusick cnp->cn_flags |= SAVENAME; 70755184Smckusick if ((cnp->cn_flags & MAKEENTRY) && 70855184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { 70952196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 71054106Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec; 71156289Smckusick else if (nqlflag && reqtime > time.tv_sec) 71256289Smckusick nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime, 71356289Smckusick frev); 71454668Smckusick cache_enter(dvp, *vpp, cnp); 71540251Smckusick } 71652196Smckusick return (0); 71738414Smckusick } 71838414Smckusick 71938414Smckusick /* 72041905Smckusick * nfs read call. 72141905Smckusick * Just call nfs_bioread() to do the work. 72241905Smckusick */ 72352234Sheideman int 72453806Smckusick nfs_read(ap) 72554668Smckusick struct vop_read_args /* { 72654668Smckusick struct vnode *a_vp; 72754668Smckusick struct uio *a_uio; 72854668Smckusick int a_ioflag; 72954668Smckusick struct ucred *a_cred; 73054668Smckusick } */ *ap; 73141905Smckusick { 73253806Smckusick register struct vnode *vp = ap->a_vp; 73353806Smckusick 73453806Smckusick if (vp->v_type != VREG) 73541905Smckusick return (EPERM); 73653806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 73741905Smckusick } 73841905Smckusick 73941905Smckusick /* 74038414Smckusick * nfs readlink call 74138414Smckusick */ 74252234Sheideman int 74353806Smckusick nfs_readlink(ap) 74454668Smckusick struct vop_readlink_args /* { 74554668Smckusick struct vnode *a_vp; 74654668Smckusick struct uio *a_uio; 74754668Smckusick struct ucred *a_cred; 74854668Smckusick } */ *ap; 74941905Smckusick { 75053806Smckusick register struct vnode *vp = ap->a_vp; 75153806Smckusick 75253806Smckusick if (vp->v_type != VLNK) 75341905Smckusick return (EPERM); 75453806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 75541905Smckusick } 75641905Smckusick 75741905Smckusick /* 75841905Smckusick * Do a readlink rpc. 75941905Smckusick * Called by nfs_doio() from below the buffer cache. 76041905Smckusick */ 76152234Sheideman int 76248054Smckusick nfs_readlinkrpc(vp, uiop, cred) 76339488Smckusick register struct vnode *vp; 76438414Smckusick struct uio *uiop; 76538414Smckusick struct ucred *cred; 76638414Smckusick { 76748054Smckusick register u_long *tl; 76839488Smckusick register caddr_t cp; 76939488Smckusick register long t1; 77039488Smckusick caddr_t bpos, dpos, cp2; 77139488Smckusick int error = 0; 77239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 77338414Smckusick long len; 77438414Smckusick 77538414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 77652196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 77738414Smckusick nfsm_fhtom(vp); 77852196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 77938414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 78038414Smckusick nfsm_mtouio(uiop, len); 78138414Smckusick nfsm_reqdone; 78238414Smckusick return (error); 78338414Smckusick } 78438414Smckusick 78538414Smckusick /* 78641905Smckusick * nfs read rpc call 78741905Smckusick * Ditto above 78838414Smckusick */ 78952234Sheideman int 79048054Smckusick nfs_readrpc(vp, uiop, cred) 79139488Smckusick register struct vnode *vp; 79238414Smckusick struct uio *uiop; 79338414Smckusick struct ucred *cred; 79438414Smckusick { 79548054Smckusick register u_long *tl; 79639488Smckusick register caddr_t cp; 79739488Smckusick register long t1; 79839488Smckusick caddr_t bpos, dpos, cp2; 79939488Smckusick int error = 0; 80039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 80138414Smckusick struct nfsmount *nmp; 80238414Smckusick long len, retlen, tsiz; 80338414Smckusick 80441398Smckusick nmp = VFSTONFS(vp->v_mount); 80538414Smckusick tsiz = uiop->uio_resid; 80656289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 80756289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 80856289Smckusick return (EFBIG); 80938414Smckusick while (tsiz > 0) { 81038414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 81138414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 81252196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 81338414Smckusick nfsm_fhtom(vp); 81448054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 81556289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 81656289Smckusick txdr_hyper(&uiop->uio_offset, tl); 81756289Smckusick *(tl + 2) = txdr_unsigned(len); 81856289Smckusick } else { 81956289Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 82056289Smckusick *tl++ = txdr_unsigned(len); 82156289Smckusick *tl = 0; 82256289Smckusick } 82352196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 82438414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 82538414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 82638414Smckusick nfsm_mtouio(uiop, retlen); 82738414Smckusick m_freem(mrep); 82838414Smckusick if (retlen < len) 82938414Smckusick tsiz = 0; 83038414Smckusick else 83138414Smckusick tsiz -= len; 83238414Smckusick } 83338414Smckusick nfsmout: 83438414Smckusick return (error); 83538414Smckusick } 83638414Smckusick 83738414Smckusick /* 83838414Smckusick * nfs write call 83938414Smckusick */ 84052234Sheideman int 84156289Smckusick nfs_writerpc(vp, uiop, cred, ioflags) 84239488Smckusick register struct vnode *vp; 84338414Smckusick struct uio *uiop; 84438414Smckusick struct ucred *cred; 84556289Smckusick int ioflags; 84638414Smckusick { 84748054Smckusick register u_long *tl; 84839488Smckusick register caddr_t cp; 84939488Smckusick register long t1; 85052196Smckusick caddr_t bpos, dpos, cp2; 85139488Smckusick int error = 0; 85239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 85338414Smckusick struct nfsmount *nmp; 85452196Smckusick struct nfsnode *np = VTONFS(vp); 85552196Smckusick u_quad_t frev; 85638414Smckusick long len, tsiz; 85738414Smckusick 85841398Smckusick nmp = VFSTONFS(vp->v_mount); 85938414Smckusick tsiz = uiop->uio_resid; 86056289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 86156289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 86256289Smckusick return (EFBIG); 86338414Smckusick while (tsiz > 0) { 86438414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 86538414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 86652196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 86752196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 86838414Smckusick nfsm_fhtom(vp); 86956289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4); 87056289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 87156289Smckusick txdr_hyper(&uiop->uio_offset, tl); 87256289Smckusick tl += 2; 87356289Smckusick if (ioflags & IO_APPEND) 87456289Smckusick *tl++ = txdr_unsigned(1); 87556289Smckusick else 87656289Smckusick *tl++ = 0; 87756289Smckusick } else { 87856289Smckusick *++tl = txdr_unsigned(uiop->uio_offset); 87956289Smckusick tl += 2; 88056289Smckusick } 88156289Smckusick *tl = txdr_unsigned(len); 88238414Smckusick nfsm_uiotom(uiop, len); 88352196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 88438414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 88552196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 88654106Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; 88752196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 88852196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 88952196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 89052196Smckusick fxdr_hyper(tl, &frev); 89154451Smckusick if (frev > np->n_brev) 89252196Smckusick np->n_brev = frev; 89352196Smckusick } 89438414Smckusick m_freem(mrep); 89538414Smckusick tsiz -= len; 89638414Smckusick } 89738414Smckusick nfsmout: 89852196Smckusick if (error) 89952196Smckusick uiop->uio_resid = tsiz; 90038414Smckusick return (error); 90138414Smckusick } 90238414Smckusick 90338414Smckusick /* 90439459Smckusick * nfs mknod call 90542246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 90642246Smckusick * set to specify the file type and the size field for rdev. 90739459Smckusick */ 90839459Smckusick /* ARGSUSED */ 90952234Sheideman int 91053806Smckusick nfs_mknod(ap) 91154668Smckusick struct vop_mknod_args /* { 91254668Smckusick struct vnode *a_dvp; 91354668Smckusick struct vnode **a_vpp; 91454668Smckusick struct componentname *a_cnp; 91554668Smckusick struct vattr *a_vap; 91654668Smckusick } */ *ap; 91739459Smckusick { 91853806Smckusick register struct vnode *dvp = ap->a_dvp; 91953806Smckusick register struct vattr *vap = ap->a_vap; 92053806Smckusick register struct componentname *cnp = ap->a_cnp; 92142246Smckusick register struct nfsv2_sattr *sp; 92248054Smckusick register u_long *tl; 92342246Smckusick register caddr_t cp; 92456289Smckusick register long t1, t2; 92556289Smckusick struct vnode *newvp; 92659116Smckusick struct vattr vattr; 92756289Smckusick char *cp2; 92842246Smckusick caddr_t bpos, dpos; 92956289Smckusick int error = 0, isnq; 93042246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 93142246Smckusick u_long rdev; 93239459Smckusick 93356289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 93453806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 93553806Smckusick rdev = txdr_unsigned(vap->va_rdev); 93642246Smckusick #ifdef FIFO 93753806Smckusick else if (vap->va_type == VFIFO) 93842246Smckusick rdev = 0xffffffff; 93942246Smckusick #endif /* FIFO */ 94042246Smckusick else { 94153806Smckusick VOP_ABORTOP(dvp, cnp); 94253806Smckusick vput(dvp); 94342246Smckusick return (EOPNOTSUPP); 94442246Smckusick } 94559116Smckusick if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) { 94659116Smckusick VOP_ABORTOP(dvp, cnp); 94759116Smckusick vput(dvp); 94859116Smckusick return (error); 94959116Smckusick } 95042246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 95153806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 95256289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 95353806Smckusick nfsm_fhtom(dvp); 95453806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 95556289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 95653806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 95753806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 95859116Smckusick sp->sa_gid = txdr_unsigned(vattr.va_gid); 95956289Smckusick if (isnq) { 96056289Smckusick sp->sa_nqrdev = rdev; 96156289Smckusick sp->sa_nqflags = 0; 96256289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 96356289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 96456289Smckusick } else { 96556289Smckusick sp->sa_nfssize = rdev; 96656289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 96756289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 96856289Smckusick } 96953806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 97056289Smckusick nfsm_mtofh(dvp, newvp); 97142246Smckusick nfsm_reqdone; 97256927Smckusick if (!error && (cnp->cn_flags & MAKEENTRY)) 97356289Smckusick cache_enter(dvp, newvp, cnp); 97453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 97553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 97653806Smckusick vrele(dvp); 97742246Smckusick return (error); 97839459Smckusick } 97939459Smckusick 98039459Smckusick /* 98138414Smckusick * nfs file create call 98238414Smckusick */ 98352234Sheideman int 98453806Smckusick nfs_create(ap) 98554668Smckusick struct vop_create_args /* { 98654668Smckusick struct vnode *a_dvp; 98754668Smckusick struct vnode **a_vpp; 98854668Smckusick struct componentname *a_cnp; 98954668Smckusick struct vattr *a_vap; 99054668Smckusick } */ *ap; 99138414Smckusick { 99253806Smckusick register struct vnode *dvp = ap->a_dvp; 99353806Smckusick register struct vattr *vap = ap->a_vap; 99453806Smckusick register struct componentname *cnp = ap->a_cnp; 99538884Smacklem register struct nfsv2_sattr *sp; 99648054Smckusick register u_long *tl; 99739488Smckusick register caddr_t cp; 99839488Smckusick register long t1, t2; 99939488Smckusick caddr_t bpos, dpos, cp2; 100056289Smckusick int error = 0, isnq; 100139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 100259116Smckusick struct vattr vattr; 100338414Smckusick 100459116Smckusick if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) { 100559116Smckusick VOP_ABORTOP(dvp, cnp); 100659116Smckusick vput(dvp); 100759116Smckusick return (error); 100859116Smckusick } 100938414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 101056289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 101153806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 101256289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 101353806Smckusick nfsm_fhtom(dvp); 101453806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 101556289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 101653806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 101753806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 101859116Smckusick sp->sa_gid = txdr_unsigned(vattr.va_gid); 101956289Smckusick if (isnq) { 102056289Smckusick u_quad_t qval = 0; 102156289Smckusick 102256289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 102356289Smckusick sp->sa_nqflags = 0; 102456289Smckusick sp->sa_nqrdev = -1; 102556289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 102656289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 102756289Smckusick } else { 102856289Smckusick sp->sa_nfssize = 0; 102956289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 103056289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 103156289Smckusick } 103253806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 103353806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 103438414Smckusick nfsm_reqdone; 103556927Smckusick if (!error && (cnp->cn_flags & MAKEENTRY)) 103656289Smckusick cache_enter(dvp, *ap->a_vpp, cnp); 103753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 103853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 103953806Smckusick vrele(dvp); 104038414Smckusick return (error); 104138414Smckusick } 104238414Smckusick 104338414Smckusick /* 104438414Smckusick * nfs file remove call 104541905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 104641905Smckusick * other processes using the vnode is renamed instead of removed and then 104739341Smckusick * removed later on the last close. 104841905Smckusick * - If v_usecount > 1 104939341Smckusick * If a rename is not already in the works 105039341Smckusick * call nfs_sillyrename() to set it up 105139341Smckusick * else 105239341Smckusick * do the remove rpc 105338414Smckusick */ 105452234Sheideman int 105553806Smckusick nfs_remove(ap) 105654451Smckusick struct vop_remove_args /* { 105754451Smckusick struct vnodeop_desc *a_desc; 105854451Smckusick struct vnode * a_dvp; 105954451Smckusick struct vnode * a_vp; 106054451Smckusick struct componentname * a_cnp; 106154451Smckusick } */ *ap; 106238414Smckusick { 106353806Smckusick register struct vnode *vp = ap->a_vp; 106453806Smckusick register struct vnode *dvp = ap->a_dvp; 106553806Smckusick register struct componentname *cnp = ap->a_cnp; 106653806Smckusick register struct nfsnode *np = VTONFS(vp); 106748054Smckusick register u_long *tl; 106839488Smckusick register caddr_t cp; 106952196Smckusick register long t2; 107039488Smckusick caddr_t bpos, dpos; 107139488Smckusick int error = 0; 107239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 107338414Smckusick 107453806Smckusick if (vp->v_usecount > 1) { 107539341Smckusick if (!np->n_sillyrename) 107653806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 107739341Smckusick } else { 107852196Smckusick /* 107952196Smckusick * Purge the name cache so that the chance of a lookup for 108052196Smckusick * the name succeeding while the remove is in progress is 108152196Smckusick * minimized. Without node locking it can still happen, such 108252196Smckusick * that an I/O op returns ESTALE, but since you get this if 108352196Smckusick * another host removes the file.. 108452196Smckusick */ 108553806Smckusick cache_purge(vp); 108652196Smckusick /* 108752196Smckusick * Throw away biocache buffers. Mainly to avoid 108852196Smckusick * unnecessary delayed writes. 108952196Smckusick */ 109057791Smckusick error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1); 109157791Smckusick if (error == EINTR) 109257791Smckusick return (error); 109352196Smckusick /* Do the rpc */ 109438414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 109553806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 109653806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 109753806Smckusick nfsm_fhtom(dvp); 109853806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 109953806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 110038414Smckusick nfsm_reqdone; 110153806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 110253806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 110339751Smckusick /* 110439751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 110539751Smckusick * the reply to the retransmitted request will be ENOENT 110639751Smckusick * since the file was in fact removed 110739751Smckusick * Therefore, we cheat and return success. 110839751Smckusick */ 110939751Smckusick if (error == ENOENT) 111039751Smckusick error = 0; 111138414Smckusick } 111240042Smckusick np->n_attrstamp = 0; 111353806Smckusick vrele(dvp); 111453806Smckusick vrele(vp); 111538414Smckusick return (error); 111638414Smckusick } 111738414Smckusick 111838414Smckusick /* 111938414Smckusick * nfs file remove rpc called from nfs_inactive 112038414Smckusick */ 112152234Sheideman int 112254451Smckusick nfs_removeit(sp) 112348364Smckusick register struct sillyrename *sp; 112438414Smckusick { 112548054Smckusick register u_long *tl; 112639488Smckusick register caddr_t cp; 112752196Smckusick register long t2; 112839488Smckusick caddr_t bpos, dpos; 112939488Smckusick int error = 0; 113039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 113138414Smckusick 113238414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 113352196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 113448364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 113548364Smckusick nfsm_fhtom(sp->s_dvp); 113648364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 113754451Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); 113838414Smckusick nfsm_reqdone; 113948364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 114038414Smckusick return (error); 114138414Smckusick } 114238414Smckusick 114338414Smckusick /* 114438414Smckusick * nfs file rename call 114538414Smckusick */ 114652234Sheideman int 114753806Smckusick nfs_rename(ap) 114854668Smckusick struct vop_rename_args /* { 114954668Smckusick struct vnode *a_fdvp; 115054668Smckusick struct vnode *a_fvp; 115154668Smckusick struct componentname *a_fcnp; 115254668Smckusick struct vnode *a_tdvp; 115354668Smckusick struct vnode *a_tvp; 115454668Smckusick struct componentname *a_tcnp; 115554668Smckusick } */ *ap; 115638414Smckusick { 115753806Smckusick register struct vnode *fvp = ap->a_fvp; 115853806Smckusick register struct vnode *tvp = ap->a_tvp; 115953806Smckusick register struct vnode *fdvp = ap->a_fdvp; 116053806Smckusick register struct vnode *tdvp = ap->a_tdvp; 116153806Smckusick register struct componentname *tcnp = ap->a_tcnp; 116253806Smckusick register struct componentname *fcnp = ap->a_fcnp; 116348054Smckusick register u_long *tl; 116439488Smckusick register caddr_t cp; 116552196Smckusick register long t2; 116639488Smckusick caddr_t bpos, dpos; 116739488Smckusick int error = 0; 116839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 116938414Smckusick 117053804Spendry /* Check for cross-device rename */ 117153806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 117253806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 117353804Spendry error = EXDEV; 117453804Spendry goto out; 117553804Spendry } 117653804Spendry 117753804Spendry 117838414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 117953806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 118053806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 118153806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 118253806Smckusick nfsm_fhtom(fdvp); 118353806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 118453806Smckusick nfsm_fhtom(tdvp); 118553806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 118653806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 118738414Smckusick nfsm_reqdone; 118853806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 118953806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 119053806Smckusick if (fvp->v_type == VDIR) { 119153806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 119253806Smckusick cache_purge(tdvp); 119353806Smckusick cache_purge(fdvp); 119438414Smckusick } 119553804Spendry out: 119653806Smckusick if (tdvp == tvp) 119753806Smckusick vrele(tdvp); 119843360Smckusick else 119953806Smckusick vput(tdvp); 120053806Smckusick if (tvp) 120153806Smckusick vput(tvp); 120253806Smckusick vrele(fdvp); 120353806Smckusick vrele(fvp); 120440112Smckusick /* 120540112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 120640112Smckusick */ 120740112Smckusick if (error == ENOENT) 120840112Smckusick error = 0; 120938414Smckusick return (error); 121038414Smckusick } 121138414Smckusick 121238414Smckusick /* 121341905Smckusick * nfs file rename rpc called from nfs_remove() above 121438414Smckusick */ 121552234Sheideman int 121652234Sheideman nfs_renameit(sdvp, scnp, sp) 121752234Sheideman struct vnode *sdvp; 121852234Sheideman struct componentname *scnp; 121948364Smckusick register struct sillyrename *sp; 122038414Smckusick { 122148054Smckusick register u_long *tl; 122239488Smckusick register caddr_t cp; 122352196Smckusick register long t2; 122439488Smckusick caddr_t bpos, dpos; 122539488Smckusick int error = 0; 122639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 122738414Smckusick 122838414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 122952234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 123052234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 123152196Smckusick nfsm_rndup(sp->s_namlen)); 123252234Sheideman nfsm_fhtom(sdvp); 123352234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 123452234Sheideman nfsm_fhtom(sdvp); 123548364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 123652234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 123738414Smckusick nfsm_reqdone; 123852234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 123952234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 124038414Smckusick return (error); 124138414Smckusick } 124238414Smckusick 124338414Smckusick /* 124438414Smckusick * nfs hard link create call 124538414Smckusick */ 124652234Sheideman int 124753806Smckusick nfs_link(ap) 124854668Smckusick struct vop_link_args /* { 124954668Smckusick struct vnode *a_vp; 125054668Smckusick struct vnode *a_tdvp; 125154668Smckusick struct componentname *a_cnp; 125254668Smckusick } */ *ap; 125338414Smckusick { 125453806Smckusick register struct vnode *vp = ap->a_vp; 125553806Smckusick register struct vnode *tdvp = ap->a_tdvp; 125653806Smckusick register struct componentname *cnp = ap->a_cnp; 125748054Smckusick register u_long *tl; 125839488Smckusick register caddr_t cp; 125952196Smckusick register long t2; 126039488Smckusick caddr_t bpos, dpos; 126139488Smckusick int error = 0; 126239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 126338414Smckusick 126453806Smckusick if (vp->v_mount != tdvp->v_mount) { 126553806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 126653806Smckusick if (tdvp == vp) 126753806Smckusick vrele(vp); 126853804Spendry else 126953806Smckusick vput(vp); 127053804Spendry return (EXDEV); 127153804Spendry } 127253804Spendry 127338414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 127453806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 127553806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 127653806Smckusick nfsm_fhtom(tdvp); 127753806Smckusick nfsm_fhtom(vp); 127853806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 127953806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 128038414Smckusick nfsm_reqdone; 128153806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 128253806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 128353806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 128453806Smckusick vrele(vp); 128540112Smckusick /* 128640112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 128740112Smckusick */ 128840112Smckusick if (error == EEXIST) 128940112Smckusick error = 0; 129038414Smckusick return (error); 129138414Smckusick } 129238414Smckusick 129338414Smckusick /* 129438414Smckusick * nfs symbolic link create call 129538414Smckusick */ 129652234Sheideman /* start here */ 129752234Sheideman int 129853806Smckusick nfs_symlink(ap) 129954668Smckusick struct vop_symlink_args /* { 130054668Smckusick struct vnode *a_dvp; 130154668Smckusick struct vnode **a_vpp; 130254668Smckusick struct componentname *a_cnp; 130354668Smckusick struct vattr *a_vap; 130454668Smckusick char *a_target; 130554668Smckusick } */ *ap; 130638414Smckusick { 130753806Smckusick register struct vnode *dvp = ap->a_dvp; 130853806Smckusick register struct vattr *vap = ap->a_vap; 130953806Smckusick register struct componentname *cnp = ap->a_cnp; 131038884Smacklem register struct nfsv2_sattr *sp; 131148054Smckusick register u_long *tl; 131239488Smckusick register caddr_t cp; 131352196Smckusick register long t2; 131439488Smckusick caddr_t bpos, dpos; 131556289Smckusick int slen, error = 0, isnq; 131639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 131738414Smckusick 131838414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 131953600Sheideman slen = strlen(ap->a_target); 132056289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 132153806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 132256289Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq)); 132353806Smckusick nfsm_fhtom(dvp); 132453806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 132553600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 132656289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 132753806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 132853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 132953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 133056289Smckusick if (isnq) { 133156289Smckusick quad_t qval = -1; 133256289Smckusick 133356289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 133456289Smckusick sp->sa_nqflags = 0; 133556289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 133656289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 133756289Smckusick } else { 133856289Smckusick sp->sa_nfssize = -1; 133956289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 134056289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 134156289Smckusick } 134253806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 134338414Smckusick nfsm_reqdone; 134453806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 134553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 134653806Smckusick vrele(dvp); 134740112Smckusick /* 134840112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 134940112Smckusick */ 135040112Smckusick if (error == EEXIST) 135140112Smckusick error = 0; 135238414Smckusick return (error); 135338414Smckusick } 135438414Smckusick 135538414Smckusick /* 135638414Smckusick * nfs make dir call 135738414Smckusick */ 135852234Sheideman int 135953806Smckusick nfs_mkdir(ap) 136054668Smckusick struct vop_mkdir_args /* { 136154668Smckusick struct vnode *a_dvp; 136254668Smckusick struct vnode **a_vpp; 136354668Smckusick struct componentname *a_cnp; 136454668Smckusick struct vattr *a_vap; 136554668Smckusick } */ *ap; 136638414Smckusick { 136753806Smckusick register struct vnode *dvp = ap->a_dvp; 136853806Smckusick register struct vattr *vap = ap->a_vap; 136953806Smckusick register struct componentname *cnp = ap->a_cnp; 137054668Smckusick register struct vnode **vpp = ap->a_vpp; 137138884Smacklem register struct nfsv2_sattr *sp; 137248054Smckusick register u_long *tl; 137339488Smckusick register caddr_t cp; 137439488Smckusick register long t1, t2; 137541905Smckusick register int len; 137639488Smckusick caddr_t bpos, dpos, cp2; 137756289Smckusick int error = 0, firsttry = 1, isnq; 137839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 137959116Smckusick struct vattr vattr; 138038414Smckusick 138159116Smckusick if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) { 138259116Smckusick VOP_ABORTOP(dvp, cnp); 138359116Smckusick vput(dvp); 138459116Smckusick return (error); 138559116Smckusick } 138653806Smckusick len = cnp->cn_namelen; 138756289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 138838414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 138953806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 139056289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq)); 139153806Smckusick nfsm_fhtom(dvp); 139253806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 139356289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 139453806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 139553806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 139659116Smckusick sp->sa_gid = txdr_unsigned(vattr.va_gid); 139756289Smckusick if (isnq) { 139856289Smckusick quad_t qval = -1; 139956289Smckusick 140056289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 140156289Smckusick sp->sa_nqflags = 0; 140256289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 140356289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 140456289Smckusick } else { 140556289Smckusick sp->sa_nfssize = -1; 140656289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 140756289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 140856289Smckusick } 140953806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 141054668Smckusick nfsm_mtofh(dvp, *vpp); 141138414Smckusick nfsm_reqdone; 141253806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 141340112Smckusick /* 141441905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 141541905Smckusick * if we can succeed in looking up the directory. 141641905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 141741905Smckusick * is above the if on errors. (Ugh) 141840112Smckusick */ 141941905Smckusick if (error == EEXIST && firsttry) { 142041905Smckusick firsttry = 0; 142140112Smckusick error = 0; 142241905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 142354668Smckusick *vpp = NULL; 142453806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 142541905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 142653806Smckusick nfsm_fhtom(dvp); 142753806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 142853806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 142954668Smckusick nfsm_mtofh(dvp, *vpp); 143054668Smckusick if ((*vpp)->v_type != VDIR) { 143154668Smckusick vput(*vpp); 143241905Smckusick error = EEXIST; 143341905Smckusick } 143441905Smckusick m_freem(mrep); 143541905Smckusick } 143653806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 143753806Smckusick vrele(dvp); 143838414Smckusick return (error); 143938414Smckusick } 144038414Smckusick 144138414Smckusick /* 144238414Smckusick * nfs remove directory call 144338414Smckusick */ 144452234Sheideman int 144553806Smckusick nfs_rmdir(ap) 144654668Smckusick struct vop_rmdir_args /* { 144754668Smckusick struct vnode *a_dvp; 144854668Smckusick struct vnode *a_vp; 144954668Smckusick struct componentname *a_cnp; 145054668Smckusick } */ *ap; 145138414Smckusick { 145253806Smckusick register struct vnode *vp = ap->a_vp; 145353806Smckusick register struct vnode *dvp = ap->a_dvp; 145453806Smckusick register struct componentname *cnp = ap->a_cnp; 145548054Smckusick register u_long *tl; 145639488Smckusick register caddr_t cp; 145752196Smckusick register long t2; 145839488Smckusick caddr_t bpos, dpos; 145939488Smckusick int error = 0; 146039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 146138414Smckusick 146253806Smckusick if (dvp == vp) { 146353806Smckusick vrele(dvp); 146453806Smckusick vrele(dvp); 146553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 146638414Smckusick return (EINVAL); 146738414Smckusick } 146838414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 146953806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 147053806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 147153806Smckusick nfsm_fhtom(dvp); 147253806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 147353806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 147438414Smckusick nfsm_reqdone; 147553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 147653806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 147753806Smckusick cache_purge(dvp); 147853806Smckusick cache_purge(vp); 147953806Smckusick vrele(vp); 148053806Smckusick vrele(dvp); 148140112Smckusick /* 148240112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 148340112Smckusick */ 148440112Smckusick if (error == ENOENT) 148540112Smckusick error = 0; 148638414Smckusick return (error); 148738414Smckusick } 148838414Smckusick 148938414Smckusick /* 149038414Smckusick * nfs readdir call 149138414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 149238414Smckusick * order so that it looks more sensible. This appears consistent with the 149338414Smckusick * Ultrix implementation of NFS. 149438414Smckusick */ 149552234Sheideman int 149653806Smckusick nfs_readdir(ap) 149754668Smckusick struct vop_readdir_args /* { 149854668Smckusick struct vnode *a_vp; 149954668Smckusick struct uio *a_uio; 150054668Smckusick struct ucred *a_cred; 150154668Smckusick } */ *ap; 150238414Smckusick { 150353806Smckusick register struct vnode *vp = ap->a_vp; 150453806Smckusick register struct nfsnode *np = VTONFS(vp); 150553806Smckusick register struct uio *uio = ap->a_uio; 150641905Smckusick int tresid, error; 150741905Smckusick struct vattr vattr; 150841905Smckusick 150953806Smckusick if (vp->v_type != VDIR) 151041905Smckusick return (EPERM); 151141905Smckusick /* 151241905Smckusick * First, check for hit on the EOF offset cache 151341905Smckusick */ 151453806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 151552196Smckusick (np->n_flag & NMODIFIED) == 0) { 151653806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 151753806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 151852196Smckusick nfsstats.direofcache_hits++; 151952196Smckusick return (0); 152052196Smckusick } 152153806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 152254106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) { 152352196Smckusick nfsstats.direofcache_hits++; 152452196Smckusick return (0); 152552196Smckusick } 152641905Smckusick } 152741905Smckusick 152841905Smckusick /* 152941905Smckusick * Call nfs_bioread() to do the real work. 153041905Smckusick */ 153153806Smckusick tresid = uio->uio_resid; 153253806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 153341905Smckusick 153454451Smckusick if (!error && uio->uio_resid == tresid) 153541905Smckusick nfsstats.direofcache_misses++; 153641905Smckusick return (error); 153741905Smckusick } 153841905Smckusick 153941905Smckusick /* 154041905Smckusick * Readdir rpc call. 154141905Smckusick * Called from below the buffer cache by nfs_doio(). 154241905Smckusick */ 154352234Sheideman int 154448054Smckusick nfs_readdirrpc(vp, uiop, cred) 154541905Smckusick register struct vnode *vp; 154641905Smckusick struct uio *uiop; 154741905Smckusick struct ucred *cred; 154841905Smckusick { 154938414Smckusick register long len; 155054740Smckusick register struct dirent *dp; 155148054Smckusick register u_long *tl; 155239488Smckusick register caddr_t cp; 155339488Smckusick register long t1; 155441905Smckusick long tlen, lastlen; 155539488Smckusick caddr_t bpos, dpos, cp2; 155639488Smckusick int error = 0; 155739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 155838414Smckusick struct mbuf *md2; 155938414Smckusick caddr_t dpos2; 156038414Smckusick int siz; 156140296Smckusick int more_dirs = 1; 156256289Smckusick u_long off, savoff; 156354740Smckusick struct dirent *savdp; 156440296Smckusick struct nfsmount *nmp; 156540296Smckusick struct nfsnode *np = VTONFS(vp); 156640296Smckusick long tresid; 156738414Smckusick 156841398Smckusick nmp = VFSTONFS(vp->v_mount); 156940296Smckusick tresid = uiop->uio_resid; 157040296Smckusick /* 157140296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 157248054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 157341905Smckusick * The stopping criteria is EOF or buffer full. 157440296Smckusick */ 157548054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 157640296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 157752196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 157856289Smckusick NFSX_FH + 2 * NFSX_UNSIGNED); 157940296Smckusick nfsm_fhtom(vp); 158056289Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 158156289Smckusick off = (u_long)uiop->uio_offset; 158256289Smckusick *tl++ = txdr_unsigned(off); 158348054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 158448054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 158552196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 158640296Smckusick siz = 0; 158752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 158848054Smckusick more_dirs = fxdr_unsigned(int, *tl); 158940296Smckusick 159040296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 159140296Smckusick dpos2 = dpos; 159240296Smckusick md2 = md; 159340296Smckusick 159440296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 159542246Smckusick #ifdef lint 159654740Smckusick dp = (struct dirent *)0; 159742246Smckusick #endif /* lint */ 159840296Smckusick while (more_dirs && siz < uiop->uio_resid) { 159940296Smckusick savoff = off; /* Hold onto offset and dp */ 160040296Smckusick savdp = dp; 160156289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 160254740Smckusick dp = (struct dirent *)tl; 160354740Smckusick dp->d_fileno = fxdr_unsigned(u_long, *tl++); 160448054Smckusick len = fxdr_unsigned(int, *tl); 160540296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 160640296Smckusick error = EBADRPC; 160740296Smckusick m_freem(mrep); 160840296Smckusick goto nfsmout; 160940296Smckusick } 161054986Smckusick dp->d_namlen = (u_char)len; 161154986Smckusick dp->d_type = DT_UNKNOWN; 161240296Smckusick nfsm_adv(len); /* Point past name */ 161340296Smckusick tlen = nfsm_rndup(len); 161440296Smckusick /* 161540296Smckusick * This should not be necessary, but some servers have 161640296Smckusick * broken XDR such that these bytes are not null filled. 161740296Smckusick */ 161840296Smckusick if (tlen != len) { 161940296Smckusick *dpos = '\0'; /* Null-terminate */ 162040296Smckusick nfsm_adv(tlen - len); 162140296Smckusick len = tlen; 162240296Smckusick } 162356289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 162454986Smckusick off = fxdr_unsigned(u_long, *tl); 162548054Smckusick *tl++ = 0; /* Ensures null termination of name */ 162648054Smckusick more_dirs = fxdr_unsigned(int, *tl); 162756289Smckusick dp->d_reclen = len + 4 * NFSX_UNSIGNED; 162840296Smckusick siz += dp->d_reclen; 162940296Smckusick } 163040296Smckusick /* 163140296Smckusick * If at end of rpc data, get the eof boolean 163240296Smckusick */ 163340296Smckusick if (!more_dirs) { 163452196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 163548054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 163638414Smckusick 163740296Smckusick /* 163840296Smckusick * If at EOF, cache directory offset 163940296Smckusick */ 164041905Smckusick if (!more_dirs) 164140296Smckusick np->n_direofoffset = off; 164238414Smckusick } 164340296Smckusick /* 164440296Smckusick * If there is too much to fit in the data buffer, use savoff and 164540296Smckusick * savdp to trim off the last record. 164640296Smckusick * --> we are not at eof 164740296Smckusick */ 164840296Smckusick if (siz > uiop->uio_resid) { 164940296Smckusick off = savoff; 165040296Smckusick siz -= dp->d_reclen; 165140296Smckusick dp = savdp; 165240296Smckusick more_dirs = 0; /* Paranoia */ 165340113Smckusick } 165440296Smckusick if (siz > 0) { 165541905Smckusick lastlen = dp->d_reclen; 165640296Smckusick md = md2; 165740296Smckusick dpos = dpos2; 165840296Smckusick nfsm_mtouio(uiop, siz); 165956289Smckusick uiop->uio_offset = (off_t)off; 166040296Smckusick } else 166140296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 166240296Smckusick m_freem(mrep); 166338414Smckusick } 166441905Smckusick /* 166548054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 166641905Smckusick * by increasing d_reclen for the last record. 166741905Smckusick */ 166841905Smckusick if (uiop->uio_resid < tresid) { 166948054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 167041905Smckusick if (len > 0) { 167154740Smckusick dp = (struct dirent *) 167241905Smckusick (uiop->uio_iov->iov_base - lastlen); 167341905Smckusick dp->d_reclen += len; 167441905Smckusick uiop->uio_iov->iov_base += len; 167541905Smckusick uiop->uio_iov->iov_len -= len; 167641905Smckusick uiop->uio_resid -= len; 167741905Smckusick } 167841905Smckusick } 167940296Smckusick nfsmout: 168038414Smckusick return (error); 168138414Smckusick } 168238414Smckusick 168352196Smckusick /* 168456289Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc(). 168552196Smckusick */ 168652234Sheideman int 168752196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 168852196Smckusick struct vnode *vp; 168952196Smckusick register struct uio *uiop; 169052196Smckusick struct ucred *cred; 169152196Smckusick { 169252196Smckusick register int len; 169354740Smckusick register struct dirent *dp; 169452196Smckusick register u_long *tl; 169552196Smckusick register caddr_t cp; 169652196Smckusick register long t1; 169752196Smckusick caddr_t bpos, dpos, cp2; 169852196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 169952196Smckusick struct nameidata nami, *ndp = &nami; 170052317Sheideman struct componentname *cnp = &ndp->ni_cnd; 170156289Smckusick u_long off, endoff, fileno; 170252196Smckusick time_t reqtime, ltime; 170352196Smckusick struct nfsmount *nmp; 170452196Smckusick struct nfsnode *np, *tp; 170552196Smckusick struct vnode *newvp; 170652196Smckusick nfsv2fh_t *fhp; 170752196Smckusick u_quad_t frev; 170852196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 170952196Smckusick int cachable; 171052196Smckusick 171152196Smckusick if (uiop->uio_iovcnt != 1) 171252196Smckusick panic("nfs rdirlook"); 171352196Smckusick nmp = VFSTONFS(vp->v_mount); 171452196Smckusick tresid = uiop->uio_resid; 171552196Smckusick ndp->ni_dvp = vp; 171652196Smckusick newvp = NULLVP; 171752196Smckusick /* 171852196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 171952196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 172052196Smckusick * The stopping criteria is EOF or buffer full. 172152196Smckusick */ 172252196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 172352196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 172452196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 172556289Smckusick NFSX_FH + 3 * NFSX_UNSIGNED); 172652196Smckusick nfsm_fhtom(vp); 172756289Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 172856289Smckusick off = (u_long)uiop->uio_offset; 172956289Smckusick *tl++ = txdr_unsigned(off); 173052196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 173152196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 173256289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) 173356289Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 173456289Smckusick else 173556289Smckusick *tl = 0; 173652196Smckusick reqtime = time.tv_sec; 173752196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 173852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 173952196Smckusick more_dirs = fxdr_unsigned(int, *tl); 174052196Smckusick 174152196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 174252196Smckusick bigenough = 1; 174352196Smckusick while (more_dirs && bigenough) { 174452196Smckusick doit = 1; 174556289Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 174656289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) { 174756289Smckusick cachable = fxdr_unsigned(int, *tl++); 174856289Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 174956289Smckusick fxdr_hyper(tl, &frev); 175056289Smckusick } 175152196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 175252196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 175352196Smckusick VREF(vp); 175452196Smckusick newvp = vp; 175552196Smckusick np = VTONFS(vp); 175652196Smckusick } else { 175752196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 175852196Smckusick doit = 0; 175952196Smckusick newvp = NFSTOV(np); 176052196Smckusick } 176152196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 176252196Smckusick (struct vattr *)0)) 176352196Smckusick doit = 0; 176456289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 176552196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 176652196Smckusick len = fxdr_unsigned(int, *tl); 176752196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 176852196Smckusick error = EBADRPC; 176952196Smckusick m_freem(mrep); 177052196Smckusick goto nfsmout; 177152196Smckusick } 177252196Smckusick tlen = (len + 4) & ~0x3; 177352196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 177452196Smckusick bigenough = 0; 177552196Smckusick if (bigenough && doit) { 177654740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base; 177754740Smckusick dp->d_fileno = fileno; 177852196Smckusick dp->d_namlen = len; 177952196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 178054986Smckusick dp->d_type = 178154986Smckusick IFTODT(VTTOIF(np->n_vattr.va_type)); 178252196Smckusick uiop->uio_resid -= DIRHDSIZ; 178352196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 178452196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 178552317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 178652317Sheideman cnp->cn_namelen = len; 178752196Smckusick ndp->ni_vp = newvp; 178852196Smckusick nfsm_mtouio(uiop, len); 178952196Smckusick cp = uiop->uio_iov->iov_base; 179052196Smckusick tlen -= len; 179152196Smckusick for (i = 0; i < tlen; i++) 179252196Smckusick *cp++ = '\0'; 179352196Smckusick uiop->uio_iov->iov_base += tlen; 179452196Smckusick uiop->uio_iov->iov_len -= tlen; 179552196Smckusick uiop->uio_resid -= tlen; 179652317Sheideman cnp->cn_hash = 0; 179752317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 179852317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 179956289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 180056289Smckusick ltime > time.tv_sec) 180156289Smckusick nqnfs_clientlease(nmp, np, NQL_READ, 180256289Smckusick cachable, ltime, frev); 180356927Smckusick if (cnp->cn_namelen <= NCHNAMLEN) 180457791Smckusick cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 180552196Smckusick } else { 180652196Smckusick nfsm_adv(nfsm_rndup(len)); 180752196Smckusick } 180852196Smckusick if (newvp != NULLVP) { 180952196Smckusick vrele(newvp); 181052196Smckusick newvp = NULLVP; 181152196Smckusick } 181256289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 181352196Smckusick if (bigenough) 181456289Smckusick endoff = off = fxdr_unsigned(u_long, *tl++); 181552196Smckusick else 181656289Smckusick endoff = fxdr_unsigned(u_long, *tl++); 181752196Smckusick more_dirs = fxdr_unsigned(int, *tl); 181852196Smckusick } 181952196Smckusick /* 182052196Smckusick * If at end of rpc data, get the eof boolean 182152196Smckusick */ 182252196Smckusick if (!more_dirs) { 182352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 182452196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 182552196Smckusick 182652196Smckusick /* 182752196Smckusick * If at EOF, cache directory offset 182852196Smckusick */ 182952196Smckusick if (!more_dirs) 183052196Smckusick VTONFS(vp)->n_direofoffset = endoff; 183152196Smckusick } 183252196Smckusick if (uiop->uio_resid < tresid) 183356289Smckusick uiop->uio_offset = (off_t)off; 183452196Smckusick else 183552196Smckusick more_dirs = 0; 183652196Smckusick m_freem(mrep); 183752196Smckusick } 183852196Smckusick /* 183952196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 184052196Smckusick * by increasing d_reclen for the last record. 184152196Smckusick */ 184252196Smckusick if (uiop->uio_resid < tresid) { 184352196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 184452196Smckusick if (len > 0) { 184552196Smckusick dp->d_reclen += len; 184652196Smckusick uiop->uio_iov->iov_base += len; 184752196Smckusick uiop->uio_iov->iov_len -= len; 184852196Smckusick uiop->uio_resid -= len; 184952196Smckusick } 185052196Smckusick } 185152196Smckusick nfsmout: 185252196Smckusick if (newvp != NULLVP) 185352196Smckusick vrele(newvp); 185452196Smckusick return (error); 185552196Smckusick } 185639488Smckusick static char hextoasc[] = "0123456789abcdef"; 185738414Smckusick 185838414Smckusick /* 185938414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 186038414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 186138414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 186238414Smckusick * nfsnode. There is the potential for another process on a different client 186338414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 186438414Smckusick * nfs_rename() completes, but... 186538414Smckusick */ 186652234Sheideman int 186752317Sheideman nfs_sillyrename(dvp, vp, cnp) 186852234Sheideman struct vnode *dvp, *vp; 186952234Sheideman struct componentname *cnp; 187038414Smckusick { 187138414Smckusick register struct nfsnode *np; 187238414Smckusick register struct sillyrename *sp; 187338414Smckusick int error; 187438414Smckusick short pid; 187538414Smckusick 187652234Sheideman cache_purge(dvp); 187752234Sheideman np = VTONFS(vp); 187851986Smckusick #ifdef SILLYSEPARATE 187938414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 188048364Smckusick M_NFSREQ, M_WAITOK); 188151986Smckusick #else 188251986Smckusick sp = &np->n_silly; 188351986Smckusick #endif 188452234Sheideman sp->s_cred = crdup(cnp->cn_cred); 188552234Sheideman sp->s_dvp = dvp; 188652234Sheideman VREF(dvp); 188738414Smckusick 188838414Smckusick /* Fudge together a funny name */ 188952234Sheideman pid = cnp->cn_proc->p_pid; 189048364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 189148364Smckusick sp->s_namlen = 12; 189248364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 189348364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 189448364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 189548364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 189638414Smckusick 189738414Smckusick /* Try lookitups until we get one that isn't there */ 189852234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 189948364Smckusick sp->s_name[4]++; 190048364Smckusick if (sp->s_name[4] > 'z') { 190138414Smckusick error = EINVAL; 190238414Smckusick goto bad; 190338414Smckusick } 190438414Smckusick } 190552234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 190638414Smckusick goto bad; 190752234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 190838414Smckusick np->n_sillyrename = sp; 190938414Smckusick return (0); 191038414Smckusick bad: 191148364Smckusick vrele(sp->s_dvp); 191248364Smckusick crfree(sp->s_cred); 191351986Smckusick #ifdef SILLYSEPARATE 191448364Smckusick free((caddr_t)sp, M_NFSREQ); 191551986Smckusick #endif 191638414Smckusick return (error); 191738414Smckusick } 191838414Smckusick 191938414Smckusick /* 192038414Smckusick * Look up a file name for silly rename stuff. 192138414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 192238414Smckusick * into the nfsnode table. 192338414Smckusick * If fhp != NULL it copies the returned file handle out 192438414Smckusick */ 192552234Sheideman int 192652196Smckusick nfs_lookitup(sp, fhp, procp) 192748364Smckusick register struct sillyrename *sp; 192838414Smckusick nfsv2fh_t *fhp; 192952196Smckusick struct proc *procp; 193038414Smckusick { 193148364Smckusick register struct vnode *vp = sp->s_dvp; 193248054Smckusick register u_long *tl; 193339488Smckusick register caddr_t cp; 193439488Smckusick register long t1, t2; 193539488Smckusick caddr_t bpos, dpos, cp2; 193639488Smckusick u_long xid; 193756289Smckusick int error = 0, isnq; 193839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 193938414Smckusick long len; 194038414Smckusick 194156289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 194238414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 194348364Smckusick len = sp->s_namlen; 194452196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 194556289Smckusick if (isnq) { 194656289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 194756289Smckusick *tl = 0; 194856289Smckusick } 194938414Smckusick nfsm_fhtom(vp); 195048364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 195152196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 195238414Smckusick if (fhp != NULL) { 195356289Smckusick if (isnq) 195456289Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 195552196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 195638414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 195738414Smckusick } 195838414Smckusick nfsm_reqdone; 195938414Smckusick return (error); 196038414Smckusick } 196138414Smckusick 196238414Smckusick /* 196338414Smckusick * Kludge City.. 196438414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 196541905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 196638414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 196738414Smckusick * nfsiobuf area. 196838414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 196938414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 197038414Smckusick * a lot more work than bcopy() and also it currently happens in the 197138414Smckusick * context of the swapper process (2). 197238414Smckusick */ 197352234Sheideman int 197453806Smckusick nfs_bmap(ap) 197554668Smckusick struct vop_bmap_args /* { 197654668Smckusick struct vnode *a_vp; 197754668Smckusick daddr_t a_bn; 197854668Smckusick struct vnode **a_vpp; 197954668Smckusick daddr_t *a_bnp; 198056452Smargo int *a_runp; 198154668Smckusick } */ *ap; 198238414Smckusick { 198353806Smckusick register struct vnode *vp = ap->a_vp; 198453806Smckusick 198553600Sheideman if (ap->a_vpp != NULL) 198653806Smckusick *ap->a_vpp = vp; 198753600Sheideman if (ap->a_bnp != NULL) 198853806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 198938414Smckusick return (0); 199038414Smckusick } 199138414Smckusick 199238414Smckusick /* 199357791Smckusick * Strategy routine. 199457791Smckusick * For async requests when nfsiod(s) are running, queue the request by 199557791Smckusick * calling nfs_asyncio(), otherwise just all nfs_doio() to do the 199657791Smckusick * request. 199738414Smckusick */ 199852234Sheideman int 199953806Smckusick nfs_strategy(ap) 200057791Smckusick struct vop_strategy_args *ap; 200138414Smckusick { 200253806Smckusick register struct buf *bp = ap->a_bp; 200357791Smckusick struct ucred *cr; 200457791Smckusick struct proc *p; 200538884Smacklem int error = 0; 200638884Smacklem 200757791Smckusick if (bp->b_flags & B_PHYS) 200857791Smckusick panic("nfs physio"); 200957791Smckusick if (bp->b_flags & B_ASYNC) 201057791Smckusick p = (struct proc *)0; 201157791Smckusick else 201257791Smckusick p = curproc; /* XXX */ 201357791Smckusick if (bp->b_flags & B_READ) 201457791Smckusick cr = bp->b_rcred; 201557791Smckusick else 201657791Smckusick cr = bp->b_wcred; 201738884Smacklem /* 201846450Skarels * If the op is asynchronous and an i/o daemon is waiting 201938884Smacklem * queue the request, wake it up and wait for completion 202046450Skarels * otherwise just do it ourselves. 202138884Smacklem */ 202257791Smckusick if ((bp->b_flags & B_ASYNC) == 0 || 202357791Smckusick nfs_asyncio(bp, NOCRED)) 202457791Smckusick error = nfs_doio(bp, cr, p); 202538884Smacklem return (error); 202638884Smacklem } 202738884Smacklem 202838884Smacklem /* 202948054Smckusick * Mmap a file 203048054Smckusick * 203148054Smckusick * NB Currently unsupported. 203248054Smckusick */ 203348054Smckusick /* ARGSUSED */ 203452234Sheideman int 203553806Smckusick nfs_mmap(ap) 203654668Smckusick struct vop_mmap_args /* { 203754668Smckusick struct vnode *a_vp; 203854668Smckusick int a_fflags; 203954668Smckusick struct ucred *a_cred; 204054668Smckusick struct proc *a_p; 204154668Smckusick } */ *ap; 204248054Smckusick { 204348054Smckusick 204448054Smckusick return (EINVAL); 204548054Smckusick } 204648054Smckusick 204748054Smckusick /* 204838884Smacklem * Flush all the blocks associated with a vnode. 204938884Smacklem * Walk through the buffer pool and push any dirty pages 205038884Smacklem * associated with the vnode. 205138884Smacklem */ 205239488Smckusick /* ARGSUSED */ 205352234Sheideman int 205453806Smckusick nfs_fsync(ap) 205554451Smckusick struct vop_fsync_args /* { 205654451Smckusick struct vnodeop_desc *a_desc; 205754451Smckusick struct vnode * a_vp; 205854451Smckusick struct ucred * a_cred; 205954451Smckusick int a_waitfor; 206054451Smckusick struct proc * a_p; 206154451Smckusick } */ *ap; 206238884Smacklem { 206354451Smckusick register struct vnode *vp = ap->a_vp; 206454451Smckusick register struct nfsnode *np = VTONFS(vp); 206554451Smckusick register struct buf *bp; 206654451Smckusick struct buf *nbp; 206757791Smckusick struct nfsmount *nmp; 206857791Smckusick int s, error = 0, slptimeo = 0, slpflag = 0; 206938884Smacklem 207057791Smckusick nmp = VFSTONFS(vp->v_mount); 207157791Smckusick if (nmp->nm_flag & NFSMNT_INT) 207257791Smckusick slpflag = PCATCH; 207354451Smckusick loop: 207454451Smckusick s = splbio(); 207556468Smckusick for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) { 207656468Smckusick nbp = bp->b_vnbufs.qe_next; 207757791Smckusick if (bp->b_flags & B_BUSY) { 207857791Smckusick if (ap->a_waitfor != MNT_WAIT) 207957791Smckusick continue; 208057791Smckusick bp->b_flags |= B_WANTED; 208157791Smckusick error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), 208257791Smckusick "nfsfsync", slptimeo); 208357791Smckusick splx(s); 208457791Smckusick if (error) { 208557791Smckusick if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p)) 208657791Smckusick return (EINTR); 208757791Smckusick if (slpflag == PCATCH) { 208857791Smckusick slpflag = 0; 208957791Smckusick slptimeo = 2 * hz; 209057791Smckusick } 209157791Smckusick } 209257791Smckusick goto loop; 209357791Smckusick } 209454451Smckusick if ((bp->b_flags & B_DELWRI) == 0) 209554451Smckusick panic("nfs_fsync: not dirty"); 209654451Smckusick bremfree(bp); 209754451Smckusick bp->b_flags |= B_BUSY; 209854451Smckusick splx(s); 209957791Smckusick bp->b_flags |= B_ASYNC; 210057791Smckusick VOP_BWRITE(bp); 210154451Smckusick goto loop; 210238884Smacklem } 210357791Smckusick splx(s); 210454451Smckusick if (ap->a_waitfor == MNT_WAIT) { 210554451Smckusick while (vp->v_numoutput) { 210654451Smckusick vp->v_flag |= VBWAIT; 210757791Smckusick error = tsleep((caddr_t)&vp->v_numoutput, 210857791Smckusick slpflag | (PRIBIO + 1), "nfsfsync", slptimeo); 210957791Smckusick if (error) { 211057791Smckusick if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p)) 211157791Smckusick return (EINTR); 211257791Smckusick if (slpflag == PCATCH) { 211357791Smckusick slpflag = 0; 211457791Smckusick slptimeo = 2 * hz; 211557791Smckusick } 211657791Smckusick } 211754451Smckusick } 211857791Smckusick if (vp->v_dirtyblkhd.le_next) { 211954451Smckusick #ifdef DIAGNOSTIC 212054451Smckusick vprint("nfs_fsync: dirty", vp); 212157791Smckusick #endif 212254451Smckusick goto loop; 212354451Smckusick } 212454451Smckusick } 212553629Smckusick if (np->n_flag & NWRITEERR) { 212639751Smckusick error = np->n_error; 212753629Smckusick np->n_flag &= ~NWRITEERR; 212853629Smckusick } 212938884Smacklem return (error); 213038884Smacklem } 213139672Smckusick 213239672Smckusick /* 2133*60400Smckusick * Return POSIX pathconf information applicable to nfs. 2134*60400Smckusick * 2135*60400Smckusick * Currently the NFS protocol does not support getting such 2136*60400Smckusick * information from the remote server. 2137*60400Smckusick */ 2138*60400Smckusick /* ARGSUSED */ 2139*60400Smckusick nfs_pathconf(ap) 2140*60400Smckusick struct vop_pathconf_args /* { 2141*60400Smckusick struct vnode *a_vp; 2142*60400Smckusick int a_name; 2143*60400Smckusick int *a_retval; 2144*60400Smckusick } */ *ap; 2145*60400Smckusick { 2146*60400Smckusick 2147*60400Smckusick return (EINVAL); 2148*60400Smckusick } 2149*60400Smckusick 2150*60400Smckusick /* 215146201Smckusick * NFS advisory byte-level locks. 215246201Smckusick * Currently unsupported. 215346201Smckusick */ 215452234Sheideman int 215553806Smckusick nfs_advlock(ap) 215654668Smckusick struct vop_advlock_args /* { 215754668Smckusick struct vnode *a_vp; 215854668Smckusick caddr_t a_id; 215954668Smckusick int a_op; 216054668Smckusick struct flock *a_fl; 216154668Smckusick int a_flags; 216254668Smckusick } */ *ap; 216346201Smckusick { 216446201Smckusick 216546201Smckusick return (EOPNOTSUPP); 216646201Smckusick } 216746201Smckusick 216846201Smckusick /* 216939672Smckusick * Print out the contents of an nfsnode. 217039672Smckusick */ 217152234Sheideman int 217253806Smckusick nfs_print(ap) 217354668Smckusick struct vop_print_args /* { 217454668Smckusick struct vnode *a_vp; 217554668Smckusick } */ *ap; 217639672Smckusick { 217753806Smckusick register struct vnode *vp = ap->a_vp; 217853806Smckusick register struct nfsnode *np = VTONFS(vp); 217939672Smckusick 218040294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 218140294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 218240294Smckusick #ifdef FIFO 218353806Smckusick if (vp->v_type == VFIFO) 218453806Smckusick fifo_printinfo(vp); 218540294Smckusick #endif /* FIFO */ 218639914Smckusick printf("\n"); 218739672Smckusick } 218851573Smckusick 218951573Smckusick /* 219051573Smckusick * NFS directory offset lookup. 219151573Smckusick * Currently unsupported. 219251573Smckusick */ 219352234Sheideman int 219453806Smckusick nfs_blkatoff(ap) 219554668Smckusick struct vop_blkatoff_args /* { 219654668Smckusick struct vnode *a_vp; 219754668Smckusick off_t a_offset; 219854668Smckusick char **a_res; 219954668Smckusick struct buf **a_bpp; 220054668Smckusick } */ *ap; 220151573Smckusick { 220251573Smckusick 220351573Smckusick return (EOPNOTSUPP); 220451573Smckusick } 220551573Smckusick 220651573Smckusick /* 220751573Smckusick * NFS flat namespace allocation. 220851573Smckusick * Currently unsupported. 220951573Smckusick */ 221052234Sheideman int 221153806Smckusick nfs_valloc(ap) 221254668Smckusick struct vop_valloc_args /* { 221354668Smckusick struct vnode *a_pvp; 221454668Smckusick int a_mode; 221554668Smckusick struct ucred *a_cred; 221654668Smckusick struct vnode **a_vpp; 221754668Smckusick } */ *ap; 221851573Smckusick { 221951573Smckusick 222051573Smckusick return (EOPNOTSUPP); 222151573Smckusick } 222251573Smckusick 222351573Smckusick /* 222451573Smckusick * NFS flat namespace free. 222551573Smckusick * Currently unsupported. 222651573Smckusick */ 222753582Sheideman int 222853806Smckusick nfs_vfree(ap) 222954668Smckusick struct vop_vfree_args /* { 223054668Smckusick struct vnode *a_pvp; 223154668Smckusick ino_t a_ino; 223254668Smckusick int a_mode; 223354668Smckusick } */ *ap; 223451573Smckusick { 223551573Smckusick 223653582Sheideman return (EOPNOTSUPP); 223751573Smckusick } 223851573Smckusick 223951573Smckusick /* 224051573Smckusick * NFS file truncation. 224151573Smckusick */ 224252234Sheideman int 224353806Smckusick nfs_truncate(ap) 224454668Smckusick struct vop_truncate_args /* { 224554668Smckusick struct vnode *a_vp; 224654668Smckusick off_t a_length; 224754668Smckusick int a_flags; 224854668Smckusick struct ucred *a_cred; 224954668Smckusick struct proc *a_p; 225054668Smckusick } */ *ap; 225151573Smckusick { 225251573Smckusick 225351573Smckusick /* Use nfs_setattr */ 225451573Smckusick printf("nfs_truncate: need to implement!!"); 225551573Smckusick return (EOPNOTSUPP); 225651573Smckusick } 225751573Smckusick 225851573Smckusick /* 225951573Smckusick * NFS update. 226051573Smckusick */ 226152234Sheideman int 226253806Smckusick nfs_update(ap) 226354668Smckusick struct vop_update_args /* { 226454668Smckusick struct vnode *a_vp; 226554668Smckusick struct timeval *a_ta; 226654668Smckusick struct timeval *a_tm; 226754668Smckusick int a_waitfor; 226854668Smckusick } */ *ap; 226951573Smckusick { 227051573Smckusick 227151573Smckusick /* Use nfs_setattr */ 227251573Smckusick printf("nfs_update: need to implement!!"); 227351573Smckusick return (EOPNOTSUPP); 227451573Smckusick } 227553629Smckusick 227653629Smckusick /* 227756364Smckusick * nfs special file access vnode op. 227856364Smckusick * Essentially just get vattr and then imitate iaccess() since the device is 227956364Smckusick * local to the client. 228056364Smckusick */ 228156364Smckusick int 228256364Smckusick nfsspec_access(ap) 228356364Smckusick struct vop_access_args /* { 228456364Smckusick struct vnode *a_vp; 228556364Smckusick int a_mode; 228656364Smckusick struct ucred *a_cred; 228756364Smckusick struct proc *a_p; 228856364Smckusick } */ *ap; 228956364Smckusick { 229056364Smckusick register struct vattr *vap; 229156364Smckusick register gid_t *gp; 229256364Smckusick register struct ucred *cred = ap->a_cred; 229356364Smckusick mode_t mode = ap->a_mode; 229456364Smckusick struct vattr vattr; 229556364Smckusick register int i; 229656364Smckusick int error; 229756364Smckusick 229856364Smckusick /* 229956364Smckusick * If you're the super-user, 230056364Smckusick * you always get access. 230156364Smckusick */ 230256364Smckusick if (cred->cr_uid == 0) 230356364Smckusick return (0); 230456364Smckusick vap = &vattr; 230556364Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 230656364Smckusick return (error); 230756364Smckusick /* 230856364Smckusick * Access check is based on only one of owner, group, public. 230956364Smckusick * If not owner, then check group. If not a member of the 231056364Smckusick * group, then check public access. 231156364Smckusick */ 231256364Smckusick if (cred->cr_uid != vap->va_uid) { 231356364Smckusick mode >>= 3; 231456364Smckusick gp = cred->cr_groups; 231556364Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 231656364Smckusick if (vap->va_gid == *gp) 231756364Smckusick goto found; 231856364Smckusick mode >>= 3; 231956364Smckusick found: 232056364Smckusick ; 232156364Smckusick } 232256708Smckusick return ((vap->va_mode & mode) == mode ? 0 : EACCES); 232356364Smckusick } 232456364Smckusick 232556364Smckusick /* 232653629Smckusick * Read wrapper for special devices. 232753629Smckusick */ 232853629Smckusick int 232953629Smckusick nfsspec_read(ap) 233054668Smckusick struct vop_read_args /* { 233154668Smckusick struct vnode *a_vp; 233254668Smckusick struct uio *a_uio; 233354668Smckusick int a_ioflag; 233454668Smckusick struct ucred *a_cred; 233554668Smckusick } */ *ap; 233653629Smckusick { 233754032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 233853629Smckusick 233953629Smckusick /* 234053629Smckusick * Set access flag. 234153629Smckusick */ 234254032Smckusick np->n_flag |= NACC; 234354032Smckusick np->n_atim = time; 234453629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 234553629Smckusick } 234653629Smckusick 234753629Smckusick /* 234853629Smckusick * Write wrapper for special devices. 234953629Smckusick */ 235053629Smckusick int 235153629Smckusick nfsspec_write(ap) 235254668Smckusick struct vop_write_args /* { 235354668Smckusick struct vnode *a_vp; 235454668Smckusick struct uio *a_uio; 235554668Smckusick int a_ioflag; 235654668Smckusick struct ucred *a_cred; 235754668Smckusick } */ *ap; 235853629Smckusick { 235954032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 236053629Smckusick 236153629Smckusick /* 236254032Smckusick * Set update flag. 236353629Smckusick */ 236454032Smckusick np->n_flag |= NUPD; 236554032Smckusick np->n_mtim = time; 236653629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 236753629Smckusick } 236853629Smckusick 236953629Smckusick /* 237053629Smckusick * Close wrapper for special devices. 237153629Smckusick * 237253629Smckusick * Update the times on the nfsnode then do device close. 237353629Smckusick */ 237453629Smckusick int 237553629Smckusick nfsspec_close(ap) 237654668Smckusick struct vop_close_args /* { 237754668Smckusick struct vnode *a_vp; 237854668Smckusick int a_fflag; 237954668Smckusick struct ucred *a_cred; 238054668Smckusick struct proc *a_p; 238154668Smckusick } */ *ap; 238253629Smckusick { 238353806Smckusick register struct vnode *vp = ap->a_vp; 238453806Smckusick register struct nfsnode *np = VTONFS(vp); 238553629Smckusick struct vattr vattr; 238653629Smckusick 238753629Smckusick if (np->n_flag & (NACC | NUPD)) { 238853629Smckusick np->n_flag |= NCHG; 238953806Smckusick if (vp->v_usecount == 1 && 239053806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 239153629Smckusick VATTR_NULL(&vattr); 239254106Smckusick if (np->n_flag & NACC) { 239354106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 239454106Smckusick vattr.va_atime.ts_nsec = 239554106Smckusick np->n_atim.tv_usec * 1000; 239654106Smckusick } 239754106Smckusick if (np->n_flag & NUPD) { 239854106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 239954106Smckusick vattr.va_mtime.ts_nsec = 240054106Smckusick np->n_mtim.tv_usec * 1000; 240154106Smckusick } 240253806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 240353629Smckusick } 240453629Smckusick } 240553629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 240653629Smckusick } 240753629Smckusick 240853629Smckusick #ifdef FIFO 240953629Smckusick /* 241053629Smckusick * Read wrapper for fifos. 241153629Smckusick */ 241253629Smckusick int 241353629Smckusick nfsfifo_read(ap) 241454668Smckusick struct vop_read_args /* { 241554668Smckusick struct vnode *a_vp; 241654668Smckusick struct uio *a_uio; 241754668Smckusick int a_ioflag; 241854668Smckusick struct ucred *a_cred; 241954668Smckusick } */ *ap; 242053629Smckusick { 242153629Smckusick extern int (**fifo_vnodeop_p)(); 242254032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 242353629Smckusick 242453629Smckusick /* 242553629Smckusick * Set access flag. 242653629Smckusick */ 242754032Smckusick np->n_flag |= NACC; 242854032Smckusick np->n_atim = time; 242953629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 243053629Smckusick } 243153629Smckusick 243253629Smckusick /* 243353629Smckusick * Write wrapper for fifos. 243453629Smckusick */ 243553629Smckusick int 243653629Smckusick nfsfifo_write(ap) 243754668Smckusick struct vop_write_args /* { 243854668Smckusick struct vnode *a_vp; 243954668Smckusick struct uio *a_uio; 244054668Smckusick int a_ioflag; 244154668Smckusick struct ucred *a_cred; 244254668Smckusick } */ *ap; 244353629Smckusick { 244453629Smckusick extern int (**fifo_vnodeop_p)(); 244554032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 244653629Smckusick 244753629Smckusick /* 244853629Smckusick * Set update flag. 244953629Smckusick */ 245054032Smckusick np->n_flag |= NUPD; 245154032Smckusick np->n_mtim = time; 245253629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 245353629Smckusick } 245453629Smckusick 245553629Smckusick /* 245653629Smckusick * Close wrapper for fifos. 245753629Smckusick * 245853629Smckusick * Update the times on the nfsnode then do fifo close. 245953629Smckusick */ 246053629Smckusick int 246153629Smckusick nfsfifo_close(ap) 246254668Smckusick struct vop_close_args /* { 246354668Smckusick struct vnode *a_vp; 246454668Smckusick int a_fflag; 246554668Smckusick struct ucred *a_cred; 246654668Smckusick struct proc *a_p; 246754668Smckusick } */ *ap; 246853629Smckusick { 246953806Smckusick register struct vnode *vp = ap->a_vp; 247053806Smckusick register struct nfsnode *np = VTONFS(vp); 247153629Smckusick struct vattr vattr; 247253629Smckusick extern int (**fifo_vnodeop_p)(); 247353629Smckusick 247453629Smckusick if (np->n_flag & (NACC | NUPD)) { 247553629Smckusick if (np->n_flag & NACC) 247653629Smckusick np->n_atim = time; 247753629Smckusick if (np->n_flag & NUPD) 247853629Smckusick np->n_mtim = time; 247953629Smckusick np->n_flag |= NCHG; 248053806Smckusick if (vp->v_usecount == 1 && 248153806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 248253629Smckusick VATTR_NULL(&vattr); 248354106Smckusick if (np->n_flag & NACC) { 248454106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 248554106Smckusick vattr.va_atime.ts_nsec = 248654106Smckusick np->n_atim.tv_usec * 1000; 248754106Smckusick } 248854106Smckusick if (np->n_flag & NUPD) { 248954106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 249054106Smckusick vattr.va_mtime.ts_nsec = 249154106Smckusick np->n_mtim.tv_usec * 1000; 249254106Smckusick } 249353806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 249453629Smckusick } 249553629Smckusick } 249653629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 249753629Smckusick } 249853629Smckusick #endif /* FIFO */ 2499