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*56390Smckusick * @(#)nfs_vnops.c 7.94 (Berkeley) 10/02/92 1138414Smckusick */ 1238414Smckusick 1338414Smckusick /* 1438414Smckusick * vnode op calls for sun nfs version 2 1538414Smckusick */ 1638414Smckusick 1753322Smckusick #include <sys/param.h> 1853322Smckusick #include <sys/proc.h> 1953322Smckusick #include <sys/kernel.h> 2053322Smckusick #include <sys/systm.h> 2153322Smckusick #include <sys/mount.h> 2253322Smckusick #include <sys/buf.h> 2353322Smckusick #include <sys/malloc.h> 2453322Smckusick #include <sys/mbuf.h> 2553322Smckusick #include <sys/conf.h> 2653322Smckusick #include <sys/namei.h> 2753322Smckusick #include <sys/vnode.h> 2853322Smckusick #include <sys/map.h> 2954740Smckusick #include <sys/dirent.h> 3047573Skarels 3153322Smckusick #include <vm/vm.h> 3238414Smckusick 3355041Smckusick #include <miscfs/specfs/specdev.h> 3455041Smckusick #include <miscfs/fifofs/fifo.h> 3555041Smckusick 3653322Smckusick #include <nfs/rpcv2.h> 3753322Smckusick #include <nfs/nfsv2.h> 3853322Smckusick #include <nfs/nfs.h> 3953322Smckusick #include <nfs/nfsnode.h> 4053322Smckusick #include <nfs/nfsmount.h> 4153322Smckusick #include <nfs/xdr_subs.h> 4253322Smckusick #include <nfs/nfsm_subs.h> 4353322Smckusick #include <nfs/nqnfs.h> 4453322Smckusick 4538414Smckusick /* Defs */ 4638414Smckusick #define TRUE 1 4738414Smckusick #define FALSE 0 4838414Smckusick 4948054Smckusick /* 5048054Smckusick * Global vfs data structures for nfs 5148054Smckusick */ 5253554Sheideman int (**nfsv2_vnodeop_p)(); 5353554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 5453554Sheideman { &vop_default_desc, vn_default_error }, 5553806Smckusick { &vop_lookup_desc, nfs_lookup }, /* lookup */ 5653806Smckusick { &vop_create_desc, nfs_create }, /* create */ 5753554Sheideman { &vop_mknod_desc, nfs_mknod }, /* mknod */ 5853554Sheideman { &vop_open_desc, nfs_open }, /* open */ 5953554Sheideman { &vop_close_desc, nfs_close }, /* close */ 6053806Smckusick { &vop_access_desc, nfs_access }, /* access */ 6153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 6253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 6353554Sheideman { &vop_read_desc, nfs_read }, /* read */ 6453554Sheideman { &vop_write_desc, nfs_write }, /* write */ 6553554Sheideman { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ 6653806Smckusick { &vop_select_desc, nfs_select }, /* select */ 6753554Sheideman { &vop_mmap_desc, nfs_mmap }, /* mmap */ 6853554Sheideman { &vop_fsync_desc, nfs_fsync }, /* fsync */ 6953554Sheideman { &vop_seek_desc, nfs_seek }, /* seek */ 7053806Smckusick { &vop_remove_desc, nfs_remove }, /* remove */ 7153554Sheideman { &vop_link_desc, nfs_link }, /* link */ 7253806Smckusick { &vop_rename_desc, nfs_rename }, /* rename */ 7353554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 7453554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 7553806Smckusick { &vop_symlink_desc, nfs_symlink }, /* symlink */ 7653806Smckusick { &vop_readdir_desc, nfs_readdir }, /* readdir */ 7753806Smckusick { &vop_readlink_desc, nfs_readlink }, /* readlink */ 7853806Smckusick { &vop_abortop_desc, nfs_abortop }, /* abortop */ 7953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 8053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 8153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 8253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 8353554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */ 8453806Smckusick { &vop_strategy_desc, nfs_strategy }, /* strategy */ 8553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 8653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 8753806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */ 8853806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */ 8953806Smckusick { &vop_valloc_desc, nfs_valloc }, /* valloc */ 9053554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */ 9153806Smckusick { &vop_truncate_desc, nfs_truncate }, /* truncate */ 9253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 9353582Sheideman { &vop_bwrite_desc, vn_bwrite }, 9453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 9538414Smckusick }; 9653554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 9753554Sheideman { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 9838414Smckusick 9948054Smckusick /* 10048054Smckusick * Special device vnode ops 10148054Smckusick */ 10253554Sheideman int (**spec_nfsv2nodeop_p)(); 10353554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 10453554Sheideman { &vop_default_desc, vn_default_error }, 10553806Smckusick { &vop_lookup_desc, spec_lookup }, /* lookup */ 10653806Smckusick { &vop_create_desc, spec_create }, /* create */ 10753806Smckusick { &vop_mknod_desc, spec_mknod }, /* mknod */ 10853554Sheideman { &vop_open_desc, spec_open }, /* open */ 10953806Smckusick { &vop_close_desc, nfsspec_close }, /* close */ 11056364Smckusick { &vop_access_desc, nfsspec_access }, /* access */ 11153806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 11253806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 11353806Smckusick { &vop_read_desc, nfsspec_read }, /* read */ 11453806Smckusick { &vop_write_desc, nfsspec_write }, /* write */ 11553806Smckusick { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 11653806Smckusick { &vop_select_desc, spec_select }, /* select */ 11753554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 11854451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 11953554Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 12053806Smckusick { &vop_remove_desc, spec_remove }, /* remove */ 12153554Sheideman { &vop_link_desc, spec_link }, /* link */ 12253806Smckusick { &vop_rename_desc, spec_rename }, /* rename */ 12353806Smckusick { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 12453806Smckusick { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 12553806Smckusick { &vop_symlink_desc, spec_symlink }, /* symlink */ 12653806Smckusick { &vop_readdir_desc, spec_readdir }, /* readdir */ 12753806Smckusick { &vop_readlink_desc, spec_readlink }, /* readlink */ 12853806Smckusick { &vop_abortop_desc, spec_abortop }, /* abortop */ 12953806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 13053806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 13153554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 13253806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 13353554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 13453806Smckusick { &vop_strategy_desc, spec_strategy }, /* strategy */ 13553554Sheideman { &vop_print_desc, nfs_print }, /* print */ 13653806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 13753806Smckusick { &vop_advlock_desc, spec_advlock }, /* advlock */ 13853806Smckusick { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 13953806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */ 14053806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */ 14153806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */ 14253806Smckusick { &vop_update_desc, nfs_update }, /* update */ 14353582Sheideman { &vop_bwrite_desc, vn_bwrite }, 14453554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 14538414Smckusick }; 14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 14753554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 14838414Smckusick 14940294Smckusick #ifdef FIFO 15053554Sheideman int (**fifo_nfsv2nodeop_p)(); 15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 15253554Sheideman { &vop_default_desc, vn_default_error }, 15353806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15453806Smckusick { &vop_create_desc, fifo_create }, /* create */ 15553806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15653554Sheideman { &vop_open_desc, fifo_open }, /* open */ 15753806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */ 15856364Smckusick { &vop_access_desc, nfsspec_access }, /* access */ 15953806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */ 16053806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */ 16153806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */ 16253806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */ 16353806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 16453806Smckusick { &vop_select_desc, fifo_select }, /* select */ 16553554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 16654451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */ 16753554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 16853806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */ 16953554Sheideman { &vop_link_desc, fifo_link }, /* link */ 17053806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */ 17153806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 17253806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 17353806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */ 17453806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */ 17553806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */ 17653806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */ 17753806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */ 17853806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 17953554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */ 18053806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */ 18153554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 18253806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */ 18353554Sheideman { &vop_print_desc, nfs_print }, /* print */ 18453806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */ 18553806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */ 18653806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 18753806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */ 18853806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */ 18953806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */ 19053806Smckusick { &vop_update_desc, nfs_update }, /* update */ 19153582Sheideman { &vop_bwrite_desc, vn_bwrite }, 19253554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 19340294Smckusick }; 19453554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 19553554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 19640294Smckusick #endif /* FIFO */ 19740294Smckusick 19856289Smckusick void nqnfs_clientlease(); 19956289Smckusick 20048054Smckusick /* 20152196Smckusick * Global variables 20248054Smckusick */ 20338414Smckusick extern u_long nfs_procids[NFS_NPROCS]; 20456364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false; 20538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20641905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 20746988Smckusick int nfs_numasync = 0; 208*56390Smckusick /* Queue head for nfsiod's */ 209*56390Smckusick struct buf *nfs_bqueuehead; 210*56390Smckusick struct buf **nfs_bqueuetail = &nfs_bqueuehead; 21154740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 21238414Smckusick 21338414Smckusick /* 21438414Smckusick * nfs null call from vfs. 21538414Smckusick */ 21652234Sheideman int 21752196Smckusick nfs_null(vp, cred, procp) 21838414Smckusick struct vnode *vp; 21938414Smckusick struct ucred *cred; 22052196Smckusick struct proc *procp; 22138414Smckusick { 22239488Smckusick caddr_t bpos, dpos; 22339488Smckusick int error = 0; 22439488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22538414Smckusick 22652196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22752196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 22838414Smckusick nfsm_reqdone; 22938414Smckusick return (error); 23038414Smckusick } 23138414Smckusick 23238414Smckusick /* 23338414Smckusick * nfs access vnode op. 23456364Smckusick * For nfs, just return ok. File accesses may fail later. 23556364Smckusick * For nqnfs, use the access rpc to check accessibility. If file modes are 23656364Smckusick * changed on the server, accesses might still fail later. 23738414Smckusick */ 23852234Sheideman int 23953806Smckusick nfs_access(ap) 24054668Smckusick struct vop_access_args /* { 24154668Smckusick struct vnode *a_vp; 24254668Smckusick int a_mode; 24354668Smckusick struct ucred *a_cred; 24454668Smckusick struct proc *a_p; 24554668Smckusick } */ *ap; 24638414Smckusick { 24756364Smckusick register struct vnode *vp = ap->a_vp; 24856364Smckusick register u_long *tl; 24956364Smckusick register caddr_t cp; 25056364Smckusick caddr_t bpos, dpos; 25156364Smckusick int error = 0; 25256364Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 25338414Smckusick 25438414Smckusick /* 25556364Smckusick * There is no way to check accessibility via. ordinary nfs, so if 25656364Smckusick * access isn't allowed they will get burned later. 25738414Smckusick */ 25856364Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 25956364Smckusick nfsstats.rpccnt[NQNFSPROC_ACCESS]++; 26056364Smckusick nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED); 26156364Smckusick nfsm_fhtom(vp); 26256364Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 26356364Smckusick if (ap->a_mode & VREAD) 26456364Smckusick *tl++ = nfs_true; 26556364Smckusick else 26656364Smckusick *tl++ = nfs_false; 26756364Smckusick if (ap->a_mode & VWRITE) 26856364Smckusick *tl++ = nfs_true; 26956364Smckusick else 27056364Smckusick *tl++ = nfs_false; 27156364Smckusick if (ap->a_mode & VEXEC) 27256364Smckusick *tl = nfs_true; 27356364Smckusick else 27456364Smckusick *tl = nfs_false; 27556364Smckusick nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred); 27656364Smckusick nfsm_reqdone; 27738884Smacklem return (error); 27856364Smckusick } else 27938414Smckusick return (0); 28038414Smckusick } 28138414Smckusick 28238414Smckusick /* 28338414Smckusick * nfs open vnode op 28456289Smckusick * Check to see if the type is ok 28552196Smckusick * and that deletion is not in progress. 28656289Smckusick * For paged in text files, you will need to flush the page cache 28756289Smckusick * if consistency is lost. 28838414Smckusick */ 28939488Smckusick /* ARGSUSED */ 29052234Sheideman int 29153806Smckusick nfs_open(ap) 29254668Smckusick struct vop_open_args /* { 29354668Smckusick struct vnode *a_vp; 29454668Smckusick int a_mode; 29554668Smckusick struct ucred *a_cred; 29654668Smckusick struct proc *a_p; 29754668Smckusick } */ *ap; 29838414Smckusick { 29953806Smckusick register struct vnode *vp = ap->a_vp; 30056289Smckusick struct nfsnode *np = VTONFS(vp); 30156289Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount); 30256289Smckusick struct vattr vattr; 30356289Smckusick int error; 30438414Smckusick 30553806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 30638414Smckusick return (EACCES); 30756289Smckusick if (vp->v_flag & VTEXT) { 30856289Smckusick /* 30956289Smckusick * Get a valid lease. If cached data is stale, flush it. 31056289Smckusick */ 31156289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 31256289Smckusick if (NQNFS_CKINVALID(vp, np, NQL_READ)) { 31356289Smckusick do { 31456289Smckusick error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p); 31556289Smckusick } while (error == NQNFS_EXPIRED); 31656289Smckusick if (error) 31756289Smckusick return (error); 31856289Smckusick if (np->n_lrev != np->n_brev) { 31956289Smckusick np->n_flag &= ~NMODIFIED; 32056289Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 32156289Smckusick (void) vnode_pager_uncache(vp); 32256289Smckusick np->n_brev = np->n_lrev; 32356289Smckusick } 32456289Smckusick } 32556289Smckusick } else { 32656289Smckusick if (np->n_flag & NMODIFIED) { 32756289Smckusick np->n_flag &= ~NMODIFIED; 32856289Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 32956289Smckusick (void) vnode_pager_uncache(vp); 33056289Smckusick np->n_attrstamp = 0; 33156289Smckusick np->n_direofoffset = 0; 33256289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 33356289Smckusick return (error); 33456289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 33556289Smckusick } else { 33656289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 33756289Smckusick return (error); 33856289Smckusick if (np->n_mtime != vattr.va_mtime.ts_sec) { 33956289Smckusick np->n_direofoffset = 0; 34056289Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 34156289Smckusick (void) vnode_pager_uncache(vp); 34256289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 34356289Smckusick } 34456289Smckusick } 34556289Smckusick } 34656289Smckusick } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 34756289Smckusick np->n_attrstamp = 0; /* For Open/Close consistency */ 34852196Smckusick return (0); 34938414Smckusick } 35038414Smckusick 35138414Smckusick /* 35238414Smckusick * nfs close vnode op 35338884Smacklem * For reg files, invalidate any buffer cache entries. 35438414Smckusick */ 35539488Smckusick /* ARGSUSED */ 35652234Sheideman int 35753806Smckusick nfs_close(ap) 35854451Smckusick struct vop_close_args /* { 35954451Smckusick struct vnodeop_desc *a_desc; 36054451Smckusick struct vnode *a_vp; 36154451Smckusick int a_fflag; 36254451Smckusick struct ucred *a_cred; 36354451Smckusick struct proc *a_p; 36454451Smckusick } */ *ap; 36538414Smckusick { 36653806Smckusick register struct vnode *vp = ap->a_vp; 36753806Smckusick register struct nfsnode *np = VTONFS(vp); 36839341Smckusick int error = 0; 36938414Smckusick 37053806Smckusick if (vp->v_type == VREG) { 37153806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 37253629Smckusick (np->n_flag & NMODIFIED)) { 37354451Smckusick error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 37441905Smckusick np->n_flag &= ~NMODIFIED; 37541905Smckusick np->n_attrstamp = 0; 37653629Smckusick } 37753629Smckusick if (np->n_flag & NWRITEERR) { 37853629Smckusick np->n_flag &= ~NWRITEERR; 37953629Smckusick error = np->n_error; 38053629Smckusick } 38138884Smacklem } 38238414Smckusick return (error); 38338414Smckusick } 38438414Smckusick 38538414Smckusick /* 38638414Smckusick * nfs getattr call from vfs. 38738414Smckusick */ 38852234Sheideman int 38953805Smckusick nfs_getattr(ap) 39054668Smckusick struct vop_getattr_args /* { 39154668Smckusick struct vnode *a_vp; 39254668Smckusick struct vattr *a_vap; 39354668Smckusick struct ucred *a_cred; 39454668Smckusick struct proc *a_p; 39554668Smckusick } */ *ap; 39638414Smckusick { 39753805Smckusick register struct vnode *vp = ap->a_vp; 39853805Smckusick register struct nfsnode *np = VTONFS(vp); 39939488Smckusick register caddr_t cp; 40039488Smckusick caddr_t bpos, dpos; 40139488Smckusick int error = 0; 40239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 40338414Smckusick 40453805Smckusick /* 40553805Smckusick * Update local times for special files. 40653805Smckusick */ 40756329Smckusick if (np->n_flag & (NACC | NUPD)) 40853805Smckusick np->n_flag |= NCHG; 40953805Smckusick /* 41053805Smckusick * First look in the cache. 41153805Smckusick */ 41253805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 41338414Smckusick return (0); 41438414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 41553805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 41653805Smckusick nfsm_fhtom(vp); 41753805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 41853805Smckusick nfsm_loadattr(vp, ap->a_vap); 41938414Smckusick nfsm_reqdone; 42038414Smckusick return (error); 42138414Smckusick } 42238414Smckusick 42338414Smckusick /* 42438414Smckusick * nfs setattr call. 42538414Smckusick */ 42652234Sheideman int 42753806Smckusick nfs_setattr(ap) 42854451Smckusick struct vop_setattr_args /* { 42954451Smckusick struct vnodeop_desc *a_desc; 43054451Smckusick struct vnode *a_vp; 43154451Smckusick struct vattr *a_vap; 43254451Smckusick struct ucred *a_cred; 43354451Smckusick struct proc *a_p; 43454451Smckusick } */ *ap; 43538414Smckusick { 43638884Smacklem register struct nfsv2_sattr *sp; 43739488Smckusick register caddr_t cp; 43839488Smckusick register long t1; 43952196Smckusick caddr_t bpos, dpos, cp2; 44052196Smckusick u_long *tl; 44156289Smckusick int error = 0, isnq; 44239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 44353806Smckusick register struct vnode *vp = ap->a_vp; 44453806Smckusick register struct nfsnode *np = VTONFS(vp); 44553806Smckusick register struct vattr *vap = ap->a_vap; 44652196Smckusick u_quad_t frev; 44738414Smckusick 44838414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 44956289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 45056289Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq)); 45153806Smckusick nfsm_fhtom(vp); 45256289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 45356289Smckusick if (vap->va_mode == (u_short)-1) 45438884Smacklem sp->sa_mode = VNOVAL; 45538414Smckusick else 45653806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 45756289Smckusick if (vap->va_uid == (uid_t)-1) 45838884Smacklem sp->sa_uid = VNOVAL; 45938414Smckusick else 46053806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 46156289Smckusick if (vap->va_gid == (gid_t)-1) 46238884Smacklem sp->sa_gid = VNOVAL; 46338414Smckusick else 46453806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 46556289Smckusick if (isnq) { 46656289Smckusick txdr_hyper(&vap->va_size, &sp->sa_nqsize); 46756289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 46856289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 46956289Smckusick sp->sa_nqflags = txdr_unsigned(vap->va_flags); 47056289Smckusick sp->sa_nqrdev = VNOVAL; 47156289Smckusick } else { 47256289Smckusick sp->sa_nfssize = txdr_unsigned(vap->va_size); 47356289Smckusick sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec); 47456289Smckusick sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags); 47556289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 47656289Smckusick } 47754106Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || 47854106Smckusick vap->va_atime.ts_sec != VNOVAL) { 47939359Smckusick if (np->n_flag & NMODIFIED) { 48053806Smckusick if (vap->va_size == 0) 48154451Smckusick error = 48254451Smckusick vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p); 48346988Smckusick else 48454451Smckusick error = 48554451Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 48654451Smckusick np->n_flag &= ~NMODIFIED; 48739359Smckusick } 48856289Smckusick if (vap->va_size != VNOVAL) 48956289Smckusick np->n_size = np->n_vattr.va_size = vap->va_size; 49039359Smckusick } 49153806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 49253806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 49353806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 49453806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 49552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 49652196Smckusick fxdr_hyper(tl, &frev); 49754451Smckusick if (frev > np->n_brev) 49852196Smckusick np->n_brev = frev; 49952196Smckusick } 50038414Smckusick nfsm_reqdone; 50138414Smckusick return (error); 50238414Smckusick } 50338414Smckusick 50438414Smckusick /* 50538414Smckusick * nfs lookup call, one step at a time... 50638414Smckusick * First look in cache 50738414Smckusick * If not found, unlock the directory nfsnode and do the rpc 50838414Smckusick */ 50952234Sheideman int 51053806Smckusick nfs_lookup(ap) 51154451Smckusick struct vop_lookup_args /* { 51254451Smckusick struct vnodeop_desc *a_desc; 51354451Smckusick struct vnode *a_dvp; 51454451Smckusick struct vnode **a_vpp; 51554451Smckusick struct componentname *a_cnp; 51654451Smckusick } */ *ap; 51738414Smckusick { 51853806Smckusick register struct componentname *cnp = ap->a_cnp; 51953806Smckusick register struct vnode *dvp = ap->a_dvp; 52054668Smckusick register struct vnode **vpp = ap->a_vpp; 52155184Smckusick register int flags = cnp->cn_flags; 52238414Smckusick register struct vnode *vdp; 52348054Smckusick register u_long *tl; 52439488Smckusick register caddr_t cp; 52539488Smckusick register long t1, t2; 52652196Smckusick struct nfsmount *nmp; 52752196Smckusick struct nfsnode *tp; 52839488Smckusick caddr_t bpos, dpos, cp2; 52952196Smckusick time_t reqtime; 53039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 53138414Smckusick struct vnode *newvp; 53238414Smckusick long len; 53338414Smckusick nfsv2fh_t *fhp; 53438414Smckusick struct nfsnode *np; 53552234Sheideman int lockparent, wantparent, error = 0; 53652196Smckusick int nqlflag, cachable; 53752196Smckusick u_quad_t frev; 53838414Smckusick 53954668Smckusick *vpp = NULL; 54053806Smckusick if (dvp->v_type != VDIR) 54138414Smckusick return (ENOTDIR); 54255184Smckusick lockparent = flags & LOCKPARENT; 54355184Smckusick wantparent = flags & (LOCKPARENT|WANTPARENT); 54453806Smckusick nmp = VFSTONFS(dvp->v_mount); 54553806Smckusick np = VTONFS(dvp); 54654668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 54738884Smacklem struct vattr vattr; 54838884Smacklem int vpid; 54938884Smacklem 55054668Smckusick vdp = *vpp; 55138884Smacklem vpid = vdp->v_id; 55238414Smckusick /* 55338884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 55438884Smacklem * for an explanation of the locking protocol 55538414Smckusick */ 55653806Smckusick if (dvp == vdp) { 55738425Smckusick VREF(vdp); 55839441Smckusick error = 0; 55952196Smckusick } else 56039441Smckusick error = vget(vdp); 56139441Smckusick if (!error) { 56240251Smckusick if (vpid == vdp->v_id) { 56352196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 56456289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) { 56556289Smckusick nfsstats.lookupcache_hits++; 56656289Smckusick if (cnp->cn_nameiop != LOOKUP && 56756289Smckusick (flags & ISLASTCN)) 56856289Smckusick cnp->cn_flags |= SAVENAME; 56956289Smckusick return (0); 57056289Smckusick } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 57154451Smckusick if (np->n_lrev != np->n_brev || 57252196Smckusick (np->n_flag & NMODIFIED)) { 57352196Smckusick np->n_direofoffset = 0; 57453806Smckusick cache_purge(dvp); 57554451Smckusick error = vinvalbuf(dvp, FALSE, 57654451Smckusick cnp->cn_cred, cnp->cn_proc); 57752196Smckusick np->n_flag &= ~NMODIFIED; 57852196Smckusick np->n_brev = np->n_lrev; 57952196Smckusick } else { 58052196Smckusick nfsstats.lookupcache_hits++; 58153806Smckusick if (cnp->cn_nameiop != LOOKUP && 58255184Smckusick (flags & ISLASTCN)) 58353806Smckusick cnp->cn_flags |= SAVENAME; 58452196Smckusick return (0); 58552196Smckusick } 58652196Smckusick } 58753806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 58854106Smckusick vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { 58939441Smckusick nfsstats.lookupcache_hits++; 59053806Smckusick if (cnp->cn_nameiop != LOOKUP && 59155184Smckusick (flags & ISLASTCN)) 59253806Smckusick cnp->cn_flags |= SAVENAME; 59339441Smckusick return (0); 59440251Smckusick } 59547289Smckusick cache_purge(vdp); 59639441Smckusick } 59752196Smckusick vrele(vdp); 59838884Smacklem } 59954668Smckusick *vpp = NULLVP; 60052196Smckusick } 60139341Smckusick error = 0; 60238414Smckusick nfsstats.lookupcache_misses++; 60338414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 60453806Smckusick len = cnp->cn_namelen; 60553806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 60652196Smckusick 60752196Smckusick /* 60852196Smckusick * For nqnfs optionally piggyback a getlease request for the name 60952196Smckusick * being looked up. 61052196Smckusick */ 61152196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 61256289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 61352196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 61455184Smckusick ((cnp->cn_flags & MAKEENTRY) && 61556289Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) 61652196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 61756289Smckusick else 61852196Smckusick *tl = 0; 61952196Smckusick } 62053806Smckusick nfsm_fhtom(dvp); 62153806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 62252196Smckusick reqtime = time.tv_sec; 62353806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 62438414Smckusick nfsmout: 62538414Smckusick if (error) { 62653806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 62755184Smckusick (flags & ISLASTCN) && error == ENOENT) 62852823Smckusick error = EJUSTRETURN; 62955184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 63053806Smckusick cnp->cn_flags |= SAVENAME; 63140483Smckusick return (error); 63238414Smckusick } 63352196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 63452196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 63552196Smckusick if (*tl) { 63652196Smckusick nqlflag = fxdr_unsigned(int, *tl); 63752196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 63852196Smckusick cachable = fxdr_unsigned(int, *tl++); 63952196Smckusick reqtime += fxdr_unsigned(int, *tl++); 64052196Smckusick fxdr_hyper(tl, &frev); 64152196Smckusick } else 64252196Smckusick nqlflag = 0; 64352196Smckusick } 64452196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 64538414Smckusick 64638414Smckusick /* 64752196Smckusick * Handle RENAME case... 64838414Smckusick */ 64955184Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 65052196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 65138414Smckusick m_freem(mrep); 65238414Smckusick return (EISDIR); 65338414Smckusick } 65453806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 65538414Smckusick m_freem(mrep); 65638414Smckusick return (error); 65738414Smckusick } 65838414Smckusick newvp = NFSTOV(np); 65939459Smckusick if (error = 66039459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 66152196Smckusick vrele(newvp); 66238414Smckusick m_freem(mrep); 66338414Smckusick return (error); 66438414Smckusick } 66554668Smckusick *vpp = newvp; 66645037Smckusick m_freem(mrep); 66753806Smckusick cnp->cn_flags |= SAVENAME; 66838414Smckusick return (0); 66938414Smckusick } 67038414Smckusick 67152196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 67253806Smckusick VREF(dvp); 67353806Smckusick newvp = dvp; 67438414Smckusick } else { 67553806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 67638414Smckusick m_freem(mrep); 67738414Smckusick return (error); 67838414Smckusick } 67938414Smckusick newvp = NFSTOV(np); 68038414Smckusick } 68139459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 68252196Smckusick vrele(newvp); 68338414Smckusick m_freem(mrep); 68438414Smckusick return (error); 68538414Smckusick } 68638414Smckusick m_freem(mrep); 68754668Smckusick *vpp = newvp; 68855184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 68953806Smckusick cnp->cn_flags |= SAVENAME; 69055184Smckusick if ((cnp->cn_flags & MAKEENTRY) && 69155184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { 69252196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 69354106Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec; 69456289Smckusick else if (nqlflag && reqtime > time.tv_sec) 69556289Smckusick nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime, 69656289Smckusick frev); 69754668Smckusick cache_enter(dvp, *vpp, cnp); 69840251Smckusick } 69952196Smckusick return (0); 70038414Smckusick } 70138414Smckusick 70238414Smckusick /* 70341905Smckusick * nfs read call. 70441905Smckusick * Just call nfs_bioread() to do the work. 70541905Smckusick */ 70652234Sheideman int 70753806Smckusick nfs_read(ap) 70854668Smckusick struct vop_read_args /* { 70954668Smckusick struct vnode *a_vp; 71054668Smckusick struct uio *a_uio; 71154668Smckusick int a_ioflag; 71254668Smckusick struct ucred *a_cred; 71354668Smckusick } */ *ap; 71441905Smckusick { 71553806Smckusick register struct vnode *vp = ap->a_vp; 71653806Smckusick 71753806Smckusick if (vp->v_type != VREG) 71841905Smckusick return (EPERM); 71953806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 72041905Smckusick } 72141905Smckusick 72241905Smckusick /* 72338414Smckusick * nfs readlink call 72438414Smckusick */ 72552234Sheideman int 72653806Smckusick nfs_readlink(ap) 72754668Smckusick struct vop_readlink_args /* { 72854668Smckusick struct vnode *a_vp; 72954668Smckusick struct uio *a_uio; 73054668Smckusick struct ucred *a_cred; 73154668Smckusick } */ *ap; 73241905Smckusick { 73353806Smckusick register struct vnode *vp = ap->a_vp; 73453806Smckusick 73553806Smckusick if (vp->v_type != VLNK) 73641905Smckusick return (EPERM); 73753806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 73841905Smckusick } 73941905Smckusick 74041905Smckusick /* 74141905Smckusick * Do a readlink rpc. 74241905Smckusick * Called by nfs_doio() from below the buffer cache. 74341905Smckusick */ 74452234Sheideman int 74548054Smckusick nfs_readlinkrpc(vp, uiop, cred) 74639488Smckusick register struct vnode *vp; 74738414Smckusick struct uio *uiop; 74838414Smckusick struct ucred *cred; 74938414Smckusick { 75048054Smckusick register u_long *tl; 75139488Smckusick register caddr_t cp; 75239488Smckusick register long t1; 75339488Smckusick caddr_t bpos, dpos, cp2; 75439488Smckusick int error = 0; 75539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 75638414Smckusick long len; 75738414Smckusick 75838414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 75952196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 76038414Smckusick nfsm_fhtom(vp); 76152196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 76238414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 76338414Smckusick nfsm_mtouio(uiop, len); 76438414Smckusick nfsm_reqdone; 76538414Smckusick return (error); 76638414Smckusick } 76738414Smckusick 76838414Smckusick /* 76941905Smckusick * nfs read rpc call 77041905Smckusick * Ditto above 77138414Smckusick */ 77252234Sheideman int 77348054Smckusick nfs_readrpc(vp, uiop, cred) 77439488Smckusick register struct vnode *vp; 77538414Smckusick struct uio *uiop; 77638414Smckusick struct ucred *cred; 77738414Smckusick { 77848054Smckusick register u_long *tl; 77939488Smckusick register caddr_t cp; 78039488Smckusick register long t1; 78139488Smckusick caddr_t bpos, dpos, cp2; 78239488Smckusick int error = 0; 78339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 78438414Smckusick struct nfsmount *nmp; 78538414Smckusick long len, retlen, tsiz; 78638414Smckusick 78741398Smckusick nmp = VFSTONFS(vp->v_mount); 78838414Smckusick tsiz = uiop->uio_resid; 78956289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 79056289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 79156289Smckusick return (EFBIG); 79238414Smckusick while (tsiz > 0) { 79338414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 79438414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 79552196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 79638414Smckusick nfsm_fhtom(vp); 79748054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 79856289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 79956289Smckusick txdr_hyper(&uiop->uio_offset, tl); 80056289Smckusick *(tl + 2) = txdr_unsigned(len); 80156289Smckusick } else { 80256289Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 80356289Smckusick *tl++ = txdr_unsigned(len); 80456289Smckusick *tl = 0; 80556289Smckusick } 80652196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 80738414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 80838414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 80938414Smckusick nfsm_mtouio(uiop, retlen); 81038414Smckusick m_freem(mrep); 81138414Smckusick if (retlen < len) 81238414Smckusick tsiz = 0; 81338414Smckusick else 81438414Smckusick tsiz -= len; 81538414Smckusick } 81638414Smckusick nfsmout: 81738414Smckusick return (error); 81838414Smckusick } 81938414Smckusick 82038414Smckusick /* 82138414Smckusick * nfs write call 82238414Smckusick */ 82352234Sheideman int 82456289Smckusick nfs_writerpc(vp, uiop, cred, ioflags) 82539488Smckusick register struct vnode *vp; 82638414Smckusick struct uio *uiop; 82738414Smckusick struct ucred *cred; 82856289Smckusick int ioflags; 82938414Smckusick { 83048054Smckusick register u_long *tl; 83139488Smckusick register caddr_t cp; 83239488Smckusick register long t1; 83352196Smckusick caddr_t bpos, dpos, cp2; 83439488Smckusick int error = 0; 83539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 83638414Smckusick struct nfsmount *nmp; 83752196Smckusick struct nfsnode *np = VTONFS(vp); 83852196Smckusick u_quad_t frev; 83938414Smckusick long len, tsiz; 84038414Smckusick 84141398Smckusick nmp = VFSTONFS(vp->v_mount); 84238414Smckusick tsiz = uiop->uio_resid; 84356289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 84456289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 84556289Smckusick return (EFBIG); 84638414Smckusick while (tsiz > 0) { 84738414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 84838414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 84952196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 85052196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 85138414Smckusick nfsm_fhtom(vp); 85256289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4); 85356289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 85456289Smckusick txdr_hyper(&uiop->uio_offset, tl); 85556289Smckusick tl += 2; 85656289Smckusick if (ioflags & IO_APPEND) 85756289Smckusick *tl++ = txdr_unsigned(1); 85856289Smckusick else 85956289Smckusick *tl++ = 0; 86056289Smckusick } else { 86156289Smckusick *++tl = txdr_unsigned(uiop->uio_offset); 86256289Smckusick tl += 2; 86356289Smckusick } 86456289Smckusick *tl = txdr_unsigned(len); 86538414Smckusick nfsm_uiotom(uiop, len); 86652196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 86738414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 86852196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 86954106Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; 87052196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 87152196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 87252196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 87352196Smckusick fxdr_hyper(tl, &frev); 87454451Smckusick if (frev > np->n_brev) 87552196Smckusick np->n_brev = frev; 87652196Smckusick } 87738414Smckusick m_freem(mrep); 87838414Smckusick tsiz -= len; 87938414Smckusick } 88038414Smckusick nfsmout: 88152196Smckusick if (error) 88252196Smckusick uiop->uio_resid = tsiz; 88338414Smckusick return (error); 88438414Smckusick } 88538414Smckusick 88638414Smckusick /* 88739459Smckusick * nfs mknod call 88842246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 88942246Smckusick * set to specify the file type and the size field for rdev. 89039459Smckusick */ 89139459Smckusick /* ARGSUSED */ 89252234Sheideman int 89353806Smckusick nfs_mknod(ap) 89454668Smckusick struct vop_mknod_args /* { 89554668Smckusick struct vnode *a_dvp; 89654668Smckusick struct vnode **a_vpp; 89754668Smckusick struct componentname *a_cnp; 89854668Smckusick struct vattr *a_vap; 89954668Smckusick } */ *ap; 90039459Smckusick { 90153806Smckusick register struct vnode *dvp = ap->a_dvp; 90253806Smckusick register struct vattr *vap = ap->a_vap; 90353806Smckusick register struct componentname *cnp = ap->a_cnp; 90442246Smckusick register struct nfsv2_sattr *sp; 90548054Smckusick register u_long *tl; 90642246Smckusick register caddr_t cp; 90756289Smckusick register long t1, t2; 90856289Smckusick struct vnode *newvp; 90956289Smckusick char *cp2; 91042246Smckusick caddr_t bpos, dpos; 91156289Smckusick int error = 0, isnq; 91242246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 91342246Smckusick u_long rdev; 91439459Smckusick 91556289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 91653806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 91753806Smckusick rdev = txdr_unsigned(vap->va_rdev); 91842246Smckusick #ifdef FIFO 91953806Smckusick else if (vap->va_type == VFIFO) 92042246Smckusick rdev = 0xffffffff; 92142246Smckusick #endif /* FIFO */ 92242246Smckusick else { 92353806Smckusick VOP_ABORTOP(dvp, cnp); 92453806Smckusick vput(dvp); 92542246Smckusick return (EOPNOTSUPP); 92642246Smckusick } 92742246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 92853806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 92956289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 93053806Smckusick nfsm_fhtom(dvp); 93153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 93256289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 93353806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 93453806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 93553806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 93656289Smckusick if (isnq) { 93756289Smckusick sp->sa_nqrdev = rdev; 93856289Smckusick sp->sa_nqflags = 0; 93956289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 94056289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 94156289Smckusick } else { 94256289Smckusick sp->sa_nfssize = rdev; 94356289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 94456289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 94556289Smckusick } 94653806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 94756289Smckusick nfsm_mtofh(dvp, newvp); 94842246Smckusick nfsm_reqdone; 94956289Smckusick if (!error) 95056289Smckusick cache_enter(dvp, newvp, cnp); 95153806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 95253806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 95353806Smckusick vrele(dvp); 95442246Smckusick return (error); 95539459Smckusick } 95639459Smckusick 95739459Smckusick /* 95838414Smckusick * nfs file create call 95938414Smckusick */ 96052234Sheideman int 96153806Smckusick nfs_create(ap) 96254668Smckusick struct vop_create_args /* { 96354668Smckusick struct vnode *a_dvp; 96454668Smckusick struct vnode **a_vpp; 96554668Smckusick struct componentname *a_cnp; 96654668Smckusick struct vattr *a_vap; 96754668Smckusick } */ *ap; 96838414Smckusick { 96953806Smckusick register struct vnode *dvp = ap->a_dvp; 97053806Smckusick register struct vattr *vap = ap->a_vap; 97153806Smckusick register struct componentname *cnp = ap->a_cnp; 97238884Smacklem register struct nfsv2_sattr *sp; 97348054Smckusick register u_long *tl; 97439488Smckusick register caddr_t cp; 97539488Smckusick register long t1, t2; 97639488Smckusick caddr_t bpos, dpos, cp2; 97756289Smckusick int error = 0, isnq; 97839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97938414Smckusick 98038414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 98156289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 98253806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 98356289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 98453806Smckusick nfsm_fhtom(dvp); 98553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 98656289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 98753806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 98853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 98953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 99056289Smckusick if (isnq) { 99156289Smckusick u_quad_t qval = 0; 99256289Smckusick 99356289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 99456289Smckusick sp->sa_nqflags = 0; 99556289Smckusick sp->sa_nqrdev = -1; 99656289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 99756289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 99856289Smckusick } else { 99956289Smckusick sp->sa_nfssize = 0; 100056289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 100156289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 100256289Smckusick } 100353806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 100453806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 100538414Smckusick nfsm_reqdone; 100656289Smckusick if (!error) 100756289Smckusick cache_enter(dvp, *ap->a_vpp, cnp); 100853806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 100953806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 101053806Smckusick vrele(dvp); 101138414Smckusick return (error); 101238414Smckusick } 101338414Smckusick 101438414Smckusick /* 101538414Smckusick * nfs file remove call 101641905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 101741905Smckusick * other processes using the vnode is renamed instead of removed and then 101839341Smckusick * removed later on the last close. 101941905Smckusick * - If v_usecount > 1 102039341Smckusick * If a rename is not already in the works 102139341Smckusick * call nfs_sillyrename() to set it up 102239341Smckusick * else 102339341Smckusick * do the remove rpc 102438414Smckusick */ 102552234Sheideman int 102653806Smckusick nfs_remove(ap) 102754451Smckusick struct vop_remove_args /* { 102854451Smckusick struct vnodeop_desc *a_desc; 102954451Smckusick struct vnode * a_dvp; 103054451Smckusick struct vnode * a_vp; 103154451Smckusick struct componentname * a_cnp; 103254451Smckusick } */ *ap; 103338414Smckusick { 103453806Smckusick register struct vnode *vp = ap->a_vp; 103553806Smckusick register struct vnode *dvp = ap->a_dvp; 103653806Smckusick register struct componentname *cnp = ap->a_cnp; 103753806Smckusick register struct nfsnode *np = VTONFS(vp); 103848054Smckusick register u_long *tl; 103939488Smckusick register caddr_t cp; 104052196Smckusick register long t2; 104139488Smckusick caddr_t bpos, dpos; 104239488Smckusick int error = 0; 104339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 104438414Smckusick 104553806Smckusick if (vp->v_usecount > 1) { 104639341Smckusick if (!np->n_sillyrename) 104753806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 104839341Smckusick } else { 104952196Smckusick /* 105052196Smckusick * Purge the name cache so that the chance of a lookup for 105152196Smckusick * the name succeeding while the remove is in progress is 105252196Smckusick * minimized. Without node locking it can still happen, such 105352196Smckusick * that an I/O op returns ESTALE, but since you get this if 105452196Smckusick * another host removes the file.. 105552196Smckusick */ 105653806Smckusick cache_purge(vp); 105752196Smckusick /* 105852196Smckusick * Throw away biocache buffers. Mainly to avoid 105952196Smckusick * unnecessary delayed writes. 106052196Smckusick */ 106154451Smckusick error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc); 106252196Smckusick /* Do the rpc */ 106338414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 106453806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 106553806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 106653806Smckusick nfsm_fhtom(dvp); 106753806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 106853806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 106938414Smckusick nfsm_reqdone; 107053806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 107153806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 107239751Smckusick /* 107339751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 107439751Smckusick * the reply to the retransmitted request will be ENOENT 107539751Smckusick * since the file was in fact removed 107639751Smckusick * Therefore, we cheat and return success. 107739751Smckusick */ 107839751Smckusick if (error == ENOENT) 107939751Smckusick error = 0; 108038414Smckusick } 108140042Smckusick np->n_attrstamp = 0; 108253806Smckusick vrele(dvp); 108353806Smckusick vrele(vp); 108438414Smckusick return (error); 108538414Smckusick } 108638414Smckusick 108738414Smckusick /* 108838414Smckusick * nfs file remove rpc called from nfs_inactive 108938414Smckusick */ 109052234Sheideman int 109154451Smckusick nfs_removeit(sp) 109248364Smckusick register struct sillyrename *sp; 109338414Smckusick { 109448054Smckusick register u_long *tl; 109539488Smckusick register caddr_t cp; 109652196Smckusick register long t2; 109739488Smckusick caddr_t bpos, dpos; 109839488Smckusick int error = 0; 109939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 110038414Smckusick 110138414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 110252196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 110348364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 110448364Smckusick nfsm_fhtom(sp->s_dvp); 110548364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 110654451Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); 110738414Smckusick nfsm_reqdone; 110848364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 110938414Smckusick return (error); 111038414Smckusick } 111138414Smckusick 111238414Smckusick /* 111338414Smckusick * nfs file rename call 111438414Smckusick */ 111552234Sheideman int 111653806Smckusick nfs_rename(ap) 111754668Smckusick struct vop_rename_args /* { 111854668Smckusick struct vnode *a_fdvp; 111954668Smckusick struct vnode *a_fvp; 112054668Smckusick struct componentname *a_fcnp; 112154668Smckusick struct vnode *a_tdvp; 112254668Smckusick struct vnode *a_tvp; 112354668Smckusick struct componentname *a_tcnp; 112454668Smckusick } */ *ap; 112538414Smckusick { 112653806Smckusick register struct vnode *fvp = ap->a_fvp; 112753806Smckusick register struct vnode *tvp = ap->a_tvp; 112853806Smckusick register struct vnode *fdvp = ap->a_fdvp; 112953806Smckusick register struct vnode *tdvp = ap->a_tdvp; 113053806Smckusick register struct componentname *tcnp = ap->a_tcnp; 113153806Smckusick register struct componentname *fcnp = ap->a_fcnp; 113248054Smckusick register u_long *tl; 113339488Smckusick register caddr_t cp; 113452196Smckusick register long t2; 113539488Smckusick caddr_t bpos, dpos; 113639488Smckusick int error = 0; 113739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 113838414Smckusick 113953804Spendry /* Check for cross-device rename */ 114053806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 114153806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 114253804Spendry error = EXDEV; 114353804Spendry goto out; 114453804Spendry } 114553804Spendry 114653804Spendry 114738414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 114853806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 114953806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 115053806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 115153806Smckusick nfsm_fhtom(fdvp); 115253806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 115353806Smckusick nfsm_fhtom(tdvp); 115453806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 115553806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 115638414Smckusick nfsm_reqdone; 115753806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 115853806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 115953806Smckusick if (fvp->v_type == VDIR) { 116053806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 116153806Smckusick cache_purge(tdvp); 116253806Smckusick cache_purge(fdvp); 116338414Smckusick } 116453804Spendry out: 116553806Smckusick if (tdvp == tvp) 116653806Smckusick vrele(tdvp); 116743360Smckusick else 116853806Smckusick vput(tdvp); 116953806Smckusick if (tvp) 117053806Smckusick vput(tvp); 117153806Smckusick vrele(fdvp); 117253806Smckusick vrele(fvp); 117340112Smckusick /* 117440112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 117540112Smckusick */ 117640112Smckusick if (error == ENOENT) 117740112Smckusick error = 0; 117838414Smckusick return (error); 117938414Smckusick } 118038414Smckusick 118138414Smckusick /* 118241905Smckusick * nfs file rename rpc called from nfs_remove() above 118338414Smckusick */ 118452234Sheideman int 118552234Sheideman nfs_renameit(sdvp, scnp, sp) 118652234Sheideman struct vnode *sdvp; 118752234Sheideman struct componentname *scnp; 118848364Smckusick register struct sillyrename *sp; 118938414Smckusick { 119048054Smckusick register u_long *tl; 119139488Smckusick register caddr_t cp; 119252196Smckusick register long t2; 119339488Smckusick caddr_t bpos, dpos; 119439488Smckusick int error = 0; 119539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 119638414Smckusick 119738414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 119852234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 119952234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 120052196Smckusick nfsm_rndup(sp->s_namlen)); 120152234Sheideman nfsm_fhtom(sdvp); 120252234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 120352234Sheideman nfsm_fhtom(sdvp); 120448364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 120552234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 120638414Smckusick nfsm_reqdone; 120752234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 120852234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 120938414Smckusick return (error); 121038414Smckusick } 121138414Smckusick 121238414Smckusick /* 121338414Smckusick * nfs hard link create call 121438414Smckusick */ 121552234Sheideman int 121653806Smckusick nfs_link(ap) 121754668Smckusick struct vop_link_args /* { 121854668Smckusick struct vnode *a_vp; 121954668Smckusick struct vnode *a_tdvp; 122054668Smckusick struct componentname *a_cnp; 122154668Smckusick } */ *ap; 122238414Smckusick { 122353806Smckusick register struct vnode *vp = ap->a_vp; 122453806Smckusick register struct vnode *tdvp = ap->a_tdvp; 122553806Smckusick register struct componentname *cnp = ap->a_cnp; 122648054Smckusick register u_long *tl; 122739488Smckusick register caddr_t cp; 122852196Smckusick register long t2; 122939488Smckusick caddr_t bpos, dpos; 123039488Smckusick int error = 0; 123139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 123238414Smckusick 123353806Smckusick if (vp->v_mount != tdvp->v_mount) { 123453806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 123553806Smckusick if (tdvp == vp) 123653806Smckusick vrele(vp); 123753804Spendry else 123853806Smckusick vput(vp); 123953804Spendry return (EXDEV); 124053804Spendry } 124153804Spendry 124238414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 124353806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 124453806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 124553806Smckusick nfsm_fhtom(tdvp); 124653806Smckusick nfsm_fhtom(vp); 124753806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 124853806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 124938414Smckusick nfsm_reqdone; 125053806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 125153806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 125253806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 125353806Smckusick vrele(vp); 125440112Smckusick /* 125540112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 125640112Smckusick */ 125740112Smckusick if (error == EEXIST) 125840112Smckusick error = 0; 125938414Smckusick return (error); 126038414Smckusick } 126138414Smckusick 126238414Smckusick /* 126338414Smckusick * nfs symbolic link create call 126438414Smckusick */ 126552234Sheideman /* start here */ 126652234Sheideman int 126753806Smckusick nfs_symlink(ap) 126854668Smckusick struct vop_symlink_args /* { 126954668Smckusick struct vnode *a_dvp; 127054668Smckusick struct vnode **a_vpp; 127154668Smckusick struct componentname *a_cnp; 127254668Smckusick struct vattr *a_vap; 127354668Smckusick char *a_target; 127454668Smckusick } */ *ap; 127538414Smckusick { 127653806Smckusick register struct vnode *dvp = ap->a_dvp; 127753806Smckusick register struct vattr *vap = ap->a_vap; 127853806Smckusick register struct componentname *cnp = ap->a_cnp; 127938884Smacklem register struct nfsv2_sattr *sp; 128048054Smckusick register u_long *tl; 128139488Smckusick register caddr_t cp; 128252196Smckusick register long t2; 128339488Smckusick caddr_t bpos, dpos; 128456289Smckusick int slen, error = 0, isnq; 128539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 128638414Smckusick 128738414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 128853600Sheideman slen = strlen(ap->a_target); 128956289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 129053806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 129156289Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq)); 129253806Smckusick nfsm_fhtom(dvp); 129353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 129453600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 129556289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 129653806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 129753806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 129853806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 129956289Smckusick if (isnq) { 130056289Smckusick quad_t qval = -1; 130156289Smckusick 130256289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 130356289Smckusick sp->sa_nqflags = 0; 130456289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 130556289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 130656289Smckusick } else { 130756289Smckusick sp->sa_nfssize = -1; 130856289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 130956289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 131056289Smckusick } 131153806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 131238414Smckusick nfsm_reqdone; 131353806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 131453806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 131553806Smckusick vrele(dvp); 131640112Smckusick /* 131740112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 131840112Smckusick */ 131940112Smckusick if (error == EEXIST) 132040112Smckusick error = 0; 132138414Smckusick return (error); 132238414Smckusick } 132338414Smckusick 132438414Smckusick /* 132538414Smckusick * nfs make dir call 132638414Smckusick */ 132752234Sheideman int 132853806Smckusick nfs_mkdir(ap) 132954668Smckusick struct vop_mkdir_args /* { 133054668Smckusick struct vnode *a_dvp; 133154668Smckusick struct vnode **a_vpp; 133254668Smckusick struct componentname *a_cnp; 133354668Smckusick struct vattr *a_vap; 133454668Smckusick } */ *ap; 133538414Smckusick { 133653806Smckusick register struct vnode *dvp = ap->a_dvp; 133753806Smckusick register struct vattr *vap = ap->a_vap; 133853806Smckusick register struct componentname *cnp = ap->a_cnp; 133954668Smckusick register struct vnode **vpp = ap->a_vpp; 134038884Smacklem register struct nfsv2_sattr *sp; 134148054Smckusick register u_long *tl; 134239488Smckusick register caddr_t cp; 134339488Smckusick register long t1, t2; 134441905Smckusick register int len; 134539488Smckusick caddr_t bpos, dpos, cp2; 134656289Smckusick int error = 0, firsttry = 1, isnq; 134739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 134838414Smckusick 134953806Smckusick len = cnp->cn_namelen; 135056289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 135138414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 135253806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 135356289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq)); 135453806Smckusick nfsm_fhtom(dvp); 135553806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 135656289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 135753806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 135853806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 135953806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 136056289Smckusick if (isnq) { 136156289Smckusick quad_t qval = -1; 136256289Smckusick 136356289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 136456289Smckusick sp->sa_nqflags = 0; 136556289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 136656289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 136756289Smckusick } else { 136856289Smckusick sp->sa_nfssize = -1; 136956289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 137056289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 137156289Smckusick } 137253806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 137354668Smckusick nfsm_mtofh(dvp, *vpp); 137438414Smckusick nfsm_reqdone; 137553806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 137640112Smckusick /* 137741905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 137841905Smckusick * if we can succeed in looking up the directory. 137941905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 138041905Smckusick * is above the if on errors. (Ugh) 138140112Smckusick */ 138241905Smckusick if (error == EEXIST && firsttry) { 138341905Smckusick firsttry = 0; 138440112Smckusick error = 0; 138541905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 138654668Smckusick *vpp = NULL; 138753806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 138841905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 138953806Smckusick nfsm_fhtom(dvp); 139053806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 139153806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 139254668Smckusick nfsm_mtofh(dvp, *vpp); 139354668Smckusick if ((*vpp)->v_type != VDIR) { 139454668Smckusick vput(*vpp); 139541905Smckusick error = EEXIST; 139641905Smckusick } 139741905Smckusick m_freem(mrep); 139841905Smckusick } 139953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 140053806Smckusick vrele(dvp); 140138414Smckusick return (error); 140238414Smckusick } 140338414Smckusick 140438414Smckusick /* 140538414Smckusick * nfs remove directory call 140638414Smckusick */ 140752234Sheideman int 140853806Smckusick nfs_rmdir(ap) 140954668Smckusick struct vop_rmdir_args /* { 141054668Smckusick struct vnode *a_dvp; 141154668Smckusick struct vnode *a_vp; 141254668Smckusick struct componentname *a_cnp; 141354668Smckusick } */ *ap; 141438414Smckusick { 141553806Smckusick register struct vnode *vp = ap->a_vp; 141653806Smckusick register struct vnode *dvp = ap->a_dvp; 141753806Smckusick register struct componentname *cnp = ap->a_cnp; 141848054Smckusick register u_long *tl; 141939488Smckusick register caddr_t cp; 142052196Smckusick register long t2; 142139488Smckusick caddr_t bpos, dpos; 142239488Smckusick int error = 0; 142339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 142438414Smckusick 142553806Smckusick if (dvp == vp) { 142653806Smckusick vrele(dvp); 142753806Smckusick vrele(dvp); 142853806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 142938414Smckusick return (EINVAL); 143038414Smckusick } 143138414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 143253806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 143353806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 143453806Smckusick nfsm_fhtom(dvp); 143553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 143653806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 143738414Smckusick nfsm_reqdone; 143853806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 143953806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 144053806Smckusick cache_purge(dvp); 144153806Smckusick cache_purge(vp); 144253806Smckusick vrele(vp); 144353806Smckusick vrele(dvp); 144440112Smckusick /* 144540112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 144640112Smckusick */ 144740112Smckusick if (error == ENOENT) 144840112Smckusick error = 0; 144938414Smckusick return (error); 145038414Smckusick } 145138414Smckusick 145238414Smckusick /* 145338414Smckusick * nfs readdir call 145438414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 145538414Smckusick * order so that it looks more sensible. This appears consistent with the 145638414Smckusick * Ultrix implementation of NFS. 145738414Smckusick */ 145852234Sheideman int 145953806Smckusick nfs_readdir(ap) 146054668Smckusick struct vop_readdir_args /* { 146154668Smckusick struct vnode *a_vp; 146254668Smckusick struct uio *a_uio; 146354668Smckusick struct ucred *a_cred; 146454668Smckusick } */ *ap; 146538414Smckusick { 146653806Smckusick register struct vnode *vp = ap->a_vp; 146753806Smckusick register struct nfsnode *np = VTONFS(vp); 146853806Smckusick register struct uio *uio = ap->a_uio; 146941905Smckusick int tresid, error; 147041905Smckusick struct vattr vattr; 147141905Smckusick 147253806Smckusick if (vp->v_type != VDIR) 147341905Smckusick return (EPERM); 147441905Smckusick /* 147541905Smckusick * First, check for hit on the EOF offset cache 147641905Smckusick */ 147753806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 147852196Smckusick (np->n_flag & NMODIFIED) == 0) { 147953806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 148053806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 148152196Smckusick nfsstats.direofcache_hits++; 148252196Smckusick return (0); 148352196Smckusick } 148453806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 148554106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) { 148652196Smckusick nfsstats.direofcache_hits++; 148752196Smckusick return (0); 148852196Smckusick } 148941905Smckusick } 149041905Smckusick 149141905Smckusick /* 149241905Smckusick * Call nfs_bioread() to do the real work. 149341905Smckusick */ 149453806Smckusick tresid = uio->uio_resid; 149553806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 149641905Smckusick 149754451Smckusick if (!error && uio->uio_resid == tresid) 149841905Smckusick nfsstats.direofcache_misses++; 149941905Smckusick return (error); 150041905Smckusick } 150141905Smckusick 150241905Smckusick /* 150341905Smckusick * Readdir rpc call. 150441905Smckusick * Called from below the buffer cache by nfs_doio(). 150541905Smckusick */ 150652234Sheideman int 150748054Smckusick nfs_readdirrpc(vp, uiop, cred) 150841905Smckusick register struct vnode *vp; 150941905Smckusick struct uio *uiop; 151041905Smckusick struct ucred *cred; 151141905Smckusick { 151238414Smckusick register long len; 151354740Smckusick register struct dirent *dp; 151448054Smckusick register u_long *tl; 151539488Smckusick register caddr_t cp; 151639488Smckusick register long t1; 151741905Smckusick long tlen, lastlen; 151839488Smckusick caddr_t bpos, dpos, cp2; 151939488Smckusick int error = 0; 152039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 152138414Smckusick struct mbuf *md2; 152238414Smckusick caddr_t dpos2; 152338414Smckusick int siz; 152440296Smckusick int more_dirs = 1; 152556289Smckusick u_long off, savoff; 152654740Smckusick struct dirent *savdp; 152740296Smckusick struct nfsmount *nmp; 152840296Smckusick struct nfsnode *np = VTONFS(vp); 152940296Smckusick long tresid; 153038414Smckusick 153141398Smckusick nmp = VFSTONFS(vp->v_mount); 153240296Smckusick tresid = uiop->uio_resid; 153340296Smckusick /* 153440296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 153548054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 153641905Smckusick * The stopping criteria is EOF or buffer full. 153740296Smckusick */ 153848054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 153940296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 154052196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 154156289Smckusick NFSX_FH + 2 * NFSX_UNSIGNED); 154240296Smckusick nfsm_fhtom(vp); 154356289Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 154456289Smckusick off = (u_long)uiop->uio_offset; 154556289Smckusick *tl++ = txdr_unsigned(off); 154648054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 154748054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 154852196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 154940296Smckusick siz = 0; 155052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 155148054Smckusick more_dirs = fxdr_unsigned(int, *tl); 155240296Smckusick 155340296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 155440296Smckusick dpos2 = dpos; 155540296Smckusick md2 = md; 155640296Smckusick 155740296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 155842246Smckusick #ifdef lint 155954740Smckusick dp = (struct dirent *)0; 156042246Smckusick #endif /* lint */ 156140296Smckusick while (more_dirs && siz < uiop->uio_resid) { 156240296Smckusick savoff = off; /* Hold onto offset and dp */ 156340296Smckusick savdp = dp; 156456289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 156554740Smckusick dp = (struct dirent *)tl; 156654740Smckusick dp->d_fileno = fxdr_unsigned(u_long, *tl++); 156748054Smckusick len = fxdr_unsigned(int, *tl); 156840296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 156940296Smckusick error = EBADRPC; 157040296Smckusick m_freem(mrep); 157140296Smckusick goto nfsmout; 157240296Smckusick } 157354986Smckusick dp->d_namlen = (u_char)len; 157454986Smckusick dp->d_type = DT_UNKNOWN; 157540296Smckusick nfsm_adv(len); /* Point past name */ 157640296Smckusick tlen = nfsm_rndup(len); 157740296Smckusick /* 157840296Smckusick * This should not be necessary, but some servers have 157940296Smckusick * broken XDR such that these bytes are not null filled. 158040296Smckusick */ 158140296Smckusick if (tlen != len) { 158240296Smckusick *dpos = '\0'; /* Null-terminate */ 158340296Smckusick nfsm_adv(tlen - len); 158440296Smckusick len = tlen; 158540296Smckusick } 158656289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 158754986Smckusick off = fxdr_unsigned(u_long, *tl); 158848054Smckusick *tl++ = 0; /* Ensures null termination of name */ 158948054Smckusick more_dirs = fxdr_unsigned(int, *tl); 159056289Smckusick dp->d_reclen = len + 4 * NFSX_UNSIGNED; 159140296Smckusick siz += dp->d_reclen; 159240296Smckusick } 159340296Smckusick /* 159440296Smckusick * If at end of rpc data, get the eof boolean 159540296Smckusick */ 159640296Smckusick if (!more_dirs) { 159752196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 159848054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 159938414Smckusick 160040296Smckusick /* 160140296Smckusick * If at EOF, cache directory offset 160240296Smckusick */ 160341905Smckusick if (!more_dirs) 160440296Smckusick np->n_direofoffset = off; 160538414Smckusick } 160640296Smckusick /* 160740296Smckusick * If there is too much to fit in the data buffer, use savoff and 160840296Smckusick * savdp to trim off the last record. 160940296Smckusick * --> we are not at eof 161040296Smckusick */ 161140296Smckusick if (siz > uiop->uio_resid) { 161240296Smckusick off = savoff; 161340296Smckusick siz -= dp->d_reclen; 161440296Smckusick dp = savdp; 161540296Smckusick more_dirs = 0; /* Paranoia */ 161640113Smckusick } 161740296Smckusick if (siz > 0) { 161841905Smckusick lastlen = dp->d_reclen; 161940296Smckusick md = md2; 162040296Smckusick dpos = dpos2; 162140296Smckusick nfsm_mtouio(uiop, siz); 162256289Smckusick uiop->uio_offset = (off_t)off; 162340296Smckusick } else 162440296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 162540296Smckusick m_freem(mrep); 162638414Smckusick } 162741905Smckusick /* 162848054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 162941905Smckusick * by increasing d_reclen for the last record. 163041905Smckusick */ 163141905Smckusick if (uiop->uio_resid < tresid) { 163248054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 163341905Smckusick if (len > 0) { 163454740Smckusick dp = (struct dirent *) 163541905Smckusick (uiop->uio_iov->iov_base - lastlen); 163641905Smckusick dp->d_reclen += len; 163741905Smckusick uiop->uio_iov->iov_base += len; 163841905Smckusick uiop->uio_iov->iov_len -= len; 163941905Smckusick uiop->uio_resid -= len; 164041905Smckusick } 164141905Smckusick } 164240296Smckusick nfsmout: 164338414Smckusick return (error); 164438414Smckusick } 164538414Smckusick 164652196Smckusick /* 164756289Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc(). 164852196Smckusick */ 164952234Sheideman int 165052196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 165152196Smckusick struct vnode *vp; 165252196Smckusick register struct uio *uiop; 165352196Smckusick struct ucred *cred; 165452196Smckusick { 165552196Smckusick register int len; 165654740Smckusick register struct dirent *dp; 165752196Smckusick register u_long *tl; 165852196Smckusick register caddr_t cp; 165952196Smckusick register long t1; 166052196Smckusick caddr_t bpos, dpos, cp2; 166152196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 166252196Smckusick struct nameidata nami, *ndp = &nami; 166352317Sheideman struct componentname *cnp = &ndp->ni_cnd; 166456289Smckusick u_long off, endoff, fileno; 166552196Smckusick time_t reqtime, ltime; 166652196Smckusick struct nfsmount *nmp; 166752196Smckusick struct nfsnode *np, *tp; 166852196Smckusick struct vnode *newvp; 166952196Smckusick nfsv2fh_t *fhp; 167052196Smckusick u_quad_t frev; 167152196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 167252196Smckusick int cachable; 167352196Smckusick 167452196Smckusick if (uiop->uio_iovcnt != 1) 167552196Smckusick panic("nfs rdirlook"); 167652196Smckusick nmp = VFSTONFS(vp->v_mount); 167752196Smckusick tresid = uiop->uio_resid; 167852196Smckusick ndp->ni_dvp = vp; 167952196Smckusick newvp = NULLVP; 168052196Smckusick /* 168152196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 168252196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 168352196Smckusick * The stopping criteria is EOF or buffer full. 168452196Smckusick */ 168552196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 168652196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 168752196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 168856289Smckusick NFSX_FH + 3 * NFSX_UNSIGNED); 168952196Smckusick nfsm_fhtom(vp); 169056289Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 169156289Smckusick off = (u_long)uiop->uio_offset; 169256289Smckusick *tl++ = txdr_unsigned(off); 169352196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 169452196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 169556289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) 169656289Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 169756289Smckusick else 169856289Smckusick *tl = 0; 169952196Smckusick reqtime = time.tv_sec; 170052196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 170152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 170252196Smckusick more_dirs = fxdr_unsigned(int, *tl); 170352196Smckusick 170452196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 170552196Smckusick bigenough = 1; 170652196Smckusick while (more_dirs && bigenough) { 170752196Smckusick doit = 1; 170856289Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 170956289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) { 171056289Smckusick cachable = fxdr_unsigned(int, *tl++); 171156289Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 171256289Smckusick fxdr_hyper(tl, &frev); 171356289Smckusick } 171452196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 171552196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 171652196Smckusick VREF(vp); 171752196Smckusick newvp = vp; 171852196Smckusick np = VTONFS(vp); 171952196Smckusick } else { 172052196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 172152196Smckusick doit = 0; 172252196Smckusick newvp = NFSTOV(np); 172352196Smckusick } 172452196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 172552196Smckusick (struct vattr *)0)) 172652196Smckusick doit = 0; 172756289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 172852196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 172952196Smckusick len = fxdr_unsigned(int, *tl); 173052196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 173152196Smckusick error = EBADRPC; 173252196Smckusick m_freem(mrep); 173352196Smckusick goto nfsmout; 173452196Smckusick } 173552196Smckusick tlen = (len + 4) & ~0x3; 173652196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 173752196Smckusick bigenough = 0; 173852196Smckusick if (bigenough && doit) { 173954740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base; 174054740Smckusick dp->d_fileno = fileno; 174152196Smckusick dp->d_namlen = len; 174252196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 174354986Smckusick dp->d_type = 174454986Smckusick IFTODT(VTTOIF(np->n_vattr.va_type)); 174552196Smckusick uiop->uio_resid -= DIRHDSIZ; 174652196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 174752196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 174852317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 174952317Sheideman cnp->cn_namelen = len; 175052196Smckusick ndp->ni_vp = newvp; 175152196Smckusick nfsm_mtouio(uiop, len); 175252196Smckusick cp = uiop->uio_iov->iov_base; 175352196Smckusick tlen -= len; 175452196Smckusick for (i = 0; i < tlen; i++) 175552196Smckusick *cp++ = '\0'; 175652196Smckusick uiop->uio_iov->iov_base += tlen; 175752196Smckusick uiop->uio_iov->iov_len -= tlen; 175852196Smckusick uiop->uio_resid -= tlen; 175952317Sheideman cnp->cn_hash = 0; 176052317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 176152317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 176256289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 176356289Smckusick ltime > time.tv_sec) 176456289Smckusick nqnfs_clientlease(nmp, np, NQL_READ, 176556289Smckusick cachable, ltime, frev); 176656289Smckusick cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 176752196Smckusick } else { 176852196Smckusick nfsm_adv(nfsm_rndup(len)); 176952196Smckusick } 177052196Smckusick if (newvp != NULLVP) { 177152196Smckusick vrele(newvp); 177252196Smckusick newvp = NULLVP; 177352196Smckusick } 177456289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 177552196Smckusick if (bigenough) 177656289Smckusick endoff = off = fxdr_unsigned(u_long, *tl++); 177752196Smckusick else 177856289Smckusick endoff = fxdr_unsigned(u_long, *tl++); 177952196Smckusick more_dirs = fxdr_unsigned(int, *tl); 178052196Smckusick } 178152196Smckusick /* 178252196Smckusick * If at end of rpc data, get the eof boolean 178352196Smckusick */ 178452196Smckusick if (!more_dirs) { 178552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 178652196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 178752196Smckusick 178852196Smckusick /* 178952196Smckusick * If at EOF, cache directory offset 179052196Smckusick */ 179152196Smckusick if (!more_dirs) 179252196Smckusick VTONFS(vp)->n_direofoffset = endoff; 179352196Smckusick } 179452196Smckusick if (uiop->uio_resid < tresid) 179556289Smckusick uiop->uio_offset = (off_t)off; 179652196Smckusick else 179752196Smckusick more_dirs = 0; 179852196Smckusick m_freem(mrep); 179952196Smckusick } 180052196Smckusick /* 180152196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 180252196Smckusick * by increasing d_reclen for the last record. 180352196Smckusick */ 180452196Smckusick if (uiop->uio_resid < tresid) { 180552196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 180652196Smckusick if (len > 0) { 180752196Smckusick dp->d_reclen += len; 180852196Smckusick uiop->uio_iov->iov_base += len; 180952196Smckusick uiop->uio_iov->iov_len -= len; 181052196Smckusick uiop->uio_resid -= len; 181152196Smckusick } 181252196Smckusick } 181352196Smckusick nfsmout: 181452196Smckusick if (newvp != NULLVP) 181552196Smckusick vrele(newvp); 181652196Smckusick return (error); 181752196Smckusick } 181839488Smckusick static char hextoasc[] = "0123456789abcdef"; 181938414Smckusick 182038414Smckusick /* 182138414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 182238414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 182338414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 182438414Smckusick * nfsnode. There is the potential for another process on a different client 182538414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 182638414Smckusick * nfs_rename() completes, but... 182738414Smckusick */ 182852234Sheideman int 182952317Sheideman nfs_sillyrename(dvp, vp, cnp) 183052234Sheideman struct vnode *dvp, *vp; 183152234Sheideman struct componentname *cnp; 183238414Smckusick { 183338414Smckusick register struct nfsnode *np; 183438414Smckusick register struct sillyrename *sp; 183538414Smckusick int error; 183638414Smckusick short pid; 183738414Smckusick 183852234Sheideman cache_purge(dvp); 183952234Sheideman np = VTONFS(vp); 184051986Smckusick #ifdef SILLYSEPARATE 184138414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 184248364Smckusick M_NFSREQ, M_WAITOK); 184351986Smckusick #else 184451986Smckusick sp = &np->n_silly; 184551986Smckusick #endif 184652234Sheideman sp->s_cred = crdup(cnp->cn_cred); 184752234Sheideman sp->s_dvp = dvp; 184852234Sheideman VREF(dvp); 184938414Smckusick 185038414Smckusick /* Fudge together a funny name */ 185152234Sheideman pid = cnp->cn_proc->p_pid; 185248364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 185348364Smckusick sp->s_namlen = 12; 185448364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 185548364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 185648364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 185748364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 185838414Smckusick 185938414Smckusick /* Try lookitups until we get one that isn't there */ 186052234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 186148364Smckusick sp->s_name[4]++; 186248364Smckusick if (sp->s_name[4] > 'z') { 186338414Smckusick error = EINVAL; 186438414Smckusick goto bad; 186538414Smckusick } 186638414Smckusick } 186752234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 186838414Smckusick goto bad; 186952234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 187038414Smckusick np->n_sillyrename = sp; 187138414Smckusick return (0); 187238414Smckusick bad: 187348364Smckusick vrele(sp->s_dvp); 187448364Smckusick crfree(sp->s_cred); 187551986Smckusick #ifdef SILLYSEPARATE 187648364Smckusick free((caddr_t)sp, M_NFSREQ); 187751986Smckusick #endif 187838414Smckusick return (error); 187938414Smckusick } 188038414Smckusick 188138414Smckusick /* 188238414Smckusick * Look up a file name for silly rename stuff. 188338414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 188438414Smckusick * into the nfsnode table. 188538414Smckusick * If fhp != NULL it copies the returned file handle out 188638414Smckusick */ 188752234Sheideman int 188852196Smckusick nfs_lookitup(sp, fhp, procp) 188948364Smckusick register struct sillyrename *sp; 189038414Smckusick nfsv2fh_t *fhp; 189152196Smckusick struct proc *procp; 189238414Smckusick { 189348364Smckusick register struct vnode *vp = sp->s_dvp; 189448054Smckusick register u_long *tl; 189539488Smckusick register caddr_t cp; 189639488Smckusick register long t1, t2; 189739488Smckusick caddr_t bpos, dpos, cp2; 189839488Smckusick u_long xid; 189956289Smckusick int error = 0, isnq; 190039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 190138414Smckusick long len; 190238414Smckusick 190356289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 190438414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 190548364Smckusick len = sp->s_namlen; 190652196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 190756289Smckusick if (isnq) { 190856289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 190956289Smckusick *tl = 0; 191056289Smckusick } 191138414Smckusick nfsm_fhtom(vp); 191248364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 191352196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 191438414Smckusick if (fhp != NULL) { 191556289Smckusick if (isnq) 191656289Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 191752196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 191838414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 191938414Smckusick } 192038414Smckusick nfsm_reqdone; 192138414Smckusick return (error); 192238414Smckusick } 192338414Smckusick 192438414Smckusick /* 192538414Smckusick * Kludge City.. 192638414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 192741905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 192838414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 192938414Smckusick * nfsiobuf area. 193038414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 193138414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 193238414Smckusick * a lot more work than bcopy() and also it currently happens in the 193338414Smckusick * context of the swapper process (2). 193438414Smckusick */ 193552234Sheideman int 193653806Smckusick nfs_bmap(ap) 193754668Smckusick struct vop_bmap_args /* { 193854668Smckusick struct vnode *a_vp; 193954668Smckusick daddr_t a_bn; 194054668Smckusick struct vnode **a_vpp; 194154668Smckusick daddr_t *a_bnp; 194254668Smckusick } */ *ap; 194338414Smckusick { 194453806Smckusick register struct vnode *vp = ap->a_vp; 194553806Smckusick 194653600Sheideman if (ap->a_vpp != NULL) 194753806Smckusick *ap->a_vpp = vp; 194853600Sheideman if (ap->a_bnp != NULL) 194953806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 195038414Smckusick return (0); 195138414Smckusick } 195238414Smckusick 195338414Smckusick /* 195438884Smacklem * Strategy routine for phys. i/o 195538884Smacklem * If the biod's are running, queue a request 195638884Smacklem * otherwise just call nfs_doio() to get it done 195738414Smckusick */ 195852234Sheideman int 195953806Smckusick nfs_strategy(ap) 196054668Smckusick struct vop_strategy_args /* { 196154668Smckusick struct buf *a_bp; 196254668Smckusick } */ *ap; 196338414Smckusick { 196453806Smckusick register struct buf *bp = ap->a_bp; 196539341Smckusick register int i; 196638884Smacklem int error = 0; 196739341Smckusick int fnd = 0; 196838884Smacklem 196938884Smacklem /* 197041905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 197141905Smckusick * doesn't set it, I will. 197246450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 197341905Smckusick * be hanging about after the process terminates. 197441905Smckusick */ 197553806Smckusick if ((bp->b_flags & B_PHYS) == 0) { 197653806Smckusick if (bp->b_flags & B_ASYNC) 197753806Smckusick bp->b_proc = (struct proc *)0; 197846988Smckusick else 197953806Smckusick bp->b_proc = curproc; 198046988Smckusick } 198141905Smckusick /* 198246450Skarels * If the op is asynchronous and an i/o daemon is waiting 198338884Smacklem * queue the request, wake it up and wait for completion 198446450Skarels * otherwise just do it ourselves. 198538884Smacklem */ 198653806Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 198753806Smckusick return (nfs_doio(bp)); 198846988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 198946988Smckusick if (nfs_iodwant[i]) { 1990*56390Smckusick bp->b_actf = NULL; 1991*56390Smckusick bp->b_actb = nfs_bqueuetail; 1992*56390Smckusick *nfs_bqueuetail = bp; 1993*56390Smckusick nfs_bqueuetail = &bp->b_actf; 199439341Smckusick fnd++; 199539341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 199639341Smckusick break; 199738884Smacklem } 199839341Smckusick } 199939341Smckusick if (!fnd) 200053806Smckusick error = nfs_doio(bp); 200138884Smacklem return (error); 200238884Smacklem } 200338884Smacklem 200438884Smacklem /* 200538884Smacklem * Fun and games with i/o 200638884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 200738884Smacklem * mapping the data buffer into kernel virtual space and doing the 200838884Smacklem * nfs read or write rpc's from it. 200941905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 201041905Smckusick * otherwise it is called by the nfsiods to do what would normally be 201138884Smacklem * partially disk interrupt driven. 201238884Smacklem */ 201352234Sheideman int 201438884Smacklem nfs_doio(bp) 201538884Smacklem register struct buf *bp; 201638884Smacklem { 201738414Smckusick register struct uio *uiop; 201838414Smckusick register struct vnode *vp; 201939341Smckusick struct nfsnode *np; 202038884Smacklem struct ucred *cr; 202141539Smckusick int error; 202241539Smckusick struct uio uio; 202341539Smckusick struct iovec io; 202438414Smckusick 202538414Smckusick vp = bp->b_vp; 202640251Smckusick np = VTONFS(vp); 202738414Smckusick uiop = &uio; 202838414Smckusick uiop->uio_iov = &io; 202938414Smckusick uiop->uio_iovcnt = 1; 203038414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 203152196Smckusick uiop->uio_procp = bp->b_proc; 203239751Smckusick 203338414Smckusick /* 203438884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 203538884Smacklem * the Nfsiomap pte's 203638884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 203738884Smacklem * and a guess at a group 203838414Smckusick */ 203938884Smacklem if (bp->b_flags & B_PHYS) { 204048054Smckusick if (bp->b_flags & B_DIRTY) 204148054Smckusick uiop->uio_procp = pageproc; 204248054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 204341539Smckusick /* mapping was already done by vmapbuf */ 204441539Smckusick io.iov_base = bp->b_un.b_addr; 204539751Smckusick 204638884Smacklem /* 204739751Smckusick * And do the i/o rpc 204839751Smckusick */ 204939751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 205039823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 205139751Smckusick if (bp->b_flags & B_READ) { 205239751Smckusick uiop->uio_rw = UIO_READ; 205339751Smckusick nfsstats.read_physios++; 205448054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 205545717Smckusick (void) vnode_pager_uncache(vp); 205639751Smckusick } else { 205739751Smckusick uiop->uio_rw = UIO_WRITE; 205839751Smckusick nfsstats.write_physios++; 205956289Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr, 0); 206039341Smckusick } 206139751Smckusick 206239751Smckusick /* 206339751Smckusick * Finally, release pte's used by physical i/o 206439751Smckusick */ 206538884Smacklem crfree(cr); 206639751Smckusick } else { 206739751Smckusick if (bp->b_flags & B_READ) { 206839751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 206939751Smckusick io.iov_base = bp->b_un.b_addr; 207039751Smckusick uiop->uio_rw = UIO_READ; 207141905Smckusick switch (vp->v_type) { 207241905Smckusick case VREG: 207341905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 207441905Smckusick nfsstats.read_bios++; 207548054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 207641905Smckusick break; 207741905Smckusick case VLNK: 207841905Smckusick uiop->uio_offset = 0; 207941905Smckusick nfsstats.readlink_bios++; 208048054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 208141905Smckusick break; 208241905Smckusick case VDIR: 208341905Smckusick uiop->uio_offset = bp->b_lblkno; 208441905Smckusick nfsstats.readdir_bios++; 208556289Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) 208652196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 208752196Smckusick else 208852196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 208941905Smckusick /* 209041905Smckusick * Save offset cookie in b_blkno. 209141905Smckusick */ 209241905Smckusick bp->b_blkno = uiop->uio_offset; 209341905Smckusick break; 209441905Smckusick }; 209541905Smckusick bp->b_error = error; 209639751Smckusick } else { 209739751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 209839751Smckusick - bp->b_dirtyoff; 209939823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 210039751Smckusick + bp->b_dirtyoff; 210139751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 210239751Smckusick uiop->uio_rw = UIO_WRITE; 210339751Smckusick nfsstats.write_bios++; 210441905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 210556289Smckusick bp->b_wcred, 0); 210639751Smckusick if (error) { 210739751Smckusick np->n_error = error; 210839751Smckusick np->n_flag |= NWRITEERR; 210939751Smckusick } 211039751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 211139751Smckusick } 211238884Smacklem } 211339751Smckusick if (error) 211439751Smckusick bp->b_flags |= B_ERROR; 211539751Smckusick bp->b_resid = uiop->uio_resid; 211638414Smckusick biodone(bp); 211738414Smckusick return (error); 211838414Smckusick } 211938884Smacklem 212038884Smacklem /* 212148054Smckusick * Mmap a file 212248054Smckusick * 212348054Smckusick * NB Currently unsupported. 212448054Smckusick */ 212548054Smckusick /* ARGSUSED */ 212652234Sheideman int 212753806Smckusick nfs_mmap(ap) 212854668Smckusick struct vop_mmap_args /* { 212954668Smckusick struct vnode *a_vp; 213054668Smckusick int a_fflags; 213154668Smckusick struct ucred *a_cred; 213254668Smckusick struct proc *a_p; 213354668Smckusick } */ *ap; 213448054Smckusick { 213548054Smckusick 213648054Smckusick return (EINVAL); 213748054Smckusick } 213848054Smckusick 213948054Smckusick /* 214038884Smacklem * Flush all the blocks associated with a vnode. 214138884Smacklem * Walk through the buffer pool and push any dirty pages 214238884Smacklem * associated with the vnode. 214338884Smacklem */ 214439488Smckusick /* ARGSUSED */ 214552234Sheideman int 214653806Smckusick nfs_fsync(ap) 214754451Smckusick struct vop_fsync_args /* { 214854451Smckusick struct vnodeop_desc *a_desc; 214954451Smckusick struct vnode * a_vp; 215054451Smckusick struct ucred * a_cred; 215154451Smckusick int a_waitfor; 215254451Smckusick struct proc * a_p; 215354451Smckusick } */ *ap; 215438884Smacklem { 215554451Smckusick register struct vnode *vp = ap->a_vp; 215654451Smckusick register struct nfsnode *np = VTONFS(vp); 215754451Smckusick register struct buf *bp; 215854451Smckusick struct buf *nbp; 215954451Smckusick int s, error = 0; 216038884Smacklem 216154451Smckusick loop: 216254451Smckusick s = splbio(); 216354451Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 216454451Smckusick nbp = bp->b_blockf; 216554451Smckusick if ((bp->b_flags & B_BUSY)) 216654451Smckusick continue; 216754451Smckusick if ((bp->b_flags & B_DELWRI) == 0) 216854451Smckusick panic("nfs_fsync: not dirty"); 216954451Smckusick bremfree(bp); 217054451Smckusick bp->b_flags |= B_BUSY; 217154451Smckusick splx(s); 217254451Smckusick error = bawrite(bp); 217354451Smckusick goto loop; 217438884Smacklem } 217554451Smckusick if (ap->a_waitfor == MNT_WAIT) { 217654451Smckusick while (vp->v_numoutput) { 217754451Smckusick vp->v_flag |= VBWAIT; 217854451Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 217954451Smckusick } 218054451Smckusick #ifdef DIAGNOSTIC 218154451Smckusick if (vp->v_dirtyblkhd) { 218254451Smckusick vprint("nfs_fsync: dirty", vp); 218354451Smckusick goto loop; 218454451Smckusick } 218554451Smckusick #endif 218654451Smckusick } 218754451Smckusick splx(s); 218854451Smckusick np->n_flag &= ~NMODIFIED; 218953629Smckusick if (np->n_flag & NWRITEERR) { 219039751Smckusick error = np->n_error; 219153629Smckusick np->n_flag &= ~NWRITEERR; 219253629Smckusick } 219338884Smacklem return (error); 219438884Smacklem } 219539672Smckusick 219639672Smckusick /* 219746201Smckusick * NFS advisory byte-level locks. 219846201Smckusick * Currently unsupported. 219946201Smckusick */ 220052234Sheideman int 220153806Smckusick nfs_advlock(ap) 220254668Smckusick struct vop_advlock_args /* { 220354668Smckusick struct vnode *a_vp; 220454668Smckusick caddr_t a_id; 220554668Smckusick int a_op; 220654668Smckusick struct flock *a_fl; 220754668Smckusick int a_flags; 220854668Smckusick } */ *ap; 220946201Smckusick { 221046201Smckusick 221146201Smckusick return (EOPNOTSUPP); 221246201Smckusick } 221346201Smckusick 221446201Smckusick /* 221539672Smckusick * Print out the contents of an nfsnode. 221639672Smckusick */ 221752234Sheideman int 221853806Smckusick nfs_print(ap) 221954668Smckusick struct vop_print_args /* { 222054668Smckusick struct vnode *a_vp; 222154668Smckusick } */ *ap; 222239672Smckusick { 222353806Smckusick register struct vnode *vp = ap->a_vp; 222453806Smckusick register struct nfsnode *np = VTONFS(vp); 222539672Smckusick 222640294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 222740294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 222840294Smckusick #ifdef FIFO 222953806Smckusick if (vp->v_type == VFIFO) 223053806Smckusick fifo_printinfo(vp); 223140294Smckusick #endif /* FIFO */ 223239914Smckusick printf("\n"); 223339672Smckusick } 223451573Smckusick 223551573Smckusick /* 223651573Smckusick * NFS directory offset lookup. 223751573Smckusick * Currently unsupported. 223851573Smckusick */ 223952234Sheideman int 224053806Smckusick nfs_blkatoff(ap) 224154668Smckusick struct vop_blkatoff_args /* { 224254668Smckusick struct vnode *a_vp; 224354668Smckusick off_t a_offset; 224454668Smckusick char **a_res; 224554668Smckusick struct buf **a_bpp; 224654668Smckusick } */ *ap; 224751573Smckusick { 224851573Smckusick 224951573Smckusick return (EOPNOTSUPP); 225051573Smckusick } 225151573Smckusick 225251573Smckusick /* 225351573Smckusick * NFS flat namespace allocation. 225451573Smckusick * Currently unsupported. 225551573Smckusick */ 225652234Sheideman int 225753806Smckusick nfs_valloc(ap) 225854668Smckusick struct vop_valloc_args /* { 225954668Smckusick struct vnode *a_pvp; 226054668Smckusick int a_mode; 226154668Smckusick struct ucred *a_cred; 226254668Smckusick struct vnode **a_vpp; 226354668Smckusick } */ *ap; 226451573Smckusick { 226551573Smckusick 226651573Smckusick return (EOPNOTSUPP); 226751573Smckusick } 226851573Smckusick 226951573Smckusick /* 227051573Smckusick * NFS flat namespace free. 227151573Smckusick * Currently unsupported. 227251573Smckusick */ 227353582Sheideman int 227453806Smckusick nfs_vfree(ap) 227554668Smckusick struct vop_vfree_args /* { 227654668Smckusick struct vnode *a_pvp; 227754668Smckusick ino_t a_ino; 227854668Smckusick int a_mode; 227954668Smckusick } */ *ap; 228051573Smckusick { 228151573Smckusick 228253582Sheideman return (EOPNOTSUPP); 228351573Smckusick } 228451573Smckusick 228551573Smckusick /* 228651573Smckusick * NFS file truncation. 228751573Smckusick */ 228852234Sheideman int 228953806Smckusick nfs_truncate(ap) 229054668Smckusick struct vop_truncate_args /* { 229154668Smckusick struct vnode *a_vp; 229254668Smckusick off_t a_length; 229354668Smckusick int a_flags; 229454668Smckusick struct ucred *a_cred; 229554668Smckusick struct proc *a_p; 229654668Smckusick } */ *ap; 229751573Smckusick { 229851573Smckusick 229951573Smckusick /* Use nfs_setattr */ 230051573Smckusick printf("nfs_truncate: need to implement!!"); 230151573Smckusick return (EOPNOTSUPP); 230251573Smckusick } 230351573Smckusick 230451573Smckusick /* 230551573Smckusick * NFS update. 230651573Smckusick */ 230752234Sheideman int 230853806Smckusick nfs_update(ap) 230954668Smckusick struct vop_update_args /* { 231054668Smckusick struct vnode *a_vp; 231154668Smckusick struct timeval *a_ta; 231254668Smckusick struct timeval *a_tm; 231354668Smckusick int a_waitfor; 231454668Smckusick } */ *ap; 231551573Smckusick { 231651573Smckusick 231751573Smckusick /* Use nfs_setattr */ 231851573Smckusick printf("nfs_update: need to implement!!"); 231951573Smckusick return (EOPNOTSUPP); 232051573Smckusick } 232153629Smckusick 232253629Smckusick /* 232356364Smckusick * nfs special file access vnode op. 232456364Smckusick * Essentially just get vattr and then imitate iaccess() since the device is 232556364Smckusick * local to the client. 232656364Smckusick */ 232756364Smckusick int 232856364Smckusick nfsspec_access(ap) 232956364Smckusick struct vop_access_args /* { 233056364Smckusick struct vnode *a_vp; 233156364Smckusick int a_mode; 233256364Smckusick struct ucred *a_cred; 233356364Smckusick struct proc *a_p; 233456364Smckusick } */ *ap; 233556364Smckusick { 233656364Smckusick register struct vattr *vap; 233756364Smckusick register gid_t *gp; 233856364Smckusick register struct ucred *cred = ap->a_cred; 233956364Smckusick mode_t mode = ap->a_mode; 234056364Smckusick struct vattr vattr; 234156364Smckusick register int i; 234256364Smckusick int error; 234356364Smckusick 234456364Smckusick /* 234556364Smckusick * If you're the super-user, 234656364Smckusick * you always get access. 234756364Smckusick */ 234856364Smckusick if (cred->cr_uid == 0) 234956364Smckusick return (0); 235056364Smckusick vap = &vattr; 235156364Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 235256364Smckusick return (error); 235356364Smckusick /* 235456364Smckusick * Access check is based on only one of owner, group, public. 235556364Smckusick * If not owner, then check group. If not a member of the 235656364Smckusick * group, then check public access. 235756364Smckusick */ 235856364Smckusick if (cred->cr_uid != vap->va_uid) { 235956364Smckusick mode >>= 3; 236056364Smckusick gp = cred->cr_groups; 236156364Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 236256364Smckusick if (vap->va_gid == *gp) 236356364Smckusick goto found; 236456364Smckusick mode >>= 3; 236556364Smckusick found: 236656364Smckusick ; 236756364Smckusick } 236856364Smckusick if ((vap->va_mode & mode) != 0) 236956364Smckusick return (0); 237056364Smckusick return (EACCES); 237156364Smckusick } 237256364Smckusick 237356364Smckusick /* 237453629Smckusick * Read wrapper for special devices. 237553629Smckusick */ 237653629Smckusick int 237753629Smckusick nfsspec_read(ap) 237854668Smckusick struct vop_read_args /* { 237954668Smckusick struct vnode *a_vp; 238054668Smckusick struct uio *a_uio; 238154668Smckusick int a_ioflag; 238254668Smckusick struct ucred *a_cred; 238354668Smckusick } */ *ap; 238453629Smckusick { 238554032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 238653629Smckusick 238753629Smckusick /* 238853629Smckusick * Set access flag. 238953629Smckusick */ 239054032Smckusick np->n_flag |= NACC; 239154032Smckusick np->n_atim = time; 239253629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 239353629Smckusick } 239453629Smckusick 239553629Smckusick /* 239653629Smckusick * Write wrapper for special devices. 239753629Smckusick */ 239853629Smckusick int 239953629Smckusick nfsspec_write(ap) 240054668Smckusick struct vop_write_args /* { 240154668Smckusick struct vnode *a_vp; 240254668Smckusick struct uio *a_uio; 240354668Smckusick int a_ioflag; 240454668Smckusick struct ucred *a_cred; 240554668Smckusick } */ *ap; 240653629Smckusick { 240754032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 240853629Smckusick 240953629Smckusick /* 241054032Smckusick * Set update flag. 241153629Smckusick */ 241254032Smckusick np->n_flag |= NUPD; 241354032Smckusick np->n_mtim = time; 241453629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 241553629Smckusick } 241653629Smckusick 241753629Smckusick /* 241853629Smckusick * Close wrapper for special devices. 241953629Smckusick * 242053629Smckusick * Update the times on the nfsnode then do device close. 242153629Smckusick */ 242253629Smckusick int 242353629Smckusick nfsspec_close(ap) 242454668Smckusick struct vop_close_args /* { 242554668Smckusick struct vnode *a_vp; 242654668Smckusick int a_fflag; 242754668Smckusick struct ucred *a_cred; 242854668Smckusick struct proc *a_p; 242954668Smckusick } */ *ap; 243053629Smckusick { 243153806Smckusick register struct vnode *vp = ap->a_vp; 243253806Smckusick register struct nfsnode *np = VTONFS(vp); 243353629Smckusick struct vattr vattr; 243453629Smckusick 243553629Smckusick if (np->n_flag & (NACC | NUPD)) { 243653629Smckusick np->n_flag |= NCHG; 243753806Smckusick if (vp->v_usecount == 1 && 243853806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 243953629Smckusick VATTR_NULL(&vattr); 244054106Smckusick if (np->n_flag & NACC) { 244154106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 244254106Smckusick vattr.va_atime.ts_nsec = 244354106Smckusick np->n_atim.tv_usec * 1000; 244454106Smckusick } 244554106Smckusick if (np->n_flag & NUPD) { 244654106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 244754106Smckusick vattr.va_mtime.ts_nsec = 244854106Smckusick np->n_mtim.tv_usec * 1000; 244954106Smckusick } 245053806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 245153629Smckusick } 245253629Smckusick } 245353629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 245453629Smckusick } 245553629Smckusick 245653629Smckusick #ifdef FIFO 245753629Smckusick /* 245853629Smckusick * Read wrapper for fifos. 245953629Smckusick */ 246053629Smckusick int 246153629Smckusick nfsfifo_read(ap) 246254668Smckusick struct vop_read_args /* { 246354668Smckusick struct vnode *a_vp; 246454668Smckusick struct uio *a_uio; 246554668Smckusick int a_ioflag; 246654668Smckusick struct ucred *a_cred; 246754668Smckusick } */ *ap; 246853629Smckusick { 246953629Smckusick extern int (**fifo_vnodeop_p)(); 247054032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 247153629Smckusick 247253629Smckusick /* 247353629Smckusick * Set access flag. 247453629Smckusick */ 247554032Smckusick np->n_flag |= NACC; 247654032Smckusick np->n_atim = time; 247753629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 247853629Smckusick } 247953629Smckusick 248053629Smckusick /* 248153629Smckusick * Write wrapper for fifos. 248253629Smckusick */ 248353629Smckusick int 248453629Smckusick nfsfifo_write(ap) 248554668Smckusick struct vop_write_args /* { 248654668Smckusick struct vnode *a_vp; 248754668Smckusick struct uio *a_uio; 248854668Smckusick int a_ioflag; 248954668Smckusick struct ucred *a_cred; 249054668Smckusick } */ *ap; 249153629Smckusick { 249253629Smckusick extern int (**fifo_vnodeop_p)(); 249354032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 249453629Smckusick 249553629Smckusick /* 249653629Smckusick * Set update flag. 249753629Smckusick */ 249854032Smckusick np->n_flag |= NUPD; 249954032Smckusick np->n_mtim = time; 250053629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 250153629Smckusick } 250253629Smckusick 250353629Smckusick /* 250453629Smckusick * Close wrapper for fifos. 250553629Smckusick * 250653629Smckusick * Update the times on the nfsnode then do fifo close. 250753629Smckusick */ 250853629Smckusick int 250953629Smckusick nfsfifo_close(ap) 251054668Smckusick struct vop_close_args /* { 251154668Smckusick struct vnode *a_vp; 251254668Smckusick int a_fflag; 251354668Smckusick struct ucred *a_cred; 251454668Smckusick struct proc *a_p; 251554668Smckusick } */ *ap; 251653629Smckusick { 251753806Smckusick register struct vnode *vp = ap->a_vp; 251853806Smckusick register struct nfsnode *np = VTONFS(vp); 251953629Smckusick struct vattr vattr; 252053629Smckusick extern int (**fifo_vnodeop_p)(); 252153629Smckusick 252253629Smckusick if (np->n_flag & (NACC | NUPD)) { 252353629Smckusick if (np->n_flag & NACC) 252453629Smckusick np->n_atim = time; 252553629Smckusick if (np->n_flag & NUPD) 252653629Smckusick np->n_mtim = time; 252753629Smckusick np->n_flag |= NCHG; 252853806Smckusick if (vp->v_usecount == 1 && 252953806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 253053629Smckusick VATTR_NULL(&vattr); 253154106Smckusick if (np->n_flag & NACC) { 253254106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 253354106Smckusick vattr.va_atime.ts_nsec = 253454106Smckusick np->n_atim.tv_usec * 1000; 253554106Smckusick } 253654106Smckusick if (np->n_flag & NUPD) { 253754106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 253854106Smckusick vattr.va_mtime.ts_nsec = 253954106Smckusick np->n_mtim.tv_usec * 1000; 254054106Smckusick } 254153806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 254253629Smckusick } 254353629Smckusick } 254453629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 254553629Smckusick } 254653629Smckusick #endif /* FIFO */ 2547