xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 54986)
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*54986Smckusick  *	@(#)nfs_vnops.c	7.87 (Berkeley) 07/12/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>
3154740Smckusick #include <sys/dirent.h>
3247573Skarels 
3353322Smckusick #include <vm/vm.h>
3438414Smckusick 
3553322Smckusick #include <nfs/rpcv2.h>
3653322Smckusick #include <nfs/nfsv2.h>
3753322Smckusick #include <nfs/nfs.h>
3853322Smckusick #include <nfs/nfsnode.h>
3953322Smckusick #include <nfs/nfsmount.h>
4053322Smckusick #include <nfs/xdr_subs.h>
4153322Smckusick #include <nfs/nfsm_subs.h>
4253322Smckusick #include <nfs/nqnfs.h>
4353322Smckusick 
4438414Smckusick /* Defs */
4538414Smckusick #define	TRUE	1
4638414Smckusick #define	FALSE	0
4738414Smckusick 
4848054Smckusick /*
4948054Smckusick  * Global vfs data structures for nfs
5048054Smckusick  */
5153554Sheideman int (**nfsv2_vnodeop_p)();
5253554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
5353554Sheideman 	{ &vop_default_desc, vn_default_error },
5453806Smckusick 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
5553806Smckusick 	{ &vop_create_desc, nfs_create },	/* create */
5653554Sheideman 	{ &vop_mknod_desc, nfs_mknod },		/* mknod */
5753554Sheideman 	{ &vop_open_desc, nfs_open },		/* open */
5853554Sheideman 	{ &vop_close_desc, nfs_close },		/* close */
5953806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
6053806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
6153806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
6253554Sheideman 	{ &vop_read_desc, nfs_read },		/* read */
6353554Sheideman 	{ &vop_write_desc, nfs_write },		/* write */
6453554Sheideman 	{ &vop_ioctl_desc, nfs_ioctl },		/* ioctl */
6553806Smckusick 	{ &vop_select_desc, nfs_select },	/* select */
6653554Sheideman 	{ &vop_mmap_desc, nfs_mmap },		/* mmap */
6753554Sheideman 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
6853554Sheideman 	{ &vop_seek_desc, nfs_seek },		/* seek */
6953806Smckusick 	{ &vop_remove_desc, nfs_remove },	/* remove */
7053554Sheideman 	{ &vop_link_desc, nfs_link },		/* link */
7153806Smckusick 	{ &vop_rename_desc, nfs_rename },	/* rename */
7253554Sheideman 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
7353554Sheideman 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
7453806Smckusick 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
7553806Smckusick 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
7653806Smckusick 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
7753806Smckusick 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
7853806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
7953806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
8053554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
8153806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
8253554Sheideman 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
8353806Smckusick 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
8453554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
8553806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
8653806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
8753806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
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 */
11754451Smckusick 	{ &vop_fsync_desc, nfs_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 */
13853806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
13953806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
14053806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
14153806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
14253582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
14353554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
14438414Smckusick };
14553554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
14653554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
14738414Smckusick 
14840294Smckusick #ifdef FIFO
14953554Sheideman int (**fifo_nfsv2nodeop_p)();
15053554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
15153554Sheideman 	{ &vop_default_desc, vn_default_error },
15253806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
15353806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
15453806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
15553554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
15653806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
15753806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
15853806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
15953806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
16053806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
16153806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
16253806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
16353806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
16453554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
16554451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
16653554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
16753806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
16853554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
16953806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
17053806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
17153806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
17253806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
17353806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
17453806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
17553806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
17653806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
17753806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
17853554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
17953806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
18053554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
18153806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
18253554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
18353806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
18453806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
18553806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
18653806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
18753806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
18853806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
18953806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
19053582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
19153554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
19240294Smckusick };
19353554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
19453554Sheideman 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
19540294Smckusick #endif /* FIFO */
19640294Smckusick 
19748054Smckusick /*
19852196Smckusick  * Global variables
19948054Smckusick  */
20038414Smckusick extern u_long nfs_procids[NFS_NPROCS];
20138414Smckusick extern u_long nfs_prog, nfs_vers;
20238414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
20338884Smacklem struct buf nfs_bqueue;		/* Queue head for nfsiod's */
20441905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
20546988Smckusick int nfs_numasync = 0;
20654740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
20738414Smckusick 
20838414Smckusick /*
20938414Smckusick  * nfs null call from vfs.
21038414Smckusick  */
21152234Sheideman int
21252196Smckusick nfs_null(vp, cred, procp)
21338414Smckusick 	struct vnode *vp;
21438414Smckusick 	struct ucred *cred;
21552196Smckusick 	struct proc *procp;
21638414Smckusick {
21739488Smckusick 	caddr_t bpos, dpos;
21839488Smckusick 	int error = 0;
21939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22038414Smckusick 
22152196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22252196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
22338414Smckusick 	nfsm_reqdone;
22438414Smckusick 	return (error);
22538414Smckusick }
22638414Smckusick 
22738414Smckusick /*
22838414Smckusick  * nfs access vnode op.
22938414Smckusick  * Essentially just get vattr and then imitate iaccess()
23038414Smckusick  */
23152234Sheideman int
23253806Smckusick nfs_access(ap)
23354668Smckusick 	struct vop_access_args /* {
23454668Smckusick 		struct vnode *a_vp;
23554668Smckusick 		int  a_mode;
23654668Smckusick 		struct ucred *a_cred;
23754668Smckusick 		struct proc *a_p;
23854668Smckusick 	} */ *ap;
23938414Smckusick {
24038414Smckusick 	register struct vattr *vap;
24138414Smckusick 	register gid_t *gp;
24253806Smckusick 	register struct ucred *cred = ap->a_cred;
24353806Smckusick 	mode_t mode = ap->a_mode;
24438414Smckusick 	struct vattr vattr;
24538414Smckusick 	register int i;
24638414Smckusick 	int error;
24738414Smckusick 
24838414Smckusick 	/*
24938414Smckusick 	 * If you're the super-user,
25038414Smckusick 	 * you always get access.
25138414Smckusick 	 */
25253806Smckusick 	if (cred->cr_uid == 0)
25338414Smckusick 		return (0);
25438414Smckusick 	vap = &vattr;
25553806Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
25638884Smacklem 		return (error);
25738414Smckusick 	/*
25838414Smckusick 	 * Access check is based on only one of owner, group, public.
25938414Smckusick 	 * If not owner, then check group. If not a member of the
26038414Smckusick 	 * group, then check public access.
26138414Smckusick 	 */
26253806Smckusick 	if (cred->cr_uid != vap->va_uid) {
26353806Smckusick 		mode >>= 3;
26453806Smckusick 		gp = cred->cr_groups;
26553806Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
26638414Smckusick 			if (vap->va_gid == *gp)
26738414Smckusick 				goto found;
26853806Smckusick 		mode >>= 3;
26938414Smckusick found:
27038414Smckusick 		;
27138414Smckusick 	}
27253806Smckusick 	if ((vap->va_mode & mode) != 0)
27338414Smckusick 		return (0);
27438414Smckusick 	return (EACCES);
27538414Smckusick }
27638414Smckusick 
27738414Smckusick /*
27838414Smckusick  * nfs open vnode op
27938414Smckusick  * Just check to see if the type is ok
28052196Smckusick  * and that deletion is not in progress.
28138414Smckusick  */
28239488Smckusick /* ARGSUSED */
28352234Sheideman int
28453806Smckusick nfs_open(ap)
28554668Smckusick 	struct vop_open_args /* {
28654668Smckusick 		struct vnode *a_vp;
28754668Smckusick 		int  a_mode;
28854668Smckusick 		struct ucred *a_cred;
28954668Smckusick 		struct proc *a_p;
29054668Smckusick 	} */ *ap;
29138414Smckusick {
29253806Smckusick 	register struct vnode *vp = ap->a_vp;
29338414Smckusick 
29453806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
29538414Smckusick 		return (EACCES);
29653806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
29753806Smckusick 		VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */
29852196Smckusick 	return (0);
29938414Smckusick }
30038414Smckusick 
30138414Smckusick /*
30238414Smckusick  * nfs close vnode op
30338884Smacklem  * For reg files, invalidate any buffer cache entries.
30438414Smckusick  */
30539488Smckusick /* ARGSUSED */
30652234Sheideman int
30753806Smckusick nfs_close(ap)
30854451Smckusick 	struct vop_close_args /* {
30954451Smckusick 		struct vnodeop_desc *a_desc;
31054451Smckusick 		struct vnode *a_vp;
31154451Smckusick 		int  a_fflag;
31254451Smckusick 		struct ucred *a_cred;
31354451Smckusick 		struct proc *a_p;
31454451Smckusick 	} */ *ap;
31538414Smckusick {
31653806Smckusick 	register struct vnode *vp = ap->a_vp;
31753806Smckusick 	register struct nfsnode *np = VTONFS(vp);
31839341Smckusick 	int error = 0;
31938414Smckusick 
32053806Smckusick 	if (vp->v_type == VREG) {
32153806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
32253629Smckusick 		(np->n_flag & NMODIFIED)) {
32354451Smckusick 		error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32441905Smckusick 		np->n_flag &= ~NMODIFIED;
32541905Smckusick 		np->n_attrstamp = 0;
32653629Smckusick 	    }
32753629Smckusick 	    if (np->n_flag & NWRITEERR) {
32853629Smckusick 		np->n_flag &= ~NWRITEERR;
32953629Smckusick 		error = np->n_error;
33053629Smckusick 	    }
33138884Smacklem 	}
33238414Smckusick 	return (error);
33338414Smckusick }
33438414Smckusick 
33538414Smckusick /*
33638414Smckusick  * nfs getattr call from vfs.
33738414Smckusick  */
33852234Sheideman int
33953805Smckusick nfs_getattr(ap)
34054668Smckusick 	struct vop_getattr_args /* {
34154668Smckusick 		struct vnode *a_vp;
34254668Smckusick 		struct vattr *a_vap;
34354668Smckusick 		struct ucred *a_cred;
34454668Smckusick 		struct proc *a_p;
34554668Smckusick 	} */ *ap;
34638414Smckusick {
34753805Smckusick 	register struct vnode *vp = ap->a_vp;
34853805Smckusick 	register struct nfsnode *np = VTONFS(vp);
34939488Smckusick 	register caddr_t cp;
35039488Smckusick 	caddr_t bpos, dpos;
35139488Smckusick 	int error = 0;
35239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
35338414Smckusick 
35453805Smckusick 	/*
35553805Smckusick 	 * Update local times for special files.
35653805Smckusick 	 */
35753805Smckusick 	if (np->n_flag & (NACC | NUPD)) {
35853805Smckusick 		if (np->n_flag & NACC)
35953805Smckusick 			np->n_atim = time;
36053805Smckusick 		if (np->n_flag & NUPD)
36153805Smckusick 			np->n_mtim = time;
36253805Smckusick 		np->n_flag |= NCHG;
36353805Smckusick 	}
36453805Smckusick 	/*
36553805Smckusick 	 * First look in the cache.
36653805Smckusick 	 */
36753805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
36838414Smckusick 		return (0);
36938414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
37053805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
37153805Smckusick 	nfsm_fhtom(vp);
37253805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
37353805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
37438414Smckusick 	nfsm_reqdone;
37538414Smckusick 	return (error);
37638414Smckusick }
37738414Smckusick 
37838414Smckusick /*
37938414Smckusick  * nfs setattr call.
38038414Smckusick  */
38152234Sheideman int
38253806Smckusick nfs_setattr(ap)
38354451Smckusick 	struct vop_setattr_args /* {
38454451Smckusick 		struct vnodeop_desc *a_desc;
38554451Smckusick 		struct vnode *a_vp;
38654451Smckusick 		struct vattr *a_vap;
38754451Smckusick 		struct ucred *a_cred;
38854451Smckusick 		struct proc *a_p;
38954451Smckusick 	} */ *ap;
39038414Smckusick {
39138884Smacklem 	register struct nfsv2_sattr *sp;
39239488Smckusick 	register caddr_t cp;
39339488Smckusick 	register long t1;
39452196Smckusick 	caddr_t bpos, dpos, cp2;
39552196Smckusick 	u_long *tl;
39639488Smckusick 	int error = 0;
39739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
39853806Smckusick 	register struct vnode *vp = ap->a_vp;
39953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
40053806Smckusick 	register struct vattr *vap = ap->a_vap;
40152196Smckusick 	u_quad_t frev;
40238414Smckusick 
40338414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
40453806Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR);
40553806Smckusick 	nfsm_fhtom(vp);
40638884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
40753806Smckusick 	if (vap->va_mode == 0xffff)
40838884Smacklem 		sp->sa_mode = VNOVAL;
40938414Smckusick 	else
41053806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
41153806Smckusick 	if (vap->va_uid == 0xffff)
41238884Smacklem 		sp->sa_uid = VNOVAL;
41338414Smckusick 	else
41453806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
41553806Smckusick 	if (vap->va_gid == 0xffff)
41638884Smacklem 		sp->sa_gid = VNOVAL;
41738414Smckusick 	else
41853806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
41953806Smckusick 	sp->sa_size = txdr_unsigned(vap->va_size);
42054106Smckusick 	sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.ts_sec);
42153806Smckusick 	sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
42253806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
42354106Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
42454106Smckusick 	    vap->va_atime.ts_sec != VNOVAL) {
42539359Smckusick 		if (np->n_flag & NMODIFIED) {
42653806Smckusick 			if (vap->va_size == 0)
42754451Smckusick 				error =
42854451Smckusick 				    vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p);
42946988Smckusick 			else
43054451Smckusick 				error =
43154451Smckusick 				    vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
43254451Smckusick 			np->n_flag &= ~NMODIFIED;
43339359Smckusick 		}
43439359Smckusick 	}
43553806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
43653806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
43753806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
43853806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
43952196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
44052196Smckusick 		fxdr_hyper(tl, &frev);
44154451Smckusick 		if (frev > np->n_brev)
44252196Smckusick 			np->n_brev = frev;
44352196Smckusick 	}
44438414Smckusick 	nfsm_reqdone;
44538414Smckusick 	return (error);
44638414Smckusick }
44738414Smckusick 
44838414Smckusick /*
44938414Smckusick  * nfs lookup call, one step at a time...
45038414Smckusick  * First look in cache
45138414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
45238414Smckusick  */
45352234Sheideman int
45453806Smckusick nfs_lookup(ap)
45554451Smckusick 	struct vop_lookup_args /* {
45654451Smckusick 		struct vnodeop_desc *a_desc;
45754451Smckusick 		struct vnode *a_dvp;
45854451Smckusick 		struct vnode **a_vpp;
45954451Smckusick 		struct componentname *a_cnp;
46054451Smckusick 	} */ *ap;
46138414Smckusick {
46253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
46353806Smckusick 	register struct vnode *dvp = ap->a_dvp;
46454668Smckusick 	register struct vnode **vpp = ap->a_vpp;
46538414Smckusick 	register struct vnode *vdp;
46648054Smckusick 	register u_long *tl;
46739488Smckusick 	register caddr_t cp;
46839488Smckusick 	register long t1, t2;
46952196Smckusick 	struct nfsmount *nmp;
47052196Smckusick 	struct nfsnode *tp;
47139488Smckusick 	caddr_t bpos, dpos, cp2;
47252196Smckusick 	time_t reqtime;
47339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
47438414Smckusick 	struct vnode *newvp;
47538414Smckusick 	long len;
47638414Smckusick 	nfsv2fh_t *fhp;
47738414Smckusick 	struct nfsnode *np;
47852234Sheideman 	int lockparent, wantparent, error = 0;
47952196Smckusick 	int nqlflag, cachable;
48052196Smckusick 	u_quad_t frev;
48138414Smckusick 
48254668Smckusick 	*vpp = NULL;
48353806Smckusick 	if (dvp->v_type != VDIR)
48438414Smckusick 		return (ENOTDIR);
48553806Smckusick 	lockparent = cnp->cn_flags & LOCKPARENT;
48653806Smckusick 	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
48753806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
48853806Smckusick 	np = VTONFS(dvp);
48954668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
49038884Smacklem 		struct vattr vattr;
49138884Smacklem 		int vpid;
49238884Smacklem 
49354668Smckusick 		vdp = *vpp;
49438884Smacklem 		vpid = vdp->v_id;
49538414Smckusick 		/*
49638884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
49738884Smacklem 		 * for an explanation of the locking protocol
49838414Smckusick 		 */
49953806Smckusick 		if (dvp == vdp) {
50038425Smckusick 			VREF(vdp);
50139441Smckusick 			error = 0;
50252196Smckusick 		} else
50339441Smckusick 			error = vget(vdp);
50439441Smckusick 		if (!error) {
50540251Smckusick 			if (vpid == vdp->v_id) {
50652196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
50753806Smckusick 			        if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
50854451Smckusick 					if (np->n_lrev != np->n_brev ||
50952196Smckusick 					    (np->n_flag & NMODIFIED)) {
51052196Smckusick 						np->n_direofoffset = 0;
51153806Smckusick 						cache_purge(dvp);
51254451Smckusick 						error = vinvalbuf(dvp, FALSE,
51354451Smckusick 						    cnp->cn_cred, cnp->cn_proc);
51452196Smckusick 						np->n_flag &= ~NMODIFIED;
51552196Smckusick 						np->n_brev = np->n_lrev;
51652196Smckusick 					} else {
51752196Smckusick 						nfsstats.lookupcache_hits++;
51853806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
51953806Smckusick 						    (cnp->cn_flags&ISLASTCN))
52053806Smckusick 						    cnp->cn_flags |= SAVENAME;
52152196Smckusick 						return (0);
52252196Smckusick 					}
52352196Smckusick 				}
52453806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
52554106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
52639441Smckusick 				nfsstats.lookupcache_hits++;
52753806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
52853806Smckusick 				    (cnp->cn_flags&ISLASTCN))
52953806Smckusick 					cnp->cn_flags |= SAVENAME;
53039441Smckusick 				return (0);
53140251Smckusick 			   }
53247289Smckusick 			   cache_purge(vdp);
53339441Smckusick 			}
53452196Smckusick 			vrele(vdp);
53538884Smacklem 		}
53654668Smckusick 		*vpp = NULLVP;
53752196Smckusick 	}
53839341Smckusick 	error = 0;
53938414Smckusick 	nfsstats.lookupcache_misses++;
54038414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
54153806Smckusick 	len = cnp->cn_namelen;
54253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
54352196Smckusick 
54452196Smckusick 	/*
54552196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
54652196Smckusick 	 * being looked up.
54752196Smckusick 	 */
54852196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
54952196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
55053806Smckusick 		    ((cnp->cn_flags&MAKEENTRY) &&
55153806Smckusick 		    (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN)))) {
55252196Smckusick 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
55352196Smckusick 			*tl++ = txdr_unsigned(NQL_READ);
55452196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
55552196Smckusick 		} else {
55652196Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
55752196Smckusick 			*tl = 0;
55852196Smckusick 		}
55952196Smckusick 	}
56053806Smckusick 	nfsm_fhtom(dvp);
56153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
56252196Smckusick 	reqtime = time.tv_sec;
56353806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
56438414Smckusick nfsmout:
56538414Smckusick 	if (error) {
56653806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
56753806Smckusick 		    (cnp->cn_flags & ISLASTCN) && error == ENOENT)
56852823Smckusick 			error = EJUSTRETURN;
56953806Smckusick 		if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
57053806Smckusick 			cnp->cn_flags |= SAVENAME;
57140483Smckusick 		return (error);
57238414Smckusick 	}
57352196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
57452196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
57552196Smckusick 		if (*tl) {
57652196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
57752196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
57852196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
57952196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
58052196Smckusick 			fxdr_hyper(tl, &frev);
58152196Smckusick 		} else
58252196Smckusick 			nqlflag = 0;
58352196Smckusick 	}
58452196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
58538414Smckusick 
58638414Smckusick 	/*
58752196Smckusick 	 * Handle RENAME case...
58838414Smckusick 	 */
58953806Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (cnp->cn_flags&ISLASTCN)) {
59052196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
59138414Smckusick 			m_freem(mrep);
59238414Smckusick 			return (EISDIR);
59338414Smckusick 		}
59453806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
59538414Smckusick 			m_freem(mrep);
59638414Smckusick 			return (error);
59738414Smckusick 		}
59838414Smckusick 		newvp = NFSTOV(np);
59939459Smckusick 		if (error =
60039459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
60152196Smckusick 			vrele(newvp);
60238414Smckusick 			m_freem(mrep);
60338414Smckusick 			return (error);
60438414Smckusick 		}
60554668Smckusick 		*vpp = newvp;
60645037Smckusick 		m_freem(mrep);
60753806Smckusick 		cnp->cn_flags |= SAVENAME;
60838414Smckusick 		return (0);
60938414Smckusick 	}
61038414Smckusick 
61152196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
61253806Smckusick 		VREF(dvp);
61353806Smckusick 		newvp = dvp;
61438414Smckusick 	} else {
61553806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
61638414Smckusick 			m_freem(mrep);
61738414Smckusick 			return (error);
61838414Smckusick 		}
61938414Smckusick 		newvp = NFSTOV(np);
62038414Smckusick 	}
62139459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
62252196Smckusick 		vrele(newvp);
62338414Smckusick 		m_freem(mrep);
62438414Smckusick 		return (error);
62538414Smckusick 	}
62638414Smckusick 	m_freem(mrep);
62754668Smckusick 	*vpp = newvp;
62853806Smckusick 	if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
62953806Smckusick 		cnp->cn_flags |= SAVENAME;
63053806Smckusick 	if ((cnp->cn_flags&MAKEENTRY) &&
63153806Smckusick 	    (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN))) {
63252196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
63354106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
63452196Smckusick 		else if (nqlflag && reqtime > time.tv_sec) {
63552196Smckusick 			if (np->n_tnext) {
63652196Smckusick 				if (np->n_tnext == (struct nfsnode *)nmp)
63752196Smckusick 					nmp->nm_tprev = np->n_tprev;
63852196Smckusick 				else
63952196Smckusick 					np->n_tnext->n_tprev = np->n_tprev;
64052196Smckusick 				if (np->n_tprev == (struct nfsnode *)nmp)
64152196Smckusick 					nmp->nm_tnext = np->n_tnext;
64252196Smckusick 				else
64352196Smckusick 					np->n_tprev->n_tnext = np->n_tnext;
64452196Smckusick 				if (nqlflag == NQL_WRITE)
64552196Smckusick 					np->n_flag |= NQNFSWRITE;
64652196Smckusick 			} else if (nqlflag == NQL_READ)
64752196Smckusick 				np->n_flag &= ~NQNFSWRITE;
64852196Smckusick 			else
64952196Smckusick 				np->n_flag |= NQNFSWRITE;
65052196Smckusick 			if (cachable)
65152196Smckusick 				np->n_flag &= ~NQNFSNONCACHE;
65252196Smckusick 			else
65352196Smckusick 				np->n_flag |= NQNFSNONCACHE;
65452196Smckusick 			np->n_expiry = reqtime;
65552196Smckusick 			np->n_lrev = frev;
65652196Smckusick 			tp = nmp->nm_tprev;
65752196Smckusick 			while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
65852196Smckusick 				tp = tp->n_tprev;
65952196Smckusick 			if (tp == (struct nfsnode *)nmp) {
66052196Smckusick 				np->n_tnext = nmp->nm_tnext;
66152196Smckusick 				nmp->nm_tnext = np;
66252196Smckusick 			} else {
66352196Smckusick 				np->n_tnext = tp->n_tnext;
66452196Smckusick 				tp->n_tnext = np;
66552196Smckusick 			}
66652196Smckusick 			np->n_tprev = tp;
66752196Smckusick 			if (np->n_tnext == (struct nfsnode *)nmp)
66852196Smckusick 				nmp->nm_tprev = np;
66952196Smckusick 			else
67052196Smckusick 				np->n_tnext->n_tprev = np;
67152196Smckusick 		}
67254668Smckusick 		cache_enter(dvp, *vpp, cnp);
67340251Smckusick 	}
67452196Smckusick 	return (0);
67538414Smckusick }
67638414Smckusick 
67738414Smckusick /*
67841905Smckusick  * nfs read call.
67941905Smckusick  * Just call nfs_bioread() to do the work.
68041905Smckusick  */
68152234Sheideman int
68253806Smckusick nfs_read(ap)
68354668Smckusick 	struct vop_read_args /* {
68454668Smckusick 		struct vnode *a_vp;
68554668Smckusick 		struct uio *a_uio;
68654668Smckusick 		int  a_ioflag;
68754668Smckusick 		struct ucred *a_cred;
68854668Smckusick 	} */ *ap;
68941905Smckusick {
69053806Smckusick 	register struct vnode *vp = ap->a_vp;
69153806Smckusick 
69253806Smckusick 	if (vp->v_type != VREG)
69341905Smckusick 		return (EPERM);
69453806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
69541905Smckusick }
69641905Smckusick 
69741905Smckusick /*
69838414Smckusick  * nfs readlink call
69938414Smckusick  */
70052234Sheideman int
70153806Smckusick nfs_readlink(ap)
70254668Smckusick 	struct vop_readlink_args /* {
70354668Smckusick 		struct vnode *a_vp;
70454668Smckusick 		struct uio *a_uio;
70554668Smckusick 		struct ucred *a_cred;
70654668Smckusick 	} */ *ap;
70741905Smckusick {
70853806Smckusick 	register struct vnode *vp = ap->a_vp;
70953806Smckusick 
71053806Smckusick 	if (vp->v_type != VLNK)
71141905Smckusick 		return (EPERM);
71253806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
71341905Smckusick }
71441905Smckusick 
71541905Smckusick /*
71641905Smckusick  * Do a readlink rpc.
71741905Smckusick  * Called by nfs_doio() from below the buffer cache.
71841905Smckusick  */
71952234Sheideman int
72048054Smckusick nfs_readlinkrpc(vp, uiop, cred)
72139488Smckusick 	register struct vnode *vp;
72238414Smckusick 	struct uio *uiop;
72338414Smckusick 	struct ucred *cred;
72438414Smckusick {
72548054Smckusick 	register u_long *tl;
72639488Smckusick 	register caddr_t cp;
72739488Smckusick 	register long t1;
72839488Smckusick 	caddr_t bpos, dpos, cp2;
72939488Smckusick 	int error = 0;
73039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
73138414Smckusick 	long len;
73238414Smckusick 
73338414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
73452196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
73538414Smckusick 	nfsm_fhtom(vp);
73652196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
73738414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
73838414Smckusick 	nfsm_mtouio(uiop, len);
73938414Smckusick 	nfsm_reqdone;
74038414Smckusick 	return (error);
74138414Smckusick }
74238414Smckusick 
74338414Smckusick /*
74441905Smckusick  * nfs read rpc call
74541905Smckusick  * Ditto above
74638414Smckusick  */
74752234Sheideman int
74848054Smckusick nfs_readrpc(vp, uiop, cred)
74939488Smckusick 	register struct vnode *vp;
75038414Smckusick 	struct uio *uiop;
75138414Smckusick 	struct ucred *cred;
75238414Smckusick {
75348054Smckusick 	register u_long *tl;
75439488Smckusick 	register caddr_t cp;
75539488Smckusick 	register long t1;
75639488Smckusick 	caddr_t bpos, dpos, cp2;
75739488Smckusick 	int error = 0;
75839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
75938414Smckusick 	struct nfsmount *nmp;
76038414Smckusick 	long len, retlen, tsiz;
76138414Smckusick 
76241398Smckusick 	nmp = VFSTONFS(vp->v_mount);
76338414Smckusick 	tsiz = uiop->uio_resid;
76438414Smckusick 	while (tsiz > 0) {
76538414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
76638414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
76752196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
76838414Smckusick 		nfsm_fhtom(vp);
76948054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
77048054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
77148054Smckusick 		*tl++ = txdr_unsigned(len);
77248054Smckusick 		*tl = 0;
77352196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
77438414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
77538414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
77638414Smckusick 		nfsm_mtouio(uiop, retlen);
77738414Smckusick 		m_freem(mrep);
77838414Smckusick 		if (retlen < len)
77938414Smckusick 			tsiz = 0;
78038414Smckusick 		else
78138414Smckusick 			tsiz -= len;
78238414Smckusick 	}
78338414Smckusick nfsmout:
78438414Smckusick 	return (error);
78538414Smckusick }
78638414Smckusick 
78738414Smckusick /*
78838414Smckusick  * nfs write call
78938414Smckusick  */
79052234Sheideman int
79148054Smckusick nfs_writerpc(vp, uiop, cred)
79239488Smckusick 	register struct vnode *vp;
79338414Smckusick 	struct uio *uiop;
79438414Smckusick 	struct ucred *cred;
79538414Smckusick {
79648054Smckusick 	register u_long *tl;
79739488Smckusick 	register caddr_t cp;
79839488Smckusick 	register long t1;
79952196Smckusick 	caddr_t bpos, dpos, cp2;
80039488Smckusick 	int error = 0;
80139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
80238414Smckusick 	struct nfsmount *nmp;
80352196Smckusick 	struct nfsnode *np = VTONFS(vp);
80452196Smckusick 	u_quad_t frev;
80538414Smckusick 	long len, tsiz;
80638414Smckusick 
80741398Smckusick 	nmp = VFSTONFS(vp->v_mount);
80838414Smckusick 	tsiz = uiop->uio_resid;
80938414Smckusick 	while (tsiz > 0) {
81038414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
81138414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
81252196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
81352196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
81438414Smckusick 		nfsm_fhtom(vp);
81548054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
81648054Smckusick 		*(tl+1) = txdr_unsigned(uiop->uio_offset);
81748054Smckusick 		*(tl+3) = txdr_unsigned(len);
81838414Smckusick 		nfsm_uiotom(uiop, len);
81952196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
82038414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
82152196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
82254106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
82352196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
82452196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
82552196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
82652196Smckusick 			fxdr_hyper(tl, &frev);
82754451Smckusick 			if (frev > np->n_brev)
82852196Smckusick 				np->n_brev = frev;
82952196Smckusick 		}
83038414Smckusick 		m_freem(mrep);
83138414Smckusick 		tsiz -= len;
83238414Smckusick 	}
83338414Smckusick nfsmout:
83452196Smckusick 	if (error)
83552196Smckusick 		uiop->uio_resid = tsiz;
83638414Smckusick 	return (error);
83738414Smckusick }
83838414Smckusick 
83938414Smckusick /*
84039459Smckusick  * nfs mknod call
84142246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
84242246Smckusick  * set to specify the file type and the size field for rdev.
84339459Smckusick  */
84439459Smckusick /* ARGSUSED */
84552234Sheideman int
84653806Smckusick nfs_mknod(ap)
84754668Smckusick 	struct vop_mknod_args /* {
84854668Smckusick 		struct vnode *a_dvp;
84954668Smckusick 		struct vnode **a_vpp;
85054668Smckusick 		struct componentname *a_cnp;
85154668Smckusick 		struct vattr *a_vap;
85254668Smckusick 	} */ *ap;
85339459Smckusick {
85453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
85553806Smckusick 	register struct vattr *vap = ap->a_vap;
85653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
85742246Smckusick 	register struct nfsv2_sattr *sp;
85848054Smckusick 	register u_long *tl;
85942246Smckusick 	register caddr_t cp;
86052196Smckusick 	register long t2;
86142246Smckusick 	caddr_t bpos, dpos;
86242246Smckusick 	int error = 0;
86342246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
86442246Smckusick 	u_long rdev;
86539459Smckusick 
86653806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
86753806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
86842246Smckusick #ifdef FIFO
86953806Smckusick 	else if (vap->va_type == VFIFO)
87042246Smckusick 		rdev = 0xffffffff;
87142246Smckusick #endif /* FIFO */
87242246Smckusick 	else {
87353806Smckusick 		VOP_ABORTOP(dvp, cnp);
87453806Smckusick 		vput(dvp);
87542246Smckusick 		return (EOPNOTSUPP);
87642246Smckusick 	}
87742246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
87853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
87953806Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
88053806Smckusick 	nfsm_fhtom(dvp);
88153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
88242246Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
88353806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
88453806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
88553806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
88642246Smckusick 	sp->sa_size = rdev;
88742246Smckusick 	/* or should these be VNOVAL ?? */
88853806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
88953806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
89053806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
89142246Smckusick 	nfsm_reqdone;
89253806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
89353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
89453806Smckusick 	vrele(dvp);
89542246Smckusick 	return (error);
89639459Smckusick }
89739459Smckusick 
89839459Smckusick /*
89938414Smckusick  * nfs file create call
90038414Smckusick  */
90152234Sheideman int
90253806Smckusick nfs_create(ap)
90354668Smckusick 	struct vop_create_args /* {
90454668Smckusick 		struct vnode *a_dvp;
90554668Smckusick 		struct vnode **a_vpp;
90654668Smckusick 		struct componentname *a_cnp;
90754668Smckusick 		struct vattr *a_vap;
90854668Smckusick 	} */ *ap;
90938414Smckusick {
91053806Smckusick 	register struct vnode *dvp = ap->a_dvp;
91153806Smckusick 	register struct vattr *vap = ap->a_vap;
91253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
91338884Smacklem 	register struct nfsv2_sattr *sp;
91448054Smckusick 	register u_long *tl;
91539488Smckusick 	register caddr_t cp;
91639488Smckusick 	register long t1, t2;
91739488Smckusick 	caddr_t bpos, dpos, cp2;
91839488Smckusick 	int error = 0;
91939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
92038414Smckusick 
92138414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
92253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
92353806Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
92453806Smckusick 	nfsm_fhtom(dvp);
92553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
92638884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
92753806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
92853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
92953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
93038884Smacklem 	sp->sa_size = txdr_unsigned(0);
93138414Smckusick 	/* or should these be VNOVAL ?? */
93253806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
93353806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
93453806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
93553806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
93638414Smckusick 	nfsm_reqdone;
93753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
93853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
93953806Smckusick 	vrele(dvp);
94038414Smckusick 	return (error);
94138414Smckusick }
94238414Smckusick 
94338414Smckusick /*
94438414Smckusick  * nfs file remove call
94541905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
94641905Smckusick  * other processes using the vnode is renamed instead of removed and then
94739341Smckusick  * removed later on the last close.
94841905Smckusick  * - If v_usecount > 1
94939341Smckusick  *	  If a rename is not already in the works
95039341Smckusick  *	     call nfs_sillyrename() to set it up
95139341Smckusick  *     else
95239341Smckusick  *	  do the remove rpc
95338414Smckusick  */
95452234Sheideman int
95553806Smckusick nfs_remove(ap)
95654451Smckusick 	struct vop_remove_args /* {
95754451Smckusick 		struct vnodeop_desc *a_desc;
95854451Smckusick 		struct vnode * a_dvp;
95954451Smckusick 		struct vnode * a_vp;
96054451Smckusick 		struct componentname * a_cnp;
96154451Smckusick 	} */ *ap;
96238414Smckusick {
96353806Smckusick 	register struct vnode *vp = ap->a_vp;
96453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
96553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
96653806Smckusick 	register struct nfsnode *np = VTONFS(vp);
96748054Smckusick 	register u_long *tl;
96839488Smckusick 	register caddr_t cp;
96952196Smckusick 	register long t2;
97039488Smckusick 	caddr_t bpos, dpos;
97139488Smckusick 	int error = 0;
97239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97338414Smckusick 
97453806Smckusick 	if (vp->v_usecount > 1) {
97539341Smckusick 		if (!np->n_sillyrename)
97653806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
97739341Smckusick 	} else {
97852196Smckusick 		/*
97952196Smckusick 		 * Purge the name cache so that the chance of a lookup for
98052196Smckusick 		 * the name succeeding while the remove is in progress is
98152196Smckusick 		 * minimized. Without node locking it can still happen, such
98252196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
98352196Smckusick 		 * another host removes the file..
98452196Smckusick 		 */
98553806Smckusick 		cache_purge(vp);
98652196Smckusick 		/*
98752196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
98852196Smckusick 		 * unnecessary delayed writes.
98952196Smckusick 		 */
99054451Smckusick 		error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc);
99152196Smckusick 		/* Do the rpc */
99238414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
99353806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
99453806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
99553806Smckusick 		nfsm_fhtom(dvp);
99653806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
99753806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
99838414Smckusick 		nfsm_reqdone;
99953806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
100053806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
100139751Smckusick 		/*
100239751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
100339751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
100439751Smckusick 		 *   since the file was in fact removed
100539751Smckusick 		 *   Therefore, we cheat and return success.
100639751Smckusick 		 */
100739751Smckusick 		if (error == ENOENT)
100839751Smckusick 			error = 0;
100938414Smckusick 	}
101040042Smckusick 	np->n_attrstamp = 0;
101153806Smckusick 	vrele(dvp);
101253806Smckusick 	vrele(vp);
101338414Smckusick 	return (error);
101438414Smckusick }
101538414Smckusick 
101638414Smckusick /*
101738414Smckusick  * nfs file remove rpc called from nfs_inactive
101838414Smckusick  */
101952234Sheideman int
102054451Smckusick nfs_removeit(sp)
102148364Smckusick 	register struct sillyrename *sp;
102238414Smckusick {
102348054Smckusick 	register u_long *tl;
102439488Smckusick 	register caddr_t cp;
102552196Smckusick 	register long t2;
102639488Smckusick 	caddr_t bpos, dpos;
102739488Smckusick 	int error = 0;
102839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
102938414Smckusick 
103038414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
103152196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
103248364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
103348364Smckusick 	nfsm_fhtom(sp->s_dvp);
103448364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
103554451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
103638414Smckusick 	nfsm_reqdone;
103748364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
103838414Smckusick 	return (error);
103938414Smckusick }
104038414Smckusick 
104138414Smckusick /*
104238414Smckusick  * nfs file rename call
104338414Smckusick  */
104452234Sheideman int
104553806Smckusick nfs_rename(ap)
104654668Smckusick 	struct vop_rename_args  /* {
104754668Smckusick 		struct vnode *a_fdvp;
104854668Smckusick 		struct vnode *a_fvp;
104954668Smckusick 		struct componentname *a_fcnp;
105054668Smckusick 		struct vnode *a_tdvp;
105154668Smckusick 		struct vnode *a_tvp;
105254668Smckusick 		struct componentname *a_tcnp;
105354668Smckusick 	} */ *ap;
105438414Smckusick {
105553806Smckusick 	register struct vnode *fvp = ap->a_fvp;
105653806Smckusick 	register struct vnode *tvp = ap->a_tvp;
105753806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
105853806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
105953806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
106053806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
106148054Smckusick 	register u_long *tl;
106239488Smckusick 	register caddr_t cp;
106352196Smckusick 	register long t2;
106439488Smckusick 	caddr_t bpos, dpos;
106539488Smckusick 	int error = 0;
106639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
106738414Smckusick 
106853804Spendry 	/* Check for cross-device rename */
106953806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
107053806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
107153804Spendry 		error = EXDEV;
107253804Spendry 		goto out;
107353804Spendry 	}
107453804Spendry 
107553804Spendry 
107638414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
107753806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
107853806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
107953806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
108053806Smckusick 	nfsm_fhtom(fdvp);
108153806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
108253806Smckusick 	nfsm_fhtom(tdvp);
108353806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
108453806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
108538414Smckusick 	nfsm_reqdone;
108653806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
108753806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
108853806Smckusick 	if (fvp->v_type == VDIR) {
108953806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
109053806Smckusick 			cache_purge(tdvp);
109153806Smckusick 		cache_purge(fdvp);
109238414Smckusick 	}
109353804Spendry out:
109453806Smckusick 	if (tdvp == tvp)
109553806Smckusick 		vrele(tdvp);
109643360Smckusick 	else
109753806Smckusick 		vput(tdvp);
109853806Smckusick 	if (tvp)
109953806Smckusick 		vput(tvp);
110053806Smckusick 	vrele(fdvp);
110153806Smckusick 	vrele(fvp);
110240112Smckusick 	/*
110340112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
110440112Smckusick 	 */
110540112Smckusick 	if (error == ENOENT)
110640112Smckusick 		error = 0;
110738414Smckusick 	return (error);
110838414Smckusick }
110938414Smckusick 
111038414Smckusick /*
111141905Smckusick  * nfs file rename rpc called from nfs_remove() above
111238414Smckusick  */
111352234Sheideman int
111452234Sheideman nfs_renameit(sdvp, scnp, sp)
111552234Sheideman 	struct vnode *sdvp;
111652234Sheideman 	struct componentname *scnp;
111748364Smckusick 	register struct sillyrename *sp;
111838414Smckusick {
111948054Smckusick 	register u_long *tl;
112039488Smckusick 	register caddr_t cp;
112152196Smckusick 	register long t2;
112239488Smckusick 	caddr_t bpos, dpos;
112339488Smckusick 	int error = 0;
112439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
112538414Smckusick 
112638414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
112752234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
112852234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
112952196Smckusick 		nfsm_rndup(sp->s_namlen));
113052234Sheideman 	nfsm_fhtom(sdvp);
113152234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
113252234Sheideman 	nfsm_fhtom(sdvp);
113348364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
113452234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
113538414Smckusick 	nfsm_reqdone;
113652234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
113752234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
113838414Smckusick 	return (error);
113938414Smckusick }
114038414Smckusick 
114138414Smckusick /*
114238414Smckusick  * nfs hard link create call
114338414Smckusick  */
114452234Sheideman int
114553806Smckusick nfs_link(ap)
114654668Smckusick 	struct vop_link_args /* {
114754668Smckusick 		struct vnode *a_vp;
114854668Smckusick 		struct vnode *a_tdvp;
114954668Smckusick 		struct componentname *a_cnp;
115054668Smckusick 	} */ *ap;
115138414Smckusick {
115253806Smckusick 	register struct vnode *vp = ap->a_vp;
115353806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
115453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
115548054Smckusick 	register u_long *tl;
115639488Smckusick 	register caddr_t cp;
115752196Smckusick 	register long t2;
115839488Smckusick 	caddr_t bpos, dpos;
115939488Smckusick 	int error = 0;
116039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
116138414Smckusick 
116253806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
116353806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
116453806Smckusick 		if (tdvp == vp)
116553806Smckusick 			vrele(vp);
116653804Spendry 		else
116753806Smckusick 			vput(vp);
116853804Spendry 		return (EXDEV);
116953804Spendry 	}
117053804Spendry 
117138414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
117253806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
117353806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
117453806Smckusick 	nfsm_fhtom(tdvp);
117553806Smckusick 	nfsm_fhtom(vp);
117653806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
117753806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
117838414Smckusick 	nfsm_reqdone;
117953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
118053806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
118153806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
118253806Smckusick 	vrele(vp);
118340112Smckusick 	/*
118440112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
118540112Smckusick 	 */
118640112Smckusick 	if (error == EEXIST)
118740112Smckusick 		error = 0;
118838414Smckusick 	return (error);
118938414Smckusick }
119038414Smckusick 
119138414Smckusick /*
119238414Smckusick  * nfs symbolic link create call
119338414Smckusick  */
119452234Sheideman /* start here */
119552234Sheideman int
119653806Smckusick nfs_symlink(ap)
119754668Smckusick 	struct vop_symlink_args /* {
119854668Smckusick 		struct vnode *a_dvp;
119954668Smckusick 		struct vnode **a_vpp;
120054668Smckusick 		struct componentname *a_cnp;
120154668Smckusick 		struct vattr *a_vap;
120254668Smckusick 		char *a_target;
120354668Smckusick 	} */ *ap;
120438414Smckusick {
120553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
120653806Smckusick 	register struct vattr *vap = ap->a_vap;
120753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
120838884Smacklem 	register struct nfsv2_sattr *sp;
120948054Smckusick 	register u_long *tl;
121039488Smckusick 	register caddr_t cp;
121152196Smckusick 	register long t2;
121239488Smckusick 	caddr_t bpos, dpos;
121352196Smckusick 	int slen, error = 0;
121439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
121538414Smckusick 
121638414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
121753600Sheideman 	slen = strlen(ap->a_target);
121853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
121953806Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR);
122053806Smckusick 	nfsm_fhtom(dvp);
122153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
122253600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
122338884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
122453806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
122553806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
122653806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
122738884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
122853806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
122953806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
123053806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
123138414Smckusick 	nfsm_reqdone;
123253806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
123353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
123453806Smckusick 	vrele(dvp);
123540112Smckusick 	/*
123640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
123740112Smckusick 	 */
123840112Smckusick 	if (error == EEXIST)
123940112Smckusick 		error = 0;
124038414Smckusick 	return (error);
124138414Smckusick }
124238414Smckusick 
124338414Smckusick /*
124438414Smckusick  * nfs make dir call
124538414Smckusick  */
124652234Sheideman int
124753806Smckusick nfs_mkdir(ap)
124854668Smckusick 	struct vop_mkdir_args /* {
124954668Smckusick 		struct vnode *a_dvp;
125054668Smckusick 		struct vnode **a_vpp;
125154668Smckusick 		struct componentname *a_cnp;
125254668Smckusick 		struct vattr *a_vap;
125354668Smckusick 	} */ *ap;
125438414Smckusick {
125553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
125653806Smckusick 	register struct vattr *vap = ap->a_vap;
125753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
125854668Smckusick 	register struct vnode **vpp = ap->a_vpp;
125938884Smacklem 	register struct nfsv2_sattr *sp;
126048054Smckusick 	register u_long *tl;
126139488Smckusick 	register caddr_t cp;
126239488Smckusick 	register long t1, t2;
126341905Smckusick 	register int len;
126439488Smckusick 	caddr_t bpos, dpos, cp2;
126541905Smckusick 	int error = 0, firsttry = 1;
126639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
126738414Smckusick 
126853806Smckusick 	len = cnp->cn_namelen;
126938414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
127053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
127141905Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
127253806Smckusick 	nfsm_fhtom(dvp);
127353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
127438884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
127553806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
127653806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
127753806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
127838884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
127953806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
128053806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
128153806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
128254668Smckusick 	nfsm_mtofh(dvp, *vpp);
128338414Smckusick 	nfsm_reqdone;
128453806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
128540112Smckusick 	/*
128641905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
128741905Smckusick 	 * if we can succeed in looking up the directory.
128841905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
128941905Smckusick 	 * is above the if on errors. (Ugh)
129040112Smckusick 	 */
129141905Smckusick 	if (error == EEXIST && firsttry) {
129241905Smckusick 		firsttry = 0;
129340112Smckusick 		error = 0;
129441905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
129554668Smckusick 		*vpp = NULL;
129653806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
129741905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
129853806Smckusick 		nfsm_fhtom(dvp);
129953806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
130053806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
130154668Smckusick 		nfsm_mtofh(dvp, *vpp);
130254668Smckusick 		if ((*vpp)->v_type != VDIR) {
130354668Smckusick 			vput(*vpp);
130441905Smckusick 			error = EEXIST;
130541905Smckusick 		}
130641905Smckusick 		m_freem(mrep);
130741905Smckusick 	}
130853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
130953806Smckusick 	vrele(dvp);
131038414Smckusick 	return (error);
131138414Smckusick }
131238414Smckusick 
131338414Smckusick /*
131438414Smckusick  * nfs remove directory call
131538414Smckusick  */
131652234Sheideman int
131753806Smckusick nfs_rmdir(ap)
131854668Smckusick 	struct vop_rmdir_args /* {
131954668Smckusick 		struct vnode *a_dvp;
132054668Smckusick 		struct vnode *a_vp;
132154668Smckusick 		struct componentname *a_cnp;
132254668Smckusick 	} */ *ap;
132338414Smckusick {
132453806Smckusick 	register struct vnode *vp = ap->a_vp;
132553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
132653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
132748054Smckusick 	register u_long *tl;
132839488Smckusick 	register caddr_t cp;
132952196Smckusick 	register long t2;
133039488Smckusick 	caddr_t bpos, dpos;
133139488Smckusick 	int error = 0;
133239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
133338414Smckusick 
133453806Smckusick 	if (dvp == vp) {
133553806Smckusick 		vrele(dvp);
133653806Smckusick 		vrele(dvp);
133753806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
133838414Smckusick 		return (EINVAL);
133938414Smckusick 	}
134038414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
134153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
134253806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
134353806Smckusick 	nfsm_fhtom(dvp);
134453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
134553806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
134638414Smckusick 	nfsm_reqdone;
134753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
134853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
134953806Smckusick 	cache_purge(dvp);
135053806Smckusick 	cache_purge(vp);
135153806Smckusick 	vrele(vp);
135253806Smckusick 	vrele(dvp);
135340112Smckusick 	/*
135440112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
135540112Smckusick 	 */
135640112Smckusick 	if (error == ENOENT)
135740112Smckusick 		error = 0;
135838414Smckusick 	return (error);
135938414Smckusick }
136038414Smckusick 
136138414Smckusick /*
136238414Smckusick  * nfs readdir call
136338414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
136438414Smckusick  * order so that it looks more sensible. This appears consistent with the
136538414Smckusick  * Ultrix implementation of NFS.
136638414Smckusick  */
136752234Sheideman int
136853806Smckusick nfs_readdir(ap)
136954668Smckusick 	struct vop_readdir_args /* {
137054668Smckusick 		struct vnode *a_vp;
137154668Smckusick 		struct uio *a_uio;
137254668Smckusick 		struct ucred *a_cred;
137354668Smckusick 	} */ *ap;
137438414Smckusick {
137553806Smckusick 	register struct vnode *vp = ap->a_vp;
137653806Smckusick 	register struct nfsnode *np = VTONFS(vp);
137753806Smckusick 	register struct uio *uio = ap->a_uio;
137841905Smckusick 	int tresid, error;
137941905Smckusick 	struct vattr vattr;
138041905Smckusick 
138153806Smckusick 	if (vp->v_type != VDIR)
138241905Smckusick 		return (EPERM);
138341905Smckusick 	/*
138441905Smckusick 	 * First, check for hit on the EOF offset cache
138541905Smckusick 	 */
138653806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
138752196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
138853806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
138953806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
139052196Smckusick 				nfsstats.direofcache_hits++;
139152196Smckusick 				return (0);
139252196Smckusick 			}
139353806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
139454106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
139552196Smckusick 			nfsstats.direofcache_hits++;
139652196Smckusick 			return (0);
139752196Smckusick 		}
139841905Smckusick 	}
139941905Smckusick 
140041905Smckusick 	/*
140141905Smckusick 	 * Call nfs_bioread() to do the real work.
140241905Smckusick 	 */
140353806Smckusick 	tresid = uio->uio_resid;
140453806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
140541905Smckusick 
140654451Smckusick 	if (!error && uio->uio_resid == tresid)
140741905Smckusick 		nfsstats.direofcache_misses++;
140841905Smckusick 	return (error);
140941905Smckusick }
141041905Smckusick 
141141905Smckusick /*
141241905Smckusick  * Readdir rpc call.
141341905Smckusick  * Called from below the buffer cache by nfs_doio().
141441905Smckusick  */
141552234Sheideman int
141648054Smckusick nfs_readdirrpc(vp, uiop, cred)
141741905Smckusick 	register struct vnode *vp;
141841905Smckusick 	struct uio *uiop;
141941905Smckusick 	struct ucred *cred;
142041905Smckusick {
142138414Smckusick 	register long len;
142254740Smckusick 	register struct dirent *dp;
142348054Smckusick 	register u_long *tl;
142439488Smckusick 	register caddr_t cp;
142539488Smckusick 	register long t1;
142641905Smckusick 	long tlen, lastlen;
142739488Smckusick 	caddr_t bpos, dpos, cp2;
142839488Smckusick 	int error = 0;
142939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
143038414Smckusick 	struct mbuf *md2;
143138414Smckusick 	caddr_t dpos2;
143238414Smckusick 	int siz;
143340296Smckusick 	int more_dirs = 1;
143438414Smckusick 	off_t off, savoff;
143554740Smckusick 	struct dirent *savdp;
143640296Smckusick 	struct nfsmount *nmp;
143740296Smckusick 	struct nfsnode *np = VTONFS(vp);
143840296Smckusick 	long tresid;
143938414Smckusick 
144041398Smckusick 	nmp = VFSTONFS(vp->v_mount);
144140296Smckusick 	tresid = uiop->uio_resid;
144240296Smckusick 	/*
144340296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
144448054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
144541905Smckusick 	 * The stopping criteria is EOF or buffer full.
144640296Smckusick 	 */
144748054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
144840296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
144952196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
145052196Smckusick 			NFSX_FH+2*NFSX_UNSIGNED);
145140296Smckusick 		nfsm_fhtom(vp);
145248054Smckusick 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
145348054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
145448054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
145548054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
145652196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
145740296Smckusick 		siz = 0;
145852196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
145948054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
146040296Smckusick 
146140296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
146240296Smckusick 		dpos2 = dpos;
146340296Smckusick 		md2 = md;
146440296Smckusick 
146540296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
146641905Smckusick 		off = uiop->uio_offset;
146742246Smckusick #ifdef lint
146854740Smckusick 		dp = (struct dirent *)0;
146942246Smckusick #endif /* lint */
147040296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
147140296Smckusick 			savoff = off;		/* Hold onto offset and dp */
147240296Smckusick 			savdp = dp;
147352196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
147454740Smckusick 			dp = (struct dirent *)tl;
147554740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
147648054Smckusick 			len = fxdr_unsigned(int, *tl);
147740296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
147840296Smckusick 				error = EBADRPC;
147940296Smckusick 				m_freem(mrep);
148040296Smckusick 				goto nfsmout;
148140296Smckusick 			}
1482*54986Smckusick 			dp->d_namlen = (u_char)len;
1483*54986Smckusick 			dp->d_type = DT_UNKNOWN;
148440296Smckusick 			nfsm_adv(len);		/* Point past name */
148540296Smckusick 			tlen = nfsm_rndup(len);
148640296Smckusick 			/*
148740296Smckusick 			 * This should not be necessary, but some servers have
148840296Smckusick 			 * broken XDR such that these bytes are not null filled.
148940296Smckusick 			 */
149040296Smckusick 			if (tlen != len) {
149140296Smckusick 				*dpos = '\0';	/* Null-terminate */
149240296Smckusick 				nfsm_adv(tlen - len);
149340296Smckusick 				len = tlen;
149440296Smckusick 			}
149552196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
1496*54986Smckusick 			off = fxdr_unsigned(u_long, *tl);
149748054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
149848054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
149940296Smckusick 			dp->d_reclen = len+4*NFSX_UNSIGNED;
150040296Smckusick 			siz += dp->d_reclen;
150140296Smckusick 		}
150240296Smckusick 		/*
150340296Smckusick 		 * If at end of rpc data, get the eof boolean
150440296Smckusick 		 */
150540296Smckusick 		if (!more_dirs) {
150652196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
150748054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
150838414Smckusick 
150940296Smckusick 			/*
151040296Smckusick 			 * If at EOF, cache directory offset
151140296Smckusick 			 */
151241905Smckusick 			if (!more_dirs)
151340296Smckusick 				np->n_direofoffset = off;
151438414Smckusick 		}
151540296Smckusick 		/*
151640296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
151740296Smckusick 		 * savdp to trim off the last record.
151840296Smckusick 		 * --> we are not at eof
151940296Smckusick 		 */
152040296Smckusick 		if (siz > uiop->uio_resid) {
152140296Smckusick 			off = savoff;
152240296Smckusick 			siz -= dp->d_reclen;
152340296Smckusick 			dp = savdp;
152440296Smckusick 			more_dirs = 0;	/* Paranoia */
152540113Smckusick 		}
152640296Smckusick 		if (siz > 0) {
152741905Smckusick 			lastlen = dp->d_reclen;
152840296Smckusick 			md = md2;
152940296Smckusick 			dpos = dpos2;
153040296Smckusick 			nfsm_mtouio(uiop, siz);
153140296Smckusick 			uiop->uio_offset = off;
153240296Smckusick 		} else
153340296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
153440296Smckusick 		m_freem(mrep);
153538414Smckusick 	}
153641905Smckusick 	/*
153748054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
153841905Smckusick 	 * by increasing d_reclen for the last record.
153941905Smckusick 	 */
154041905Smckusick 	if (uiop->uio_resid < tresid) {
154148054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
154241905Smckusick 		if (len > 0) {
154354740Smckusick 			dp = (struct dirent *)
154441905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
154541905Smckusick 			dp->d_reclen += len;
154641905Smckusick 			uiop->uio_iov->iov_base += len;
154741905Smckusick 			uiop->uio_iov->iov_len -= len;
154841905Smckusick 			uiop->uio_resid -= len;
154941905Smckusick 		}
155041905Smckusick 	}
155140296Smckusick nfsmout:
155238414Smckusick 	return (error);
155338414Smckusick }
155438414Smckusick 
155552196Smckusick /*
155652196Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when
155752196Smckusick  * the "rdirlook" mount option is specified.
155852196Smckusick  */
155952234Sheideman int
156052196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
156152196Smckusick 	struct vnode *vp;
156252196Smckusick 	register struct uio *uiop;
156352196Smckusick 	struct ucred *cred;
156452196Smckusick {
156552196Smckusick 	register int len;
156654740Smckusick 	register struct dirent *dp;
156752196Smckusick 	register u_long *tl;
156852196Smckusick 	register caddr_t cp;
156952196Smckusick 	register long t1;
157052196Smckusick 	caddr_t bpos, dpos, cp2;
157152196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
157252196Smckusick 	struct nameidata nami, *ndp = &nami;
157352317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
157452196Smckusick 	off_t off, endoff;
157552196Smckusick 	time_t reqtime, ltime;
157652196Smckusick 	struct nfsmount *nmp;
157752196Smckusick 	struct nfsnode *np, *tp;
157852196Smckusick 	struct vnode *newvp;
157952196Smckusick 	nfsv2fh_t *fhp;
158052196Smckusick 	u_long fileno;
158152196Smckusick 	u_quad_t frev;
158252196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
158352196Smckusick 	int cachable;
158452196Smckusick 
158552196Smckusick 	if (uiop->uio_iovcnt != 1)
158652196Smckusick 		panic("nfs rdirlook");
158752196Smckusick 	nmp = VFSTONFS(vp->v_mount);
158852196Smckusick 	tresid = uiop->uio_resid;
158952196Smckusick 	ndp->ni_dvp = vp;
159052196Smckusick 	newvp = NULLVP;
159152196Smckusick 	/*
159252196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
159352196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
159452196Smckusick 	 * The stopping criteria is EOF or buffer full.
159552196Smckusick 	 */
159652196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
159752196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
159852196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
159952196Smckusick 			NFSX_FH+3*NFSX_UNSIGNED);
160052196Smckusick 		nfsm_fhtom(vp);
160152196Smckusick 		nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED);
160252196Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
160352196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
160452196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
160552196Smckusick 		*tl = txdr_unsigned(nmp->nm_leaseterm);
160652196Smckusick 		reqtime = time.tv_sec;
160752196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
160852196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
160952196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
161052196Smckusick 
161152196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
161252196Smckusick 		off = uiop->uio_offset;
161352196Smckusick 		bigenough = 1;
161452196Smckusick 		while (more_dirs && bigenough) {
161552196Smckusick 			doit = 1;
161652196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
161752196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
161852196Smckusick 			ltime = reqtime + fxdr_unsigned(int, *tl++);
161952196Smckusick 			fxdr_hyper(tl, &frev);
162052196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
162152196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
162252196Smckusick 				VREF(vp);
162352196Smckusick 				newvp = vp;
162452196Smckusick 				np = VTONFS(vp);
162552196Smckusick 			} else {
162652196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
162752196Smckusick 					doit = 0;
162852196Smckusick 				newvp = NFSTOV(np);
162952196Smckusick 			}
163052196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
163152196Smckusick 				(struct vattr *)0))
163252196Smckusick 				doit = 0;
163352196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
163452196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
163552196Smckusick 			len = fxdr_unsigned(int, *tl);
163652196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
163752196Smckusick 				error = EBADRPC;
163852196Smckusick 				m_freem(mrep);
163952196Smckusick 				goto nfsmout;
164052196Smckusick 			}
164152196Smckusick 			tlen = (len + 4) & ~0x3;
164252196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
164352196Smckusick 				bigenough = 0;
164452196Smckusick 			if (bigenough && doit) {
164554740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
164654740Smckusick 				dp->d_fileno = fileno;
164752196Smckusick 				dp->d_namlen = len;
164852196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
1649*54986Smckusick 				dp->d_type =
1650*54986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
165152196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
165252196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
165352196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
165452317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
165552317Sheideman 				cnp->cn_namelen = len;
165652196Smckusick 				ndp->ni_vp = newvp;
165752196Smckusick 				nfsm_mtouio(uiop, len);
165852196Smckusick 				cp = uiop->uio_iov->iov_base;
165952196Smckusick 				tlen -= len;
166052196Smckusick 				for (i = 0; i < tlen; i++)
166152196Smckusick 					*cp++ = '\0';
166252196Smckusick 				uiop->uio_iov->iov_base += tlen;
166352196Smckusick 				uiop->uio_iov->iov_len -= tlen;
166452196Smckusick 				uiop->uio_resid -= tlen;
166552317Sheideman 				cnp->cn_hash = 0;
166652317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
166752317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
166852196Smckusick 				if (ltime > time.tv_sec) {
166952196Smckusick 					if (np->n_tnext) {
167052196Smckusick 						if (np->n_tnext == (struct nfsnode *)nmp)
167152196Smckusick 							nmp->nm_tprev = np->n_tprev;
167252196Smckusick 						else
167352196Smckusick 							np->n_tnext->n_tprev = np->n_tprev;
167452196Smckusick 						if (np->n_tprev == (struct nfsnode *)nmp)
167552196Smckusick 							nmp->nm_tnext = np->n_tnext;
167652196Smckusick 						else
167752196Smckusick 							np->n_tprev->n_tnext = np->n_tnext;
167852196Smckusick 					} else
167952196Smckusick 						np->n_flag &= ~NQNFSWRITE;
168052196Smckusick 					if (cachable)
168152196Smckusick 						np->n_flag &= ~NQNFSNONCACHE;
168252196Smckusick 					else
168352196Smckusick 						np->n_flag |= NQNFSNONCACHE;
168452196Smckusick 					np->n_expiry = ltime;
168552196Smckusick 					np->n_lrev = frev;
168652196Smckusick 					tp = nmp->nm_tprev;
168752196Smckusick 					while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
168852196Smckusick 						tp = tp->n_tprev;
168952196Smckusick 					if (tp == (struct nfsnode *)nmp) {
169052196Smckusick 						np->n_tnext = nmp->nm_tnext;
169152196Smckusick 						nmp->nm_tnext = np;
169252196Smckusick 					} else {
169352196Smckusick 						np->n_tnext = tp->n_tnext;
169452196Smckusick 						tp->n_tnext = np;
169552196Smckusick 					}
169652196Smckusick 					np->n_tprev = tp;
169752196Smckusick 					if (np->n_tnext == (struct nfsnode *)nmp)
169852196Smckusick 						nmp->nm_tprev = np;
169952196Smckusick 					else
170052196Smckusick 						np->n_tnext->n_tprev = np;
170152317Sheideman 					cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
170252196Smckusick 				}
170352196Smckusick 			} else {
170452196Smckusick 				nfsm_adv(nfsm_rndup(len));
170552196Smckusick 			}
170652196Smckusick 			if (newvp != NULLVP) {
170752196Smckusick 				vrele(newvp);
170852196Smckusick 				newvp = NULLVP;
170952196Smckusick 			}
171052196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
171152196Smckusick 			if (bigenough)
171252196Smckusick 				endoff = off = fxdr_unsigned(off_t, *tl++);
171352196Smckusick 			else
171452196Smckusick 				endoff = fxdr_unsigned(off_t, *tl++);
171552196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
171652196Smckusick 		}
171752196Smckusick 		/*
171852196Smckusick 		 * If at end of rpc data, get the eof boolean
171952196Smckusick 		 */
172052196Smckusick 		if (!more_dirs) {
172152196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
172252196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
172352196Smckusick 
172452196Smckusick 			/*
172552196Smckusick 			 * If at EOF, cache directory offset
172652196Smckusick 			 */
172752196Smckusick 			if (!more_dirs)
172852196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
172952196Smckusick 		}
173052196Smckusick 		if (uiop->uio_resid < tresid)
173152196Smckusick 			uiop->uio_offset = off;
173252196Smckusick 		else
173352196Smckusick 			more_dirs = 0;
173452196Smckusick 		m_freem(mrep);
173552196Smckusick 	}
173652196Smckusick 	/*
173752196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
173852196Smckusick 	 * by increasing d_reclen for the last record.
173952196Smckusick 	 */
174052196Smckusick 	if (uiop->uio_resid < tresid) {
174152196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
174252196Smckusick 		if (len > 0) {
174352196Smckusick 			dp->d_reclen += len;
174452196Smckusick 			uiop->uio_iov->iov_base += len;
174552196Smckusick 			uiop->uio_iov->iov_len -= len;
174652196Smckusick 			uiop->uio_resid -= len;
174752196Smckusick 		}
174852196Smckusick 	}
174952196Smckusick nfsmout:
175052196Smckusick 	if (newvp != NULLVP)
175152196Smckusick 		vrele(newvp);
175252196Smckusick 	return (error);
175352196Smckusick }
175439488Smckusick static char hextoasc[] = "0123456789abcdef";
175538414Smckusick 
175638414Smckusick /*
175738414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
175838414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
175938414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
176038414Smckusick  * nfsnode. There is the potential for another process on a different client
176138414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
176238414Smckusick  * nfs_rename() completes, but...
176338414Smckusick  */
176452234Sheideman int
176552317Sheideman nfs_sillyrename(dvp, vp, cnp)
176652234Sheideman 	struct vnode *dvp, *vp;
176752234Sheideman 	struct componentname *cnp;
176838414Smckusick {
176938414Smckusick 	register struct nfsnode *np;
177038414Smckusick 	register struct sillyrename *sp;
177138414Smckusick 	int error;
177238414Smckusick 	short pid;
177338414Smckusick 
177452234Sheideman 	cache_purge(dvp);
177552234Sheideman 	np = VTONFS(vp);
177651986Smckusick #ifdef SILLYSEPARATE
177738414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
177848364Smckusick 		M_NFSREQ, M_WAITOK);
177951986Smckusick #else
178051986Smckusick 	sp = &np->n_silly;
178151986Smckusick #endif
178252234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
178352234Sheideman 	sp->s_dvp = dvp;
178452234Sheideman 	VREF(dvp);
178538414Smckusick 
178638414Smckusick 	/* Fudge together a funny name */
178752234Sheideman 	pid = cnp->cn_proc->p_pid;
178848364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
178948364Smckusick 	sp->s_namlen = 12;
179048364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
179148364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
179248364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
179348364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
179438414Smckusick 
179538414Smckusick 	/* Try lookitups until we get one that isn't there */
179652234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
179748364Smckusick 		sp->s_name[4]++;
179848364Smckusick 		if (sp->s_name[4] > 'z') {
179938414Smckusick 			error = EINVAL;
180038414Smckusick 			goto bad;
180138414Smckusick 		}
180238414Smckusick 	}
180352234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
180438414Smckusick 		goto bad;
180552234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
180638414Smckusick 	np->n_sillyrename = sp;
180738414Smckusick 	return (0);
180838414Smckusick bad:
180948364Smckusick 	vrele(sp->s_dvp);
181048364Smckusick 	crfree(sp->s_cred);
181151986Smckusick #ifdef SILLYSEPARATE
181248364Smckusick 	free((caddr_t)sp, M_NFSREQ);
181351986Smckusick #endif
181438414Smckusick 	return (error);
181538414Smckusick }
181638414Smckusick 
181738414Smckusick /*
181838414Smckusick  * Look up a file name for silly rename stuff.
181938414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
182038414Smckusick  * into the nfsnode table.
182138414Smckusick  * If fhp != NULL it copies the returned file handle out
182238414Smckusick  */
182352234Sheideman int
182452196Smckusick nfs_lookitup(sp, fhp, procp)
182548364Smckusick 	register struct sillyrename *sp;
182638414Smckusick 	nfsv2fh_t *fhp;
182752196Smckusick 	struct proc *procp;
182838414Smckusick {
182948364Smckusick 	register struct vnode *vp = sp->s_dvp;
183048054Smckusick 	register u_long *tl;
183139488Smckusick 	register caddr_t cp;
183239488Smckusick 	register long t1, t2;
183339488Smckusick 	caddr_t bpos, dpos, cp2;
183439488Smckusick 	u_long xid;
183539488Smckusick 	int error = 0;
183639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
183738414Smckusick 	long len;
183838414Smckusick 
183938414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
184048364Smckusick 	len = sp->s_namlen;
184152196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
184238414Smckusick 	nfsm_fhtom(vp);
184348364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
184452196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
184538414Smckusick 	if (fhp != NULL) {
184652196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
184738414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
184838414Smckusick 	}
184938414Smckusick 	nfsm_reqdone;
185038414Smckusick 	return (error);
185138414Smckusick }
185238414Smckusick 
185338414Smckusick /*
185438414Smckusick  * Kludge City..
185538414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
185641905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
185738414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
185838414Smckusick  *   nfsiobuf area.
185938414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
186038414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
186138414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
186238414Smckusick  *    context of the swapper process (2).
186338414Smckusick  */
186452234Sheideman int
186553806Smckusick nfs_bmap(ap)
186654668Smckusick 	struct vop_bmap_args /* {
186754668Smckusick 		struct vnode *a_vp;
186854668Smckusick 		daddr_t  a_bn;
186954668Smckusick 		struct vnode **a_vpp;
187054668Smckusick 		daddr_t *a_bnp;
187154668Smckusick 	} */ *ap;
187238414Smckusick {
187353806Smckusick 	register struct vnode *vp = ap->a_vp;
187453806Smckusick 
187553600Sheideman 	if (ap->a_vpp != NULL)
187653806Smckusick 		*ap->a_vpp = vp;
187753600Sheideman 	if (ap->a_bnp != NULL)
187853806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
187938414Smckusick 	return (0);
188038414Smckusick }
188138414Smckusick 
188238414Smckusick /*
188338884Smacklem  * Strategy routine for phys. i/o
188438884Smacklem  * If the biod's are running, queue a request
188538884Smacklem  * otherwise just call nfs_doio() to get it done
188638414Smckusick  */
188752234Sheideman int
188853806Smckusick nfs_strategy(ap)
188954668Smckusick 	struct vop_strategy_args /* {
189054668Smckusick 		struct buf *a_bp;
189154668Smckusick 	} */ *ap;
189238414Smckusick {
189353806Smckusick 	register struct buf *bp = ap->a_bp;
189438884Smacklem 	register struct buf *dp;
189539341Smckusick 	register int i;
189638884Smacklem 	int error = 0;
189739341Smckusick 	int fnd = 0;
189838884Smacklem 
189938884Smacklem 	/*
190041905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
190141905Smckusick 	 * doesn't set it, I will.
190246450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
190341905Smckusick 	 * be hanging about after the process terminates.
190441905Smckusick 	 */
190553806Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
190653806Smckusick 		if (bp->b_flags & B_ASYNC)
190753806Smckusick 			bp->b_proc = (struct proc *)0;
190846988Smckusick 		else
190953806Smckusick 			bp->b_proc = curproc;
191046988Smckusick 	}
191141905Smckusick 	/*
191246450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
191338884Smacklem 	 * queue the request, wake it up and wait for completion
191446450Skarels 	 * otherwise just do it ourselves.
191538884Smacklem 	 */
191653806Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
191753806Smckusick 		return (nfs_doio(bp));
191846988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
191946988Smckusick 		if (nfs_iodwant[i]) {
192039341Smckusick 			dp = &nfs_bqueue;
192139341Smckusick 			if (dp->b_actf == NULL) {
192253806Smckusick 				dp->b_actl = bp;
192353806Smckusick 				bp->b_actf = dp;
192439341Smckusick 			} else {
192553806Smckusick 				dp->b_actf->b_actl = bp;
192653806Smckusick 				bp->b_actf = dp->b_actf;
192739341Smckusick 			}
192853806Smckusick 			dp->b_actf = bp;
192953806Smckusick 			bp->b_actl = dp;
193039341Smckusick 			fnd++;
193139341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
193239341Smckusick 			break;
193338884Smacklem 		}
193439341Smckusick 	}
193539341Smckusick 	if (!fnd)
193653806Smckusick 		error = nfs_doio(bp);
193738884Smacklem 	return (error);
193838884Smacklem }
193938884Smacklem 
194038884Smacklem /*
194138884Smacklem  * Fun and games with i/o
194238884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
194338884Smacklem  * mapping the data buffer into kernel virtual space and doing the
194438884Smacklem  * nfs read or write rpc's from it.
194541905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
194641905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
194738884Smacklem  * partially disk interrupt driven.
194838884Smacklem  */
194952234Sheideman int
195038884Smacklem nfs_doio(bp)
195138884Smacklem 	register struct buf *bp;
195238884Smacklem {
195338414Smckusick 	register struct uio *uiop;
195438414Smckusick 	register struct vnode *vp;
195539341Smckusick 	struct nfsnode *np;
195638884Smacklem 	struct ucred *cr;
195741539Smckusick 	int error;
195841539Smckusick 	struct uio uio;
195941539Smckusick 	struct iovec io;
196038414Smckusick 
196138414Smckusick 	vp = bp->b_vp;
196240251Smckusick 	np = VTONFS(vp);
196338414Smckusick 	uiop = &uio;
196438414Smckusick 	uiop->uio_iov = &io;
196538414Smckusick 	uiop->uio_iovcnt = 1;
196638414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
196752196Smckusick 	uiop->uio_procp = bp->b_proc;
196839751Smckusick 
196938414Smckusick 	/*
197038884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
197138884Smacklem 	 * the Nfsiomap pte's
197238884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
197338884Smacklem 	 * and a guess at a group
197438414Smckusick 	 */
197538884Smacklem 	if (bp->b_flags & B_PHYS) {
197648054Smckusick 		if (bp->b_flags & B_DIRTY)
197748054Smckusick 			uiop->uio_procp = pageproc;
197848054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
197941539Smckusick 		/* mapping was already done by vmapbuf */
198041539Smckusick 		io.iov_base = bp->b_un.b_addr;
198139751Smckusick 
198238884Smacklem 		/*
198339751Smckusick 		 * And do the i/o rpc
198439751Smckusick 		 */
198539751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
198639823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
198739751Smckusick 		if (bp->b_flags & B_READ) {
198839751Smckusick 			uiop->uio_rw = UIO_READ;
198939751Smckusick 			nfsstats.read_physios++;
199048054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
199145717Smckusick 			(void) vnode_pager_uncache(vp);
199239751Smckusick 		} else {
199339751Smckusick 			uiop->uio_rw = UIO_WRITE;
199439751Smckusick 			nfsstats.write_physios++;
199548054Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr);
199639341Smckusick 		}
199739751Smckusick 
199839751Smckusick 		/*
199939751Smckusick 		 * Finally, release pte's used by physical i/o
200039751Smckusick 		 */
200138884Smacklem 		crfree(cr);
200239751Smckusick 	} else {
200339751Smckusick 		if (bp->b_flags & B_READ) {
200439751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
200539751Smckusick 			io.iov_base = bp->b_un.b_addr;
200639751Smckusick 			uiop->uio_rw = UIO_READ;
200741905Smckusick 			switch (vp->v_type) {
200841905Smckusick 			case VREG:
200941905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
201041905Smckusick 				nfsstats.read_bios++;
201148054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
201241905Smckusick 				break;
201341905Smckusick 			case VLNK:
201441905Smckusick 				uiop->uio_offset = 0;
201541905Smckusick 				nfsstats.readlink_bios++;
201648054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
201741905Smckusick 				break;
201841905Smckusick 			case VDIR:
201941905Smckusick 				uiop->uio_offset = bp->b_lblkno;
202041905Smckusick 				nfsstats.readdir_bios++;
202152196Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK)
202252196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
202352196Smckusick 				else
202452196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
202541905Smckusick 				/*
202641905Smckusick 				 * Save offset cookie in b_blkno.
202741905Smckusick 				 */
202841905Smckusick 				bp->b_blkno = uiop->uio_offset;
202941905Smckusick 				break;
203041905Smckusick 			};
203141905Smckusick 			bp->b_error = error;
203239751Smckusick 		} else {
203339751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
203439751Smckusick 				- bp->b_dirtyoff;
203539823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
203639751Smckusick 				+ bp->b_dirtyoff;
203739751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
203839751Smckusick 			uiop->uio_rw = UIO_WRITE;
203939751Smckusick 			nfsstats.write_bios++;
204041905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
204148054Smckusick 				bp->b_wcred);
204239751Smckusick 			if (error) {
204339751Smckusick 				np->n_error = error;
204439751Smckusick 				np->n_flag |= NWRITEERR;
204539751Smckusick 			}
204639751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
204739751Smckusick 		}
204838884Smacklem 	}
204939751Smckusick 	if (error)
205039751Smckusick 		bp->b_flags |= B_ERROR;
205139751Smckusick 	bp->b_resid = uiop->uio_resid;
205238414Smckusick 	biodone(bp);
205338414Smckusick 	return (error);
205438414Smckusick }
205538884Smacklem 
205638884Smacklem /*
205748054Smckusick  * Mmap a file
205848054Smckusick  *
205948054Smckusick  * NB Currently unsupported.
206048054Smckusick  */
206148054Smckusick /* ARGSUSED */
206252234Sheideman int
206353806Smckusick nfs_mmap(ap)
206454668Smckusick 	struct vop_mmap_args /* {
206554668Smckusick 		struct vnode *a_vp;
206654668Smckusick 		int  a_fflags;
206754668Smckusick 		struct ucred *a_cred;
206854668Smckusick 		struct proc *a_p;
206954668Smckusick 	} */ *ap;
207048054Smckusick {
207148054Smckusick 
207248054Smckusick 	return (EINVAL);
207348054Smckusick }
207448054Smckusick 
207548054Smckusick /*
207638884Smacklem  * Flush all the blocks associated with a vnode.
207738884Smacklem  * 	Walk through the buffer pool and push any dirty pages
207838884Smacklem  *	associated with the vnode.
207938884Smacklem  */
208039488Smckusick /* ARGSUSED */
208152234Sheideman int
208253806Smckusick nfs_fsync(ap)
208354451Smckusick 	struct vop_fsync_args /* {
208454451Smckusick 		struct vnodeop_desc *a_desc;
208554451Smckusick 		struct vnode * a_vp;
208654451Smckusick 		struct ucred * a_cred;
208754451Smckusick 		int  a_waitfor;
208854451Smckusick 		struct proc * a_p;
208954451Smckusick 	} */ *ap;
209038884Smacklem {
209154451Smckusick 	register struct vnode *vp = ap->a_vp;
209254451Smckusick 	register struct nfsnode *np = VTONFS(vp);
209354451Smckusick 	register struct buf *bp;
209454451Smckusick 	struct buf *nbp;
209554451Smckusick 	int s, error = 0;
209638884Smacklem 
209754451Smckusick loop:
209854451Smckusick 	s = splbio();
209954451Smckusick 	for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
210054451Smckusick 		nbp = bp->b_blockf;
210154451Smckusick 		if ((bp->b_flags & B_BUSY))
210254451Smckusick 			continue;
210354451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
210454451Smckusick 			panic("nfs_fsync: not dirty");
210554451Smckusick 		bremfree(bp);
210654451Smckusick 		bp->b_flags |= B_BUSY;
210754451Smckusick 		splx(s);
210854451Smckusick 		error = bawrite(bp);
210954451Smckusick 		goto loop;
211038884Smacklem 	}
211154451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
211254451Smckusick 		while (vp->v_numoutput) {
211354451Smckusick 			vp->v_flag |= VBWAIT;
211454451Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
211554451Smckusick 		}
211654451Smckusick #ifdef DIAGNOSTIC
211754451Smckusick 		if (vp->v_dirtyblkhd) {
211854451Smckusick 			vprint("nfs_fsync: dirty", vp);
211954451Smckusick 			goto loop;
212054451Smckusick 		}
212154451Smckusick #endif
212254451Smckusick 	}
212354451Smckusick 	splx(s);
212454451Smckusick 	np->n_flag &= ~NMODIFIED;
212553629Smckusick 	if (np->n_flag & NWRITEERR) {
212639751Smckusick 		error = np->n_error;
212753629Smckusick 		np->n_flag &= ~NWRITEERR;
212853629Smckusick 	}
212938884Smacklem 	return (error);
213038884Smacklem }
213139672Smckusick 
213239672Smckusick /*
213346201Smckusick  * NFS advisory byte-level locks.
213446201Smckusick  * Currently unsupported.
213546201Smckusick  */
213652234Sheideman int
213753806Smckusick nfs_advlock(ap)
213854668Smckusick 	struct vop_advlock_args /* {
213954668Smckusick 		struct vnode *a_vp;
214054668Smckusick 		caddr_t  a_id;
214154668Smckusick 		int  a_op;
214254668Smckusick 		struct flock *a_fl;
214354668Smckusick 		int  a_flags;
214454668Smckusick 	} */ *ap;
214546201Smckusick {
214646201Smckusick 
214746201Smckusick 	return (EOPNOTSUPP);
214846201Smckusick }
214946201Smckusick 
215046201Smckusick /*
215139672Smckusick  * Print out the contents of an nfsnode.
215239672Smckusick  */
215352234Sheideman int
215453806Smckusick nfs_print(ap)
215554668Smckusick 	struct vop_print_args /* {
215654668Smckusick 		struct vnode *a_vp;
215754668Smckusick 	} */ *ap;
215839672Smckusick {
215953806Smckusick 	register struct vnode *vp = ap->a_vp;
216053806Smckusick 	register struct nfsnode *np = VTONFS(vp);
216139672Smckusick 
216240294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
216340294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
216440294Smckusick #ifdef FIFO
216553806Smckusick 	if (vp->v_type == VFIFO)
216653806Smckusick 		fifo_printinfo(vp);
216740294Smckusick #endif /* FIFO */
216839914Smckusick 	printf("\n");
216939672Smckusick }
217051573Smckusick 
217151573Smckusick /*
217251573Smckusick  * NFS directory offset lookup.
217351573Smckusick  * Currently unsupported.
217451573Smckusick  */
217552234Sheideman int
217653806Smckusick nfs_blkatoff(ap)
217754668Smckusick 	struct vop_blkatoff_args /* {
217854668Smckusick 		struct vnode *a_vp;
217954668Smckusick 		off_t a_offset;
218054668Smckusick 		char **a_res;
218154668Smckusick 		struct buf **a_bpp;
218254668Smckusick 	} */ *ap;
218351573Smckusick {
218451573Smckusick 
218551573Smckusick 	return (EOPNOTSUPP);
218651573Smckusick }
218751573Smckusick 
218851573Smckusick /*
218951573Smckusick  * NFS flat namespace allocation.
219051573Smckusick  * Currently unsupported.
219151573Smckusick  */
219252234Sheideman int
219353806Smckusick nfs_valloc(ap)
219454668Smckusick 	struct vop_valloc_args /* {
219554668Smckusick 		struct vnode *a_pvp;
219654668Smckusick 		int a_mode;
219754668Smckusick 		struct ucred *a_cred;
219854668Smckusick 		struct vnode **a_vpp;
219954668Smckusick 	} */ *ap;
220051573Smckusick {
220151573Smckusick 
220251573Smckusick 	return (EOPNOTSUPP);
220351573Smckusick }
220451573Smckusick 
220551573Smckusick /*
220651573Smckusick  * NFS flat namespace free.
220751573Smckusick  * Currently unsupported.
220851573Smckusick  */
220953582Sheideman int
221053806Smckusick nfs_vfree(ap)
221154668Smckusick 	struct vop_vfree_args /* {
221254668Smckusick 		struct vnode *a_pvp;
221354668Smckusick 		ino_t a_ino;
221454668Smckusick 		int a_mode;
221554668Smckusick 	} */ *ap;
221651573Smckusick {
221751573Smckusick 
221853582Sheideman 	return (EOPNOTSUPP);
221951573Smckusick }
222051573Smckusick 
222151573Smckusick /*
222251573Smckusick  * NFS file truncation.
222351573Smckusick  */
222452234Sheideman int
222553806Smckusick nfs_truncate(ap)
222654668Smckusick 	struct vop_truncate_args /* {
222754668Smckusick 		struct vnode *a_vp;
222854668Smckusick 		off_t a_length;
222954668Smckusick 		int a_flags;
223054668Smckusick 		struct ucred *a_cred;
223154668Smckusick 		struct proc *a_p;
223254668Smckusick 	} */ *ap;
223351573Smckusick {
223451573Smckusick 
223551573Smckusick 	/* Use nfs_setattr */
223651573Smckusick 	printf("nfs_truncate: need to implement!!");
223751573Smckusick 	return (EOPNOTSUPP);
223851573Smckusick }
223951573Smckusick 
224051573Smckusick /*
224151573Smckusick  * NFS update.
224251573Smckusick  */
224352234Sheideman int
224453806Smckusick nfs_update(ap)
224554668Smckusick 	struct vop_update_args /* {
224654668Smckusick 		struct vnode *a_vp;
224754668Smckusick 		struct timeval *a_ta;
224854668Smckusick 		struct timeval *a_tm;
224954668Smckusick 		int a_waitfor;
225054668Smckusick 	} */ *ap;
225151573Smckusick {
225251573Smckusick 
225351573Smckusick 	/* Use nfs_setattr */
225451573Smckusick 	printf("nfs_update: need to implement!!");
225551573Smckusick 	return (EOPNOTSUPP);
225651573Smckusick }
225753629Smckusick 
225853629Smckusick /*
225953629Smckusick  * Read wrapper for special devices.
226053629Smckusick  */
226153629Smckusick int
226253629Smckusick nfsspec_read(ap)
226354668Smckusick 	struct vop_read_args /* {
226454668Smckusick 		struct vnode *a_vp;
226554668Smckusick 		struct uio *a_uio;
226654668Smckusick 		int  a_ioflag;
226754668Smckusick 		struct ucred *a_cred;
226854668Smckusick 	} */ *ap;
226953629Smckusick {
227053629Smckusick 	extern int (**spec_vnodeop_p)();
227154032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
227253629Smckusick 
227353629Smckusick 	/*
227453629Smckusick 	 * Set access flag.
227553629Smckusick 	 */
227654032Smckusick 	np->n_flag |= NACC;
227754032Smckusick 	np->n_atim = time;
227853629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
227953629Smckusick }
228053629Smckusick 
228153629Smckusick /*
228253629Smckusick  * Write wrapper for special devices.
228353629Smckusick  */
228453629Smckusick int
228553629Smckusick nfsspec_write(ap)
228654668Smckusick 	struct vop_write_args /* {
228754668Smckusick 		struct vnode *a_vp;
228854668Smckusick 		struct uio *a_uio;
228954668Smckusick 		int  a_ioflag;
229054668Smckusick 		struct ucred *a_cred;
229154668Smckusick 	} */ *ap;
229253629Smckusick {
229353629Smckusick 	extern int (**spec_vnodeop_p)();
229454032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
229553629Smckusick 
229653629Smckusick 	/*
229754032Smckusick 	 * Set update flag.
229853629Smckusick 	 */
229954032Smckusick 	np->n_flag |= NUPD;
230054032Smckusick 	np->n_mtim = time;
230153629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
230253629Smckusick }
230353629Smckusick 
230453629Smckusick /*
230553629Smckusick  * Close wrapper for special devices.
230653629Smckusick  *
230753629Smckusick  * Update the times on the nfsnode then do device close.
230853629Smckusick  */
230953629Smckusick int
231053629Smckusick nfsspec_close(ap)
231154668Smckusick 	struct vop_close_args /* {
231254668Smckusick 		struct vnode *a_vp;
231354668Smckusick 		int  a_fflag;
231454668Smckusick 		struct ucred *a_cred;
231554668Smckusick 		struct proc *a_p;
231654668Smckusick 	} */ *ap;
231753629Smckusick {
231853806Smckusick 	register struct vnode *vp = ap->a_vp;
231953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
232053629Smckusick 	struct vattr vattr;
232153629Smckusick 	extern int (**spec_vnodeop_p)();
232253629Smckusick 
232353629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
232453629Smckusick 		if (np->n_flag & NACC)
232553629Smckusick 			np->n_atim = time;
232653629Smckusick 		if (np->n_flag & NUPD)
232753629Smckusick 			np->n_mtim = time;
232853629Smckusick 		np->n_flag |= NCHG;
232953806Smckusick 		if (vp->v_usecount == 1 &&
233053806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
233153629Smckusick 			VATTR_NULL(&vattr);
233254106Smckusick 			if (np->n_flag & NACC) {
233354106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
233454106Smckusick 				vattr.va_atime.ts_nsec =
233554106Smckusick 				    np->n_atim.tv_usec * 1000;
233654106Smckusick 			}
233754106Smckusick 			if (np->n_flag & NUPD) {
233854106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
233954106Smckusick 				vattr.va_mtime.ts_nsec =
234054106Smckusick 				    np->n_mtim.tv_usec * 1000;
234154106Smckusick 			}
234253806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
234353629Smckusick 		}
234453629Smckusick 	}
234553629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
234653629Smckusick }
234753629Smckusick 
234853629Smckusick #ifdef FIFO
234953629Smckusick /*
235053629Smckusick  * Read wrapper for fifos.
235153629Smckusick  */
235253629Smckusick int
235353629Smckusick nfsfifo_read(ap)
235454668Smckusick 	struct vop_read_args /* {
235554668Smckusick 		struct vnode *a_vp;
235654668Smckusick 		struct uio *a_uio;
235754668Smckusick 		int  a_ioflag;
235854668Smckusick 		struct ucred *a_cred;
235954668Smckusick 	} */ *ap;
236053629Smckusick {
236153629Smckusick 	extern int (**fifo_vnodeop_p)();
236254032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
236353629Smckusick 
236453629Smckusick 	/*
236553629Smckusick 	 * Set access flag.
236653629Smckusick 	 */
236754032Smckusick 	np->n_flag |= NACC;
236854032Smckusick 	np->n_atim = time;
236953629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
237053629Smckusick }
237153629Smckusick 
237253629Smckusick /*
237353629Smckusick  * Write wrapper for fifos.
237453629Smckusick  */
237553629Smckusick int
237653629Smckusick nfsfifo_write(ap)
237754668Smckusick 	struct vop_write_args /* {
237854668Smckusick 		struct vnode *a_vp;
237954668Smckusick 		struct uio *a_uio;
238054668Smckusick 		int  a_ioflag;
238154668Smckusick 		struct ucred *a_cred;
238254668Smckusick 	} */ *ap;
238353629Smckusick {
238453629Smckusick 	extern int (**fifo_vnodeop_p)();
238554032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
238653629Smckusick 
238753629Smckusick 	/*
238853629Smckusick 	 * Set update flag.
238953629Smckusick 	 */
239054032Smckusick 	np->n_flag |= NUPD;
239154032Smckusick 	np->n_mtim = time;
239253629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
239353629Smckusick }
239453629Smckusick 
239553629Smckusick /*
239653629Smckusick  * Close wrapper for fifos.
239753629Smckusick  *
239853629Smckusick  * Update the times on the nfsnode then do fifo close.
239953629Smckusick  */
240053629Smckusick int
240153629Smckusick nfsfifo_close(ap)
240254668Smckusick 	struct vop_close_args /* {
240354668Smckusick 		struct vnode *a_vp;
240454668Smckusick 		int  a_fflag;
240554668Smckusick 		struct ucred *a_cred;
240654668Smckusick 		struct proc *a_p;
240754668Smckusick 	} */ *ap;
240853629Smckusick {
240953806Smckusick 	register struct vnode *vp = ap->a_vp;
241053806Smckusick 	register struct nfsnode *np = VTONFS(vp);
241153629Smckusick 	struct vattr vattr;
241253629Smckusick 	extern int (**fifo_vnodeop_p)();
241353629Smckusick 
241453629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
241553629Smckusick 		if (np->n_flag & NACC)
241653629Smckusick 			np->n_atim = time;
241753629Smckusick 		if (np->n_flag & NUPD)
241853629Smckusick 			np->n_mtim = time;
241953629Smckusick 		np->n_flag |= NCHG;
242053806Smckusick 		if (vp->v_usecount == 1 &&
242153806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
242253629Smckusick 			VATTR_NULL(&vattr);
242354106Smckusick 			if (np->n_flag & NACC) {
242454106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
242554106Smckusick 				vattr.va_atime.ts_nsec =
242654106Smckusick 				    np->n_atim.tv_usec * 1000;
242754106Smckusick 			}
242854106Smckusick 			if (np->n_flag & NUPD) {
242954106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
243054106Smckusick 				vattr.va_mtime.ts_nsec =
243154106Smckusick 				    np->n_mtim.tv_usec * 1000;
243254106Smckusick 			}
243353806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
243453629Smckusick 		}
243553629Smckusick 	}
243653629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
243753629Smckusick }
243853629Smckusick #endif /* FIFO */
2439