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*56364Smckusick * @(#)nfs_vnops.c 7.93 (Berkeley) 09/30/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 */ 110*56364Smckusick { &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 */ 158*56364Smckusick { &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]; 204*56364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false; 20538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG]; 20638884Smacklem struct buf nfs_bqueue; /* Queue head for nfsiod's */ 20741905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 20846988Smckusick int nfs_numasync = 0; 20954740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 21038414Smckusick 21138414Smckusick /* 21238414Smckusick * nfs null call from vfs. 21338414Smckusick */ 21452234Sheideman int 21552196Smckusick nfs_null(vp, cred, procp) 21638414Smckusick struct vnode *vp; 21738414Smckusick struct ucred *cred; 21852196Smckusick struct proc *procp; 21938414Smckusick { 22039488Smckusick caddr_t bpos, dpos; 22139488Smckusick int error = 0; 22239488Smckusick struct mbuf *mreq, *mrep, *md, *mb; 22338414Smckusick 22452196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0); 22552196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred); 22638414Smckusick nfsm_reqdone; 22738414Smckusick return (error); 22838414Smckusick } 22938414Smckusick 23038414Smckusick /* 23138414Smckusick * nfs access vnode op. 232*56364Smckusick * For nfs, just return ok. File accesses may fail later. 233*56364Smckusick * For nqnfs, use the access rpc to check accessibility. If file modes are 234*56364Smckusick * changed on the server, accesses might still fail later. 23538414Smckusick */ 23652234Sheideman int 23753806Smckusick nfs_access(ap) 23854668Smckusick struct vop_access_args /* { 23954668Smckusick struct vnode *a_vp; 24054668Smckusick int a_mode; 24154668Smckusick struct ucred *a_cred; 24254668Smckusick struct proc *a_p; 24354668Smckusick } */ *ap; 24438414Smckusick { 245*56364Smckusick register struct vnode *vp = ap->a_vp; 246*56364Smckusick register u_long *tl; 247*56364Smckusick register caddr_t cp; 248*56364Smckusick caddr_t bpos, dpos; 249*56364Smckusick int error = 0; 250*56364Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 25138414Smckusick 25238414Smckusick /* 253*56364Smckusick * There is no way to check accessibility via. ordinary nfs, so if 254*56364Smckusick * access isn't allowed they will get burned later. 25538414Smckusick */ 256*56364Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 257*56364Smckusick nfsstats.rpccnt[NQNFSPROC_ACCESS]++; 258*56364Smckusick nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED); 259*56364Smckusick nfsm_fhtom(vp); 260*56364Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 261*56364Smckusick if (ap->a_mode & VREAD) 262*56364Smckusick *tl++ = nfs_true; 263*56364Smckusick else 264*56364Smckusick *tl++ = nfs_false; 265*56364Smckusick if (ap->a_mode & VWRITE) 266*56364Smckusick *tl++ = nfs_true; 267*56364Smckusick else 268*56364Smckusick *tl++ = nfs_false; 269*56364Smckusick if (ap->a_mode & VEXEC) 270*56364Smckusick *tl = nfs_true; 271*56364Smckusick else 272*56364Smckusick *tl = nfs_false; 273*56364Smckusick nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred); 274*56364Smckusick nfsm_reqdone; 27538884Smacklem return (error); 276*56364Smckusick } else 27738414Smckusick return (0); 27838414Smckusick } 27938414Smckusick 28038414Smckusick /* 28138414Smckusick * nfs open vnode op 28256289Smckusick * Check to see if the type is ok 28352196Smckusick * and that deletion is not in progress. 28456289Smckusick * For paged in text files, you will need to flush the page cache 28556289Smckusick * if consistency is lost. 28638414Smckusick */ 28739488Smckusick /* ARGSUSED */ 28852234Sheideman int 28953806Smckusick nfs_open(ap) 29054668Smckusick struct vop_open_args /* { 29154668Smckusick struct vnode *a_vp; 29254668Smckusick int a_mode; 29354668Smckusick struct ucred *a_cred; 29454668Smckusick struct proc *a_p; 29554668Smckusick } */ *ap; 29638414Smckusick { 29753806Smckusick register struct vnode *vp = ap->a_vp; 29856289Smckusick struct nfsnode *np = VTONFS(vp); 29956289Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount); 30056289Smckusick struct vattr vattr; 30156289Smckusick int error; 30238414Smckusick 30353806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 30438414Smckusick return (EACCES); 30556289Smckusick if (vp->v_flag & VTEXT) { 30656289Smckusick /* 30756289Smckusick * Get a valid lease. If cached data is stale, flush it. 30856289Smckusick */ 30956289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 31056289Smckusick if (NQNFS_CKINVALID(vp, np, NQL_READ)) { 31156289Smckusick do { 31256289Smckusick error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p); 31356289Smckusick } while (error == NQNFS_EXPIRED); 31456289Smckusick if (error) 31556289Smckusick return (error); 31656289Smckusick if (np->n_lrev != np->n_brev) { 31756289Smckusick np->n_flag &= ~NMODIFIED; 31856289Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 31956289Smckusick (void) vnode_pager_uncache(vp); 32056289Smckusick np->n_brev = np->n_lrev; 32156289Smckusick } 32256289Smckusick } 32356289Smckusick } else { 32456289Smckusick if (np->n_flag & NMODIFIED) { 32556289Smckusick np->n_flag &= ~NMODIFIED; 32656289Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 32756289Smckusick (void) vnode_pager_uncache(vp); 32856289Smckusick np->n_attrstamp = 0; 32956289Smckusick np->n_direofoffset = 0; 33056289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 33156289Smckusick return (error); 33256289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 33356289Smckusick } else { 33456289Smckusick if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) 33556289Smckusick return (error); 33656289Smckusick if (np->n_mtime != vattr.va_mtime.ts_sec) { 33756289Smckusick np->n_direofoffset = 0; 33856289Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 33956289Smckusick (void) vnode_pager_uncache(vp); 34056289Smckusick np->n_mtime = vattr.va_mtime.ts_sec; 34156289Smckusick } 34256289Smckusick } 34356289Smckusick } 34456289Smckusick } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 34556289Smckusick np->n_attrstamp = 0; /* For Open/Close consistency */ 34652196Smckusick return (0); 34738414Smckusick } 34838414Smckusick 34938414Smckusick /* 35038414Smckusick * nfs close vnode op 35138884Smacklem * For reg files, invalidate any buffer cache entries. 35238414Smckusick */ 35339488Smckusick /* ARGSUSED */ 35452234Sheideman int 35553806Smckusick nfs_close(ap) 35654451Smckusick struct vop_close_args /* { 35754451Smckusick struct vnodeop_desc *a_desc; 35854451Smckusick struct vnode *a_vp; 35954451Smckusick int a_fflag; 36054451Smckusick struct ucred *a_cred; 36154451Smckusick struct proc *a_p; 36254451Smckusick } */ *ap; 36338414Smckusick { 36453806Smckusick register struct vnode *vp = ap->a_vp; 36553806Smckusick register struct nfsnode *np = VTONFS(vp); 36639341Smckusick int error = 0; 36738414Smckusick 36853806Smckusick if (vp->v_type == VREG) { 36953806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && 37053629Smckusick (np->n_flag & NMODIFIED)) { 37154451Smckusick error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 37241905Smckusick np->n_flag &= ~NMODIFIED; 37341905Smckusick np->n_attrstamp = 0; 37453629Smckusick } 37553629Smckusick if (np->n_flag & NWRITEERR) { 37653629Smckusick np->n_flag &= ~NWRITEERR; 37753629Smckusick error = np->n_error; 37853629Smckusick } 37938884Smacklem } 38038414Smckusick return (error); 38138414Smckusick } 38238414Smckusick 38338414Smckusick /* 38438414Smckusick * nfs getattr call from vfs. 38538414Smckusick */ 38652234Sheideman int 38753805Smckusick nfs_getattr(ap) 38854668Smckusick struct vop_getattr_args /* { 38954668Smckusick struct vnode *a_vp; 39054668Smckusick struct vattr *a_vap; 39154668Smckusick struct ucred *a_cred; 39254668Smckusick struct proc *a_p; 39354668Smckusick } */ *ap; 39438414Smckusick { 39553805Smckusick register struct vnode *vp = ap->a_vp; 39653805Smckusick register struct nfsnode *np = VTONFS(vp); 39739488Smckusick register caddr_t cp; 39839488Smckusick caddr_t bpos, dpos; 39939488Smckusick int error = 0; 40039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 40138414Smckusick 40253805Smckusick /* 40353805Smckusick * Update local times for special files. 40453805Smckusick */ 40556329Smckusick if (np->n_flag & (NACC | NUPD)) 40653805Smckusick np->n_flag |= NCHG; 40753805Smckusick /* 40853805Smckusick * First look in the cache. 40953805Smckusick */ 41053805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0) 41138414Smckusick return (0); 41238414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++; 41353805Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); 41453805Smckusick nfsm_fhtom(vp); 41553805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); 41653805Smckusick nfsm_loadattr(vp, ap->a_vap); 41738414Smckusick nfsm_reqdone; 41838414Smckusick return (error); 41938414Smckusick } 42038414Smckusick 42138414Smckusick /* 42238414Smckusick * nfs setattr call. 42338414Smckusick */ 42452234Sheideman int 42553806Smckusick nfs_setattr(ap) 42654451Smckusick struct vop_setattr_args /* { 42754451Smckusick struct vnodeop_desc *a_desc; 42854451Smckusick struct vnode *a_vp; 42954451Smckusick struct vattr *a_vap; 43054451Smckusick struct ucred *a_cred; 43154451Smckusick struct proc *a_p; 43254451Smckusick } */ *ap; 43338414Smckusick { 43438884Smacklem register struct nfsv2_sattr *sp; 43539488Smckusick register caddr_t cp; 43639488Smckusick register long t1; 43752196Smckusick caddr_t bpos, dpos, cp2; 43852196Smckusick u_long *tl; 43956289Smckusick int error = 0, isnq; 44039488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 44153806Smckusick register struct vnode *vp = ap->a_vp; 44253806Smckusick register struct nfsnode *np = VTONFS(vp); 44353806Smckusick register struct vattr *vap = ap->a_vap; 44452196Smckusick u_quad_t frev; 44538414Smckusick 44638414Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++; 44756289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 44856289Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq)); 44953806Smckusick nfsm_fhtom(vp); 45056289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 45156289Smckusick if (vap->va_mode == (u_short)-1) 45238884Smacklem sp->sa_mode = VNOVAL; 45338414Smckusick else 45453806Smckusick sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); 45556289Smckusick if (vap->va_uid == (uid_t)-1) 45638884Smacklem sp->sa_uid = VNOVAL; 45738414Smckusick else 45853806Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid); 45956289Smckusick if (vap->va_gid == (gid_t)-1) 46038884Smacklem sp->sa_gid = VNOVAL; 46138414Smckusick else 46253806Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid); 46356289Smckusick if (isnq) { 46456289Smckusick txdr_hyper(&vap->va_size, &sp->sa_nqsize); 46556289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 46656289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 46756289Smckusick sp->sa_nqflags = txdr_unsigned(vap->va_flags); 46856289Smckusick sp->sa_nqrdev = VNOVAL; 46956289Smckusick } else { 47056289Smckusick sp->sa_nfssize = txdr_unsigned(vap->va_size); 47156289Smckusick sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec); 47256289Smckusick sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags); 47356289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 47456289Smckusick } 47554106Smckusick if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || 47654106Smckusick vap->va_atime.ts_sec != VNOVAL) { 47739359Smckusick if (np->n_flag & NMODIFIED) { 47853806Smckusick if (vap->va_size == 0) 47954451Smckusick error = 48054451Smckusick vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p); 48146988Smckusick else 48254451Smckusick error = 48354451Smckusick vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p); 48454451Smckusick np->n_flag &= ~NMODIFIED; 48539359Smckusick } 48656289Smckusick if (vap->va_size != VNOVAL) 48756289Smckusick np->n_size = np->n_vattr.va_size = vap->va_size; 48839359Smckusick } 48953806Smckusick nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); 49053806Smckusick nfsm_loadattr(vp, (struct vattr *)0); 49153806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && 49253806Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 49352196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 49452196Smckusick fxdr_hyper(tl, &frev); 49554451Smckusick if (frev > np->n_brev) 49652196Smckusick np->n_brev = frev; 49752196Smckusick } 49838414Smckusick nfsm_reqdone; 49938414Smckusick return (error); 50038414Smckusick } 50138414Smckusick 50238414Smckusick /* 50338414Smckusick * nfs lookup call, one step at a time... 50438414Smckusick * First look in cache 50538414Smckusick * If not found, unlock the directory nfsnode and do the rpc 50638414Smckusick */ 50752234Sheideman int 50853806Smckusick nfs_lookup(ap) 50954451Smckusick struct vop_lookup_args /* { 51054451Smckusick struct vnodeop_desc *a_desc; 51154451Smckusick struct vnode *a_dvp; 51254451Smckusick struct vnode **a_vpp; 51354451Smckusick struct componentname *a_cnp; 51454451Smckusick } */ *ap; 51538414Smckusick { 51653806Smckusick register struct componentname *cnp = ap->a_cnp; 51753806Smckusick register struct vnode *dvp = ap->a_dvp; 51854668Smckusick register struct vnode **vpp = ap->a_vpp; 51955184Smckusick register int flags = cnp->cn_flags; 52038414Smckusick register struct vnode *vdp; 52148054Smckusick register u_long *tl; 52239488Smckusick register caddr_t cp; 52339488Smckusick register long t1, t2; 52452196Smckusick struct nfsmount *nmp; 52552196Smckusick struct nfsnode *tp; 52639488Smckusick caddr_t bpos, dpos, cp2; 52752196Smckusick time_t reqtime; 52839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 52938414Smckusick struct vnode *newvp; 53038414Smckusick long len; 53138414Smckusick nfsv2fh_t *fhp; 53238414Smckusick struct nfsnode *np; 53352234Sheideman int lockparent, wantparent, error = 0; 53452196Smckusick int nqlflag, cachable; 53552196Smckusick u_quad_t frev; 53638414Smckusick 53754668Smckusick *vpp = NULL; 53853806Smckusick if (dvp->v_type != VDIR) 53938414Smckusick return (ENOTDIR); 54055184Smckusick lockparent = flags & LOCKPARENT; 54155184Smckusick wantparent = flags & (LOCKPARENT|WANTPARENT); 54253806Smckusick nmp = VFSTONFS(dvp->v_mount); 54353806Smckusick np = VTONFS(dvp); 54454668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { 54538884Smacklem struct vattr vattr; 54638884Smacklem int vpid; 54738884Smacklem 54854668Smckusick vdp = *vpp; 54938884Smacklem vpid = vdp->v_id; 55038414Smckusick /* 55138884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c 55238884Smacklem * for an explanation of the locking protocol 55338414Smckusick */ 55453806Smckusick if (dvp == vdp) { 55538425Smckusick VREF(vdp); 55639441Smckusick error = 0; 55752196Smckusick } else 55839441Smckusick error = vget(vdp); 55939441Smckusick if (!error) { 56040251Smckusick if (vpid == vdp->v_id) { 56152196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 56256289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) { 56356289Smckusick nfsstats.lookupcache_hits++; 56456289Smckusick if (cnp->cn_nameiop != LOOKUP && 56556289Smckusick (flags & ISLASTCN)) 56656289Smckusick cnp->cn_flags |= SAVENAME; 56756289Smckusick return (0); 56856289Smckusick } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { 56954451Smckusick if (np->n_lrev != np->n_brev || 57052196Smckusick (np->n_flag & NMODIFIED)) { 57152196Smckusick np->n_direofoffset = 0; 57253806Smckusick cache_purge(dvp); 57354451Smckusick error = vinvalbuf(dvp, FALSE, 57454451Smckusick cnp->cn_cred, cnp->cn_proc); 57552196Smckusick np->n_flag &= ~NMODIFIED; 57652196Smckusick np->n_brev = np->n_lrev; 57752196Smckusick } else { 57852196Smckusick nfsstats.lookupcache_hits++; 57953806Smckusick if (cnp->cn_nameiop != LOOKUP && 58055184Smckusick (flags & ISLASTCN)) 58153806Smckusick cnp->cn_flags |= SAVENAME; 58252196Smckusick return (0); 58352196Smckusick } 58452196Smckusick } 58553806Smckusick } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && 58654106Smckusick vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { 58739441Smckusick nfsstats.lookupcache_hits++; 58853806Smckusick if (cnp->cn_nameiop != LOOKUP && 58955184Smckusick (flags & ISLASTCN)) 59053806Smckusick cnp->cn_flags |= SAVENAME; 59139441Smckusick return (0); 59240251Smckusick } 59347289Smckusick cache_purge(vdp); 59439441Smckusick } 59552196Smckusick vrele(vdp); 59638884Smacklem } 59754668Smckusick *vpp = NULLVP; 59852196Smckusick } 59939341Smckusick error = 0; 60038414Smckusick nfsstats.lookupcache_misses++; 60138414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 60253806Smckusick len = cnp->cn_namelen; 60353806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 60452196Smckusick 60552196Smckusick /* 60652196Smckusick * For nqnfs optionally piggyback a getlease request for the name 60752196Smckusick * being looked up. 60852196Smckusick */ 60952196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 61056289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 61152196Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 61255184Smckusick ((cnp->cn_flags & MAKEENTRY) && 61356289Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) 61452196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 61556289Smckusick else 61652196Smckusick *tl = 0; 61752196Smckusick } 61853806Smckusick nfsm_fhtom(dvp); 61953806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 62052196Smckusick reqtime = time.tv_sec; 62153806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 62238414Smckusick nfsmout: 62338414Smckusick if (error) { 62453806Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 62555184Smckusick (flags & ISLASTCN) && error == ENOENT) 62652823Smckusick error = EJUSTRETURN; 62755184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 62853806Smckusick cnp->cn_flags |= SAVENAME; 62940483Smckusick return (error); 63038414Smckusick } 63152196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 63252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 63352196Smckusick if (*tl) { 63452196Smckusick nqlflag = fxdr_unsigned(int, *tl); 63552196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 63652196Smckusick cachable = fxdr_unsigned(int, *tl++); 63752196Smckusick reqtime += fxdr_unsigned(int, *tl++); 63852196Smckusick fxdr_hyper(tl, &frev); 63952196Smckusick } else 64052196Smckusick nqlflag = 0; 64152196Smckusick } 64252196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 64338414Smckusick 64438414Smckusick /* 64552196Smckusick * Handle RENAME case... 64638414Smckusick */ 64755184Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 64852196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 64938414Smckusick m_freem(mrep); 65038414Smckusick return (EISDIR); 65138414Smckusick } 65253806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 65338414Smckusick m_freem(mrep); 65438414Smckusick return (error); 65538414Smckusick } 65638414Smckusick newvp = NFSTOV(np); 65739459Smckusick if (error = 65839459Smckusick nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 65952196Smckusick vrele(newvp); 66038414Smckusick m_freem(mrep); 66138414Smckusick return (error); 66238414Smckusick } 66354668Smckusick *vpp = newvp; 66445037Smckusick m_freem(mrep); 66553806Smckusick cnp->cn_flags |= SAVENAME; 66638414Smckusick return (0); 66738414Smckusick } 66838414Smckusick 66952196Smckusick if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 67053806Smckusick VREF(dvp); 67153806Smckusick newvp = dvp; 67238414Smckusick } else { 67353806Smckusick if (error = nfs_nget(dvp->v_mount, fhp, &np)) { 67438414Smckusick m_freem(mrep); 67538414Smckusick return (error); 67638414Smckusick } 67738414Smckusick newvp = NFSTOV(np); 67838414Smckusick } 67939459Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { 68052196Smckusick vrele(newvp); 68138414Smckusick m_freem(mrep); 68238414Smckusick return (error); 68338414Smckusick } 68438414Smckusick m_freem(mrep); 68554668Smckusick *vpp = newvp; 68655184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 68753806Smckusick cnp->cn_flags |= SAVENAME; 68855184Smckusick if ((cnp->cn_flags & MAKEENTRY) && 68955184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { 69052196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) 69154106Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec; 69256289Smckusick else if (nqlflag && reqtime > time.tv_sec) 69356289Smckusick nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime, 69456289Smckusick frev); 69554668Smckusick cache_enter(dvp, *vpp, cnp); 69640251Smckusick } 69752196Smckusick return (0); 69838414Smckusick } 69938414Smckusick 70038414Smckusick /* 70141905Smckusick * nfs read call. 70241905Smckusick * Just call nfs_bioread() to do the work. 70341905Smckusick */ 70452234Sheideman int 70553806Smckusick nfs_read(ap) 70654668Smckusick struct vop_read_args /* { 70754668Smckusick struct vnode *a_vp; 70854668Smckusick struct uio *a_uio; 70954668Smckusick int a_ioflag; 71054668Smckusick struct ucred *a_cred; 71154668Smckusick } */ *ap; 71241905Smckusick { 71353806Smckusick register struct vnode *vp = ap->a_vp; 71453806Smckusick 71553806Smckusick if (vp->v_type != VREG) 71641905Smckusick return (EPERM); 71753806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 71841905Smckusick } 71941905Smckusick 72041905Smckusick /* 72138414Smckusick * nfs readlink call 72238414Smckusick */ 72352234Sheideman int 72453806Smckusick nfs_readlink(ap) 72554668Smckusick struct vop_readlink_args /* { 72654668Smckusick struct vnode *a_vp; 72754668Smckusick struct uio *a_uio; 72854668Smckusick struct ucred *a_cred; 72954668Smckusick } */ *ap; 73041905Smckusick { 73153806Smckusick register struct vnode *vp = ap->a_vp; 73253806Smckusick 73353806Smckusick if (vp->v_type != VLNK) 73441905Smckusick return (EPERM); 73553806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); 73641905Smckusick } 73741905Smckusick 73841905Smckusick /* 73941905Smckusick * Do a readlink rpc. 74041905Smckusick * Called by nfs_doio() from below the buffer cache. 74141905Smckusick */ 74252234Sheideman int 74348054Smckusick nfs_readlinkrpc(vp, uiop, cred) 74439488Smckusick register struct vnode *vp; 74538414Smckusick struct uio *uiop; 74638414Smckusick struct ucred *cred; 74738414Smckusick { 74848054Smckusick register u_long *tl; 74939488Smckusick register caddr_t cp; 75039488Smckusick register long t1; 75139488Smckusick caddr_t bpos, dpos, cp2; 75239488Smckusick int error = 0; 75339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 75438414Smckusick long len; 75538414Smckusick 75638414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++; 75752196Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); 75838414Smckusick nfsm_fhtom(vp); 75952196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); 76038414Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN); 76138414Smckusick nfsm_mtouio(uiop, len); 76238414Smckusick nfsm_reqdone; 76338414Smckusick return (error); 76438414Smckusick } 76538414Smckusick 76638414Smckusick /* 76741905Smckusick * nfs read rpc call 76841905Smckusick * Ditto above 76938414Smckusick */ 77052234Sheideman int 77148054Smckusick nfs_readrpc(vp, uiop, cred) 77239488Smckusick register struct vnode *vp; 77338414Smckusick struct uio *uiop; 77438414Smckusick struct ucred *cred; 77538414Smckusick { 77648054Smckusick register u_long *tl; 77739488Smckusick register caddr_t cp; 77839488Smckusick register long t1; 77939488Smckusick caddr_t bpos, dpos, cp2; 78039488Smckusick int error = 0; 78139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 78238414Smckusick struct nfsmount *nmp; 78338414Smckusick long len, retlen, tsiz; 78438414Smckusick 78541398Smckusick nmp = VFSTONFS(vp->v_mount); 78638414Smckusick tsiz = uiop->uio_resid; 78756289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 78856289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 78956289Smckusick return (EFBIG); 79038414Smckusick while (tsiz > 0) { 79138414Smckusick nfsstats.rpccnt[NFSPROC_READ]++; 79238414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 79352196Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); 79438414Smckusick nfsm_fhtom(vp); 79548054Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); 79656289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 79756289Smckusick txdr_hyper(&uiop->uio_offset, tl); 79856289Smckusick *(tl + 2) = txdr_unsigned(len); 79956289Smckusick } else { 80056289Smckusick *tl++ = txdr_unsigned(uiop->uio_offset); 80156289Smckusick *tl++ = txdr_unsigned(len); 80256289Smckusick *tl = 0; 80356289Smckusick } 80452196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); 80538414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 80638414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize); 80738414Smckusick nfsm_mtouio(uiop, retlen); 80838414Smckusick m_freem(mrep); 80938414Smckusick if (retlen < len) 81038414Smckusick tsiz = 0; 81138414Smckusick else 81238414Smckusick tsiz -= len; 81338414Smckusick } 81438414Smckusick nfsmout: 81538414Smckusick return (error); 81638414Smckusick } 81738414Smckusick 81838414Smckusick /* 81938414Smckusick * nfs write call 82038414Smckusick */ 82152234Sheideman int 82256289Smckusick nfs_writerpc(vp, uiop, cred, ioflags) 82339488Smckusick register struct vnode *vp; 82438414Smckusick struct uio *uiop; 82538414Smckusick struct ucred *cred; 82656289Smckusick int ioflags; 82738414Smckusick { 82848054Smckusick register u_long *tl; 82939488Smckusick register caddr_t cp; 83039488Smckusick register long t1; 83152196Smckusick caddr_t bpos, dpos, cp2; 83239488Smckusick int error = 0; 83339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 83438414Smckusick struct nfsmount *nmp; 83552196Smckusick struct nfsnode *np = VTONFS(vp); 83652196Smckusick u_quad_t frev; 83738414Smckusick long len, tsiz; 83838414Smckusick 83941398Smckusick nmp = VFSTONFS(vp->v_mount); 84038414Smckusick tsiz = uiop->uio_resid; 84156289Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && 84256289Smckusick (nmp->nm_flag & NFSMNT_NQNFS) == 0) 84356289Smckusick return (EFBIG); 84438414Smckusick while (tsiz > 0) { 84538414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++; 84638414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; 84752196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE, 84852196Smckusick NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); 84938414Smckusick nfsm_fhtom(vp); 85056289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4); 85156289Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 85256289Smckusick txdr_hyper(&uiop->uio_offset, tl); 85356289Smckusick tl += 2; 85456289Smckusick if (ioflags & IO_APPEND) 85556289Smckusick *tl++ = txdr_unsigned(1); 85656289Smckusick else 85756289Smckusick *tl++ = 0; 85856289Smckusick } else { 85956289Smckusick *++tl = txdr_unsigned(uiop->uio_offset); 86056289Smckusick tl += 2; 86156289Smckusick } 86256289Smckusick *tl = txdr_unsigned(len); 86338414Smckusick nfsm_uiotom(uiop, len); 86452196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); 86538414Smckusick nfsm_loadattr(vp, (struct vattr *)0); 86652196Smckusick if (nmp->nm_flag & NFSMNT_MYWRITE) 86754106Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; 86852196Smckusick else if ((nmp->nm_flag & NFSMNT_NQNFS) && 86952196Smckusick NQNFS_CKCACHABLE(vp, NQL_WRITE)) { 87052196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 87152196Smckusick fxdr_hyper(tl, &frev); 87254451Smckusick if (frev > np->n_brev) 87352196Smckusick np->n_brev = frev; 87452196Smckusick } 87538414Smckusick m_freem(mrep); 87638414Smckusick tsiz -= len; 87738414Smckusick } 87838414Smckusick nfsmout: 87952196Smckusick if (error) 88052196Smckusick uiop->uio_resid = tsiz; 88138414Smckusick return (error); 88238414Smckusick } 88338414Smckusick 88438414Smckusick /* 88539459Smckusick * nfs mknod call 88642246Smckusick * This is a kludge. Use a create rpc but with the IFMT bits of the mode 88742246Smckusick * set to specify the file type and the size field for rdev. 88839459Smckusick */ 88939459Smckusick /* ARGSUSED */ 89052234Sheideman int 89153806Smckusick nfs_mknod(ap) 89254668Smckusick struct vop_mknod_args /* { 89354668Smckusick struct vnode *a_dvp; 89454668Smckusick struct vnode **a_vpp; 89554668Smckusick struct componentname *a_cnp; 89654668Smckusick struct vattr *a_vap; 89754668Smckusick } */ *ap; 89839459Smckusick { 89953806Smckusick register struct vnode *dvp = ap->a_dvp; 90053806Smckusick register struct vattr *vap = ap->a_vap; 90153806Smckusick register struct componentname *cnp = ap->a_cnp; 90242246Smckusick register struct nfsv2_sattr *sp; 90348054Smckusick register u_long *tl; 90442246Smckusick register caddr_t cp; 90556289Smckusick register long t1, t2; 90656289Smckusick struct vnode *newvp; 90756289Smckusick char *cp2; 90842246Smckusick caddr_t bpos, dpos; 90956289Smckusick int error = 0, isnq; 91042246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 91142246Smckusick u_long rdev; 91239459Smckusick 91356289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 91453806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) 91553806Smckusick rdev = txdr_unsigned(vap->va_rdev); 91642246Smckusick #ifdef FIFO 91753806Smckusick else if (vap->va_type == VFIFO) 91842246Smckusick rdev = 0xffffffff; 91942246Smckusick #endif /* FIFO */ 92042246Smckusick else { 92153806Smckusick VOP_ABORTOP(dvp, cnp); 92253806Smckusick vput(dvp); 92342246Smckusick return (EOPNOTSUPP); 92442246Smckusick } 92542246Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 92653806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 92756289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 92853806Smckusick nfsm_fhtom(dvp); 92953806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 93056289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 93153806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 93253806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 93353806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 93456289Smckusick if (isnq) { 93556289Smckusick sp->sa_nqrdev = rdev; 93656289Smckusick sp->sa_nqflags = 0; 93756289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 93856289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 93956289Smckusick } else { 94056289Smckusick sp->sa_nfssize = rdev; 94156289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 94256289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 94356289Smckusick } 94453806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 94556289Smckusick nfsm_mtofh(dvp, newvp); 94642246Smckusick nfsm_reqdone; 94756289Smckusick if (!error) 94856289Smckusick cache_enter(dvp, newvp, cnp); 94953806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 95053806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 95153806Smckusick vrele(dvp); 95242246Smckusick return (error); 95339459Smckusick } 95439459Smckusick 95539459Smckusick /* 95638414Smckusick * nfs file create call 95738414Smckusick */ 95852234Sheideman int 95953806Smckusick nfs_create(ap) 96054668Smckusick struct vop_create_args /* { 96154668Smckusick struct vnode *a_dvp; 96254668Smckusick struct vnode **a_vpp; 96354668Smckusick struct componentname *a_cnp; 96454668Smckusick struct vattr *a_vap; 96554668Smckusick } */ *ap; 96638414Smckusick { 96753806Smckusick register struct vnode *dvp = ap->a_dvp; 96853806Smckusick register struct vattr *vap = ap->a_vap; 96953806Smckusick register struct componentname *cnp = ap->a_cnp; 97038884Smacklem register struct nfsv2_sattr *sp; 97148054Smckusick register u_long *tl; 97239488Smckusick register caddr_t cp; 97339488Smckusick register long t1, t2; 97439488Smckusick caddr_t bpos, dpos, cp2; 97556289Smckusick int error = 0, isnq; 97639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 97738414Smckusick 97838414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++; 97956289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 98053806Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, 98156289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); 98253806Smckusick nfsm_fhtom(dvp); 98353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 98456289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 98553806Smckusick sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); 98653806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 98753806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 98856289Smckusick if (isnq) { 98956289Smckusick u_quad_t qval = 0; 99056289Smckusick 99156289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 99256289Smckusick sp->sa_nqflags = 0; 99356289Smckusick sp->sa_nqrdev = -1; 99456289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 99556289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 99656289Smckusick } else { 99756289Smckusick sp->sa_nfssize = 0; 99856289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 99956289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 100056289Smckusick } 100153806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); 100253806Smckusick nfsm_mtofh(dvp, *ap->a_vpp); 100338414Smckusick nfsm_reqdone; 100456289Smckusick if (!error) 100556289Smckusick cache_enter(dvp, *ap->a_vpp, cnp); 100653806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 100753806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 100853806Smckusick vrele(dvp); 100938414Smckusick return (error); 101038414Smckusick } 101138414Smckusick 101238414Smckusick /* 101338414Smckusick * nfs file remove call 101441905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has 101541905Smckusick * other processes using the vnode is renamed instead of removed and then 101639341Smckusick * removed later on the last close. 101741905Smckusick * - If v_usecount > 1 101839341Smckusick * If a rename is not already in the works 101939341Smckusick * call nfs_sillyrename() to set it up 102039341Smckusick * else 102139341Smckusick * do the remove rpc 102238414Smckusick */ 102352234Sheideman int 102453806Smckusick nfs_remove(ap) 102554451Smckusick struct vop_remove_args /* { 102654451Smckusick struct vnodeop_desc *a_desc; 102754451Smckusick struct vnode * a_dvp; 102854451Smckusick struct vnode * a_vp; 102954451Smckusick struct componentname * a_cnp; 103054451Smckusick } */ *ap; 103138414Smckusick { 103253806Smckusick register struct vnode *vp = ap->a_vp; 103353806Smckusick register struct vnode *dvp = ap->a_dvp; 103453806Smckusick register struct componentname *cnp = ap->a_cnp; 103553806Smckusick register struct nfsnode *np = VTONFS(vp); 103648054Smckusick register u_long *tl; 103739488Smckusick register caddr_t cp; 103852196Smckusick register long t2; 103939488Smckusick caddr_t bpos, dpos; 104039488Smckusick int error = 0; 104139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 104238414Smckusick 104353806Smckusick if (vp->v_usecount > 1) { 104439341Smckusick if (!np->n_sillyrename) 104553806Smckusick error = nfs_sillyrename(dvp, vp, cnp); 104639341Smckusick } else { 104752196Smckusick /* 104852196Smckusick * Purge the name cache so that the chance of a lookup for 104952196Smckusick * the name succeeding while the remove is in progress is 105052196Smckusick * minimized. Without node locking it can still happen, such 105152196Smckusick * that an I/O op returns ESTALE, but since you get this if 105252196Smckusick * another host removes the file.. 105352196Smckusick */ 105453806Smckusick cache_purge(vp); 105552196Smckusick /* 105652196Smckusick * Throw away biocache buffers. Mainly to avoid 105752196Smckusick * unnecessary delayed writes. 105852196Smckusick */ 105954451Smckusick error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc); 106052196Smckusick /* Do the rpc */ 106138414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 106253806Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE, 106353806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 106453806Smckusick nfsm_fhtom(dvp); 106553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 106653806Smckusick nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); 106738414Smckusick nfsm_reqdone; 106853806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 106953806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 107039751Smckusick /* 107139751Smckusick * Kludge City: If the first reply to the remove rpc is lost.. 107239751Smckusick * the reply to the retransmitted request will be ENOENT 107339751Smckusick * since the file was in fact removed 107439751Smckusick * Therefore, we cheat and return success. 107539751Smckusick */ 107639751Smckusick if (error == ENOENT) 107739751Smckusick error = 0; 107838414Smckusick } 107940042Smckusick np->n_attrstamp = 0; 108053806Smckusick vrele(dvp); 108153806Smckusick vrele(vp); 108238414Smckusick return (error); 108338414Smckusick } 108438414Smckusick 108538414Smckusick /* 108638414Smckusick * nfs file remove rpc called from nfs_inactive 108738414Smckusick */ 108852234Sheideman int 108954451Smckusick nfs_removeit(sp) 109048364Smckusick register struct sillyrename *sp; 109138414Smckusick { 109248054Smckusick register u_long *tl; 109339488Smckusick register caddr_t cp; 109452196Smckusick register long t2; 109539488Smckusick caddr_t bpos, dpos; 109639488Smckusick int error = 0; 109739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 109838414Smckusick 109938414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++; 110052196Smckusick nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, 110148364Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); 110248364Smckusick nfsm_fhtom(sp->s_dvp); 110348364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 110454451Smckusick nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); 110538414Smckusick nfsm_reqdone; 110648364Smckusick VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; 110738414Smckusick return (error); 110838414Smckusick } 110938414Smckusick 111038414Smckusick /* 111138414Smckusick * nfs file rename call 111238414Smckusick */ 111352234Sheideman int 111453806Smckusick nfs_rename(ap) 111554668Smckusick struct vop_rename_args /* { 111654668Smckusick struct vnode *a_fdvp; 111754668Smckusick struct vnode *a_fvp; 111854668Smckusick struct componentname *a_fcnp; 111954668Smckusick struct vnode *a_tdvp; 112054668Smckusick struct vnode *a_tvp; 112154668Smckusick struct componentname *a_tcnp; 112254668Smckusick } */ *ap; 112338414Smckusick { 112453806Smckusick register struct vnode *fvp = ap->a_fvp; 112553806Smckusick register struct vnode *tvp = ap->a_tvp; 112653806Smckusick register struct vnode *fdvp = ap->a_fdvp; 112753806Smckusick register struct vnode *tdvp = ap->a_tdvp; 112853806Smckusick register struct componentname *tcnp = ap->a_tcnp; 112953806Smckusick register struct componentname *fcnp = ap->a_fcnp; 113048054Smckusick register u_long *tl; 113139488Smckusick register caddr_t cp; 113252196Smckusick register long t2; 113339488Smckusick caddr_t bpos, dpos; 113439488Smckusick int error = 0; 113539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 113638414Smckusick 113753804Spendry /* Check for cross-device rename */ 113853806Smckusick if ((fvp->v_mount != tdvp->v_mount) || 113953806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) { 114053804Spendry error = EXDEV; 114153804Spendry goto out; 114253804Spendry } 114353804Spendry 114453804Spendry 114538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 114653806Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME, 114753806Smckusick (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ 114853806Smckusick nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ 114953806Smckusick nfsm_fhtom(fdvp); 115053806Smckusick nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); 115153806Smckusick nfsm_fhtom(tdvp); 115253806Smckusick nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); 115353806Smckusick nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); 115438414Smckusick nfsm_reqdone; 115553806Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED; 115653806Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED; 115753806Smckusick if (fvp->v_type == VDIR) { 115853806Smckusick if (tvp != NULL && tvp->v_type == VDIR) 115953806Smckusick cache_purge(tdvp); 116053806Smckusick cache_purge(fdvp); 116138414Smckusick } 116253804Spendry out: 116353806Smckusick if (tdvp == tvp) 116453806Smckusick vrele(tdvp); 116543360Smckusick else 116653806Smckusick vput(tdvp); 116753806Smckusick if (tvp) 116853806Smckusick vput(tvp); 116953806Smckusick vrele(fdvp); 117053806Smckusick vrele(fvp); 117140112Smckusick /* 117240112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 117340112Smckusick */ 117440112Smckusick if (error == ENOENT) 117540112Smckusick error = 0; 117638414Smckusick return (error); 117738414Smckusick } 117838414Smckusick 117938414Smckusick /* 118041905Smckusick * nfs file rename rpc called from nfs_remove() above 118138414Smckusick */ 118252234Sheideman int 118352234Sheideman nfs_renameit(sdvp, scnp, sp) 118452234Sheideman struct vnode *sdvp; 118552234Sheideman struct componentname *scnp; 118648364Smckusick register struct sillyrename *sp; 118738414Smckusick { 118848054Smckusick register u_long *tl; 118939488Smckusick register caddr_t cp; 119052196Smckusick register long t2; 119139488Smckusick caddr_t bpos, dpos; 119239488Smckusick int error = 0; 119339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 119438414Smckusick 119538414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++; 119652234Sheideman nfsm_reqhead(sdvp, NFSPROC_RENAME, 119752234Sheideman (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ 119852196Smckusick nfsm_rndup(sp->s_namlen)); 119952234Sheideman nfsm_fhtom(sdvp); 120052234Sheideman nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); 120152234Sheideman nfsm_fhtom(sdvp); 120248364Smckusick nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); 120352234Sheideman nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); 120438414Smckusick nfsm_reqdone; 120552234Sheideman FREE(scnp->cn_pnbuf, M_NAMEI); 120652234Sheideman VTONFS(sdvp)->n_flag |= NMODIFIED; 120738414Smckusick return (error); 120838414Smckusick } 120938414Smckusick 121038414Smckusick /* 121138414Smckusick * nfs hard link create call 121238414Smckusick */ 121352234Sheideman int 121453806Smckusick nfs_link(ap) 121554668Smckusick struct vop_link_args /* { 121654668Smckusick struct vnode *a_vp; 121754668Smckusick struct vnode *a_tdvp; 121854668Smckusick struct componentname *a_cnp; 121954668Smckusick } */ *ap; 122038414Smckusick { 122153806Smckusick register struct vnode *vp = ap->a_vp; 122253806Smckusick register struct vnode *tdvp = ap->a_tdvp; 122353806Smckusick register struct componentname *cnp = ap->a_cnp; 122448054Smckusick register u_long *tl; 122539488Smckusick register caddr_t cp; 122652196Smckusick register long t2; 122739488Smckusick caddr_t bpos, dpos; 122839488Smckusick int error = 0; 122939488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 123038414Smckusick 123153806Smckusick if (vp->v_mount != tdvp->v_mount) { 123253806Smckusick /*VOP_ABORTOP(vp, cnp);*/ 123353806Smckusick if (tdvp == vp) 123453806Smckusick vrele(vp); 123553804Spendry else 123653806Smckusick vput(vp); 123753804Spendry return (EXDEV); 123853804Spendry } 123953804Spendry 124038414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++; 124153806Smckusick nfsm_reqhead(tdvp, NFSPROC_LINK, 124253806Smckusick NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 124353806Smckusick nfsm_fhtom(tdvp); 124453806Smckusick nfsm_fhtom(vp); 124553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 124653806Smckusick nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); 124738414Smckusick nfsm_reqdone; 124853806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 124953806Smckusick VTONFS(tdvp)->n_attrstamp = 0; 125053806Smckusick VTONFS(vp)->n_flag |= NMODIFIED; 125153806Smckusick vrele(vp); 125240112Smckusick /* 125340112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 125440112Smckusick */ 125540112Smckusick if (error == EEXIST) 125640112Smckusick error = 0; 125738414Smckusick return (error); 125838414Smckusick } 125938414Smckusick 126038414Smckusick /* 126138414Smckusick * nfs symbolic link create call 126238414Smckusick */ 126352234Sheideman /* start here */ 126452234Sheideman int 126553806Smckusick nfs_symlink(ap) 126654668Smckusick struct vop_symlink_args /* { 126754668Smckusick struct vnode *a_dvp; 126854668Smckusick struct vnode **a_vpp; 126954668Smckusick struct componentname *a_cnp; 127054668Smckusick struct vattr *a_vap; 127154668Smckusick char *a_target; 127254668Smckusick } */ *ap; 127338414Smckusick { 127453806Smckusick register struct vnode *dvp = ap->a_dvp; 127553806Smckusick register struct vattr *vap = ap->a_vap; 127653806Smckusick register struct componentname *cnp = ap->a_cnp; 127738884Smacklem register struct nfsv2_sattr *sp; 127848054Smckusick register u_long *tl; 127939488Smckusick register caddr_t cp; 128052196Smckusick register long t2; 128139488Smckusick caddr_t bpos, dpos; 128256289Smckusick int slen, error = 0, isnq; 128339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 128438414Smckusick 128538414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++; 128653600Sheideman slen = strlen(ap->a_target); 128756289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 128853806Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ 128956289Smckusick nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq)); 129053806Smckusick nfsm_fhtom(dvp); 129153806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 129253600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 129356289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 129453806Smckusick sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); 129553806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 129653806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 129756289Smckusick if (isnq) { 129856289Smckusick quad_t qval = -1; 129956289Smckusick 130056289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 130156289Smckusick sp->sa_nqflags = 0; 130256289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 130356289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 130456289Smckusick } else { 130556289Smckusick sp->sa_nfssize = -1; 130656289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 130756289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 130856289Smckusick } 130953806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); 131038414Smckusick nfsm_reqdone; 131153806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 131253806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 131353806Smckusick vrele(dvp); 131440112Smckusick /* 131540112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 131640112Smckusick */ 131740112Smckusick if (error == EEXIST) 131840112Smckusick error = 0; 131938414Smckusick return (error); 132038414Smckusick } 132138414Smckusick 132238414Smckusick /* 132338414Smckusick * nfs make dir call 132438414Smckusick */ 132552234Sheideman int 132653806Smckusick nfs_mkdir(ap) 132754668Smckusick struct vop_mkdir_args /* { 132854668Smckusick struct vnode *a_dvp; 132954668Smckusick struct vnode **a_vpp; 133054668Smckusick struct componentname *a_cnp; 133154668Smckusick struct vattr *a_vap; 133254668Smckusick } */ *ap; 133338414Smckusick { 133453806Smckusick register struct vnode *dvp = ap->a_dvp; 133553806Smckusick register struct vattr *vap = ap->a_vap; 133653806Smckusick register struct componentname *cnp = ap->a_cnp; 133754668Smckusick register struct vnode **vpp = ap->a_vpp; 133838884Smacklem register struct nfsv2_sattr *sp; 133948054Smckusick register u_long *tl; 134039488Smckusick register caddr_t cp; 134139488Smckusick register long t1, t2; 134241905Smckusick register int len; 134339488Smckusick caddr_t bpos, dpos, cp2; 134456289Smckusick int error = 0, firsttry = 1, isnq; 134539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 134638414Smckusick 134753806Smckusick len = cnp->cn_namelen; 134856289Smckusick isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); 134938414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++; 135053806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR, 135156289Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq)); 135253806Smckusick nfsm_fhtom(dvp); 135353806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 135456289Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); 135553806Smckusick sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); 135653806Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); 135753806Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); 135856289Smckusick if (isnq) { 135956289Smckusick quad_t qval = -1; 136056289Smckusick 136156289Smckusick txdr_hyper(&qval, &sp->sa_nqsize); 136256289Smckusick sp->sa_nqflags = 0; 136356289Smckusick txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); 136456289Smckusick txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); 136556289Smckusick } else { 136656289Smckusick sp->sa_nfssize = -1; 136756289Smckusick txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); 136856289Smckusick txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); 136956289Smckusick } 137053806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); 137154668Smckusick nfsm_mtofh(dvp, *vpp); 137238414Smckusick nfsm_reqdone; 137353806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 137440112Smckusick /* 137541905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 137641905Smckusick * if we can succeed in looking up the directory. 137741905Smckusick * "firsttry" is necessary since the macros may "goto nfsmout" which 137841905Smckusick * is above the if on errors. (Ugh) 137940112Smckusick */ 138041905Smckusick if (error == EEXIST && firsttry) { 138141905Smckusick firsttry = 0; 138240112Smckusick error = 0; 138341905Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 138454668Smckusick *vpp = NULL; 138553806Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP, 138641905Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 138753806Smckusick nfsm_fhtom(dvp); 138853806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 138953806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); 139054668Smckusick nfsm_mtofh(dvp, *vpp); 139154668Smckusick if ((*vpp)->v_type != VDIR) { 139254668Smckusick vput(*vpp); 139341905Smckusick error = EEXIST; 139441905Smckusick } 139541905Smckusick m_freem(mrep); 139641905Smckusick } 139753806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 139853806Smckusick vrele(dvp); 139938414Smckusick return (error); 140038414Smckusick } 140138414Smckusick 140238414Smckusick /* 140338414Smckusick * nfs remove directory call 140438414Smckusick */ 140552234Sheideman int 140653806Smckusick nfs_rmdir(ap) 140754668Smckusick struct vop_rmdir_args /* { 140854668Smckusick struct vnode *a_dvp; 140954668Smckusick struct vnode *a_vp; 141054668Smckusick struct componentname *a_cnp; 141154668Smckusick } */ *ap; 141238414Smckusick { 141353806Smckusick register struct vnode *vp = ap->a_vp; 141453806Smckusick register struct vnode *dvp = ap->a_dvp; 141553806Smckusick register struct componentname *cnp = ap->a_cnp; 141648054Smckusick register u_long *tl; 141739488Smckusick register caddr_t cp; 141852196Smckusick register long t2; 141939488Smckusick caddr_t bpos, dpos; 142039488Smckusick int error = 0; 142139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 142238414Smckusick 142353806Smckusick if (dvp == vp) { 142453806Smckusick vrele(dvp); 142553806Smckusick vrele(dvp); 142653806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 142738414Smckusick return (EINVAL); 142838414Smckusick } 142938414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++; 143053806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR, 143153806Smckusick NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); 143253806Smckusick nfsm_fhtom(dvp); 143353806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 143453806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); 143538414Smckusick nfsm_reqdone; 143653806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI); 143753806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED; 143853806Smckusick cache_purge(dvp); 143953806Smckusick cache_purge(vp); 144053806Smckusick vrele(vp); 144153806Smckusick vrele(dvp); 144240112Smckusick /* 144340112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 144440112Smckusick */ 144540112Smckusick if (error == ENOENT) 144640112Smckusick error = 0; 144738414Smckusick return (error); 144838414Smckusick } 144938414Smckusick 145038414Smckusick /* 145138414Smckusick * nfs readdir call 145238414Smckusick * Although cookie is defined as opaque, I translate it to/from net byte 145338414Smckusick * order so that it looks more sensible. This appears consistent with the 145438414Smckusick * Ultrix implementation of NFS. 145538414Smckusick */ 145652234Sheideman int 145753806Smckusick nfs_readdir(ap) 145854668Smckusick struct vop_readdir_args /* { 145954668Smckusick struct vnode *a_vp; 146054668Smckusick struct uio *a_uio; 146154668Smckusick struct ucred *a_cred; 146254668Smckusick } */ *ap; 146338414Smckusick { 146453806Smckusick register struct vnode *vp = ap->a_vp; 146553806Smckusick register struct nfsnode *np = VTONFS(vp); 146653806Smckusick register struct uio *uio = ap->a_uio; 146741905Smckusick int tresid, error; 146841905Smckusick struct vattr vattr; 146941905Smckusick 147053806Smckusick if (vp->v_type != VDIR) 147141905Smckusick return (EPERM); 147241905Smckusick /* 147341905Smckusick * First, check for hit on the EOF offset cache 147441905Smckusick */ 147553806Smckusick if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && 147652196Smckusick (np->n_flag & NMODIFIED) == 0) { 147753806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 147853806Smckusick if (NQNFS_CKCACHABLE(vp, NQL_READ)) { 147952196Smckusick nfsstats.direofcache_hits++; 148052196Smckusick return (0); 148152196Smckusick } 148253806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && 148354106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) { 148452196Smckusick nfsstats.direofcache_hits++; 148552196Smckusick return (0); 148652196Smckusick } 148741905Smckusick } 148841905Smckusick 148941905Smckusick /* 149041905Smckusick * Call nfs_bioread() to do the real work. 149141905Smckusick */ 149253806Smckusick tresid = uio->uio_resid; 149353806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred); 149441905Smckusick 149554451Smckusick if (!error && uio->uio_resid == tresid) 149641905Smckusick nfsstats.direofcache_misses++; 149741905Smckusick return (error); 149841905Smckusick } 149941905Smckusick 150041905Smckusick /* 150141905Smckusick * Readdir rpc call. 150241905Smckusick * Called from below the buffer cache by nfs_doio(). 150341905Smckusick */ 150452234Sheideman int 150548054Smckusick nfs_readdirrpc(vp, uiop, cred) 150641905Smckusick register struct vnode *vp; 150741905Smckusick struct uio *uiop; 150841905Smckusick struct ucred *cred; 150941905Smckusick { 151038414Smckusick register long len; 151154740Smckusick register struct dirent *dp; 151248054Smckusick register u_long *tl; 151339488Smckusick register caddr_t cp; 151439488Smckusick register long t1; 151541905Smckusick long tlen, lastlen; 151639488Smckusick caddr_t bpos, dpos, cp2; 151739488Smckusick int error = 0; 151839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 151938414Smckusick struct mbuf *md2; 152038414Smckusick caddr_t dpos2; 152138414Smckusick int siz; 152240296Smckusick int more_dirs = 1; 152356289Smckusick u_long off, savoff; 152454740Smckusick struct dirent *savdp; 152540296Smckusick struct nfsmount *nmp; 152640296Smckusick struct nfsnode *np = VTONFS(vp); 152740296Smckusick long tresid; 152838414Smckusick 152941398Smckusick nmp = VFSTONFS(vp->v_mount); 153040296Smckusick tresid = uiop->uio_resid; 153140296Smckusick /* 153240296Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 153348054Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 153441905Smckusick * The stopping criteria is EOF or buffer full. 153540296Smckusick */ 153648054Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 153740296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++; 153852196Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, 153956289Smckusick NFSX_FH + 2 * NFSX_UNSIGNED); 154040296Smckusick nfsm_fhtom(vp); 154156289Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 154256289Smckusick off = (u_long)uiop->uio_offset; 154356289Smckusick *tl++ = txdr_unsigned(off); 154448054Smckusick *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 154548054Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 154652196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); 154740296Smckusick siz = 0; 154852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 154948054Smckusick more_dirs = fxdr_unsigned(int, *tl); 155040296Smckusick 155140296Smckusick /* Save the position so that we can do nfsm_mtouio() later */ 155240296Smckusick dpos2 = dpos; 155340296Smckusick md2 = md; 155440296Smckusick 155540296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 155642246Smckusick #ifdef lint 155754740Smckusick dp = (struct dirent *)0; 155842246Smckusick #endif /* lint */ 155940296Smckusick while (more_dirs && siz < uiop->uio_resid) { 156040296Smckusick savoff = off; /* Hold onto offset and dp */ 156140296Smckusick savdp = dp; 156256289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 156354740Smckusick dp = (struct dirent *)tl; 156454740Smckusick dp->d_fileno = fxdr_unsigned(u_long, *tl++); 156548054Smckusick len = fxdr_unsigned(int, *tl); 156640296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 156740296Smckusick error = EBADRPC; 156840296Smckusick m_freem(mrep); 156940296Smckusick goto nfsmout; 157040296Smckusick } 157154986Smckusick dp->d_namlen = (u_char)len; 157254986Smckusick dp->d_type = DT_UNKNOWN; 157340296Smckusick nfsm_adv(len); /* Point past name */ 157440296Smckusick tlen = nfsm_rndup(len); 157540296Smckusick /* 157640296Smckusick * This should not be necessary, but some servers have 157740296Smckusick * broken XDR such that these bytes are not null filled. 157840296Smckusick */ 157940296Smckusick if (tlen != len) { 158040296Smckusick *dpos = '\0'; /* Null-terminate */ 158140296Smckusick nfsm_adv(tlen - len); 158240296Smckusick len = tlen; 158340296Smckusick } 158456289Smckusick nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED); 158554986Smckusick off = fxdr_unsigned(u_long, *tl); 158648054Smckusick *tl++ = 0; /* Ensures null termination of name */ 158748054Smckusick more_dirs = fxdr_unsigned(int, *tl); 158856289Smckusick dp->d_reclen = len + 4 * NFSX_UNSIGNED; 158940296Smckusick siz += dp->d_reclen; 159040296Smckusick } 159140296Smckusick /* 159240296Smckusick * If at end of rpc data, get the eof boolean 159340296Smckusick */ 159440296Smckusick if (!more_dirs) { 159552196Smckusick nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED); 159648054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 159738414Smckusick 159840296Smckusick /* 159940296Smckusick * If at EOF, cache directory offset 160040296Smckusick */ 160141905Smckusick if (!more_dirs) 160240296Smckusick np->n_direofoffset = off; 160338414Smckusick } 160440296Smckusick /* 160540296Smckusick * If there is too much to fit in the data buffer, use savoff and 160640296Smckusick * savdp to trim off the last record. 160740296Smckusick * --> we are not at eof 160840296Smckusick */ 160940296Smckusick if (siz > uiop->uio_resid) { 161040296Smckusick off = savoff; 161140296Smckusick siz -= dp->d_reclen; 161240296Smckusick dp = savdp; 161340296Smckusick more_dirs = 0; /* Paranoia */ 161440113Smckusick } 161540296Smckusick if (siz > 0) { 161641905Smckusick lastlen = dp->d_reclen; 161740296Smckusick md = md2; 161840296Smckusick dpos = dpos2; 161940296Smckusick nfsm_mtouio(uiop, siz); 162056289Smckusick uiop->uio_offset = (off_t)off; 162140296Smckusick } else 162240296Smckusick more_dirs = 0; /* Ugh, never happens, but in case.. */ 162340296Smckusick m_freem(mrep); 162438414Smckusick } 162541905Smckusick /* 162648054Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 162741905Smckusick * by increasing d_reclen for the last record. 162841905Smckusick */ 162941905Smckusick if (uiop->uio_resid < tresid) { 163048054Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 163141905Smckusick if (len > 0) { 163254740Smckusick dp = (struct dirent *) 163341905Smckusick (uiop->uio_iov->iov_base - lastlen); 163441905Smckusick dp->d_reclen += len; 163541905Smckusick uiop->uio_iov->iov_base += len; 163641905Smckusick uiop->uio_iov->iov_len -= len; 163741905Smckusick uiop->uio_resid -= len; 163841905Smckusick } 163941905Smckusick } 164040296Smckusick nfsmout: 164138414Smckusick return (error); 164238414Smckusick } 164338414Smckusick 164452196Smckusick /* 164556289Smckusick * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc(). 164652196Smckusick */ 164752234Sheideman int 164852196Smckusick nfs_readdirlookrpc(vp, uiop, cred) 164952196Smckusick struct vnode *vp; 165052196Smckusick register struct uio *uiop; 165152196Smckusick struct ucred *cred; 165252196Smckusick { 165352196Smckusick register int len; 165454740Smckusick register struct dirent *dp; 165552196Smckusick register u_long *tl; 165652196Smckusick register caddr_t cp; 165752196Smckusick register long t1; 165852196Smckusick caddr_t bpos, dpos, cp2; 165952196Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 166052196Smckusick struct nameidata nami, *ndp = &nami; 166152317Sheideman struct componentname *cnp = &ndp->ni_cnd; 166256289Smckusick u_long off, endoff, fileno; 166352196Smckusick time_t reqtime, ltime; 166452196Smckusick struct nfsmount *nmp; 166552196Smckusick struct nfsnode *np, *tp; 166652196Smckusick struct vnode *newvp; 166752196Smckusick nfsv2fh_t *fhp; 166852196Smckusick u_quad_t frev; 166952196Smckusick int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; 167052196Smckusick int cachable; 167152196Smckusick 167252196Smckusick if (uiop->uio_iovcnt != 1) 167352196Smckusick panic("nfs rdirlook"); 167452196Smckusick nmp = VFSTONFS(vp->v_mount); 167552196Smckusick tresid = uiop->uio_resid; 167652196Smckusick ndp->ni_dvp = vp; 167752196Smckusick newvp = NULLVP; 167852196Smckusick /* 167952196Smckusick * Loop around doing readdir rpc's of size uio_resid or nm_rsize, 168052196Smckusick * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. 168152196Smckusick * The stopping criteria is EOF or buffer full. 168252196Smckusick */ 168352196Smckusick while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { 168452196Smckusick nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; 168552196Smckusick nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, 168656289Smckusick NFSX_FH + 3 * NFSX_UNSIGNED); 168752196Smckusick nfsm_fhtom(vp); 168856289Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); 168956289Smckusick off = (u_long)uiop->uio_offset; 169056289Smckusick *tl++ = txdr_unsigned(off); 169152196Smckusick *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? 169252196Smckusick nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); 169356289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) 169456289Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 169556289Smckusick else 169656289Smckusick *tl = 0; 169752196Smckusick reqtime = time.tv_sec; 169852196Smckusick nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); 169952196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 170052196Smckusick more_dirs = fxdr_unsigned(int, *tl); 170152196Smckusick 170252196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */ 170352196Smckusick bigenough = 1; 170452196Smckusick while (more_dirs && bigenough) { 170552196Smckusick doit = 1; 170656289Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 170756289Smckusick if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) { 170856289Smckusick cachable = fxdr_unsigned(int, *tl++); 170956289Smckusick ltime = reqtime + fxdr_unsigned(int, *tl++); 171056289Smckusick fxdr_hyper(tl, &frev); 171156289Smckusick } 171252196Smckusick nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); 171352196Smckusick if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { 171452196Smckusick VREF(vp); 171552196Smckusick newvp = vp; 171652196Smckusick np = VTONFS(vp); 171752196Smckusick } else { 171852196Smckusick if (error = nfs_nget(vp->v_mount, fhp, &np)) 171952196Smckusick doit = 0; 172052196Smckusick newvp = NFSTOV(np); 172152196Smckusick } 172252196Smckusick if (error = nfs_loadattrcache(&newvp, &md, &dpos, 172352196Smckusick (struct vattr *)0)) 172452196Smckusick doit = 0; 172556289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 172652196Smckusick fileno = fxdr_unsigned(u_long, *tl++); 172752196Smckusick len = fxdr_unsigned(int, *tl); 172852196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) { 172952196Smckusick error = EBADRPC; 173052196Smckusick m_freem(mrep); 173152196Smckusick goto nfsmout; 173252196Smckusick } 173352196Smckusick tlen = (len + 4) & ~0x3; 173452196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid) 173552196Smckusick bigenough = 0; 173652196Smckusick if (bigenough && doit) { 173754740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base; 173854740Smckusick dp->d_fileno = fileno; 173952196Smckusick dp->d_namlen = len; 174052196Smckusick dp->d_reclen = tlen + DIRHDSIZ; 174154986Smckusick dp->d_type = 174254986Smckusick IFTODT(VTTOIF(np->n_vattr.va_type)); 174352196Smckusick uiop->uio_resid -= DIRHDSIZ; 174452196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ; 174552196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ; 174652317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base; 174752317Sheideman cnp->cn_namelen = len; 174852196Smckusick ndp->ni_vp = newvp; 174952196Smckusick nfsm_mtouio(uiop, len); 175052196Smckusick cp = uiop->uio_iov->iov_base; 175152196Smckusick tlen -= len; 175252196Smckusick for (i = 0; i < tlen; i++) 175352196Smckusick *cp++ = '\0'; 175452196Smckusick uiop->uio_iov->iov_base += tlen; 175552196Smckusick uiop->uio_iov->iov_len -= tlen; 175652196Smckusick uiop->uio_resid -= tlen; 175752317Sheideman cnp->cn_hash = 0; 175852317Sheideman for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) 175952317Sheideman cnp->cn_hash += (unsigned char)*cp * i; 176056289Smckusick if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && 176156289Smckusick ltime > time.tv_sec) 176256289Smckusick nqnfs_clientlease(nmp, np, NQL_READ, 176356289Smckusick cachable, ltime, frev); 176456289Smckusick cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); 176552196Smckusick } else { 176652196Smckusick nfsm_adv(nfsm_rndup(len)); 176752196Smckusick } 176852196Smckusick if (newvp != NULLVP) { 176952196Smckusick vrele(newvp); 177052196Smckusick newvp = NULLVP; 177152196Smckusick } 177256289Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 177352196Smckusick if (bigenough) 177456289Smckusick endoff = off = fxdr_unsigned(u_long, *tl++); 177552196Smckusick else 177656289Smckusick endoff = fxdr_unsigned(u_long, *tl++); 177752196Smckusick more_dirs = fxdr_unsigned(int, *tl); 177852196Smckusick } 177952196Smckusick /* 178052196Smckusick * If at end of rpc data, get the eof boolean 178152196Smckusick */ 178252196Smckusick if (!more_dirs) { 178352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 178452196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0); 178552196Smckusick 178652196Smckusick /* 178752196Smckusick * If at EOF, cache directory offset 178852196Smckusick */ 178952196Smckusick if (!more_dirs) 179052196Smckusick VTONFS(vp)->n_direofoffset = endoff; 179152196Smckusick } 179252196Smckusick if (uiop->uio_resid < tresid) 179356289Smckusick uiop->uio_offset = (off_t)off; 179452196Smckusick else 179552196Smckusick more_dirs = 0; 179652196Smckusick m_freem(mrep); 179752196Smckusick } 179852196Smckusick /* 179952196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ 180052196Smckusick * by increasing d_reclen for the last record. 180152196Smckusick */ 180252196Smckusick if (uiop->uio_resid < tresid) { 180352196Smckusick len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); 180452196Smckusick if (len > 0) { 180552196Smckusick dp->d_reclen += len; 180652196Smckusick uiop->uio_iov->iov_base += len; 180752196Smckusick uiop->uio_iov->iov_len -= len; 180852196Smckusick uiop->uio_resid -= len; 180952196Smckusick } 181052196Smckusick } 181152196Smckusick nfsmout: 181252196Smckusick if (newvp != NULLVP) 181352196Smckusick vrele(newvp); 181452196Smckusick return (error); 181552196Smckusick } 181639488Smckusick static char hextoasc[] = "0123456789abcdef"; 181738414Smckusick 181838414Smckusick /* 181938414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little 182038414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename 182138414Smckusick * to a funny looking filename that is removed by nfs_inactive on the 182238414Smckusick * nfsnode. There is the potential for another process on a different client 182338414Smckusick * to create the same funny name between the nfs_lookitup() fails and the 182438414Smckusick * nfs_rename() completes, but... 182538414Smckusick */ 182652234Sheideman int 182752317Sheideman nfs_sillyrename(dvp, vp, cnp) 182852234Sheideman struct vnode *dvp, *vp; 182952234Sheideman struct componentname *cnp; 183038414Smckusick { 183138414Smckusick register struct nfsnode *np; 183238414Smckusick register struct sillyrename *sp; 183338414Smckusick int error; 183438414Smckusick short pid; 183538414Smckusick 183652234Sheideman cache_purge(dvp); 183752234Sheideman np = VTONFS(vp); 183851986Smckusick #ifdef SILLYSEPARATE 183938414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 184048364Smckusick M_NFSREQ, M_WAITOK); 184151986Smckusick #else 184251986Smckusick sp = &np->n_silly; 184351986Smckusick #endif 184452234Sheideman sp->s_cred = crdup(cnp->cn_cred); 184552234Sheideman sp->s_dvp = dvp; 184652234Sheideman VREF(dvp); 184738414Smckusick 184838414Smckusick /* Fudge together a funny name */ 184952234Sheideman pid = cnp->cn_proc->p_pid; 185048364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13); 185148364Smckusick sp->s_namlen = 12; 185248364Smckusick sp->s_name[8] = hextoasc[pid & 0xf]; 185348364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf]; 185448364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf]; 185548364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; 185638414Smckusick 185738414Smckusick /* Try lookitups until we get one that isn't there */ 185852234Sheideman while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { 185948364Smckusick sp->s_name[4]++; 186048364Smckusick if (sp->s_name[4] > 'z') { 186138414Smckusick error = EINVAL; 186238414Smckusick goto bad; 186338414Smckusick } 186438414Smckusick } 186552234Sheideman if (error = nfs_renameit(dvp, cnp, sp)) 186638414Smckusick goto bad; 186752234Sheideman nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); 186838414Smckusick np->n_sillyrename = sp; 186938414Smckusick return (0); 187038414Smckusick bad: 187148364Smckusick vrele(sp->s_dvp); 187248364Smckusick crfree(sp->s_cred); 187351986Smckusick #ifdef SILLYSEPARATE 187448364Smckusick free((caddr_t)sp, M_NFSREQ); 187551986Smckusick #endif 187638414Smckusick return (error); 187738414Smckusick } 187838414Smckusick 187938414Smckusick /* 188038414Smckusick * Look up a file name for silly rename stuff. 188138414Smckusick * Just like nfs_lookup() except that it doesn't load returned values 188238414Smckusick * into the nfsnode table. 188338414Smckusick * If fhp != NULL it copies the returned file handle out 188438414Smckusick */ 188552234Sheideman int 188652196Smckusick nfs_lookitup(sp, fhp, procp) 188748364Smckusick register struct sillyrename *sp; 188838414Smckusick nfsv2fh_t *fhp; 188952196Smckusick struct proc *procp; 189038414Smckusick { 189148364Smckusick register struct vnode *vp = sp->s_dvp; 189248054Smckusick register u_long *tl; 189339488Smckusick register caddr_t cp; 189439488Smckusick register long t1, t2; 189539488Smckusick caddr_t bpos, dpos, cp2; 189639488Smckusick u_long xid; 189756289Smckusick int error = 0, isnq; 189839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 189938414Smckusick long len; 190038414Smckusick 190156289Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 190238414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++; 190348364Smckusick len = sp->s_namlen; 190452196Smckusick nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); 190556289Smckusick if (isnq) { 190656289Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 190756289Smckusick *tl = 0; 190856289Smckusick } 190938414Smckusick nfsm_fhtom(vp); 191048364Smckusick nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); 191152196Smckusick nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); 191238414Smckusick if (fhp != NULL) { 191356289Smckusick if (isnq) 191456289Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 191552196Smckusick nfsm_dissect(cp, caddr_t, NFSX_FH); 191638414Smckusick bcopy(cp, (caddr_t)fhp, NFSX_FH); 191738414Smckusick } 191838414Smckusick nfsm_reqdone; 191938414Smckusick return (error); 192038414Smckusick } 192138414Smckusick 192238414Smckusick /* 192338414Smckusick * Kludge City.. 192438414Smckusick * - make nfs_bmap() essentially a no-op that does no translation 192541905Smckusick * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc 192638414Smckusick * after mapping the physical addresses into Kernel Virtual space in the 192738414Smckusick * nfsiobuf area. 192838414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that 192938414Smckusick * Kernel Write might not be enabled and also figured copyout() would do 193038414Smckusick * a lot more work than bcopy() and also it currently happens in the 193138414Smckusick * context of the swapper process (2). 193238414Smckusick */ 193352234Sheideman int 193453806Smckusick nfs_bmap(ap) 193554668Smckusick struct vop_bmap_args /* { 193654668Smckusick struct vnode *a_vp; 193754668Smckusick daddr_t a_bn; 193854668Smckusick struct vnode **a_vpp; 193954668Smckusick daddr_t *a_bnp; 194054668Smckusick } */ *ap; 194138414Smckusick { 194253806Smckusick register struct vnode *vp = ap->a_vp; 194353806Smckusick 194453600Sheideman if (ap->a_vpp != NULL) 194553806Smckusick *ap->a_vpp = vp; 194653600Sheideman if (ap->a_bnp != NULL) 194753806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize); 194838414Smckusick return (0); 194938414Smckusick } 195038414Smckusick 195138414Smckusick /* 195238884Smacklem * Strategy routine for phys. i/o 195338884Smacklem * If the biod's are running, queue a request 195438884Smacklem * otherwise just call nfs_doio() to get it done 195538414Smckusick */ 195652234Sheideman int 195753806Smckusick nfs_strategy(ap) 195854668Smckusick struct vop_strategy_args /* { 195954668Smckusick struct buf *a_bp; 196054668Smckusick } */ *ap; 196138414Smckusick { 196253806Smckusick register struct buf *bp = ap->a_bp; 196338884Smacklem register struct buf *dp; 196439341Smckusick register int i; 196538884Smacklem int error = 0; 196639341Smckusick int fnd = 0; 196738884Smacklem 196838884Smacklem /* 196941905Smckusick * Set b_proc. It seems a bit silly to do it here, but since bread() 197041905Smckusick * doesn't set it, I will. 197146450Skarels * Set b_proc == NULL for asynchronous ops, since these may still 197241905Smckusick * be hanging about after the process terminates. 197341905Smckusick */ 197453806Smckusick if ((bp->b_flags & B_PHYS) == 0) { 197553806Smckusick if (bp->b_flags & B_ASYNC) 197653806Smckusick bp->b_proc = (struct proc *)0; 197746988Smckusick else 197853806Smckusick bp->b_proc = curproc; 197946988Smckusick } 198041905Smckusick /* 198146450Skarels * If the op is asynchronous and an i/o daemon is waiting 198238884Smacklem * queue the request, wake it up and wait for completion 198346450Skarels * otherwise just do it ourselves. 198438884Smacklem */ 198553806Smckusick if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0) 198653806Smckusick return (nfs_doio(bp)); 198746988Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 198846988Smckusick if (nfs_iodwant[i]) { 198939341Smckusick dp = &nfs_bqueue; 199039341Smckusick if (dp->b_actf == NULL) { 199153806Smckusick dp->b_actl = bp; 199253806Smckusick bp->b_actf = dp; 199339341Smckusick } else { 199453806Smckusick dp->b_actf->b_actl = bp; 199553806Smckusick bp->b_actf = dp->b_actf; 199639341Smckusick } 199753806Smckusick dp->b_actf = bp; 199853806Smckusick bp->b_actl = dp; 199939341Smckusick fnd++; 200039341Smckusick wakeup((caddr_t)&nfs_iodwant[i]); 200139341Smckusick break; 200238884Smacklem } 200339341Smckusick } 200439341Smckusick if (!fnd) 200553806Smckusick error = nfs_doio(bp); 200638884Smacklem return (error); 200738884Smacklem } 200838884Smacklem 200938884Smacklem /* 201038884Smacklem * Fun and games with i/o 201138884Smacklem * Essentially play ubasetup() and disk interrupt service routine by 201238884Smacklem * mapping the data buffer into kernel virtual space and doing the 201338884Smacklem * nfs read or write rpc's from it. 201441905Smckusick * If the nfsiod's are not running, this is just called from nfs_strategy(), 201541905Smckusick * otherwise it is called by the nfsiods to do what would normally be 201638884Smacklem * partially disk interrupt driven. 201738884Smacklem */ 201852234Sheideman int 201938884Smacklem nfs_doio(bp) 202038884Smacklem register struct buf *bp; 202138884Smacklem { 202238414Smckusick register struct uio *uiop; 202338414Smckusick register struct vnode *vp; 202439341Smckusick struct nfsnode *np; 202538884Smacklem struct ucred *cr; 202641539Smckusick int error; 202741539Smckusick struct uio uio; 202841539Smckusick struct iovec io; 202938414Smckusick 203038414Smckusick vp = bp->b_vp; 203140251Smckusick np = VTONFS(vp); 203238414Smckusick uiop = &uio; 203338414Smckusick uiop->uio_iov = &io; 203438414Smckusick uiop->uio_iovcnt = 1; 203538414Smckusick uiop->uio_segflg = UIO_SYSSPACE; 203652196Smckusick uiop->uio_procp = bp->b_proc; 203739751Smckusick 203838414Smckusick /* 203938884Smacklem * For phys i/o, map the b_addr into kernel virtual space using 204038884Smacklem * the Nfsiomap pte's 204138884Smacklem * Also, add a temporary b_rcred for reading using the process's uid 204238884Smacklem * and a guess at a group 204338414Smckusick */ 204438884Smacklem if (bp->b_flags & B_PHYS) { 204548054Smckusick if (bp->b_flags & B_DIRTY) 204648054Smckusick uiop->uio_procp = pageproc; 204748054Smckusick cr = crcopy(uiop->uio_procp->p_ucred); 204841539Smckusick /* mapping was already done by vmapbuf */ 204941539Smckusick io.iov_base = bp->b_un.b_addr; 205039751Smckusick 205138884Smacklem /* 205239751Smckusick * And do the i/o rpc 205339751Smckusick */ 205439751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 205539823Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 205639751Smckusick if (bp->b_flags & B_READ) { 205739751Smckusick uiop->uio_rw = UIO_READ; 205839751Smckusick nfsstats.read_physios++; 205948054Smckusick bp->b_error = error = nfs_readrpc(vp, uiop, cr); 206045717Smckusick (void) vnode_pager_uncache(vp); 206139751Smckusick } else { 206239751Smckusick uiop->uio_rw = UIO_WRITE; 206339751Smckusick nfsstats.write_physios++; 206456289Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, cr, 0); 206539341Smckusick } 206639751Smckusick 206739751Smckusick /* 206839751Smckusick * Finally, release pte's used by physical i/o 206939751Smckusick */ 207038884Smacklem crfree(cr); 207139751Smckusick } else { 207239751Smckusick if (bp->b_flags & B_READ) { 207339751Smckusick io.iov_len = uiop->uio_resid = bp->b_bcount; 207439751Smckusick io.iov_base = bp->b_un.b_addr; 207539751Smckusick uiop->uio_rw = UIO_READ; 207641905Smckusick switch (vp->v_type) { 207741905Smckusick case VREG: 207841905Smckusick uiop->uio_offset = bp->b_blkno * DEV_BSIZE; 207941905Smckusick nfsstats.read_bios++; 208048054Smckusick error = nfs_readrpc(vp, uiop, bp->b_rcred); 208141905Smckusick break; 208241905Smckusick case VLNK: 208341905Smckusick uiop->uio_offset = 0; 208441905Smckusick nfsstats.readlink_bios++; 208548054Smckusick error = nfs_readlinkrpc(vp, uiop, bp->b_rcred); 208641905Smckusick break; 208741905Smckusick case VDIR: 208841905Smckusick uiop->uio_offset = bp->b_lblkno; 208941905Smckusick nfsstats.readdir_bios++; 209056289Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) 209152196Smckusick error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred); 209252196Smckusick else 209352196Smckusick error = nfs_readdirrpc(vp, uiop, bp->b_rcred); 209441905Smckusick /* 209541905Smckusick * Save offset cookie in b_blkno. 209641905Smckusick */ 209741905Smckusick bp->b_blkno = uiop->uio_offset; 209841905Smckusick break; 209941905Smckusick }; 210041905Smckusick bp->b_error = error; 210139751Smckusick } else { 210239751Smckusick io.iov_len = uiop->uio_resid = bp->b_dirtyend 210339751Smckusick - bp->b_dirtyoff; 210439823Smckusick uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) 210539751Smckusick + bp->b_dirtyoff; 210639751Smckusick io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff; 210739751Smckusick uiop->uio_rw = UIO_WRITE; 210839751Smckusick nfsstats.write_bios++; 210941905Smckusick bp->b_error = error = nfs_writerpc(vp, uiop, 211056289Smckusick bp->b_wcred, 0); 211139751Smckusick if (error) { 211239751Smckusick np->n_error = error; 211339751Smckusick np->n_flag |= NWRITEERR; 211439751Smckusick } 211539751Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 211639751Smckusick } 211738884Smacklem } 211839751Smckusick if (error) 211939751Smckusick bp->b_flags |= B_ERROR; 212039751Smckusick bp->b_resid = uiop->uio_resid; 212138414Smckusick biodone(bp); 212238414Smckusick return (error); 212338414Smckusick } 212438884Smacklem 212538884Smacklem /* 212648054Smckusick * Mmap a file 212748054Smckusick * 212848054Smckusick * NB Currently unsupported. 212948054Smckusick */ 213048054Smckusick /* ARGSUSED */ 213152234Sheideman int 213253806Smckusick nfs_mmap(ap) 213354668Smckusick struct vop_mmap_args /* { 213454668Smckusick struct vnode *a_vp; 213554668Smckusick int a_fflags; 213654668Smckusick struct ucred *a_cred; 213754668Smckusick struct proc *a_p; 213854668Smckusick } */ *ap; 213948054Smckusick { 214048054Smckusick 214148054Smckusick return (EINVAL); 214248054Smckusick } 214348054Smckusick 214448054Smckusick /* 214538884Smacklem * Flush all the blocks associated with a vnode. 214638884Smacklem * Walk through the buffer pool and push any dirty pages 214738884Smacklem * associated with the vnode. 214838884Smacklem */ 214939488Smckusick /* ARGSUSED */ 215052234Sheideman int 215153806Smckusick nfs_fsync(ap) 215254451Smckusick struct vop_fsync_args /* { 215354451Smckusick struct vnodeop_desc *a_desc; 215454451Smckusick struct vnode * a_vp; 215554451Smckusick struct ucred * a_cred; 215654451Smckusick int a_waitfor; 215754451Smckusick struct proc * a_p; 215854451Smckusick } */ *ap; 215938884Smacklem { 216054451Smckusick register struct vnode *vp = ap->a_vp; 216154451Smckusick register struct nfsnode *np = VTONFS(vp); 216254451Smckusick register struct buf *bp; 216354451Smckusick struct buf *nbp; 216454451Smckusick int s, error = 0; 216538884Smacklem 216654451Smckusick loop: 216754451Smckusick s = splbio(); 216854451Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 216954451Smckusick nbp = bp->b_blockf; 217054451Smckusick if ((bp->b_flags & B_BUSY)) 217154451Smckusick continue; 217254451Smckusick if ((bp->b_flags & B_DELWRI) == 0) 217354451Smckusick panic("nfs_fsync: not dirty"); 217454451Smckusick bremfree(bp); 217554451Smckusick bp->b_flags |= B_BUSY; 217654451Smckusick splx(s); 217754451Smckusick error = bawrite(bp); 217854451Smckusick goto loop; 217938884Smacklem } 218054451Smckusick if (ap->a_waitfor == MNT_WAIT) { 218154451Smckusick while (vp->v_numoutput) { 218254451Smckusick vp->v_flag |= VBWAIT; 218354451Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 218454451Smckusick } 218554451Smckusick #ifdef DIAGNOSTIC 218654451Smckusick if (vp->v_dirtyblkhd) { 218754451Smckusick vprint("nfs_fsync: dirty", vp); 218854451Smckusick goto loop; 218954451Smckusick } 219054451Smckusick #endif 219154451Smckusick } 219254451Smckusick splx(s); 219354451Smckusick np->n_flag &= ~NMODIFIED; 219453629Smckusick if (np->n_flag & NWRITEERR) { 219539751Smckusick error = np->n_error; 219653629Smckusick np->n_flag &= ~NWRITEERR; 219753629Smckusick } 219838884Smacklem return (error); 219938884Smacklem } 220039672Smckusick 220139672Smckusick /* 220246201Smckusick * NFS advisory byte-level locks. 220346201Smckusick * Currently unsupported. 220446201Smckusick */ 220552234Sheideman int 220653806Smckusick nfs_advlock(ap) 220754668Smckusick struct vop_advlock_args /* { 220854668Smckusick struct vnode *a_vp; 220954668Smckusick caddr_t a_id; 221054668Smckusick int a_op; 221154668Smckusick struct flock *a_fl; 221254668Smckusick int a_flags; 221354668Smckusick } */ *ap; 221446201Smckusick { 221546201Smckusick 221646201Smckusick return (EOPNOTSUPP); 221746201Smckusick } 221846201Smckusick 221946201Smckusick /* 222039672Smckusick * Print out the contents of an nfsnode. 222139672Smckusick */ 222252234Sheideman int 222353806Smckusick nfs_print(ap) 222454668Smckusick struct vop_print_args /* { 222554668Smckusick struct vnode *a_vp; 222654668Smckusick } */ *ap; 222739672Smckusick { 222853806Smckusick register struct vnode *vp = ap->a_vp; 222953806Smckusick register struct nfsnode *np = VTONFS(vp); 223039672Smckusick 223140294Smckusick printf("tag VT_NFS, fileid %d fsid 0x%x", 223240294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid); 223340294Smckusick #ifdef FIFO 223453806Smckusick if (vp->v_type == VFIFO) 223553806Smckusick fifo_printinfo(vp); 223640294Smckusick #endif /* FIFO */ 223739914Smckusick printf("\n"); 223839672Smckusick } 223951573Smckusick 224051573Smckusick /* 224151573Smckusick * NFS directory offset lookup. 224251573Smckusick * Currently unsupported. 224351573Smckusick */ 224452234Sheideman int 224553806Smckusick nfs_blkatoff(ap) 224654668Smckusick struct vop_blkatoff_args /* { 224754668Smckusick struct vnode *a_vp; 224854668Smckusick off_t a_offset; 224954668Smckusick char **a_res; 225054668Smckusick struct buf **a_bpp; 225154668Smckusick } */ *ap; 225251573Smckusick { 225351573Smckusick 225451573Smckusick return (EOPNOTSUPP); 225551573Smckusick } 225651573Smckusick 225751573Smckusick /* 225851573Smckusick * NFS flat namespace allocation. 225951573Smckusick * Currently unsupported. 226051573Smckusick */ 226152234Sheideman int 226253806Smckusick nfs_valloc(ap) 226354668Smckusick struct vop_valloc_args /* { 226454668Smckusick struct vnode *a_pvp; 226554668Smckusick int a_mode; 226654668Smckusick struct ucred *a_cred; 226754668Smckusick struct vnode **a_vpp; 226854668Smckusick } */ *ap; 226951573Smckusick { 227051573Smckusick 227151573Smckusick return (EOPNOTSUPP); 227251573Smckusick } 227351573Smckusick 227451573Smckusick /* 227551573Smckusick * NFS flat namespace free. 227651573Smckusick * Currently unsupported. 227751573Smckusick */ 227853582Sheideman int 227953806Smckusick nfs_vfree(ap) 228054668Smckusick struct vop_vfree_args /* { 228154668Smckusick struct vnode *a_pvp; 228254668Smckusick ino_t a_ino; 228354668Smckusick int a_mode; 228454668Smckusick } */ *ap; 228551573Smckusick { 228651573Smckusick 228753582Sheideman return (EOPNOTSUPP); 228851573Smckusick } 228951573Smckusick 229051573Smckusick /* 229151573Smckusick * NFS file truncation. 229251573Smckusick */ 229352234Sheideman int 229453806Smckusick nfs_truncate(ap) 229554668Smckusick struct vop_truncate_args /* { 229654668Smckusick struct vnode *a_vp; 229754668Smckusick off_t a_length; 229854668Smckusick int a_flags; 229954668Smckusick struct ucred *a_cred; 230054668Smckusick struct proc *a_p; 230154668Smckusick } */ *ap; 230251573Smckusick { 230351573Smckusick 230451573Smckusick /* Use nfs_setattr */ 230551573Smckusick printf("nfs_truncate: need to implement!!"); 230651573Smckusick return (EOPNOTSUPP); 230751573Smckusick } 230851573Smckusick 230951573Smckusick /* 231051573Smckusick * NFS update. 231151573Smckusick */ 231252234Sheideman int 231353806Smckusick nfs_update(ap) 231454668Smckusick struct vop_update_args /* { 231554668Smckusick struct vnode *a_vp; 231654668Smckusick struct timeval *a_ta; 231754668Smckusick struct timeval *a_tm; 231854668Smckusick int a_waitfor; 231954668Smckusick } */ *ap; 232051573Smckusick { 232151573Smckusick 232251573Smckusick /* Use nfs_setattr */ 232351573Smckusick printf("nfs_update: need to implement!!"); 232451573Smckusick return (EOPNOTSUPP); 232551573Smckusick } 232653629Smckusick 232753629Smckusick /* 2328*56364Smckusick * nfs special file access vnode op. 2329*56364Smckusick * Essentially just get vattr and then imitate iaccess() since the device is 2330*56364Smckusick * local to the client. 2331*56364Smckusick */ 2332*56364Smckusick int 2333*56364Smckusick nfsspec_access(ap) 2334*56364Smckusick struct vop_access_args /* { 2335*56364Smckusick struct vnode *a_vp; 2336*56364Smckusick int a_mode; 2337*56364Smckusick struct ucred *a_cred; 2338*56364Smckusick struct proc *a_p; 2339*56364Smckusick } */ *ap; 2340*56364Smckusick { 2341*56364Smckusick register struct vattr *vap; 2342*56364Smckusick register gid_t *gp; 2343*56364Smckusick register struct ucred *cred = ap->a_cred; 2344*56364Smckusick mode_t mode = ap->a_mode; 2345*56364Smckusick struct vattr vattr; 2346*56364Smckusick register int i; 2347*56364Smckusick int error; 2348*56364Smckusick 2349*56364Smckusick /* 2350*56364Smckusick * If you're the super-user, 2351*56364Smckusick * you always get access. 2352*56364Smckusick */ 2353*56364Smckusick if (cred->cr_uid == 0) 2354*56364Smckusick return (0); 2355*56364Smckusick vap = &vattr; 2356*56364Smckusick if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) 2357*56364Smckusick return (error); 2358*56364Smckusick /* 2359*56364Smckusick * Access check is based on only one of owner, group, public. 2360*56364Smckusick * If not owner, then check group. If not a member of the 2361*56364Smckusick * group, then check public access. 2362*56364Smckusick */ 2363*56364Smckusick if (cred->cr_uid != vap->va_uid) { 2364*56364Smckusick mode >>= 3; 2365*56364Smckusick gp = cred->cr_groups; 2366*56364Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 2367*56364Smckusick if (vap->va_gid == *gp) 2368*56364Smckusick goto found; 2369*56364Smckusick mode >>= 3; 2370*56364Smckusick found: 2371*56364Smckusick ; 2372*56364Smckusick } 2373*56364Smckusick if ((vap->va_mode & mode) != 0) 2374*56364Smckusick return (0); 2375*56364Smckusick return (EACCES); 2376*56364Smckusick } 2377*56364Smckusick 2378*56364Smckusick /* 237953629Smckusick * Read wrapper for special devices. 238053629Smckusick */ 238153629Smckusick int 238253629Smckusick nfsspec_read(ap) 238354668Smckusick struct vop_read_args /* { 238454668Smckusick struct vnode *a_vp; 238554668Smckusick struct uio *a_uio; 238654668Smckusick int a_ioflag; 238754668Smckusick struct ucred *a_cred; 238854668Smckusick } */ *ap; 238953629Smckusick { 239054032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 239153629Smckusick 239253629Smckusick /* 239353629Smckusick * Set access flag. 239453629Smckusick */ 239554032Smckusick np->n_flag |= NACC; 239654032Smckusick np->n_atim = time; 239753629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 239853629Smckusick } 239953629Smckusick 240053629Smckusick /* 240153629Smckusick * Write wrapper for special devices. 240253629Smckusick */ 240353629Smckusick int 240453629Smckusick nfsspec_write(ap) 240554668Smckusick struct vop_write_args /* { 240654668Smckusick struct vnode *a_vp; 240754668Smckusick struct uio *a_uio; 240854668Smckusick int a_ioflag; 240954668Smckusick struct ucred *a_cred; 241054668Smckusick } */ *ap; 241153629Smckusick { 241254032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 241353629Smckusick 241453629Smckusick /* 241554032Smckusick * Set update flag. 241653629Smckusick */ 241754032Smckusick np->n_flag |= NUPD; 241854032Smckusick np->n_mtim = time; 241953629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 242053629Smckusick } 242153629Smckusick 242253629Smckusick /* 242353629Smckusick * Close wrapper for special devices. 242453629Smckusick * 242553629Smckusick * Update the times on the nfsnode then do device close. 242653629Smckusick */ 242753629Smckusick int 242853629Smckusick nfsspec_close(ap) 242954668Smckusick struct vop_close_args /* { 243054668Smckusick struct vnode *a_vp; 243154668Smckusick int a_fflag; 243254668Smckusick struct ucred *a_cred; 243354668Smckusick struct proc *a_p; 243454668Smckusick } */ *ap; 243553629Smckusick { 243653806Smckusick register struct vnode *vp = ap->a_vp; 243753806Smckusick register struct nfsnode *np = VTONFS(vp); 243853629Smckusick struct vattr vattr; 243953629Smckusick 244053629Smckusick if (np->n_flag & (NACC | NUPD)) { 244153629Smckusick np->n_flag |= NCHG; 244253806Smckusick if (vp->v_usecount == 1 && 244353806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 244453629Smckusick VATTR_NULL(&vattr); 244554106Smckusick if (np->n_flag & NACC) { 244654106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 244754106Smckusick vattr.va_atime.ts_nsec = 244854106Smckusick np->n_atim.tv_usec * 1000; 244954106Smckusick } 245054106Smckusick if (np->n_flag & NUPD) { 245154106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 245254106Smckusick vattr.va_mtime.ts_nsec = 245354106Smckusick np->n_mtim.tv_usec * 1000; 245454106Smckusick } 245553806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 245653629Smckusick } 245753629Smckusick } 245853629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 245953629Smckusick } 246053629Smckusick 246153629Smckusick #ifdef FIFO 246253629Smckusick /* 246353629Smckusick * Read wrapper for fifos. 246453629Smckusick */ 246553629Smckusick int 246653629Smckusick nfsfifo_read(ap) 246754668Smckusick struct vop_read_args /* { 246854668Smckusick struct vnode *a_vp; 246954668Smckusick struct uio *a_uio; 247054668Smckusick int a_ioflag; 247154668Smckusick struct ucred *a_cred; 247254668Smckusick } */ *ap; 247353629Smckusick { 247453629Smckusick extern int (**fifo_vnodeop_p)(); 247554032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 247653629Smckusick 247753629Smckusick /* 247853629Smckusick * Set access flag. 247953629Smckusick */ 248054032Smckusick np->n_flag |= NACC; 248154032Smckusick np->n_atim = time; 248253629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 248353629Smckusick } 248453629Smckusick 248553629Smckusick /* 248653629Smckusick * Write wrapper for fifos. 248753629Smckusick */ 248853629Smckusick int 248953629Smckusick nfsfifo_write(ap) 249054668Smckusick struct vop_write_args /* { 249154668Smckusick struct vnode *a_vp; 249254668Smckusick struct uio *a_uio; 249354668Smckusick int a_ioflag; 249454668Smckusick struct ucred *a_cred; 249554668Smckusick } */ *ap; 249653629Smckusick { 249753629Smckusick extern int (**fifo_vnodeop_p)(); 249854032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp); 249953629Smckusick 250053629Smckusick /* 250153629Smckusick * Set update flag. 250253629Smckusick */ 250354032Smckusick np->n_flag |= NUPD; 250454032Smckusick np->n_mtim = time; 250553629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 250653629Smckusick } 250753629Smckusick 250853629Smckusick /* 250953629Smckusick * Close wrapper for fifos. 251053629Smckusick * 251153629Smckusick * Update the times on the nfsnode then do fifo close. 251253629Smckusick */ 251353629Smckusick int 251453629Smckusick nfsfifo_close(ap) 251554668Smckusick struct vop_close_args /* { 251654668Smckusick struct vnode *a_vp; 251754668Smckusick int a_fflag; 251854668Smckusick struct ucred *a_cred; 251954668Smckusick struct proc *a_p; 252054668Smckusick } */ *ap; 252153629Smckusick { 252253806Smckusick register struct vnode *vp = ap->a_vp; 252353806Smckusick register struct nfsnode *np = VTONFS(vp); 252453629Smckusick struct vattr vattr; 252553629Smckusick extern int (**fifo_vnodeop_p)(); 252653629Smckusick 252753629Smckusick if (np->n_flag & (NACC | NUPD)) { 252853629Smckusick if (np->n_flag & NACC) 252953629Smckusick np->n_atim = time; 253053629Smckusick if (np->n_flag & NUPD) 253153629Smckusick np->n_mtim = time; 253253629Smckusick np->n_flag |= NCHG; 253353806Smckusick if (vp->v_usecount == 1 && 253453806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 253553629Smckusick VATTR_NULL(&vattr); 253654106Smckusick if (np->n_flag & NACC) { 253754106Smckusick vattr.va_atime.ts_sec = np->n_atim.tv_sec; 253854106Smckusick vattr.va_atime.ts_nsec = 253954106Smckusick np->n_atim.tv_usec * 1000; 254054106Smckusick } 254154106Smckusick if (np->n_flag & NUPD) { 254254106Smckusick vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; 254354106Smckusick vattr.va_mtime.ts_nsec = 254454106Smckusick np->n_mtim.tv_usec * 1000; 254554106Smckusick } 254653806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); 254753629Smckusick } 254853629Smckusick } 254953629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 255053629Smckusick } 255153629Smckusick #endif /* FIFO */ 2552