xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 54032)
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*54032Smckusick  *	@(#)nfs_vnops.c	7.81 (Berkeley) 06/17/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 },
5353806Smckusick 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
5453806Smckusick 	{ &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 */
5853806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
5953806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
6053806Smckusick 	{ &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 */
6453806Smckusick 	{ &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 */
6853806Smckusick 	{ &vop_remove_desc, nfs_remove },	/* remove */
6953554Sheideman 	{ &vop_link_desc, nfs_link },		/* link */
7053806Smckusick 	{ &vop_rename_desc, nfs_rename },	/* rename */
7153554Sheideman 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
7253554Sheideman 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
7353806Smckusick 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
7453806Smckusick 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
7553806Smckusick 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
7653806Smckusick 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
7753806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
7853806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
7953554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
8053806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
8153554Sheideman 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
8253806Smckusick 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
8353554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
8453806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
8553806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
8653806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
8753554Sheideman 	{ &vop_vget_desc, nfs_vget },		/* vget */
8853806Smckusick 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
8953554Sheideman 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
9053806Smckusick 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
9153806Smckusick 	{ &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 },
10453806Smckusick 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
10553806Smckusick 	{ &vop_create_desc, spec_create },	/* create */
10653806Smckusick 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
10753554Sheideman 	{ &vop_open_desc, spec_open },		/* open */
10853806Smckusick 	{ &vop_close_desc, nfsspec_close },	/* close */
10953806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
11053806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
11153806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
11253806Smckusick 	{ &vop_read_desc, nfsspec_read },	/* read */
11353806Smckusick 	{ &vop_write_desc, nfsspec_write },	/* write */
11453806Smckusick 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
11553806Smckusick 	{ &vop_select_desc, spec_select },	/* select */
11653554Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
11753806Smckusick 	{ &vop_fsync_desc, spec_fsync },	/* fsync */
11853554Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
11953806Smckusick 	{ &vop_remove_desc, spec_remove },	/* remove */
12053554Sheideman 	{ &vop_link_desc, spec_link },		/* link */
12153806Smckusick 	{ &vop_rename_desc, spec_rename },	/* rename */
12253806Smckusick 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
12353806Smckusick 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
12453806Smckusick 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
12553806Smckusick 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
12653806Smckusick 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
12753806Smckusick 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
12853806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
12953806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
13053554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
13153806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
13253554Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
13353806Smckusick 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
13453554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
13553806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
13653806Smckusick 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
13753806Smckusick 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
13853554Sheideman 	{ &vop_vget_desc, spec_vget },		/* vget */
13953806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
14053806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
14153806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
14253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
14353582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
14453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
14538414Smckusick };
14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
14753554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
14838414Smckusick 
14940294Smckusick #ifdef FIFO
15053554Sheideman int (**fifo_nfsv2nodeop_p)();
15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
15253554Sheideman 	{ &vop_default_desc, vn_default_error },
15353806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
15453806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
15553806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
15653554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
15753806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
15853806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
15953806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
16053806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
16153806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
16253806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
16353806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
16453806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
16553554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
16653806Smckusick 	{ &vop_fsync_desc, fifo_fsync },	/* fsync */
16753554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
16853806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
16953554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
17053806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
17153806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
17253806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
17353806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
17453806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
17553806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
17653806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
17753806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
17853806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
17953554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
18053806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
18153554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
18253806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
18353554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
18453806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
18553806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
18653806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
18753554Sheideman 	{ &vop_vget_desc, fifo_vget },		/* vget */
18853806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
18953806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
19053806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
19153806Smckusick 	{ &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
23453806Smckusick nfs_access(ap)
23553554Sheideman 	struct vop_access_args *ap;
23638414Smckusick {
23753554Sheideman 	USES_VOP_GETATTR;
23838414Smckusick 	register struct vattr *vap;
23938414Smckusick 	register gid_t *gp;
24053806Smckusick 	register struct ucred *cred = ap->a_cred;
24153806Smckusick 	mode_t mode = ap->a_mode;
24238414Smckusick 	struct vattr vattr;
24338414Smckusick 	register int i;
24438414Smckusick 	int error;
24538414Smckusick 
24638414Smckusick 	/*
24738414Smckusick 	 * If you're the super-user,
24838414Smckusick 	 * you always get access.
24938414Smckusick 	 */
25053806Smckusick 	if (cred->cr_uid == 0)
25138414Smckusick 		return (0);
25238414Smckusick 	vap = &vattr;
25353806Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
25438884Smacklem 		return (error);
25538414Smckusick 	/*
25638414Smckusick 	 * Access check is based on only one of owner, group, public.
25738414Smckusick 	 * If not owner, then check group. If not a member of the
25838414Smckusick 	 * group, then check public access.
25938414Smckusick 	 */
26053806Smckusick 	if (cred->cr_uid != vap->va_uid) {
26153806Smckusick 		mode >>= 3;
26253806Smckusick 		gp = cred->cr_groups;
26353806Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
26438414Smckusick 			if (vap->va_gid == *gp)
26538414Smckusick 				goto found;
26653806Smckusick 		mode >>= 3;
26738414Smckusick found:
26838414Smckusick 		;
26938414Smckusick 	}
27053806Smckusick 	if ((vap->va_mode & mode) != 0)
27138414Smckusick 		return (0);
27238414Smckusick 	return (EACCES);
27338414Smckusick }
27438414Smckusick 
27538414Smckusick /*
27638414Smckusick  * nfs open vnode op
27738414Smckusick  * Just check to see if the type is ok
27852196Smckusick  * and that deletion is not in progress.
27938414Smckusick  */
28039488Smckusick /* ARGSUSED */
28152234Sheideman int
28253806Smckusick nfs_open(ap)
28353554Sheideman 	struct vop_open_args *ap;
28438414Smckusick {
28553806Smckusick 	register struct vnode *vp = ap->a_vp;
28638414Smckusick 
28753806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
28838414Smckusick 		return (EACCES);
28953806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
29053806Smckusick 		VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */
29152196Smckusick 	return (0);
29238414Smckusick }
29338414Smckusick 
29438414Smckusick /*
29538414Smckusick  * nfs close vnode op
29638884Smacklem  * For reg files, invalidate any buffer cache entries.
29738414Smckusick  */
29839488Smckusick /* ARGSUSED */
29952234Sheideman int
30053806Smckusick nfs_close(ap)
30153554Sheideman 	struct vop_close_args *ap;
30238414Smckusick {
30353806Smckusick 	register struct vnode *vp = ap->a_vp;
30453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
30539341Smckusick 	int error = 0;
30638414Smckusick 
30753806Smckusick 	if (vp->v_type == VREG) {
30853806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
30953629Smckusick 		(np->n_flag & NMODIFIED)) {
31041905Smckusick 		np->n_flag &= ~NMODIFIED;
31153806Smckusick 		vinvalbuf(vp, TRUE);
31241905Smckusick 		np->n_attrstamp = 0;
31353629Smckusick 	    }
31453629Smckusick 	    if (np->n_flag & NWRITEERR) {
31553629Smckusick 		np->n_flag &= ~NWRITEERR;
31653629Smckusick 		error = np->n_error;
31753629Smckusick 	    }
31838884Smacklem 	}
31938414Smckusick 	return (error);
32038414Smckusick }
32138414Smckusick 
32238414Smckusick /*
32338414Smckusick  * nfs getattr call from vfs.
32438414Smckusick  */
32552234Sheideman int
32653805Smckusick nfs_getattr(ap)
32753554Sheideman 	struct vop_getattr_args *ap;
32838414Smckusick {
32953805Smckusick 	register struct vnode *vp = ap->a_vp;
33053805Smckusick 	register struct nfsnode *np = VTONFS(vp);
33139488Smckusick 	register caddr_t cp;
33239488Smckusick 	caddr_t bpos, dpos;
33339488Smckusick 	int error = 0;
33439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
33538414Smckusick 
33653805Smckusick 	/*
33753805Smckusick 	 * Update local times for special files.
33853805Smckusick 	 */
33953805Smckusick 	if (np->n_flag & (NACC | NUPD)) {
34053805Smckusick 		if (np->n_flag & NACC)
34153805Smckusick 			np->n_atim = time;
34253805Smckusick 		if (np->n_flag & NUPD)
34353805Smckusick 			np->n_mtim = time;
34453805Smckusick 		np->n_flag |= NCHG;
34553805Smckusick 	}
34653805Smckusick 	/*
34753805Smckusick 	 * First look in the cache.
34853805Smckusick 	 */
34953805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
35038414Smckusick 		return (0);
35138414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
35253805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
35353805Smckusick 	nfsm_fhtom(vp);
35453805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
35553805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
35638414Smckusick 	nfsm_reqdone;
35738414Smckusick 	return (error);
35838414Smckusick }
35938414Smckusick 
36038414Smckusick /*
36138414Smckusick  * nfs setattr call.
36238414Smckusick  */
36352234Sheideman int
36453806Smckusick nfs_setattr(ap)
36553554Sheideman 	struct vop_setattr_args *ap;
36638414Smckusick {
36738884Smacklem 	register struct nfsv2_sattr *sp;
36839488Smckusick 	register caddr_t cp;
36939488Smckusick 	register long t1;
37052196Smckusick 	caddr_t bpos, dpos, cp2;
37152196Smckusick 	u_long *tl;
37239488Smckusick 	int error = 0;
37339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
37453806Smckusick 	register struct vnode *vp = ap->a_vp;
37553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
37653806Smckusick 	register struct vattr *vap = ap->a_vap;
37752196Smckusick 	u_quad_t frev;
37838414Smckusick 
37938414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
38053806Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR);
38153806Smckusick 	nfsm_fhtom(vp);
38238884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
38353806Smckusick 	if (vap->va_mode == 0xffff)
38438884Smacklem 		sp->sa_mode = VNOVAL;
38538414Smckusick 	else
38653806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
38753806Smckusick 	if (vap->va_uid == 0xffff)
38838884Smacklem 		sp->sa_uid = VNOVAL;
38938414Smckusick 	else
39053806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
39153806Smckusick 	if (vap->va_gid == 0xffff)
39238884Smacklem 		sp->sa_gid = VNOVAL;
39338414Smckusick 	else
39453806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
39553806Smckusick 	sp->sa_size = txdr_unsigned(vap->va_size);
39653806Smckusick 	sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
39753806Smckusick 	sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
39853806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
39953806Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
40053806Smckusick 	    vap->va_atime.tv_sec != VNOVAL) {
40139359Smckusick 		if (np->n_flag & NMODIFIED) {
40239359Smckusick 			np->n_flag &= ~NMODIFIED;
40353806Smckusick 			if (vap->va_size == 0)
40453806Smckusick 				vinvalbuf(vp, FALSE);
40546988Smckusick 			else
40653806Smckusick 				vinvalbuf(vp, TRUE);
40739359Smckusick 		}
40839359Smckusick 	}
40953806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
41053806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
41153806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
41253806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
41352196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
41452196Smckusick 		fxdr_hyper(tl, &frev);
41552196Smckusick 		if (QUADGT(frev, np->n_brev))
41652196Smckusick 			np->n_brev = frev;
41752196Smckusick 	}
41838414Smckusick 	nfsm_reqdone;
41938414Smckusick 	return (error);
42038414Smckusick }
42138414Smckusick 
42238414Smckusick /*
42338414Smckusick  * nfs lookup call, one step at a time...
42438414Smckusick  * First look in cache
42538414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
42638414Smckusick  */
42752234Sheideman int
42853806Smckusick nfs_lookup(ap)
42953554Sheideman 	struct vop_lookup_args *ap;
43038414Smckusick {
43153554Sheideman 	USES_VOP_GETATTR;
43253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
43353806Smckusick 	register struct vnode *dvp = ap->a_dvp;
43438414Smckusick 	register struct vnode *vdp;
43548054Smckusick 	register u_long *tl;
43639488Smckusick 	register caddr_t cp;
43739488Smckusick 	register long t1, t2;
43852196Smckusick 	struct nfsmount *nmp;
43952196Smckusick 	struct nfsnode *tp;
44039488Smckusick 	caddr_t bpos, dpos, cp2;
44152196Smckusick 	time_t reqtime;
44239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
44338414Smckusick 	struct vnode *newvp;
44438414Smckusick 	long len;
44538414Smckusick 	nfsv2fh_t *fhp;
44638414Smckusick 	struct nfsnode *np;
44752234Sheideman 	int lockparent, wantparent, error = 0;
44852196Smckusick 	int nqlflag, cachable;
44952196Smckusick 	u_quad_t frev;
45038414Smckusick 
45153600Sheideman 	*ap->a_vpp = NULL;
45253806Smckusick 	if (dvp->v_type != VDIR)
45338414Smckusick 		return (ENOTDIR);
45453806Smckusick 	lockparent = cnp->cn_flags & LOCKPARENT;
45553806Smckusick 	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
45653806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
45753806Smckusick 	np = VTONFS(dvp);
45853806Smckusick 	if ((error = cache_lookup(dvp, ap->a_vpp, cnp)) && error != ENOENT) {
45938884Smacklem 		struct vattr vattr;
46038884Smacklem 		int vpid;
46138884Smacklem 
46253600Sheideman 		vdp = *ap->a_vpp;
46338884Smacklem 		vpid = vdp->v_id;
46438414Smckusick 		/*
46538884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
46638884Smacklem 		 * for an explanation of the locking protocol
46738414Smckusick 		 */
46853806Smckusick 		if (dvp == vdp) {
46938425Smckusick 			VREF(vdp);
47039441Smckusick 			error = 0;
47152196Smckusick 		} else
47239441Smckusick 			error = vget(vdp);
47339441Smckusick 		if (!error) {
47440251Smckusick 			if (vpid == vdp->v_id) {
47552196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
47653806Smckusick 			        if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
47752196Smckusick 					if (QUADNE(np->n_lrev, np->n_brev) ||
47852196Smckusick 					    (np->n_flag & NMODIFIED)) {
47952196Smckusick 						np->n_direofoffset = 0;
48053806Smckusick 						cache_purge(dvp);
48152196Smckusick 						np->n_flag &= ~NMODIFIED;
48253806Smckusick 						vinvalbuf(dvp, FALSE);
48352196Smckusick 						np->n_brev = np->n_lrev;
48452196Smckusick 					} else {
48552196Smckusick 						nfsstats.lookupcache_hits++;
48653806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
48753806Smckusick 						    (cnp->cn_flags&ISLASTCN))
48853806Smckusick 						    cnp->cn_flags |= SAVENAME;
48952196Smckusick 						return (0);
49052196Smckusick 					}
49152196Smckusick 				}
49253806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
49340251Smckusick 			       vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) {
49439441Smckusick 				nfsstats.lookupcache_hits++;
49553806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
49653806Smckusick 				    (cnp->cn_flags&ISLASTCN))
49753806Smckusick 					cnp->cn_flags |= SAVENAME;
49839441Smckusick 				return (0);
49940251Smckusick 			   }
50047289Smckusick 			   cache_purge(vdp);
50139441Smckusick 			}
50252196Smckusick 			vrele(vdp);
50338884Smacklem 		}
50453600Sheideman 		*ap->a_vpp = NULLVP;
50552196Smckusick 	}
50639341Smckusick 	error = 0;
50738414Smckusick 	nfsstats.lookupcache_misses++;
50838414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
50953806Smckusick 	len = cnp->cn_namelen;
51053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
51152196Smckusick 
51252196Smckusick 	/*
51352196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
51452196Smckusick 	 * being looked up.
51552196Smckusick 	 */
51652196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
51752196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
51853806Smckusick 		    ((cnp->cn_flags&MAKEENTRY) &&
51953806Smckusick 		    (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN)))) {
52052196Smckusick 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
52152196Smckusick 			*tl++ = txdr_unsigned(NQL_READ);
52252196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
52352196Smckusick 		} else {
52452196Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
52552196Smckusick 			*tl = 0;
52652196Smckusick 		}
52752196Smckusick 	}
52853806Smckusick 	nfsm_fhtom(dvp);
52953806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
53052196Smckusick 	reqtime = time.tv_sec;
53153806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
53238414Smckusick nfsmout:
53338414Smckusick 	if (error) {
53453806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
53553806Smckusick 		    (cnp->cn_flags & ISLASTCN) && error == ENOENT)
53652823Smckusick 			error = EJUSTRETURN;
53753806Smckusick 		if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
53853806Smckusick 			cnp->cn_flags |= SAVENAME;
53940483Smckusick 		return (error);
54038414Smckusick 	}
54152196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
54252196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
54352196Smckusick 		if (*tl) {
54452196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
54552196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
54652196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
54752196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
54852196Smckusick 			fxdr_hyper(tl, &frev);
54952196Smckusick 		} else
55052196Smckusick 			nqlflag = 0;
55152196Smckusick 	}
55252196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
55338414Smckusick 
55438414Smckusick 	/*
55552196Smckusick 	 * Handle RENAME case...
55638414Smckusick 	 */
55753806Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (cnp->cn_flags&ISLASTCN)) {
55852196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
55938414Smckusick 			m_freem(mrep);
56038414Smckusick 			return (EISDIR);
56138414Smckusick 		}
56253806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
56338414Smckusick 			m_freem(mrep);
56438414Smckusick 			return (error);
56538414Smckusick 		}
56638414Smckusick 		newvp = NFSTOV(np);
56739459Smckusick 		if (error =
56839459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
56952196Smckusick 			vrele(newvp);
57038414Smckusick 			m_freem(mrep);
57138414Smckusick 			return (error);
57238414Smckusick 		}
57353600Sheideman 		*ap->a_vpp = newvp;
57445037Smckusick 		m_freem(mrep);
57553806Smckusick 		cnp->cn_flags |= SAVENAME;
57638414Smckusick 		return (0);
57738414Smckusick 	}
57838414Smckusick 
57952196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
58053806Smckusick 		VREF(dvp);
58153806Smckusick 		newvp = dvp;
58238414Smckusick 	} else {
58353806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
58438414Smckusick 			m_freem(mrep);
58538414Smckusick 			return (error);
58638414Smckusick 		}
58738414Smckusick 		newvp = NFSTOV(np);
58838414Smckusick 	}
58939459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
59052196Smckusick 		vrele(newvp);
59138414Smckusick 		m_freem(mrep);
59238414Smckusick 		return (error);
59338414Smckusick 	}
59438414Smckusick 	m_freem(mrep);
59553600Sheideman 	*ap->a_vpp = newvp;
59653806Smckusick 	if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
59753806Smckusick 		cnp->cn_flags |= SAVENAME;
59853806Smckusick 	if ((cnp->cn_flags&MAKEENTRY) &&
59953806Smckusick 	    (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN))) {
60052196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
60152196Smckusick 			np->n_ctime = np->n_vattr.va_ctime.tv_sec;
60252196Smckusick 		else if (nqlflag && reqtime > time.tv_sec) {
60352196Smckusick 			if (np->n_tnext) {
60452196Smckusick 				if (np->n_tnext == (struct nfsnode *)nmp)
60552196Smckusick 					nmp->nm_tprev = np->n_tprev;
60652196Smckusick 				else
60752196Smckusick 					np->n_tnext->n_tprev = np->n_tprev;
60852196Smckusick 				if (np->n_tprev == (struct nfsnode *)nmp)
60952196Smckusick 					nmp->nm_tnext = np->n_tnext;
61052196Smckusick 				else
61152196Smckusick 					np->n_tprev->n_tnext = np->n_tnext;
61252196Smckusick 				if (nqlflag == NQL_WRITE)
61352196Smckusick 					np->n_flag |= NQNFSWRITE;
61452196Smckusick 			} else if (nqlflag == NQL_READ)
61552196Smckusick 				np->n_flag &= ~NQNFSWRITE;
61652196Smckusick 			else
61752196Smckusick 				np->n_flag |= NQNFSWRITE;
61852196Smckusick 			if (cachable)
61952196Smckusick 				np->n_flag &= ~NQNFSNONCACHE;
62052196Smckusick 			else
62152196Smckusick 				np->n_flag |= NQNFSNONCACHE;
62252196Smckusick 			np->n_expiry = reqtime;
62352196Smckusick 			np->n_lrev = frev;
62452196Smckusick 			tp = nmp->nm_tprev;
62552196Smckusick 			while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
62652196Smckusick 				tp = tp->n_tprev;
62752196Smckusick 			if (tp == (struct nfsnode *)nmp) {
62852196Smckusick 				np->n_tnext = nmp->nm_tnext;
62952196Smckusick 				nmp->nm_tnext = np;
63052196Smckusick 			} else {
63152196Smckusick 				np->n_tnext = tp->n_tnext;
63252196Smckusick 				tp->n_tnext = np;
63352196Smckusick 			}
63452196Smckusick 			np->n_tprev = tp;
63552196Smckusick 			if (np->n_tnext == (struct nfsnode *)nmp)
63652196Smckusick 				nmp->nm_tprev = np;
63752196Smckusick 			else
63852196Smckusick 				np->n_tnext->n_tprev = np;
63952196Smckusick 		}
64053806Smckusick 		cache_enter(dvp, *ap->a_vpp, cnp);
64140251Smckusick 	}
64252196Smckusick 	return (0);
64338414Smckusick }
64438414Smckusick 
64538414Smckusick /*
64641905Smckusick  * nfs read call.
64741905Smckusick  * Just call nfs_bioread() to do the work.
64841905Smckusick  */
64952234Sheideman int
65053806Smckusick nfs_read(ap)
65153554Sheideman 	struct vop_read_args *ap;
65241905Smckusick {
65353806Smckusick 	register struct vnode *vp = ap->a_vp;
65453806Smckusick 
65553806Smckusick 	if (vp->v_type != VREG)
65641905Smckusick 		return (EPERM);
65753806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
65841905Smckusick }
65941905Smckusick 
66041905Smckusick /*
66138414Smckusick  * nfs readlink call
66238414Smckusick  */
66352234Sheideman int
66453806Smckusick nfs_readlink(ap)
66553554Sheideman 	struct vop_readlink_args *ap;
66641905Smckusick {
66753806Smckusick 	register struct vnode *vp = ap->a_vp;
66853806Smckusick 
66953806Smckusick 	if (vp->v_type != VLNK)
67041905Smckusick 		return (EPERM);
67153806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
67241905Smckusick }
67341905Smckusick 
67441905Smckusick /*
67541905Smckusick  * Do a readlink rpc.
67641905Smckusick  * Called by nfs_doio() from below the buffer cache.
67741905Smckusick  */
67852234Sheideman int
67948054Smckusick nfs_readlinkrpc(vp, uiop, cred)
68039488Smckusick 	register struct vnode *vp;
68138414Smckusick 	struct uio *uiop;
68238414Smckusick 	struct ucred *cred;
68338414Smckusick {
68448054Smckusick 	register u_long *tl;
68539488Smckusick 	register caddr_t cp;
68639488Smckusick 	register long t1;
68739488Smckusick 	caddr_t bpos, dpos, cp2;
68839488Smckusick 	int error = 0;
68939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
69038414Smckusick 	long len;
69138414Smckusick 
69238414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
69352196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
69438414Smckusick 	nfsm_fhtom(vp);
69552196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
69638414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
69738414Smckusick 	nfsm_mtouio(uiop, len);
69838414Smckusick 	nfsm_reqdone;
69938414Smckusick 	return (error);
70038414Smckusick }
70138414Smckusick 
70238414Smckusick /*
70341905Smckusick  * nfs read rpc call
70441905Smckusick  * Ditto above
70538414Smckusick  */
70652234Sheideman int
70748054Smckusick nfs_readrpc(vp, uiop, cred)
70839488Smckusick 	register struct vnode *vp;
70938414Smckusick 	struct uio *uiop;
71038414Smckusick 	struct ucred *cred;
71138414Smckusick {
71248054Smckusick 	register u_long *tl;
71339488Smckusick 	register caddr_t cp;
71439488Smckusick 	register long t1;
71539488Smckusick 	caddr_t bpos, dpos, cp2;
71639488Smckusick 	int error = 0;
71739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
71838414Smckusick 	struct nfsmount *nmp;
71938414Smckusick 	long len, retlen, tsiz;
72038414Smckusick 
72141398Smckusick 	nmp = VFSTONFS(vp->v_mount);
72238414Smckusick 	tsiz = uiop->uio_resid;
72338414Smckusick 	while (tsiz > 0) {
72438414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
72538414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
72652196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
72738414Smckusick 		nfsm_fhtom(vp);
72848054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
72948054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
73048054Smckusick 		*tl++ = txdr_unsigned(len);
73148054Smckusick 		*tl = 0;
73252196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
73338414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
73438414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
73538414Smckusick 		nfsm_mtouio(uiop, retlen);
73638414Smckusick 		m_freem(mrep);
73738414Smckusick 		if (retlen < len)
73838414Smckusick 			tsiz = 0;
73938414Smckusick 		else
74038414Smckusick 			tsiz -= len;
74138414Smckusick 	}
74238414Smckusick nfsmout:
74338414Smckusick 	return (error);
74438414Smckusick }
74538414Smckusick 
74638414Smckusick /*
74738414Smckusick  * nfs write call
74838414Smckusick  */
74952234Sheideman int
75048054Smckusick nfs_writerpc(vp, uiop, cred)
75139488Smckusick 	register struct vnode *vp;
75238414Smckusick 	struct uio *uiop;
75338414Smckusick 	struct ucred *cred;
75438414Smckusick {
75548054Smckusick 	register u_long *tl;
75639488Smckusick 	register caddr_t cp;
75739488Smckusick 	register long t1;
75852196Smckusick 	caddr_t bpos, dpos, cp2;
75939488Smckusick 	int error = 0;
76039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
76138414Smckusick 	struct nfsmount *nmp;
76252196Smckusick 	struct nfsnode *np = VTONFS(vp);
76352196Smckusick 	u_quad_t frev;
76438414Smckusick 	long len, tsiz;
76538414Smckusick 
76641398Smckusick 	nmp = VFSTONFS(vp->v_mount);
76738414Smckusick 	tsiz = uiop->uio_resid;
76838414Smckusick 	while (tsiz > 0) {
76938414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
77038414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
77152196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
77252196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
77338414Smckusick 		nfsm_fhtom(vp);
77448054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
77548054Smckusick 		*(tl+1) = txdr_unsigned(uiop->uio_offset);
77648054Smckusick 		*(tl+3) = txdr_unsigned(len);
77738414Smckusick 		nfsm_uiotom(uiop, len);
77852196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
77938414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
78052196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
78152196Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
78252196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
78352196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
78452196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
78552196Smckusick 			fxdr_hyper(tl, &frev);
78652196Smckusick 			if (QUADGT(frev, np->n_brev))
78752196Smckusick 				np->n_brev = frev;
78852196Smckusick 		}
78938414Smckusick 		m_freem(mrep);
79038414Smckusick 		tsiz -= len;
79138414Smckusick 	}
79238414Smckusick nfsmout:
79352196Smckusick 	if (error)
79452196Smckusick 		uiop->uio_resid = tsiz;
79538414Smckusick 	return (error);
79638414Smckusick }
79738414Smckusick 
79838414Smckusick /*
79939459Smckusick  * nfs mknod call
80042246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
80142246Smckusick  * set to specify the file type and the size field for rdev.
80239459Smckusick  */
80339459Smckusick /* ARGSUSED */
80452234Sheideman int
80553806Smckusick nfs_mknod(ap)
80653554Sheideman 	struct vop_mknod_args *ap;
80739459Smckusick {
80853554Sheideman 	USES_VOP_ABORTOP;
80953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
81053806Smckusick 	register struct vattr *vap = ap->a_vap;
81153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
81242246Smckusick 	register struct nfsv2_sattr *sp;
81348054Smckusick 	register u_long *tl;
81442246Smckusick 	register caddr_t cp;
81552196Smckusick 	register long t2;
81642246Smckusick 	caddr_t bpos, dpos;
81742246Smckusick 	int error = 0;
81842246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
81942246Smckusick 	u_long rdev;
82039459Smckusick 
82153806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
82253806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
82342246Smckusick #ifdef FIFO
82453806Smckusick 	else if (vap->va_type == VFIFO)
82542246Smckusick 		rdev = 0xffffffff;
82642246Smckusick #endif /* FIFO */
82742246Smckusick 	else {
82853806Smckusick 		VOP_ABORTOP(dvp, cnp);
82953806Smckusick 		vput(dvp);
83042246Smckusick 		return (EOPNOTSUPP);
83142246Smckusick 	}
83242246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
83353806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
83453806Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
83553806Smckusick 	nfsm_fhtom(dvp);
83653806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
83742246Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
83853806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
83953806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
84053806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
84142246Smckusick 	sp->sa_size = rdev;
84242246Smckusick 	/* or should these be VNOVAL ?? */
84353806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
84453806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
84553806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
84642246Smckusick 	nfsm_reqdone;
84753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
84853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
84953806Smckusick 	vrele(dvp);
85042246Smckusick 	return (error);
85139459Smckusick }
85239459Smckusick 
85339459Smckusick /*
85438414Smckusick  * nfs file create call
85538414Smckusick  */
85652234Sheideman int
85753806Smckusick nfs_create(ap)
85853554Sheideman 	struct vop_create_args *ap;
85938414Smckusick {
86053806Smckusick 	register struct vnode *dvp = ap->a_dvp;
86153806Smckusick 	register struct vattr *vap = ap->a_vap;
86253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
86338884Smacklem 	register struct nfsv2_sattr *sp;
86448054Smckusick 	register u_long *tl;
86539488Smckusick 	register caddr_t cp;
86639488Smckusick 	register long t1, t2;
86739488Smckusick 	caddr_t bpos, dpos, cp2;
86839488Smckusick 	int error = 0;
86939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
87038414Smckusick 
87138414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
87253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
87353806Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
87453806Smckusick 	nfsm_fhtom(dvp);
87553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
87638884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
87753806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
87853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
87953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
88038884Smacklem 	sp->sa_size = txdr_unsigned(0);
88138414Smckusick 	/* or should these be VNOVAL ?? */
88253806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
88353806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
88453806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
88553806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
88638414Smckusick 	nfsm_reqdone;
88753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
88853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
88953806Smckusick 	vrele(dvp);
89038414Smckusick 	return (error);
89138414Smckusick }
89238414Smckusick 
89338414Smckusick /*
89438414Smckusick  * nfs file remove call
89541905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
89641905Smckusick  * other processes using the vnode is renamed instead of removed and then
89739341Smckusick  * removed later on the last close.
89841905Smckusick  * - If v_usecount > 1
89939341Smckusick  *	  If a rename is not already in the works
90039341Smckusick  *	     call nfs_sillyrename() to set it up
90139341Smckusick  *     else
90239341Smckusick  *	  do the remove rpc
90338414Smckusick  */
90452234Sheideman int
90553806Smckusick nfs_remove(ap)
90653554Sheideman 	struct vop_remove_args *ap;
90738414Smckusick {
90853806Smckusick 	register struct vnode *vp = ap->a_vp;
90953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
91053806Smckusick 	register struct componentname *cnp = ap->a_cnp;
91153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
91248054Smckusick 	register u_long *tl;
91339488Smckusick 	register caddr_t cp;
91452196Smckusick 	register long t2;
91539488Smckusick 	caddr_t bpos, dpos;
91639488Smckusick 	int error = 0;
91739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91838414Smckusick 
91953806Smckusick 	if (vp->v_usecount > 1) {
92039341Smckusick 		if (!np->n_sillyrename)
92153806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
92239341Smckusick 	} else {
92352196Smckusick 		/*
92452196Smckusick 		 * Purge the name cache so that the chance of a lookup for
92552196Smckusick 		 * the name succeeding while the remove is in progress is
92652196Smckusick 		 * minimized. Without node locking it can still happen, such
92752196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
92852196Smckusick 		 * another host removes the file..
92952196Smckusick 		 */
93053806Smckusick 		cache_purge(vp);
93152196Smckusick 		/*
93252196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
93352196Smckusick 		 * unnecessary delayed writes.
93452196Smckusick 		 */
93553806Smckusick 		vinvalbuf(vp, FALSE);
93652196Smckusick 		/* Do the rpc */
93738414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
93853806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
93953806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
94053806Smckusick 		nfsm_fhtom(dvp);
94153806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
94253806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
94338414Smckusick 		nfsm_reqdone;
94453806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
94553806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
94639751Smckusick 		/*
94739751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
94839751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
94939751Smckusick 		 *   since the file was in fact removed
95039751Smckusick 		 *   Therefore, we cheat and return success.
95139751Smckusick 		 */
95239751Smckusick 		if (error == ENOENT)
95339751Smckusick 			error = 0;
95438414Smckusick 	}
95540042Smckusick 	np->n_attrstamp = 0;
95653806Smckusick 	vrele(dvp);
95753806Smckusick 	vrele(vp);
95838414Smckusick 	return (error);
95938414Smckusick }
96038414Smckusick 
96138414Smckusick /*
96238414Smckusick  * nfs file remove rpc called from nfs_inactive
96338414Smckusick  */
96452234Sheideman int
96552196Smckusick nfs_removeit(sp, procp)
96648364Smckusick 	register struct sillyrename *sp;
96752196Smckusick 	struct proc *procp;
96838414Smckusick {
96948054Smckusick 	register u_long *tl;
97039488Smckusick 	register caddr_t cp;
97152196Smckusick 	register long t2;
97239488Smckusick 	caddr_t bpos, dpos;
97339488Smckusick 	int error = 0;
97439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97538414Smckusick 
97638414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
97752196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
97848364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
97948364Smckusick 	nfsm_fhtom(sp->s_dvp);
98048364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
98152196Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, procp, sp->s_cred);
98238414Smckusick 	nfsm_reqdone;
98348364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
98438414Smckusick 	return (error);
98538414Smckusick }
98638414Smckusick 
98738414Smckusick /*
98838414Smckusick  * nfs file rename call
98938414Smckusick  */
99052234Sheideman int
99153806Smckusick nfs_rename(ap)
99253554Sheideman 	struct vop_rename_args *ap;
99338414Smckusick {
99453806Smckusick 	register struct vnode *fvp = ap->a_fvp;
99553806Smckusick 	register struct vnode *tvp = ap->a_tvp;
99653806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
99753806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
99853806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
99953806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
100048054Smckusick 	register u_long *tl;
100139488Smckusick 	register caddr_t cp;
100252196Smckusick 	register long t2;
100339488Smckusick 	caddr_t bpos, dpos;
100439488Smckusick 	int error = 0;
100539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
100638414Smckusick 
100753804Spendry 	/* Check for cross-device rename */
100853806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
100953806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
101053804Spendry 		error = EXDEV;
101153804Spendry 		goto out;
101253804Spendry 	}
101353804Spendry 
101453804Spendry 
101538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
101653806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
101753806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
101853806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
101953806Smckusick 	nfsm_fhtom(fdvp);
102053806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
102153806Smckusick 	nfsm_fhtom(tdvp);
102253806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
102353806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
102438414Smckusick 	nfsm_reqdone;
102553806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
102653806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
102753806Smckusick 	if (fvp->v_type == VDIR) {
102853806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
102953806Smckusick 			cache_purge(tdvp);
103053806Smckusick 		cache_purge(fdvp);
103138414Smckusick 	}
103253804Spendry out:
103353806Smckusick 	if (tdvp == tvp)
103453806Smckusick 		vrele(tdvp);
103543360Smckusick 	else
103653806Smckusick 		vput(tdvp);
103753806Smckusick 	if (tvp)
103853806Smckusick 		vput(tvp);
103953806Smckusick 	vrele(fdvp);
104053806Smckusick 	vrele(fvp);
104140112Smckusick 	/*
104240112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
104340112Smckusick 	 */
104440112Smckusick 	if (error == ENOENT)
104540112Smckusick 		error = 0;
104638414Smckusick 	return (error);
104738414Smckusick }
104838414Smckusick 
104938414Smckusick /*
105041905Smckusick  * nfs file rename rpc called from nfs_remove() above
105138414Smckusick  */
105252234Sheideman int
105352234Sheideman nfs_renameit(sdvp, scnp, sp)
105452234Sheideman 	struct vnode *sdvp;
105552234Sheideman 	struct componentname *scnp;
105648364Smckusick 	register struct sillyrename *sp;
105738414Smckusick {
105848054Smckusick 	register u_long *tl;
105939488Smckusick 	register caddr_t cp;
106052196Smckusick 	register long t2;
106139488Smckusick 	caddr_t bpos, dpos;
106239488Smckusick 	int error = 0;
106339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
106438414Smckusick 
106538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
106652234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
106752234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
106852196Smckusick 		nfsm_rndup(sp->s_namlen));
106952234Sheideman 	nfsm_fhtom(sdvp);
107052234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
107152234Sheideman 	nfsm_fhtom(sdvp);
107248364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
107352234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
107438414Smckusick 	nfsm_reqdone;
107552234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
107652234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
107738414Smckusick 	return (error);
107838414Smckusick }
107938414Smckusick 
108038414Smckusick /*
108138414Smckusick  * nfs hard link create call
108238414Smckusick  */
108352234Sheideman int
108453806Smckusick nfs_link(ap)
108553554Sheideman 	struct vop_link_args *ap;
108638414Smckusick {
108753806Smckusick 	register struct vnode *vp = ap->a_vp;
108853806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
108953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
109048054Smckusick 	register u_long *tl;
109139488Smckusick 	register caddr_t cp;
109252196Smckusick 	register long t2;
109339488Smckusick 	caddr_t bpos, dpos;
109439488Smckusick 	int error = 0;
109539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
109638414Smckusick 
109753806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
109853806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
109953806Smckusick 		if (tdvp == vp)
110053806Smckusick 			vrele(vp);
110153804Spendry 		else
110253806Smckusick 			vput(vp);
110353806Smckusick 		vrele(tdvp);
110453804Spendry 		return (EXDEV);
110553804Spendry 	}
110653804Spendry 
110738414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
110853806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
110953806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
111053806Smckusick 	nfsm_fhtom(tdvp);
111153806Smckusick 	nfsm_fhtom(vp);
111253806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
111353806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
111438414Smckusick 	nfsm_reqdone;
111553806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
111653806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
111753806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
111853806Smckusick 	vrele(vp);
111940112Smckusick 	/*
112040112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
112140112Smckusick 	 */
112240112Smckusick 	if (error == EEXIST)
112340112Smckusick 		error = 0;
112438414Smckusick 	return (error);
112538414Smckusick }
112638414Smckusick 
112738414Smckusick /*
112838414Smckusick  * nfs symbolic link create call
112938414Smckusick  */
113052234Sheideman /* start here */
113152234Sheideman int
113253806Smckusick nfs_symlink(ap)
113353554Sheideman 	struct vop_symlink_args *ap;
113438414Smckusick {
113553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
113653806Smckusick 	register struct vattr *vap = ap->a_vap;
113753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
113838884Smacklem 	register struct nfsv2_sattr *sp;
113948054Smckusick 	register u_long *tl;
114039488Smckusick 	register caddr_t cp;
114152196Smckusick 	register long t2;
114239488Smckusick 	caddr_t bpos, dpos;
114352196Smckusick 	int slen, error = 0;
114439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
114538414Smckusick 
114638414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
114753600Sheideman 	slen = strlen(ap->a_target);
114853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
114953806Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR);
115053806Smckusick 	nfsm_fhtom(dvp);
115153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
115253600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
115338884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
115453806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
115553806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
115653806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
115738884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
115853806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
115953806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
116053806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
116138414Smckusick 	nfsm_reqdone;
116253806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
116353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
116453806Smckusick 	vrele(dvp);
116540112Smckusick 	/*
116640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
116740112Smckusick 	 */
116840112Smckusick 	if (error == EEXIST)
116940112Smckusick 		error = 0;
117038414Smckusick 	return (error);
117138414Smckusick }
117238414Smckusick 
117338414Smckusick /*
117438414Smckusick  * nfs make dir call
117538414Smckusick  */
117652234Sheideman int
117753806Smckusick nfs_mkdir(ap)
117853554Sheideman 	struct vop_mkdir_args *ap;
117938414Smckusick {
118053806Smckusick 	register struct vnode *dvp = ap->a_dvp;
118153806Smckusick 	register struct vattr *vap = ap->a_vap;
118253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
118338884Smacklem 	register struct nfsv2_sattr *sp;
118448054Smckusick 	register u_long *tl;
118539488Smckusick 	register caddr_t cp;
118639488Smckusick 	register long t1, t2;
118741905Smckusick 	register int len;
118839488Smckusick 	caddr_t bpos, dpos, cp2;
118941905Smckusick 	int error = 0, firsttry = 1;
119039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
119138414Smckusick 
119253806Smckusick 	len = cnp->cn_namelen;
119338414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
119453806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
119541905Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
119653806Smckusick 	nfsm_fhtom(dvp);
119753806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
119838884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
119953806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
120053806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
120153806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
120238884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
120353806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
120453806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
120553806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
120653806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
120738414Smckusick 	nfsm_reqdone;
120853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
120940112Smckusick 	/*
121041905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
121141905Smckusick 	 * if we can succeed in looking up the directory.
121241905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
121341905Smckusick 	 * is above the if on errors. (Ugh)
121440112Smckusick 	 */
121541905Smckusick 	if (error == EEXIST && firsttry) {
121641905Smckusick 		firsttry = 0;
121740112Smckusick 		error = 0;
121841905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
121953600Sheideman 		*ap->a_vpp = NULL;
122053806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
122141905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
122253806Smckusick 		nfsm_fhtom(dvp);
122353806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
122453806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
122553806Smckusick 		nfsm_mtofh(dvp, *ap->a_vpp);
122653600Sheideman 		if ((*ap->a_vpp)->v_type != VDIR) {
122753600Sheideman 			vput(*ap->a_vpp);
122841905Smckusick 			error = EEXIST;
122941905Smckusick 		}
123041905Smckusick 		m_freem(mrep);
123141905Smckusick 	}
123253806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
123353806Smckusick 	vrele(dvp);
123438414Smckusick 	return (error);
123538414Smckusick }
123638414Smckusick 
123738414Smckusick /*
123838414Smckusick  * nfs remove directory call
123938414Smckusick  */
124052234Sheideman int
124153806Smckusick nfs_rmdir(ap)
124253554Sheideman 	struct vop_rmdir_args *ap;
124338414Smckusick {
124453806Smckusick 	register struct vnode *vp = ap->a_vp;
124553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
124653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
124748054Smckusick 	register u_long *tl;
124839488Smckusick 	register caddr_t cp;
124952196Smckusick 	register long t2;
125039488Smckusick 	caddr_t bpos, dpos;
125139488Smckusick 	int error = 0;
125239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
125338414Smckusick 
125453806Smckusick 	if (dvp == vp) {
125553806Smckusick 		vrele(dvp);
125653806Smckusick 		vrele(dvp);
125753806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
125838414Smckusick 		return (EINVAL);
125938414Smckusick 	}
126038414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
126153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
126253806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
126353806Smckusick 	nfsm_fhtom(dvp);
126453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
126553806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
126638414Smckusick 	nfsm_reqdone;
126753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
126853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
126953806Smckusick 	cache_purge(dvp);
127053806Smckusick 	cache_purge(vp);
127153806Smckusick 	vrele(vp);
127253806Smckusick 	vrele(dvp);
127340112Smckusick 	/*
127440112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
127540112Smckusick 	 */
127640112Smckusick 	if (error == ENOENT)
127740112Smckusick 		error = 0;
127838414Smckusick 	return (error);
127938414Smckusick }
128038414Smckusick 
128138414Smckusick /*
128238414Smckusick  * nfs readdir call
128338414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
128438414Smckusick  * order so that it looks more sensible. This appears consistent with the
128538414Smckusick  * Ultrix implementation of NFS.
128638414Smckusick  */
128752234Sheideman int
128853806Smckusick nfs_readdir(ap)
128953554Sheideman 	struct vop_readdir_args *ap;
129038414Smckusick {
129153554Sheideman 	USES_VOP_GETATTR;
129253806Smckusick 	register struct vnode *vp = ap->a_vp;
129353806Smckusick 	register struct nfsnode *np = VTONFS(vp);
129453806Smckusick 	register struct uio *uio = ap->a_uio;
129553806Smckusick 	register int *eofflagp = ap->a_eofflagp;
129641905Smckusick 	int tresid, error;
129741905Smckusick 	struct vattr vattr;
129841905Smckusick 
129953806Smckusick 	if (vp->v_type != VDIR)
130041905Smckusick 		return (EPERM);
130141905Smckusick 	/*
130241905Smckusick 	 * First, check for hit on the EOF offset cache
130341905Smckusick 	 */
130453806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
130552196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
130653806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
130753806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
130853806Smckusick 				*eofflagp = 1;
130952196Smckusick 				nfsstats.direofcache_hits++;
131052196Smckusick 				return (0);
131152196Smckusick 			}
131253806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
131352196Smckusick 			np->n_mtime == vattr.va_mtime.tv_sec) {
131453806Smckusick 			*eofflagp = 1;
131552196Smckusick 			nfsstats.direofcache_hits++;
131652196Smckusick 			return (0);
131752196Smckusick 		}
131841905Smckusick 	}
131941905Smckusick 
132041905Smckusick 	/*
132141905Smckusick 	 * Call nfs_bioread() to do the real work.
132241905Smckusick 	 */
132353806Smckusick 	tresid = uio->uio_resid;
132453806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
132541905Smckusick 
132653806Smckusick 	if (!error && uio->uio_resid == tresid) {
132753806Smckusick 		*eofflagp = 1;
132841905Smckusick 		nfsstats.direofcache_misses++;
132941905Smckusick 	} else
133053806Smckusick 		*eofflagp = 0;
133141905Smckusick 	return (error);
133241905Smckusick }
133341905Smckusick 
133441905Smckusick /*
133541905Smckusick  * Readdir rpc call.
133641905Smckusick  * Called from below the buffer cache by nfs_doio().
133741905Smckusick  */
133852234Sheideman int
133948054Smckusick nfs_readdirrpc(vp, uiop, cred)
134041905Smckusick 	register struct vnode *vp;
134141905Smckusick 	struct uio *uiop;
134241905Smckusick 	struct ucred *cred;
134341905Smckusick {
134438414Smckusick 	register long len;
134552436Smckusick 	register struct readdir *dp;
134648054Smckusick 	register u_long *tl;
134739488Smckusick 	register caddr_t cp;
134839488Smckusick 	register long t1;
134941905Smckusick 	long tlen, lastlen;
135039488Smckusick 	caddr_t bpos, dpos, cp2;
135139488Smckusick 	int error = 0;
135239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
135338414Smckusick 	struct mbuf *md2;
135438414Smckusick 	caddr_t dpos2;
135538414Smckusick 	int siz;
135640296Smckusick 	int more_dirs = 1;
135738414Smckusick 	off_t off, savoff;
135852436Smckusick 	struct readdir *savdp;
135940296Smckusick 	struct nfsmount *nmp;
136040296Smckusick 	struct nfsnode *np = VTONFS(vp);
136140296Smckusick 	long tresid;
136238414Smckusick 
136341398Smckusick 	nmp = VFSTONFS(vp->v_mount);
136440296Smckusick 	tresid = uiop->uio_resid;
136540296Smckusick 	/*
136640296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
136748054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
136841905Smckusick 	 * The stopping criteria is EOF or buffer full.
136940296Smckusick 	 */
137048054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
137140296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
137252196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
137352196Smckusick 			NFSX_FH+2*NFSX_UNSIGNED);
137440296Smckusick 		nfsm_fhtom(vp);
137548054Smckusick 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
137648054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
137748054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
137848054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
137952196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
138040296Smckusick 		siz = 0;
138152196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
138248054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
138340296Smckusick 
138440296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
138540296Smckusick 		dpos2 = dpos;
138640296Smckusick 		md2 = md;
138740296Smckusick 
138840296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
138941905Smckusick 		off = uiop->uio_offset;
139042246Smckusick #ifdef lint
139152436Smckusick 		dp = (struct readdir *)0;
139242246Smckusick #endif /* lint */
139340296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
139440296Smckusick 			savoff = off;		/* Hold onto offset and dp */
139540296Smckusick 			savdp = dp;
139652196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
139752436Smckusick 			dp = (struct readdir *)tl;
139848054Smckusick 			dp->d_ino = fxdr_unsigned(u_long, *tl++);
139948054Smckusick 			len = fxdr_unsigned(int, *tl);
140040296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
140140296Smckusick 				error = EBADRPC;
140240296Smckusick 				m_freem(mrep);
140340296Smckusick 				goto nfsmout;
140440296Smckusick 			}
140540296Smckusick 			dp->d_namlen = (u_short)len;
140640296Smckusick 			nfsm_adv(len);		/* Point past name */
140740296Smckusick 			tlen = nfsm_rndup(len);
140840296Smckusick 			/*
140940296Smckusick 			 * This should not be necessary, but some servers have
141040296Smckusick 			 * broken XDR such that these bytes are not null filled.
141140296Smckusick 			 */
141240296Smckusick 			if (tlen != len) {
141340296Smckusick 				*dpos = '\0';	/* Null-terminate */
141440296Smckusick 				nfsm_adv(tlen - len);
141540296Smckusick 				len = tlen;
141640296Smckusick 			}
141752196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
141848054Smckusick 			off = fxdr_unsigned(off_t, *tl);
141948054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
142048054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
142140296Smckusick 			dp->d_reclen = len+4*NFSX_UNSIGNED;
142240296Smckusick 			siz += dp->d_reclen;
142340296Smckusick 		}
142440296Smckusick 		/*
142540296Smckusick 		 * If at end of rpc data, get the eof boolean
142640296Smckusick 		 */
142740296Smckusick 		if (!more_dirs) {
142852196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
142948054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
143038414Smckusick 
143140296Smckusick 			/*
143240296Smckusick 			 * If at EOF, cache directory offset
143340296Smckusick 			 */
143441905Smckusick 			if (!more_dirs)
143540296Smckusick 				np->n_direofoffset = off;
143638414Smckusick 		}
143740296Smckusick 		/*
143840296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
143940296Smckusick 		 * savdp to trim off the last record.
144040296Smckusick 		 * --> we are not at eof
144140296Smckusick 		 */
144240296Smckusick 		if (siz > uiop->uio_resid) {
144340296Smckusick 			off = savoff;
144440296Smckusick 			siz -= dp->d_reclen;
144540296Smckusick 			dp = savdp;
144640296Smckusick 			more_dirs = 0;	/* Paranoia */
144740113Smckusick 		}
144840296Smckusick 		if (siz > 0) {
144941905Smckusick 			lastlen = dp->d_reclen;
145040296Smckusick 			md = md2;
145140296Smckusick 			dpos = dpos2;
145240296Smckusick 			nfsm_mtouio(uiop, siz);
145340296Smckusick 			uiop->uio_offset = off;
145440296Smckusick 		} else
145540296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
145640296Smckusick 		m_freem(mrep);
145738414Smckusick 	}
145841905Smckusick 	/*
145948054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
146041905Smckusick 	 * by increasing d_reclen for the last record.
146141905Smckusick 	 */
146241905Smckusick 	if (uiop->uio_resid < tresid) {
146348054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
146441905Smckusick 		if (len > 0) {
146552436Smckusick 			dp = (struct readdir *)
146641905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
146741905Smckusick 			dp->d_reclen += len;
146841905Smckusick 			uiop->uio_iov->iov_base += len;
146941905Smckusick 			uiop->uio_iov->iov_len -= len;
147041905Smckusick 			uiop->uio_resid -= len;
147141905Smckusick 		}
147241905Smckusick 	}
147340296Smckusick nfsmout:
147438414Smckusick 	return (error);
147538414Smckusick }
147638414Smckusick 
147752196Smckusick /*
147852196Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when
147952196Smckusick  * the "rdirlook" mount option is specified.
148052196Smckusick  */
148152234Sheideman int
148252196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
148352196Smckusick 	struct vnode *vp;
148452196Smckusick 	register struct uio *uiop;
148552196Smckusick 	struct ucred *cred;
148652196Smckusick {
148752196Smckusick 	register int len;
148852436Smckusick 	register struct readdir *dp;
148952196Smckusick 	register u_long *tl;
149052196Smckusick 	register caddr_t cp;
149152196Smckusick 	register long t1;
149252196Smckusick 	caddr_t bpos, dpos, cp2;
149352196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
149452196Smckusick 	struct nameidata nami, *ndp = &nami;
149552317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
149652196Smckusick 	off_t off, endoff;
149752196Smckusick 	time_t reqtime, ltime;
149852196Smckusick 	struct nfsmount *nmp;
149952196Smckusick 	struct nfsnode *np, *tp;
150052196Smckusick 	struct vnode *newvp;
150152196Smckusick 	nfsv2fh_t *fhp;
150252196Smckusick 	u_long fileno;
150352196Smckusick 	u_quad_t frev;
150452196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
150552196Smckusick 	int cachable;
150652196Smckusick 
150752196Smckusick 	if (uiop->uio_iovcnt != 1)
150852196Smckusick 		panic("nfs rdirlook");
150952196Smckusick 	nmp = VFSTONFS(vp->v_mount);
151052196Smckusick 	tresid = uiop->uio_resid;
151152196Smckusick 	ndp->ni_dvp = vp;
151252196Smckusick 	newvp = NULLVP;
151352196Smckusick 	/*
151452196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
151552196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
151652196Smckusick 	 * The stopping criteria is EOF or buffer full.
151752196Smckusick 	 */
151852196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
151952196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
152052196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
152152196Smckusick 			NFSX_FH+3*NFSX_UNSIGNED);
152252196Smckusick 		nfsm_fhtom(vp);
152352196Smckusick 		nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED);
152452196Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
152552196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
152652196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
152752196Smckusick 		*tl = txdr_unsigned(nmp->nm_leaseterm);
152852196Smckusick 		reqtime = time.tv_sec;
152952196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
153052196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
153152196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
153252196Smckusick 
153352196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
153452196Smckusick 		off = uiop->uio_offset;
153552196Smckusick 		bigenough = 1;
153652196Smckusick 		while (more_dirs && bigenough) {
153752196Smckusick 			doit = 1;
153852196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
153952196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
154052196Smckusick 			ltime = reqtime + fxdr_unsigned(int, *tl++);
154152196Smckusick 			fxdr_hyper(tl, &frev);
154252196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
154352196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
154452196Smckusick 				VREF(vp);
154552196Smckusick 				newvp = vp;
154652196Smckusick 				np = VTONFS(vp);
154752196Smckusick 			} else {
154852196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
154952196Smckusick 					doit = 0;
155052196Smckusick 				newvp = NFSTOV(np);
155152196Smckusick 			}
155252196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
155352196Smckusick 				(struct vattr *)0))
155452196Smckusick 				doit = 0;
155552196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
155652196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
155752196Smckusick 			len = fxdr_unsigned(int, *tl);
155852196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
155952196Smckusick 				error = EBADRPC;
156052196Smckusick 				m_freem(mrep);
156152196Smckusick 				goto nfsmout;
156252196Smckusick 			}
156352196Smckusick 			tlen = (len + 4) & ~0x3;
156452196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
156552196Smckusick 				bigenough = 0;
156652196Smckusick 			if (bigenough && doit) {
156752436Smckusick 				dp = (struct readdir *)uiop->uio_iov->iov_base;
156852196Smckusick 				dp->d_ino = fileno;
156952196Smckusick 				dp->d_namlen = len;
157052196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
157152196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
157252196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
157352196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
157452317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
157552317Sheideman 				cnp->cn_namelen = len;
157652196Smckusick 				ndp->ni_vp = newvp;
157752196Smckusick 				nfsm_mtouio(uiop, len);
157852196Smckusick 				cp = uiop->uio_iov->iov_base;
157952196Smckusick 				tlen -= len;
158052196Smckusick 				for (i = 0; i < tlen; i++)
158152196Smckusick 					*cp++ = '\0';
158252196Smckusick 				uiop->uio_iov->iov_base += tlen;
158352196Smckusick 				uiop->uio_iov->iov_len -= tlen;
158452196Smckusick 				uiop->uio_resid -= tlen;
158552317Sheideman 				cnp->cn_hash = 0;
158652317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
158752317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
158852196Smckusick 				if (ltime > time.tv_sec) {
158952196Smckusick 					if (np->n_tnext) {
159052196Smckusick 						if (np->n_tnext == (struct nfsnode *)nmp)
159152196Smckusick 							nmp->nm_tprev = np->n_tprev;
159252196Smckusick 						else
159352196Smckusick 							np->n_tnext->n_tprev = np->n_tprev;
159452196Smckusick 						if (np->n_tprev == (struct nfsnode *)nmp)
159552196Smckusick 							nmp->nm_tnext = np->n_tnext;
159652196Smckusick 						else
159752196Smckusick 							np->n_tprev->n_tnext = np->n_tnext;
159852196Smckusick 					} else
159952196Smckusick 						np->n_flag &= ~NQNFSWRITE;
160052196Smckusick 					if (cachable)
160152196Smckusick 						np->n_flag &= ~NQNFSNONCACHE;
160252196Smckusick 					else
160352196Smckusick 						np->n_flag |= NQNFSNONCACHE;
160452196Smckusick 					np->n_expiry = ltime;
160552196Smckusick 					np->n_lrev = frev;
160652196Smckusick 					tp = nmp->nm_tprev;
160752196Smckusick 					while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
160852196Smckusick 						tp = tp->n_tprev;
160952196Smckusick 					if (tp == (struct nfsnode *)nmp) {
161052196Smckusick 						np->n_tnext = nmp->nm_tnext;
161152196Smckusick 						nmp->nm_tnext = np;
161252196Smckusick 					} else {
161352196Smckusick 						np->n_tnext = tp->n_tnext;
161452196Smckusick 						tp->n_tnext = np;
161552196Smckusick 					}
161652196Smckusick 					np->n_tprev = tp;
161752196Smckusick 					if (np->n_tnext == (struct nfsnode *)nmp)
161852196Smckusick 						nmp->nm_tprev = np;
161952196Smckusick 					else
162052196Smckusick 						np->n_tnext->n_tprev = np;
162152317Sheideman 					cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
162252196Smckusick 				}
162352196Smckusick 			} else {
162452196Smckusick 				nfsm_adv(nfsm_rndup(len));
162552196Smckusick 			}
162652196Smckusick 			if (newvp != NULLVP) {
162752196Smckusick 				vrele(newvp);
162852196Smckusick 				newvp = NULLVP;
162952196Smckusick 			}
163052196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
163152196Smckusick 			if (bigenough)
163252196Smckusick 				endoff = off = fxdr_unsigned(off_t, *tl++);
163352196Smckusick 			else
163452196Smckusick 				endoff = fxdr_unsigned(off_t, *tl++);
163552196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
163652196Smckusick 		}
163752196Smckusick 		/*
163852196Smckusick 		 * If at end of rpc data, get the eof boolean
163952196Smckusick 		 */
164052196Smckusick 		if (!more_dirs) {
164152196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
164252196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
164352196Smckusick 
164452196Smckusick 			/*
164552196Smckusick 			 * If at EOF, cache directory offset
164652196Smckusick 			 */
164752196Smckusick 			if (!more_dirs)
164852196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
164952196Smckusick 		}
165052196Smckusick 		if (uiop->uio_resid < tresid)
165152196Smckusick 			uiop->uio_offset = off;
165252196Smckusick 		else
165352196Smckusick 			more_dirs = 0;
165452196Smckusick 		m_freem(mrep);
165552196Smckusick 	}
165652196Smckusick 	/*
165752196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
165852196Smckusick 	 * by increasing d_reclen for the last record.
165952196Smckusick 	 */
166052196Smckusick 	if (uiop->uio_resid < tresid) {
166152196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
166252196Smckusick 		if (len > 0) {
166352196Smckusick 			dp->d_reclen += len;
166452196Smckusick 			uiop->uio_iov->iov_base += len;
166552196Smckusick 			uiop->uio_iov->iov_len -= len;
166652196Smckusick 			uiop->uio_resid -= len;
166752196Smckusick 		}
166852196Smckusick 	}
166952196Smckusick nfsmout:
167052196Smckusick 	if (newvp != NULLVP)
167152196Smckusick 		vrele(newvp);
167252196Smckusick 	return (error);
167352196Smckusick }
167439488Smckusick static char hextoasc[] = "0123456789abcdef";
167538414Smckusick 
167638414Smckusick /*
167738414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
167838414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
167938414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
168038414Smckusick  * nfsnode. There is the potential for another process on a different client
168138414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
168238414Smckusick  * nfs_rename() completes, but...
168338414Smckusick  */
168452234Sheideman int
168552317Sheideman nfs_sillyrename(dvp, vp, cnp)
168652234Sheideman 	struct vnode *dvp, *vp;
168752234Sheideman 	struct componentname *cnp;
168838414Smckusick {
168938414Smckusick 	register struct nfsnode *np;
169038414Smckusick 	register struct sillyrename *sp;
169138414Smckusick 	int error;
169238414Smckusick 	short pid;
169338414Smckusick 
169452234Sheideman 	cache_purge(dvp);
169552234Sheideman 	np = VTONFS(vp);
169651986Smckusick #ifdef SILLYSEPARATE
169738414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
169848364Smckusick 		M_NFSREQ, M_WAITOK);
169951986Smckusick #else
170051986Smckusick 	sp = &np->n_silly;
170151986Smckusick #endif
170252234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
170352234Sheideman 	sp->s_dvp = dvp;
170452234Sheideman 	VREF(dvp);
170538414Smckusick 
170638414Smckusick 	/* Fudge together a funny name */
170752234Sheideman 	pid = cnp->cn_proc->p_pid;
170848364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
170948364Smckusick 	sp->s_namlen = 12;
171048364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
171148364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
171248364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
171348364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
171438414Smckusick 
171538414Smckusick 	/* Try lookitups until we get one that isn't there */
171652234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
171748364Smckusick 		sp->s_name[4]++;
171848364Smckusick 		if (sp->s_name[4] > 'z') {
171938414Smckusick 			error = EINVAL;
172038414Smckusick 			goto bad;
172138414Smckusick 		}
172238414Smckusick 	}
172352234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
172438414Smckusick 		goto bad;
172552234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
172638414Smckusick 	np->n_sillyrename = sp;
172738414Smckusick 	return (0);
172838414Smckusick bad:
172948364Smckusick 	vrele(sp->s_dvp);
173048364Smckusick 	crfree(sp->s_cred);
173151986Smckusick #ifdef SILLYSEPARATE
173248364Smckusick 	free((caddr_t)sp, M_NFSREQ);
173351986Smckusick #endif
173438414Smckusick 	return (error);
173538414Smckusick }
173638414Smckusick 
173738414Smckusick /*
173838414Smckusick  * Look up a file name for silly rename stuff.
173938414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
174038414Smckusick  * into the nfsnode table.
174138414Smckusick  * If fhp != NULL it copies the returned file handle out
174238414Smckusick  */
174352234Sheideman int
174452196Smckusick nfs_lookitup(sp, fhp, procp)
174548364Smckusick 	register struct sillyrename *sp;
174638414Smckusick 	nfsv2fh_t *fhp;
174752196Smckusick 	struct proc *procp;
174838414Smckusick {
174948364Smckusick 	register struct vnode *vp = sp->s_dvp;
175048054Smckusick 	register u_long *tl;
175139488Smckusick 	register caddr_t cp;
175239488Smckusick 	register long t1, t2;
175339488Smckusick 	caddr_t bpos, dpos, cp2;
175439488Smckusick 	u_long xid;
175539488Smckusick 	int error = 0;
175639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
175738414Smckusick 	long len;
175838414Smckusick 
175938414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
176048364Smckusick 	len = sp->s_namlen;
176152196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
176238414Smckusick 	nfsm_fhtom(vp);
176348364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
176452196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
176538414Smckusick 	if (fhp != NULL) {
176652196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
176738414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
176838414Smckusick 	}
176938414Smckusick 	nfsm_reqdone;
177038414Smckusick 	return (error);
177138414Smckusick }
177238414Smckusick 
177338414Smckusick /*
177438414Smckusick  * Kludge City..
177538414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
177641905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
177738414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
177838414Smckusick  *   nfsiobuf area.
177938414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
178038414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
178138414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
178238414Smckusick  *    context of the swapper process (2).
178338414Smckusick  */
178452234Sheideman int
178553806Smckusick nfs_bmap(ap)
178653554Sheideman 	struct vop_bmap_args *ap;
178738414Smckusick {
178853806Smckusick 	register struct vnode *vp = ap->a_vp;
178953806Smckusick 
179053600Sheideman 	if (ap->a_vpp != NULL)
179153806Smckusick 		*ap->a_vpp = vp;
179253600Sheideman 	if (ap->a_bnp != NULL)
179353806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
179438414Smckusick 	return (0);
179538414Smckusick }
179638414Smckusick 
179738414Smckusick /*
179838884Smacklem  * Strategy routine for phys. i/o
179938884Smacklem  * If the biod's are running, queue a request
180038884Smacklem  * otherwise just call nfs_doio() to get it done
180138414Smckusick  */
180252234Sheideman int
180353806Smckusick nfs_strategy(ap)
180453554Sheideman 	struct vop_strategy_args *ap;
180538414Smckusick {
180653806Smckusick 	register struct buf *bp = ap->a_bp;
180738884Smacklem 	register struct buf *dp;
180839341Smckusick 	register int i;
180938884Smacklem 	int error = 0;
181039341Smckusick 	int fnd = 0;
181138884Smacklem 
181238884Smacklem 	/*
181341905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
181441905Smckusick 	 * doesn't set it, I will.
181546450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
181641905Smckusick 	 * be hanging about after the process terminates.
181741905Smckusick 	 */
181853806Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
181953806Smckusick 		if (bp->b_flags & B_ASYNC)
182053806Smckusick 			bp->b_proc = (struct proc *)0;
182146988Smckusick 		else
182253806Smckusick 			bp->b_proc = curproc;
182346988Smckusick 	}
182441905Smckusick 	/*
182546450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
182638884Smacklem 	 * queue the request, wake it up and wait for completion
182746450Skarels 	 * otherwise just do it ourselves.
182838884Smacklem 	 */
182953806Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
183053806Smckusick 		return (nfs_doio(bp));
183146988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
183246988Smckusick 		if (nfs_iodwant[i]) {
183339341Smckusick 			dp = &nfs_bqueue;
183439341Smckusick 			if (dp->b_actf == NULL) {
183553806Smckusick 				dp->b_actl = bp;
183653806Smckusick 				bp->b_actf = dp;
183739341Smckusick 			} else {
183853806Smckusick 				dp->b_actf->b_actl = bp;
183953806Smckusick 				bp->b_actf = dp->b_actf;
184039341Smckusick 			}
184153806Smckusick 			dp->b_actf = bp;
184253806Smckusick 			bp->b_actl = dp;
184339341Smckusick 			fnd++;
184439341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
184539341Smckusick 			break;
184638884Smacklem 		}
184739341Smckusick 	}
184839341Smckusick 	if (!fnd)
184953806Smckusick 		error = nfs_doio(bp);
185038884Smacklem 	return (error);
185138884Smacklem }
185238884Smacklem 
185338884Smacklem /*
185438884Smacklem  * Fun and games with i/o
185538884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
185638884Smacklem  * mapping the data buffer into kernel virtual space and doing the
185738884Smacklem  * nfs read or write rpc's from it.
185841905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
185941905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
186038884Smacklem  * partially disk interrupt driven.
186138884Smacklem  */
186252234Sheideman int
186338884Smacklem nfs_doio(bp)
186438884Smacklem 	register struct buf *bp;
186538884Smacklem {
186638414Smckusick 	register struct uio *uiop;
186738414Smckusick 	register struct vnode *vp;
186839341Smckusick 	struct nfsnode *np;
186938884Smacklem 	struct ucred *cr;
187041539Smckusick 	int error;
187141539Smckusick 	struct uio uio;
187241539Smckusick 	struct iovec io;
187338414Smckusick 
187438414Smckusick 	vp = bp->b_vp;
187540251Smckusick 	np = VTONFS(vp);
187638414Smckusick 	uiop = &uio;
187738414Smckusick 	uiop->uio_iov = &io;
187838414Smckusick 	uiop->uio_iovcnt = 1;
187938414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
188052196Smckusick 	uiop->uio_procp = bp->b_proc;
188139751Smckusick 
188238414Smckusick 	/*
188338884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
188438884Smacklem 	 * the Nfsiomap pte's
188538884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
188638884Smacklem 	 * and a guess at a group
188738414Smckusick 	 */
188838884Smacklem 	if (bp->b_flags & B_PHYS) {
188948054Smckusick 		if (bp->b_flags & B_DIRTY)
189048054Smckusick 			uiop->uio_procp = pageproc;
189148054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
189241539Smckusick 		/* mapping was already done by vmapbuf */
189341539Smckusick 		io.iov_base = bp->b_un.b_addr;
189439751Smckusick 
189538884Smacklem 		/*
189639751Smckusick 		 * And do the i/o rpc
189739751Smckusick 		 */
189839751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
189939823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
190039751Smckusick 		if (bp->b_flags & B_READ) {
190139751Smckusick 			uiop->uio_rw = UIO_READ;
190239751Smckusick 			nfsstats.read_physios++;
190348054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
190445717Smckusick 			(void) vnode_pager_uncache(vp);
190539751Smckusick 		} else {
190639751Smckusick 			uiop->uio_rw = UIO_WRITE;
190739751Smckusick 			nfsstats.write_physios++;
190848054Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr);
190939341Smckusick 		}
191039751Smckusick 
191139751Smckusick 		/*
191239751Smckusick 		 * Finally, release pte's used by physical i/o
191339751Smckusick 		 */
191438884Smacklem 		crfree(cr);
191539751Smckusick 	} else {
191639751Smckusick 		if (bp->b_flags & B_READ) {
191739751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
191839751Smckusick 			io.iov_base = bp->b_un.b_addr;
191939751Smckusick 			uiop->uio_rw = UIO_READ;
192041905Smckusick 			switch (vp->v_type) {
192141905Smckusick 			case VREG:
192241905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
192341905Smckusick 				nfsstats.read_bios++;
192448054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
192541905Smckusick 				break;
192641905Smckusick 			case VLNK:
192741905Smckusick 				uiop->uio_offset = 0;
192841905Smckusick 				nfsstats.readlink_bios++;
192948054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
193041905Smckusick 				break;
193141905Smckusick 			case VDIR:
193241905Smckusick 				uiop->uio_offset = bp->b_lblkno;
193341905Smckusick 				nfsstats.readdir_bios++;
193452196Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK)
193552196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
193652196Smckusick 				else
193752196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
193841905Smckusick 				/*
193941905Smckusick 				 * Save offset cookie in b_blkno.
194041905Smckusick 				 */
194141905Smckusick 				bp->b_blkno = uiop->uio_offset;
194241905Smckusick 				break;
194341905Smckusick 			};
194441905Smckusick 			bp->b_error = error;
194539751Smckusick 		} else {
194639751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
194739751Smckusick 				- bp->b_dirtyoff;
194839823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
194939751Smckusick 				+ bp->b_dirtyoff;
195039751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
195139751Smckusick 			uiop->uio_rw = UIO_WRITE;
195239751Smckusick 			nfsstats.write_bios++;
195341905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
195448054Smckusick 				bp->b_wcred);
195539751Smckusick 			if (error) {
195639751Smckusick 				np->n_error = error;
195739751Smckusick 				np->n_flag |= NWRITEERR;
195839751Smckusick 			}
195939751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
196039751Smckusick 		}
196138884Smacklem 	}
196239751Smckusick 	if (error)
196339751Smckusick 		bp->b_flags |= B_ERROR;
196439751Smckusick 	bp->b_resid = uiop->uio_resid;
196538414Smckusick 	biodone(bp);
196638414Smckusick 	return (error);
196738414Smckusick }
196838884Smacklem 
196938884Smacklem /*
197048054Smckusick  * Mmap a file
197148054Smckusick  *
197248054Smckusick  * NB Currently unsupported.
197348054Smckusick  */
197448054Smckusick /* ARGSUSED */
197552234Sheideman int
197653806Smckusick nfs_mmap(ap)
197753554Sheideman 	struct vop_mmap_args *ap;
197848054Smckusick {
197948054Smckusick 
198048054Smckusick 	return (EINVAL);
198148054Smckusick }
198248054Smckusick 
198348054Smckusick /*
198438884Smacklem  * Flush all the blocks associated with a vnode.
198538884Smacklem  * 	Walk through the buffer pool and push any dirty pages
198638884Smacklem  *	associated with the vnode.
198738884Smacklem  */
198839488Smckusick /* ARGSUSED */
198952234Sheideman int
199053806Smckusick nfs_fsync(ap)
199153554Sheideman 	struct vop_fsync_args *ap;
199238884Smacklem {
199353600Sheideman 	register struct nfsnode *np = VTONFS(ap->a_vp);
199439751Smckusick 	int error = 0;
199538884Smacklem 
199638884Smacklem 	if (np->n_flag & NMODIFIED) {
199738884Smacklem 		np->n_flag &= ~NMODIFIED;
199853600Sheideman 		vflushbuf(ap->a_vp, ap->a_waitfor == MNT_WAIT ? B_SYNC : 0);
199938884Smacklem 	}
200053629Smckusick 	if (np->n_flag & NWRITEERR) {
200139751Smckusick 		error = np->n_error;
200253629Smckusick 		np->n_flag &= ~NWRITEERR;
200353629Smckusick 	}
200438884Smacklem 	return (error);
200538884Smacklem }
200639672Smckusick 
200739672Smckusick /*
200846201Smckusick  * NFS advisory byte-level locks.
200946201Smckusick  * Currently unsupported.
201046201Smckusick  */
201152234Sheideman int
201253806Smckusick nfs_advlock(ap)
201353554Sheideman 	struct vop_advlock_args *ap;
201446201Smckusick {
201546201Smckusick 
201646201Smckusick 	return (EOPNOTSUPP);
201746201Smckusick }
201846201Smckusick 
201946201Smckusick /*
202039672Smckusick  * Print out the contents of an nfsnode.
202139672Smckusick  */
202252234Sheideman int
202353806Smckusick nfs_print(ap)
202453554Sheideman 	struct vop_print_args *ap;
202539672Smckusick {
202653806Smckusick 	register struct vnode *vp = ap->a_vp;
202753806Smckusick 	register struct nfsnode *np = VTONFS(vp);
202839672Smckusick 
202940294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
203040294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
203140294Smckusick #ifdef FIFO
203253806Smckusick 	if (vp->v_type == VFIFO)
203353806Smckusick 		fifo_printinfo(vp);
203440294Smckusick #endif /* FIFO */
203539914Smckusick 	printf("\n");
203639672Smckusick }
203751573Smckusick 
203851573Smckusick /*
203951573Smckusick  * NFS directory offset lookup.
204051573Smckusick  * Currently unsupported.
204151573Smckusick  */
204252234Sheideman int
204353806Smckusick nfs_blkatoff(ap)
204453554Sheideman 	struct vop_blkatoff_args *ap;
204551573Smckusick {
204651573Smckusick 
204751573Smckusick 	return (EOPNOTSUPP);
204851573Smckusick }
204951573Smckusick 
205051573Smckusick /*
205151573Smckusick  * NFS flat namespace lookup.
205251573Smckusick  * Currently unsupported.
205351573Smckusick  */
205452234Sheideman int
205553806Smckusick nfs_vget(ap)
205653554Sheideman 	struct vop_vget_args *ap;
205751573Smckusick {
205851573Smckusick 
205951573Smckusick 	return (EOPNOTSUPP);
206051573Smckusick }
206151573Smckusick 
206251573Smckusick /*
206351573Smckusick  * NFS flat namespace allocation.
206451573Smckusick  * Currently unsupported.
206551573Smckusick  */
206652234Sheideman int
206753806Smckusick nfs_valloc(ap)
206853554Sheideman 	struct vop_valloc_args *ap;
206951573Smckusick {
207051573Smckusick 
207151573Smckusick 	return (EOPNOTSUPP);
207251573Smckusick }
207351573Smckusick 
207451573Smckusick /*
207551573Smckusick  * NFS flat namespace free.
207651573Smckusick  * Currently unsupported.
207751573Smckusick  */
207853582Sheideman int
207953806Smckusick nfs_vfree(ap)
208053554Sheideman 	struct vop_vfree_args *ap;
208151573Smckusick {
208251573Smckusick 
208353582Sheideman 	return (EOPNOTSUPP);
208451573Smckusick }
208551573Smckusick 
208651573Smckusick /*
208751573Smckusick  * NFS file truncation.
208851573Smckusick  */
208952234Sheideman int
209053806Smckusick nfs_truncate(ap)
209153554Sheideman 	struct vop_truncate_args *ap;
209251573Smckusick {
209351573Smckusick 
209451573Smckusick 	/* Use nfs_setattr */
209551573Smckusick 	printf("nfs_truncate: need to implement!!");
209651573Smckusick 	return (EOPNOTSUPP);
209751573Smckusick }
209851573Smckusick 
209951573Smckusick /*
210051573Smckusick  * NFS update.
210151573Smckusick  */
210252234Sheideman int
210353806Smckusick nfs_update(ap)
210453554Sheideman 	struct vop_update_args *ap;
210551573Smckusick {
210651573Smckusick 
210751573Smckusick 	/* Use nfs_setattr */
210851573Smckusick 	printf("nfs_update: need to implement!!");
210951573Smckusick 	return (EOPNOTSUPP);
211051573Smckusick }
211153629Smckusick 
211253629Smckusick /*
211353629Smckusick  * Read wrapper for special devices.
211453629Smckusick  */
211553629Smckusick int
211653629Smckusick nfsspec_read(ap)
211753629Smckusick 	struct vop_read_args *ap;
211853629Smckusick {
211953629Smckusick 	extern int (**spec_vnodeop_p)();
2120*54032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
212153629Smckusick 
212253629Smckusick 	/*
212353629Smckusick 	 * Set access flag.
212453629Smckusick 	 */
2125*54032Smckusick 	np->n_flag |= NACC;
2126*54032Smckusick 	np->n_atim = time;
212753629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
212853629Smckusick }
212953629Smckusick 
213053629Smckusick /*
213153629Smckusick  * Write wrapper for special devices.
213253629Smckusick  */
213353629Smckusick int
213453629Smckusick nfsspec_write(ap)
213553629Smckusick 	struct vop_write_args *ap;
213653629Smckusick {
213753629Smckusick 	extern int (**spec_vnodeop_p)();
2138*54032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
213953629Smckusick 
214053629Smckusick 	/*
2141*54032Smckusick 	 * Set update flag.
214253629Smckusick 	 */
2143*54032Smckusick 	np->n_flag |= NUPD;
2144*54032Smckusick 	np->n_mtim = time;
214553629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
214653629Smckusick }
214753629Smckusick 
214853629Smckusick /*
214953629Smckusick  * Close wrapper for special devices.
215053629Smckusick  *
215153629Smckusick  * Update the times on the nfsnode then do device close.
215253629Smckusick  */
215353629Smckusick int
215453629Smckusick nfsspec_close(ap)
215553629Smckusick 	struct vop_close_args *ap;
215653629Smckusick {
215753629Smckusick 	USES_VOP_SETATTR;
215853806Smckusick 	register struct vnode *vp = ap->a_vp;
215953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
216053629Smckusick 	struct vattr vattr;
216153629Smckusick 	extern int (**spec_vnodeop_p)();
216253629Smckusick 
216353629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
216453629Smckusick 		if (np->n_flag & NACC)
216553629Smckusick 			np->n_atim = time;
216653629Smckusick 		if (np->n_flag & NUPD)
216753629Smckusick 			np->n_mtim = time;
216853629Smckusick 		np->n_flag |= NCHG;
216953806Smckusick 		if (vp->v_usecount == 1 &&
217053806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
217153629Smckusick 			VATTR_NULL(&vattr);
217253629Smckusick 			if (np->n_flag & NACC)
217353629Smckusick 				vattr.va_atime = np->n_atim;
217453629Smckusick 			if (np->n_flag & NUPD)
217553629Smckusick 				vattr.va_mtime = np->n_mtim;
217653806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
217753629Smckusick 		}
217853629Smckusick 	}
217953629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
218053629Smckusick }
218153629Smckusick 
218253629Smckusick #ifdef FIFO
218353629Smckusick /*
218453629Smckusick  * Read wrapper for fifos.
218553629Smckusick  */
218653629Smckusick int
218753629Smckusick nfsfifo_read(ap)
218853629Smckusick 	struct vop_read_args *ap;
218953629Smckusick {
219053629Smckusick 	extern int (**fifo_vnodeop_p)();
2191*54032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
219253629Smckusick 
219353629Smckusick 	/*
219453629Smckusick 	 * Set access flag.
219553629Smckusick 	 */
2196*54032Smckusick 	np->n_flag |= NACC;
2197*54032Smckusick 	np->n_atim = time;
219853629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
219953629Smckusick }
220053629Smckusick 
220153629Smckusick /*
220253629Smckusick  * Write wrapper for fifos.
220353629Smckusick  */
220453629Smckusick int
220553629Smckusick nfsfifo_write(ap)
220653629Smckusick 	struct vop_write_args *ap;
220753629Smckusick {
220853629Smckusick 	extern int (**fifo_vnodeop_p)();
2209*54032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
221053629Smckusick 
221153629Smckusick 	/*
221253629Smckusick 	 * Set update flag.
221353629Smckusick 	 */
2214*54032Smckusick 	np->n_flag |= NUPD;
2215*54032Smckusick 	np->n_mtim = time;
221653629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
221753629Smckusick }
221853629Smckusick 
221953629Smckusick /*
222053629Smckusick  * Close wrapper for fifos.
222153629Smckusick  *
222253629Smckusick  * Update the times on the nfsnode then do fifo close.
222353629Smckusick  */
222453629Smckusick int
222553629Smckusick nfsfifo_close(ap)
222653629Smckusick 	struct vop_close_args *ap;
222753629Smckusick {
222853629Smckusick 	USES_VOP_SETATTR;
222953806Smckusick 	register struct vnode *vp = ap->a_vp;
223053806Smckusick 	register struct nfsnode *np = VTONFS(vp);
223153629Smckusick 	struct vattr vattr;
223253629Smckusick 	extern int (**fifo_vnodeop_p)();
223353629Smckusick 
223453629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
223553629Smckusick 		if (np->n_flag & NACC)
223653629Smckusick 			np->n_atim = time;
223753629Smckusick 		if (np->n_flag & NUPD)
223853629Smckusick 			np->n_mtim = time;
223953629Smckusick 		np->n_flag |= NCHG;
224053806Smckusick 		if (vp->v_usecount == 1 &&
224153806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
224253629Smckusick 			VATTR_NULL(&vattr);
224353629Smckusick 			if (np->n_flag & NACC)
224453629Smckusick 				vattr.va_atime = np->n_atim;
224553629Smckusick 			if (np->n_flag & NUPD)
224653629Smckusick 				vattr.va_mtime = np->n_mtim;
224753806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
224853629Smckusick 		}
224953629Smckusick 	}
225053629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
225153629Smckusick }
225253629Smckusick #endif /* FIFO */
2253