xref: /netbsd-src/sys/fs/nfs/server/nfs_nfsdsocket.c (revision c10f8b5081799c06e7cdfb1e21480fb0ef402d8b)
1*c10f8b50Spgoyette /*	$NetBSD: nfs_nfsdsocket.c,v 1.2 2016/12/13 21:50:32 pgoyette Exp $	*/
26ca35587Sdholland /*-
36ca35587Sdholland  * Copyright (c) 1989, 1993
46ca35587Sdholland  *	The Regents of the University of California.  All rights reserved.
56ca35587Sdholland  *
66ca35587Sdholland  * This code is derived from software contributed to Berkeley by
76ca35587Sdholland  * Rick Macklem at The University of Guelph.
86ca35587Sdholland  *
96ca35587Sdholland  * Redistribution and use in source and binary forms, with or without
106ca35587Sdholland  * modification, are permitted provided that the following conditions
116ca35587Sdholland  * are met:
126ca35587Sdholland  * 1. Redistributions of source code must retain the above copyright
136ca35587Sdholland  *    notice, this list of conditions and the following disclaimer.
146ca35587Sdholland  * 2. Redistributions in binary form must reproduce the above copyright
156ca35587Sdholland  *    notice, this list of conditions and the following disclaimer in the
166ca35587Sdholland  *    documentation and/or other materials provided with the distribution.
176ca35587Sdholland  * 4. Neither the name of the University nor the names of its contributors
186ca35587Sdholland  *    may be used to endorse or promote products derived from this software
196ca35587Sdholland  *    without specific prior written permission.
206ca35587Sdholland  *
216ca35587Sdholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
226ca35587Sdholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
236ca35587Sdholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
246ca35587Sdholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
256ca35587Sdholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
266ca35587Sdholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276ca35587Sdholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
286ca35587Sdholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
296ca35587Sdholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
306ca35587Sdholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
316ca35587Sdholland  * SUCH DAMAGE.
326ca35587Sdholland  *
336ca35587Sdholland  */
346ca35587Sdholland 
356ca35587Sdholland #include <sys/cdefs.h>
36e81f0ea2Spgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdsocket.c 304026 2016-08-12 22:44:59Z rmacklem "); */
37*c10f8b50Spgoyette __RCSID("$NetBSD: nfs_nfsdsocket.c,v 1.2 2016/12/13 21:50:32 pgoyette Exp $");
386ca35587Sdholland 
396ca35587Sdholland /*
406ca35587Sdholland  * Socket operations for use by the nfs server.
416ca35587Sdholland  */
426ca35587Sdholland 
436ca35587Sdholland #ifndef APPLEKEXT
44*c10f8b50Spgoyette #include <fs/nfs/common/nfsport.h>
456ca35587Sdholland 
46e81f0ea2Spgoyette extern struct nfsstatsv1 nfsstatsv1;
476ca35587Sdholland extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
486ca35587Sdholland extern int nfs_pubfhset, nfs_rootfhset;
496ca35587Sdholland extern struct nfsv4lock nfsv4rootfs_lock;
506ca35587Sdholland extern struct nfsrv_stablefirst nfsrv_stablefirst;
51e81f0ea2Spgoyette extern struct nfsclienthashhead *nfsclienthash;
52e81f0ea2Spgoyette extern int nfsrv_clienthashsize;
536ca35587Sdholland extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
54e81f0ea2Spgoyette extern int nfsd_debuglevel;
556ca35587Sdholland NFSV4ROOTLOCKMUTEX;
566ca35587Sdholland NFSSTATESPINLOCK;
576ca35587Sdholland 
586ca35587Sdholland int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
596ca35587Sdholland     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
606ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
616ca35587Sdholland 	nfsrvd_getattr,
626ca35587Sdholland 	nfsrvd_setattr,
636ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
646ca35587Sdholland 	nfsrvd_access,
656ca35587Sdholland 	nfsrvd_readlink,
666ca35587Sdholland 	nfsrvd_read,
676ca35587Sdholland 	nfsrvd_write,
686ca35587Sdholland 	nfsrvd_create,
696ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
706ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
716ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
726ca35587Sdholland 	nfsrvd_remove,
736ca35587Sdholland 	nfsrvd_remove,
746ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
756ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
766ca35587Sdholland 	nfsrvd_readdir,
776ca35587Sdholland 	nfsrvd_readdirplus,
786ca35587Sdholland 	nfsrvd_statfs,
796ca35587Sdholland 	nfsrvd_fsinfo,
806ca35587Sdholland 	nfsrvd_pathconf,
816ca35587Sdholland 	nfsrvd_commit,
826ca35587Sdholland };
836ca35587Sdholland 
846ca35587Sdholland int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
856ca35587Sdholland     int, vnode_t , vnode_t *, fhandle_t *,
866ca35587Sdholland     NFSPROC_T *, struct nfsexstuff *) = {
876ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
886ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
896ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
906ca35587Sdholland 	nfsrvd_lookup,
916ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
926ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
936ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
946ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
956ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
966ca35587Sdholland 	nfsrvd_mkdir,
976ca35587Sdholland 	nfsrvd_symlink,
986ca35587Sdholland 	nfsrvd_mknod,
996ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1006ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1016ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1026ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1036ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1046ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1056ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1066ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1076ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1086ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1096ca35587Sdholland };
1106ca35587Sdholland 
1116ca35587Sdholland int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
1126ca35587Sdholland     int, vnode_t , vnode_t , NFSPROC_T *,
1136ca35587Sdholland     struct nfsexstuff *, struct nfsexstuff *) = {
1146ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1156ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1166ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1176ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1186ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1196ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1206ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1216ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1226ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1236ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1246ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1256ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1266ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1276ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1286ca35587Sdholland 	nfsrvd_rename,
1296ca35587Sdholland 	nfsrvd_link,
1306ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1316ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1326ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1336ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1346ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1356ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1366ca35587Sdholland };
1376ca35587Sdholland 
138e81f0ea2Spgoyette int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *,
1396ca35587Sdholland     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
1406ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1416ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1426ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1436ca35587Sdholland 	nfsrvd_access,
1446ca35587Sdholland 	nfsrvd_close,
1456ca35587Sdholland 	nfsrvd_commit,
1466ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1476ca35587Sdholland 	nfsrvd_delegpurge,
1486ca35587Sdholland 	nfsrvd_delegreturn,
1496ca35587Sdholland 	nfsrvd_getattr,
1506ca35587Sdholland 	nfsrvd_getfh,
1516ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1526ca35587Sdholland 	nfsrvd_lock,
1536ca35587Sdholland 	nfsrvd_lockt,
1546ca35587Sdholland 	nfsrvd_locku,
1556ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1566ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1576ca35587Sdholland 	nfsrvd_verify,
1586ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1596ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1606ca35587Sdholland 	nfsrvd_openconfirm,
1616ca35587Sdholland 	nfsrvd_opendowngrade,
1626ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1636ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1646ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1656ca35587Sdholland 	nfsrvd_read,
1666ca35587Sdholland 	nfsrvd_readdirplus,
1676ca35587Sdholland 	nfsrvd_readlink,
1686ca35587Sdholland 	nfsrvd_remove,
1696ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1706ca35587Sdholland 	nfsrvd_renew,
1716ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1726ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1736ca35587Sdholland 	nfsrvd_secinfo,
1746ca35587Sdholland 	nfsrvd_setattr,
1756ca35587Sdholland 	nfsrvd_setclientid,
1766ca35587Sdholland 	nfsrvd_setclientidcfrm,
1776ca35587Sdholland 	nfsrvd_verify,
1786ca35587Sdholland 	nfsrvd_write,
1796ca35587Sdholland 	nfsrvd_releaselckown,
180e81f0ea2Spgoyette 	nfsrvd_notsupp,
181e81f0ea2Spgoyette 	nfsrvd_notsupp,
182e81f0ea2Spgoyette 	nfsrvd_exchangeid,
183e81f0ea2Spgoyette 	nfsrvd_createsession,
184e81f0ea2Spgoyette 	nfsrvd_destroysession,
185e81f0ea2Spgoyette 	nfsrvd_freestateid,
186e81f0ea2Spgoyette 	nfsrvd_notsupp,
187e81f0ea2Spgoyette 	nfsrvd_notsupp,
188e81f0ea2Spgoyette 	nfsrvd_notsupp,
189e81f0ea2Spgoyette 	nfsrvd_notsupp,
190e81f0ea2Spgoyette 	nfsrvd_notsupp,
191e81f0ea2Spgoyette 	nfsrvd_notsupp,
192e81f0ea2Spgoyette 	nfsrvd_notsupp,
193e81f0ea2Spgoyette 	nfsrvd_sequence,
194e81f0ea2Spgoyette 	nfsrvd_notsupp,
195e81f0ea2Spgoyette 	nfsrvd_notsupp,
196e81f0ea2Spgoyette 	nfsrvd_notsupp,
197e81f0ea2Spgoyette 	nfsrvd_destroyclientid,
198e81f0ea2Spgoyette 	nfsrvd_reclaimcomplete,
1996ca35587Sdholland };
2006ca35587Sdholland 
201e81f0ea2Spgoyette int (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
2026ca35587Sdholland     int, vnode_t , vnode_t *, fhandle_t *,
2036ca35587Sdholland     NFSPROC_T *, struct nfsexstuff *) = {
2046ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2056ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2066ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2076ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2086ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2096ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2106ca35587Sdholland 	nfsrvd_mknod,
2116ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2126ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2136ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2146ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2156ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2166ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2176ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2186ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2196ca35587Sdholland 	nfsrvd_lookup,
2206ca35587Sdholland 	nfsrvd_lookup,
2216ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2226ca35587Sdholland 	nfsrvd_open,
2236ca35587Sdholland 	nfsrvd_openattr,
2246ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2256ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2266ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2276ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2286ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2296ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2306ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2316ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2326ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2336ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2346ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2356ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2366ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2376ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2386ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2396ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2406ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2416ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2426ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2436ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
244e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
245e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
246e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
247e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
248e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
249e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
250e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
251e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
252e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
253e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
254e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
255e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
256e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
257e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
258e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
259e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
260e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
261e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
262e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2636ca35587Sdholland };
2646ca35587Sdholland 
265e81f0ea2Spgoyette int (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
2666ca35587Sdholland     int, vnode_t , vnode_t , NFSPROC_T *,
2676ca35587Sdholland     struct nfsexstuff *, struct nfsexstuff *) = {
2686ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2696ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2706ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2716ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2726ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2736ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2746ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2756ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2766ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2776ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2786ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2796ca35587Sdholland 	nfsrvd_link,
2806ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2816ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2826ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2836ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2846ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2856ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2866ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2876ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2886ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2896ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2906ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2916ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2926ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2936ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2946ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2956ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2966ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2976ca35587Sdholland 	nfsrvd_rename,
2986ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2996ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3006ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3016ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3026ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3036ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3046ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3056ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3066ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3076ca35587Sdholland 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
308e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
309e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
310e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
311e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
312e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
313e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
314e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
315e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
316e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
317e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
318e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
319e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
320e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
321e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
322e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
323e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
324e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
325e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
326e81f0ea2Spgoyette 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3276ca35587Sdholland };
3286ca35587Sdholland #endif	/* !APPLEKEXT */
3296ca35587Sdholland 
3306ca35587Sdholland /*
3316ca35587Sdholland  * Static array that defines which nfs rpc's are nonidempotent
3326ca35587Sdholland  */
3336ca35587Sdholland static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
3346ca35587Sdholland 	FALSE,
3356ca35587Sdholland 	FALSE,
3366ca35587Sdholland 	TRUE,
3376ca35587Sdholland 	FALSE,
3386ca35587Sdholland 	FALSE,
3396ca35587Sdholland 	FALSE,
3406ca35587Sdholland 	FALSE,
3416ca35587Sdholland 	TRUE,
3426ca35587Sdholland 	TRUE,
3436ca35587Sdholland 	TRUE,
3446ca35587Sdholland 	TRUE,
3456ca35587Sdholland 	TRUE,
3466ca35587Sdholland 	TRUE,
3476ca35587Sdholland 	TRUE,
3486ca35587Sdholland 	TRUE,
3496ca35587Sdholland 	TRUE,
3506ca35587Sdholland 	FALSE,
3516ca35587Sdholland 	FALSE,
3526ca35587Sdholland 	FALSE,
3536ca35587Sdholland 	FALSE,
3546ca35587Sdholland 	FALSE,
3556ca35587Sdholland 	FALSE,
3566ca35587Sdholland };
3576ca35587Sdholland 
3586ca35587Sdholland /*
3596ca35587Sdholland  * This static array indicates whether or not the RPC modifies the
3606ca35587Sdholland  * file system.
3616ca35587Sdholland  */
3626ca35587Sdholland static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
3636ca35587Sdholland     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
3646ca35587Sdholland     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
3656ca35587Sdholland 
3666ca35587Sdholland /* local functions */
3676ca35587Sdholland static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
368e81f0ea2Spgoyette     u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p);
3696ca35587Sdholland 
3706ca35587Sdholland 
3716ca35587Sdholland /*
3726ca35587Sdholland  * This static array indicates which server procedures require the extra
3736ca35587Sdholland  * arguments to return the current file handle for V2, 3.
3746ca35587Sdholland  */
3756ca35587Sdholland static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
3766ca35587Sdholland 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
3776ca35587Sdholland 
378e81f0ea2Spgoyette extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
3796ca35587Sdholland 
3806ca35587Sdholland static int nfsv3to4op[NFS_V3NPROCS] = {
3816ca35587Sdholland 	NFSPROC_NULL,
3826ca35587Sdholland 	NFSV4OP_GETATTR,
3836ca35587Sdholland 	NFSV4OP_SETATTR,
3846ca35587Sdholland 	NFSV4OP_LOOKUP,
3856ca35587Sdholland 	NFSV4OP_ACCESS,
3866ca35587Sdholland 	NFSV4OP_READLINK,
3876ca35587Sdholland 	NFSV4OP_READ,
3886ca35587Sdholland 	NFSV4OP_WRITE,
3896ca35587Sdholland 	NFSV4OP_V3CREATE,
3906ca35587Sdholland 	NFSV4OP_MKDIR,
3916ca35587Sdholland 	NFSV4OP_SYMLINK,
3926ca35587Sdholland 	NFSV4OP_MKNOD,
3936ca35587Sdholland 	NFSV4OP_REMOVE,
3946ca35587Sdholland 	NFSV4OP_RMDIR,
3956ca35587Sdholland 	NFSV4OP_RENAME,
3966ca35587Sdholland 	NFSV4OP_LINK,
3976ca35587Sdholland 	NFSV4OP_READDIR,
3986ca35587Sdholland 	NFSV4OP_READDIRPLUS,
3996ca35587Sdholland 	NFSV4OP_FSSTAT,
4006ca35587Sdholland 	NFSV4OP_FSINFO,
4016ca35587Sdholland 	NFSV4OP_PATHCONF,
4026ca35587Sdholland 	NFSV4OP_COMMIT,
4036ca35587Sdholland };
4046ca35587Sdholland 
405e81f0ea2Spgoyette static struct mtx nfsrvd_statmtx;
406e81f0ea2Spgoyette MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
407e81f0ea2Spgoyette 
408e81f0ea2Spgoyette static void
nfsrvd_statstart(int op,struct bintime * now)409e81f0ea2Spgoyette nfsrvd_statstart(int op, struct bintime *now)
410e81f0ea2Spgoyette {
411e81f0ea2Spgoyette 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
412e81f0ea2Spgoyette 		printf("%s: op %d invalid\n", __func__, op);
413e81f0ea2Spgoyette 		return;
414e81f0ea2Spgoyette 	}
415e81f0ea2Spgoyette 
416e81f0ea2Spgoyette 	mtx_lock(&nfsrvd_statmtx);
417e81f0ea2Spgoyette 	if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
418e81f0ea2Spgoyette 		if (now != NULL)
419e81f0ea2Spgoyette 			nfsstatsv1.busyfrom = *now;
420e81f0ea2Spgoyette 		else
421e81f0ea2Spgoyette 			binuptime(&nfsstatsv1.busyfrom);
422e81f0ea2Spgoyette 
423e81f0ea2Spgoyette 	}
424e81f0ea2Spgoyette 	nfsstatsv1.srvrpccnt[op]++;
425e81f0ea2Spgoyette 	nfsstatsv1.srvstartcnt++;
426e81f0ea2Spgoyette 	mtx_unlock(&nfsrvd_statmtx);
427e81f0ea2Spgoyette 
428e81f0ea2Spgoyette }
429e81f0ea2Spgoyette 
430e81f0ea2Spgoyette static void
nfsrvd_statend(int op,uint64_t bytes,struct bintime * now,struct bintime * then)431e81f0ea2Spgoyette nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
432e81f0ea2Spgoyette     struct bintime *then)
433e81f0ea2Spgoyette {
434e81f0ea2Spgoyette 	struct bintime dt, lnow;
435e81f0ea2Spgoyette 
436e81f0ea2Spgoyette 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
437e81f0ea2Spgoyette 		printf("%s: op %d invalid\n", __func__, op);
438e81f0ea2Spgoyette 		return;
439e81f0ea2Spgoyette 	}
440e81f0ea2Spgoyette 
441e81f0ea2Spgoyette 	if (now == NULL) {
442e81f0ea2Spgoyette 		now = &lnow;
443e81f0ea2Spgoyette 		binuptime(now);
444e81f0ea2Spgoyette 	}
445e81f0ea2Spgoyette 
446e81f0ea2Spgoyette 	mtx_lock(&nfsrvd_statmtx);
447e81f0ea2Spgoyette 
448e81f0ea2Spgoyette 	nfsstatsv1.srvbytes[op] += bytes;
449e81f0ea2Spgoyette 	nfsstatsv1.srvops[op]++;
450e81f0ea2Spgoyette 
451e81f0ea2Spgoyette 	if (then != NULL) {
452e81f0ea2Spgoyette 		dt = *now;
453e81f0ea2Spgoyette 		bintime_sub(&dt, then);
454e81f0ea2Spgoyette 		bintime_add(&nfsstatsv1.srvduration[op], &dt);
455e81f0ea2Spgoyette 	}
456e81f0ea2Spgoyette 
457e81f0ea2Spgoyette 	dt = *now;
458e81f0ea2Spgoyette 	bintime_sub(&dt, &nfsstatsv1.busyfrom);
459e81f0ea2Spgoyette 	bintime_add(&nfsstatsv1.busytime, &dt);
460e81f0ea2Spgoyette 	nfsstatsv1.busyfrom = *now;
461e81f0ea2Spgoyette 
462e81f0ea2Spgoyette 	nfsstatsv1.srvdonecnt++;
463e81f0ea2Spgoyette 
464e81f0ea2Spgoyette 	mtx_unlock(&nfsrvd_statmtx);
465e81f0ea2Spgoyette }
466e81f0ea2Spgoyette 
4676ca35587Sdholland /*
4686ca35587Sdholland  * Do an RPC. Basically, get the file handles translated to vnode pointers
4696ca35587Sdholland  * and then call the appropriate server routine. The server routines are
4706ca35587Sdholland  * split into groups, based on whether they use a file handle or file
4716ca35587Sdholland  * handle plus name or ...
4726ca35587Sdholland  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
4736ca35587Sdholland  */
4746ca35587Sdholland APPLESTATIC void
nfsrvd_dorpc(struct nfsrv_descript * nd,int isdgram,u_char * tag,int taglen,u_int32_t minorvers,NFSPROC_T * p)475e81f0ea2Spgoyette nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
476e81f0ea2Spgoyette     u_int32_t minorvers, NFSPROC_T *p)
4776ca35587Sdholland {
4786ca35587Sdholland 	int error = 0, lktype;
4796ca35587Sdholland 	vnode_t vp;
4806ca35587Sdholland 	mount_t mp = NULL;
4816ca35587Sdholland 	struct nfsrvfh fh;
4826ca35587Sdholland 	struct nfsexstuff nes;
4836ca35587Sdholland 
4846ca35587Sdholland 	/*
4856ca35587Sdholland 	 * Get a locked vnode for the first file handle
4866ca35587Sdholland 	 */
4876ca35587Sdholland 	if (!(nd->nd_flag & ND_NFSV4)) {
4886ca35587Sdholland 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
4896ca35587Sdholland 		/*
4906ca35587Sdholland 		 * For NFSv3, if the malloc/mget allocation is near limits,
4916ca35587Sdholland 		 * return NFSERR_DELAY.
4926ca35587Sdholland 		 */
4936ca35587Sdholland 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
4946ca35587Sdholland 			nd->nd_repstat = NFSERR_DELAY;
4956ca35587Sdholland 			vp = NULL;
4966ca35587Sdholland 		} else {
4976ca35587Sdholland 			error = nfsrv_mtofh(nd, &fh);
4986ca35587Sdholland 			if (error) {
4996ca35587Sdholland 				if (error != EBADRPC)
5006ca35587Sdholland 					printf("nfs dorpc err1=%d\n", error);
5016ca35587Sdholland 				nd->nd_repstat = NFSERR_GARBAGE;
5026ca35587Sdholland 				goto out;
5036ca35587Sdholland 			}
5046ca35587Sdholland 			if (nd->nd_procnum == NFSPROC_READ ||
5056ca35587Sdholland 			    nd->nd_procnum == NFSPROC_WRITE ||
5066ca35587Sdholland 			    nd->nd_procnum == NFSPROC_READDIR ||
507e81f0ea2Spgoyette 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
5086ca35587Sdholland 			    nd->nd_procnum == NFSPROC_READLINK ||
5096ca35587Sdholland 			    nd->nd_procnum == NFSPROC_GETATTR ||
510e81f0ea2Spgoyette 			    nd->nd_procnum == NFSPROC_ACCESS ||
511e81f0ea2Spgoyette 			    nd->nd_procnum == NFSPROC_FSSTAT ||
512e81f0ea2Spgoyette 			    nd->nd_procnum == NFSPROC_FSINFO)
5136ca35587Sdholland 				lktype = LK_SHARED;
5146ca35587Sdholland 			else
5156ca35587Sdholland 				lktype = LK_EXCLUSIVE;
5166ca35587Sdholland 			if (nd->nd_flag & ND_PUBLOOKUP)
5176ca35587Sdholland 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
5186ca35587Sdholland 				    &mp, nfs_writerpc[nd->nd_procnum], p);
5196ca35587Sdholland 			else
5206ca35587Sdholland 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
5216ca35587Sdholland 				    &mp, nfs_writerpc[nd->nd_procnum], p);
5226ca35587Sdholland 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
5236ca35587Sdholland 				goto out;
5246ca35587Sdholland 		}
5256ca35587Sdholland 	}
5266ca35587Sdholland 
5276ca35587Sdholland 	/*
5286ca35587Sdholland 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
5296ca35587Sdholland 	 * cache, as required.
5306ca35587Sdholland 	 * For V4, nfsrvd_compound() does this.
5316ca35587Sdholland 	 */
5326ca35587Sdholland 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
5336ca35587Sdholland 		nd->nd_flag |= ND_SAVEREPLY;
5346ca35587Sdholland 
5356ca35587Sdholland 	nfsrvd_rephead(nd);
5366ca35587Sdholland 	/*
5376ca35587Sdholland 	 * If nd_repstat is non-zero, just fill in the reply status
5386ca35587Sdholland 	 * to complete the RPC reply for V2. Otherwise, you must do
5396ca35587Sdholland 	 * the RPC.
5406ca35587Sdholland 	 */
5416ca35587Sdholland 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
5426ca35587Sdholland 		*nd->nd_errp = nfsd_errmap(nd);
543e81f0ea2Spgoyette 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
544e81f0ea2Spgoyette 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
545e81f0ea2Spgoyette 		   /*now*/ NULL, /*then*/ NULL);
5466ca35587Sdholland 		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
5476ca35587Sdholland 			vn_finished_write(mp);
5486ca35587Sdholland 		goto out;
5496ca35587Sdholland 	}
5506ca35587Sdholland 
5516ca35587Sdholland 	/*
5526ca35587Sdholland 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
5536ca35587Sdholland 	 * works through the sub-rpcs, otherwise just call the procedure.
5546ca35587Sdholland 	 * The procedures are in three groups with different arguments.
5556ca35587Sdholland 	 * The group is indicated by the value in nfs_retfh[].
5566ca35587Sdholland 	 */
5576ca35587Sdholland 	if (nd->nd_flag & ND_NFSV4) {
558e81f0ea2Spgoyette 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
5596ca35587Sdholland 	} else {
560e81f0ea2Spgoyette 		struct bintime start_time;
561e81f0ea2Spgoyette 
562e81f0ea2Spgoyette 		binuptime(&start_time);
563e81f0ea2Spgoyette 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
564e81f0ea2Spgoyette 
5656ca35587Sdholland 		if (nfs_retfh[nd->nd_procnum] == 1) {
5666ca35587Sdholland 			if (vp)
5676ca35587Sdholland 				NFSVOPUNLOCK(vp, 0);
5686ca35587Sdholland 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
5696ca35587Sdholland 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
5706ca35587Sdholland 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
5716ca35587Sdholland 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
5726ca35587Sdholland 			    vp, NULL, p, &nes, NULL);
5736ca35587Sdholland 		} else {
5746ca35587Sdholland 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
5756ca35587Sdholland 			    vp, p, &nes);
5766ca35587Sdholland 		}
5776ca35587Sdholland 		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
5786ca35587Sdholland 			vn_finished_write(mp);
579e81f0ea2Spgoyette 
580e81f0ea2Spgoyette 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
581e81f0ea2Spgoyette 		    /*now*/ NULL, /*then*/ &start_time);
5826ca35587Sdholland 	}
5836ca35587Sdholland 	if (error) {
5846ca35587Sdholland 		if (error != EBADRPC)
5856ca35587Sdholland 			printf("nfs dorpc err2=%d\n", error);
5866ca35587Sdholland 		nd->nd_repstat = NFSERR_GARBAGE;
5876ca35587Sdholland 	}
5886ca35587Sdholland 	*nd->nd_errp = nfsd_errmap(nd);
5896ca35587Sdholland 
5906ca35587Sdholland 	/*
5916ca35587Sdholland 	 * Don't cache certain reply status values.
5926ca35587Sdholland 	 */
5936ca35587Sdholland 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
5946ca35587Sdholland 	    (nd->nd_repstat == NFSERR_GARBAGE ||
5956ca35587Sdholland 	     nd->nd_repstat == NFSERR_BADXDR ||
5966ca35587Sdholland 	     nd->nd_repstat == NFSERR_MOVED ||
5976ca35587Sdholland 	     nd->nd_repstat == NFSERR_DELAY ||
5986ca35587Sdholland 	     nd->nd_repstat == NFSERR_BADSEQID ||
5996ca35587Sdholland 	     nd->nd_repstat == NFSERR_RESOURCE ||
6006ca35587Sdholland 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
6016ca35587Sdholland 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
6026ca35587Sdholland 	     nd->nd_repstat == NFSERR_STALESTATEID ||
6036ca35587Sdholland 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
6046ca35587Sdholland 	     nd->nd_repstat == NFSERR_BADSTATEID ||
6056ca35587Sdholland 	     nd->nd_repstat == NFSERR_GRACE ||
6066ca35587Sdholland 	     nd->nd_repstat == NFSERR_NOGRACE))
6076ca35587Sdholland 		nd->nd_flag &= ~ND_SAVEREPLY;
6086ca35587Sdholland 
6096ca35587Sdholland out:
6106ca35587Sdholland 	NFSEXITCODE2(0, nd);
6116ca35587Sdholland }
6126ca35587Sdholland 
6136ca35587Sdholland /*
6146ca35587Sdholland  * Breaks down a compound RPC request and calls the server routines for
6156ca35587Sdholland  * the subprocedures.
6166ca35587Sdholland  * Some suboperations are performed directly here to simplify file handle<-->
6176ca35587Sdholland  * vnode pointer handling.
6186ca35587Sdholland  */
6196ca35587Sdholland static void
nfsrvd_compound(struct nfsrv_descript * nd,int isdgram,u_char * tag,int taglen,u_int32_t minorvers,NFSPROC_T * p)620e81f0ea2Spgoyette nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
621e81f0ea2Spgoyette     int taglen, u_int32_t minorvers, NFSPROC_T *p)
6226ca35587Sdholland {
623e81f0ea2Spgoyette 	int i, lktype, op, op0 = 0, statsinprog = 0;
6246ca35587Sdholland 	u_int32_t *tl;
6256ca35587Sdholland 	struct nfsclient *clp, *nclp;
626e81f0ea2Spgoyette 	int numops, error = 0, igotlock;
627e81f0ea2Spgoyette 	u_int32_t retops = 0, *retopsp = NULL, *repp;
6286ca35587Sdholland 	vnode_t vp, nvp, savevp;
6296ca35587Sdholland 	struct nfsrvfh fh;
6306ca35587Sdholland 	mount_t new_mp, temp_mp = NULL;
6316ca35587Sdholland 	struct ucred *credanon;
6326ca35587Sdholland 	struct nfsexstuff nes, vpnes, savevpnes;
6336ca35587Sdholland 	fsid_t cur_fsid, save_fsid;
6346ca35587Sdholland 	static u_int64_t compref = 0;
635e81f0ea2Spgoyette 	struct bintime start_time;
6366ca35587Sdholland 
6376ca35587Sdholland 	NFSVNO_EXINIT(&vpnes);
6386ca35587Sdholland 	NFSVNO_EXINIT(&savevpnes);
6396ca35587Sdholland 	/*
6406ca35587Sdholland 	 * Put the seq# of the current compound RPC in nfsrv_descript.
6416ca35587Sdholland 	 * (This is used by nfsrv_checkgetattr(), to see if the write
6426ca35587Sdholland 	 *  delegation was created by the same compound RPC as the one
6436ca35587Sdholland 	 *  with that Getattr in it.)
6446ca35587Sdholland 	 * Don't worry about the 64bit number wrapping around. It ain't
6456ca35587Sdholland 	 * gonna happen before this server gets shut down/rebooted.
6466ca35587Sdholland 	 */
6476ca35587Sdholland 	nd->nd_compref = compref++;
6486ca35587Sdholland 
6496ca35587Sdholland 	/*
6506ca35587Sdholland 	 * Check for and optionally get a lock on the root. This lock means that
6516ca35587Sdholland 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
6526ca35587Sdholland 	 * is required when the V4 root is being changed, the stable storage
6536ca35587Sdholland 	 * restart file is being updated, or callbacks are being done.
6546ca35587Sdholland 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
6556ca35587Sdholland 	 * either hold a reference count (nfs_usecnt) or the lock. When
6566ca35587Sdholland 	 * nfsrv_unlock() is called to release the lock, it can optionally
6576ca35587Sdholland 	 * also get a reference count, which saves the need for a call to
6586ca35587Sdholland 	 * nfsrv_getref() after nfsrv_unlock().
6596ca35587Sdholland 	 */
6606ca35587Sdholland 	/*
6616ca35587Sdholland 	 * First, check to see if we need to wait for an update lock.
6626ca35587Sdholland 	 */
6636ca35587Sdholland 	igotlock = 0;
6646ca35587Sdholland 	NFSLOCKV4ROOTMUTEX();
6656ca35587Sdholland 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
6666ca35587Sdholland 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
6676ca35587Sdholland 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
6686ca35587Sdholland 	else
6696ca35587Sdholland 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
6706ca35587Sdholland 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
6716ca35587Sdholland 	NFSUNLOCKV4ROOTMUTEX();
6726ca35587Sdholland 	if (igotlock) {
6736ca35587Sdholland 		/*
6746ca35587Sdholland 		 * If I got the lock, I can update the stable storage file.
6756ca35587Sdholland 		 * Done when the grace period is over or a client has long
6766ca35587Sdholland 		 * since expired.
6776ca35587Sdholland 		 */
6786ca35587Sdholland 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
6796ca35587Sdholland 		if ((nfsrv_stablefirst.nsf_flags &
6806ca35587Sdholland 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
6816ca35587Sdholland 			nfsrv_updatestable(p);
6826ca35587Sdholland 
6836ca35587Sdholland 		/*
6846ca35587Sdholland 		 * If at least one client has long since expired, search
6856ca35587Sdholland 		 * the client list for them, write a REVOKE record on the
6866ca35587Sdholland 		 * stable storage file and then remove them from the client
6876ca35587Sdholland 		 * list.
6886ca35587Sdholland 		 */
6896ca35587Sdholland 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
6906ca35587Sdholland 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
691e81f0ea2Spgoyette 			for (i = 0; i < nfsrv_clienthashsize; i++) {
6926ca35587Sdholland 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
6936ca35587Sdholland 				nclp) {
6946ca35587Sdholland 				if (clp->lc_flags & LCL_EXPIREIT) {
6956ca35587Sdholland 				    if (!LIST_EMPTY(&clp->lc_open) ||
6966ca35587Sdholland 					!LIST_EMPTY(&clp->lc_deleg))
6976ca35587Sdholland 					nfsrv_writestable(clp->lc_id,
6986ca35587Sdholland 					    clp->lc_idlen, NFSNST_REVOKE, p);
6996ca35587Sdholland 				    nfsrv_cleanclient(clp, p);
7006ca35587Sdholland 				    nfsrv_freedeleglist(&clp->lc_deleg);
7016ca35587Sdholland 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
7026ca35587Sdholland 				    LIST_REMOVE(clp, lc_hash);
7036ca35587Sdholland 				    nfsrv_zapclient(clp, p);
7046ca35587Sdholland 				}
7056ca35587Sdholland 			    }
7066ca35587Sdholland 			}
7076ca35587Sdholland 		}
7086ca35587Sdholland 		NFSLOCKV4ROOTMUTEX();
7096ca35587Sdholland 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
7106ca35587Sdholland 		NFSUNLOCKV4ROOTMUTEX();
7116ca35587Sdholland 	} else {
7126ca35587Sdholland 		/*
7136ca35587Sdholland 		 * If we didn't get the lock, we need to get a refcnt,
7146ca35587Sdholland 		 * which also checks for and waits for the lock.
7156ca35587Sdholland 		 */
7166ca35587Sdholland 		NFSLOCKV4ROOTMUTEX();
7176ca35587Sdholland 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
7186ca35587Sdholland 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
7196ca35587Sdholland 		NFSUNLOCKV4ROOTMUTEX();
7206ca35587Sdholland 	}
7216ca35587Sdholland 
7226ca35587Sdholland 	/*
7236ca35587Sdholland 	 * If flagged, search for open owners that haven't had any opens
7246ca35587Sdholland 	 * for a long time.
7256ca35587Sdholland 	 */
7266ca35587Sdholland 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
7276ca35587Sdholland 		nfsrv_throwawayopens(p);
7286ca35587Sdholland 	}
7296ca35587Sdholland 
7306ca35587Sdholland 	savevp = vp = NULL;
7316ca35587Sdholland 	save_fsid.val[0] = save_fsid.val[1] = 0;
7326ca35587Sdholland 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
733e81f0ea2Spgoyette 
734e81f0ea2Spgoyette 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
7356ca35587Sdholland 	if (taglen < 0) {
7366ca35587Sdholland 		error = EBADRPC;
7376ca35587Sdholland 		goto nfsmout;
7386ca35587Sdholland 	}
739e81f0ea2Spgoyette 
7406ca35587Sdholland 	(void) nfsm_strtom(nd, tag, taglen);
7416ca35587Sdholland 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
742e81f0ea2Spgoyette 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
743e81f0ea2Spgoyette 	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
7446ca35587Sdholland 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
7456ca35587Sdholland 	if (nd->nd_repstat)
7466ca35587Sdholland 		numops = 0;
7476ca35587Sdholland 	else
7486ca35587Sdholland 		numops = fxdr_unsigned(int, *tl);
7496ca35587Sdholland 	/*
7506ca35587Sdholland 	 * Loop around doing the sub ops.
7516ca35587Sdholland 	 * vp - is an unlocked vnode pointer for the CFH
7526ca35587Sdholland 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
7536ca35587Sdholland 	 * (at some future date, it might turn out to be more appropriate
7546ca35587Sdholland 	 *  to keep the file handles instead of vnode pointers?)
7556ca35587Sdholland 	 * savevpnes and vpnes - are the export flags for the above.
7566ca35587Sdholland 	 */
7576ca35587Sdholland 	for (i = 0; i < numops; i++) {
7586ca35587Sdholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
7596ca35587Sdholland 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
7606ca35587Sdholland 		*repp = *tl;
7616ca35587Sdholland 		op = fxdr_unsigned(int, *tl);
762e81f0ea2Spgoyette 		NFSD_DEBUG(4, "op=%d\n", op);
763e81f0ea2Spgoyette 
764e81f0ea2Spgoyette 		binuptime(&start_time);
765e81f0ea2Spgoyette 		nfsrvd_statstart(op, &start_time);
766e81f0ea2Spgoyette 		statsinprog = 1;
767e81f0ea2Spgoyette 
768e81f0ea2Spgoyette 		if (op < NFSV4OP_ACCESS ||
769e81f0ea2Spgoyette 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
770e81f0ea2Spgoyette 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
7716ca35587Sdholland 			nd->nd_repstat = NFSERR_OPILLEGAL;
7726ca35587Sdholland 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
7736ca35587Sdholland 			*repp = nfsd_errmap(nd);
7746ca35587Sdholland 			retops++;
7756ca35587Sdholland 			break;
7766ca35587Sdholland 		} else {
7776ca35587Sdholland 			repp++;
7786ca35587Sdholland 		}
779e81f0ea2Spgoyette 		if (i == 0)
780e81f0ea2Spgoyette 			op0 = op;
781e81f0ea2Spgoyette 		if (i == numops - 1)
782e81f0ea2Spgoyette 			nd->nd_flag |= ND_LASTOP;
7836ca35587Sdholland 
7846ca35587Sdholland 		/*
7856ca35587Sdholland 		 * Check for a referral on the current FH and, if so, return
7866ca35587Sdholland 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
7876ca35587Sdholland 		 */
7886ca35587Sdholland 		if (vp != NULL && op != NFSV4OP_GETATTR &&
7896ca35587Sdholland 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
7906ca35587Sdholland 		    nfsrv_errmoved(op)) {
7916ca35587Sdholland 			nd->nd_repstat = NFSERR_MOVED;
7926ca35587Sdholland 			*repp = nfsd_errmap(nd);
7936ca35587Sdholland 			retops++;
7946ca35587Sdholland 			break;
7956ca35587Sdholland 		}
7966ca35587Sdholland 
797e81f0ea2Spgoyette 		/*
798e81f0ea2Spgoyette 		 * For NFSv4.1, check for a Sequence Operation being first
799e81f0ea2Spgoyette 		 * or one of the other allowed operations by itself.
800e81f0ea2Spgoyette 		 */
801e81f0ea2Spgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0) {
802e81f0ea2Spgoyette 			if (i != 0 && op == NFSV4OP_SEQUENCE)
803e81f0ea2Spgoyette 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
804e81f0ea2Spgoyette 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
805e81f0ea2Spgoyette 			    op != NFSV4OP_EXCHANGEID &&
806e81f0ea2Spgoyette 			    op != NFSV4OP_CREATESESSION &&
807e81f0ea2Spgoyette 			    op != NFSV4OP_BINDCONNTOSESS &&
808e81f0ea2Spgoyette 			    op != NFSV4OP_DESTROYCLIENTID &&
809e81f0ea2Spgoyette 			    op != NFSV4OP_DESTROYSESSION)
810e81f0ea2Spgoyette 				nd->nd_repstat = NFSERR_OPNOTINSESS;
811e81f0ea2Spgoyette 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
812e81f0ea2Spgoyette 				nd->nd_repstat = NFSERR_NOTONLYOP;
813e81f0ea2Spgoyette 			if (nd->nd_repstat != 0) {
814e81f0ea2Spgoyette 				*repp = nfsd_errmap(nd);
815e81f0ea2Spgoyette 				retops++;
816e81f0ea2Spgoyette 				break;
817e81f0ea2Spgoyette 			}
818e81f0ea2Spgoyette 		}
819e81f0ea2Spgoyette 
8206ca35587Sdholland 		nd->nd_procnum = op;
8216ca35587Sdholland 		/*
8226ca35587Sdholland 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
8236ca35587Sdholland 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
8246ca35587Sdholland 		 * really nasty for certain Op sequences, I'll play it safe
8256ca35587Sdholland 		 * and only return the error at the beginning.) The cache
8266ca35587Sdholland 		 * will still function over flood level, but uses lots of
8276ca35587Sdholland 		 * mbufs.)
8286ca35587Sdholland 		 * If nfsrv_mallocmget_limit() returns True, the system is near
8296ca35587Sdholland 		 * to its limit for memory that malloc()/mget() can allocate.
8306ca35587Sdholland 		 */
831e81f0ea2Spgoyette 		if (i == 0 && (nd->nd_rp == NULL ||
832e81f0ea2Spgoyette 		    nd->nd_rp->rc_refcnt == 0) &&
8336ca35587Sdholland 		    (nfsrv_mallocmget_limit() ||
8346ca35587Sdholland 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
835e81f0ea2Spgoyette 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
836e81f0ea2Spgoyette 				printf("nfsd server cache flooded, try "
837e81f0ea2Spgoyette 				    "increasing vfs.nfsd.tcphighwater\n");
8386ca35587Sdholland 			nd->nd_repstat = NFSERR_RESOURCE;
8396ca35587Sdholland 			*repp = nfsd_errmap(nd);
8406ca35587Sdholland 			if (op == NFSV4OP_SETATTR) {
8416ca35587Sdholland 				/*
8426ca35587Sdholland 				 * Setattr replies require a bitmap.
8436ca35587Sdholland 				 * even for errors like these.
8446ca35587Sdholland 				 */
8456ca35587Sdholland 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8466ca35587Sdholland 				*tl = 0;
8476ca35587Sdholland 			}
8486ca35587Sdholland 			retops++;
8496ca35587Sdholland 			break;
8506ca35587Sdholland 		}
8516ca35587Sdholland 		if (nfsv4_opflag[op].savereply)
8526ca35587Sdholland 			nd->nd_flag |= ND_SAVEREPLY;
8536ca35587Sdholland 		switch (op) {
8546ca35587Sdholland 		case NFSV4OP_PUTFH:
8556ca35587Sdholland 			error = nfsrv_mtofh(nd, &fh);
8566ca35587Sdholland 			if (error)
8576ca35587Sdholland 				goto nfsmout;
8586ca35587Sdholland 			if (!nd->nd_repstat)
8596ca35587Sdholland 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
8606ca35587Sdholland 				    NULL, 0, p);
8616ca35587Sdholland 			/* For now, allow this for non-export FHs */
8626ca35587Sdholland 			if (!nd->nd_repstat) {
8636ca35587Sdholland 				if (vp)
8646ca35587Sdholland 					vrele(vp);
8656ca35587Sdholland 				vp = nvp;
8666ca35587Sdholland 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
8676ca35587Sdholland 				NFSVOPUNLOCK(vp, 0);
8686ca35587Sdholland 				vpnes = nes;
8696ca35587Sdholland 			}
8706ca35587Sdholland 			break;
8716ca35587Sdholland 		case NFSV4OP_PUTPUBFH:
8726ca35587Sdholland 			if (nfs_pubfhset)
8736ca35587Sdholland 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
8746ca35587Sdholland 				&nes, NULL, 0, p);
8756ca35587Sdholland 			else
8766ca35587Sdholland 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
8776ca35587Sdholland 			if (!nd->nd_repstat) {
8786ca35587Sdholland 				if (vp)
8796ca35587Sdholland 					vrele(vp);
8806ca35587Sdholland 				vp = nvp;
8816ca35587Sdholland 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
8826ca35587Sdholland 				NFSVOPUNLOCK(vp, 0);
8836ca35587Sdholland 				vpnes = nes;
8846ca35587Sdholland 			}
8856ca35587Sdholland 			break;
8866ca35587Sdholland 		case NFSV4OP_PUTROOTFH:
8876ca35587Sdholland 			if (nfs_rootfhset) {
8886ca35587Sdholland 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
8896ca35587Sdholland 				    &nes, NULL, 0, p);
8906ca35587Sdholland 				if (!nd->nd_repstat) {
8916ca35587Sdholland 					if (vp)
8926ca35587Sdholland 						vrele(vp);
8936ca35587Sdholland 					vp = nvp;
8946ca35587Sdholland 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
8956ca35587Sdholland 					NFSVOPUNLOCK(vp, 0);
8966ca35587Sdholland 					vpnes = nes;
8976ca35587Sdholland 				}
8986ca35587Sdholland 			} else
8996ca35587Sdholland 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
9006ca35587Sdholland 			break;
9016ca35587Sdholland 		case NFSV4OP_SAVEFH:
9026ca35587Sdholland 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
9036ca35587Sdholland 				nd->nd_repstat = 0;
9046ca35587Sdholland 				/* If vp == savevp, a no-op */
9056ca35587Sdholland 				if (vp != savevp) {
9066ca35587Sdholland 					if (savevp)
9076ca35587Sdholland 						vrele(savevp);
9086ca35587Sdholland 					VREF(vp);
9096ca35587Sdholland 					savevp = vp;
9106ca35587Sdholland 					savevpnes = vpnes;
9116ca35587Sdholland 					save_fsid = cur_fsid;
9126ca35587Sdholland 				}
9136ca35587Sdholland 			} else {
9146ca35587Sdholland 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
9156ca35587Sdholland 			}
9166ca35587Sdholland 			break;
9176ca35587Sdholland 		case NFSV4OP_RESTOREFH:
9186ca35587Sdholland 			if (savevp) {
9196ca35587Sdholland 				nd->nd_repstat = 0;
9206ca35587Sdholland 				/* If vp == savevp, a no-op */
9216ca35587Sdholland 				if (vp != savevp) {
9226ca35587Sdholland 					VREF(savevp);
9236ca35587Sdholland 					vrele(vp);
9246ca35587Sdholland 					vp = savevp;
9256ca35587Sdholland 					vpnes = savevpnes;
9266ca35587Sdholland 					cur_fsid = save_fsid;
9276ca35587Sdholland 				}
9286ca35587Sdholland 			} else {
9296ca35587Sdholland 				nd->nd_repstat = NFSERR_RESTOREFH;
9306ca35587Sdholland 			}
9316ca35587Sdholland 			break;
9326ca35587Sdholland 		default:
9336ca35587Sdholland 		    /*
9346ca35587Sdholland 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
9356ca35587Sdholland 		     * non-exported directory if
9366ca35587Sdholland 		     * nfs_rootfhset. Do I need to allow any other Ops?
9376ca35587Sdholland 		     * (You can only have a non-exported vpnes if
9386ca35587Sdholland 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
9396ca35587Sdholland 		     * Allow AUTH_SYS to be used for file systems
9406ca35587Sdholland 		     * exported GSS only for certain Ops, to allow
9416ca35587Sdholland 		     * clients to do mounts more easily.
9426ca35587Sdholland 		     */
9436ca35587Sdholland 		    if (nfsv4_opflag[op].needscfh && vp) {
9446ca35587Sdholland 			if (!NFSVNO_EXPORTED(&vpnes) &&
9456ca35587Sdholland 			    op != NFSV4OP_LOOKUP &&
9466ca35587Sdholland 			    op != NFSV4OP_GETATTR &&
9476ca35587Sdholland 			    op != NFSV4OP_GETFH &&
9486ca35587Sdholland 			    op != NFSV4OP_ACCESS &&
9496ca35587Sdholland 			    op != NFSV4OP_READLINK &&
9506ca35587Sdholland 			    op != NFSV4OP_SECINFO)
9516ca35587Sdholland 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
9526ca35587Sdholland 			else if (nfsvno_testexp(nd, &vpnes) &&
9536ca35587Sdholland 			    op != NFSV4OP_LOOKUP &&
9546ca35587Sdholland 			    op != NFSV4OP_GETFH &&
9556ca35587Sdholland 			    op != NFSV4OP_GETATTR &&
9566ca35587Sdholland 			    op != NFSV4OP_SECINFO)
9576ca35587Sdholland 				nd->nd_repstat = NFSERR_WRONGSEC;
9586ca35587Sdholland 			if (nd->nd_repstat) {
9596ca35587Sdholland 				if (op == NFSV4OP_SETATTR) {
9606ca35587Sdholland 				    /*
9616ca35587Sdholland 				     * Setattr reply requires a bitmap
9626ca35587Sdholland 				     * even for errors like these.
9636ca35587Sdholland 				     */
9646ca35587Sdholland 				    NFSM_BUILD(tl, u_int32_t *,
9656ca35587Sdholland 					NFSX_UNSIGNED);
9666ca35587Sdholland 				    *tl = 0;
9676ca35587Sdholland 				}
9686ca35587Sdholland 				break;
9696ca35587Sdholland 			}
9706ca35587Sdholland 		    }
9716ca35587Sdholland 		    if (nfsv4_opflag[op].retfh == 1) {
9726ca35587Sdholland 			if (!vp) {
9736ca35587Sdholland 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
9746ca35587Sdholland 				break;
9756ca35587Sdholland 			}
9766ca35587Sdholland 			VREF(vp);
9776ca35587Sdholland 			if (nfsv4_opflag[op].modifyfs)
9786ca35587Sdholland 				vn_start_write(vp, &temp_mp, V_WAIT);
9796ca35587Sdholland 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
9806ca35587Sdholland 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
9816ca35587Sdholland 			if (!error && !nd->nd_repstat) {
9826ca35587Sdholland 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
9836ca35587Sdholland 				new_mp = nvp->v_mount;
9846ca35587Sdholland 				if (cur_fsid.val[0] !=
9856ca35587Sdholland 				    new_mp->mnt_stat.f_fsid.val[0] ||
9866ca35587Sdholland 				    cur_fsid.val[1] !=
9876ca35587Sdholland 				    new_mp->mnt_stat.f_fsid.val[1]) {
9886ca35587Sdholland 				    /* crossed a server mount point */
9896ca35587Sdholland 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
9906ca35587Sdholland 					nd->nd_nam, &nes, &credanon);
9916ca35587Sdholland 				    if (!nd->nd_repstat)
9926ca35587Sdholland 					nd->nd_repstat = nfsd_excred(nd,
9936ca35587Sdholland 					    &nes, credanon);
9946ca35587Sdholland 				    if (credanon != NULL)
9956ca35587Sdholland 					crfree(credanon);
9966ca35587Sdholland 				    if (!nd->nd_repstat) {
9976ca35587Sdholland 					vpnes = nes;
9986ca35587Sdholland 					cur_fsid = new_mp->mnt_stat.f_fsid;
9996ca35587Sdholland 				    }
10006ca35587Sdholland 				}
10016ca35587Sdholland 				/* Lookup ops return a locked vnode */
10026ca35587Sdholland 				NFSVOPUNLOCK(nvp, 0);
10036ca35587Sdholland 			    }
10046ca35587Sdholland 			    if (!nd->nd_repstat) {
10056ca35587Sdholland 				    vrele(vp);
10066ca35587Sdholland 				    vp = nvp;
10076ca35587Sdholland 			    } else
10086ca35587Sdholland 				    vrele(nvp);
10096ca35587Sdholland 			}
10106ca35587Sdholland 			if (nfsv4_opflag[op].modifyfs)
10116ca35587Sdholland 				vn_finished_write(temp_mp);
10126ca35587Sdholland 		    } else if (nfsv4_opflag[op].retfh == 2) {
10136ca35587Sdholland 			if (vp == NULL || savevp == NULL) {
10146ca35587Sdholland 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
10156ca35587Sdholland 				break;
10166ca35587Sdholland 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
10176ca35587Sdholland 			    cur_fsid.val[1] != save_fsid.val[1]) {
10186ca35587Sdholland 				nd->nd_repstat = NFSERR_XDEV;
10196ca35587Sdholland 				break;
10206ca35587Sdholland 			}
10216ca35587Sdholland 			if (nfsv4_opflag[op].modifyfs)
10226ca35587Sdholland 				vn_start_write(savevp, &temp_mp, V_WAIT);
10236ca35587Sdholland 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
10246ca35587Sdholland 				VREF(vp);
10256ca35587Sdholland 				VREF(savevp);
10266ca35587Sdholland 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
10276ca35587Sdholland 				    savevp, vp, p, &savevpnes, &vpnes);
10286ca35587Sdholland 			} else
10296ca35587Sdholland 				nd->nd_repstat = NFSERR_PERM;
10306ca35587Sdholland 			if (nfsv4_opflag[op].modifyfs)
10316ca35587Sdholland 				vn_finished_write(temp_mp);
10326ca35587Sdholland 		    } else {
10336ca35587Sdholland 			if (nfsv4_opflag[op].retfh != 0)
10346ca35587Sdholland 				panic("nfsrvd_compound");
10356ca35587Sdholland 			if (nfsv4_opflag[op].needscfh) {
10366ca35587Sdholland 				if (vp != NULL) {
1037e81f0ea2Spgoyette 					lktype = nfsv4_opflag[op].lktype;
1038e81f0ea2Spgoyette 					if (nfsv4_opflag[op].modifyfs) {
10396ca35587Sdholland 						vn_start_write(vp, &temp_mp,
10406ca35587Sdholland 						    V_WAIT);
1041e81f0ea2Spgoyette 						if (op == NFSV4OP_WRITE &&
1042e81f0ea2Spgoyette 						    MNT_SHARED_WRITES(temp_mp))
1043e81f0ea2Spgoyette 							lktype = LK_SHARED;
1044e81f0ea2Spgoyette 					}
1045e81f0ea2Spgoyette 					if (NFSVOPLOCK(vp, lktype) == 0)
10466ca35587Sdholland 						VREF(vp);
10476ca35587Sdholland 					else
10486ca35587Sdholland 						nd->nd_repstat = NFSERR_PERM;
10496ca35587Sdholland 				} else {
10506ca35587Sdholland 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
10516ca35587Sdholland 					if (op == NFSV4OP_SETATTR) {
10526ca35587Sdholland 						/*
10536ca35587Sdholland 						 * Setattr reply requires a
10546ca35587Sdholland 						 * bitmap even for errors like
10556ca35587Sdholland 						 * these.
10566ca35587Sdholland 						 */
10576ca35587Sdholland 						NFSM_BUILD(tl, u_int32_t *,
10586ca35587Sdholland 						    NFSX_UNSIGNED);
10596ca35587Sdholland 						*tl = 0;
10606ca35587Sdholland 					}
10616ca35587Sdholland 					break;
10626ca35587Sdholland 				}
10636ca35587Sdholland 				if (nd->nd_repstat == 0)
10646ca35587Sdholland 					error = (*(nfsrv4_ops0[op]))(nd,
10656ca35587Sdholland 					    isdgram, vp, p, &vpnes);
10666ca35587Sdholland 				if (nfsv4_opflag[op].modifyfs)
10676ca35587Sdholland 					vn_finished_write(temp_mp);
10686ca35587Sdholland 			} else {
10696ca35587Sdholland 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
10706ca35587Sdholland 				    NULL, p, &vpnes);
10716ca35587Sdholland 			}
10726ca35587Sdholland 		    }
1073e81f0ea2Spgoyette 		}
10746ca35587Sdholland 		if (error) {
10756ca35587Sdholland 			if (error == EBADRPC || error == NFSERR_BADXDR) {
10766ca35587Sdholland 				nd->nd_repstat = NFSERR_BADXDR;
10776ca35587Sdholland 			} else {
10786ca35587Sdholland 				nd->nd_repstat = error;
10796ca35587Sdholland 				printf("nfsv4 comperr0=%d\n", error);
10806ca35587Sdholland 			}
10816ca35587Sdholland 			error = 0;
10826ca35587Sdholland 		}
1083e81f0ea2Spgoyette 
1084e81f0ea2Spgoyette 		if (statsinprog != 0) {
1085e81f0ea2Spgoyette 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1086e81f0ea2Spgoyette 			    /*then*/ &start_time);
1087e81f0ea2Spgoyette 			statsinprog = 0;
1088e81f0ea2Spgoyette 		}
1089e81f0ea2Spgoyette 
10906ca35587Sdholland 		retops++;
10916ca35587Sdholland 		if (nd->nd_repstat) {
10926ca35587Sdholland 			*repp = nfsd_errmap(nd);
10936ca35587Sdholland 			break;
10946ca35587Sdholland 		} else {
10956ca35587Sdholland 			*repp = 0;	/* NFS4_OK */
10966ca35587Sdholland 		}
10976ca35587Sdholland 	}
10986ca35587Sdholland nfsmout:
1099e81f0ea2Spgoyette 	if (statsinprog != 0) {
1100e81f0ea2Spgoyette 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1101e81f0ea2Spgoyette 		    /*then*/ &start_time);
1102e81f0ea2Spgoyette 		statsinprog = 0;
1103e81f0ea2Spgoyette 	}
11046ca35587Sdholland 	if (error) {
11056ca35587Sdholland 		if (error == EBADRPC || error == NFSERR_BADXDR)
11066ca35587Sdholland 			nd->nd_repstat = NFSERR_BADXDR;
11076ca35587Sdholland 		else
11086ca35587Sdholland 			printf("nfsv4 comperr1=%d\n", error);
11096ca35587Sdholland 	}
11106ca35587Sdholland 	if (taglen == -1) {
11116ca35587Sdholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
11126ca35587Sdholland 		*tl++ = 0;
11136ca35587Sdholland 		*tl = 0;
11146ca35587Sdholland 	} else {
11156ca35587Sdholland 		*retopsp = txdr_unsigned(retops);
11166ca35587Sdholland 	}
11176ca35587Sdholland 	if (vp)
11186ca35587Sdholland 		vrele(vp);
11196ca35587Sdholland 	if (savevp)
11206ca35587Sdholland 		vrele(savevp);
11216ca35587Sdholland 	NFSLOCKV4ROOTMUTEX();
11226ca35587Sdholland 	nfsv4_relref(&nfsv4rootfs_lock);
11236ca35587Sdholland 	NFSUNLOCKV4ROOTMUTEX();
11246ca35587Sdholland 
11256ca35587Sdholland 	NFSEXITCODE2(0, nd);
11266ca35587Sdholland }
1127