xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 17891d00)
19ec7b004SRick Macklem /*-
29ec7b004SRick Macklem  * Copyright (c) 1989, 1993
39ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
49ec7b004SRick Macklem  *
59ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
69ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
79ec7b004SRick Macklem  *
89ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
99ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
109ec7b004SRick Macklem  * are met:
119ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
129ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
139ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
159ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
169ec7b004SRick Macklem  * 4. Neither the name of the University nor the names of its contributors
179ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
189ec7b004SRick Macklem  *    without specific prior written permission.
199ec7b004SRick Macklem  *
209ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
219ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
249ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309ec7b004SRick Macklem  * SUCH DAMAGE.
319ec7b004SRick Macklem  *
329ec7b004SRick Macklem  */
339ec7b004SRick Macklem 
349ec7b004SRick Macklem #include <sys/cdefs.h>
359ec7b004SRick Macklem __FBSDID("$FreeBSD$");
369ec7b004SRick Macklem 
379ec7b004SRick Macklem /*
389ec7b004SRick Macklem  * Socket operations for use by the nfs server.
399ec7b004SRick Macklem  */
409ec7b004SRick Macklem 
419ec7b004SRick Macklem #ifndef APPLEKEXT
429ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
439ec7b004SRick Macklem 
449ec7b004SRick Macklem extern struct nfsstats newnfsstats;
459ec7b004SRick Macklem extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
469ec7b004SRick Macklem extern int nfs_pubfhset, nfs_rootfhset;
479ec7b004SRick Macklem extern struct nfsv4lock nfsv4rootfs_lock;
489ec7b004SRick Macklem extern struct nfsrv_stablefirst nfsrv_stablefirst;
499ec7b004SRick Macklem extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
509ec7b004SRick Macklem extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
519ec7b004SRick Macklem NFSV4ROOTLOCKMUTEX;
529ec7b004SRick Macklem NFSSTATESPINLOCK;
539ec7b004SRick Macklem vnode_t nfsv4root_vp = NULL;
549ec7b004SRick Macklem int nfsv4root_set = 0;
559ec7b004SRick Macklem 
569ec7b004SRick Macklem int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
579ec7b004SRick Macklem     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
589ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
599ec7b004SRick Macklem 	nfsrvd_getattr,
609ec7b004SRick Macklem 	nfsrvd_setattr,
619ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
629ec7b004SRick Macklem 	nfsrvd_access,
639ec7b004SRick Macklem 	nfsrvd_readlink,
649ec7b004SRick Macklem 	nfsrvd_read,
659ec7b004SRick Macklem 	nfsrvd_write,
669ec7b004SRick Macklem 	nfsrvd_create,
679ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
689ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
699ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
709ec7b004SRick Macklem 	nfsrvd_remove,
719ec7b004SRick Macklem 	nfsrvd_remove,
729ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
739ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
749ec7b004SRick Macklem 	nfsrvd_readdir,
759ec7b004SRick Macklem 	nfsrvd_readdirplus,
769ec7b004SRick Macklem 	nfsrvd_statfs,
779ec7b004SRick Macklem 	nfsrvd_fsinfo,
789ec7b004SRick Macklem 	nfsrvd_pathconf,
799ec7b004SRick Macklem 	nfsrvd_commit,
809ec7b004SRick Macklem };
819ec7b004SRick Macklem 
829ec7b004SRick Macklem int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
839ec7b004SRick Macklem     int, vnode_t , vnode_t *, fhandle_t *,
849ec7b004SRick Macklem     NFSPROC_T *, struct nfsexstuff *) = {
859ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
869ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
879ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
889ec7b004SRick Macklem 	nfsrvd_lookup,
899ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
909ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
919ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
929ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
939ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
949ec7b004SRick Macklem 	nfsrvd_mkdir,
959ec7b004SRick Macklem 	nfsrvd_symlink,
969ec7b004SRick Macklem 	nfsrvd_mknod,
979ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
989ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
999ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1009ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1019ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1029ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1039ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1049ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1059ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1069ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1079ec7b004SRick Macklem };
1089ec7b004SRick Macklem 
1099ec7b004SRick Macklem int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
1109ec7b004SRick Macklem     int, vnode_t , vnode_t , NFSPROC_T *,
1119ec7b004SRick Macklem     struct nfsexstuff *, struct nfsexstuff *) = {
1129ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1139ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1149ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1159ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1169ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1179ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1189ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1199ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1209ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1219ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1229ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1239ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1249ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1259ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1269ec7b004SRick Macklem 	nfsrvd_rename,
1279ec7b004SRick Macklem 	nfsrvd_link,
1289ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1299ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1309ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1319ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1329ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1339ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1349ec7b004SRick Macklem };
1359ec7b004SRick Macklem 
1369ec7b004SRick Macklem int (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *,
1379ec7b004SRick Macklem     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
1389ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1399ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1409ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1419ec7b004SRick Macklem 	nfsrvd_access,
1429ec7b004SRick Macklem 	nfsrvd_close,
1439ec7b004SRick Macklem 	nfsrvd_commit,
1449ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1459ec7b004SRick Macklem 	nfsrvd_delegpurge,
1469ec7b004SRick Macklem 	nfsrvd_delegreturn,
1479ec7b004SRick Macklem 	nfsrvd_getattr,
1489ec7b004SRick Macklem 	nfsrvd_getfh,
1499ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1509ec7b004SRick Macklem 	nfsrvd_lock,
1519ec7b004SRick Macklem 	nfsrvd_lockt,
1529ec7b004SRick Macklem 	nfsrvd_locku,
1539ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1549ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1559ec7b004SRick Macklem 	nfsrvd_verify,
1569ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1579ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1589ec7b004SRick Macklem 	nfsrvd_openconfirm,
1599ec7b004SRick Macklem 	nfsrvd_opendowngrade,
1609ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1619ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1629ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1639ec7b004SRick Macklem 	nfsrvd_read,
1649ec7b004SRick Macklem 	nfsrvd_readdirplus,
1659ec7b004SRick Macklem 	nfsrvd_readlink,
1669ec7b004SRick Macklem 	nfsrvd_remove,
1679ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1689ec7b004SRick Macklem 	nfsrvd_renew,
1699ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1709ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1719ec7b004SRick Macklem 	nfsrvd_secinfo,
1729ec7b004SRick Macklem 	nfsrvd_setattr,
1739ec7b004SRick Macklem 	nfsrvd_setclientid,
1749ec7b004SRick Macklem 	nfsrvd_setclientidcfrm,
1759ec7b004SRick Macklem 	nfsrvd_verify,
1769ec7b004SRick Macklem 	nfsrvd_write,
1779ec7b004SRick Macklem 	nfsrvd_releaselckown,
1789ec7b004SRick Macklem };
1799ec7b004SRick Macklem 
1809ec7b004SRick Macklem int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
1819ec7b004SRick Macklem     int, vnode_t , vnode_t *, fhandle_t *,
1829ec7b004SRick Macklem     NFSPROC_T *, struct nfsexstuff *) = {
1839ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1849ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1859ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1869ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1879ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1889ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1899ec7b004SRick Macklem 	nfsrvd_mknod,
1909ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1919ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1929ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1939ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1949ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1959ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1969ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1979ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1989ec7b004SRick Macklem 	nfsrvd_lookup,
1999ec7b004SRick Macklem 	nfsrvd_lookup,
2009ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2019ec7b004SRick Macklem 	nfsrvd_open,
2029ec7b004SRick Macklem 	nfsrvd_openattr,
2039ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2049ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2059ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2069ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2079ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2089ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2099ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2109ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2119ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2129ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2139ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2149ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2159ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2169ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2179ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2189ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2199ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2209ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2219ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2229ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2239ec7b004SRick Macklem };
2249ec7b004SRick Macklem 
2259ec7b004SRick Macklem int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
2269ec7b004SRick Macklem     int, vnode_t , vnode_t , NFSPROC_T *,
2279ec7b004SRick Macklem     struct nfsexstuff *, struct nfsexstuff *) = {
2289ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2299ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2309ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2319ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2329ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2339ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2349ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2359ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2369ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2379ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2389ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2399ec7b004SRick Macklem 	nfsrvd_link,
2409ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2419ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2429ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2439ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2449ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2459ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2469ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2479ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2489ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2499ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2509ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2519ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2529ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2539ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2549ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2559ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2569ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2579ec7b004SRick Macklem 	nfsrvd_rename,
2589ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2599ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2609ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2619ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2629ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2639ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2649ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2659ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2669ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2679ec7b004SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2689ec7b004SRick Macklem };
2699ec7b004SRick Macklem #endif	/* !APPLEKEXT */
2709ec7b004SRick Macklem 
2719ec7b004SRick Macklem /*
2729ec7b004SRick Macklem  * Static array that defines which nfs rpc's are nonidempotent
2739ec7b004SRick Macklem  */
2749ec7b004SRick Macklem static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
2759ec7b004SRick Macklem 	FALSE,
2769ec7b004SRick Macklem 	FALSE,
2779ec7b004SRick Macklem 	TRUE,
2789ec7b004SRick Macklem 	FALSE,
2799ec7b004SRick Macklem 	FALSE,
2809ec7b004SRick Macklem 	FALSE,
2819ec7b004SRick Macklem 	FALSE,
2829ec7b004SRick Macklem 	TRUE,
2839ec7b004SRick Macklem 	TRUE,
2849ec7b004SRick Macklem 	TRUE,
2859ec7b004SRick Macklem 	TRUE,
2869ec7b004SRick Macklem 	TRUE,
2879ec7b004SRick Macklem 	TRUE,
2889ec7b004SRick Macklem 	TRUE,
2899ec7b004SRick Macklem 	TRUE,
2909ec7b004SRick Macklem 	TRUE,
2919ec7b004SRick Macklem 	FALSE,
2929ec7b004SRick Macklem 	FALSE,
2939ec7b004SRick Macklem 	FALSE,
2949ec7b004SRick Macklem 	FALSE,
2959ec7b004SRick Macklem 	FALSE,
2969ec7b004SRick Macklem 	FALSE,
2979ec7b004SRick Macklem };
2989ec7b004SRick Macklem 
2999ec7b004SRick Macklem /*
3009ec7b004SRick Macklem  * This static array indicates whether or not the RPC modifies the
3019ec7b004SRick Macklem  * file system.
3029ec7b004SRick Macklem  */
3039ec7b004SRick Macklem static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
3049ec7b004SRick Macklem     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
3059ec7b004SRick Macklem     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
3069ec7b004SRick Macklem 
3079ec7b004SRick Macklem /* local functions */
3089ec7b004SRick Macklem static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
3099ec7b004SRick Macklem     NFSPROC_T *p);
3109ec7b004SRick Macklem 
3119ec7b004SRick Macklem 
3129ec7b004SRick Macklem /*
3139ec7b004SRick Macklem  * This static array indicates which server procedures require the extra
3149ec7b004SRick Macklem  * arguments to return the current file handle for V2, 3.
3159ec7b004SRick Macklem  */
3169ec7b004SRick Macklem static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
3179ec7b004SRick Macklem 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
3189ec7b004SRick Macklem 
3199ec7b004SRick Macklem extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
3209ec7b004SRick Macklem 
3219ec7b004SRick Macklem static int nfsv3to4op[NFS_V3NPROCS] = {
3229ec7b004SRick Macklem 	NFSPROC_NULL,
3239ec7b004SRick Macklem 	NFSV4OP_GETATTR,
3249ec7b004SRick Macklem 	NFSV4OP_SETATTR,
3259ec7b004SRick Macklem 	NFSV4OP_LOOKUP,
3269ec7b004SRick Macklem 	NFSV4OP_ACCESS,
3279ec7b004SRick Macklem 	NFSV4OP_READLINK,
3289ec7b004SRick Macklem 	NFSV4OP_READ,
3299ec7b004SRick Macklem 	NFSV4OP_WRITE,
3309ec7b004SRick Macklem 	NFSV4OP_V3CREATE,
3319ec7b004SRick Macklem 	NFSV4OP_MKDIR,
3329ec7b004SRick Macklem 	NFSV4OP_SYMLINK,
3339ec7b004SRick Macklem 	NFSV4OP_MKNOD,
3349ec7b004SRick Macklem 	NFSV4OP_REMOVE,
3359ec7b004SRick Macklem 	NFSV4OP_RMDIR,
3369ec7b004SRick Macklem 	NFSV4OP_RENAME,
3379ec7b004SRick Macklem 	NFSV4OP_LINK,
3389ec7b004SRick Macklem 	NFSV4OP_READDIR,
3399ec7b004SRick Macklem 	NFSV4OP_READDIRPLUS,
3409ec7b004SRick Macklem 	NFSV4OP_FSSTAT,
3419ec7b004SRick Macklem 	NFSV4OP_FSINFO,
3429ec7b004SRick Macklem 	NFSV4OP_PATHCONF,
3439ec7b004SRick Macklem 	NFSV4OP_COMMIT,
3449ec7b004SRick Macklem };
3459ec7b004SRick Macklem 
3469ec7b004SRick Macklem /*
3479ec7b004SRick Macklem  * Do an RPC. Basically, get the file handles translated to vnode pointers
3489ec7b004SRick Macklem  * and then call the appropriate server routine. The server routines are
3499ec7b004SRick Macklem  * split into groups, based on whether they use a file handle or file
3509ec7b004SRick Macklem  * handle plus name or ...
3519ec7b004SRick Macklem  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
3529ec7b004SRick Macklem  */
3539ec7b004SRick Macklem APPLESTATIC void
3549ec7b004SRick Macklem nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
3559ec7b004SRick Macklem     NFSPROC_T *p)
3569ec7b004SRick Macklem {
35717891d00SRick Macklem 	int error = 0, lktype;
3589ec7b004SRick Macklem 	vnode_t vp;
3599ec7b004SRick Macklem 	mount_t mp = NULL;
3609ec7b004SRick Macklem 	struct nfsrvfh fh;
3619ec7b004SRick Macklem 	struct nfsexstuff nes;
3629ec7b004SRick Macklem 
3639ec7b004SRick Macklem 	/*
3649ec7b004SRick Macklem 	 * Get a locked vnode for the first file handle
3659ec7b004SRick Macklem 	 */
3669ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4)) {
367b38f7723SKonstantin Belousov 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
3689ec7b004SRick Macklem 		/*
3699ec7b004SRick Macklem 		 * For NFSv3, if the malloc/mget allocation is near limits,
3709ec7b004SRick Macklem 		 * return NFSERR_DELAY.
3719ec7b004SRick Macklem 		 */
3729ec7b004SRick Macklem 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
3739ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_DELAY;
3749ec7b004SRick Macklem 			vp = NULL;
3759ec7b004SRick Macklem 		} else {
3769ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &fh);
3779ec7b004SRick Macklem 			if (error) {
3789ec7b004SRick Macklem 				if (error != EBADRPC)
3799ec7b004SRick Macklem 					printf("nfs dorpc err1=%d\n", error);
3809ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_GARBAGE;
3819ec7b004SRick Macklem 				return;
3829ec7b004SRick Macklem 			}
38317891d00SRick Macklem 			if (nd->nd_procnum == NFSPROC_READ ||
38417891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_READDIR ||
38517891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_READLINK ||
38617891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_GETATTR ||
38717891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_ACCESS)
38817891d00SRick Macklem 				lktype = LK_SHARED;
38917891d00SRick Macklem 			else
39017891d00SRick Macklem 				lktype = LK_EXCLUSIVE;
3919ec7b004SRick Macklem 			nes.nes_vfslocked = 0;
3929ec7b004SRick Macklem 			if (nd->nd_flag & ND_PUBLOOKUP)
39317891d00SRick Macklem 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
3949ec7b004SRick Macklem 				    &mp, nfs_writerpc[nd->nd_procnum], p);
3959ec7b004SRick Macklem 			else
39617891d00SRick Macklem 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
3979ec7b004SRick Macklem 				    &mp, nfs_writerpc[nd->nd_procnum], p);
3989ec7b004SRick Macklem 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
3999ec7b004SRick Macklem 				return;
4009ec7b004SRick Macklem 		}
4019ec7b004SRick Macklem 	}
4029ec7b004SRick Macklem 
4039ec7b004SRick Macklem 	/*
4049ec7b004SRick Macklem 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
4059ec7b004SRick Macklem 	 * cache, as required.
4069ec7b004SRick Macklem 	 * For V4, nfsrvd_compound() does this.
4079ec7b004SRick Macklem 	 */
4089ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
4099ec7b004SRick Macklem 		nd->nd_flag |= ND_SAVEREPLY;
4109ec7b004SRick Macklem 
4119ec7b004SRick Macklem 	nfsrvd_rephead(nd);
4129ec7b004SRick Macklem 	/*
4139ec7b004SRick Macklem 	 * If nd_repstat is non-zero, just fill in the reply status
4149ec7b004SRick Macklem 	 * to complete the RPC reply for V2. Otherwise, you must do
4159ec7b004SRick Macklem 	 * the RPC.
4169ec7b004SRick Macklem 	 */
4179ec7b004SRick Macklem 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
4189ec7b004SRick Macklem 		*nd->nd_errp = nfsd_errmap(nd);
4199ec7b004SRick Macklem 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
4209ec7b004SRick Macklem 		if (mp != NULL) {
4219ec7b004SRick Macklem 			if (nfs_writerpc[nd->nd_procnum])
4229ec7b004SRick Macklem 				NFS_ENDWRITE(mp);
4239ec7b004SRick Macklem 			if (nes.nes_vfslocked)
4249ec7b004SRick Macklem 				nfsvno_unlockvfs(mp);
4259ec7b004SRick Macklem 		}
4269ec7b004SRick Macklem 		return;
4279ec7b004SRick Macklem 	}
4289ec7b004SRick Macklem 
4299ec7b004SRick Macklem 	/*
4309ec7b004SRick Macklem 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
4319ec7b004SRick Macklem 	 * works through the sub-rpcs, otherwise just call the procedure.
4329ec7b004SRick Macklem 	 * The procedures are in three groups with different arguments.
4339ec7b004SRick Macklem 	 * The group is indicated by the value in nfs_retfh[].
4349ec7b004SRick Macklem 	 */
4359ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
4369ec7b004SRick Macklem 		nfsrvd_compound(nd, isdgram, p);
4379ec7b004SRick Macklem 	} else {
4389ec7b004SRick Macklem 		if (nfs_retfh[nd->nd_procnum] == 1) {
4399ec7b004SRick Macklem 			if (vp)
4409ec7b004SRick Macklem 				NFSVOPUNLOCK(vp, 0, p);
4419ec7b004SRick Macklem 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
4429ec7b004SRick Macklem 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
4439ec7b004SRick Macklem 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
4449ec7b004SRick Macklem 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
4459ec7b004SRick Macklem 			    vp, NULL, p, &nes, NULL);
4469ec7b004SRick Macklem 		} else {
4479ec7b004SRick Macklem 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
4489ec7b004SRick Macklem 			    vp, p, &nes);
4499ec7b004SRick Macklem 		}
4509ec7b004SRick Macklem 		if (mp) {
4519ec7b004SRick Macklem 			if (nfs_writerpc[nd->nd_procnum])
4529ec7b004SRick Macklem 				NFS_ENDWRITE(mp);
4539ec7b004SRick Macklem 			if (nes.nes_vfslocked)
4549ec7b004SRick Macklem 				nfsvno_unlockvfs(mp);
4559ec7b004SRick Macklem 		}
4569ec7b004SRick Macklem 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
4579ec7b004SRick Macklem 	}
4589ec7b004SRick Macklem 	if (error) {
4599ec7b004SRick Macklem 		if (error != EBADRPC)
4609ec7b004SRick Macklem 			printf("nfs dorpc err2=%d\n", error);
4619ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_GARBAGE;
4629ec7b004SRick Macklem 	}
4639ec7b004SRick Macklem 	*nd->nd_errp = nfsd_errmap(nd);
4649ec7b004SRick Macklem 
4659ec7b004SRick Macklem 	/*
4669ec7b004SRick Macklem 	 * Don't cache certain reply status values.
4679ec7b004SRick Macklem 	 */
4689ec7b004SRick Macklem 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
4699ec7b004SRick Macklem 	    (nd->nd_repstat == NFSERR_GARBAGE ||
4709ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_BADXDR ||
4719ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_MOVED ||
4729ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_DELAY ||
4739ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_BADSEQID ||
4749ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_RESOURCE ||
4759ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
4769ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
4779ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_STALESTATEID ||
4789ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
4799ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_BADSTATEID ||
4809ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_GRACE ||
4819ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_NOGRACE))
4829ec7b004SRick Macklem 		nd->nd_flag &= ~ND_SAVEREPLY;
4839ec7b004SRick Macklem }
4849ec7b004SRick Macklem 
4859ec7b004SRick Macklem /*
4869ec7b004SRick Macklem  * Breaks down a compound RPC request and calls the server routines for
4879ec7b004SRick Macklem  * the subprocedures.
4889ec7b004SRick Macklem  * Some suboperations are performed directly here to simplify file handle<-->
4899ec7b004SRick Macklem  * vnode pointer handling.
4909ec7b004SRick Macklem  */
4919ec7b004SRick Macklem static void
4929ec7b004SRick Macklem nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
4939ec7b004SRick Macklem     NFSPROC_T *p)
4949ec7b004SRick Macklem {
4959ec7b004SRick Macklem 	int i, op;
4969ec7b004SRick Macklem 	u_int32_t *tl;
4979ec7b004SRick Macklem 	struct nfsclient *clp, *nclp;
4989ec7b004SRick Macklem 	int numops, taglen = -1, error = 0, igotlock;
4999ec7b004SRick Macklem 	u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp;
5009ec7b004SRick Macklem 	u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
5019ec7b004SRick Macklem 	vnode_t vp, nvp, savevp;
5029ec7b004SRick Macklem 	struct nfsrvfh fh;
5039ec7b004SRick Macklem 	mount_t mp, savemp;
5049ec7b004SRick Macklem 	struct ucred *credanon;
5059ec7b004SRick Macklem 	struct nfsexstuff nes, vpnes, savevpnes;
5069ec7b004SRick Macklem 	static u_int64_t compref = 0;
5079ec7b004SRick Macklem 
5089ec7b004SRick Macklem 	NFSVNO_EXINIT(&vpnes);
5099ec7b004SRick Macklem 	NFSVNO_EXINIT(&savevpnes);
5109ec7b004SRick Macklem 	/*
5119ec7b004SRick Macklem 	 * Put the seq# of the current compound RPC in nfsrv_descript.
5129ec7b004SRick Macklem 	 * (This is used by nfsrv_checkgetattr(), to see if the write
5139ec7b004SRick Macklem 	 *  delegation was created by the same compound RPC as the one
5149ec7b004SRick Macklem 	 *  with that Getattr in it.)
5159ec7b004SRick Macklem 	 * Don't worry about the 64bit number wrapping around. It ain't
5169ec7b004SRick Macklem 	 * gonna happen before this server gets shut down/rebooted.
5179ec7b004SRick Macklem 	 */
5189ec7b004SRick Macklem 	nd->nd_compref = compref++;
5199ec7b004SRick Macklem 
5209ec7b004SRick Macklem 	/*
5219ec7b004SRick Macklem 	 * Check for and optionally get a lock on the root. This lock means that
5229ec7b004SRick Macklem 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
5239ec7b004SRick Macklem 	 * is required when the V4 root is being changed, the stable storage
5249ec7b004SRick Macklem 	 * restart file is being updated, or callbacks are being done.
5259ec7b004SRick Macklem 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
5269ec7b004SRick Macklem 	 * either hold a reference count (nfs_usecnt) or the lock. When
5279ec7b004SRick Macklem 	 * nfsrv_unlock() is called to release the lock, it can optionally
5289ec7b004SRick Macklem 	 * also get a reference count, which saves the need for a call to
5299ec7b004SRick Macklem 	 * nfsrv_getref() after nfsrv_unlock().
5309ec7b004SRick Macklem 	 */
5319ec7b004SRick Macklem 	/*
5329ec7b004SRick Macklem 	 * First, check to see if we need to wait for an update lock.
5339ec7b004SRick Macklem 	 */
5349ec7b004SRick Macklem 	igotlock = 0;
5359ec7b004SRick Macklem 	NFSLOCKV4ROOTMUTEX();
5369ec7b004SRick Macklem 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
5379ec7b004SRick Macklem 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
5389ec7b004SRick Macklem 		    NFSV4ROOTLOCKMUTEXPTR);
5399ec7b004SRick Macklem 	else
5409ec7b004SRick Macklem 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
5419ec7b004SRick Macklem 		    NFSV4ROOTLOCKMUTEXPTR);
5429ec7b004SRick Macklem 	NFSUNLOCKV4ROOTMUTEX();
5439ec7b004SRick Macklem 	if (igotlock) {
5449ec7b004SRick Macklem 		/*
5459ec7b004SRick Macklem 		 * If I got the lock, I can update the stable storage file.
5469ec7b004SRick Macklem 		 * Done when the grace period is over or a client has long
5479ec7b004SRick Macklem 		 * since expired.
5489ec7b004SRick Macklem 		 */
5499ec7b004SRick Macklem 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
5509ec7b004SRick Macklem 		if ((nfsrv_stablefirst.nsf_flags &
5519ec7b004SRick Macklem 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
5529ec7b004SRick Macklem 			nfsrv_updatestable(p);
5539ec7b004SRick Macklem 
5549ec7b004SRick Macklem 		/*
5559ec7b004SRick Macklem 		 * If at least one client has long since expired, search
5569ec7b004SRick Macklem 		 * the client list for them, write a REVOKE record on the
5579ec7b004SRick Macklem 		 * stable storage file and then remove them from the client
5589ec7b004SRick Macklem 		 * list.
5599ec7b004SRick Macklem 		 */
5609ec7b004SRick Macklem 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
5619ec7b004SRick Macklem 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
5629ec7b004SRick Macklem 			for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
5639ec7b004SRick Macklem 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
5649ec7b004SRick Macklem 				nclp) {
5659ec7b004SRick Macklem 				if (clp->lc_flags & LCL_EXPIREIT) {
5669ec7b004SRick Macklem 				    if (!LIST_EMPTY(&clp->lc_open) ||
5679ec7b004SRick Macklem 					!LIST_EMPTY(&clp->lc_deleg))
5689ec7b004SRick Macklem 					nfsrv_writestable(clp->lc_id,
5699ec7b004SRick Macklem 					    clp->lc_idlen, NFSNST_REVOKE, p);
5709ec7b004SRick Macklem 				    nfsrv_cleanclient(clp, p);
5719ec7b004SRick Macklem 				    nfsrv_freedeleglist(&clp->lc_deleg);
5729ec7b004SRick Macklem 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
5739ec7b004SRick Macklem 				    LIST_REMOVE(clp, lc_hash);
5749ec7b004SRick Macklem 				    nfsrv_zapclient(clp, p);
5759ec7b004SRick Macklem 				}
5769ec7b004SRick Macklem 			    }
5779ec7b004SRick Macklem 			}
5789ec7b004SRick Macklem 		}
5799ec7b004SRick Macklem 		NFSLOCKV4ROOTMUTEX();
5809ec7b004SRick Macklem 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
5819ec7b004SRick Macklem 		NFSUNLOCKV4ROOTMUTEX();
5829ec7b004SRick Macklem 	} else {
5839ec7b004SRick Macklem 		/*
5849ec7b004SRick Macklem 		 * If we didn't get the lock, we need to get a refcnt,
5859ec7b004SRick Macklem 		 * which also checks for and waits for the lock.
5869ec7b004SRick Macklem 		 */
5879ec7b004SRick Macklem 		NFSLOCKV4ROOTMUTEX();
5889ec7b004SRick Macklem 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
5899ec7b004SRick Macklem 		    NFSV4ROOTLOCKMUTEXPTR);
5909ec7b004SRick Macklem 		NFSUNLOCKV4ROOTMUTEX();
5919ec7b004SRick Macklem 	}
5929ec7b004SRick Macklem 
5939ec7b004SRick Macklem 	/*
5949ec7b004SRick Macklem 	 * If flagged, search for open owners that haven't had any opens
5959ec7b004SRick Macklem 	 * for a long time.
5969ec7b004SRick Macklem 	 */
5979ec7b004SRick Macklem 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
5989ec7b004SRick Macklem 		nfsrv_throwawayopens(p);
5999ec7b004SRick Macklem 	}
6009ec7b004SRick Macklem 
6019ec7b004SRick Macklem 	savevp = vp = NULL;
6029ec7b004SRick Macklem 	savevpnes.nes_vfslocked = vpnes.nes_vfslocked = 0;
6039ec7b004SRick Macklem 	savemp = mp = NULL;
6049ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
6059ec7b004SRick Macklem 	taglen = fxdr_unsigned(int, *tl);
6069ec7b004SRick Macklem 	if (taglen < 0) {
6079ec7b004SRick Macklem 		error = EBADRPC;
6089ec7b004SRick Macklem 		goto nfsmout;
6099ec7b004SRick Macklem 	}
6109ec7b004SRick Macklem 	if (taglen <= NFSV4_SMALLSTR)
6119ec7b004SRick Macklem 		tagstr = tag;
6129ec7b004SRick Macklem 	else
6139ec7b004SRick Macklem 		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
6149ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, tagstr, taglen);
6159ec7b004SRick Macklem 	if (error) {
6169ec7b004SRick Macklem 		if (taglen > NFSV4_SMALLSTR)
6179ec7b004SRick Macklem 			free(tagstr, M_TEMP);
6189ec7b004SRick Macklem 		taglen = -1;
6199ec7b004SRick Macklem 		goto nfsmout;
6209ec7b004SRick Macklem 	}
6219ec7b004SRick Macklem 	(void) nfsm_strtom(nd, tag, taglen);
6229ec7b004SRick Macklem 	if (taglen > NFSV4_SMALLSTR) {
6239ec7b004SRick Macklem 		free(tagstr, M_TEMP);
6249ec7b004SRick Macklem 	}
6259ec7b004SRick Macklem 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
6269ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6279ec7b004SRick Macklem 	minorvers = fxdr_unsigned(u_int32_t, *tl++);
6289ec7b004SRick Macklem 	if (minorvers != NFSV4_MINORVERSION)
6299ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
6309ec7b004SRick Macklem 	if (nd->nd_repstat)
6319ec7b004SRick Macklem 		numops = 0;
6329ec7b004SRick Macklem 	else
6339ec7b004SRick Macklem 		numops = fxdr_unsigned(int, *tl);
6349ec7b004SRick Macklem 	/*
6359ec7b004SRick Macklem 	 * Loop around doing the sub ops.
6369ec7b004SRick Macklem 	 * vp - is an unlocked vnode pointer for the CFH
6379ec7b004SRick Macklem 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
6389ec7b004SRick Macklem 	 * (at some future date, it might turn out to be more appropriate
6399ec7b004SRick Macklem 	 *  to keep the file handles instead of vnode pointers?)
6409ec7b004SRick Macklem 	 * savevpnes and vpnes - are the export flags for the above.
6419ec7b004SRick Macklem 	 */
6429ec7b004SRick Macklem 	for (i = 0; i < numops; i++) {
6439ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
6449ec7b004SRick Macklem 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
6459183a2a3SRick Macklem 		*repp = *tl;
6469ec7b004SRick Macklem 		op = fxdr_unsigned(int, *tl);
6479ec7b004SRick Macklem 		if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
6489ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_OPILLEGAL;
6499183a2a3SRick Macklem 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
6509ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
6519ec7b004SRick Macklem 			retops++;
6529ec7b004SRick Macklem 			break;
6539183a2a3SRick Macklem 		} else {
6549183a2a3SRick Macklem 			repp++;
6559ec7b004SRick Macklem 		}
6569ec7b004SRick Macklem 
6579ec7b004SRick Macklem 		/*
6589ec7b004SRick Macklem 		 * Check for a referral on the current FH and, if so, return
6599ec7b004SRick Macklem 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
6609ec7b004SRick Macklem 		 */
6619ec7b004SRick Macklem 		if (vp != NULL && op != NFSV4OP_GETATTR &&
6629ec7b004SRick Macklem 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
6639ec7b004SRick Macklem 		    nfsrv_errmoved(op)) {
6649ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_MOVED;
6659ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
6669ec7b004SRick Macklem 			retops++;
6679ec7b004SRick Macklem 			break;
6689ec7b004SRick Macklem 		}
6699ec7b004SRick Macklem 
6709ec7b004SRick Macklem 		nd->nd_procnum = op;
6719ec7b004SRick Macklem 		/*
6729ec7b004SRick Macklem 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
6739ec7b004SRick Macklem 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
6749ec7b004SRick Macklem 		 * really nasty for certain Op sequences, I'll play it safe
6759ec7b004SRick Macklem 		 * and only return the error at the beginning.) The cache
6769ec7b004SRick Macklem 		 * will still function over flood level, but uses lots of
6779ec7b004SRick Macklem 		 * mbufs.)
6789ec7b004SRick Macklem 		 * If nfsrv_mallocmget_limit() returns True, the system is near
6799ec7b004SRick Macklem 		 * to its limit for memory that malloc()/mget() can allocate.
6809ec7b004SRick Macklem 		 */
6819ec7b004SRick Macklem 		if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
6829ec7b004SRick Macklem 		    (nfsrv_mallocmget_limit() ||
6839ec7b004SRick Macklem 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
6849ec7b004SRick Macklem 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
6859ec7b004SRick Macklem 				printf("nfsd server cache flooded, try to");
6869ec7b004SRick Macklem 				printf(" increase nfsrc_floodlevel\n");
6879ec7b004SRick Macklem 			}
6889ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_RESOURCE;
6899ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
6909ec7b004SRick Macklem 			if (op == NFSV4OP_SETATTR) {
6919ec7b004SRick Macklem 				/*
6929ec7b004SRick Macklem 				 * Setattr replies require a bitmap.
6939ec7b004SRick Macklem 				 * even for errors like these.
6949ec7b004SRick Macklem 				 */
6959ec7b004SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6969ec7b004SRick Macklem 				*tl = 0;
6979ec7b004SRick Macklem 			}
6989ec7b004SRick Macklem 			retops++;
6999ec7b004SRick Macklem 			break;
7009ec7b004SRick Macklem 		}
7019ec7b004SRick Macklem 		if (nfsv4_opflag[op].savereply)
7029ec7b004SRick Macklem 			nd->nd_flag |= ND_SAVEREPLY;
7039ec7b004SRick Macklem 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
7049ec7b004SRick Macklem 		switch (op) {
7059ec7b004SRick Macklem 		case NFSV4OP_PUTFH:
7069ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &fh);
7079ec7b004SRick Macklem 			if (error)
7089ec7b004SRick Macklem 				goto nfsmout;
7099ec7b004SRick Macklem 			if (!nd->nd_repstat) {
7109ec7b004SRick Macklem 				nes.nes_vfslocked = vpnes.nes_vfslocked;
71117891d00SRick Macklem 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes, &mp,
7129ec7b004SRick Macklem 				    0, p);
7139ec7b004SRick Macklem 			}
7149ec7b004SRick Macklem 			/* For now, allow this for non-export FHs */
7159ec7b004SRick Macklem 			if (!nd->nd_repstat) {
7169ec7b004SRick Macklem 				if (vp)
7179ec7b004SRick Macklem 					vrele(vp);
7189ec7b004SRick Macklem 				vp = nvp;
7199ec7b004SRick Macklem 				NFSVOPUNLOCK(vp, 0, p);
7209ec7b004SRick Macklem 				vpnes = nes;
7219ec7b004SRick Macklem 			}
7229ec7b004SRick Macklem 			break;
7239ec7b004SRick Macklem 		case NFSV4OP_PUTPUBFH:
7249ec7b004SRick Macklem 			if (nfs_pubfhset) {
7259ec7b004SRick Macklem 			    nes.nes_vfslocked = vpnes.nes_vfslocked;
72617891d00SRick Macklem 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
7279ec7b004SRick Macklem 				&nes, &mp, 0, p);
7289ec7b004SRick Macklem 			} else {
7299ec7b004SRick Macklem 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
7309ec7b004SRick Macklem 			}
7319ec7b004SRick Macklem 			if (!nd->nd_repstat) {
7329ec7b004SRick Macklem 				if (vp)
7339ec7b004SRick Macklem 					vrele(vp);
7349ec7b004SRick Macklem 				vp = nvp;
7359ec7b004SRick Macklem 				NFSVOPUNLOCK(vp, 0, p);
7369ec7b004SRick Macklem 				vpnes = nes;
7379ec7b004SRick Macklem 			}
7389ec7b004SRick Macklem 			break;
7399ec7b004SRick Macklem 		case NFSV4OP_PUTROOTFH:
7409ec7b004SRick Macklem 			if (nfs_rootfhset) {
7419ec7b004SRick Macklem 				nes.nes_vfslocked = vpnes.nes_vfslocked;
74217891d00SRick Macklem 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
7439ec7b004SRick Macklem 				    &nes, &mp, 0, p);
7449ec7b004SRick Macklem 				if (!nd->nd_repstat) {
7459ec7b004SRick Macklem 					if (vp)
7469ec7b004SRick Macklem 						vrele(vp);
7479ec7b004SRick Macklem 					vp = nvp;
7489ec7b004SRick Macklem 					NFSVOPUNLOCK(vp, 0, p);
7499ec7b004SRick Macklem 					vpnes = nes;
7509ec7b004SRick Macklem 				}
7519ec7b004SRick Macklem 			} else if (nfsv4root_vp && nfsv4root_set) {
7529ec7b004SRick Macklem 				if (vp) {
7539ec7b004SRick Macklem 					if (vpnes.nes_vfslocked)
7549ec7b004SRick Macklem 						nfsvno_unlockvfs(mp);
7559ec7b004SRick Macklem 					vrele(vp);
7569ec7b004SRick Macklem 				}
7579ec7b004SRick Macklem 				vp = nfsv4root_vp;
7589ec7b004SRick Macklem 				VREF(vp);
7599ec7b004SRick Macklem 				NFSVNO_SETEXRDONLY(&vpnes);
7609ec7b004SRick Macklem 				vpnes.nes_vfslocked = 0;
7619ec7b004SRick Macklem 				mp = vnode_mount(vp);
7629ec7b004SRick Macklem 			} else {
7639ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
7649ec7b004SRick Macklem 			}
7659ec7b004SRick Macklem 			break;
7669ec7b004SRick Macklem 		case NFSV4OP_SAVEFH:
7679ec7b004SRick Macklem 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
7689ec7b004SRick Macklem 				nd->nd_repstat = 0;
7699ec7b004SRick Macklem 				/* If vp == savevp, a no-op */
7709ec7b004SRick Macklem 				if (vp != savevp) {
7719ec7b004SRick Macklem 					if (savevp)
7729ec7b004SRick Macklem 						vrele(savevp);
7739ec7b004SRick Macklem 					VREF(vp);
7749ec7b004SRick Macklem 					savevp = vp;
7759ec7b004SRick Macklem 					savevpnes = vpnes;
7769ec7b004SRick Macklem 					savemp = mp;
7779ec7b004SRick Macklem 				}
7789ec7b004SRick Macklem 			} else {
7799ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
7809ec7b004SRick Macklem 			}
7819ec7b004SRick Macklem 			break;
7829ec7b004SRick Macklem 		case NFSV4OP_RESTOREFH:
7839ec7b004SRick Macklem 			if (savevp) {
7849ec7b004SRick Macklem 				nd->nd_repstat = 0;
7859ec7b004SRick Macklem 				/* If vp == savevp, a no-op */
7869ec7b004SRick Macklem 				if (vp != savevp) {
7879ec7b004SRick Macklem 					VREF(savevp);
7889ec7b004SRick Macklem 					if (mp == NULL || savemp == NULL)
7899ec7b004SRick Macklem 						panic("nfscmpmp");
7909ec7b004SRick Macklem 					if (!savevpnes.nes_vfslocked &&
7919ec7b004SRick Macklem 					    vpnes.nes_vfslocked) {
7929ec7b004SRick Macklem 						if (mp == savemp)
7939ec7b004SRick Macklem 							panic("nfscmp2");
7949ec7b004SRick Macklem 						nfsvno_unlockvfs(mp);
7959ec7b004SRick Macklem 					} else if (savevpnes.nes_vfslocked &&
7969ec7b004SRick Macklem 					    !vpnes.nes_vfslocked) {
7979ec7b004SRick Macklem 						if (mp == savemp)
7989ec7b004SRick Macklem 							panic("nfscmp3");
7999ec7b004SRick Macklem 						savevpnes.nes_vfslocked = nfsvno_lockvfs(savemp);
8009ec7b004SRick Macklem 					}
8019ec7b004SRick Macklem 					vrele(vp);
8029ec7b004SRick Macklem 					vp = savevp;
8039ec7b004SRick Macklem 					vpnes = savevpnes;
8049ec7b004SRick Macklem 					mp = savemp;
8059ec7b004SRick Macklem 				}
8069ec7b004SRick Macklem 			} else {
8079ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_RESTOREFH;
8089ec7b004SRick Macklem 			}
8099ec7b004SRick Macklem 			break;
8109ec7b004SRick Macklem 		default:
8119ec7b004SRick Macklem 		    /*
8129ec7b004SRick Macklem 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
8139ec7b004SRick Macklem 		     * non-exported directory if
8149ec7b004SRick Macklem 		     * nfs_rootfhset. Do I need to allow any other Ops?
8159ec7b004SRick Macklem 		     * (You can only have a non-exported vpnes if
8169ec7b004SRick Macklem 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
8179ec7b004SRick Macklem 		     * Allow AUTH_SYS to be used for file systems
8189ec7b004SRick Macklem 		     * exported GSS only for certain Ops, to allow
8199ec7b004SRick Macklem 		     * clients to do mounts more easily.
8209ec7b004SRick Macklem 		     */
8219ec7b004SRick Macklem 		    if (nfsv4_opflag[op].needscfh && vp) {
8229ec7b004SRick Macklem 			if (!NFSVNO_EXPORTED(&vpnes) &&
8239ec7b004SRick Macklem 			    op != NFSV4OP_LOOKUP &&
8249ec7b004SRick Macklem 			    op != NFSV4OP_GETATTR &&
8259ec7b004SRick Macklem 			    op != NFSV4OP_GETFH &&
8269ec7b004SRick Macklem 			    op != NFSV4OP_SECINFO)
8279ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
82898ad4453SRick Macklem 			else if (nfsvno_testexp(nd, &vpnes) &&
8299ec7b004SRick Macklem 			    op != NFSV4OP_LOOKUP &&
8309ec7b004SRick Macklem 			    op != NFSV4OP_GETFH &&
8319ec7b004SRick Macklem 			    op != NFSV4OP_GETATTR &&
8329ec7b004SRick Macklem 			    op != NFSV4OP_SECINFO)
8339ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_WRONGSEC;
8349ec7b004SRick Macklem 			if (nd->nd_repstat) {
8359ec7b004SRick Macklem 				if (op == NFSV4OP_SETATTR) {
8369ec7b004SRick Macklem 				    /*
8379ec7b004SRick Macklem 				     * Setattr reply requires a bitmap
8389ec7b004SRick Macklem 				     * even for errors like these.
8399ec7b004SRick Macklem 				     */
8409ec7b004SRick Macklem 				    NFSM_BUILD(tl, u_int32_t *,
8419ec7b004SRick Macklem 					NFSX_UNSIGNED);
8429ec7b004SRick Macklem 				    *tl = 0;
8439ec7b004SRick Macklem 				}
8449ec7b004SRick Macklem 				break;
8459ec7b004SRick Macklem 			}
8469ec7b004SRick Macklem 		    }
8479ec7b004SRick Macklem 		    if (nfsv4_opflag[op].retfh == 1) {
8489ec7b004SRick Macklem 			if (!vp) {
8499ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
8509ec7b004SRick Macklem 				break;
8519ec7b004SRick Macklem 			}
8529ec7b004SRick Macklem 			VREF(vp);
8539ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
8549ec7b004SRick Macklem 				NFS_STARTWRITE(NULL, &mp);
8559ec7b004SRick Macklem 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
8569ec7b004SRick Macklem 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
8579ec7b004SRick Macklem 			if (!error && !nd->nd_repstat) {
8589ec7b004SRick Macklem 			    if (vfs_statfs(mp)->f_fsid.val[0] !=
8599ec7b004SRick Macklem 				vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ||
8609ec7b004SRick Macklem 				vfs_statfs(mp)->f_fsid.val[1] !=
8619ec7b004SRick Macklem 				vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) {
8629ec7b004SRick Macklem 				if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ==
8639ec7b004SRick Macklem 				    NFSV4ROOT_FSID0 &&
8649ec7b004SRick Macklem 				    vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] ==
8659ec7b004SRick Macklem 				    NFSV4ROOT_FSID1) {
8669ec7b004SRick Macklem 				    if (vpnes.nes_vfslocked) {
8679ec7b004SRick Macklem 					nfsvno_unlockvfs(mp);
8689ec7b004SRick Macklem 					vpnes.nes_vfslocked = 0;
8699ec7b004SRick Macklem 				    }
8709ec7b004SRick Macklem 				    NFSVNO_SETEXRDONLY(&vpnes);
8719ec7b004SRick Macklem 				    mp = vnode_mount(nvp);
8729ec7b004SRick Macklem 				} else {
8739ec7b004SRick Macklem 				    nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp),
8749ec7b004SRick Macklem 					nd->nd_nam, &nes, &credanon);
8759ec7b004SRick Macklem 				    if (!nd->nd_repstat)
8769ec7b004SRick Macklem 					nd->nd_repstat = nfsd_excred(nd,
8779ec7b004SRick Macklem 					    &nes, credanon);
8785679fe19SAlexander Kabaev 				    if (credanon != NULL)
8795679fe19SAlexander Kabaev 					crfree(credanon);
8809ec7b004SRick Macklem 				    if (!nd->nd_repstat) {
8819ec7b004SRick Macklem 					if (vpnes.nes_vfslocked)
8829ec7b004SRick Macklem 					    nfsvno_unlockvfs(mp);
8839ec7b004SRick Macklem 					mp = vnode_mount(nvp);
8849ec7b004SRick Macklem 					vpnes = nes;
8859ec7b004SRick Macklem 					vpnes.nes_vfslocked =
8869ec7b004SRick Macklem 					    nfsvno_lockvfs(mp);
8879ec7b004SRick Macklem 				    }
8889ec7b004SRick Macklem 				}
8899ec7b004SRick Macklem 			    }
8909ec7b004SRick Macklem 			    if (!nd->nd_repstat) {
8919ec7b004SRick Macklem 				    vrele(vp);
8929ec7b004SRick Macklem 				    vp = nvp;
8939ec7b004SRick Macklem 			    }
8949ec7b004SRick Macklem 			}
8959ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
8969ec7b004SRick Macklem 				NFS_ENDWRITE(mp);
8979ec7b004SRick Macklem 		    } else if (nfsv4_opflag[op].retfh == 2) {
8989ec7b004SRick Macklem 			if (vp == NULL || savevp == NULL) {
8999ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
9009ec7b004SRick Macklem 				break;
9019ec7b004SRick Macklem 			} else if (mp != savemp) {
9029ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_XDEV;
9039ec7b004SRick Macklem 				break;
9049ec7b004SRick Macklem 			}
9059ec7b004SRick Macklem 			VREF(vp);
9069ec7b004SRick Macklem 			VREF(savevp);
9079ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
9089ec7b004SRick Macklem 				NFS_STARTWRITE(NULL, &mp);
9099ec7b004SRick Macklem 			NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
9109ec7b004SRick Macklem 			error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
9119ec7b004SRick Macklem 			    vp, p, &savevpnes, &vpnes);
9129ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
9139ec7b004SRick Macklem 				NFS_ENDWRITE(mp);
9149ec7b004SRick Macklem 		    } else {
9159ec7b004SRick Macklem 			if (nfsv4_opflag[op].retfh != 0)
9169ec7b004SRick Macklem 				panic("nfsrvd_compound");
9179ec7b004SRick Macklem 			if (nfsv4_opflag[op].needscfh) {
91817891d00SRick Macklem 				if (vp != NULL) {
91917891d00SRick Macklem 					if (vn_lock(vp, nfsv4_opflag[op].lktype)
92017891d00SRick Macklem 					    != 0)
92117891d00SRick Macklem 						nd->nd_repstat = NFSERR_PERM;
92217891d00SRick Macklem 				} else
9239ec7b004SRick Macklem 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
92417891d00SRick Macklem 				if (nd->nd_repstat != 0) {
9259ec7b004SRick Macklem 					if (op == NFSV4OP_SETATTR) {
9269ec7b004SRick Macklem 						/*
92717891d00SRick Macklem 						 * Setattr reply requires a
92817891d00SRick Macklem 						 * bitmap even for errors like
92917891d00SRick Macklem 						 * these.
9309ec7b004SRick Macklem 						 */
9319ec7b004SRick Macklem 						NFSM_BUILD(tl, u_int32_t *,
9329ec7b004SRick Macklem 						    NFSX_UNSIGNED);
9339ec7b004SRick Macklem 						*tl = 0;
9349ec7b004SRick Macklem 					}
9359ec7b004SRick Macklem 					break;
9369ec7b004SRick Macklem 				}
93717891d00SRick Macklem 				VREF(vp);
93817891d00SRick Macklem 				if (nfsv4_opflag[op].modifyfs)
93917891d00SRick Macklem 					NFS_STARTWRITE(NULL, &mp);
9409ec7b004SRick Macklem 				error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
9419ec7b004SRick Macklem 				    p, &vpnes);
9429ec7b004SRick Macklem 				if (nfsv4_opflag[op].modifyfs)
9439ec7b004SRick Macklem 					NFS_ENDWRITE(mp);
9449ec7b004SRick Macklem 			} else {
9459ec7b004SRick Macklem 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
9469ec7b004SRick Macklem 				    NULL, p, &vpnes);
9479ec7b004SRick Macklem 			}
9489ec7b004SRick Macklem 		    }
9499ec7b004SRick Macklem 		};
9509ec7b004SRick Macklem 		if (error) {
9519ec7b004SRick Macklem 			if (error == EBADRPC || error == NFSERR_BADXDR) {
9529ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_BADXDR;
9539ec7b004SRick Macklem 			} else {
9549ec7b004SRick Macklem 				nd->nd_repstat = error;
9559ec7b004SRick Macklem 				printf("nfsv4 comperr0=%d\n", error);
9569ec7b004SRick Macklem 			}
9579ec7b004SRick Macklem 			error = 0;
9589ec7b004SRick Macklem 		}
9599ec7b004SRick Macklem 		retops++;
9609ec7b004SRick Macklem 		if (nd->nd_repstat) {
9619ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
9629ec7b004SRick Macklem 			break;
9639ec7b004SRick Macklem 		} else {
9649ec7b004SRick Macklem 			*repp = 0;	/* NFS4_OK */
9659ec7b004SRick Macklem 		}
9669ec7b004SRick Macklem 	}
9679ec7b004SRick Macklem nfsmout:
9689ec7b004SRick Macklem 	if (error) {
9699ec7b004SRick Macklem 		if (error == EBADRPC || error == NFSERR_BADXDR)
9709ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
9719ec7b004SRick Macklem 		else
9729ec7b004SRick Macklem 			printf("nfsv4 comperr1=%d\n", error);
9739ec7b004SRick Macklem 	}
9749ec7b004SRick Macklem 	if (taglen == -1) {
9759ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
9769ec7b004SRick Macklem 		*tl++ = 0;
9779ec7b004SRick Macklem 		*tl = 0;
9789ec7b004SRick Macklem 	} else {
9799ec7b004SRick Macklem 		*retopsp = txdr_unsigned(retops);
9809ec7b004SRick Macklem 	}
9819ec7b004SRick Macklem 	if (mp && vpnes.nes_vfslocked)
9829ec7b004SRick Macklem 		nfsvno_unlockvfs(mp);
9839ec7b004SRick Macklem 	if (vp)
9849ec7b004SRick Macklem 		vrele(vp);
9859ec7b004SRick Macklem 	if (savevp)
9869ec7b004SRick Macklem 		vrele(savevp);
9879ec7b004SRick Macklem 	NFSLOCKV4ROOTMUTEX();
9889ec7b004SRick Macklem 	nfsv4_relref(&nfsv4rootfs_lock);
9899ec7b004SRick Macklem 	NFSUNLOCKV4ROOTMUTEX();
9909ec7b004SRick Macklem }
991