xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 55184)
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*55184Smckusick  *	@(#)nfs_vnops.c	7.89 (Berkeley) 07/13/92
1138414Smckusick  */
1238414Smckusick 
1338414Smckusick /*
1438414Smckusick  * vnode op calls for sun nfs version 2
1538414Smckusick  */
1638414Smckusick 
1753322Smckusick #include <sys/param.h>
1853322Smckusick #include <sys/proc.h>
1953322Smckusick #include <sys/kernel.h>
2053322Smckusick #include <sys/systm.h>
2153322Smckusick #include <sys/mount.h>
2253322Smckusick #include <sys/buf.h>
2353322Smckusick #include <sys/malloc.h>
2453322Smckusick #include <sys/mbuf.h>
2553322Smckusick #include <sys/conf.h>
2653322Smckusick #include <sys/namei.h>
2753322Smckusick #include <sys/vnode.h>
2853322Smckusick #include <sys/map.h>
2954740Smckusick #include <sys/dirent.h>
3047573Skarels 
3153322Smckusick #include <vm/vm.h>
3238414Smckusick 
3355041Smckusick #include <miscfs/specfs/specdev.h>
3455041Smckusick #include <miscfs/fifofs/fifo.h>
3555041Smckusick 
3653322Smckusick #include <nfs/rpcv2.h>
3753322Smckusick #include <nfs/nfsv2.h>
3853322Smckusick #include <nfs/nfs.h>
3953322Smckusick #include <nfs/nfsnode.h>
4053322Smckusick #include <nfs/nfsmount.h>
4153322Smckusick #include <nfs/xdr_subs.h>
4253322Smckusick #include <nfs/nfsm_subs.h>
4353322Smckusick #include <nfs/nqnfs.h>
4453322Smckusick 
4538414Smckusick /* Defs */
4638414Smckusick #define	TRUE	1
4738414Smckusick #define	FALSE	0
4838414Smckusick 
4948054Smckusick /*
5048054Smckusick  * Global vfs data structures for nfs
5148054Smckusick  */
5253554Sheideman int (**nfsv2_vnodeop_p)();
5353554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
5453554Sheideman 	{ &vop_default_desc, vn_default_error },
5553806Smckusick 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
5653806Smckusick 	{ &vop_create_desc, nfs_create },	/* create */
5753554Sheideman 	{ &vop_mknod_desc, nfs_mknod },		/* mknod */
5853554Sheideman 	{ &vop_open_desc, nfs_open },		/* open */
5953554Sheideman 	{ &vop_close_desc, nfs_close },		/* close */
6053806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
6153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
6253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
6353554Sheideman 	{ &vop_read_desc, nfs_read },		/* read */
6453554Sheideman 	{ &vop_write_desc, nfs_write },		/* write */
6553554Sheideman 	{ &vop_ioctl_desc, nfs_ioctl },		/* ioctl */
6653806Smckusick 	{ &vop_select_desc, nfs_select },	/* select */
6753554Sheideman 	{ &vop_mmap_desc, nfs_mmap },		/* mmap */
6853554Sheideman 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
6953554Sheideman 	{ &vop_seek_desc, nfs_seek },		/* seek */
7053806Smckusick 	{ &vop_remove_desc, nfs_remove },	/* remove */
7153554Sheideman 	{ &vop_link_desc, nfs_link },		/* link */
7253806Smckusick 	{ &vop_rename_desc, nfs_rename },	/* rename */
7353554Sheideman 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
7453554Sheideman 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
7553806Smckusick 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
7653806Smckusick 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
7753806Smckusick 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
7853806Smckusick 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
7953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
8053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
8153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
8253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
8353554Sheideman 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
8453806Smckusick 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
8553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
8653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
8753806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
8853806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
8953806Smckusick 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
9053554Sheideman 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
9153806Smckusick 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
9253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
9353582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
9453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
9538414Smckusick };
9653554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
9753554Sheideman 	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
9838414Smckusick 
9948054Smckusick /*
10048054Smckusick  * Special device vnode ops
10148054Smckusick  */
10253554Sheideman int (**spec_nfsv2nodeop_p)();
10353554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
10453554Sheideman 	{ &vop_default_desc, vn_default_error },
10553806Smckusick 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
10653806Smckusick 	{ &vop_create_desc, spec_create },	/* create */
10753806Smckusick 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
10853554Sheideman 	{ &vop_open_desc, spec_open },		/* open */
10953806Smckusick 	{ &vop_close_desc, nfsspec_close },	/* close */
11053806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
11153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
11253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
11353806Smckusick 	{ &vop_read_desc, nfsspec_read },	/* read */
11453806Smckusick 	{ &vop_write_desc, nfsspec_write },	/* write */
11553806Smckusick 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
11653806Smckusick 	{ &vop_select_desc, spec_select },	/* select */
11753554Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
11854451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
11953554Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
12053806Smckusick 	{ &vop_remove_desc, spec_remove },	/* remove */
12153554Sheideman 	{ &vop_link_desc, spec_link },		/* link */
12253806Smckusick 	{ &vop_rename_desc, spec_rename },	/* rename */
12353806Smckusick 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
12453806Smckusick 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
12553806Smckusick 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
12653806Smckusick 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
12753806Smckusick 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
12853806Smckusick 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
12953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
13053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
13153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
13253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
13353554Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
13453806Smckusick 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
13553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
13653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
13753806Smckusick 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
13853806Smckusick 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
13953806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
14053806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
14153806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
14253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
14353582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
14453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
14538414Smckusick };
14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
14753554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
14838414Smckusick 
14940294Smckusick #ifdef FIFO
15053554Sheideman int (**fifo_nfsv2nodeop_p)();
15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
15253554Sheideman 	{ &vop_default_desc, vn_default_error },
15353806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
15453806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
15553806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
15653554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
15753806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
15853806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
15953806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
16053806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
16153806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
16253806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
16353806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
16453806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
16553554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
16654451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
16753554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
16853806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
16953554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
17053806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
17153806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
17253806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
17353806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
17453806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
17553806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
17653806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
17753806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
17853806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
17953554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
18053806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
18153554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
18253806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
18353554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
18453806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
18553806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
18653806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
18753806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
18853806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
18953806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
19053806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
19153582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
19253554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
19340294Smckusick };
19453554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
19553554Sheideman 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
19640294Smckusick #endif /* FIFO */
19740294Smckusick 
19848054Smckusick /*
19952196Smckusick  * Global variables
20048054Smckusick  */
20138414Smckusick extern u_long nfs_procids[NFS_NPROCS];
20238414Smckusick extern u_long nfs_prog, nfs_vers;
20338414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
20438884Smacklem struct buf nfs_bqueue;		/* Queue head for nfsiod's */
20541905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
20646988Smckusick int nfs_numasync = 0;
20754740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
20838414Smckusick 
20938414Smckusick /*
21038414Smckusick  * nfs null call from vfs.
21138414Smckusick  */
21252234Sheideman int
21352196Smckusick nfs_null(vp, cred, procp)
21438414Smckusick 	struct vnode *vp;
21538414Smckusick 	struct ucred *cred;
21652196Smckusick 	struct proc *procp;
21738414Smckusick {
21839488Smckusick 	caddr_t bpos, dpos;
21939488Smckusick 	int error = 0;
22039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22138414Smckusick 
22252196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22352196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
22438414Smckusick 	nfsm_reqdone;
22538414Smckusick 	return (error);
22638414Smckusick }
22738414Smckusick 
22838414Smckusick /*
22938414Smckusick  * nfs access vnode op.
23038414Smckusick  * Essentially just get vattr and then imitate iaccess()
23138414Smckusick  */
23252234Sheideman int
23353806Smckusick nfs_access(ap)
23454668Smckusick 	struct vop_access_args /* {
23554668Smckusick 		struct vnode *a_vp;
23654668Smckusick 		int  a_mode;
23754668Smckusick 		struct ucred *a_cred;
23854668Smckusick 		struct proc *a_p;
23954668Smckusick 	} */ *ap;
24038414Smckusick {
24138414Smckusick 	register struct vattr *vap;
24238414Smckusick 	register gid_t *gp;
24353806Smckusick 	register struct ucred *cred = ap->a_cred;
24453806Smckusick 	mode_t mode = ap->a_mode;
24538414Smckusick 	struct vattr vattr;
24638414Smckusick 	register int i;
24738414Smckusick 	int error;
24838414Smckusick 
24938414Smckusick 	/*
25038414Smckusick 	 * If you're the super-user,
25138414Smckusick 	 * you always get access.
25238414Smckusick 	 */
25353806Smckusick 	if (cred->cr_uid == 0)
25438414Smckusick 		return (0);
25538414Smckusick 	vap = &vattr;
25653806Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
25738884Smacklem 		return (error);
25838414Smckusick 	/*
25938414Smckusick 	 * Access check is based on only one of owner, group, public.
26038414Smckusick 	 * If not owner, then check group. If not a member of the
26138414Smckusick 	 * group, then check public access.
26238414Smckusick 	 */
26353806Smckusick 	if (cred->cr_uid != vap->va_uid) {
26453806Smckusick 		mode >>= 3;
26553806Smckusick 		gp = cred->cr_groups;
26653806Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
26738414Smckusick 			if (vap->va_gid == *gp)
26838414Smckusick 				goto found;
26953806Smckusick 		mode >>= 3;
27038414Smckusick found:
27138414Smckusick 		;
27238414Smckusick 	}
27353806Smckusick 	if ((vap->va_mode & mode) != 0)
27438414Smckusick 		return (0);
27538414Smckusick 	return (EACCES);
27638414Smckusick }
27738414Smckusick 
27838414Smckusick /*
27938414Smckusick  * nfs open vnode op
28038414Smckusick  * Just check to see if the type is ok
28152196Smckusick  * and that deletion is not in progress.
28238414Smckusick  */
28339488Smckusick /* ARGSUSED */
28452234Sheideman int
28553806Smckusick nfs_open(ap)
28654668Smckusick 	struct vop_open_args /* {
28754668Smckusick 		struct vnode *a_vp;
28854668Smckusick 		int  a_mode;
28954668Smckusick 		struct ucred *a_cred;
29054668Smckusick 		struct proc *a_p;
29154668Smckusick 	} */ *ap;
29238414Smckusick {
29353806Smckusick 	register struct vnode *vp = ap->a_vp;
29438414Smckusick 
29553806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
29638414Smckusick 		return (EACCES);
29753806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
29853806Smckusick 		VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */
29952196Smckusick 	return (0);
30038414Smckusick }
30138414Smckusick 
30238414Smckusick /*
30338414Smckusick  * nfs close vnode op
30438884Smacklem  * For reg files, invalidate any buffer cache entries.
30538414Smckusick  */
30639488Smckusick /* ARGSUSED */
30752234Sheideman int
30853806Smckusick nfs_close(ap)
30954451Smckusick 	struct vop_close_args /* {
31054451Smckusick 		struct vnodeop_desc *a_desc;
31154451Smckusick 		struct vnode *a_vp;
31254451Smckusick 		int  a_fflag;
31354451Smckusick 		struct ucred *a_cred;
31454451Smckusick 		struct proc *a_p;
31554451Smckusick 	} */ *ap;
31638414Smckusick {
31753806Smckusick 	register struct vnode *vp = ap->a_vp;
31853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
31939341Smckusick 	int error = 0;
32038414Smckusick 
32153806Smckusick 	if (vp->v_type == VREG) {
32253806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
32353629Smckusick 		(np->n_flag & NMODIFIED)) {
32454451Smckusick 		error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32541905Smckusick 		np->n_flag &= ~NMODIFIED;
32641905Smckusick 		np->n_attrstamp = 0;
32753629Smckusick 	    }
32853629Smckusick 	    if (np->n_flag & NWRITEERR) {
32953629Smckusick 		np->n_flag &= ~NWRITEERR;
33053629Smckusick 		error = np->n_error;
33153629Smckusick 	    }
33238884Smacklem 	}
33338414Smckusick 	return (error);
33438414Smckusick }
33538414Smckusick 
33638414Smckusick /*
33738414Smckusick  * nfs getattr call from vfs.
33838414Smckusick  */
33952234Sheideman int
34053805Smckusick nfs_getattr(ap)
34154668Smckusick 	struct vop_getattr_args /* {
34254668Smckusick 		struct vnode *a_vp;
34354668Smckusick 		struct vattr *a_vap;
34454668Smckusick 		struct ucred *a_cred;
34554668Smckusick 		struct proc *a_p;
34654668Smckusick 	} */ *ap;
34738414Smckusick {
34853805Smckusick 	register struct vnode *vp = ap->a_vp;
34953805Smckusick 	register struct nfsnode *np = VTONFS(vp);
35039488Smckusick 	register caddr_t cp;
35139488Smckusick 	caddr_t bpos, dpos;
35239488Smckusick 	int error = 0;
35339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
35438414Smckusick 
35553805Smckusick 	/*
35653805Smckusick 	 * Update local times for special files.
35753805Smckusick 	 */
35853805Smckusick 	if (np->n_flag & (NACC | NUPD)) {
35953805Smckusick 		if (np->n_flag & NACC)
36053805Smckusick 			np->n_atim = time;
36153805Smckusick 		if (np->n_flag & NUPD)
36253805Smckusick 			np->n_mtim = time;
36353805Smckusick 		np->n_flag |= NCHG;
36453805Smckusick 	}
36553805Smckusick 	/*
36653805Smckusick 	 * First look in the cache.
36753805Smckusick 	 */
36853805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
36938414Smckusick 		return (0);
37038414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
37153805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
37253805Smckusick 	nfsm_fhtom(vp);
37353805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
37453805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
37538414Smckusick 	nfsm_reqdone;
37638414Smckusick 	return (error);
37738414Smckusick }
37838414Smckusick 
37938414Smckusick /*
38038414Smckusick  * nfs setattr call.
38138414Smckusick  */
38252234Sheideman int
38353806Smckusick nfs_setattr(ap)
38454451Smckusick 	struct vop_setattr_args /* {
38554451Smckusick 		struct vnodeop_desc *a_desc;
38654451Smckusick 		struct vnode *a_vp;
38754451Smckusick 		struct vattr *a_vap;
38854451Smckusick 		struct ucred *a_cred;
38954451Smckusick 		struct proc *a_p;
39054451Smckusick 	} */ *ap;
39138414Smckusick {
39238884Smacklem 	register struct nfsv2_sattr *sp;
39339488Smckusick 	register caddr_t cp;
39439488Smckusick 	register long t1;
39552196Smckusick 	caddr_t bpos, dpos, cp2;
39652196Smckusick 	u_long *tl;
39739488Smckusick 	int error = 0;
39839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
39953806Smckusick 	register struct vnode *vp = ap->a_vp;
40053806Smckusick 	register struct nfsnode *np = VTONFS(vp);
40153806Smckusick 	register struct vattr *vap = ap->a_vap;
40252196Smckusick 	u_quad_t frev;
40338414Smckusick 
40438414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
40553806Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR);
40653806Smckusick 	nfsm_fhtom(vp);
40738884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
40853806Smckusick 	if (vap->va_mode == 0xffff)
40938884Smacklem 		sp->sa_mode = VNOVAL;
41038414Smckusick 	else
41153806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
41253806Smckusick 	if (vap->va_uid == 0xffff)
41338884Smacklem 		sp->sa_uid = VNOVAL;
41438414Smckusick 	else
41553806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
41653806Smckusick 	if (vap->va_gid == 0xffff)
41738884Smacklem 		sp->sa_gid = VNOVAL;
41838414Smckusick 	else
41953806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
42053806Smckusick 	sp->sa_size = txdr_unsigned(vap->va_size);
42154106Smckusick 	sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.ts_sec);
42253806Smckusick 	sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
42353806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
42454106Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
42554106Smckusick 	    vap->va_atime.ts_sec != VNOVAL) {
42639359Smckusick 		if (np->n_flag & NMODIFIED) {
42753806Smckusick 			if (vap->va_size == 0)
42854451Smckusick 				error =
42954451Smckusick 				    vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p);
43046988Smckusick 			else
43154451Smckusick 				error =
43254451Smckusick 				    vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
43354451Smckusick 			np->n_flag &= ~NMODIFIED;
43439359Smckusick 		}
43539359Smckusick 	}
43653806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
43753806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
43853806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
43953806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
44052196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
44152196Smckusick 		fxdr_hyper(tl, &frev);
44254451Smckusick 		if (frev > np->n_brev)
44352196Smckusick 			np->n_brev = frev;
44452196Smckusick 	}
44538414Smckusick 	nfsm_reqdone;
44638414Smckusick 	return (error);
44738414Smckusick }
44838414Smckusick 
44938414Smckusick /*
45038414Smckusick  * nfs lookup call, one step at a time...
45138414Smckusick  * First look in cache
45238414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
45338414Smckusick  */
45452234Sheideman int
45553806Smckusick nfs_lookup(ap)
45654451Smckusick 	struct vop_lookup_args /* {
45754451Smckusick 		struct vnodeop_desc *a_desc;
45854451Smckusick 		struct vnode *a_dvp;
45954451Smckusick 		struct vnode **a_vpp;
46054451Smckusick 		struct componentname *a_cnp;
46154451Smckusick 	} */ *ap;
46238414Smckusick {
46353806Smckusick 	register struct componentname *cnp = ap->a_cnp;
46453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
46554668Smckusick 	register struct vnode **vpp = ap->a_vpp;
466*55184Smckusick 	register int flags = cnp->cn_flags;
46738414Smckusick 	register struct vnode *vdp;
46848054Smckusick 	register u_long *tl;
46939488Smckusick 	register caddr_t cp;
47039488Smckusick 	register long t1, t2;
47152196Smckusick 	struct nfsmount *nmp;
47252196Smckusick 	struct nfsnode *tp;
47339488Smckusick 	caddr_t bpos, dpos, cp2;
47452196Smckusick 	time_t reqtime;
47539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
47638414Smckusick 	struct vnode *newvp;
47738414Smckusick 	long len;
47838414Smckusick 	nfsv2fh_t *fhp;
47938414Smckusick 	struct nfsnode *np;
48052234Sheideman 	int lockparent, wantparent, error = 0;
48152196Smckusick 	int nqlflag, cachable;
48252196Smckusick 	u_quad_t frev;
48338414Smckusick 
48454668Smckusick 	*vpp = NULL;
48553806Smckusick 	if (dvp->v_type != VDIR)
48638414Smckusick 		return (ENOTDIR);
487*55184Smckusick 	lockparent = flags & LOCKPARENT;
488*55184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
48953806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
49053806Smckusick 	np = VTONFS(dvp);
49154668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
49238884Smacklem 		struct vattr vattr;
49338884Smacklem 		int vpid;
49438884Smacklem 
49554668Smckusick 		vdp = *vpp;
49638884Smacklem 		vpid = vdp->v_id;
49738414Smckusick 		/*
49838884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
49938884Smacklem 		 * for an explanation of the locking protocol
50038414Smckusick 		 */
50153806Smckusick 		if (dvp == vdp) {
50238425Smckusick 			VREF(vdp);
50339441Smckusick 			error = 0;
50452196Smckusick 		} else
50539441Smckusick 			error = vget(vdp);
50639441Smckusick 		if (!error) {
50740251Smckusick 			if (vpid == vdp->v_id) {
50852196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
50953806Smckusick 			        if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
51054451Smckusick 					if (np->n_lrev != np->n_brev ||
51152196Smckusick 					    (np->n_flag & NMODIFIED)) {
51252196Smckusick 						np->n_direofoffset = 0;
51353806Smckusick 						cache_purge(dvp);
51454451Smckusick 						error = vinvalbuf(dvp, FALSE,
51554451Smckusick 						    cnp->cn_cred, cnp->cn_proc);
51652196Smckusick 						np->n_flag &= ~NMODIFIED;
51752196Smckusick 						np->n_brev = np->n_lrev;
51852196Smckusick 					} else {
51952196Smckusick 						nfsstats.lookupcache_hits++;
52053806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
521*55184Smckusick 						    (flags & ISLASTCN))
52253806Smckusick 						    cnp->cn_flags |= SAVENAME;
52352196Smckusick 						return (0);
52452196Smckusick 					}
52552196Smckusick 				}
52653806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
52754106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
52839441Smckusick 				nfsstats.lookupcache_hits++;
52953806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
530*55184Smckusick 				    (flags & ISLASTCN))
53153806Smckusick 					cnp->cn_flags |= SAVENAME;
53239441Smckusick 				return (0);
53340251Smckusick 			   }
53447289Smckusick 			   cache_purge(vdp);
53539441Smckusick 			}
53652196Smckusick 			vrele(vdp);
53738884Smacklem 		}
53854668Smckusick 		*vpp = NULLVP;
53952196Smckusick 	}
54039341Smckusick 	error = 0;
54138414Smckusick 	nfsstats.lookupcache_misses++;
54238414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
54353806Smckusick 	len = cnp->cn_namelen;
54453806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
54552196Smckusick 
54652196Smckusick 	/*
54752196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
54852196Smckusick 	 * being looked up.
54952196Smckusick 	 */
55052196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
55152196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
552*55184Smckusick 		    ((cnp->cn_flags & MAKEENTRY) &&
553*55184Smckusick 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) {
55452196Smckusick 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
55552196Smckusick 			*tl++ = txdr_unsigned(NQL_READ);
55652196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
55752196Smckusick 		} else {
55852196Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
55952196Smckusick 			*tl = 0;
56052196Smckusick 		}
56152196Smckusick 	}
56253806Smckusick 	nfsm_fhtom(dvp);
56353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
56452196Smckusick 	reqtime = time.tv_sec;
56553806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
56638414Smckusick nfsmout:
56738414Smckusick 	if (error) {
56853806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
569*55184Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
57052823Smckusick 			error = EJUSTRETURN;
571*55184Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
57253806Smckusick 			cnp->cn_flags |= SAVENAME;
57340483Smckusick 		return (error);
57438414Smckusick 	}
57552196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
57652196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
57752196Smckusick 		if (*tl) {
57852196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
57952196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
58052196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
58152196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
58252196Smckusick 			fxdr_hyper(tl, &frev);
58352196Smckusick 		} else
58452196Smckusick 			nqlflag = 0;
58552196Smckusick 	}
58652196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
58738414Smckusick 
58838414Smckusick 	/*
58952196Smckusick 	 * Handle RENAME case...
59038414Smckusick 	 */
591*55184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
59252196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
59338414Smckusick 			m_freem(mrep);
59438414Smckusick 			return (EISDIR);
59538414Smckusick 		}
59653806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
59738414Smckusick 			m_freem(mrep);
59838414Smckusick 			return (error);
59938414Smckusick 		}
60038414Smckusick 		newvp = NFSTOV(np);
60139459Smckusick 		if (error =
60239459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
60352196Smckusick 			vrele(newvp);
60438414Smckusick 			m_freem(mrep);
60538414Smckusick 			return (error);
60638414Smckusick 		}
60754668Smckusick 		*vpp = newvp;
60845037Smckusick 		m_freem(mrep);
60953806Smckusick 		cnp->cn_flags |= SAVENAME;
61038414Smckusick 		return (0);
61138414Smckusick 	}
61238414Smckusick 
61352196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
61453806Smckusick 		VREF(dvp);
61553806Smckusick 		newvp = dvp;
61638414Smckusick 	} else {
61753806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
61838414Smckusick 			m_freem(mrep);
61938414Smckusick 			return (error);
62038414Smckusick 		}
62138414Smckusick 		newvp = NFSTOV(np);
62238414Smckusick 	}
62339459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
62452196Smckusick 		vrele(newvp);
62538414Smckusick 		m_freem(mrep);
62638414Smckusick 		return (error);
62738414Smckusick 	}
62838414Smckusick 	m_freem(mrep);
62954668Smckusick 	*vpp = newvp;
630*55184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
63153806Smckusick 		cnp->cn_flags |= SAVENAME;
632*55184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
633*55184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
63452196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
63554106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
63652196Smckusick 		else if (nqlflag && reqtime > time.tv_sec) {
63752196Smckusick 			if (np->n_tnext) {
63852196Smckusick 				if (np->n_tnext == (struct nfsnode *)nmp)
63952196Smckusick 					nmp->nm_tprev = np->n_tprev;
64052196Smckusick 				else
64152196Smckusick 					np->n_tnext->n_tprev = np->n_tprev;
64252196Smckusick 				if (np->n_tprev == (struct nfsnode *)nmp)
64352196Smckusick 					nmp->nm_tnext = np->n_tnext;
64452196Smckusick 				else
64552196Smckusick 					np->n_tprev->n_tnext = np->n_tnext;
64652196Smckusick 				if (nqlflag == NQL_WRITE)
64752196Smckusick 					np->n_flag |= NQNFSWRITE;
64852196Smckusick 			} else if (nqlflag == NQL_READ)
64952196Smckusick 				np->n_flag &= ~NQNFSWRITE;
65052196Smckusick 			else
65152196Smckusick 				np->n_flag |= NQNFSWRITE;
65252196Smckusick 			if (cachable)
65352196Smckusick 				np->n_flag &= ~NQNFSNONCACHE;
65452196Smckusick 			else
65552196Smckusick 				np->n_flag |= NQNFSNONCACHE;
65652196Smckusick 			np->n_expiry = reqtime;
65752196Smckusick 			np->n_lrev = frev;
65852196Smckusick 			tp = nmp->nm_tprev;
65952196Smckusick 			while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
66052196Smckusick 				tp = tp->n_tprev;
66152196Smckusick 			if (tp == (struct nfsnode *)nmp) {
66252196Smckusick 				np->n_tnext = nmp->nm_tnext;
66352196Smckusick 				nmp->nm_tnext = np;
66452196Smckusick 			} else {
66552196Smckusick 				np->n_tnext = tp->n_tnext;
66652196Smckusick 				tp->n_tnext = np;
66752196Smckusick 			}
66852196Smckusick 			np->n_tprev = tp;
66952196Smckusick 			if (np->n_tnext == (struct nfsnode *)nmp)
67052196Smckusick 				nmp->nm_tprev = np;
67152196Smckusick 			else
67252196Smckusick 				np->n_tnext->n_tprev = np;
67352196Smckusick 		}
67454668Smckusick 		cache_enter(dvp, *vpp, cnp);
67540251Smckusick 	}
67652196Smckusick 	return (0);
67738414Smckusick }
67838414Smckusick 
67938414Smckusick /*
68041905Smckusick  * nfs read call.
68141905Smckusick  * Just call nfs_bioread() to do the work.
68241905Smckusick  */
68352234Sheideman int
68453806Smckusick nfs_read(ap)
68554668Smckusick 	struct vop_read_args /* {
68654668Smckusick 		struct vnode *a_vp;
68754668Smckusick 		struct uio *a_uio;
68854668Smckusick 		int  a_ioflag;
68954668Smckusick 		struct ucred *a_cred;
69054668Smckusick 	} */ *ap;
69141905Smckusick {
69253806Smckusick 	register struct vnode *vp = ap->a_vp;
69353806Smckusick 
69453806Smckusick 	if (vp->v_type != VREG)
69541905Smckusick 		return (EPERM);
69653806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
69741905Smckusick }
69841905Smckusick 
69941905Smckusick /*
70038414Smckusick  * nfs readlink call
70138414Smckusick  */
70252234Sheideman int
70353806Smckusick nfs_readlink(ap)
70454668Smckusick 	struct vop_readlink_args /* {
70554668Smckusick 		struct vnode *a_vp;
70654668Smckusick 		struct uio *a_uio;
70754668Smckusick 		struct ucred *a_cred;
70854668Smckusick 	} */ *ap;
70941905Smckusick {
71053806Smckusick 	register struct vnode *vp = ap->a_vp;
71153806Smckusick 
71253806Smckusick 	if (vp->v_type != VLNK)
71341905Smckusick 		return (EPERM);
71453806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
71541905Smckusick }
71641905Smckusick 
71741905Smckusick /*
71841905Smckusick  * Do a readlink rpc.
71941905Smckusick  * Called by nfs_doio() from below the buffer cache.
72041905Smckusick  */
72152234Sheideman int
72248054Smckusick nfs_readlinkrpc(vp, uiop, cred)
72339488Smckusick 	register struct vnode *vp;
72438414Smckusick 	struct uio *uiop;
72538414Smckusick 	struct ucred *cred;
72638414Smckusick {
72748054Smckusick 	register u_long *tl;
72839488Smckusick 	register caddr_t cp;
72939488Smckusick 	register long t1;
73039488Smckusick 	caddr_t bpos, dpos, cp2;
73139488Smckusick 	int error = 0;
73239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
73338414Smckusick 	long len;
73438414Smckusick 
73538414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
73652196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
73738414Smckusick 	nfsm_fhtom(vp);
73852196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
73938414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
74038414Smckusick 	nfsm_mtouio(uiop, len);
74138414Smckusick 	nfsm_reqdone;
74238414Smckusick 	return (error);
74338414Smckusick }
74438414Smckusick 
74538414Smckusick /*
74641905Smckusick  * nfs read rpc call
74741905Smckusick  * Ditto above
74838414Smckusick  */
74952234Sheideman int
75048054Smckusick nfs_readrpc(vp, uiop, cred)
75139488Smckusick 	register struct vnode *vp;
75238414Smckusick 	struct uio *uiop;
75338414Smckusick 	struct ucred *cred;
75438414Smckusick {
75548054Smckusick 	register u_long *tl;
75639488Smckusick 	register caddr_t cp;
75739488Smckusick 	register long t1;
75839488Smckusick 	caddr_t bpos, dpos, cp2;
75939488Smckusick 	int error = 0;
76039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
76138414Smckusick 	struct nfsmount *nmp;
76238414Smckusick 	long len, retlen, tsiz;
76338414Smckusick 
76441398Smckusick 	nmp = VFSTONFS(vp->v_mount);
76538414Smckusick 	tsiz = uiop->uio_resid;
76638414Smckusick 	while (tsiz > 0) {
76738414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
76838414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
76952196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
77038414Smckusick 		nfsm_fhtom(vp);
77148054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
77248054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
77348054Smckusick 		*tl++ = txdr_unsigned(len);
77448054Smckusick 		*tl = 0;
77552196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
77638414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
77738414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
77838414Smckusick 		nfsm_mtouio(uiop, retlen);
77938414Smckusick 		m_freem(mrep);
78038414Smckusick 		if (retlen < len)
78138414Smckusick 			tsiz = 0;
78238414Smckusick 		else
78338414Smckusick 			tsiz -= len;
78438414Smckusick 	}
78538414Smckusick nfsmout:
78638414Smckusick 	return (error);
78738414Smckusick }
78838414Smckusick 
78938414Smckusick /*
79038414Smckusick  * nfs write call
79138414Smckusick  */
79252234Sheideman int
79348054Smckusick nfs_writerpc(vp, uiop, cred)
79439488Smckusick 	register struct vnode *vp;
79538414Smckusick 	struct uio *uiop;
79638414Smckusick 	struct ucred *cred;
79738414Smckusick {
79848054Smckusick 	register u_long *tl;
79939488Smckusick 	register caddr_t cp;
80039488Smckusick 	register long t1;
80152196Smckusick 	caddr_t bpos, dpos, cp2;
80239488Smckusick 	int error = 0;
80339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
80438414Smckusick 	struct nfsmount *nmp;
80552196Smckusick 	struct nfsnode *np = VTONFS(vp);
80652196Smckusick 	u_quad_t frev;
80738414Smckusick 	long len, tsiz;
80838414Smckusick 
80941398Smckusick 	nmp = VFSTONFS(vp->v_mount);
81038414Smckusick 	tsiz = uiop->uio_resid;
81138414Smckusick 	while (tsiz > 0) {
81238414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
81338414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
81452196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
81552196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
81638414Smckusick 		nfsm_fhtom(vp);
81748054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
81848054Smckusick 		*(tl+1) = txdr_unsigned(uiop->uio_offset);
81948054Smckusick 		*(tl+3) = txdr_unsigned(len);
82038414Smckusick 		nfsm_uiotom(uiop, len);
82152196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
82238414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
82352196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
82454106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
82552196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
82652196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
82752196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
82852196Smckusick 			fxdr_hyper(tl, &frev);
82954451Smckusick 			if (frev > np->n_brev)
83052196Smckusick 				np->n_brev = frev;
83152196Smckusick 		}
83238414Smckusick 		m_freem(mrep);
83338414Smckusick 		tsiz -= len;
83438414Smckusick 	}
83538414Smckusick nfsmout:
83652196Smckusick 	if (error)
83752196Smckusick 		uiop->uio_resid = tsiz;
83838414Smckusick 	return (error);
83938414Smckusick }
84038414Smckusick 
84138414Smckusick /*
84239459Smckusick  * nfs mknod call
84342246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
84442246Smckusick  * set to specify the file type and the size field for rdev.
84539459Smckusick  */
84639459Smckusick /* ARGSUSED */
84752234Sheideman int
84853806Smckusick nfs_mknod(ap)
84954668Smckusick 	struct vop_mknod_args /* {
85054668Smckusick 		struct vnode *a_dvp;
85154668Smckusick 		struct vnode **a_vpp;
85254668Smckusick 		struct componentname *a_cnp;
85354668Smckusick 		struct vattr *a_vap;
85454668Smckusick 	} */ *ap;
85539459Smckusick {
85653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
85753806Smckusick 	register struct vattr *vap = ap->a_vap;
85853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
85942246Smckusick 	register struct nfsv2_sattr *sp;
86048054Smckusick 	register u_long *tl;
86142246Smckusick 	register caddr_t cp;
86252196Smckusick 	register long t2;
86342246Smckusick 	caddr_t bpos, dpos;
86442246Smckusick 	int error = 0;
86542246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
86642246Smckusick 	u_long rdev;
86739459Smckusick 
86853806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
86953806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
87042246Smckusick #ifdef FIFO
87153806Smckusick 	else if (vap->va_type == VFIFO)
87242246Smckusick 		rdev = 0xffffffff;
87342246Smckusick #endif /* FIFO */
87442246Smckusick 	else {
87553806Smckusick 		VOP_ABORTOP(dvp, cnp);
87653806Smckusick 		vput(dvp);
87742246Smckusick 		return (EOPNOTSUPP);
87842246Smckusick 	}
87942246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
88053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
88153806Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
88253806Smckusick 	nfsm_fhtom(dvp);
88353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
88442246Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
88553806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
88653806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
88753806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
88842246Smckusick 	sp->sa_size = rdev;
88942246Smckusick 	/* or should these be VNOVAL ?? */
89053806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
89153806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
89253806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
89342246Smckusick 	nfsm_reqdone;
89453806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
89553806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
89653806Smckusick 	vrele(dvp);
89742246Smckusick 	return (error);
89839459Smckusick }
89939459Smckusick 
90039459Smckusick /*
90138414Smckusick  * nfs file create call
90238414Smckusick  */
90352234Sheideman int
90453806Smckusick nfs_create(ap)
90554668Smckusick 	struct vop_create_args /* {
90654668Smckusick 		struct vnode *a_dvp;
90754668Smckusick 		struct vnode **a_vpp;
90854668Smckusick 		struct componentname *a_cnp;
90954668Smckusick 		struct vattr *a_vap;
91054668Smckusick 	} */ *ap;
91138414Smckusick {
91253806Smckusick 	register struct vnode *dvp = ap->a_dvp;
91353806Smckusick 	register struct vattr *vap = ap->a_vap;
91453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
91538884Smacklem 	register struct nfsv2_sattr *sp;
91648054Smckusick 	register u_long *tl;
91739488Smckusick 	register caddr_t cp;
91839488Smckusick 	register long t1, t2;
91939488Smckusick 	caddr_t bpos, dpos, cp2;
92039488Smckusick 	int error = 0;
92139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
92238414Smckusick 
92338414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
92453806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
92553806Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
92653806Smckusick 	nfsm_fhtom(dvp);
92753806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
92838884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
92953806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
93053806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
93153806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
93238884Smacklem 	sp->sa_size = txdr_unsigned(0);
93338414Smckusick 	/* or should these be VNOVAL ?? */
93453806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
93553806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
93653806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
93753806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
93838414Smckusick 	nfsm_reqdone;
93953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
94053806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
94153806Smckusick 	vrele(dvp);
94238414Smckusick 	return (error);
94338414Smckusick }
94438414Smckusick 
94538414Smckusick /*
94638414Smckusick  * nfs file remove call
94741905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
94841905Smckusick  * other processes using the vnode is renamed instead of removed and then
94939341Smckusick  * removed later on the last close.
95041905Smckusick  * - If v_usecount > 1
95139341Smckusick  *	  If a rename is not already in the works
95239341Smckusick  *	     call nfs_sillyrename() to set it up
95339341Smckusick  *     else
95439341Smckusick  *	  do the remove rpc
95538414Smckusick  */
95652234Sheideman int
95753806Smckusick nfs_remove(ap)
95854451Smckusick 	struct vop_remove_args /* {
95954451Smckusick 		struct vnodeop_desc *a_desc;
96054451Smckusick 		struct vnode * a_dvp;
96154451Smckusick 		struct vnode * a_vp;
96254451Smckusick 		struct componentname * a_cnp;
96354451Smckusick 	} */ *ap;
96438414Smckusick {
96553806Smckusick 	register struct vnode *vp = ap->a_vp;
96653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
96753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
96853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
96948054Smckusick 	register u_long *tl;
97039488Smckusick 	register caddr_t cp;
97152196Smckusick 	register long t2;
97239488Smckusick 	caddr_t bpos, dpos;
97339488Smckusick 	int error = 0;
97439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97538414Smckusick 
97653806Smckusick 	if (vp->v_usecount > 1) {
97739341Smckusick 		if (!np->n_sillyrename)
97853806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
97939341Smckusick 	} else {
98052196Smckusick 		/*
98152196Smckusick 		 * Purge the name cache so that the chance of a lookup for
98252196Smckusick 		 * the name succeeding while the remove is in progress is
98352196Smckusick 		 * minimized. Without node locking it can still happen, such
98452196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
98552196Smckusick 		 * another host removes the file..
98652196Smckusick 		 */
98753806Smckusick 		cache_purge(vp);
98852196Smckusick 		/*
98952196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
99052196Smckusick 		 * unnecessary delayed writes.
99152196Smckusick 		 */
99254451Smckusick 		error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc);
99352196Smckusick 		/* Do the rpc */
99438414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
99553806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
99653806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
99753806Smckusick 		nfsm_fhtom(dvp);
99853806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
99953806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
100038414Smckusick 		nfsm_reqdone;
100153806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
100253806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
100339751Smckusick 		/*
100439751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
100539751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
100639751Smckusick 		 *   since the file was in fact removed
100739751Smckusick 		 *   Therefore, we cheat and return success.
100839751Smckusick 		 */
100939751Smckusick 		if (error == ENOENT)
101039751Smckusick 			error = 0;
101138414Smckusick 	}
101240042Smckusick 	np->n_attrstamp = 0;
101353806Smckusick 	vrele(dvp);
101453806Smckusick 	vrele(vp);
101538414Smckusick 	return (error);
101638414Smckusick }
101738414Smckusick 
101838414Smckusick /*
101938414Smckusick  * nfs file remove rpc called from nfs_inactive
102038414Smckusick  */
102152234Sheideman int
102254451Smckusick nfs_removeit(sp)
102348364Smckusick 	register struct sillyrename *sp;
102438414Smckusick {
102548054Smckusick 	register u_long *tl;
102639488Smckusick 	register caddr_t cp;
102752196Smckusick 	register long t2;
102839488Smckusick 	caddr_t bpos, dpos;
102939488Smckusick 	int error = 0;
103039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
103138414Smckusick 
103238414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
103352196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
103448364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
103548364Smckusick 	nfsm_fhtom(sp->s_dvp);
103648364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
103754451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
103838414Smckusick 	nfsm_reqdone;
103948364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
104038414Smckusick 	return (error);
104138414Smckusick }
104238414Smckusick 
104338414Smckusick /*
104438414Smckusick  * nfs file rename call
104538414Smckusick  */
104652234Sheideman int
104753806Smckusick nfs_rename(ap)
104854668Smckusick 	struct vop_rename_args  /* {
104954668Smckusick 		struct vnode *a_fdvp;
105054668Smckusick 		struct vnode *a_fvp;
105154668Smckusick 		struct componentname *a_fcnp;
105254668Smckusick 		struct vnode *a_tdvp;
105354668Smckusick 		struct vnode *a_tvp;
105454668Smckusick 		struct componentname *a_tcnp;
105554668Smckusick 	} */ *ap;
105638414Smckusick {
105753806Smckusick 	register struct vnode *fvp = ap->a_fvp;
105853806Smckusick 	register struct vnode *tvp = ap->a_tvp;
105953806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
106053806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
106153806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
106253806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
106348054Smckusick 	register u_long *tl;
106439488Smckusick 	register caddr_t cp;
106552196Smckusick 	register long t2;
106639488Smckusick 	caddr_t bpos, dpos;
106739488Smckusick 	int error = 0;
106839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
106938414Smckusick 
107053804Spendry 	/* Check for cross-device rename */
107153806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
107253806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
107353804Spendry 		error = EXDEV;
107453804Spendry 		goto out;
107553804Spendry 	}
107653804Spendry 
107753804Spendry 
107838414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
107953806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
108053806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
108153806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
108253806Smckusick 	nfsm_fhtom(fdvp);
108353806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
108453806Smckusick 	nfsm_fhtom(tdvp);
108553806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
108653806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
108738414Smckusick 	nfsm_reqdone;
108853806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
108953806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
109053806Smckusick 	if (fvp->v_type == VDIR) {
109153806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
109253806Smckusick 			cache_purge(tdvp);
109353806Smckusick 		cache_purge(fdvp);
109438414Smckusick 	}
109553804Spendry out:
109653806Smckusick 	if (tdvp == tvp)
109753806Smckusick 		vrele(tdvp);
109843360Smckusick 	else
109953806Smckusick 		vput(tdvp);
110053806Smckusick 	if (tvp)
110153806Smckusick 		vput(tvp);
110253806Smckusick 	vrele(fdvp);
110353806Smckusick 	vrele(fvp);
110440112Smckusick 	/*
110540112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
110640112Smckusick 	 */
110740112Smckusick 	if (error == ENOENT)
110840112Smckusick 		error = 0;
110938414Smckusick 	return (error);
111038414Smckusick }
111138414Smckusick 
111238414Smckusick /*
111341905Smckusick  * nfs file rename rpc called from nfs_remove() above
111438414Smckusick  */
111552234Sheideman int
111652234Sheideman nfs_renameit(sdvp, scnp, sp)
111752234Sheideman 	struct vnode *sdvp;
111852234Sheideman 	struct componentname *scnp;
111948364Smckusick 	register struct sillyrename *sp;
112038414Smckusick {
112148054Smckusick 	register u_long *tl;
112239488Smckusick 	register caddr_t cp;
112352196Smckusick 	register long t2;
112439488Smckusick 	caddr_t bpos, dpos;
112539488Smckusick 	int error = 0;
112639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
112738414Smckusick 
112838414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
112952234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
113052234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
113152196Smckusick 		nfsm_rndup(sp->s_namlen));
113252234Sheideman 	nfsm_fhtom(sdvp);
113352234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
113452234Sheideman 	nfsm_fhtom(sdvp);
113548364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
113652234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
113738414Smckusick 	nfsm_reqdone;
113852234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
113952234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
114038414Smckusick 	return (error);
114138414Smckusick }
114238414Smckusick 
114338414Smckusick /*
114438414Smckusick  * nfs hard link create call
114538414Smckusick  */
114652234Sheideman int
114753806Smckusick nfs_link(ap)
114854668Smckusick 	struct vop_link_args /* {
114954668Smckusick 		struct vnode *a_vp;
115054668Smckusick 		struct vnode *a_tdvp;
115154668Smckusick 		struct componentname *a_cnp;
115254668Smckusick 	} */ *ap;
115338414Smckusick {
115453806Smckusick 	register struct vnode *vp = ap->a_vp;
115553806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
115653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
115748054Smckusick 	register u_long *tl;
115839488Smckusick 	register caddr_t cp;
115952196Smckusick 	register long t2;
116039488Smckusick 	caddr_t bpos, dpos;
116139488Smckusick 	int error = 0;
116239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
116338414Smckusick 
116453806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
116553806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
116653806Smckusick 		if (tdvp == vp)
116753806Smckusick 			vrele(vp);
116853804Spendry 		else
116953806Smckusick 			vput(vp);
117053804Spendry 		return (EXDEV);
117153804Spendry 	}
117253804Spendry 
117338414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
117453806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
117553806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
117653806Smckusick 	nfsm_fhtom(tdvp);
117753806Smckusick 	nfsm_fhtom(vp);
117853806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
117953806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
118038414Smckusick 	nfsm_reqdone;
118153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
118253806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
118353806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
118453806Smckusick 	vrele(vp);
118540112Smckusick 	/*
118640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
118740112Smckusick 	 */
118840112Smckusick 	if (error == EEXIST)
118940112Smckusick 		error = 0;
119038414Smckusick 	return (error);
119138414Smckusick }
119238414Smckusick 
119338414Smckusick /*
119438414Smckusick  * nfs symbolic link create call
119538414Smckusick  */
119652234Sheideman /* start here */
119752234Sheideman int
119853806Smckusick nfs_symlink(ap)
119954668Smckusick 	struct vop_symlink_args /* {
120054668Smckusick 		struct vnode *a_dvp;
120154668Smckusick 		struct vnode **a_vpp;
120254668Smckusick 		struct componentname *a_cnp;
120354668Smckusick 		struct vattr *a_vap;
120454668Smckusick 		char *a_target;
120554668Smckusick 	} */ *ap;
120638414Smckusick {
120753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
120853806Smckusick 	register struct vattr *vap = ap->a_vap;
120953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
121038884Smacklem 	register struct nfsv2_sattr *sp;
121148054Smckusick 	register u_long *tl;
121239488Smckusick 	register caddr_t cp;
121352196Smckusick 	register long t2;
121439488Smckusick 	caddr_t bpos, dpos;
121552196Smckusick 	int slen, error = 0;
121639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
121738414Smckusick 
121838414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
121953600Sheideman 	slen = strlen(ap->a_target);
122053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
122153806Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR);
122253806Smckusick 	nfsm_fhtom(dvp);
122353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
122453600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
122538884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
122653806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
122753806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
122853806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
122938884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
123053806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
123153806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
123253806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
123338414Smckusick 	nfsm_reqdone;
123453806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
123553806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
123653806Smckusick 	vrele(dvp);
123740112Smckusick 	/*
123840112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
123940112Smckusick 	 */
124040112Smckusick 	if (error == EEXIST)
124140112Smckusick 		error = 0;
124238414Smckusick 	return (error);
124338414Smckusick }
124438414Smckusick 
124538414Smckusick /*
124638414Smckusick  * nfs make dir call
124738414Smckusick  */
124852234Sheideman int
124953806Smckusick nfs_mkdir(ap)
125054668Smckusick 	struct vop_mkdir_args /* {
125154668Smckusick 		struct vnode *a_dvp;
125254668Smckusick 		struct vnode **a_vpp;
125354668Smckusick 		struct componentname *a_cnp;
125454668Smckusick 		struct vattr *a_vap;
125554668Smckusick 	} */ *ap;
125638414Smckusick {
125753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
125853806Smckusick 	register struct vattr *vap = ap->a_vap;
125953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
126054668Smckusick 	register struct vnode **vpp = ap->a_vpp;
126138884Smacklem 	register struct nfsv2_sattr *sp;
126248054Smckusick 	register u_long *tl;
126339488Smckusick 	register caddr_t cp;
126439488Smckusick 	register long t1, t2;
126541905Smckusick 	register int len;
126639488Smckusick 	caddr_t bpos, dpos, cp2;
126741905Smckusick 	int error = 0, firsttry = 1;
126839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
126938414Smckusick 
127053806Smckusick 	len = cnp->cn_namelen;
127138414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
127253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
127341905Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
127453806Smckusick 	nfsm_fhtom(dvp);
127553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
127638884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
127753806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
127853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
127953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
128038884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
128153806Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
128253806Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
128353806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
128454668Smckusick 	nfsm_mtofh(dvp, *vpp);
128538414Smckusick 	nfsm_reqdone;
128653806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
128740112Smckusick 	/*
128841905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
128941905Smckusick 	 * if we can succeed in looking up the directory.
129041905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
129141905Smckusick 	 * is above the if on errors. (Ugh)
129240112Smckusick 	 */
129341905Smckusick 	if (error == EEXIST && firsttry) {
129441905Smckusick 		firsttry = 0;
129540112Smckusick 		error = 0;
129641905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
129754668Smckusick 		*vpp = NULL;
129853806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
129941905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
130053806Smckusick 		nfsm_fhtom(dvp);
130153806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
130253806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
130354668Smckusick 		nfsm_mtofh(dvp, *vpp);
130454668Smckusick 		if ((*vpp)->v_type != VDIR) {
130554668Smckusick 			vput(*vpp);
130641905Smckusick 			error = EEXIST;
130741905Smckusick 		}
130841905Smckusick 		m_freem(mrep);
130941905Smckusick 	}
131053806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
131153806Smckusick 	vrele(dvp);
131238414Smckusick 	return (error);
131338414Smckusick }
131438414Smckusick 
131538414Smckusick /*
131638414Smckusick  * nfs remove directory call
131738414Smckusick  */
131852234Sheideman int
131953806Smckusick nfs_rmdir(ap)
132054668Smckusick 	struct vop_rmdir_args /* {
132154668Smckusick 		struct vnode *a_dvp;
132254668Smckusick 		struct vnode *a_vp;
132354668Smckusick 		struct componentname *a_cnp;
132454668Smckusick 	} */ *ap;
132538414Smckusick {
132653806Smckusick 	register struct vnode *vp = ap->a_vp;
132753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
132853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
132948054Smckusick 	register u_long *tl;
133039488Smckusick 	register caddr_t cp;
133152196Smckusick 	register long t2;
133239488Smckusick 	caddr_t bpos, dpos;
133339488Smckusick 	int error = 0;
133439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
133538414Smckusick 
133653806Smckusick 	if (dvp == vp) {
133753806Smckusick 		vrele(dvp);
133853806Smckusick 		vrele(dvp);
133953806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
134038414Smckusick 		return (EINVAL);
134138414Smckusick 	}
134238414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
134353806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
134453806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
134553806Smckusick 	nfsm_fhtom(dvp);
134653806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
134753806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
134838414Smckusick 	nfsm_reqdone;
134953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
135053806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
135153806Smckusick 	cache_purge(dvp);
135253806Smckusick 	cache_purge(vp);
135353806Smckusick 	vrele(vp);
135453806Smckusick 	vrele(dvp);
135540112Smckusick 	/*
135640112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
135740112Smckusick 	 */
135840112Smckusick 	if (error == ENOENT)
135940112Smckusick 		error = 0;
136038414Smckusick 	return (error);
136138414Smckusick }
136238414Smckusick 
136338414Smckusick /*
136438414Smckusick  * nfs readdir call
136538414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
136638414Smckusick  * order so that it looks more sensible. This appears consistent with the
136738414Smckusick  * Ultrix implementation of NFS.
136838414Smckusick  */
136952234Sheideman int
137053806Smckusick nfs_readdir(ap)
137154668Smckusick 	struct vop_readdir_args /* {
137254668Smckusick 		struct vnode *a_vp;
137354668Smckusick 		struct uio *a_uio;
137454668Smckusick 		struct ucred *a_cred;
137554668Smckusick 	} */ *ap;
137638414Smckusick {
137753806Smckusick 	register struct vnode *vp = ap->a_vp;
137853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
137953806Smckusick 	register struct uio *uio = ap->a_uio;
138041905Smckusick 	int tresid, error;
138141905Smckusick 	struct vattr vattr;
138241905Smckusick 
138353806Smckusick 	if (vp->v_type != VDIR)
138441905Smckusick 		return (EPERM);
138541905Smckusick 	/*
138641905Smckusick 	 * First, check for hit on the EOF offset cache
138741905Smckusick 	 */
138853806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
138952196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
139053806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
139153806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
139252196Smckusick 				nfsstats.direofcache_hits++;
139352196Smckusick 				return (0);
139452196Smckusick 			}
139553806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
139654106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
139752196Smckusick 			nfsstats.direofcache_hits++;
139852196Smckusick 			return (0);
139952196Smckusick 		}
140041905Smckusick 	}
140141905Smckusick 
140241905Smckusick 	/*
140341905Smckusick 	 * Call nfs_bioread() to do the real work.
140441905Smckusick 	 */
140553806Smckusick 	tresid = uio->uio_resid;
140653806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
140741905Smckusick 
140854451Smckusick 	if (!error && uio->uio_resid == tresid)
140941905Smckusick 		nfsstats.direofcache_misses++;
141041905Smckusick 	return (error);
141141905Smckusick }
141241905Smckusick 
141341905Smckusick /*
141441905Smckusick  * Readdir rpc call.
141541905Smckusick  * Called from below the buffer cache by nfs_doio().
141641905Smckusick  */
141752234Sheideman int
141848054Smckusick nfs_readdirrpc(vp, uiop, cred)
141941905Smckusick 	register struct vnode *vp;
142041905Smckusick 	struct uio *uiop;
142141905Smckusick 	struct ucred *cred;
142241905Smckusick {
142338414Smckusick 	register long len;
142454740Smckusick 	register struct dirent *dp;
142548054Smckusick 	register u_long *tl;
142639488Smckusick 	register caddr_t cp;
142739488Smckusick 	register long t1;
142841905Smckusick 	long tlen, lastlen;
142939488Smckusick 	caddr_t bpos, dpos, cp2;
143039488Smckusick 	int error = 0;
143139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
143238414Smckusick 	struct mbuf *md2;
143338414Smckusick 	caddr_t dpos2;
143438414Smckusick 	int siz;
143540296Smckusick 	int more_dirs = 1;
143638414Smckusick 	off_t off, savoff;
143754740Smckusick 	struct dirent *savdp;
143840296Smckusick 	struct nfsmount *nmp;
143940296Smckusick 	struct nfsnode *np = VTONFS(vp);
144040296Smckusick 	long tresid;
144138414Smckusick 
144241398Smckusick 	nmp = VFSTONFS(vp->v_mount);
144340296Smckusick 	tresid = uiop->uio_resid;
144440296Smckusick 	/*
144540296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
144648054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
144741905Smckusick 	 * The stopping criteria is EOF or buffer full.
144840296Smckusick 	 */
144948054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
145040296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
145152196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
145252196Smckusick 			NFSX_FH+2*NFSX_UNSIGNED);
145340296Smckusick 		nfsm_fhtom(vp);
145448054Smckusick 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
145548054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
145648054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
145748054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
145852196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
145940296Smckusick 		siz = 0;
146052196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
146148054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
146240296Smckusick 
146340296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
146440296Smckusick 		dpos2 = dpos;
146540296Smckusick 		md2 = md;
146640296Smckusick 
146740296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
146841905Smckusick 		off = uiop->uio_offset;
146942246Smckusick #ifdef lint
147054740Smckusick 		dp = (struct dirent *)0;
147142246Smckusick #endif /* lint */
147240296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
147340296Smckusick 			savoff = off;		/* Hold onto offset and dp */
147440296Smckusick 			savdp = dp;
147552196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
147654740Smckusick 			dp = (struct dirent *)tl;
147754740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
147848054Smckusick 			len = fxdr_unsigned(int, *tl);
147940296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
148040296Smckusick 				error = EBADRPC;
148140296Smckusick 				m_freem(mrep);
148240296Smckusick 				goto nfsmout;
148340296Smckusick 			}
148454986Smckusick 			dp->d_namlen = (u_char)len;
148554986Smckusick 			dp->d_type = DT_UNKNOWN;
148640296Smckusick 			nfsm_adv(len);		/* Point past name */
148740296Smckusick 			tlen = nfsm_rndup(len);
148840296Smckusick 			/*
148940296Smckusick 			 * This should not be necessary, but some servers have
149040296Smckusick 			 * broken XDR such that these bytes are not null filled.
149140296Smckusick 			 */
149240296Smckusick 			if (tlen != len) {
149340296Smckusick 				*dpos = '\0';	/* Null-terminate */
149440296Smckusick 				nfsm_adv(tlen - len);
149540296Smckusick 				len = tlen;
149640296Smckusick 			}
149752196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
149854986Smckusick 			off = fxdr_unsigned(u_long, *tl);
149948054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
150048054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
150140296Smckusick 			dp->d_reclen = len+4*NFSX_UNSIGNED;
150240296Smckusick 			siz += dp->d_reclen;
150340296Smckusick 		}
150440296Smckusick 		/*
150540296Smckusick 		 * If at end of rpc data, get the eof boolean
150640296Smckusick 		 */
150740296Smckusick 		if (!more_dirs) {
150852196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
150948054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
151038414Smckusick 
151140296Smckusick 			/*
151240296Smckusick 			 * If at EOF, cache directory offset
151340296Smckusick 			 */
151441905Smckusick 			if (!more_dirs)
151540296Smckusick 				np->n_direofoffset = off;
151638414Smckusick 		}
151740296Smckusick 		/*
151840296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
151940296Smckusick 		 * savdp to trim off the last record.
152040296Smckusick 		 * --> we are not at eof
152140296Smckusick 		 */
152240296Smckusick 		if (siz > uiop->uio_resid) {
152340296Smckusick 			off = savoff;
152440296Smckusick 			siz -= dp->d_reclen;
152540296Smckusick 			dp = savdp;
152640296Smckusick 			more_dirs = 0;	/* Paranoia */
152740113Smckusick 		}
152840296Smckusick 		if (siz > 0) {
152941905Smckusick 			lastlen = dp->d_reclen;
153040296Smckusick 			md = md2;
153140296Smckusick 			dpos = dpos2;
153240296Smckusick 			nfsm_mtouio(uiop, siz);
153340296Smckusick 			uiop->uio_offset = off;
153440296Smckusick 		} else
153540296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
153640296Smckusick 		m_freem(mrep);
153738414Smckusick 	}
153841905Smckusick 	/*
153948054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
154041905Smckusick 	 * by increasing d_reclen for the last record.
154141905Smckusick 	 */
154241905Smckusick 	if (uiop->uio_resid < tresid) {
154348054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
154441905Smckusick 		if (len > 0) {
154554740Smckusick 			dp = (struct dirent *)
154641905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
154741905Smckusick 			dp->d_reclen += len;
154841905Smckusick 			uiop->uio_iov->iov_base += len;
154941905Smckusick 			uiop->uio_iov->iov_len -= len;
155041905Smckusick 			uiop->uio_resid -= len;
155141905Smckusick 		}
155241905Smckusick 	}
155340296Smckusick nfsmout:
155438414Smckusick 	return (error);
155538414Smckusick }
155638414Smckusick 
155752196Smckusick /*
155852196Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when
155952196Smckusick  * the "rdirlook" mount option is specified.
156052196Smckusick  */
156152234Sheideman int
156252196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
156352196Smckusick 	struct vnode *vp;
156452196Smckusick 	register struct uio *uiop;
156552196Smckusick 	struct ucred *cred;
156652196Smckusick {
156752196Smckusick 	register int len;
156854740Smckusick 	register struct dirent *dp;
156952196Smckusick 	register u_long *tl;
157052196Smckusick 	register caddr_t cp;
157152196Smckusick 	register long t1;
157252196Smckusick 	caddr_t bpos, dpos, cp2;
157352196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
157452196Smckusick 	struct nameidata nami, *ndp = &nami;
157552317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
157652196Smckusick 	off_t off, endoff;
157752196Smckusick 	time_t reqtime, ltime;
157852196Smckusick 	struct nfsmount *nmp;
157952196Smckusick 	struct nfsnode *np, *tp;
158052196Smckusick 	struct vnode *newvp;
158152196Smckusick 	nfsv2fh_t *fhp;
158252196Smckusick 	u_long fileno;
158352196Smckusick 	u_quad_t frev;
158452196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
158552196Smckusick 	int cachable;
158652196Smckusick 
158752196Smckusick 	if (uiop->uio_iovcnt != 1)
158852196Smckusick 		panic("nfs rdirlook");
158952196Smckusick 	nmp = VFSTONFS(vp->v_mount);
159052196Smckusick 	tresid = uiop->uio_resid;
159152196Smckusick 	ndp->ni_dvp = vp;
159252196Smckusick 	newvp = NULLVP;
159352196Smckusick 	/*
159452196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
159552196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
159652196Smckusick 	 * The stopping criteria is EOF or buffer full.
159752196Smckusick 	 */
159852196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
159952196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
160052196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
160152196Smckusick 			NFSX_FH+3*NFSX_UNSIGNED);
160252196Smckusick 		nfsm_fhtom(vp);
160352196Smckusick 		nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED);
160452196Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
160552196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
160652196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
160752196Smckusick 		*tl = txdr_unsigned(nmp->nm_leaseterm);
160852196Smckusick 		reqtime = time.tv_sec;
160952196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
161052196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
161152196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
161252196Smckusick 
161352196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
161452196Smckusick 		off = uiop->uio_offset;
161552196Smckusick 		bigenough = 1;
161652196Smckusick 		while (more_dirs && bigenough) {
161752196Smckusick 			doit = 1;
161852196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
161952196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
162052196Smckusick 			ltime = reqtime + fxdr_unsigned(int, *tl++);
162152196Smckusick 			fxdr_hyper(tl, &frev);
162252196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
162352196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
162452196Smckusick 				VREF(vp);
162552196Smckusick 				newvp = vp;
162652196Smckusick 				np = VTONFS(vp);
162752196Smckusick 			} else {
162852196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
162952196Smckusick 					doit = 0;
163052196Smckusick 				newvp = NFSTOV(np);
163152196Smckusick 			}
163252196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
163352196Smckusick 				(struct vattr *)0))
163452196Smckusick 				doit = 0;
163552196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
163652196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
163752196Smckusick 			len = fxdr_unsigned(int, *tl);
163852196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
163952196Smckusick 				error = EBADRPC;
164052196Smckusick 				m_freem(mrep);
164152196Smckusick 				goto nfsmout;
164252196Smckusick 			}
164352196Smckusick 			tlen = (len + 4) & ~0x3;
164452196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
164552196Smckusick 				bigenough = 0;
164652196Smckusick 			if (bigenough && doit) {
164754740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
164854740Smckusick 				dp->d_fileno = fileno;
164952196Smckusick 				dp->d_namlen = len;
165052196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
165154986Smckusick 				dp->d_type =
165254986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
165352196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
165452196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
165552196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
165652317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
165752317Sheideman 				cnp->cn_namelen = len;
165852196Smckusick 				ndp->ni_vp = newvp;
165952196Smckusick 				nfsm_mtouio(uiop, len);
166052196Smckusick 				cp = uiop->uio_iov->iov_base;
166152196Smckusick 				tlen -= len;
166252196Smckusick 				for (i = 0; i < tlen; i++)
166352196Smckusick 					*cp++ = '\0';
166452196Smckusick 				uiop->uio_iov->iov_base += tlen;
166552196Smckusick 				uiop->uio_iov->iov_len -= tlen;
166652196Smckusick 				uiop->uio_resid -= tlen;
166752317Sheideman 				cnp->cn_hash = 0;
166852317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
166952317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
167052196Smckusick 				if (ltime > time.tv_sec) {
167152196Smckusick 					if (np->n_tnext) {
167252196Smckusick 						if (np->n_tnext == (struct nfsnode *)nmp)
167352196Smckusick 							nmp->nm_tprev = np->n_tprev;
167452196Smckusick 						else
167552196Smckusick 							np->n_tnext->n_tprev = np->n_tprev;
167652196Smckusick 						if (np->n_tprev == (struct nfsnode *)nmp)
167752196Smckusick 							nmp->nm_tnext = np->n_tnext;
167852196Smckusick 						else
167952196Smckusick 							np->n_tprev->n_tnext = np->n_tnext;
168052196Smckusick 					} else
168152196Smckusick 						np->n_flag &= ~NQNFSWRITE;
168252196Smckusick 					if (cachable)
168352196Smckusick 						np->n_flag &= ~NQNFSNONCACHE;
168452196Smckusick 					else
168552196Smckusick 						np->n_flag |= NQNFSNONCACHE;
168652196Smckusick 					np->n_expiry = ltime;
168752196Smckusick 					np->n_lrev = frev;
168852196Smckusick 					tp = nmp->nm_tprev;
168952196Smckusick 					while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
169052196Smckusick 						tp = tp->n_tprev;
169152196Smckusick 					if (tp == (struct nfsnode *)nmp) {
169252196Smckusick 						np->n_tnext = nmp->nm_tnext;
169352196Smckusick 						nmp->nm_tnext = np;
169452196Smckusick 					} else {
169552196Smckusick 						np->n_tnext = tp->n_tnext;
169652196Smckusick 						tp->n_tnext = np;
169752196Smckusick 					}
169852196Smckusick 					np->n_tprev = tp;
169952196Smckusick 					if (np->n_tnext == (struct nfsnode *)nmp)
170052196Smckusick 						nmp->nm_tprev = np;
170152196Smckusick 					else
170252196Smckusick 						np->n_tnext->n_tprev = np;
170352317Sheideman 					cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
170452196Smckusick 				}
170552196Smckusick 			} else {
170652196Smckusick 				nfsm_adv(nfsm_rndup(len));
170752196Smckusick 			}
170852196Smckusick 			if (newvp != NULLVP) {
170952196Smckusick 				vrele(newvp);
171052196Smckusick 				newvp = NULLVP;
171152196Smckusick 			}
171252196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
171352196Smckusick 			if (bigenough)
171452196Smckusick 				endoff = off = fxdr_unsigned(off_t, *tl++);
171552196Smckusick 			else
171652196Smckusick 				endoff = fxdr_unsigned(off_t, *tl++);
171752196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
171852196Smckusick 		}
171952196Smckusick 		/*
172052196Smckusick 		 * If at end of rpc data, get the eof boolean
172152196Smckusick 		 */
172252196Smckusick 		if (!more_dirs) {
172352196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
172452196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
172552196Smckusick 
172652196Smckusick 			/*
172752196Smckusick 			 * If at EOF, cache directory offset
172852196Smckusick 			 */
172952196Smckusick 			if (!more_dirs)
173052196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
173152196Smckusick 		}
173252196Smckusick 		if (uiop->uio_resid < tresid)
173352196Smckusick 			uiop->uio_offset = off;
173452196Smckusick 		else
173552196Smckusick 			more_dirs = 0;
173652196Smckusick 		m_freem(mrep);
173752196Smckusick 	}
173852196Smckusick 	/*
173952196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
174052196Smckusick 	 * by increasing d_reclen for the last record.
174152196Smckusick 	 */
174252196Smckusick 	if (uiop->uio_resid < tresid) {
174352196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
174452196Smckusick 		if (len > 0) {
174552196Smckusick 			dp->d_reclen += len;
174652196Smckusick 			uiop->uio_iov->iov_base += len;
174752196Smckusick 			uiop->uio_iov->iov_len -= len;
174852196Smckusick 			uiop->uio_resid -= len;
174952196Smckusick 		}
175052196Smckusick 	}
175152196Smckusick nfsmout:
175252196Smckusick 	if (newvp != NULLVP)
175352196Smckusick 		vrele(newvp);
175452196Smckusick 	return (error);
175552196Smckusick }
175639488Smckusick static char hextoasc[] = "0123456789abcdef";
175738414Smckusick 
175838414Smckusick /*
175938414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
176038414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
176138414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
176238414Smckusick  * nfsnode. There is the potential for another process on a different client
176338414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
176438414Smckusick  * nfs_rename() completes, but...
176538414Smckusick  */
176652234Sheideman int
176752317Sheideman nfs_sillyrename(dvp, vp, cnp)
176852234Sheideman 	struct vnode *dvp, *vp;
176952234Sheideman 	struct componentname *cnp;
177038414Smckusick {
177138414Smckusick 	register struct nfsnode *np;
177238414Smckusick 	register struct sillyrename *sp;
177338414Smckusick 	int error;
177438414Smckusick 	short pid;
177538414Smckusick 
177652234Sheideman 	cache_purge(dvp);
177752234Sheideman 	np = VTONFS(vp);
177851986Smckusick #ifdef SILLYSEPARATE
177938414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
178048364Smckusick 		M_NFSREQ, M_WAITOK);
178151986Smckusick #else
178251986Smckusick 	sp = &np->n_silly;
178351986Smckusick #endif
178452234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
178552234Sheideman 	sp->s_dvp = dvp;
178652234Sheideman 	VREF(dvp);
178738414Smckusick 
178838414Smckusick 	/* Fudge together a funny name */
178952234Sheideman 	pid = cnp->cn_proc->p_pid;
179048364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
179148364Smckusick 	sp->s_namlen = 12;
179248364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
179348364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
179448364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
179548364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
179638414Smckusick 
179738414Smckusick 	/* Try lookitups until we get one that isn't there */
179852234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
179948364Smckusick 		sp->s_name[4]++;
180048364Smckusick 		if (sp->s_name[4] > 'z') {
180138414Smckusick 			error = EINVAL;
180238414Smckusick 			goto bad;
180338414Smckusick 		}
180438414Smckusick 	}
180552234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
180638414Smckusick 		goto bad;
180752234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
180838414Smckusick 	np->n_sillyrename = sp;
180938414Smckusick 	return (0);
181038414Smckusick bad:
181148364Smckusick 	vrele(sp->s_dvp);
181248364Smckusick 	crfree(sp->s_cred);
181351986Smckusick #ifdef SILLYSEPARATE
181448364Smckusick 	free((caddr_t)sp, M_NFSREQ);
181551986Smckusick #endif
181638414Smckusick 	return (error);
181738414Smckusick }
181838414Smckusick 
181938414Smckusick /*
182038414Smckusick  * Look up a file name for silly rename stuff.
182138414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
182238414Smckusick  * into the nfsnode table.
182338414Smckusick  * If fhp != NULL it copies the returned file handle out
182438414Smckusick  */
182552234Sheideman int
182652196Smckusick nfs_lookitup(sp, fhp, procp)
182748364Smckusick 	register struct sillyrename *sp;
182838414Smckusick 	nfsv2fh_t *fhp;
182952196Smckusick 	struct proc *procp;
183038414Smckusick {
183148364Smckusick 	register struct vnode *vp = sp->s_dvp;
183248054Smckusick 	register u_long *tl;
183339488Smckusick 	register caddr_t cp;
183439488Smckusick 	register long t1, t2;
183539488Smckusick 	caddr_t bpos, dpos, cp2;
183639488Smckusick 	u_long xid;
183739488Smckusick 	int error = 0;
183839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
183938414Smckusick 	long len;
184038414Smckusick 
184138414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
184248364Smckusick 	len = sp->s_namlen;
184352196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
184438414Smckusick 	nfsm_fhtom(vp);
184548364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
184652196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
184738414Smckusick 	if (fhp != NULL) {
184852196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
184938414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
185038414Smckusick 	}
185138414Smckusick 	nfsm_reqdone;
185238414Smckusick 	return (error);
185338414Smckusick }
185438414Smckusick 
185538414Smckusick /*
185638414Smckusick  * Kludge City..
185738414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
185841905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
185938414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
186038414Smckusick  *   nfsiobuf area.
186138414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
186238414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
186338414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
186438414Smckusick  *    context of the swapper process (2).
186538414Smckusick  */
186652234Sheideman int
186753806Smckusick nfs_bmap(ap)
186854668Smckusick 	struct vop_bmap_args /* {
186954668Smckusick 		struct vnode *a_vp;
187054668Smckusick 		daddr_t  a_bn;
187154668Smckusick 		struct vnode **a_vpp;
187254668Smckusick 		daddr_t *a_bnp;
187354668Smckusick 	} */ *ap;
187438414Smckusick {
187553806Smckusick 	register struct vnode *vp = ap->a_vp;
187653806Smckusick 
187753600Sheideman 	if (ap->a_vpp != NULL)
187853806Smckusick 		*ap->a_vpp = vp;
187953600Sheideman 	if (ap->a_bnp != NULL)
188053806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
188138414Smckusick 	return (0);
188238414Smckusick }
188338414Smckusick 
188438414Smckusick /*
188538884Smacklem  * Strategy routine for phys. i/o
188638884Smacklem  * If the biod's are running, queue a request
188738884Smacklem  * otherwise just call nfs_doio() to get it done
188838414Smckusick  */
188952234Sheideman int
189053806Smckusick nfs_strategy(ap)
189154668Smckusick 	struct vop_strategy_args /* {
189254668Smckusick 		struct buf *a_bp;
189354668Smckusick 	} */ *ap;
189438414Smckusick {
189553806Smckusick 	register struct buf *bp = ap->a_bp;
189638884Smacklem 	register struct buf *dp;
189739341Smckusick 	register int i;
189838884Smacklem 	int error = 0;
189939341Smckusick 	int fnd = 0;
190038884Smacklem 
190138884Smacklem 	/*
190241905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
190341905Smckusick 	 * doesn't set it, I will.
190446450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
190541905Smckusick 	 * be hanging about after the process terminates.
190641905Smckusick 	 */
190753806Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
190853806Smckusick 		if (bp->b_flags & B_ASYNC)
190953806Smckusick 			bp->b_proc = (struct proc *)0;
191046988Smckusick 		else
191153806Smckusick 			bp->b_proc = curproc;
191246988Smckusick 	}
191341905Smckusick 	/*
191446450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
191538884Smacklem 	 * queue the request, wake it up and wait for completion
191646450Skarels 	 * otherwise just do it ourselves.
191738884Smacklem 	 */
191853806Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
191953806Smckusick 		return (nfs_doio(bp));
192046988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
192146988Smckusick 		if (nfs_iodwant[i]) {
192239341Smckusick 			dp = &nfs_bqueue;
192339341Smckusick 			if (dp->b_actf == NULL) {
192453806Smckusick 				dp->b_actl = bp;
192553806Smckusick 				bp->b_actf = dp;
192639341Smckusick 			} else {
192753806Smckusick 				dp->b_actf->b_actl = bp;
192853806Smckusick 				bp->b_actf = dp->b_actf;
192939341Smckusick 			}
193053806Smckusick 			dp->b_actf = bp;
193153806Smckusick 			bp->b_actl = dp;
193239341Smckusick 			fnd++;
193339341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
193439341Smckusick 			break;
193538884Smacklem 		}
193639341Smckusick 	}
193739341Smckusick 	if (!fnd)
193853806Smckusick 		error = nfs_doio(bp);
193938884Smacklem 	return (error);
194038884Smacklem }
194138884Smacklem 
194238884Smacklem /*
194338884Smacklem  * Fun and games with i/o
194438884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
194538884Smacklem  * mapping the data buffer into kernel virtual space and doing the
194638884Smacklem  * nfs read or write rpc's from it.
194741905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
194841905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
194938884Smacklem  * partially disk interrupt driven.
195038884Smacklem  */
195152234Sheideman int
195238884Smacklem nfs_doio(bp)
195338884Smacklem 	register struct buf *bp;
195438884Smacklem {
195538414Smckusick 	register struct uio *uiop;
195638414Smckusick 	register struct vnode *vp;
195739341Smckusick 	struct nfsnode *np;
195838884Smacklem 	struct ucred *cr;
195941539Smckusick 	int error;
196041539Smckusick 	struct uio uio;
196141539Smckusick 	struct iovec io;
196238414Smckusick 
196338414Smckusick 	vp = bp->b_vp;
196440251Smckusick 	np = VTONFS(vp);
196538414Smckusick 	uiop = &uio;
196638414Smckusick 	uiop->uio_iov = &io;
196738414Smckusick 	uiop->uio_iovcnt = 1;
196838414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
196952196Smckusick 	uiop->uio_procp = bp->b_proc;
197039751Smckusick 
197138414Smckusick 	/*
197238884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
197338884Smacklem 	 * the Nfsiomap pte's
197438884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
197538884Smacklem 	 * and a guess at a group
197638414Smckusick 	 */
197738884Smacklem 	if (bp->b_flags & B_PHYS) {
197848054Smckusick 		if (bp->b_flags & B_DIRTY)
197948054Smckusick 			uiop->uio_procp = pageproc;
198048054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
198141539Smckusick 		/* mapping was already done by vmapbuf */
198241539Smckusick 		io.iov_base = bp->b_un.b_addr;
198339751Smckusick 
198438884Smacklem 		/*
198539751Smckusick 		 * And do the i/o rpc
198639751Smckusick 		 */
198739751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
198839823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
198939751Smckusick 		if (bp->b_flags & B_READ) {
199039751Smckusick 			uiop->uio_rw = UIO_READ;
199139751Smckusick 			nfsstats.read_physios++;
199248054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
199345717Smckusick 			(void) vnode_pager_uncache(vp);
199439751Smckusick 		} else {
199539751Smckusick 			uiop->uio_rw = UIO_WRITE;
199639751Smckusick 			nfsstats.write_physios++;
199748054Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr);
199839341Smckusick 		}
199939751Smckusick 
200039751Smckusick 		/*
200139751Smckusick 		 * Finally, release pte's used by physical i/o
200239751Smckusick 		 */
200338884Smacklem 		crfree(cr);
200439751Smckusick 	} else {
200539751Smckusick 		if (bp->b_flags & B_READ) {
200639751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
200739751Smckusick 			io.iov_base = bp->b_un.b_addr;
200839751Smckusick 			uiop->uio_rw = UIO_READ;
200941905Smckusick 			switch (vp->v_type) {
201041905Smckusick 			case VREG:
201141905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
201241905Smckusick 				nfsstats.read_bios++;
201348054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
201441905Smckusick 				break;
201541905Smckusick 			case VLNK:
201641905Smckusick 				uiop->uio_offset = 0;
201741905Smckusick 				nfsstats.readlink_bios++;
201848054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
201941905Smckusick 				break;
202041905Smckusick 			case VDIR:
202141905Smckusick 				uiop->uio_offset = bp->b_lblkno;
202241905Smckusick 				nfsstats.readdir_bios++;
202352196Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK)
202452196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
202552196Smckusick 				else
202652196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
202741905Smckusick 				/*
202841905Smckusick 				 * Save offset cookie in b_blkno.
202941905Smckusick 				 */
203041905Smckusick 				bp->b_blkno = uiop->uio_offset;
203141905Smckusick 				break;
203241905Smckusick 			};
203341905Smckusick 			bp->b_error = error;
203439751Smckusick 		} else {
203539751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
203639751Smckusick 				- bp->b_dirtyoff;
203739823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
203839751Smckusick 				+ bp->b_dirtyoff;
203939751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
204039751Smckusick 			uiop->uio_rw = UIO_WRITE;
204139751Smckusick 			nfsstats.write_bios++;
204241905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
204348054Smckusick 				bp->b_wcred);
204439751Smckusick 			if (error) {
204539751Smckusick 				np->n_error = error;
204639751Smckusick 				np->n_flag |= NWRITEERR;
204739751Smckusick 			}
204839751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
204939751Smckusick 		}
205038884Smacklem 	}
205139751Smckusick 	if (error)
205239751Smckusick 		bp->b_flags |= B_ERROR;
205339751Smckusick 	bp->b_resid = uiop->uio_resid;
205438414Smckusick 	biodone(bp);
205538414Smckusick 	return (error);
205638414Smckusick }
205738884Smacklem 
205838884Smacklem /*
205948054Smckusick  * Mmap a file
206048054Smckusick  *
206148054Smckusick  * NB Currently unsupported.
206248054Smckusick  */
206348054Smckusick /* ARGSUSED */
206452234Sheideman int
206553806Smckusick nfs_mmap(ap)
206654668Smckusick 	struct vop_mmap_args /* {
206754668Smckusick 		struct vnode *a_vp;
206854668Smckusick 		int  a_fflags;
206954668Smckusick 		struct ucred *a_cred;
207054668Smckusick 		struct proc *a_p;
207154668Smckusick 	} */ *ap;
207248054Smckusick {
207348054Smckusick 
207448054Smckusick 	return (EINVAL);
207548054Smckusick }
207648054Smckusick 
207748054Smckusick /*
207838884Smacklem  * Flush all the blocks associated with a vnode.
207938884Smacklem  * 	Walk through the buffer pool and push any dirty pages
208038884Smacklem  *	associated with the vnode.
208138884Smacklem  */
208239488Smckusick /* ARGSUSED */
208352234Sheideman int
208453806Smckusick nfs_fsync(ap)
208554451Smckusick 	struct vop_fsync_args /* {
208654451Smckusick 		struct vnodeop_desc *a_desc;
208754451Smckusick 		struct vnode * a_vp;
208854451Smckusick 		struct ucred * a_cred;
208954451Smckusick 		int  a_waitfor;
209054451Smckusick 		struct proc * a_p;
209154451Smckusick 	} */ *ap;
209238884Smacklem {
209354451Smckusick 	register struct vnode *vp = ap->a_vp;
209454451Smckusick 	register struct nfsnode *np = VTONFS(vp);
209554451Smckusick 	register struct buf *bp;
209654451Smckusick 	struct buf *nbp;
209754451Smckusick 	int s, error = 0;
209838884Smacklem 
209954451Smckusick loop:
210054451Smckusick 	s = splbio();
210154451Smckusick 	for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
210254451Smckusick 		nbp = bp->b_blockf;
210354451Smckusick 		if ((bp->b_flags & B_BUSY))
210454451Smckusick 			continue;
210554451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
210654451Smckusick 			panic("nfs_fsync: not dirty");
210754451Smckusick 		bremfree(bp);
210854451Smckusick 		bp->b_flags |= B_BUSY;
210954451Smckusick 		splx(s);
211054451Smckusick 		error = bawrite(bp);
211154451Smckusick 		goto loop;
211238884Smacklem 	}
211354451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
211454451Smckusick 		while (vp->v_numoutput) {
211554451Smckusick 			vp->v_flag |= VBWAIT;
211654451Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
211754451Smckusick 		}
211854451Smckusick #ifdef DIAGNOSTIC
211954451Smckusick 		if (vp->v_dirtyblkhd) {
212054451Smckusick 			vprint("nfs_fsync: dirty", vp);
212154451Smckusick 			goto loop;
212254451Smckusick 		}
212354451Smckusick #endif
212454451Smckusick 	}
212554451Smckusick 	splx(s);
212654451Smckusick 	np->n_flag &= ~NMODIFIED;
212753629Smckusick 	if (np->n_flag & NWRITEERR) {
212839751Smckusick 		error = np->n_error;
212953629Smckusick 		np->n_flag &= ~NWRITEERR;
213053629Smckusick 	}
213138884Smacklem 	return (error);
213238884Smacklem }
213339672Smckusick 
213439672Smckusick /*
213546201Smckusick  * NFS advisory byte-level locks.
213646201Smckusick  * Currently unsupported.
213746201Smckusick  */
213852234Sheideman int
213953806Smckusick nfs_advlock(ap)
214054668Smckusick 	struct vop_advlock_args /* {
214154668Smckusick 		struct vnode *a_vp;
214254668Smckusick 		caddr_t  a_id;
214354668Smckusick 		int  a_op;
214454668Smckusick 		struct flock *a_fl;
214554668Smckusick 		int  a_flags;
214654668Smckusick 	} */ *ap;
214746201Smckusick {
214846201Smckusick 
214946201Smckusick 	return (EOPNOTSUPP);
215046201Smckusick }
215146201Smckusick 
215246201Smckusick /*
215339672Smckusick  * Print out the contents of an nfsnode.
215439672Smckusick  */
215552234Sheideman int
215653806Smckusick nfs_print(ap)
215754668Smckusick 	struct vop_print_args /* {
215854668Smckusick 		struct vnode *a_vp;
215954668Smckusick 	} */ *ap;
216039672Smckusick {
216153806Smckusick 	register struct vnode *vp = ap->a_vp;
216253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
216339672Smckusick 
216440294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
216540294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
216640294Smckusick #ifdef FIFO
216753806Smckusick 	if (vp->v_type == VFIFO)
216853806Smckusick 		fifo_printinfo(vp);
216940294Smckusick #endif /* FIFO */
217039914Smckusick 	printf("\n");
217139672Smckusick }
217251573Smckusick 
217351573Smckusick /*
217451573Smckusick  * NFS directory offset lookup.
217551573Smckusick  * Currently unsupported.
217651573Smckusick  */
217752234Sheideman int
217853806Smckusick nfs_blkatoff(ap)
217954668Smckusick 	struct vop_blkatoff_args /* {
218054668Smckusick 		struct vnode *a_vp;
218154668Smckusick 		off_t a_offset;
218254668Smckusick 		char **a_res;
218354668Smckusick 		struct buf **a_bpp;
218454668Smckusick 	} */ *ap;
218551573Smckusick {
218651573Smckusick 
218751573Smckusick 	return (EOPNOTSUPP);
218851573Smckusick }
218951573Smckusick 
219051573Smckusick /*
219151573Smckusick  * NFS flat namespace allocation.
219251573Smckusick  * Currently unsupported.
219351573Smckusick  */
219452234Sheideman int
219553806Smckusick nfs_valloc(ap)
219654668Smckusick 	struct vop_valloc_args /* {
219754668Smckusick 		struct vnode *a_pvp;
219854668Smckusick 		int a_mode;
219954668Smckusick 		struct ucred *a_cred;
220054668Smckusick 		struct vnode **a_vpp;
220154668Smckusick 	} */ *ap;
220251573Smckusick {
220351573Smckusick 
220451573Smckusick 	return (EOPNOTSUPP);
220551573Smckusick }
220651573Smckusick 
220751573Smckusick /*
220851573Smckusick  * NFS flat namespace free.
220951573Smckusick  * Currently unsupported.
221051573Smckusick  */
221153582Sheideman int
221253806Smckusick nfs_vfree(ap)
221354668Smckusick 	struct vop_vfree_args /* {
221454668Smckusick 		struct vnode *a_pvp;
221554668Smckusick 		ino_t a_ino;
221654668Smckusick 		int a_mode;
221754668Smckusick 	} */ *ap;
221851573Smckusick {
221951573Smckusick 
222053582Sheideman 	return (EOPNOTSUPP);
222151573Smckusick }
222251573Smckusick 
222351573Smckusick /*
222451573Smckusick  * NFS file truncation.
222551573Smckusick  */
222652234Sheideman int
222753806Smckusick nfs_truncate(ap)
222854668Smckusick 	struct vop_truncate_args /* {
222954668Smckusick 		struct vnode *a_vp;
223054668Smckusick 		off_t a_length;
223154668Smckusick 		int a_flags;
223254668Smckusick 		struct ucred *a_cred;
223354668Smckusick 		struct proc *a_p;
223454668Smckusick 	} */ *ap;
223551573Smckusick {
223651573Smckusick 
223751573Smckusick 	/* Use nfs_setattr */
223851573Smckusick 	printf("nfs_truncate: need to implement!!");
223951573Smckusick 	return (EOPNOTSUPP);
224051573Smckusick }
224151573Smckusick 
224251573Smckusick /*
224351573Smckusick  * NFS update.
224451573Smckusick  */
224552234Sheideman int
224653806Smckusick nfs_update(ap)
224754668Smckusick 	struct vop_update_args /* {
224854668Smckusick 		struct vnode *a_vp;
224954668Smckusick 		struct timeval *a_ta;
225054668Smckusick 		struct timeval *a_tm;
225154668Smckusick 		int a_waitfor;
225254668Smckusick 	} */ *ap;
225351573Smckusick {
225451573Smckusick 
225551573Smckusick 	/* Use nfs_setattr */
225651573Smckusick 	printf("nfs_update: need to implement!!");
225751573Smckusick 	return (EOPNOTSUPP);
225851573Smckusick }
225953629Smckusick 
226053629Smckusick /*
226153629Smckusick  * Read wrapper for special devices.
226253629Smckusick  */
226353629Smckusick int
226453629Smckusick nfsspec_read(ap)
226554668Smckusick 	struct vop_read_args /* {
226654668Smckusick 		struct vnode *a_vp;
226754668Smckusick 		struct uio *a_uio;
226854668Smckusick 		int  a_ioflag;
226954668Smckusick 		struct ucred *a_cred;
227054668Smckusick 	} */ *ap;
227153629Smckusick {
227253629Smckusick 	extern int (**spec_vnodeop_p)();
227354032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
227453629Smckusick 
227553629Smckusick 	/*
227653629Smckusick 	 * Set access flag.
227753629Smckusick 	 */
227854032Smckusick 	np->n_flag |= NACC;
227954032Smckusick 	np->n_atim = time;
228053629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
228153629Smckusick }
228253629Smckusick 
228353629Smckusick /*
228453629Smckusick  * Write wrapper for special devices.
228553629Smckusick  */
228653629Smckusick int
228753629Smckusick nfsspec_write(ap)
228854668Smckusick 	struct vop_write_args /* {
228954668Smckusick 		struct vnode *a_vp;
229054668Smckusick 		struct uio *a_uio;
229154668Smckusick 		int  a_ioflag;
229254668Smckusick 		struct ucred *a_cred;
229354668Smckusick 	} */ *ap;
229453629Smckusick {
229553629Smckusick 	extern int (**spec_vnodeop_p)();
229654032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
229753629Smckusick 
229853629Smckusick 	/*
229954032Smckusick 	 * Set update flag.
230053629Smckusick 	 */
230154032Smckusick 	np->n_flag |= NUPD;
230254032Smckusick 	np->n_mtim = time;
230353629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
230453629Smckusick }
230553629Smckusick 
230653629Smckusick /*
230753629Smckusick  * Close wrapper for special devices.
230853629Smckusick  *
230953629Smckusick  * Update the times on the nfsnode then do device close.
231053629Smckusick  */
231153629Smckusick int
231253629Smckusick nfsspec_close(ap)
231354668Smckusick 	struct vop_close_args /* {
231454668Smckusick 		struct vnode *a_vp;
231554668Smckusick 		int  a_fflag;
231654668Smckusick 		struct ucred *a_cred;
231754668Smckusick 		struct proc *a_p;
231854668Smckusick 	} */ *ap;
231953629Smckusick {
232053806Smckusick 	register struct vnode *vp = ap->a_vp;
232153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
232253629Smckusick 	struct vattr vattr;
232353629Smckusick 	extern int (**spec_vnodeop_p)();
232453629Smckusick 
232553629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
232653629Smckusick 		if (np->n_flag & NACC)
232753629Smckusick 			np->n_atim = time;
232853629Smckusick 		if (np->n_flag & NUPD)
232953629Smckusick 			np->n_mtim = time;
233053629Smckusick 		np->n_flag |= NCHG;
233153806Smckusick 		if (vp->v_usecount == 1 &&
233253806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
233353629Smckusick 			VATTR_NULL(&vattr);
233454106Smckusick 			if (np->n_flag & NACC) {
233554106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
233654106Smckusick 				vattr.va_atime.ts_nsec =
233754106Smckusick 				    np->n_atim.tv_usec * 1000;
233854106Smckusick 			}
233954106Smckusick 			if (np->n_flag & NUPD) {
234054106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
234154106Smckusick 				vattr.va_mtime.ts_nsec =
234254106Smckusick 				    np->n_mtim.tv_usec * 1000;
234354106Smckusick 			}
234453806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
234553629Smckusick 		}
234653629Smckusick 	}
234753629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
234853629Smckusick }
234953629Smckusick 
235053629Smckusick #ifdef FIFO
235153629Smckusick /*
235253629Smckusick  * Read wrapper for fifos.
235353629Smckusick  */
235453629Smckusick int
235553629Smckusick nfsfifo_read(ap)
235654668Smckusick 	struct vop_read_args /* {
235754668Smckusick 		struct vnode *a_vp;
235854668Smckusick 		struct uio *a_uio;
235954668Smckusick 		int  a_ioflag;
236054668Smckusick 		struct ucred *a_cred;
236154668Smckusick 	} */ *ap;
236253629Smckusick {
236353629Smckusick 	extern int (**fifo_vnodeop_p)();
236454032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
236553629Smckusick 
236653629Smckusick 	/*
236753629Smckusick 	 * Set access flag.
236853629Smckusick 	 */
236954032Smckusick 	np->n_flag |= NACC;
237054032Smckusick 	np->n_atim = time;
237153629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
237253629Smckusick }
237353629Smckusick 
237453629Smckusick /*
237553629Smckusick  * Write wrapper for fifos.
237653629Smckusick  */
237753629Smckusick int
237853629Smckusick nfsfifo_write(ap)
237954668Smckusick 	struct vop_write_args /* {
238054668Smckusick 		struct vnode *a_vp;
238154668Smckusick 		struct uio *a_uio;
238254668Smckusick 		int  a_ioflag;
238354668Smckusick 		struct ucred *a_cred;
238454668Smckusick 	} */ *ap;
238553629Smckusick {
238653629Smckusick 	extern int (**fifo_vnodeop_p)();
238754032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
238853629Smckusick 
238953629Smckusick 	/*
239053629Smckusick 	 * Set update flag.
239153629Smckusick 	 */
239254032Smckusick 	np->n_flag |= NUPD;
239354032Smckusick 	np->n_mtim = time;
239453629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
239553629Smckusick }
239653629Smckusick 
239753629Smckusick /*
239853629Smckusick  * Close wrapper for fifos.
239953629Smckusick  *
240053629Smckusick  * Update the times on the nfsnode then do fifo close.
240153629Smckusick  */
240253629Smckusick int
240353629Smckusick nfsfifo_close(ap)
240454668Smckusick 	struct vop_close_args /* {
240554668Smckusick 		struct vnode *a_vp;
240654668Smckusick 		int  a_fflag;
240754668Smckusick 		struct ucred *a_cred;
240854668Smckusick 		struct proc *a_p;
240954668Smckusick 	} */ *ap;
241053629Smckusick {
241153806Smckusick 	register struct vnode *vp = ap->a_vp;
241253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
241353629Smckusick 	struct vattr vattr;
241453629Smckusick 	extern int (**fifo_vnodeop_p)();
241553629Smckusick 
241653629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
241753629Smckusick 		if (np->n_flag & NACC)
241853629Smckusick 			np->n_atim = time;
241953629Smckusick 		if (np->n_flag & NUPD)
242053629Smckusick 			np->n_mtim = time;
242153629Smckusick 		np->n_flag |= NCHG;
242253806Smckusick 		if (vp->v_usecount == 1 &&
242353806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
242453629Smckusick 			VATTR_NULL(&vattr);
242554106Smckusick 			if (np->n_flag & NACC) {
242654106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
242754106Smckusick 				vattr.va_atime.ts_nsec =
242854106Smckusick 				    np->n_atim.tv_usec * 1000;
242954106Smckusick 			}
243054106Smckusick 			if (np->n_flag & NUPD) {
243154106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
243254106Smckusick 				vattr.va_mtime.ts_nsec =
243354106Smckusick 				    np->n_mtim.tv_usec * 1000;
243454106Smckusick 			}
243553806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
243653629Smckusick 		}
243753629Smckusick 	}
243853629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
243953629Smckusick }
244053629Smckusick #endif /* FIFO */
2441