138414Smckusick /*
263486Sbostic * Copyright (c) 1989, 1993
363486Sbostic * The Regents of the University of California. 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*69743Smckusick * @(#)nfs_vnops.c 8.16 (Berkeley) 05/27/95
1138414Smckusick */
1238414Smckusick
1368653Smckusick
1438414Smckusick /*
1568653Smckusick * vnode op calls for Sun NFS version 2 and 3
1638414Smckusick */
1738414Smckusick
1853322Smckusick #include <sys/param.h>
1953322Smckusick #include <sys/kernel.h>
2053322Smckusick #include <sys/systm.h>
2168653Smckusick #include <sys/resourcevar.h>
2268653Smckusick #include <sys/proc.h>
2353322Smckusick #include <sys/mount.h>
2453322Smckusick #include <sys/buf.h>
2553322Smckusick #include <sys/malloc.h>
2653322Smckusick #include <sys/mbuf.h>
2753322Smckusick #include <sys/conf.h>
2853322Smckusick #include <sys/namei.h>
2953322Smckusick #include <sys/vnode.h>
3054740Smckusick #include <sys/dirent.h>
3168653Smckusick #include <sys/fcntl.h>
3268653Smckusick #include <ufs/ufs/dir.h>
3347573Skarels
3453322Smckusick #include <vm/vm.h>
3538414Smckusick
3655041Smckusick #include <miscfs/specfs/specdev.h>
3755041Smckusick #include <miscfs/fifofs/fifo.h>
3855041Smckusick
3953322Smckusick #include <nfs/rpcv2.h>
4068653Smckusick #include <nfs/nfsproto.h>
4153322Smckusick #include <nfs/nfs.h>
4253322Smckusick #include <nfs/nfsnode.h>
4353322Smckusick #include <nfs/nfsmount.h>
4453322Smckusick #include <nfs/xdr_subs.h>
4553322Smckusick #include <nfs/nfsm_subs.h>
4653322Smckusick #include <nfs/nqnfs.h>
4753322Smckusick
4868653Smckusick #include <net/if.h>
4968653Smckusick #include <netinet/in.h>
5068653Smckusick #include <netinet/in_var.h>
5168653Smckusick
5238414Smckusick /* Defs */
5338414Smckusick #define TRUE 1
5438414Smckusick #define FALSE 0
5538414Smckusick
5648054Smckusick /*
5748054Smckusick * Global vfs data structures for nfs
5848054Smckusick */
5953554Sheideman int (**nfsv2_vnodeop_p)();
6053554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
6153554Sheideman { &vop_default_desc, vn_default_error },
6253806Smckusick { &vop_lookup_desc, nfs_lookup }, /* lookup */
6353806Smckusick { &vop_create_desc, nfs_create }, /* create */
6453554Sheideman { &vop_mknod_desc, nfs_mknod }, /* mknod */
6553554Sheideman { &vop_open_desc, nfs_open }, /* open */
6653554Sheideman { &vop_close_desc, nfs_close }, /* close */
6753806Smckusick { &vop_access_desc, nfs_access }, /* access */
6853806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */
6953806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */
7053554Sheideman { &vop_read_desc, nfs_read }, /* read */
7153554Sheideman { &vop_write_desc, nfs_write }, /* write */
7267651Smckusick { &vop_lease_desc, nfs_lease_check }, /* lease */
7353554Sheideman { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */
7453806Smckusick { &vop_select_desc, nfs_select }, /* select */
7568418Smckusick { &vop_revoke_desc, nfs_revoke }, /* revoke */
7653554Sheideman { &vop_mmap_desc, nfs_mmap }, /* mmap */
7753554Sheideman { &vop_fsync_desc, nfs_fsync }, /* fsync */
7853554Sheideman { &vop_seek_desc, nfs_seek }, /* seek */
7953806Smckusick { &vop_remove_desc, nfs_remove }, /* remove */
8053554Sheideman { &vop_link_desc, nfs_link }, /* link */
8153806Smckusick { &vop_rename_desc, nfs_rename }, /* rename */
8253554Sheideman { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */
8353554Sheideman { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */
8453806Smckusick { &vop_symlink_desc, nfs_symlink }, /* symlink */
8553806Smckusick { &vop_readdir_desc, nfs_readdir }, /* readdir */
8653806Smckusick { &vop_readlink_desc, nfs_readlink }, /* readlink */
8753806Smckusick { &vop_abortop_desc, nfs_abortop }, /* abortop */
8853806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */
8953806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
9053554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */
9153806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */
9253554Sheideman { &vop_bmap_desc, nfs_bmap }, /* bmap */
9353806Smckusick { &vop_strategy_desc, nfs_strategy }, /* strategy */
9453554Sheideman { &vop_print_desc, nfs_print }, /* print */
9553806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */
9660400Smckusick { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */
9753806Smckusick { &vop_advlock_desc, nfs_advlock }, /* advlock */
9853806Smckusick { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */
9953806Smckusick { &vop_valloc_desc, nfs_valloc }, /* valloc */
10066079Shibler { &vop_reallocblks_desc, nfs_reallocblks }, /* reallocblks */
10153554Sheideman { &vop_vfree_desc, nfs_vfree }, /* vfree */
10253806Smckusick { &vop_truncate_desc, nfs_truncate }, /* truncate */
10353806Smckusick { &vop_update_desc, nfs_update }, /* update */
10468653Smckusick { &vop_bwrite_desc, nfs_bwrite },
10553554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
10638414Smckusick };
10753554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
10853554Sheideman { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
10938414Smckusick
11048054Smckusick /*
11148054Smckusick * Special device vnode ops
11248054Smckusick */
11353554Sheideman int (**spec_nfsv2nodeop_p)();
11453554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
11553554Sheideman { &vop_default_desc, vn_default_error },
11653806Smckusick { &vop_lookup_desc, spec_lookup }, /* lookup */
11753806Smckusick { &vop_create_desc, spec_create }, /* create */
11853806Smckusick { &vop_mknod_desc, spec_mknod }, /* mknod */
11953554Sheideman { &vop_open_desc, spec_open }, /* open */
12053806Smckusick { &vop_close_desc, nfsspec_close }, /* close */
12156364Smckusick { &vop_access_desc, nfsspec_access }, /* access */
12253806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */
12353806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */
12453806Smckusick { &vop_read_desc, nfsspec_read }, /* read */
12553806Smckusick { &vop_write_desc, nfsspec_write }, /* write */
12667651Smckusick { &vop_lease_desc, spec_lease_check }, /* lease */
12753806Smckusick { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
12853806Smckusick { &vop_select_desc, spec_select }, /* select */
12968418Smckusick { &vop_revoke_desc, spec_revoke }, /* revoke */
13053554Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */
13154451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */
13253554Sheideman { &vop_seek_desc, spec_seek }, /* seek */
13353806Smckusick { &vop_remove_desc, spec_remove }, /* remove */
13453554Sheideman { &vop_link_desc, spec_link }, /* link */
13553806Smckusick { &vop_rename_desc, spec_rename }, /* rename */
13653806Smckusick { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
13753806Smckusick { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
13853806Smckusick { &vop_symlink_desc, spec_symlink }, /* symlink */
13953806Smckusick { &vop_readdir_desc, spec_readdir }, /* readdir */
14053806Smckusick { &vop_readlink_desc, spec_readlink }, /* readlink */
14153806Smckusick { &vop_abortop_desc, spec_abortop }, /* abortop */
14253806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */
14353806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
14453554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */
14553806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */
14653554Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */
14753806Smckusick { &vop_strategy_desc, spec_strategy }, /* strategy */
14853554Sheideman { &vop_print_desc, nfs_print }, /* print */
14953806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */
15060400Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
15153806Smckusick { &vop_advlock_desc, spec_advlock }, /* advlock */
15253806Smckusick { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
15353806Smckusick { &vop_valloc_desc, spec_valloc }, /* valloc */
15466079Shibler { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
15553806Smckusick { &vop_vfree_desc, spec_vfree }, /* vfree */
15653806Smckusick { &vop_truncate_desc, spec_truncate }, /* truncate */
15753806Smckusick { &vop_update_desc, nfs_update }, /* update */
15857809Smckusick { &vop_bwrite_desc, vn_bwrite },
15953554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
16038414Smckusick };
16153554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
16253554Sheideman { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
16338414Smckusick
16453554Sheideman int (**fifo_nfsv2nodeop_p)();
16553554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
16653554Sheideman { &vop_default_desc, vn_default_error },
16753806Smckusick { &vop_lookup_desc, fifo_lookup }, /* lookup */
16853806Smckusick { &vop_create_desc, fifo_create }, /* create */
16953806Smckusick { &vop_mknod_desc, fifo_mknod }, /* mknod */
17053554Sheideman { &vop_open_desc, fifo_open }, /* open */
17153806Smckusick { &vop_close_desc, nfsfifo_close }, /* close */
17256364Smckusick { &vop_access_desc, nfsspec_access }, /* access */
17353806Smckusick { &vop_getattr_desc, nfs_getattr }, /* getattr */
17453806Smckusick { &vop_setattr_desc, nfs_setattr }, /* setattr */
17553806Smckusick { &vop_read_desc, nfsfifo_read }, /* read */
17653806Smckusick { &vop_write_desc, nfsfifo_write }, /* write */
17767651Smckusick { &vop_lease_desc, fifo_lease_check }, /* lease */
17853806Smckusick { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
17953806Smckusick { &vop_select_desc, fifo_select }, /* select */
18068418Smckusick { &vop_revoke_desc, fifo_revoke }, /* revoke */
18153554Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */
18254451Smckusick { &vop_fsync_desc, nfs_fsync }, /* fsync */
18353554Sheideman { &vop_seek_desc, fifo_seek }, /* seek */
18453806Smckusick { &vop_remove_desc, fifo_remove }, /* remove */
18553554Sheideman { &vop_link_desc, fifo_link }, /* link */
18653806Smckusick { &vop_rename_desc, fifo_rename }, /* rename */
18753806Smckusick { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
18853806Smckusick { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
18953806Smckusick { &vop_symlink_desc, fifo_symlink }, /* symlink */
19053806Smckusick { &vop_readdir_desc, fifo_readdir }, /* readdir */
19153806Smckusick { &vop_readlink_desc, fifo_readlink }, /* readlink */
19253806Smckusick { &vop_abortop_desc, fifo_abortop }, /* abortop */
19353806Smckusick { &vop_inactive_desc, nfs_inactive }, /* inactive */
19453806Smckusick { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
19553554Sheideman { &vop_lock_desc, nfs_lock }, /* lock */
19653806Smckusick { &vop_unlock_desc, nfs_unlock }, /* unlock */
19753554Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */
19853806Smckusick { &vop_strategy_desc, fifo_badop }, /* strategy */
19953554Sheideman { &vop_print_desc, nfs_print }, /* print */
20053806Smckusick { &vop_islocked_desc, nfs_islocked }, /* islocked */
20160400Smckusick { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
20253806Smckusick { &vop_advlock_desc, fifo_advlock }, /* advlock */
20353806Smckusick { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
20453806Smckusick { &vop_valloc_desc, fifo_valloc }, /* valloc */
20566079Shibler { &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */
20653806Smckusick { &vop_vfree_desc, fifo_vfree }, /* vfree */
20753806Smckusick { &vop_truncate_desc, fifo_truncate }, /* truncate */
20853806Smckusick { &vop_update_desc, nfs_update }, /* update */
20957809Smckusick { &vop_bwrite_desc, vn_bwrite },
21053554Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
21140294Smckusick };
21253554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
21353554Sheideman { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
21440294Smckusick
21556289Smckusick void nqnfs_clientlease();
21668653Smckusick int nfs_commit();
21756289Smckusick
21848054Smckusick /*
21952196Smckusick * Global variables
22048054Smckusick */
22168653Smckusick extern u_long nfs_true, nfs_false;
22268653Smckusick extern struct nfsstats nfsstats;
22368653Smckusick extern nfstype nfsv3_type[9];
22441905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
22546988Smckusick int nfs_numasync = 0;
22654740Smckusick #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
22738414Smckusick
22838414Smckusick /*
22938414Smckusick * nfs null call from vfs.
23038414Smckusick */
23152234Sheideman int
nfs_null(vp,cred,procp)23252196Smckusick nfs_null(vp, cred, procp)
23338414Smckusick struct vnode *vp;
23438414Smckusick struct ucred *cred;
23552196Smckusick struct proc *procp;
23638414Smckusick {
23739488Smckusick caddr_t bpos, dpos;
23839488Smckusick int error = 0;
23939488Smckusick struct mbuf *mreq, *mrep, *md, *mb;
24038414Smckusick
24152196Smckusick nfsm_reqhead(vp, NFSPROC_NULL, 0);
24252196Smckusick nfsm_request(vp, NFSPROC_NULL, procp, cred);
24338414Smckusick nfsm_reqdone;
24438414Smckusick return (error);
24538414Smckusick }
24638414Smckusick
24738414Smckusick /*
24838414Smckusick * nfs access vnode op.
24968653Smckusick * For nfs version 2, just return ok. File accesses may fail later.
25068653Smckusick * For nfs version 3, use the access rpc to check accessibility. If file modes
25168653Smckusick * are changed on the server, accesses might still fail later.
25238414Smckusick */
25352234Sheideman int
nfs_access(ap)25453806Smckusick nfs_access(ap)
25554668Smckusick struct vop_access_args /* {
25654668Smckusick struct vnode *a_vp;
25754668Smckusick int a_mode;
25854668Smckusick struct ucred *a_cred;
25954668Smckusick struct proc *a_p;
26054668Smckusick } */ *ap;
26138414Smckusick {
26256364Smckusick register struct vnode *vp = ap->a_vp;
26356364Smckusick register u_long *tl;
26456364Smckusick register caddr_t cp;
26568653Smckusick register int t1, t2;
26668653Smckusick caddr_t bpos, dpos, cp2;
26768653Smckusick int error = 0, attrflag;
26856364Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
26968653Smckusick u_long mode, rmode;
27068653Smckusick int v3 = NFS_ISV3(vp);
27138414Smckusick
27238414Smckusick /*
273*69743Smckusick * Disallow write attempts on filesystems mounted read-only;
274*69743Smckusick * unless the file is a socket, fifo, or a block or character
275*69743Smckusick * device resident on the filesystem.
276*69743Smckusick */
277*69743Smckusick if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
278*69743Smckusick switch (vp->v_type) {
279*69743Smckusick case VREG: case VDIR: case VLNK:
280*69743Smckusick return (EROFS);
281*69743Smckusick }
282*69743Smckusick }
283*69743Smckusick /*
28468653Smckusick * For nfs v3, do an access rpc, otherwise you are stuck emulating
28556708Smckusick * ufs_access() locally using the vattr. This may not be correct,
28656708Smckusick * since the server may apply other access criteria such as
28756708Smckusick * client uid-->server uid mapping that we do not know about, but
28856708Smckusick * this is better than just returning anything that is lying about
28956708Smckusick * in the cache.
29038414Smckusick */
29168653Smckusick if (v3) {
29268653Smckusick nfsstats.rpccnt[NFSPROC_ACCESS]++;
29368653Smckusick nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
29468653Smckusick nfsm_fhtom(vp, v3);
29568653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
29656364Smckusick if (ap->a_mode & VREAD)
29768653Smckusick mode = NFSV3ACCESS_READ;
29856364Smckusick else
29968653Smckusick mode = 0;
30068653Smckusick if (vp->v_type == VDIR) {
30168653Smckusick if (ap->a_mode & VWRITE)
30268653Smckusick mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
30368653Smckusick NFSV3ACCESS_DELETE);
30468653Smckusick if (ap->a_mode & VEXEC)
30568653Smckusick mode |= NFSV3ACCESS_LOOKUP;
30668653Smckusick } else {
30768653Smckusick if (ap->a_mode & VWRITE)
30868653Smckusick mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
30968653Smckusick if (ap->a_mode & VEXEC)
31068653Smckusick mode |= NFSV3ACCESS_EXECUTE;
31168653Smckusick }
31268653Smckusick *tl = txdr_unsigned(mode);
31368653Smckusick nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
31468653Smckusick nfsm_postop_attr(vp, attrflag);
31568653Smckusick if (!error) {
31668653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
31768653Smckusick rmode = fxdr_unsigned(u_long, *tl);
31868653Smckusick /*
31968653Smckusick * The NFS V3 spec does not clarify whether or not
32068653Smckusick * the returned access bits can be a superset of
32168653Smckusick * the ones requested, so...
32268653Smckusick */
32368653Smckusick if ((rmode & mode) != mode)
32468653Smckusick error = EACCES;
32568653Smckusick }
32656364Smckusick nfsm_reqdone;
32738884Smacklem return (error);
32856364Smckusick } else
32956708Smckusick return (nfsspec_access(ap));
33038414Smckusick }
33138414Smckusick
33238414Smckusick /*
33338414Smckusick * nfs open vnode op
33456289Smckusick * Check to see if the type is ok
33552196Smckusick * and that deletion is not in progress.
33656289Smckusick * For paged in text files, you will need to flush the page cache
33756289Smckusick * if consistency is lost.
33838414Smckusick */
33939488Smckusick /* ARGSUSED */
34052234Sheideman int
nfs_open(ap)34153806Smckusick nfs_open(ap)
34254668Smckusick struct vop_open_args /* {
34354668Smckusick struct vnode *a_vp;
34454668Smckusick int a_mode;
34554668Smckusick struct ucred *a_cred;
34654668Smckusick struct proc *a_p;
34754668Smckusick } */ *ap;
34838414Smckusick {
34953806Smckusick register struct vnode *vp = ap->a_vp;
35056289Smckusick struct nfsnode *np = VTONFS(vp);
35156289Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount);
35256289Smckusick struct vattr vattr;
35356289Smckusick int error;
35438414Smckusick
35553806Smckusick if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
35668653Smckusick { printf("open eacces vtyp=%d\n",vp->v_type);
35738414Smckusick return (EACCES);
35868653Smckusick }
35968653Smckusick /*
36068653Smckusick * Get a valid lease. If cached data is stale, flush it.
36168653Smckusick */
36268653Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) {
36368653Smckusick if (NQNFS_CKINVALID(vp, np, ND_READ)) {
36456289Smckusick do {
36568653Smckusick error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
36668653Smckusick ap->a_p);
36756289Smckusick } while (error == NQNFS_EXPIRED);
36856289Smckusick if (error)
36956289Smckusick return (error);
37059706Smckusick if (np->n_lrev != np->n_brev ||
37159706Smckusick (np->n_flag & NQNFSNONCACHE)) {
37257791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
37357791Smckusick ap->a_p, 1)) == EINTR)
37457791Smckusick return (error);
37556289Smckusick (void) vnode_pager_uncache(vp);
37656289Smckusick np->n_brev = np->n_lrev;
37756289Smckusick }
37856289Smckusick }
37968653Smckusick } else {
38056289Smckusick if (np->n_flag & NMODIFIED) {
38157791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
38257791Smckusick ap->a_p, 1)) == EINTR)
38357791Smckusick return (error);
38456289Smckusick (void) vnode_pager_uncache(vp);
38556289Smckusick np->n_attrstamp = 0;
38668653Smckusick if (vp->v_type == VDIR)
38768653Smckusick np->n_direofoffset = 0;
38868653Smckusick error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
38968653Smckusick if (error)
39056289Smckusick return (error);
39156289Smckusick np->n_mtime = vattr.va_mtime.ts_sec;
39256289Smckusick } else {
39368653Smckusick error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
39468653Smckusick if (error)
39556289Smckusick return (error);
39656289Smckusick if (np->n_mtime != vattr.va_mtime.ts_sec) {
39768653Smckusick if (vp->v_type == VDIR)
39868653Smckusick np->n_direofoffset = 0;
39957791Smckusick if ((error = nfs_vinvalbuf(vp, V_SAVE,
40057791Smckusick ap->a_cred, ap->a_p, 1)) == EINTR)
40157791Smckusick return (error);
40256289Smckusick (void) vnode_pager_uncache(vp);
40356289Smckusick np->n_mtime = vattr.va_mtime.ts_sec;
40456289Smckusick }
40556289Smckusick }
40668653Smckusick }
40768653Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
40856289Smckusick np->n_attrstamp = 0; /* For Open/Close consistency */
40952196Smckusick return (0);
41038414Smckusick }
41138414Smckusick
41238414Smckusick /*
41338414Smckusick * nfs close vnode op
41468653Smckusick * What an NFS client should do upon close after writing is a debatable issue.
41568653Smckusick * Most NFS clients push delayed writes to the server upon close, basically for
41668653Smckusick * two reasons:
41768653Smckusick * 1 - So that any write errors may be reported back to the client process
41868653Smckusick * doing the close system call. By far the two most likely errors are
41968653Smckusick * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
42068653Smckusick * 2 - To put a worst case upper bound on cache inconsistency between
42168653Smckusick * multiple clients for the file.
42268653Smckusick * There is also a consistency problem for Version 2 of the protocol w.r.t.
42368653Smckusick * not being able to tell if other clients are writing a file concurrently,
42468653Smckusick * since there is no way of knowing if the changed modify time in the reply
42568653Smckusick * is only due to the write for this client.
42668653Smckusick * (NFS Version 3 provides weak cache consistency data in the reply that
42768653Smckusick * should be sufficient to detect and handle this case.)
42868653Smckusick *
42968653Smckusick * The current code does the following:
43068653Smckusick * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
43168653Smckusick * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
43268653Smckusick * or commit them (this satisfies 1 and 2 except for the
43368653Smckusick * case where the server crashes after this close but
43468653Smckusick * before the commit RPC, which is felt to be "good
43568653Smckusick * enough". Changing the last argument to nfs_flush() to
43668653Smckusick * a 1 would force a commit operation, if it is felt a
43768653Smckusick * commit is necessary now.
43868653Smckusick * for NQNFS - do nothing now, since 2 is dealt with via leases and
43968653Smckusick * 1 should be dealt with via an fsync() system call for
44068653Smckusick * cases where write errors are important.
44138414Smckusick */
44239488Smckusick /* ARGSUSED */
44352234Sheideman int
nfs_close(ap)44453806Smckusick nfs_close(ap)
44554451Smckusick struct vop_close_args /* {
44654451Smckusick struct vnodeop_desc *a_desc;
44754451Smckusick struct vnode *a_vp;
44854451Smckusick int a_fflag;
44954451Smckusick struct ucred *a_cred;
45054451Smckusick struct proc *a_p;
45154451Smckusick } */ *ap;
45238414Smckusick {
45353806Smckusick register struct vnode *vp = ap->a_vp;
45453806Smckusick register struct nfsnode *np = VTONFS(vp);
45539341Smckusick int error = 0;
45638414Smckusick
45753806Smckusick if (vp->v_type == VREG) {
45853806Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
45953629Smckusick (np->n_flag & NMODIFIED)) {
46068653Smckusick if (NFS_ISV3(vp))
46168653Smckusick error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
46268653Smckusick else
46368653Smckusick error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
46441905Smckusick np->n_attrstamp = 0;
46553629Smckusick }
46653629Smckusick if (np->n_flag & NWRITEERR) {
46753629Smckusick np->n_flag &= ~NWRITEERR;
46853629Smckusick error = np->n_error;
46953629Smckusick }
47038884Smacklem }
47138414Smckusick return (error);
47238414Smckusick }
47338414Smckusick
47438414Smckusick /*
47538414Smckusick * nfs getattr call from vfs.
47638414Smckusick */
47752234Sheideman int
nfs_getattr(ap)47853805Smckusick nfs_getattr(ap)
47954668Smckusick struct vop_getattr_args /* {
48054668Smckusick struct vnode *a_vp;
48154668Smckusick struct vattr *a_vap;
48254668Smckusick struct ucred *a_cred;
48354668Smckusick struct proc *a_p;
48454668Smckusick } */ *ap;
48538414Smckusick {
48653805Smckusick register struct vnode *vp = ap->a_vp;
48753805Smckusick register struct nfsnode *np = VTONFS(vp);
48839488Smckusick register caddr_t cp;
48968653Smckusick register u_long *tl;
49068653Smckusick register int t1, t2;
49139488Smckusick caddr_t bpos, dpos;
49239488Smckusick int error = 0;
49339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
49468653Smckusick int v3 = NFS_ISV3(vp);
49538414Smckusick
49653805Smckusick /*
49753805Smckusick * Update local times for special files.
49853805Smckusick */
49956329Smckusick if (np->n_flag & (NACC | NUPD))
50053805Smckusick np->n_flag |= NCHG;
50153805Smckusick /*
50253805Smckusick * First look in the cache.
50353805Smckusick */
50453805Smckusick if (nfs_getattrcache(vp, ap->a_vap) == 0)
50538414Smckusick return (0);
50638414Smckusick nfsstats.rpccnt[NFSPROC_GETATTR]++;
50768653Smckusick nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
50868653Smckusick nfsm_fhtom(vp, v3);
50953805Smckusick nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
51068653Smckusick if (!error)
51168653Smckusick nfsm_loadattr(vp, ap->a_vap);
51238414Smckusick nfsm_reqdone;
51338414Smckusick return (error);
51438414Smckusick }
51538414Smckusick
51638414Smckusick /*
51738414Smckusick * nfs setattr call.
51838414Smckusick */
51952234Sheideman int
nfs_setattr(ap)52053806Smckusick nfs_setattr(ap)
52154451Smckusick struct vop_setattr_args /* {
52254451Smckusick struct vnodeop_desc *a_desc;
52354451Smckusick struct vnode *a_vp;
52454451Smckusick struct vattr *a_vap;
52554451Smckusick struct ucred *a_cred;
52654451Smckusick struct proc *a_p;
52754451Smckusick } */ *ap;
52838414Smckusick {
52968653Smckusick register struct vnode *vp = ap->a_vp;
53068653Smckusick register struct nfsnode *np = VTONFS(vp);
53168653Smckusick register struct vattr *vap = ap->a_vap;
53268653Smckusick int error = 0;
53368653Smckusick u_quad_t tsize;
53468653Smckusick
53568653Smckusick #ifndef nolint
53668653Smckusick tsize = (u_quad_t)0;
53768653Smckusick #endif
538*69743Smckusick /*
539*69743Smckusick * Disallow write attempts if the filesystem is mounted read-only.
540*69743Smckusick */
541*69743Smckusick if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
542*69743Smckusick vap->va_gid != (gid_t)VNOVAL || vap->va_atime.ts_sec != VNOVAL ||
543*69743Smckusick vap->va_mtime.ts_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
544*69743Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY))
545*69743Smckusick return (EROFS);
54668653Smckusick if (vap->va_size != VNOVAL) {
54768653Smckusick switch (vp->v_type) {
54868653Smckusick case VDIR:
54968653Smckusick return (EISDIR);
55068653Smckusick case VCHR:
55168653Smckusick case VBLK:
552*69743Smckusick case VSOCK:
553*69743Smckusick case VFIFO:
55468653Smckusick if (vap->va_mtime.ts_sec == VNOVAL &&
55568653Smckusick vap->va_atime.ts_sec == VNOVAL &&
55668653Smckusick vap->va_mode == (u_short)VNOVAL &&
55768653Smckusick vap->va_uid == (uid_t)VNOVAL &&
55868653Smckusick vap->va_gid == (gid_t)VNOVAL)
55968653Smckusick return (0);
56068653Smckusick vap->va_size = VNOVAL;
56168653Smckusick break;
56268653Smckusick default:
563*69743Smckusick /*
564*69743Smckusick * Disallow write attempts if the filesystem is
565*69743Smckusick * mounted read-only.
566*69743Smckusick */
567*69743Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY)
568*69743Smckusick return (EROFS);
56968653Smckusick if (np->n_flag & NMODIFIED) {
57068653Smckusick if (vap->va_size == 0)
57168653Smckusick error = nfs_vinvalbuf(vp, 0,
57268653Smckusick ap->a_cred, ap->a_p, 1);
57368653Smckusick else
57468653Smckusick error = nfs_vinvalbuf(vp, V_SAVE,
57568653Smckusick ap->a_cred, ap->a_p, 1);
57668653Smckusick if (error)
57768653Smckusick return (error);
57868653Smckusick }
57968653Smckusick tsize = np->n_size;
58068653Smckusick np->n_size = np->n_vattr.va_size = vap->va_size;
58168653Smckusick vnode_pager_setsize(vp, (u_long)np->n_size);
58268653Smckusick };
58368653Smckusick } else if ((vap->va_mtime.ts_sec != VNOVAL ||
58468653Smckusick vap->va_atime.ts_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
58568653Smckusick vp->v_type == VREG &&
58668653Smckusick (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
58768653Smckusick ap->a_p, 1)) == EINTR)
58868653Smckusick return (error);
58968653Smckusick error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
59068653Smckusick if (error) {
59168653Smckusick np->n_size = np->n_vattr.va_size = tsize;
59268653Smckusick vnode_pager_setsize(vp, (u_long)np->n_size);
59368653Smckusick }
59468653Smckusick return (error);
59568653Smckusick }
59668653Smckusick
59768653Smckusick /*
59868653Smckusick * Do an nfs setattr rpc.
59968653Smckusick */
60068653Smckusick int
nfs_setattrrpc(vp,vap,cred,procp)60168653Smckusick nfs_setattrrpc(vp, vap, cred, procp)
60268653Smckusick register struct vnode *vp;
60368653Smckusick register struct vattr *vap;
60468653Smckusick struct ucred *cred;
60568653Smckusick struct proc *procp;
60668653Smckusick {
60738884Smacklem register struct nfsv2_sattr *sp;
60839488Smckusick register caddr_t cp;
60968653Smckusick register long t1, t2;
61052196Smckusick caddr_t bpos, dpos, cp2;
61152196Smckusick u_long *tl;
61268653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR;
61339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
61468653Smckusick u_quad_t frev;
61568653Smckusick int v3 = NFS_ISV3(vp);
61638414Smckusick
61768653Smckusick nfsstats.rpccnt[NFSPROC_SETATTR]++;
61868653Smckusick nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
61968653Smckusick nfsm_fhtom(vp, v3);
62068653Smckusick if (v3) {
62168653Smckusick if (vap->va_mode != (u_short)VNOVAL) {
62268653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
62368653Smckusick *tl++ = nfs_true;
62468653Smckusick *tl = txdr_unsigned(vap->va_mode);
62568653Smckusick } else {
62668653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
62768653Smckusick *tl = nfs_false;
62868653Smckusick }
62968653Smckusick if (vap->va_uid != (uid_t)VNOVAL) {
63068653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
63168653Smckusick *tl++ = nfs_true;
63268653Smckusick *tl = txdr_unsigned(vap->va_uid);
63368653Smckusick } else {
63468653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
63568653Smckusick *tl = nfs_false;
63668653Smckusick }
63768653Smckusick if (vap->va_gid != (gid_t)VNOVAL) {
63868653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
63968653Smckusick *tl++ = nfs_true;
64068653Smckusick *tl = txdr_unsigned(vap->va_gid);
64168653Smckusick } else {
64268653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
64368653Smckusick *tl = nfs_false;
64468653Smckusick }
64557791Smckusick if (vap->va_size != VNOVAL) {
64668653Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
64768653Smckusick *tl++ = nfs_true;
64868653Smckusick txdr_hyper(&vap->va_size, tl);
64968653Smckusick } else {
65068653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
65168653Smckusick *tl = nfs_false;
65268653Smckusick }
65368653Smckusick if (vap->va_atime.ts_sec != VNOVAL) {
65468653Smckusick if (vap->va_atime.ts_sec != time.tv_sec) {
65568653Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
65668653Smckusick *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
65768653Smckusick txdr_nfsv3time(&vap->va_atime, tl);
65868653Smckusick } else {
65968653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
66068653Smckusick *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
66157791Smckusick }
66268653Smckusick } else {
66368653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
66468653Smckusick *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
66568653Smckusick }
66668653Smckusick if (vap->va_mtime.ts_sec != VNOVAL) {
66768653Smckusick if (vap->va_mtime.ts_sec != time.tv_sec) {
66868653Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
66968653Smckusick *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
67068653Smckusick txdr_nfsv3time(&vap->va_atime, tl);
67168653Smckusick } else {
67268653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
67368653Smckusick *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
67468653Smckusick }
67568653Smckusick } else {
67668653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
67768653Smckusick *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
67868653Smckusick }
67968653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
68068653Smckusick *tl = nfs_false;
68156289Smckusick } else {
68268653Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
68368653Smckusick if (vap->va_mode == (u_short)VNOVAL)
68468653Smckusick sp->sa_mode = VNOVAL;
68568653Smckusick else
68668653Smckusick sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
68768653Smckusick if (vap->va_uid == (uid_t)VNOVAL)
68868653Smckusick sp->sa_uid = VNOVAL;
68968653Smckusick else
69068653Smckusick sp->sa_uid = txdr_unsigned(vap->va_uid);
69168653Smckusick if (vap->va_gid == (gid_t)VNOVAL)
69268653Smckusick sp->sa_gid = VNOVAL;
69368653Smckusick else
69468653Smckusick sp->sa_gid = txdr_unsigned(vap->va_gid);
69568653Smckusick sp->sa_size = txdr_unsigned(vap->va_size);
69668653Smckusick txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
69768653Smckusick txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
69856289Smckusick }
69968653Smckusick nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
70068653Smckusick if (v3) {
70168653Smckusick nfsm_wcc_data(vp, wccflag);
70268653Smckusick } else
70368653Smckusick nfsm_loadattr(vp, (struct vattr *)0);
70438414Smckusick nfsm_reqdone;
70538414Smckusick return (error);
70638414Smckusick }
70738414Smckusick
70838414Smckusick /*
70938414Smckusick * nfs lookup call, one step at a time...
71038414Smckusick * First look in cache
71138414Smckusick * If not found, unlock the directory nfsnode and do the rpc
71238414Smckusick */
71352234Sheideman int
nfs_lookup(ap)71453806Smckusick nfs_lookup(ap)
71554451Smckusick struct vop_lookup_args /* {
71654451Smckusick struct vnodeop_desc *a_desc;
71754451Smckusick struct vnode *a_dvp;
71854451Smckusick struct vnode **a_vpp;
71954451Smckusick struct componentname *a_cnp;
72054451Smckusick } */ *ap;
72138414Smckusick {
72253806Smckusick register struct componentname *cnp = ap->a_cnp;
72353806Smckusick register struct vnode *dvp = ap->a_dvp;
72454668Smckusick register struct vnode **vpp = ap->a_vpp;
72555184Smckusick register int flags = cnp->cn_flags;
72669424Smckusick register struct proc *p = cnp->cn_proc;
72768653Smckusick register struct vnode *newvp;
72848054Smckusick register u_long *tl;
72939488Smckusick register caddr_t cp;
73039488Smckusick register long t1, t2;
73152196Smckusick struct nfsmount *nmp;
73239488Smckusick caddr_t bpos, dpos, cp2;
73339488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
73438414Smckusick long len;
73568653Smckusick nfsfh_t *fhp;
73638414Smckusick struct nfsnode *np;
73768653Smckusick int lockparent, wantparent, error = 0, attrflag, fhsize;
73868653Smckusick int v3 = NFS_ISV3(dvp);
73938414Smckusick
740*69743Smckusick if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
741*69743Smckusick (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
742*69743Smckusick return (EROFS);
74368653Smckusick *vpp = NULLVP;
74453806Smckusick if (dvp->v_type != VDIR)
74538414Smckusick return (ENOTDIR);
74655184Smckusick lockparent = flags & LOCKPARENT;
74755184Smckusick wantparent = flags & (LOCKPARENT|WANTPARENT);
74853806Smckusick nmp = VFSTONFS(dvp->v_mount);
74953806Smckusick np = VTONFS(dvp);
75054668Smckusick if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
75138884Smacklem struct vattr vattr;
75238884Smacklem int vpid;
75338884Smacklem
75468653Smckusick newvp = *vpp;
75568653Smckusick vpid = newvp->v_id;
75638414Smckusick /*
75738884Smacklem * See the comment starting `Step through' in ufs/ufs_lookup.c
75838884Smacklem * for an explanation of the locking protocol
75938414Smckusick */
76068653Smckusick if (dvp == newvp) {
76168653Smckusick VREF(newvp);
76239441Smckusick error = 0;
76352196Smckusick } else
76469424Smckusick error = vget(newvp, LK_EXCLUSIVE, p);
76539441Smckusick if (!error) {
76668653Smckusick if (vpid == newvp->v_id) {
76768653Smckusick if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
76868653Smckusick && vattr.va_ctime.ts_sec == VTONFS(newvp)->n_ctime) {
76939441Smckusick nfsstats.lookupcache_hits++;
77053806Smckusick if (cnp->cn_nameiop != LOOKUP &&
77155184Smckusick (flags & ISLASTCN))
77253806Smckusick cnp->cn_flags |= SAVENAME;
77339441Smckusick return (0);
77440251Smckusick }
77568653Smckusick cache_purge(newvp);
77639441Smckusick }
77768653Smckusick vrele(newvp);
77838884Smacklem }
77954668Smckusick *vpp = NULLVP;
78052196Smckusick }
78139341Smckusick error = 0;
78268653Smckusick newvp = NULLVP;
78338414Smckusick nfsstats.lookupcache_misses++;
78438414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++;
78553806Smckusick len = cnp->cn_namelen;
78668653Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP,
78768653Smckusick NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
78868653Smckusick nfsm_fhtom(dvp, v3);
78953806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
79053806Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
79138414Smckusick if (error) {
79268653Smckusick nfsm_postop_attr(dvp, attrflag);
79368653Smckusick m_freem(mrep);
79468653Smckusick goto nfsmout;
79538414Smckusick }
79668653Smckusick nfsm_getfh(fhp, fhsize, v3);
79738414Smckusick
79838414Smckusick /*
79952196Smckusick * Handle RENAME case...
80038414Smckusick */
80155184Smckusick if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
80268653Smckusick if (NFS_CMPFH(np, fhp, fhsize)) {
80338414Smckusick m_freem(mrep);
80438414Smckusick return (EISDIR);
80538414Smckusick }
80668653Smckusick if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
80738414Smckusick m_freem(mrep);
80838414Smckusick return (error);
80938414Smckusick }
81038414Smckusick newvp = NFSTOV(np);
81168653Smckusick if (v3) {
81268653Smckusick nfsm_postop_attr(newvp, attrflag);
81368653Smckusick nfsm_postop_attr(dvp, attrflag);
81468653Smckusick } else
81568653Smckusick nfsm_loadattr(newvp, (struct vattr *)0);
81654668Smckusick *vpp = newvp;
81745037Smckusick m_freem(mrep);
81853806Smckusick cnp->cn_flags |= SAVENAME;
81938414Smckusick return (0);
82038414Smckusick }
82138414Smckusick
82268653Smckusick if (NFS_CMPFH(np, fhp, fhsize)) {
82353806Smckusick VREF(dvp);
82453806Smckusick newvp = dvp;
82538414Smckusick } else {
82668653Smckusick if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
82738414Smckusick m_freem(mrep);
82838414Smckusick return (error);
82938414Smckusick }
83038414Smckusick newvp = NFSTOV(np);
83138414Smckusick }
83268653Smckusick if (v3) {
83368653Smckusick nfsm_postop_attr(newvp, attrflag);
83468653Smckusick nfsm_postop_attr(dvp, attrflag);
83568653Smckusick } else
83668653Smckusick nfsm_loadattr(newvp, (struct vattr *)0);
83755184Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
83853806Smckusick cnp->cn_flags |= SAVENAME;
83955184Smckusick if ((cnp->cn_flags & MAKEENTRY) &&
84055184Smckusick (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
84168653Smckusick np->n_ctime = np->n_vattr.va_ctime.ts_sec;
84268653Smckusick cache_enter(dvp, newvp, cnp);
84340251Smckusick }
84468653Smckusick *vpp = newvp;
84568653Smckusick nfsm_reqdone;
84668653Smckusick if (error) {
84768653Smckusick if (newvp != NULLVP)
84868653Smckusick vrele(newvp);
84968653Smckusick if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
850*69743Smckusick (flags & ISLASTCN) && error == ENOENT) {
851*69743Smckusick if (dvp->v_mount->mnt_flag & MNT_RDONLY)
852*69743Smckusick error = EROFS;
853*69743Smckusick else
854*69743Smckusick error = EJUSTRETURN;
855*69743Smckusick }
85668653Smckusick if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
85768653Smckusick cnp->cn_flags |= SAVENAME;
85868653Smckusick }
85968653Smckusick return (error);
86038414Smckusick }
86138414Smckusick
86238414Smckusick /*
86341905Smckusick * nfs read call.
86441905Smckusick * Just call nfs_bioread() to do the work.
86541905Smckusick */
86652234Sheideman int
nfs_read(ap)86753806Smckusick nfs_read(ap)
86854668Smckusick struct vop_read_args /* {
86954668Smckusick struct vnode *a_vp;
87054668Smckusick struct uio *a_uio;
87154668Smckusick int a_ioflag;
87254668Smckusick struct ucred *a_cred;
87354668Smckusick } */ *ap;
87441905Smckusick {
87553806Smckusick register struct vnode *vp = ap->a_vp;
87653806Smckusick
87753806Smckusick if (vp->v_type != VREG)
87841905Smckusick return (EPERM);
87953806Smckusick return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
88041905Smckusick }
88141905Smckusick
88241905Smckusick /*
88338414Smckusick * nfs readlink call
88438414Smckusick */
88552234Sheideman int
nfs_readlink(ap)88653806Smckusick nfs_readlink(ap)
88754668Smckusick struct vop_readlink_args /* {
88854668Smckusick struct vnode *a_vp;
88954668Smckusick struct uio *a_uio;
89054668Smckusick struct ucred *a_cred;
89154668Smckusick } */ *ap;
89241905Smckusick {
89353806Smckusick register struct vnode *vp = ap->a_vp;
89453806Smckusick
89553806Smckusick if (vp->v_type != VLNK)
89641905Smckusick return (EPERM);
89753806Smckusick return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
89841905Smckusick }
89941905Smckusick
90041905Smckusick /*
90141905Smckusick * Do a readlink rpc.
90241905Smckusick * Called by nfs_doio() from below the buffer cache.
90341905Smckusick */
90452234Sheideman int
nfs_readlinkrpc(vp,uiop,cred)90548054Smckusick nfs_readlinkrpc(vp, uiop, cred)
90639488Smckusick register struct vnode *vp;
90738414Smckusick struct uio *uiop;
90838414Smckusick struct ucred *cred;
90938414Smckusick {
91048054Smckusick register u_long *tl;
91139488Smckusick register caddr_t cp;
91268653Smckusick register long t1, t2;
91339488Smckusick caddr_t bpos, dpos, cp2;
91468653Smckusick int error = 0, len, attrflag;
91539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91668653Smckusick int v3 = NFS_ISV3(vp);
91738414Smckusick
91838414Smckusick nfsstats.rpccnt[NFSPROC_READLINK]++;
91968653Smckusick nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
92068653Smckusick nfsm_fhtom(vp, v3);
92152196Smckusick nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
92268653Smckusick if (v3)
92368653Smckusick nfsm_postop_attr(vp, attrflag);
92468653Smckusick if (!error) {
92568653Smckusick nfsm_strsiz(len, NFS_MAXPATHLEN);
92668653Smckusick nfsm_mtouio(uiop, len);
92768653Smckusick }
92838414Smckusick nfsm_reqdone;
92938414Smckusick return (error);
93038414Smckusick }
93138414Smckusick
93238414Smckusick /*
93341905Smckusick * nfs read rpc call
93441905Smckusick * Ditto above
93538414Smckusick */
93652234Sheideman int
nfs_readrpc(vp,uiop,cred)93748054Smckusick nfs_readrpc(vp, uiop, cred)
93839488Smckusick register struct vnode *vp;
93938414Smckusick struct uio *uiop;
94038414Smckusick struct ucred *cred;
94138414Smckusick {
94248054Smckusick register u_long *tl;
94339488Smckusick register caddr_t cp;
94468653Smckusick register long t1, t2;
94539488Smckusick caddr_t bpos, dpos, cp2;
94639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
94738414Smckusick struct nfsmount *nmp;
94868653Smckusick int error = 0, len, retlen, tsiz, eof, attrflag;
94968653Smckusick int v3 = NFS_ISV3(vp);
95038414Smckusick
95168653Smckusick #ifndef nolint
95268653Smckusick eof = 0;
95368653Smckusick #endif
95441398Smckusick nmp = VFSTONFS(vp->v_mount);
95538414Smckusick tsiz = uiop->uio_resid;
95668653Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
95756289Smckusick return (EFBIG);
95838414Smckusick while (tsiz > 0) {
95938414Smckusick nfsstats.rpccnt[NFSPROC_READ]++;
96038414Smckusick len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
96168653Smckusick nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
96268653Smckusick nfsm_fhtom(vp, v3);
96368653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
96468653Smckusick if (v3) {
96556289Smckusick txdr_hyper(&uiop->uio_offset, tl);
96656289Smckusick *(tl + 2) = txdr_unsigned(len);
96756289Smckusick } else {
96856289Smckusick *tl++ = txdr_unsigned(uiop->uio_offset);
96956289Smckusick *tl++ = txdr_unsigned(len);
97056289Smckusick *tl = 0;
97156289Smckusick }
97252196Smckusick nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
97368653Smckusick if (v3) {
97468653Smckusick nfsm_postop_attr(vp, attrflag);
97568653Smckusick if (error) {
97668653Smckusick m_freem(mrep);
97768653Smckusick goto nfsmout;
97868653Smckusick }
97968653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
98068653Smckusick eof = fxdr_unsigned(int, *(tl + 1));
98168653Smckusick } else
98268653Smckusick nfsm_loadattr(vp, (struct vattr *)0);
98338414Smckusick nfsm_strsiz(retlen, nmp->nm_rsize);
98438414Smckusick nfsm_mtouio(uiop, retlen);
98538414Smckusick m_freem(mrep);
98668653Smckusick tsiz -= retlen;
98768653Smckusick if (v3) {
98868653Smckusick if (eof || retlen == 0)
98968653Smckusick tsiz = 0;
99068653Smckusick } else if (retlen < len)
99138414Smckusick tsiz = 0;
99238414Smckusick }
99338414Smckusick nfsmout:
99438414Smckusick return (error);
99538414Smckusick }
99638414Smckusick
99738414Smckusick /*
99838414Smckusick * nfs write call
99938414Smckusick */
100052234Sheideman int
nfs_writerpc(vp,uiop,cred,iomode,must_commit)100168653Smckusick nfs_writerpc(vp, uiop, cred, iomode, must_commit)
100239488Smckusick register struct vnode *vp;
100368653Smckusick register struct uio *uiop;
100438414Smckusick struct ucred *cred;
100568653Smckusick int *iomode, *must_commit;
100638414Smckusick {
100748054Smckusick register u_long *tl;
100839488Smckusick register caddr_t cp;
100968653Smckusick register int t1, t2, backup;
101052196Smckusick caddr_t bpos, dpos, cp2;
101139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
101268653Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount);
101352196Smckusick struct nfsnode *np = VTONFS(vp);
101452196Smckusick u_quad_t frev;
101568653Smckusick int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
101668653Smckusick int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
101738414Smckusick
101868653Smckusick #ifndef DIAGNOSTIC
101968653Smckusick if (uiop->uio_iovcnt != 1)
102068653Smckusick panic("nfs: writerpc iovcnt > 1");
102168653Smckusick #endif
102268653Smckusick *must_commit = 0;
102338414Smckusick tsiz = uiop->uio_resid;
102468653Smckusick if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
102556289Smckusick return (EFBIG);
102638414Smckusick while (tsiz > 0) {
102738414Smckusick nfsstats.rpccnt[NFSPROC_WRITE]++;
102838414Smckusick len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
102952196Smckusick nfsm_reqhead(vp, NFSPROC_WRITE,
103068653Smckusick NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
103168653Smckusick nfsm_fhtom(vp, v3);
103268653Smckusick if (v3) {
103368653Smckusick nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
103456289Smckusick txdr_hyper(&uiop->uio_offset, tl);
103556289Smckusick tl += 2;
103668653Smckusick *tl++ = txdr_unsigned(len);
103768653Smckusick *tl++ = txdr_unsigned(*iomode);
103856289Smckusick } else {
103968653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
104056289Smckusick *++tl = txdr_unsigned(uiop->uio_offset);
104156289Smckusick tl += 2;
104256289Smckusick }
104356289Smckusick *tl = txdr_unsigned(len);
104438414Smckusick nfsm_uiotom(uiop, len);
104552196Smckusick nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
104668653Smckusick if (v3) {
104768653Smckusick wccflag = NFSV3_WCCCHK;
104868653Smckusick nfsm_wcc_data(vp, wccflag);
104968653Smckusick if (!error) {
105068653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
105168653Smckusick NFSX_V3WRITEVERF);
105268653Smckusick rlen = fxdr_unsigned(int, *tl++);
105368653Smckusick if (rlen == 0) {
105468653Smckusick error = NFSERR_IO;
105568653Smckusick break;
105668653Smckusick } else if (rlen < len) {
105768653Smckusick backup = len - rlen;
105868653Smckusick uiop->uio_iov->iov_base -= backup;
105968653Smckusick uiop->uio_iov->iov_len += backup;
106068653Smckusick uiop->uio_offset -= backup;
106168653Smckusick uiop->uio_resid += backup;
106268653Smckusick len = rlen;
106368653Smckusick }
106468653Smckusick commit = fxdr_unsigned(int, *tl++);
106568653Smckusick
106668653Smckusick /*
106768653Smckusick * Return the lowest committment level
106868653Smckusick * obtained by any of the RPCs.
106968653Smckusick */
107068653Smckusick if (committed == NFSV3WRITE_FILESYNC)
107168653Smckusick committed = commit;
107268653Smckusick else if (committed == NFSV3WRITE_DATASYNC &&
107368653Smckusick commit == NFSV3WRITE_UNSTABLE)
107468653Smckusick committed = commit;
107568653Smckusick if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
107668653Smckusick bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
107768653Smckusick NFSX_V3WRITEVERF);
107868653Smckusick nmp->nm_flag |= NFSMNT_HASWRITEVERF;
107968653Smckusick } else if (bcmp((caddr_t)tl,
108068653Smckusick (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
108168653Smckusick *must_commit = 1;
108268653Smckusick bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
108368653Smckusick NFSX_V3WRITEVERF);
108468653Smckusick }
108568653Smckusick }
108668653Smckusick } else
108768653Smckusick nfsm_loadattr(vp, (struct vattr *)0);
108868653Smckusick if (wccflag)
108968653Smckusick VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
109038414Smckusick m_freem(mrep);
109138414Smckusick tsiz -= len;
109238414Smckusick }
109338414Smckusick nfsmout:
109468653Smckusick *iomode = committed;
109552196Smckusick if (error)
109652196Smckusick uiop->uio_resid = tsiz;
109738414Smckusick return (error);
109838414Smckusick }
109938414Smckusick
110038414Smckusick /*
110168653Smckusick * nfs mknod rpc
110268653Smckusick * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
110368653Smckusick * mode set to specify the file type and the size field for rdev.
110439459Smckusick */
110552234Sheideman int
nfs_mknodrpc(dvp,vpp,cnp,vap)110668653Smckusick nfs_mknodrpc(dvp, vpp, cnp, vap)
110768653Smckusick register struct vnode *dvp;
110868653Smckusick register struct vnode **vpp;
110968653Smckusick register struct componentname *cnp;
111068653Smckusick register struct vattr *vap;
111139459Smckusick {
111242246Smckusick register struct nfsv2_sattr *sp;
111368653Smckusick register struct nfsv3_sattr *sp3;
111448054Smckusick register u_long *tl;
111542246Smckusick register caddr_t cp;
111656289Smckusick register long t1, t2;
111768653Smckusick struct vnode *newvp = (struct vnode *)0;
111868653Smckusick struct nfsnode *np;
111959116Smckusick struct vattr vattr;
112056289Smckusick char *cp2;
112142246Smckusick caddr_t bpos, dpos;
112268653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
112342246Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
112442246Smckusick u_long rdev;
112568653Smckusick int v3 = NFS_ISV3(dvp);
112639459Smckusick
112753806Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK)
112853806Smckusick rdev = txdr_unsigned(vap->va_rdev);
112968653Smckusick else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
113042246Smckusick rdev = 0xffffffff;
113142246Smckusick else {
113253806Smckusick VOP_ABORTOP(dvp, cnp);
113353806Smckusick vput(dvp);
113442246Smckusick return (EOPNOTSUPP);
113542246Smckusick }
113659116Smckusick if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
113759116Smckusick VOP_ABORTOP(dvp, cnp);
113859116Smckusick vput(dvp);
113959116Smckusick return (error);
114059116Smckusick }
114168653Smckusick nfsstats.rpccnt[NFSPROC_MKNOD]++;
114268653Smckusick nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
114368653Smckusick + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
114468653Smckusick nfsm_fhtom(dvp, v3);
114553806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
114668653Smckusick if (v3) {
114768653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
114868653Smckusick *tl++ = vtonfsv3_type(vap->va_type);
114968653Smckusick sp3 = (struct nfsv3_sattr *)tl;
115068653Smckusick nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
115168653Smckusick if (vap->va_type == VCHR || vap->va_type == VBLK) {
115268653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
115368653Smckusick *tl++ = txdr_unsigned(major(vap->va_rdev));
115468653Smckusick *tl = txdr_unsigned(minor(vap->va_rdev));
115568653Smckusick }
115656289Smckusick } else {
115768653Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
115868653Smckusick sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
115968653Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
116068653Smckusick sp->sa_gid = txdr_unsigned(vattr.va_gid);
116168653Smckusick sp->sa_size = rdev;
116268653Smckusick txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
116368653Smckusick txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
116456289Smckusick }
116568653Smckusick nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
116668653Smckusick if (!error) {
116768653Smckusick nfsm_mtofh(dvp, newvp, v3, gotvp);
116868653Smckusick if (!gotvp) {
116968653Smckusick if (newvp) {
117068653Smckusick vrele(newvp);
117168653Smckusick newvp = (struct vnode *)0;
117268653Smckusick }
117368653Smckusick error = nfs_lookitup(dvp, cnp->cn_nameptr,
117468653Smckusick cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
117568653Smckusick if (!error)
117668653Smckusick newvp = NFSTOV(np);
117768653Smckusick }
117868653Smckusick }
117968653Smckusick if (v3)
118068653Smckusick nfsm_wcc_data(dvp, wccflag);
118142246Smckusick nfsm_reqdone;
118268653Smckusick if (error) {
118368653Smckusick if (newvp)
118468653Smckusick vrele(newvp);
118568653Smckusick } else {
118668653Smckusick if (cnp->cn_flags & MAKEENTRY)
118768653Smckusick cache_enter(dvp, newvp, cnp);
118868653Smckusick *vpp = newvp;
118968653Smckusick }
119053806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
119153806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED;
119268653Smckusick if (!wccflag)
119368653Smckusick VTONFS(dvp)->n_attrstamp = 0;
119453806Smckusick vrele(dvp);
119542246Smckusick return (error);
119639459Smckusick }
119739459Smckusick
119839459Smckusick /*
119968653Smckusick * nfs mknod vop
120068653Smckusick * just call nfs_mknodrpc() to do the work.
120168653Smckusick */
120268653Smckusick /* ARGSUSED */
120368653Smckusick int
nfs_mknod(ap)120468653Smckusick nfs_mknod(ap)
120568653Smckusick struct vop_mknod_args /* {
120668653Smckusick struct vnode *a_dvp;
120768653Smckusick struct vnode **a_vpp;
120868653Smckusick struct componentname *a_cnp;
120968653Smckusick struct vattr *a_vap;
121068653Smckusick } */ *ap;
121168653Smckusick {
121268653Smckusick struct vnode *newvp;
121368653Smckusick int error;
121468653Smckusick
121568653Smckusick error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
121668653Smckusick if (!error)
121768653Smckusick vrele(newvp);
121868653Smckusick return (error);
121968653Smckusick }
122068653Smckusick
122168653Smckusick static u_long create_verf;
122268653Smckusick /*
122338414Smckusick * nfs file create call
122438414Smckusick */
122552234Sheideman int
nfs_create(ap)122653806Smckusick nfs_create(ap)
122754668Smckusick struct vop_create_args /* {
122854668Smckusick struct vnode *a_dvp;
122954668Smckusick struct vnode **a_vpp;
123054668Smckusick struct componentname *a_cnp;
123154668Smckusick struct vattr *a_vap;
123254668Smckusick } */ *ap;
123338414Smckusick {
123453806Smckusick register struct vnode *dvp = ap->a_dvp;
123553806Smckusick register struct vattr *vap = ap->a_vap;
123653806Smckusick register struct componentname *cnp = ap->a_cnp;
123738884Smacklem register struct nfsv2_sattr *sp;
123868653Smckusick register struct nfsv3_sattr *sp3;
123948054Smckusick register u_long *tl;
124039488Smckusick register caddr_t cp;
124139488Smckusick register long t1, t2;
124268653Smckusick struct nfsnode *np = (struct nfsnode *)0;
124368653Smckusick struct vnode *newvp = (struct vnode *)0;
124439488Smckusick caddr_t bpos, dpos, cp2;
124568653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
124639488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
124759116Smckusick struct vattr vattr;
124868653Smckusick int v3 = NFS_ISV3(dvp);
124938414Smckusick
125068653Smckusick /*
125168653Smckusick * Oops, not for me..
125268653Smckusick */
125368653Smckusick if (vap->va_type == VSOCK)
125468653Smckusick return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
125568653Smckusick
125659116Smckusick if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
125759116Smckusick VOP_ABORTOP(dvp, cnp);
125859116Smckusick vput(dvp);
125959116Smckusick return (error);
126059116Smckusick }
126168653Smckusick if (vap->va_vaflags & VA_EXCLUSIVE)
126268653Smckusick fmode |= O_EXCL;
126368653Smckusick again:
126438414Smckusick nfsstats.rpccnt[NFSPROC_CREATE]++;
126568653Smckusick nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
126668653Smckusick nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
126768653Smckusick nfsm_fhtom(dvp, v3);
126853806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
126968653Smckusick if (v3) {
127068653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
127168653Smckusick if (fmode & O_EXCL) {
127268653Smckusick *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
127368653Smckusick nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
127468653Smckusick if (in_ifaddr)
127568653Smckusick *tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr;
127668653Smckusick else
127768653Smckusick *tl++ = create_verf;
127868653Smckusick *tl = ++create_verf;
127968653Smckusick } else {
128068653Smckusick *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
128168653Smckusick nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
128268653Smckusick sp3 = (struct nfsv3_sattr *)tl;
128368653Smckusick nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
128468653Smckusick }
128556289Smckusick } else {
128668653Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
128768653Smckusick sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
128868653Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
128968653Smckusick sp->sa_gid = txdr_unsigned(vattr.va_gid);
129068653Smckusick sp->sa_size = 0;
129168653Smckusick txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
129268653Smckusick txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
129356289Smckusick }
129453806Smckusick nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
129568653Smckusick if (!error) {
129668653Smckusick nfsm_mtofh(dvp, newvp, v3, gotvp);
129768653Smckusick if (!gotvp) {
129868653Smckusick if (newvp) {
129968653Smckusick vrele(newvp);
130068653Smckusick newvp = (struct vnode *)0;
130168653Smckusick }
130268653Smckusick error = nfs_lookitup(dvp, cnp->cn_nameptr,
130368653Smckusick cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
130468653Smckusick if (!error)
130568653Smckusick newvp = NFSTOV(np);
130668653Smckusick }
130768653Smckusick }
130868653Smckusick if (v3)
130968653Smckusick nfsm_wcc_data(dvp, wccflag);
131038414Smckusick nfsm_reqdone;
131168653Smckusick if (error) {
131268653Smckusick if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
131368653Smckusick fmode &= ~O_EXCL;
131468653Smckusick goto again;
131568653Smckusick }
131668653Smckusick if (newvp)
131768653Smckusick vrele(newvp);
131868653Smckusick } else if (v3 && (fmode & O_EXCL))
131968653Smckusick error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
132068653Smckusick if (!error) {
132168653Smckusick if (cnp->cn_flags & MAKEENTRY)
132268653Smckusick cache_enter(dvp, newvp, cnp);
132368653Smckusick *ap->a_vpp = newvp;
132468653Smckusick }
132553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
132653806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED;
132768653Smckusick if (!wccflag)
132868653Smckusick VTONFS(dvp)->n_attrstamp = 0;
132953806Smckusick vrele(dvp);
133038414Smckusick return (error);
133138414Smckusick }
133238414Smckusick
133338414Smckusick /*
133438414Smckusick * nfs file remove call
133541905Smckusick * To try and make nfs semantics closer to ufs semantics, a file that has
133641905Smckusick * other processes using the vnode is renamed instead of removed and then
133739341Smckusick * removed later on the last close.
133841905Smckusick * - If v_usecount > 1
133939341Smckusick * If a rename is not already in the works
134039341Smckusick * call nfs_sillyrename() to set it up
134139341Smckusick * else
134239341Smckusick * do the remove rpc
134338414Smckusick */
134452234Sheideman int
nfs_remove(ap)134553806Smckusick nfs_remove(ap)
134654451Smckusick struct vop_remove_args /* {
134754451Smckusick struct vnodeop_desc *a_desc;
134854451Smckusick struct vnode * a_dvp;
134954451Smckusick struct vnode * a_vp;
135054451Smckusick struct componentname * a_cnp;
135154451Smckusick } */ *ap;
135238414Smckusick {
135353806Smckusick register struct vnode *vp = ap->a_vp;
135453806Smckusick register struct vnode *dvp = ap->a_dvp;
135553806Smckusick register struct componentname *cnp = ap->a_cnp;
135653806Smckusick register struct nfsnode *np = VTONFS(vp);
135748054Smckusick register u_long *tl;
135839488Smckusick register caddr_t cp;
135952196Smckusick register long t2;
136039488Smckusick caddr_t bpos, dpos;
136139488Smckusick int error = 0;
136239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
136368653Smckusick struct vattr vattr;
136468653Smckusick int v3 = NFS_ISV3(dvp);
136538414Smckusick
136668653Smckusick #ifndef DIAGNOSTIC
136768653Smckusick if ((cnp->cn_flags & HASBUF) == 0)
136868653Smckusick panic("nfs_remove: no name");
136968653Smckusick if (vp->v_usecount < 1)
137068653Smckusick panic("nfs_remove: bad v_usecount");
137168653Smckusick #endif
137268653Smckusick if (vp->v_usecount == 1 || (np->n_sillyrename &&
137368653Smckusick VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
137468653Smckusick vattr.va_nlink > 1)) {
137552196Smckusick /*
137652196Smckusick * Purge the name cache so that the chance of a lookup for
137752196Smckusick * the name succeeding while the remove is in progress is
137852196Smckusick * minimized. Without node locking it can still happen, such
137952196Smckusick * that an I/O op returns ESTALE, but since you get this if
138052196Smckusick * another host removes the file..
138152196Smckusick */
138253806Smckusick cache_purge(vp);
138352196Smckusick /*
138468653Smckusick * throw away biocache buffers, mainly to avoid
138568653Smckusick * unnecessary delayed writes later.
138652196Smckusick */
138757791Smckusick error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
138852196Smckusick /* Do the rpc */
138968653Smckusick if (error != EINTR)
139068653Smckusick error = nfs_removerpc(dvp, cnp->cn_nameptr,
139168653Smckusick cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
139239751Smckusick /*
139339751Smckusick * Kludge City: If the first reply to the remove rpc is lost..
139439751Smckusick * the reply to the retransmitted request will be ENOENT
139539751Smckusick * since the file was in fact removed
139639751Smckusick * Therefore, we cheat and return success.
139739751Smckusick */
139839751Smckusick if (error == ENOENT)
139939751Smckusick error = 0;
140068653Smckusick } else if (!np->n_sillyrename)
140168653Smckusick error = nfs_sillyrename(dvp, vp, cnp);
140268653Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
140340042Smckusick np->n_attrstamp = 0;
140453806Smckusick vrele(dvp);
140553806Smckusick vrele(vp);
140638414Smckusick return (error);
140738414Smckusick }
140838414Smckusick
140938414Smckusick /*
141038414Smckusick * nfs file remove rpc called from nfs_inactive
141138414Smckusick */
141252234Sheideman int
nfs_removeit(sp)141354451Smckusick nfs_removeit(sp)
141448364Smckusick register struct sillyrename *sp;
141538414Smckusick {
141668653Smckusick
141768653Smckusick return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
141868653Smckusick (struct proc *)0));
141968653Smckusick }
142068653Smckusick
142168653Smckusick /*
142268653Smckusick * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
142368653Smckusick */
142468653Smckusick int
nfs_removerpc(dvp,name,namelen,cred,proc)142568653Smckusick nfs_removerpc(dvp, name, namelen, cred, proc)
142668653Smckusick register struct vnode *dvp;
142768653Smckusick char *name;
142868653Smckusick int namelen;
142968653Smckusick struct ucred *cred;
143068653Smckusick struct proc *proc;
143168653Smckusick {
143248054Smckusick register u_long *tl;
143339488Smckusick register caddr_t cp;
143468653Smckusick register long t1, t2;
143568653Smckusick caddr_t bpos, dpos, cp2;
143668653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR;
143739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
143868653Smckusick int v3 = NFS_ISV3(dvp);
143938414Smckusick
144038414Smckusick nfsstats.rpccnt[NFSPROC_REMOVE]++;
144168653Smckusick nfsm_reqhead(dvp, NFSPROC_REMOVE,
144268653Smckusick NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
144368653Smckusick nfsm_fhtom(dvp, v3);
144468653Smckusick nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
144568653Smckusick nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
144668653Smckusick if (v3)
144768653Smckusick nfsm_wcc_data(dvp, wccflag);
144838414Smckusick nfsm_reqdone;
144968653Smckusick VTONFS(dvp)->n_flag |= NMODIFIED;
145068653Smckusick if (!wccflag)
145168653Smckusick VTONFS(dvp)->n_attrstamp = 0;
145238414Smckusick return (error);
145338414Smckusick }
145438414Smckusick
145538414Smckusick /*
145638414Smckusick * nfs file rename call
145738414Smckusick */
145852234Sheideman int
nfs_rename(ap)145953806Smckusick nfs_rename(ap)
146054668Smckusick struct vop_rename_args /* {
146154668Smckusick struct vnode *a_fdvp;
146254668Smckusick struct vnode *a_fvp;
146354668Smckusick struct componentname *a_fcnp;
146454668Smckusick struct vnode *a_tdvp;
146554668Smckusick struct vnode *a_tvp;
146654668Smckusick struct componentname *a_tcnp;
146754668Smckusick } */ *ap;
146838414Smckusick {
146953806Smckusick register struct vnode *fvp = ap->a_fvp;
147053806Smckusick register struct vnode *tvp = ap->a_tvp;
147153806Smckusick register struct vnode *fdvp = ap->a_fdvp;
147253806Smckusick register struct vnode *tdvp = ap->a_tdvp;
147353806Smckusick register struct componentname *tcnp = ap->a_tcnp;
147453806Smckusick register struct componentname *fcnp = ap->a_fcnp;
147568653Smckusick int error;
147638414Smckusick
147768653Smckusick #ifndef DIAGNOSTIC
147868653Smckusick if ((tcnp->cn_flags & HASBUF) == 0 ||
147968653Smckusick (fcnp->cn_flags & HASBUF) == 0)
148068653Smckusick panic("nfs_rename: no name");
148168653Smckusick #endif
148253804Spendry /* Check for cross-device rename */
148353806Smckusick if ((fvp->v_mount != tdvp->v_mount) ||
148453806Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) {
148553804Spendry error = EXDEV;
148653804Spendry goto out;
148753804Spendry }
148853804Spendry
148968653Smckusick /*
149068653Smckusick * If the tvp exists and is in use, sillyrename it before doing the
149168653Smckusick * rename of the new file over it.
149268653Smckusick */
149368653Smckusick if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
149468653Smckusick !nfs_sillyrename(tdvp, tvp, tcnp)) {
149568653Smckusick vrele(tvp);
149668653Smckusick tvp = NULL;
149768653Smckusick }
149853804Spendry
149968653Smckusick error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
150068653Smckusick tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
150168653Smckusick tcnp->cn_proc);
150268653Smckusick
150353806Smckusick if (fvp->v_type == VDIR) {
150453806Smckusick if (tvp != NULL && tvp->v_type == VDIR)
150553806Smckusick cache_purge(tdvp);
150653806Smckusick cache_purge(fdvp);
150738414Smckusick }
150853804Spendry out:
150953806Smckusick if (tdvp == tvp)
151053806Smckusick vrele(tdvp);
151143360Smckusick else
151253806Smckusick vput(tdvp);
151353806Smckusick if (tvp)
151453806Smckusick vput(tvp);
151553806Smckusick vrele(fdvp);
151653806Smckusick vrele(fvp);
151740112Smckusick /*
151840112Smckusick * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
151940112Smckusick */
152040112Smckusick if (error == ENOENT)
152140112Smckusick error = 0;
152238414Smckusick return (error);
152338414Smckusick }
152438414Smckusick
152538414Smckusick /*
152641905Smckusick * nfs file rename rpc called from nfs_remove() above
152738414Smckusick */
152852234Sheideman int
nfs_renameit(sdvp,scnp,sp)152952234Sheideman nfs_renameit(sdvp, scnp, sp)
153052234Sheideman struct vnode *sdvp;
153152234Sheideman struct componentname *scnp;
153248364Smckusick register struct sillyrename *sp;
153338414Smckusick {
153468653Smckusick return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
153568653Smckusick sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
153668653Smckusick }
153768653Smckusick
153868653Smckusick /*
153968653Smckusick * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
154068653Smckusick */
154168653Smckusick int
nfs_renamerpc(fdvp,fnameptr,fnamelen,tdvp,tnameptr,tnamelen,cred,proc)154268653Smckusick nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
154368653Smckusick register struct vnode *fdvp;
154468653Smckusick char *fnameptr;
154568653Smckusick int fnamelen;
154668653Smckusick register struct vnode *tdvp;
154768653Smckusick char *tnameptr;
154868653Smckusick int tnamelen;
154968653Smckusick struct ucred *cred;
155068653Smckusick struct proc *proc;
155168653Smckusick {
155248054Smckusick register u_long *tl;
155339488Smckusick register caddr_t cp;
155468653Smckusick register long t1, t2;
155568653Smckusick caddr_t bpos, dpos, cp2;
155668653Smckusick int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
155739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
155868653Smckusick int v3 = NFS_ISV3(fdvp);
155938414Smckusick
156038414Smckusick nfsstats.rpccnt[NFSPROC_RENAME]++;
156168653Smckusick nfsm_reqhead(fdvp, NFSPROC_RENAME,
156268653Smckusick (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
156368653Smckusick nfsm_rndup(tnamelen));
156468653Smckusick nfsm_fhtom(fdvp, v3);
156568653Smckusick nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
156668653Smckusick nfsm_fhtom(tdvp, v3);
156768653Smckusick nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
156868653Smckusick nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
156968653Smckusick if (v3) {
157068653Smckusick nfsm_wcc_data(fdvp, fwccflag);
157168653Smckusick nfsm_wcc_data(tdvp, twccflag);
157268653Smckusick }
157338414Smckusick nfsm_reqdone;
157468653Smckusick VTONFS(fdvp)->n_flag |= NMODIFIED;
157568653Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED;
157668653Smckusick if (!fwccflag)
157768653Smckusick VTONFS(fdvp)->n_attrstamp = 0;
157868653Smckusick if (!twccflag)
157968653Smckusick VTONFS(tdvp)->n_attrstamp = 0;
158038414Smckusick return (error);
158138414Smckusick }
158238414Smckusick
158338414Smckusick /*
158438414Smckusick * nfs hard link create call
158538414Smckusick */
158652234Sheideman int
nfs_link(ap)158753806Smckusick nfs_link(ap)
158854668Smckusick struct vop_link_args /* {
158954668Smckusick struct vnode *a_vp;
159054668Smckusick struct vnode *a_tdvp;
159154668Smckusick struct componentname *a_cnp;
159254668Smckusick } */ *ap;
159338414Smckusick {
159453806Smckusick register struct vnode *vp = ap->a_vp;
159553806Smckusick register struct vnode *tdvp = ap->a_tdvp;
159653806Smckusick register struct componentname *cnp = ap->a_cnp;
159748054Smckusick register u_long *tl;
159839488Smckusick register caddr_t cp;
159968653Smckusick register long t1, t2;
160068653Smckusick caddr_t bpos, dpos, cp2;
160168653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
160239488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
160368653Smckusick int v3 = NFS_ISV3(vp);
160438414Smckusick
160568653Smckusick if (vp->v_mount != tdvp->v_mount) {
160668653Smckusick /*VOP_ABORTOP(vp, cnp);*/
160768653Smckusick if (tdvp == vp)
160868653Smckusick vrele(tdvp);
160968653Smckusick else
161068653Smckusick vput(tdvp);
161153804Spendry return (EXDEV);
161253804Spendry }
161353804Spendry
161467659Smckusick /*
161567659Smckusick * Push all writes to the server, so that the attribute cache
161667659Smckusick * doesn't get "out of sync" with the server.
161767659Smckusick * XXX There should be a better way!
161867659Smckusick */
161968539Smckusick VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
162067659Smckusick
162138414Smckusick nfsstats.rpccnt[NFSPROC_LINK]++;
162268539Smckusick nfsm_reqhead(vp, NFSPROC_LINK,
162368653Smckusick NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
162468653Smckusick nfsm_fhtom(vp, v3);
162568653Smckusick nfsm_fhtom(tdvp, v3);
162653806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
162768539Smckusick nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
162868653Smckusick if (v3) {
162968653Smckusick nfsm_postop_attr(vp, attrflag);
163068653Smckusick nfsm_wcc_data(tdvp, wccflag);
163168653Smckusick }
163238414Smckusick nfsm_reqdone;
163353806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
163468653Smckusick VTONFS(tdvp)->n_flag |= NMODIFIED;
163568653Smckusick if (!attrflag)
163668653Smckusick VTONFS(vp)->n_attrstamp = 0;
163768653Smckusick if (!wccflag)
163868653Smckusick VTONFS(tdvp)->n_attrstamp = 0;
163968653Smckusick vrele(tdvp);
164040112Smckusick /*
164140112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
164240112Smckusick */
164340112Smckusick if (error == EEXIST)
164440112Smckusick error = 0;
164538414Smckusick return (error);
164638414Smckusick }
164738414Smckusick
164838414Smckusick /*
164938414Smckusick * nfs symbolic link create call
165038414Smckusick */
165152234Sheideman int
nfs_symlink(ap)165253806Smckusick nfs_symlink(ap)
165354668Smckusick struct vop_symlink_args /* {
165454668Smckusick struct vnode *a_dvp;
165554668Smckusick struct vnode **a_vpp;
165654668Smckusick struct componentname *a_cnp;
165754668Smckusick struct vattr *a_vap;
165854668Smckusick char *a_target;
165954668Smckusick } */ *ap;
166038414Smckusick {
166153806Smckusick register struct vnode *dvp = ap->a_dvp;
166253806Smckusick register struct vattr *vap = ap->a_vap;
166353806Smckusick register struct componentname *cnp = ap->a_cnp;
166438884Smacklem register struct nfsv2_sattr *sp;
166568653Smckusick register struct nfsv3_sattr *sp3;
166648054Smckusick register u_long *tl;
166739488Smckusick register caddr_t cp;
166868653Smckusick register long t1, t2;
166968653Smckusick caddr_t bpos, dpos, cp2;
167068653Smckusick int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
167139488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
167268653Smckusick struct vnode *newvp = (struct vnode *)0;
167368653Smckusick int v3 = NFS_ISV3(dvp);
167438414Smckusick
167538414Smckusick nfsstats.rpccnt[NFSPROC_SYMLINK]++;
167653600Sheideman slen = strlen(ap->a_target);
167768653Smckusick nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
167868653Smckusick nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
167968653Smckusick nfsm_fhtom(dvp, v3);
168053806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
168168653Smckusick if (v3) {
168268653Smckusick nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
168368653Smckusick nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
168468653Smckusick cnp->cn_cred->cr_gid);
168568653Smckusick }
168653600Sheideman nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
168768653Smckusick if (!v3) {
168868653Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
168968653Smckusick sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
169068653Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
169168653Smckusick sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
169268653Smckusick sp->sa_size = -1;
169368653Smckusick txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
169468653Smckusick txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
169556289Smckusick }
169653806Smckusick nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
169768653Smckusick if (v3) {
169868653Smckusick if (!error)
169968653Smckusick nfsm_mtofh(dvp, newvp, v3, gotvp);
170068653Smckusick nfsm_wcc_data(dvp, wccflag);
170168653Smckusick }
170238414Smckusick nfsm_reqdone;
170368653Smckusick if (newvp)
170468653Smckusick vrele(newvp);
170553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
170653806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED;
170768653Smckusick if (!wccflag)
170868653Smckusick VTONFS(dvp)->n_attrstamp = 0;
170953806Smckusick vrele(dvp);
171040112Smckusick /*
171140112Smckusick * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
171240112Smckusick */
171340112Smckusick if (error == EEXIST)
171440112Smckusick error = 0;
171538414Smckusick return (error);
171638414Smckusick }
171738414Smckusick
171838414Smckusick /*
171938414Smckusick * nfs make dir call
172038414Smckusick */
172152234Sheideman int
nfs_mkdir(ap)172253806Smckusick nfs_mkdir(ap)
172354668Smckusick struct vop_mkdir_args /* {
172454668Smckusick struct vnode *a_dvp;
172554668Smckusick struct vnode **a_vpp;
172654668Smckusick struct componentname *a_cnp;
172754668Smckusick struct vattr *a_vap;
172854668Smckusick } */ *ap;
172938414Smckusick {
173053806Smckusick register struct vnode *dvp = ap->a_dvp;
173153806Smckusick register struct vattr *vap = ap->a_vap;
173253806Smckusick register struct componentname *cnp = ap->a_cnp;
173338884Smacklem register struct nfsv2_sattr *sp;
173468653Smckusick register struct nfsv3_sattr *sp3;
173548054Smckusick register u_long *tl;
173639488Smckusick register caddr_t cp;
173739488Smckusick register long t1, t2;
173841905Smckusick register int len;
173968653Smckusick struct nfsnode *np = (struct nfsnode *)0;
174068653Smckusick struct vnode *newvp = (struct vnode *)0;
174139488Smckusick caddr_t bpos, dpos, cp2;
174268653Smckusick nfsfh_t *fhp;
174368653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR, attrflag;
174468653Smckusick int fhsize, gotvp = 0;
174539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
174659116Smckusick struct vattr vattr;
174768653Smckusick int v3 = NFS_ISV3(dvp);
174838414Smckusick
174959116Smckusick if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
175059116Smckusick VOP_ABORTOP(dvp, cnp);
175159116Smckusick vput(dvp);
175259116Smckusick return (error);
175359116Smckusick }
175453806Smckusick len = cnp->cn_namelen;
175538414Smckusick nfsstats.rpccnt[NFSPROC_MKDIR]++;
175653806Smckusick nfsm_reqhead(dvp, NFSPROC_MKDIR,
175768653Smckusick NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
175868653Smckusick nfsm_fhtom(dvp, v3);
175953806Smckusick nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
176068653Smckusick if (v3) {
176168653Smckusick nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
176268653Smckusick nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
176356289Smckusick } else {
176468653Smckusick nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
176568653Smckusick sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
176668653Smckusick sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
176768653Smckusick sp->sa_gid = txdr_unsigned(vattr.va_gid);
176868653Smckusick sp->sa_size = -1;
176968653Smckusick txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
177068653Smckusick txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
177156289Smckusick }
177253806Smckusick nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
177368653Smckusick if (!error)
177468653Smckusick nfsm_mtofh(dvp, newvp, v3, gotvp);
177568653Smckusick if (v3)
177668653Smckusick nfsm_wcc_data(dvp, wccflag);
177738414Smckusick nfsm_reqdone;
177853806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED;
177968653Smckusick if (!wccflag)
178068653Smckusick VTONFS(dvp)->n_attrstamp = 0;
178140112Smckusick /*
178241905Smckusick * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
178341905Smckusick * if we can succeed in looking up the directory.
178440112Smckusick */
178568653Smckusick if (error == EEXIST || (!error && !gotvp)) {
178668653Smckusick if (newvp) {
178768653Smckusick vrele(newvp);
178868653Smckusick newvp = (struct vnode *)0;
178941905Smckusick }
179068653Smckusick error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
179168653Smckusick cnp->cn_proc, &np);
179268653Smckusick if (!error) {
179368653Smckusick newvp = NFSTOV(np);
179468653Smckusick if (newvp->v_type != VDIR)
179568653Smckusick error = EEXIST;
179668653Smckusick }
179741905Smckusick }
179868653Smckusick if (error) {
179968653Smckusick if (newvp)
180068653Smckusick vrele(newvp);
180168653Smckusick } else
180268653Smckusick *ap->a_vpp = newvp;
180353806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
180453806Smckusick vrele(dvp);
180538414Smckusick return (error);
180638414Smckusick }
180738414Smckusick
180838414Smckusick /*
180938414Smckusick * nfs remove directory call
181038414Smckusick */
181152234Sheideman int
nfs_rmdir(ap)181253806Smckusick nfs_rmdir(ap)
181354668Smckusick struct vop_rmdir_args /* {
181454668Smckusick struct vnode *a_dvp;
181554668Smckusick struct vnode *a_vp;
181654668Smckusick struct componentname *a_cnp;
181754668Smckusick } */ *ap;
181838414Smckusick {
181953806Smckusick register struct vnode *vp = ap->a_vp;
182053806Smckusick register struct vnode *dvp = ap->a_dvp;
182153806Smckusick register struct componentname *cnp = ap->a_cnp;
182248054Smckusick register u_long *tl;
182339488Smckusick register caddr_t cp;
182468653Smckusick register long t1, t2;
182568653Smckusick caddr_t bpos, dpos, cp2;
182668653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR;
182739488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
182868653Smckusick int v3 = NFS_ISV3(dvp);
182938414Smckusick
183053806Smckusick if (dvp == vp) {
183153806Smckusick vrele(dvp);
183253806Smckusick vrele(dvp);
183353806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
183438414Smckusick return (EINVAL);
183538414Smckusick }
183638414Smckusick nfsstats.rpccnt[NFSPROC_RMDIR]++;
183753806Smckusick nfsm_reqhead(dvp, NFSPROC_RMDIR,
183868653Smckusick NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
183968653Smckusick nfsm_fhtom(dvp, v3);
184053806Smckusick nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
184153806Smckusick nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
184268653Smckusick if (v3)
184368653Smckusick nfsm_wcc_data(dvp, wccflag);
184438414Smckusick nfsm_reqdone;
184553806Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
184653806Smckusick VTONFS(dvp)->n_flag |= NMODIFIED;
184768653Smckusick if (!wccflag)
184868653Smckusick VTONFS(dvp)->n_attrstamp = 0;
184953806Smckusick cache_purge(dvp);
185053806Smckusick cache_purge(vp);
185153806Smckusick vrele(vp);
185253806Smckusick vrele(dvp);
185340112Smckusick /*
185440112Smckusick * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
185540112Smckusick */
185640112Smckusick if (error == ENOENT)
185740112Smckusick error = 0;
185838414Smckusick return (error);
185938414Smckusick }
186038414Smckusick
186138414Smckusick /*
186238414Smckusick * nfs readdir call
186338414Smckusick */
186452234Sheideman int
nfs_readdir(ap)186553806Smckusick nfs_readdir(ap)
186654668Smckusick struct vop_readdir_args /* {
186754668Smckusick struct vnode *a_vp;
186854668Smckusick struct uio *a_uio;
186954668Smckusick struct ucred *a_cred;
187054668Smckusick } */ *ap;
187138414Smckusick {
187253806Smckusick register struct vnode *vp = ap->a_vp;
187353806Smckusick register struct nfsnode *np = VTONFS(vp);
187453806Smckusick register struct uio *uio = ap->a_uio;
187541905Smckusick int tresid, error;
187641905Smckusick struct vattr vattr;
187741905Smckusick
187853806Smckusick if (vp->v_type != VDIR)
187941905Smckusick return (EPERM);
188041905Smckusick /*
188141905Smckusick * First, check for hit on the EOF offset cache
188241905Smckusick */
188368653Smckusick if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
188452196Smckusick (np->n_flag & NMODIFIED) == 0) {
188553806Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
188668653Smckusick if (NQNFS_CKCACHABLE(vp, ND_READ)) {
188752196Smckusick nfsstats.direofcache_hits++;
188852196Smckusick return (0);
188952196Smckusick }
189053806Smckusick } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
189154106Smckusick np->n_mtime == vattr.va_mtime.ts_sec) {
189252196Smckusick nfsstats.direofcache_hits++;
189352196Smckusick return (0);
189452196Smckusick }
189541905Smckusick }
189641905Smckusick
189741905Smckusick /*
189841905Smckusick * Call nfs_bioread() to do the real work.
189941905Smckusick */
190053806Smckusick tresid = uio->uio_resid;
190153806Smckusick error = nfs_bioread(vp, uio, 0, ap->a_cred);
190241905Smckusick
190354451Smckusick if (!error && uio->uio_resid == tresid)
190441905Smckusick nfsstats.direofcache_misses++;
190541905Smckusick return (error);
190641905Smckusick }
190741905Smckusick
190841905Smckusick /*
190941905Smckusick * Readdir rpc call.
191041905Smckusick * Called from below the buffer cache by nfs_doio().
191141905Smckusick */
191252234Sheideman int
nfs_readdirrpc(vp,uiop,cred)191348054Smckusick nfs_readdirrpc(vp, uiop, cred)
191468653Smckusick struct vnode *vp;
191568653Smckusick register struct uio *uiop;
191641905Smckusick struct ucred *cred;
191741905Smckusick {
191868653Smckusick register int len, left;
191954740Smckusick register struct dirent *dp;
192048054Smckusick register u_long *tl;
192139488Smckusick register caddr_t cp;
192268653Smckusick register long t1, t2;
192368653Smckusick register nfsuint64 *cookiep;
192439488Smckusick caddr_t bpos, dpos, cp2;
192539488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
192668653Smckusick nfsuint64 cookie;
192768653Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount);
192868653Smckusick struct nfsnode *dnp = VTONFS(vp);
192968653Smckusick nfsfh_t *fhp;
193068653Smckusick u_quad_t frev, fileno;
193168653Smckusick int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1, i;
193268653Smckusick int cachable, attrflag, fhsize;
193368653Smckusick int v3 = NFS_ISV3(vp);
193438414Smckusick
193568653Smckusick #ifndef nolint
193668653Smckusick dp = (struct dirent *)0;
193768653Smckusick #endif
193868653Smckusick #ifndef DIAGNOSTIC
193968653Smckusick if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
194068653Smckusick (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
194168653Smckusick panic("nfs readdirrpc bad uio");
194268653Smckusick #endif
194368653Smckusick
194440296Smckusick /*
194568653Smckusick * If there is no cookie, assume end of directory.
194668653Smckusick */
194768653Smckusick cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
194868653Smckusick if (cookiep)
194968653Smckusick cookie = *cookiep;
195068653Smckusick else
195168653Smckusick return (0);
195268653Smckusick /*
195368653Smckusick * Loop around doing readdir rpc's of size nm_readdirsize
195468653Smckusick * truncated to a multiple of DIRBLKSIZ.
195541905Smckusick * The stopping criteria is EOF or buffer full.
195640296Smckusick */
195768653Smckusick while (more_dirs && bigenough) {
195840296Smckusick nfsstats.rpccnt[NFSPROC_READDIR]++;
195968653Smckusick nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
196068653Smckusick NFSX_READDIR(v3));
196168653Smckusick nfsm_fhtom(vp, v3);
196268653Smckusick if (v3) {
196368653Smckusick nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
196468653Smckusick *tl++ = cookie.nfsuquad[0];
196568653Smckusick *tl++ = cookie.nfsuquad[1];
196668653Smckusick *tl++ = dnp->n_cookieverf.nfsuquad[0];
196768653Smckusick *tl++ = dnp->n_cookieverf.nfsuquad[1];
196868653Smckusick } else {
196968653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
197068653Smckusick *tl++ = cookie.nfsuquad[0];
197168653Smckusick }
197268653Smckusick *tl = txdr_unsigned(nmp->nm_readdirsize);
197352196Smckusick nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
197468653Smckusick if (v3) {
197568653Smckusick nfsm_postop_attr(vp, attrflag);
197668653Smckusick if (!error) {
197768653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
197868653Smckusick dnp->n_cookieverf.nfsuquad[0] = *tl++;
197968653Smckusick dnp->n_cookieverf.nfsuquad[1] = *tl;
198068653Smckusick } else {
198168653Smckusick m_freem(mrep);
198268653Smckusick goto nfsmout;
198368653Smckusick }
198468653Smckusick }
198552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
198648054Smckusick more_dirs = fxdr_unsigned(int, *tl);
198740296Smckusick
198840296Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */
198968653Smckusick while (more_dirs && bigenough) {
199068653Smckusick if (v3) {
199168653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
199268653Smckusick fxdr_hyper(tl, &fileno);
199368653Smckusick len = fxdr_unsigned(int, *(tl + 2));
199468653Smckusick } else {
199568653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
199668653Smckusick fileno = fxdr_unsigned(u_quad_t, *tl++);
199768653Smckusick len = fxdr_unsigned(int, *tl);
199868653Smckusick }
199940296Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) {
200040296Smckusick error = EBADRPC;
200140296Smckusick m_freem(mrep);
200240296Smckusick goto nfsmout;
200340296Smckusick }
200440296Smckusick tlen = nfsm_rndup(len);
200568653Smckusick if (tlen == len)
200668653Smckusick tlen += 4; /* To ensure null termination */
200768653Smckusick left = DIRBLKSIZ - blksiz;
200868653Smckusick if ((tlen + DIRHDSIZ) > left) {
200968653Smckusick dp->d_reclen += left;
201068653Smckusick uiop->uio_iov->iov_base += left;
201168653Smckusick uiop->uio_iov->iov_len -= left;
201268653Smckusick uiop->uio_offset += left;
201368653Smckusick uiop->uio_resid -= left;
201468653Smckusick blksiz = 0;
201540296Smckusick }
201668653Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid)
201768653Smckusick bigenough = 0;
201868653Smckusick if (bigenough) {
201968653Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base;
202068653Smckusick dp->d_fileno = (int)fileno;
202168653Smckusick dp->d_namlen = len;
202268653Smckusick dp->d_reclen = tlen + DIRHDSIZ;
202368653Smckusick dp->d_type = DT_UNKNOWN;
202468653Smckusick blksiz += dp->d_reclen;
202568653Smckusick if (blksiz == DIRBLKSIZ)
202668653Smckusick blksiz = 0;
202768653Smckusick uiop->uio_offset += DIRHDSIZ;
202868653Smckusick uiop->uio_resid -= DIRHDSIZ;
202968653Smckusick uiop->uio_iov->iov_base += DIRHDSIZ;
203068653Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ;
203168653Smckusick nfsm_mtouio(uiop, len);
203268653Smckusick cp = uiop->uio_iov->iov_base;
203368653Smckusick tlen -= len;
203468653Smckusick *cp = '\0'; /* null terminate */
203568653Smckusick uiop->uio_iov->iov_base += tlen;
203668653Smckusick uiop->uio_iov->iov_len -= tlen;
203768653Smckusick uiop->uio_offset += tlen;
203868653Smckusick uiop->uio_resid -= tlen;
203968653Smckusick } else
204068653Smckusick nfsm_adv(nfsm_rndup(len));
204168653Smckusick if (v3) {
204268653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
204368653Smckusick } else {
204468653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
204568653Smckusick }
204668653Smckusick if (bigenough) {
204768653Smckusick cookie.nfsuquad[0] = *tl++;
204868653Smckusick if (v3)
204968653Smckusick cookie.nfsuquad[1] = *tl++;
205068653Smckusick } else if (v3)
205168653Smckusick tl += 2;
205268653Smckusick else
205368653Smckusick tl++;
205448054Smckusick more_dirs = fxdr_unsigned(int, *tl);
205540296Smckusick }
205640296Smckusick /*
205740296Smckusick * If at end of rpc data, get the eof boolean
205840296Smckusick */
205940296Smckusick if (!more_dirs) {
206063483Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
206148054Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0);
206238414Smckusick }
206340296Smckusick m_freem(mrep);
206438414Smckusick }
206541905Smckusick /*
206668653Smckusick * Fill last record, iff any, out to a multiple of DIRBLKSIZ
206741905Smckusick * by increasing d_reclen for the last record.
206841905Smckusick */
206968653Smckusick if (blksiz > 0) {
207068653Smckusick left = DIRBLKSIZ - blksiz;
207168653Smckusick dp->d_reclen += left;
207268653Smckusick uiop->uio_iov->iov_base += left;
207368653Smckusick uiop->uio_iov->iov_len -= left;
207468653Smckusick uiop->uio_offset += left;
207568653Smckusick uiop->uio_resid -= left;
207641905Smckusick }
207768653Smckusick
207868653Smckusick /*
207968653Smckusick * We are now either at the end of the directory or have filled the
208068653Smckusick * block.
208168653Smckusick */
208268653Smckusick if (bigenough)
208368653Smckusick dnp->n_direofoffset = uiop->uio_offset;
208468653Smckusick else {
208568653Smckusick if (uiop->uio_resid > 0)
208668653Smckusick printf("EEK! readdirrpc resid > 0\n");
208768653Smckusick cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
208868653Smckusick *cookiep = cookie;
208968653Smckusick }
209040296Smckusick nfsmout:
209138414Smckusick return (error);
209238414Smckusick }
209338414Smckusick
209452196Smckusick /*
209568653Smckusick * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
209652196Smckusick */
209752234Sheideman int
nfs_readdirplusrpc(vp,uiop,cred)209868653Smckusick nfs_readdirplusrpc(vp, uiop, cred)
209952196Smckusick struct vnode *vp;
210052196Smckusick register struct uio *uiop;
210152196Smckusick struct ucred *cred;
210252196Smckusick {
210368653Smckusick register int len, left;
210454740Smckusick register struct dirent *dp;
210552196Smckusick register u_long *tl;
210652196Smckusick register caddr_t cp;
210768653Smckusick register long t1, t2;
210868653Smckusick register struct vnode *newvp;
210968653Smckusick register nfsuint64 *cookiep;
211068653Smckusick caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
211168653Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
211252196Smckusick struct nameidata nami, *ndp = &nami;
211352317Sheideman struct componentname *cnp = &ndp->ni_cnd;
211468653Smckusick nfsuint64 cookie;
211568653Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount);
211668653Smckusick struct nfsnode *dnp = VTONFS(vp), *np;
211768653Smckusick nfsfh_t *fhp;
211868653Smckusick u_quad_t frev, fileno;
211968653Smckusick int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
212068653Smckusick int cachable, attrflag, fhsize;
212152196Smckusick
212268653Smckusick #ifndef nolint
212368653Smckusick dp = (struct dirent *)0;
212468653Smckusick #endif
212568653Smckusick #ifndef DIAGNOSTIC
212668653Smckusick if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
212768653Smckusick (uiop->uio_resid & (DIRBLKSIZ - 1)))
212868653Smckusick panic("nfs readdirplusrpc bad uio");
212968653Smckusick #endif
213052196Smckusick ndp->ni_dvp = vp;
213152196Smckusick newvp = NULLVP;
213268653Smckusick
213352196Smckusick /*
213468653Smckusick * If there is no cookie, assume end of directory.
213568653Smckusick */
213668653Smckusick cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
213768653Smckusick if (cookiep)
213868653Smckusick cookie = *cookiep;
213968653Smckusick else
214068653Smckusick return (0);
214168653Smckusick /*
214268653Smckusick * Loop around doing readdir rpc's of size nm_readdirsize
214368653Smckusick * truncated to a multiple of DIRBLKSIZ.
214452196Smckusick * The stopping criteria is EOF or buffer full.
214552196Smckusick */
214668653Smckusick while (more_dirs && bigenough) {
214768653Smckusick nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
214868653Smckusick nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
214968653Smckusick NFSX_FH(1) + 6 * NFSX_UNSIGNED);
215068653Smckusick nfsm_fhtom(vp, 1);
215168653Smckusick nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
215268653Smckusick *tl++ = cookie.nfsuquad[0];
215368653Smckusick *tl++ = cookie.nfsuquad[1];
215468653Smckusick *tl++ = dnp->n_cookieverf.nfsuquad[0];
215568653Smckusick *tl++ = dnp->n_cookieverf.nfsuquad[1];
215668653Smckusick *tl++ = txdr_unsigned(nmp->nm_readdirsize);
215768653Smckusick *tl = txdr_unsigned(nmp->nm_rsize);
215868653Smckusick nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
215968653Smckusick nfsm_postop_attr(vp, attrflag);
216068653Smckusick if (error) {
216168653Smckusick m_freem(mrep);
216268653Smckusick goto nfsmout;
216368653Smckusick }
216468653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
216568653Smckusick dnp->n_cookieverf.nfsuquad[0] = *tl++;
216668653Smckusick dnp->n_cookieverf.nfsuquad[1] = *tl++;
216752196Smckusick more_dirs = fxdr_unsigned(int, *tl);
216852196Smckusick
216952196Smckusick /* loop thru the dir entries, doctoring them to 4bsd form */
217052196Smckusick while (more_dirs && bigenough) {
217168653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
217268653Smckusick fxdr_hyper(tl, &fileno);
217368653Smckusick len = fxdr_unsigned(int, *(tl + 2));
217452196Smckusick if (len <= 0 || len > NFS_MAXNAMLEN) {
217552196Smckusick error = EBADRPC;
217652196Smckusick m_freem(mrep);
217752196Smckusick goto nfsmout;
217852196Smckusick }
217968653Smckusick tlen = nfsm_rndup(len);
218068653Smckusick if (tlen == len)
218168653Smckusick tlen += 4; /* To ensure null termination*/
218268653Smckusick left = DIRBLKSIZ - blksiz;
218368653Smckusick if ((tlen + DIRHDSIZ) > left) {
218468653Smckusick dp->d_reclen += left;
218568653Smckusick uiop->uio_iov->iov_base += left;
218668653Smckusick uiop->uio_iov->iov_len -= left;
218768653Smckusick uiop->uio_offset += left;
218868653Smckusick uiop->uio_resid -= left;
218968653Smckusick blksiz = 0;
219068653Smckusick }
219152196Smckusick if ((tlen + DIRHDSIZ) > uiop->uio_resid)
219252196Smckusick bigenough = 0;
219368653Smckusick if (bigenough) {
219454740Smckusick dp = (struct dirent *)uiop->uio_iov->iov_base;
219568653Smckusick dp->d_fileno = (int)fileno;
219652196Smckusick dp->d_namlen = len;
219752196Smckusick dp->d_reclen = tlen + DIRHDSIZ;
219868653Smckusick dp->d_type = DT_UNKNOWN;
219968653Smckusick blksiz += dp->d_reclen;
220068653Smckusick if (blksiz == DIRBLKSIZ)
220168653Smckusick blksiz = 0;
220268653Smckusick uiop->uio_offset += DIRHDSIZ;
220352196Smckusick uiop->uio_resid -= DIRHDSIZ;
220452196Smckusick uiop->uio_iov->iov_base += DIRHDSIZ;
220552196Smckusick uiop->uio_iov->iov_len -= DIRHDSIZ;
220652317Sheideman cnp->cn_nameptr = uiop->uio_iov->iov_base;
220752317Sheideman cnp->cn_namelen = len;
220852196Smckusick nfsm_mtouio(uiop, len);
220952196Smckusick cp = uiop->uio_iov->iov_base;
221052196Smckusick tlen -= len;
221168653Smckusick *cp = '\0';
221252196Smckusick uiop->uio_iov->iov_base += tlen;
221352196Smckusick uiop->uio_iov->iov_len -= tlen;
221468653Smckusick uiop->uio_offset += tlen;
221552196Smckusick uiop->uio_resid -= tlen;
221668653Smckusick } else
221768653Smckusick nfsm_adv(nfsm_rndup(len));
221868653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
221968653Smckusick if (bigenough) {
222068653Smckusick cookie.nfsuquad[0] = *tl++;
222168653Smckusick cookie.nfsuquad[1] = *tl++;
222268653Smckusick } else
222368653Smckusick tl += 2;
222468653Smckusick
222568653Smckusick /*
222668653Smckusick * Since the attributes are before the file handle
222768653Smckusick * (sigh), we must skip over the attributes and then
222868653Smckusick * come back and get them.
222968653Smckusick */
223068653Smckusick attrflag = fxdr_unsigned(int, *tl);
223168653Smckusick if (attrflag) {
223268653Smckusick dpossav1 = dpos;
223368653Smckusick mdsav1 = md;
223468653Smckusick nfsm_adv(NFSX_V3FATTR);
223568653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
223668653Smckusick doit = fxdr_unsigned(int, *tl);
223768653Smckusick if (doit) {
223868653Smckusick nfsm_getfh(fhp, fhsize, 1);
223968653Smckusick if (NFS_CMPFH(dnp, fhp, fhsize)) {
224068653Smckusick VREF(vp);
224168653Smckusick newvp = vp;
224268653Smckusick np = dnp;
224368653Smckusick } else {
224468653Smckusick if (error = nfs_nget(vp->v_mount, fhp,
224568653Smckusick fhsize, &np))
224668653Smckusick doit = 0;
224768653Smckusick else
224868653Smckusick newvp = NFSTOV(np);
224968653Smckusick }
225068653Smckusick }
225168653Smckusick if (doit) {
225268653Smckusick dpossav2 = dpos;
225368653Smckusick dpos = dpossav1;
225468653Smckusick mdsav2 = md;
225568653Smckusick md = mdsav1;
225668653Smckusick nfsm_loadattr(newvp, (struct vattr *)0);
225768653Smckusick dpos = dpossav2;
225868653Smckusick md = mdsav2;
225968653Smckusick dp->d_type =
226068653Smckusick IFTODT(VTTOIF(np->n_vattr.va_type));
226168653Smckusick ndp->ni_vp = newvp;
226252317Sheideman cnp->cn_hash = 0;
226368653Smckusick for (cp = cnp->cn_nameptr, i = 1; i <= len;
226468653Smckusick i++, cp++)
226568653Smckusick cnp->cn_hash += (unsigned char)*cp * i;
226656927Smckusick if (cnp->cn_namelen <= NCHNAMLEN)
226757791Smckusick cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
226868653Smckusick }
226952196Smckusick } else {
227068653Smckusick /* Just skip over the file handle */
227168653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
227268653Smckusick i = fxdr_unsigned(int, *tl);
227368653Smckusick nfsm_adv(nfsm_rndup(i));
227452196Smckusick }
227552196Smckusick if (newvp != NULLVP) {
227668653Smckusick vrele(newvp);
227768653Smckusick newvp = NULLVP;
227852196Smckusick }
227968653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
228052196Smckusick more_dirs = fxdr_unsigned(int, *tl);
228152196Smckusick }
228252196Smckusick /*
228352196Smckusick * If at end of rpc data, get the eof boolean
228452196Smckusick */
228552196Smckusick if (!more_dirs) {
228652196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
228752196Smckusick more_dirs = (fxdr_unsigned(int, *tl) == 0);
228852196Smckusick }
228952196Smckusick m_freem(mrep);
229052196Smckusick }
229152196Smckusick /*
229252196Smckusick * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
229352196Smckusick * by increasing d_reclen for the last record.
229452196Smckusick */
229568653Smckusick if (blksiz > 0) {
229668653Smckusick left = DIRBLKSIZ - blksiz;
229768653Smckusick dp->d_reclen += left;
229868653Smckusick uiop->uio_iov->iov_base += left;
229968653Smckusick uiop->uio_iov->iov_len -= left;
230068653Smckusick uiop->uio_offset += left;
230168653Smckusick uiop->uio_resid -= left;
230252196Smckusick }
230368653Smckusick
230468653Smckusick /*
230568653Smckusick * We are now either at the end of the directory or have filled the
230668653Smckusick * block.
230768653Smckusick */
230868653Smckusick if (bigenough)
230968653Smckusick dnp->n_direofoffset = uiop->uio_offset;
231068653Smckusick else {
231168653Smckusick if (uiop->uio_resid > 0)
231268653Smckusick printf("EEK! readdirplusrpc resid > 0\n");
231368653Smckusick cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
231468653Smckusick *cookiep = cookie;
231568653Smckusick }
231652196Smckusick nfsmout:
231752196Smckusick if (newvp != NULLVP)
231852196Smckusick vrele(newvp);
231952196Smckusick return (error);
232052196Smckusick }
232139488Smckusick static char hextoasc[] = "0123456789abcdef";
232238414Smckusick
232338414Smckusick /*
232438414Smckusick * Silly rename. To make the NFS filesystem that is stateless look a little
232538414Smckusick * more like the "ufs" a remove of an active vnode is translated to a rename
232638414Smckusick * to a funny looking filename that is removed by nfs_inactive on the
232738414Smckusick * nfsnode. There is the potential for another process on a different client
232838414Smckusick * to create the same funny name between the nfs_lookitup() fails and the
232938414Smckusick * nfs_rename() completes, but...
233038414Smckusick */
233152234Sheideman int
nfs_sillyrename(dvp,vp,cnp)233252317Sheideman nfs_sillyrename(dvp, vp, cnp)
233352234Sheideman struct vnode *dvp, *vp;
233452234Sheideman struct componentname *cnp;
233538414Smckusick {
233638414Smckusick register struct sillyrename *sp;
233768653Smckusick struct nfsnode *np;
233838414Smckusick int error;
233938414Smckusick short pid;
234038414Smckusick
234152234Sheideman cache_purge(dvp);
234252234Sheideman np = VTONFS(vp);
234368653Smckusick #ifndef DIAGNOSTIC
234468653Smckusick if (vp->v_type == VDIR)
234568653Smckusick panic("nfs: sillyrename dir");
234668653Smckusick #endif
234738414Smckusick MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
234848364Smckusick M_NFSREQ, M_WAITOK);
234952234Sheideman sp->s_cred = crdup(cnp->cn_cred);
235052234Sheideman sp->s_dvp = dvp;
235152234Sheideman VREF(dvp);
235238414Smckusick
235338414Smckusick /* Fudge together a funny name */
235452234Sheideman pid = cnp->cn_proc->p_pid;
235548364Smckusick bcopy(".nfsAxxxx4.4", sp->s_name, 13);
235648364Smckusick sp->s_namlen = 12;
235748364Smckusick sp->s_name[8] = hextoasc[pid & 0xf];
235848364Smckusick sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
235948364Smckusick sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
236048364Smckusick sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
236138414Smckusick
236238414Smckusick /* Try lookitups until we get one that isn't there */
236368653Smckusick while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
236468653Smckusick cnp->cn_proc, (struct nfsnode **)0) == 0) {
236548364Smckusick sp->s_name[4]++;
236648364Smckusick if (sp->s_name[4] > 'z') {
236738414Smckusick error = EINVAL;
236838414Smckusick goto bad;
236938414Smckusick }
237038414Smckusick }
237152234Sheideman if (error = nfs_renameit(dvp, cnp, sp))
237238414Smckusick goto bad;
237368653Smckusick error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
237468653Smckusick cnp->cn_proc, &np);
237538414Smckusick np->n_sillyrename = sp;
237638414Smckusick return (0);
237738414Smckusick bad:
237848364Smckusick vrele(sp->s_dvp);
237948364Smckusick crfree(sp->s_cred);
238048364Smckusick free((caddr_t)sp, M_NFSREQ);
238138414Smckusick return (error);
238238414Smckusick }
238338414Smckusick
238438414Smckusick /*
238568653Smckusick * Look up a file name and optionally either update the file handle or
238668653Smckusick * allocate an nfsnode, depending on the value of npp.
238768653Smckusick * npp == NULL --> just do the lookup
238868653Smckusick * *npp == NULL --> allocate a new nfsnode and make sure attributes are
238968653Smckusick * handled too
239068653Smckusick * *npp != NULL --> update the file handle in the vnode
239138414Smckusick */
239252234Sheideman int
nfs_lookitup(dvp,name,len,cred,procp,npp)239368653Smckusick nfs_lookitup(dvp, name, len, cred, procp, npp)
239468653Smckusick register struct vnode *dvp;
239568653Smckusick char *name;
239668653Smckusick int len;
239768653Smckusick struct ucred *cred;
239852196Smckusick struct proc *procp;
239968653Smckusick struct nfsnode **npp;
240038414Smckusick {
240148054Smckusick register u_long *tl;
240239488Smckusick register caddr_t cp;
240339488Smckusick register long t1, t2;
240468653Smckusick struct vnode *newvp = (struct vnode *)0;
240568653Smckusick struct nfsnode *np, *dnp = VTONFS(dvp);
240639488Smckusick caddr_t bpos, dpos, cp2;
240768653Smckusick int error = 0, fhlen, attrflag;
240839488Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
240968653Smckusick nfsfh_t *nfhp;
241068653Smckusick int v3 = NFS_ISV3(dvp);
241138414Smckusick
241238414Smckusick nfsstats.rpccnt[NFSPROC_LOOKUP]++;
241368653Smckusick nfsm_reqhead(dvp, NFSPROC_LOOKUP,
241468653Smckusick NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
241568653Smckusick nfsm_fhtom(dvp, v3);
241668653Smckusick nfsm_strtom(name, len, NFS_MAXNAMLEN);
241768653Smckusick nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
241868653Smckusick if (npp && !error) {
241968653Smckusick nfsm_getfh(nfhp, fhlen, v3);
242068653Smckusick if (*npp) {
242168653Smckusick np = *npp;
242268653Smckusick if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
242368653Smckusick free((caddr_t)np->n_fhp, M_NFSBIGFH);
242468653Smckusick np->n_fhp = &np->n_fh;
242568653Smckusick } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
242668653Smckusick np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
242768653Smckusick bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
242868653Smckusick np->n_fhsize = fhlen;
242968653Smckusick newvp = NFSTOV(np);
243068653Smckusick } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
243168653Smckusick VREF(dvp);
243268653Smckusick newvp = dvp;
243368653Smckusick } else {
243468653Smckusick error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
243568653Smckusick if (error) {
243668653Smckusick m_freem(mrep);
243768653Smckusick return (error);
243868653Smckusick }
243968653Smckusick newvp = NFSTOV(np);
244068653Smckusick }
244168653Smckusick if (v3) {
244268653Smckusick nfsm_postop_attr(newvp, attrflag);
244368653Smckusick if (!attrflag && *npp == NULL) {
244468653Smckusick m_freem(mrep);
244568653Smckusick vrele(newvp);
244668653Smckusick return (ENOENT);
244768653Smckusick }
244868653Smckusick } else
244968653Smckusick nfsm_loadattr(newvp, (struct vattr *)0);
245056289Smckusick }
245168653Smckusick nfsm_reqdone;
245268653Smckusick if (npp && *npp == NULL) {
245368653Smckusick if (error) {
245468653Smckusick if (newvp)
245568653Smckusick vrele(newvp);
245668653Smckusick } else
245768653Smckusick *npp = np;
245838414Smckusick }
245968653Smckusick return (error);
246068653Smckusick }
246168653Smckusick
246268653Smckusick /*
246368653Smckusick * Nfs Version 3 commit rpc
246468653Smckusick */
246568653Smckusick int
nfs_commit(vp,offset,cnt,cred,procp)246668653Smckusick nfs_commit(vp, offset, cnt, cred, procp)
246768653Smckusick register struct vnode *vp;
246868653Smckusick u_quad_t offset;
246968653Smckusick int cnt;
247068653Smckusick struct ucred *cred;
247168653Smckusick struct proc *procp;
247268653Smckusick {
247368653Smckusick register caddr_t cp;
247468653Smckusick register u_long *tl;
247568653Smckusick register int t1, t2;
247668653Smckusick register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
247768653Smckusick caddr_t bpos, dpos, cp2;
247868653Smckusick int error = 0, wccflag = NFSV3_WCCRATTR;
247968653Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
248068653Smckusick
248168653Smckusick if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
248268653Smckusick return (0);
248368653Smckusick nfsstats.rpccnt[NFSPROC_COMMIT]++;
248468653Smckusick nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
248568653Smckusick nfsm_fhtom(vp, 1);
248668653Smckusick nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
248768653Smckusick txdr_hyper(&offset, tl);
248868653Smckusick tl += 2;
248968653Smckusick *tl = txdr_unsigned(cnt);
249068653Smckusick nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
249168653Smckusick nfsm_wcc_data(vp, wccflag);
249268653Smckusick if (!error) {
249368653Smckusick nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
249468653Smckusick if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
249568653Smckusick NFSX_V3WRITEVERF)) {
249668653Smckusick bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
249768653Smckusick NFSX_V3WRITEVERF);
249868653Smckusick error = NFSERR_STALEWRITEVERF;
249968653Smckusick }
250068653Smckusick }
250138414Smckusick nfsm_reqdone;
250238414Smckusick return (error);
250338414Smckusick }
250438414Smckusick
250538414Smckusick /*
250638414Smckusick * Kludge City..
250738414Smckusick * - make nfs_bmap() essentially a no-op that does no translation
250868653Smckusick * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
250938414Smckusick * (Maybe I could use the process's page mapping, but I was concerned that
251038414Smckusick * Kernel Write might not be enabled and also figured copyout() would do
251138414Smckusick * a lot more work than bcopy() and also it currently happens in the
251238414Smckusick * context of the swapper process (2).
251338414Smckusick */
251452234Sheideman int
nfs_bmap(ap)251553806Smckusick nfs_bmap(ap)
251654668Smckusick struct vop_bmap_args /* {
251754668Smckusick struct vnode *a_vp;
251854668Smckusick daddr_t a_bn;
251954668Smckusick struct vnode **a_vpp;
252054668Smckusick daddr_t *a_bnp;
252156452Smargo int *a_runp;
252254668Smckusick } */ *ap;
252338414Smckusick {
252453806Smckusick register struct vnode *vp = ap->a_vp;
252553806Smckusick
252653600Sheideman if (ap->a_vpp != NULL)
252753806Smckusick *ap->a_vpp = vp;
252853600Sheideman if (ap->a_bnp != NULL)
252953806Smckusick *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
253038414Smckusick return (0);
253138414Smckusick }
253238414Smckusick
253338414Smckusick /*
253457791Smckusick * Strategy routine.
253557791Smckusick * For async requests when nfsiod(s) are running, queue the request by
253657791Smckusick * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
253757791Smckusick * request.
253838414Smckusick */
253952234Sheideman int
nfs_strategy(ap)254053806Smckusick nfs_strategy(ap)
254157791Smckusick struct vop_strategy_args *ap;
254238414Smckusick {
254353806Smckusick register struct buf *bp = ap->a_bp;
254457791Smckusick struct ucred *cr;
254557791Smckusick struct proc *p;
254638884Smacklem int error = 0;
254738884Smacklem
254857791Smckusick if (bp->b_flags & B_PHYS)
254957791Smckusick panic("nfs physio");
255057791Smckusick if (bp->b_flags & B_ASYNC)
255157791Smckusick p = (struct proc *)0;
255257791Smckusick else
255357791Smckusick p = curproc; /* XXX */
255457791Smckusick if (bp->b_flags & B_READ)
255557791Smckusick cr = bp->b_rcred;
255657791Smckusick else
255757791Smckusick cr = bp->b_wcred;
255838884Smacklem /*
255946450Skarels * If the op is asynchronous and an i/o daemon is waiting
256038884Smacklem * queue the request, wake it up and wait for completion
256146450Skarels * otherwise just do it ourselves.
256238884Smacklem */
256357791Smckusick if ((bp->b_flags & B_ASYNC) == 0 ||
256457791Smckusick nfs_asyncio(bp, NOCRED))
256557791Smckusick error = nfs_doio(bp, cr, p);
256638884Smacklem return (error);
256738884Smacklem }
256838884Smacklem
256938884Smacklem /*
257048054Smckusick * Mmap a file
257148054Smckusick *
257248054Smckusick * NB Currently unsupported.
257348054Smckusick */
257448054Smckusick /* ARGSUSED */
257552234Sheideman int
nfs_mmap(ap)257653806Smckusick nfs_mmap(ap)
257754668Smckusick struct vop_mmap_args /* {
257854668Smckusick struct vnode *a_vp;
257954668Smckusick int a_fflags;
258054668Smckusick struct ucred *a_cred;
258154668Smckusick struct proc *a_p;
258254668Smckusick } */ *ap;
258348054Smckusick {
258448054Smckusick
258548054Smckusick return (EINVAL);
258648054Smckusick }
258748054Smckusick
258848054Smckusick /*
258968653Smckusick * fsync vnode op. Just call nfs_flush() with commit == 1.
259038884Smacklem */
259139488Smckusick /* ARGSUSED */
259252234Sheideman int
nfs_fsync(ap)259353806Smckusick nfs_fsync(ap)
259454451Smckusick struct vop_fsync_args /* {
259554451Smckusick struct vnodeop_desc *a_desc;
259654451Smckusick struct vnode * a_vp;
259754451Smckusick struct ucred * a_cred;
259854451Smckusick int a_waitfor;
259954451Smckusick struct proc * a_p;
260054451Smckusick } */ *ap;
260138884Smacklem {
260268653Smckusick
260368653Smckusick return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
260468653Smckusick }
260568653Smckusick
260668653Smckusick /*
260768653Smckusick * Flush all the blocks associated with a vnode.
260868653Smckusick * Walk through the buffer pool and push any dirty pages
260968653Smckusick * associated with the vnode.
261068653Smckusick */
261168653Smckusick int
nfs_flush(vp,cred,waitfor,p,commit)261268653Smckusick nfs_flush(vp, cred, waitfor, p, commit)
261368653Smckusick register struct vnode *vp;
261468653Smckusick struct ucred *cred;
261568653Smckusick int waitfor;
261668653Smckusick struct proc *p;
261768653Smckusick int commit;
261868653Smckusick {
261954451Smckusick register struct nfsnode *np = VTONFS(vp);
262054451Smckusick register struct buf *bp;
262168653Smckusick register int i;
262254451Smckusick struct buf *nbp;
262368653Smckusick struct nfsmount *nmp = VFSTONFS(vp->v_mount);
262468653Smckusick int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
262568653Smckusick int passone = 1;
262668653Smckusick u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
262768653Smckusick #ifndef NFS_COMMITBVECSIZ
262868653Smckusick #define NFS_COMMITBVECSIZ 20
262968653Smckusick #endif
263068653Smckusick struct buf *bvec[NFS_COMMITBVECSIZ];
263138884Smacklem
263257791Smckusick if (nmp->nm_flag & NFSMNT_INT)
263357791Smckusick slpflag = PCATCH;
263468653Smckusick if (!commit)
263568653Smckusick passone = 0;
263668653Smckusick /*
263768653Smckusick * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
263868653Smckusick * server, but nas not been committed to stable storage on the server
263968653Smckusick * yet. On the first pass, the byte range is worked out and the commit
264068653Smckusick * rpc is done. On the second pass, nfs_writebp() is called to do the
264168653Smckusick * job.
264268653Smckusick */
264368653Smckusick again:
264468653Smckusick bvecpos = 0;
264568653Smckusick if (NFS_ISV3(vp) && commit) {
264668653Smckusick s = splbio();
264768653Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
264868653Smckusick nbp = bp->b_vnbufs.le_next;
264968653Smckusick if (bvecpos >= NFS_COMMITBVECSIZ)
265068653Smckusick break;
265168653Smckusick if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
265268653Smckusick != (B_DELWRI | B_NEEDCOMMIT))
265368653Smckusick continue;
265468653Smckusick bremfree(bp);
265568653Smckusick bp->b_flags |= (B_BUSY | B_WRITEINPROG);
265668653Smckusick /*
265768653Smckusick * A list of these buffers is kept so that the
265868653Smckusick * second loop knows which buffers have actually
265968653Smckusick * been committed. This is necessary, since there
266068653Smckusick * may be a race between the commit rpc and new
266168653Smckusick * uncommitted writes on the file.
266268653Smckusick */
266368653Smckusick bvec[bvecpos++] = bp;
266468653Smckusick toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
266568653Smckusick bp->b_dirtyoff;
266668653Smckusick if (toff < off)
266768653Smckusick off = toff;
266868653Smckusick toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
266968653Smckusick if (toff > endoff)
267068653Smckusick endoff = toff;
267168653Smckusick }
267268653Smckusick splx(s);
267368653Smckusick }
267468653Smckusick if (bvecpos > 0) {
267568653Smckusick /*
267668653Smckusick * Commit data on the server, as required.
267768653Smckusick */
267868653Smckusick retv = nfs_commit(vp, off, (int)(endoff - off), cred, p);
267968653Smckusick if (retv == NFSERR_STALEWRITEVERF)
268068653Smckusick nfs_clearcommit(vp->v_mount);
268168653Smckusick /*
268268653Smckusick * Now, either mark the blocks I/O done or mark the
268368653Smckusick * blocks dirty, depending on whether the commit
268468653Smckusick * succeeded.
268568653Smckusick */
268668653Smckusick for (i = 0; i < bvecpos; i++) {
268768653Smckusick bp = bvec[i];
268868653Smckusick bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
268968653Smckusick if (retv) {
269068653Smckusick brelse(bp);
269168653Smckusick } else {
269268653Smckusick vp->v_numoutput++;
269368653Smckusick bp->b_flags |= B_ASYNC;
269468653Smckusick bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
269568653Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0;
269668653Smckusick reassignbuf(bp, vp);
269768653Smckusick biodone(bp);
269868653Smckusick }
269968653Smckusick }
270068653Smckusick }
270168653Smckusick
270268653Smckusick /*
270368653Smckusick * Start/do any write(s) that are required.
270468653Smckusick */
270554451Smckusick loop:
270654451Smckusick s = splbio();
270765252Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
270865252Smckusick nbp = bp->b_vnbufs.le_next;
270957791Smckusick if (bp->b_flags & B_BUSY) {
271068653Smckusick if (waitfor != MNT_WAIT || passone)
271157791Smckusick continue;
271257791Smckusick bp->b_flags |= B_WANTED;
271357791Smckusick error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
271457791Smckusick "nfsfsync", slptimeo);
271557791Smckusick splx(s);
271657791Smckusick if (error) {
271768653Smckusick if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
271857791Smckusick return (EINTR);
271957791Smckusick if (slpflag == PCATCH) {
272057791Smckusick slpflag = 0;
272157791Smckusick slptimeo = 2 * hz;
272257791Smckusick }
272357791Smckusick }
272457791Smckusick goto loop;
272557791Smckusick }
272654451Smckusick if ((bp->b_flags & B_DELWRI) == 0)
272754451Smckusick panic("nfs_fsync: not dirty");
272868653Smckusick if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
272968653Smckusick continue;
273054451Smckusick bremfree(bp);
273168653Smckusick if (passone || !commit)
273268653Smckusick bp->b_flags |= (B_BUSY|B_ASYNC);
273368653Smckusick else
273468653Smckusick bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
273554451Smckusick splx(s);
273657791Smckusick VOP_BWRITE(bp);
273754451Smckusick goto loop;
273838884Smacklem }
273957791Smckusick splx(s);
274068653Smckusick if (passone) {
274168653Smckusick passone = 0;
274268653Smckusick goto again;
274368653Smckusick }
274468653Smckusick if (waitfor == MNT_WAIT) {
274554451Smckusick while (vp->v_numoutput) {
274654451Smckusick vp->v_flag |= VBWAIT;
274757791Smckusick error = tsleep((caddr_t)&vp->v_numoutput,
274857791Smckusick slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
274957791Smckusick if (error) {
275068653Smckusick if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
275157791Smckusick return (EINTR);
275257791Smckusick if (slpflag == PCATCH) {
275357791Smckusick slpflag = 0;
275457791Smckusick slptimeo = 2 * hz;
275557791Smckusick }
275657791Smckusick }
275754451Smckusick }
275868653Smckusick if (vp->v_dirtyblkhd.lh_first && commit) {
275968653Smckusick #ifndef DIAGNOSTIC
276054451Smckusick vprint("nfs_fsync: dirty", vp);
276157791Smckusick #endif
276254451Smckusick goto loop;
276354451Smckusick }
276454451Smckusick }
276553629Smckusick if (np->n_flag & NWRITEERR) {
276639751Smckusick error = np->n_error;
276753629Smckusick np->n_flag &= ~NWRITEERR;
276853629Smckusick }
276938884Smacklem return (error);
277038884Smacklem }
277139672Smckusick
277239672Smckusick /*
277360400Smckusick * Return POSIX pathconf information applicable to nfs.
277460400Smckusick *
277568653Smckusick * The NFS V2 protocol doesn't support this, so just return EINVAL
277668653Smckusick * for V2.
277760400Smckusick */
277860400Smckusick /* ARGSUSED */
277968653Smckusick int
nfs_pathconf(ap)278060400Smckusick nfs_pathconf(ap)
278160400Smckusick struct vop_pathconf_args /* {
278260400Smckusick struct vnode *a_vp;
278360400Smckusick int a_name;
278460400Smckusick int *a_retval;
278560400Smckusick } */ *ap;
278660400Smckusick {
278760400Smckusick
278860400Smckusick return (EINVAL);
278960400Smckusick }
279060400Smckusick
279160400Smckusick /*
279246201Smckusick * NFS advisory byte-level locks.
279346201Smckusick * Currently unsupported.
279446201Smckusick */
279552234Sheideman int
nfs_advlock(ap)279653806Smckusick nfs_advlock(ap)
279754668Smckusick struct vop_advlock_args /* {
279854668Smckusick struct vnode *a_vp;
279954668Smckusick caddr_t a_id;
280054668Smckusick int a_op;
280154668Smckusick struct flock *a_fl;
280254668Smckusick int a_flags;
280354668Smckusick } */ *ap;
280446201Smckusick {
280546201Smckusick
280646201Smckusick return (EOPNOTSUPP);
280746201Smckusick }
280846201Smckusick
280946201Smckusick /*
281039672Smckusick * Print out the contents of an nfsnode.
281139672Smckusick */
281252234Sheideman int
nfs_print(ap)281353806Smckusick nfs_print(ap)
281454668Smckusick struct vop_print_args /* {
281554668Smckusick struct vnode *a_vp;
281654668Smckusick } */ *ap;
281739672Smckusick {
281853806Smckusick register struct vnode *vp = ap->a_vp;
281953806Smckusick register struct nfsnode *np = VTONFS(vp);
282039672Smckusick
282168653Smckusick printf("tag VT_NFS, fileid %ld fsid 0x%lx",
282240294Smckusick np->n_vattr.va_fileid, np->n_vattr.va_fsid);
282353806Smckusick if (vp->v_type == VFIFO)
282453806Smckusick fifo_printinfo(vp);
282539914Smckusick printf("\n");
282668653Smckusick return (0);
282739672Smckusick }
282851573Smckusick
282951573Smckusick /*
283051573Smckusick * NFS directory offset lookup.
283151573Smckusick * Currently unsupported.
283251573Smckusick */
283352234Sheideman int
nfs_blkatoff(ap)283453806Smckusick nfs_blkatoff(ap)
283554668Smckusick struct vop_blkatoff_args /* {
283654668Smckusick struct vnode *a_vp;
283754668Smckusick off_t a_offset;
283854668Smckusick char **a_res;
283954668Smckusick struct buf **a_bpp;
284054668Smckusick } */ *ap;
284151573Smckusick {
284251573Smckusick
284351573Smckusick return (EOPNOTSUPP);
284451573Smckusick }
284551573Smckusick
284651573Smckusick /*
284751573Smckusick * NFS flat namespace allocation.
284851573Smckusick * Currently unsupported.
284951573Smckusick */
285052234Sheideman int
nfs_valloc(ap)285153806Smckusick nfs_valloc(ap)
285254668Smckusick struct vop_valloc_args /* {
285354668Smckusick struct vnode *a_pvp;
285454668Smckusick int a_mode;
285554668Smckusick struct ucred *a_cred;
285654668Smckusick struct vnode **a_vpp;
285754668Smckusick } */ *ap;
285851573Smckusick {
285951573Smckusick
286051573Smckusick return (EOPNOTSUPP);
286151573Smckusick }
286251573Smckusick
286351573Smckusick /*
286451573Smckusick * NFS flat namespace free.
286551573Smckusick * Currently unsupported.
286651573Smckusick */
286753582Sheideman int
nfs_vfree(ap)286853806Smckusick nfs_vfree(ap)
286954668Smckusick struct vop_vfree_args /* {
287054668Smckusick struct vnode *a_pvp;
287154668Smckusick ino_t a_ino;
287254668Smckusick int a_mode;
287354668Smckusick } */ *ap;
287451573Smckusick {
287551573Smckusick
287653582Sheideman return (EOPNOTSUPP);
287751573Smckusick }
287851573Smckusick
287951573Smckusick /*
288051573Smckusick * NFS file truncation.
288151573Smckusick */
288252234Sheideman int
nfs_truncate(ap)288353806Smckusick nfs_truncate(ap)
288454668Smckusick struct vop_truncate_args /* {
288554668Smckusick struct vnode *a_vp;
288654668Smckusick off_t a_length;
288754668Smckusick int a_flags;
288854668Smckusick struct ucred *a_cred;
288954668Smckusick struct proc *a_p;
289054668Smckusick } */ *ap;
289151573Smckusick {
289251573Smckusick
289351573Smckusick /* Use nfs_setattr */
289451573Smckusick printf("nfs_truncate: need to implement!!");
289551573Smckusick return (EOPNOTSUPP);
289651573Smckusick }
289751573Smckusick
289851573Smckusick /*
289951573Smckusick * NFS update.
290051573Smckusick */
290152234Sheideman int
nfs_update(ap)290253806Smckusick nfs_update(ap)
290354668Smckusick struct vop_update_args /* {
290454668Smckusick struct vnode *a_vp;
290554668Smckusick struct timeval *a_ta;
290654668Smckusick struct timeval *a_tm;
290754668Smckusick int a_waitfor;
290854668Smckusick } */ *ap;
290951573Smckusick {
291051573Smckusick
291151573Smckusick /* Use nfs_setattr */
291251573Smckusick printf("nfs_update: need to implement!!");
291351573Smckusick return (EOPNOTSUPP);
291451573Smckusick }
291553629Smckusick
291653629Smckusick /*
291768653Smckusick * Just call nfs_writebp() with the force argument set to 1.
291868653Smckusick */
291968653Smckusick int
nfs_bwrite(ap)292068653Smckusick nfs_bwrite(ap)
292168653Smckusick struct vop_bwrite_args /* {
292268653Smckusick struct vnode *a_bp;
292368653Smckusick } */ *ap;
292468653Smckusick {
292568653Smckusick
292668653Smckusick return (nfs_writebp(ap->a_bp, 1));
292768653Smckusick }
292868653Smckusick
292968653Smckusick /*
293068653Smckusick * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
293168653Smckusick * the force flag is one and it also handles the B_NEEDCOMMIT flag.
293268653Smckusick */
293368653Smckusick int
nfs_writebp(bp,force)293468653Smckusick nfs_writebp(bp, force)
293568653Smckusick register struct buf *bp;
293668653Smckusick int force;
293768653Smckusick {
293868653Smckusick register int oldflags = bp->b_flags, retv = 1;
293968653Smckusick register struct proc *p = curproc; /* XXX */
294068653Smckusick off_t off;
294168653Smckusick
294268653Smckusick if(!(bp->b_flags & B_BUSY))
294368653Smckusick panic("bwrite: buffer is not busy???");
294468653Smckusick
294568653Smckusick bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
294668653Smckusick
294768653Smckusick if (oldflags & B_ASYNC) {
294868653Smckusick if (oldflags & B_DELWRI) {
294968653Smckusick reassignbuf(bp, bp->b_vp);
295068653Smckusick } else if (p) {
295168653Smckusick ++p->p_stats->p_ru.ru_oublock;
295268653Smckusick }
295368653Smckusick }
295468653Smckusick bp->b_vp->v_numoutput++;
295568653Smckusick
295668653Smckusick /*
295768653Smckusick * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
295868653Smckusick * an actual write will have to be scheduled via. VOP_STRATEGY().
295968653Smckusick * If B_WRITEINPROG is already set, then push it with a write anyhow.
296068653Smckusick */
296168653Smckusick if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) {
296268653Smckusick off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
296368653Smckusick bp->b_flags |= B_WRITEINPROG;
296468653Smckusick retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
296568653Smckusick bp->b_wcred, bp->b_proc);
296668653Smckusick bp->b_flags &= ~B_WRITEINPROG;
296768653Smckusick if (!retv) {
296868653Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0;
296968653Smckusick bp->b_flags &= ~B_NEEDCOMMIT;
297068653Smckusick biodone(bp);
297168653Smckusick } else if (retv == NFSERR_STALEWRITEVERF)
297268653Smckusick nfs_clearcommit(bp->b_vp->v_mount);
297368653Smckusick }
297468653Smckusick if (retv) {
297568653Smckusick if (force)
297668653Smckusick bp->b_flags |= B_WRITEINPROG;
297768653Smckusick VOP_STRATEGY(bp);
297868653Smckusick }
297968653Smckusick
298068653Smckusick if( (oldflags & B_ASYNC) == 0) {
298168653Smckusick int rtval = biowait(bp);
298268653Smckusick if (oldflags & B_DELWRI) {
298368653Smckusick reassignbuf(bp, bp->b_vp);
298468653Smckusick } else if (p) {
298568653Smckusick ++p->p_stats->p_ru.ru_oublock;
298668653Smckusick }
298768653Smckusick brelse(bp);
298868653Smckusick return (rtval);
298968653Smckusick }
299068653Smckusick
299168653Smckusick return (0);
299268653Smckusick }
299368653Smckusick
299468653Smckusick /*
299556364Smckusick * nfs special file access vnode op.
299656364Smckusick * Essentially just get vattr and then imitate iaccess() since the device is
299756364Smckusick * local to the client.
299856364Smckusick */
299956364Smckusick int
nfsspec_access(ap)300056364Smckusick nfsspec_access(ap)
300156364Smckusick struct vop_access_args /* {
300256364Smckusick struct vnode *a_vp;
300356364Smckusick int a_mode;
300456364Smckusick struct ucred *a_cred;
300556364Smckusick struct proc *a_p;
300656364Smckusick } */ *ap;
300756364Smckusick {
300856364Smckusick register struct vattr *vap;
300956364Smckusick register gid_t *gp;
301056364Smckusick register struct ucred *cred = ap->a_cred;
3011*69743Smckusick struct vnode *vp = ap->a_vp;
301256364Smckusick mode_t mode = ap->a_mode;
301356364Smckusick struct vattr vattr;
301456364Smckusick register int i;
301556364Smckusick int error;
301656364Smckusick
301756364Smckusick /*
3018*69743Smckusick * Disallow write attempts on filesystems mounted read-only;
3019*69743Smckusick * unless the file is a socket, fifo, or a block or character
3020*69743Smckusick * device resident on the filesystem.
3021*69743Smckusick */
3022*69743Smckusick if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3023*69743Smckusick switch (vp->v_type) {
3024*69743Smckusick case VREG: case VDIR: case VLNK:
3025*69743Smckusick return (EROFS);
3026*69743Smckusick }
3027*69743Smckusick }
3028*69743Smckusick /*
302956364Smckusick * If you're the super-user,
303056364Smckusick * you always get access.
303156364Smckusick */
303256364Smckusick if (cred->cr_uid == 0)
303356364Smckusick return (0);
303456364Smckusick vap = &vattr;
3035*69743Smckusick error = VOP_GETATTR(vp, vap, cred, ap->a_p);
303668653Smckusick if (error)
303756364Smckusick return (error);
303856364Smckusick /*
303956364Smckusick * Access check is based on only one of owner, group, public.
304056364Smckusick * If not owner, then check group. If not a member of the
304156364Smckusick * group, then check public access.
304256364Smckusick */
304356364Smckusick if (cred->cr_uid != vap->va_uid) {
304456364Smckusick mode >>= 3;
304556364Smckusick gp = cred->cr_groups;
304656364Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++)
304756364Smckusick if (vap->va_gid == *gp)
304856364Smckusick goto found;
304956364Smckusick mode >>= 3;
305056364Smckusick found:
305156364Smckusick ;
305256364Smckusick }
305368653Smckusick error = (vap->va_mode & mode) == mode ? 0 : EACCES;
305468653Smckusick return (error);
305556364Smckusick }
305656364Smckusick
305756364Smckusick /*
305853629Smckusick * Read wrapper for special devices.
305953629Smckusick */
306053629Smckusick int
nfsspec_read(ap)306153629Smckusick nfsspec_read(ap)
306254668Smckusick struct vop_read_args /* {
306354668Smckusick struct vnode *a_vp;
306454668Smckusick struct uio *a_uio;
306554668Smckusick int a_ioflag;
306654668Smckusick struct ucred *a_cred;
306754668Smckusick } */ *ap;
306853629Smckusick {
306954032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp);
307053629Smckusick
307153629Smckusick /*
307253629Smckusick * Set access flag.
307353629Smckusick */
307454032Smckusick np->n_flag |= NACC;
307568653Smckusick np->n_atim.ts_sec = time.tv_sec;
307668653Smckusick np->n_atim.ts_nsec = time.tv_usec * 1000;
307753629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
307853629Smckusick }
307953629Smckusick
308053629Smckusick /*
308153629Smckusick * Write wrapper for special devices.
308253629Smckusick */
308353629Smckusick int
nfsspec_write(ap)308453629Smckusick nfsspec_write(ap)
308554668Smckusick struct vop_write_args /* {
308654668Smckusick struct vnode *a_vp;
308754668Smckusick struct uio *a_uio;
308854668Smckusick int a_ioflag;
308954668Smckusick struct ucred *a_cred;
309054668Smckusick } */ *ap;
309153629Smckusick {
309254032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp);
309353629Smckusick
309453629Smckusick /*
309554032Smckusick * Set update flag.
309653629Smckusick */
309754032Smckusick np->n_flag |= NUPD;
309868653Smckusick np->n_mtim.ts_sec = time.tv_sec;
309968653Smckusick np->n_mtim.ts_nsec = time.tv_usec * 1000;
310053629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
310153629Smckusick }
310253629Smckusick
310353629Smckusick /*
310453629Smckusick * Close wrapper for special devices.
310553629Smckusick *
310653629Smckusick * Update the times on the nfsnode then do device close.
310753629Smckusick */
310853629Smckusick int
nfsspec_close(ap)310953629Smckusick nfsspec_close(ap)
311054668Smckusick struct vop_close_args /* {
311154668Smckusick struct vnode *a_vp;
311254668Smckusick int a_fflag;
311354668Smckusick struct ucred *a_cred;
311454668Smckusick struct proc *a_p;
311554668Smckusick } */ *ap;
311653629Smckusick {
311753806Smckusick register struct vnode *vp = ap->a_vp;
311853806Smckusick register struct nfsnode *np = VTONFS(vp);
311953629Smckusick struct vattr vattr;
312053629Smckusick
312153629Smckusick if (np->n_flag & (NACC | NUPD)) {
312253629Smckusick np->n_flag |= NCHG;
312353806Smckusick if (vp->v_usecount == 1 &&
312453806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
312553629Smckusick VATTR_NULL(&vattr);
312668653Smckusick if (np->n_flag & NACC)
312768653Smckusick vattr.va_atime = np->n_atim;
312868653Smckusick if (np->n_flag & NUPD)
312968653Smckusick vattr.va_mtime = np->n_mtim;
313053806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
313153629Smckusick }
313253629Smckusick }
313353629Smckusick return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
313453629Smckusick }
313553629Smckusick
313653629Smckusick /*
313753629Smckusick * Read wrapper for fifos.
313853629Smckusick */
313953629Smckusick int
nfsfifo_read(ap)314053629Smckusick nfsfifo_read(ap)
314154668Smckusick struct vop_read_args /* {
314254668Smckusick struct vnode *a_vp;
314354668Smckusick struct uio *a_uio;
314454668Smckusick int a_ioflag;
314554668Smckusick struct ucred *a_cred;
314654668Smckusick } */ *ap;
314753629Smckusick {
314853629Smckusick extern int (**fifo_vnodeop_p)();
314954032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp);
315053629Smckusick
315153629Smckusick /*
315253629Smckusick * Set access flag.
315353629Smckusick */
315454032Smckusick np->n_flag |= NACC;
315568653Smckusick np->n_atim.ts_sec = time.tv_sec;
315668653Smckusick np->n_atim.ts_nsec = time.tv_usec * 1000;
315753629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
315853629Smckusick }
315953629Smckusick
316053629Smckusick /*
316153629Smckusick * Write wrapper for fifos.
316253629Smckusick */
316353629Smckusick int
nfsfifo_write(ap)316453629Smckusick nfsfifo_write(ap)
316554668Smckusick struct vop_write_args /* {
316654668Smckusick struct vnode *a_vp;
316754668Smckusick struct uio *a_uio;
316854668Smckusick int a_ioflag;
316954668Smckusick struct ucred *a_cred;
317054668Smckusick } */ *ap;
317153629Smckusick {
317253629Smckusick extern int (**fifo_vnodeop_p)();
317354032Smckusick register struct nfsnode *np = VTONFS(ap->a_vp);
317453629Smckusick
317553629Smckusick /*
317653629Smckusick * Set update flag.
317753629Smckusick */
317854032Smckusick np->n_flag |= NUPD;
317968653Smckusick np->n_mtim.ts_sec = time.tv_sec;
318068653Smckusick np->n_mtim.ts_nsec = time.tv_usec * 1000;
318153629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
318253629Smckusick }
318353629Smckusick
318453629Smckusick /*
318553629Smckusick * Close wrapper for fifos.
318653629Smckusick *
318753629Smckusick * Update the times on the nfsnode then do fifo close.
318853629Smckusick */
318953629Smckusick int
nfsfifo_close(ap)319053629Smckusick nfsfifo_close(ap)
319154668Smckusick struct vop_close_args /* {
319254668Smckusick struct vnode *a_vp;
319354668Smckusick int a_fflag;
319454668Smckusick struct ucred *a_cred;
319554668Smckusick struct proc *a_p;
319654668Smckusick } */ *ap;
319753629Smckusick {
319853806Smckusick register struct vnode *vp = ap->a_vp;
319953806Smckusick register struct nfsnode *np = VTONFS(vp);
320053629Smckusick struct vattr vattr;
320153629Smckusick extern int (**fifo_vnodeop_p)();
320253629Smckusick
320353629Smckusick if (np->n_flag & (NACC | NUPD)) {
320468653Smckusick if (np->n_flag & NACC) {
320568653Smckusick np->n_atim.ts_sec = time.tv_sec;
320668653Smckusick np->n_atim.ts_nsec = time.tv_usec * 1000;
320768653Smckusick }
320868653Smckusick if (np->n_flag & NUPD) {
320968653Smckusick np->n_mtim.ts_sec = time.tv_sec;
321068653Smckusick np->n_mtim.ts_nsec = time.tv_usec * 1000;
321168653Smckusick }
321253629Smckusick np->n_flag |= NCHG;
321353806Smckusick if (vp->v_usecount == 1 &&
321453806Smckusick (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
321553629Smckusick VATTR_NULL(&vattr);
321668653Smckusick if (np->n_flag & NACC)
321768653Smckusick vattr.va_atime = np->n_atim;
321868653Smckusick if (np->n_flag & NUPD)
321968653Smckusick vattr.va_mtime = np->n_mtim;
322053806Smckusick (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
322153629Smckusick }
322253629Smckusick }
322353629Smckusick return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
322453629Smckusick }
3225