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