1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 1989, 1993
3191783Srmacklem *	The Regents of the University of California.  All rights reserved.
4191783Srmacklem *
5191783Srmacklem * This code is derived from software contributed to Berkeley by
6191783Srmacklem * Rick Macklem at The University of Guelph.
7191783Srmacklem *
8191783Srmacklem * Redistribution and use in source and binary forms, with or without
9191783Srmacklem * modification, are permitted provided that the following conditions
10191783Srmacklem * are met:
11191783Srmacklem * 1. Redistributions of source code must retain the above copyright
12191783Srmacklem *    notice, this list of conditions and the following disclaimer.
13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
14191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
15191783Srmacklem *    documentation and/or other materials provided with the distribution.
16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors
17191783Srmacklem *    may be used to endorse or promote products derived from this software
18191783Srmacklem *    without specific prior written permission.
19191783Srmacklem *
20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23191783Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30191783Srmacklem * SUCH DAMAGE.
31191783Srmacklem *
32191783Srmacklem */
33191783Srmacklem
34191783Srmacklem#include <sys/cdefs.h>
35191783Srmacklem__FBSDID("$FreeBSD$");
36191783Srmacklem
37191783Srmacklem/*
38191783Srmacklem * Socket operations for use by the nfs server.
39191783Srmacklem */
40191783Srmacklem
41191783Srmacklem#ifndef APPLEKEXT
42191783Srmacklem#include <fs/nfs/nfsport.h>
43191783Srmacklem
44191783Srmacklemextern struct nfsstats newnfsstats;
45191783Srmacklemextern struct nfsrvfh nfs_pubfh, nfs_rootfh;
46191783Srmacklemextern int nfs_pubfhset, nfs_rootfhset;
47191783Srmacklemextern struct nfsv4lock nfsv4rootfs_lock;
48191783Srmacklemextern struct nfsrv_stablefirst nfsrv_stablefirst;
49191783Srmacklemextern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
50191783Srmacklemextern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
51191783SrmacklemNFSV4ROOTLOCKMUTEX;
52191783SrmacklemNFSSTATESPINLOCK;
53191783Srmacklem
54191783Srmacklemint (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
55191783Srmacklem    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
56191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
57191783Srmacklem	nfsrvd_getattr,
58191783Srmacklem	nfsrvd_setattr,
59191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
60191783Srmacklem	nfsrvd_access,
61191783Srmacklem	nfsrvd_readlink,
62191783Srmacklem	nfsrvd_read,
63191783Srmacklem	nfsrvd_write,
64191783Srmacklem	nfsrvd_create,
65191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
66191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
67191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
68191783Srmacklem	nfsrvd_remove,
69191783Srmacklem	nfsrvd_remove,
70191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
71191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
72191783Srmacklem	nfsrvd_readdir,
73191783Srmacklem	nfsrvd_readdirplus,
74191783Srmacklem	nfsrvd_statfs,
75191783Srmacklem	nfsrvd_fsinfo,
76191783Srmacklem	nfsrvd_pathconf,
77191783Srmacklem	nfsrvd_commit,
78191783Srmacklem};
79191783Srmacklem
80191783Srmacklemint (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
81191783Srmacklem    int, vnode_t , vnode_t *, fhandle_t *,
82191783Srmacklem    NFSPROC_T *, struct nfsexstuff *) = {
83191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
84191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
85191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
86191783Srmacklem	nfsrvd_lookup,
87191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
88191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
89191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
90191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
91191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
92191783Srmacklem	nfsrvd_mkdir,
93191783Srmacklem	nfsrvd_symlink,
94191783Srmacklem	nfsrvd_mknod,
95191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
96191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
97191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
98191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
99191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
100191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
101191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
102191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
103191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
104191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
105191783Srmacklem};
106191783Srmacklem
107191783Srmacklemint (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
108191783Srmacklem    int, vnode_t , vnode_t , NFSPROC_T *,
109191783Srmacklem    struct nfsexstuff *, struct nfsexstuff *) = {
110191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
111191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
112191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
113191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
114191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
115191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
116191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
117191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
118191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
119191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
120191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
121191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
122191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
123191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
124191783Srmacklem	nfsrvd_rename,
125191783Srmacklem	nfsrvd_link,
126191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
127191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
128191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
129191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
130191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
131191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
132191783Srmacklem};
133191783Srmacklem
134191783Srmacklemint (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *,
135191783Srmacklem    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
136191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
137191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
138191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
139191783Srmacklem	nfsrvd_access,
140191783Srmacklem	nfsrvd_close,
141191783Srmacklem	nfsrvd_commit,
142191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
143191783Srmacklem	nfsrvd_delegpurge,
144191783Srmacklem	nfsrvd_delegreturn,
145191783Srmacklem	nfsrvd_getattr,
146191783Srmacklem	nfsrvd_getfh,
147191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
148191783Srmacklem	nfsrvd_lock,
149191783Srmacklem	nfsrvd_lockt,
150191783Srmacklem	nfsrvd_locku,
151191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
152191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
153191783Srmacklem	nfsrvd_verify,
154191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
155191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
156191783Srmacklem	nfsrvd_openconfirm,
157191783Srmacklem	nfsrvd_opendowngrade,
158191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
159191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
160191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
161191783Srmacklem	nfsrvd_read,
162191783Srmacklem	nfsrvd_readdirplus,
163191783Srmacklem	nfsrvd_readlink,
164191783Srmacklem	nfsrvd_remove,
165191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
166191783Srmacklem	nfsrvd_renew,
167191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
168191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
169191783Srmacklem	nfsrvd_secinfo,
170191783Srmacklem	nfsrvd_setattr,
171191783Srmacklem	nfsrvd_setclientid,
172191783Srmacklem	nfsrvd_setclientidcfrm,
173191783Srmacklem	nfsrvd_verify,
174191783Srmacklem	nfsrvd_write,
175191783Srmacklem	nfsrvd_releaselckown,
176191783Srmacklem};
177191783Srmacklem
178191783Srmacklemint (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
179191783Srmacklem    int, vnode_t , vnode_t *, fhandle_t *,
180191783Srmacklem    NFSPROC_T *, struct nfsexstuff *) = {
181191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
182191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
183191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
184191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
185191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
186191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
187191783Srmacklem	nfsrvd_mknod,
188191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
189191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
190191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
191191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
192191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
193191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
194191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
195191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
196191783Srmacklem	nfsrvd_lookup,
197191783Srmacklem	nfsrvd_lookup,
198191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
199191783Srmacklem	nfsrvd_open,
200191783Srmacklem	nfsrvd_openattr,
201191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
202191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
203191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
204191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
205191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
206191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
207191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
208191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
209191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
210191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
211191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
212191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
213191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
214191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
215191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
216191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
217191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
218191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
219191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
220191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
221191783Srmacklem};
222191783Srmacklem
223191783Srmacklemint (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
224191783Srmacklem    int, vnode_t , vnode_t , NFSPROC_T *,
225191783Srmacklem    struct nfsexstuff *, struct nfsexstuff *) = {
226191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
227191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
228191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
229191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
230191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
231191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
232191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
233191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
234191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
235191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
236191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
237191783Srmacklem	nfsrvd_link,
238191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
239191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
240191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
241191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
242191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
243191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
244191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
245191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
246191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
247191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
248191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
249191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
250191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
251191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
252191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
253191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
254191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
255191783Srmacklem	nfsrvd_rename,
256191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
257191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
258191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
259191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
260191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
261191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
262191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
263191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
264191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
265191783Srmacklem	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
266191783Srmacklem};
267191783Srmacklem#endif	/* !APPLEKEXT */
268191783Srmacklem
269191783Srmacklem/*
270191783Srmacklem * Static array that defines which nfs rpc's are nonidempotent
271191783Srmacklem */
272191783Srmacklemstatic int nfsrv_nonidempotent[NFS_V3NPROCS] = {
273191783Srmacklem	FALSE,
274191783Srmacklem	FALSE,
275191783Srmacklem	TRUE,
276191783Srmacklem	FALSE,
277191783Srmacklem	FALSE,
278191783Srmacklem	FALSE,
279191783Srmacklem	FALSE,
280191783Srmacklem	TRUE,
281191783Srmacklem	TRUE,
282191783Srmacklem	TRUE,
283191783Srmacklem	TRUE,
284191783Srmacklem	TRUE,
285191783Srmacklem	TRUE,
286191783Srmacklem	TRUE,
287191783Srmacklem	TRUE,
288191783Srmacklem	TRUE,
289191783Srmacklem	FALSE,
290191783Srmacklem	FALSE,
291191783Srmacklem	FALSE,
292191783Srmacklem	FALSE,
293191783Srmacklem	FALSE,
294191783Srmacklem	FALSE,
295191783Srmacklem};
296191783Srmacklem
297191783Srmacklem/*
298191783Srmacklem * This static array indicates whether or not the RPC modifies the
299191783Srmacklem * file system.
300191783Srmacklem */
301191783Srmacklemstatic int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
302191783Srmacklem    1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
303191783Srmacklem    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
304191783Srmacklem
305191783Srmacklem/* local functions */
306191783Srmacklemstatic void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
307191783Srmacklem    NFSPROC_T *p);
308191783Srmacklem
309191783Srmacklem
310191783Srmacklem/*
311191783Srmacklem * This static array indicates which server procedures require the extra
312191783Srmacklem * arguments to return the current file handle for V2, 3.
313191783Srmacklem */
314191783Srmacklemstatic int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
315191783Srmacklem	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
316191783Srmacklem
317191783Srmacklemextern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
318191783Srmacklem
319191783Srmacklemstatic int nfsv3to4op[NFS_V3NPROCS] = {
320191783Srmacklem	NFSPROC_NULL,
321191783Srmacklem	NFSV4OP_GETATTR,
322191783Srmacklem	NFSV4OP_SETATTR,
323191783Srmacklem	NFSV4OP_LOOKUP,
324191783Srmacklem	NFSV4OP_ACCESS,
325191783Srmacklem	NFSV4OP_READLINK,
326191783Srmacklem	NFSV4OP_READ,
327191783Srmacklem	NFSV4OP_WRITE,
328191783Srmacklem	NFSV4OP_V3CREATE,
329191783Srmacklem	NFSV4OP_MKDIR,
330191783Srmacklem	NFSV4OP_SYMLINK,
331191783Srmacklem	NFSV4OP_MKNOD,
332191783Srmacklem	NFSV4OP_REMOVE,
333191783Srmacklem	NFSV4OP_RMDIR,
334191783Srmacklem	NFSV4OP_RENAME,
335191783Srmacklem	NFSV4OP_LINK,
336191783Srmacklem	NFSV4OP_READDIR,
337191783Srmacklem	NFSV4OP_READDIRPLUS,
338191783Srmacklem	NFSV4OP_FSSTAT,
339191783Srmacklem	NFSV4OP_FSINFO,
340191783Srmacklem	NFSV4OP_PATHCONF,
341191783Srmacklem	NFSV4OP_COMMIT,
342191783Srmacklem};
343191783Srmacklem
344191783Srmacklem/*
345191783Srmacklem * Do an RPC. Basically, get the file handles translated to vnode pointers
346191783Srmacklem * and then call the appropriate server routine. The server routines are
347191783Srmacklem * split into groups, based on whether they use a file handle or file
348191783Srmacklem * handle plus name or ...
349191783Srmacklem * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
350191783Srmacklem */
351191783SrmacklemAPPLESTATIC void
352191783Srmacklemnfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
353191783Srmacklem    NFSPROC_T *p)
354191783Srmacklem{
355216700Srmacklem	int error = 0, lktype;
356191783Srmacklem	vnode_t vp;
357191783Srmacklem	mount_t mp = NULL;
358191783Srmacklem	struct nfsrvfh fh;
359191783Srmacklem	struct nfsexstuff nes;
360191783Srmacklem
361191783Srmacklem	/*
362191783Srmacklem	 * Get a locked vnode for the first file handle
363191783Srmacklem	 */
364191783Srmacklem	if (!(nd->nd_flag & ND_NFSV4)) {
365209120Skib		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
366191783Srmacklem		/*
367191783Srmacklem		 * For NFSv3, if the malloc/mget allocation is near limits,
368191783Srmacklem		 * return NFSERR_DELAY.
369191783Srmacklem		 */
370191783Srmacklem		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
371191783Srmacklem			nd->nd_repstat = NFSERR_DELAY;
372191783Srmacklem			vp = NULL;
373191783Srmacklem		} else {
374191783Srmacklem			error = nfsrv_mtofh(nd, &fh);
375191783Srmacklem			if (error) {
376191783Srmacklem				if (error != EBADRPC)
377191783Srmacklem					printf("nfs dorpc err1=%d\n", error);
378191783Srmacklem				nd->nd_repstat = NFSERR_GARBAGE;
379224086Szack				goto out;
380191783Srmacklem			}
381216700Srmacklem			if (nd->nd_procnum == NFSPROC_READ ||
382249592Sken			    nd->nd_procnum == NFSPROC_WRITE ||
383216700Srmacklem			    nd->nd_procnum == NFSPROC_READDIR ||
384216700Srmacklem			    nd->nd_procnum == NFSPROC_READLINK ||
385216700Srmacklem			    nd->nd_procnum == NFSPROC_GETATTR ||
386216700Srmacklem			    nd->nd_procnum == NFSPROC_ACCESS)
387216700Srmacklem				lktype = LK_SHARED;
388216700Srmacklem			else
389216700Srmacklem				lktype = LK_EXCLUSIVE;
390191783Srmacklem			if (nd->nd_flag & ND_PUBLOOKUP)
391216700Srmacklem				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
392191783Srmacklem				    &mp, nfs_writerpc[nd->nd_procnum], p);
393191783Srmacklem			else
394216700Srmacklem				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
395191783Srmacklem				    &mp, nfs_writerpc[nd->nd_procnum], p);
396191783Srmacklem			if (nd->nd_repstat == NFSERR_PROGNOTV4)
397224086Szack				goto out;
398191783Srmacklem		}
399191783Srmacklem	}
400191783Srmacklem
401191783Srmacklem	/*
402191783Srmacklem	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
403191783Srmacklem	 * cache, as required.
404191783Srmacklem	 * For V4, nfsrvd_compound() does this.
405191783Srmacklem	 */
406191783Srmacklem	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
407191783Srmacklem		nd->nd_flag |= ND_SAVEREPLY;
408191783Srmacklem
409191783Srmacklem	nfsrvd_rephead(nd);
410191783Srmacklem	/*
411191783Srmacklem	 * If nd_repstat is non-zero, just fill in the reply status
412191783Srmacklem	 * to complete the RPC reply for V2. Otherwise, you must do
413191783Srmacklem	 * the RPC.
414191783Srmacklem	 */
415191783Srmacklem	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
416191783Srmacklem		*nd->nd_errp = nfsd_errmap(nd);
417191783Srmacklem		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
418217063Srmacklem		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
419217063Srmacklem			vn_finished_write(mp);
420224086Szack		goto out;
421191783Srmacklem	}
422191783Srmacklem
423191783Srmacklem	/*
424191783Srmacklem	 * Now the procedure can be performed. For V4, nfsrvd_compound()
425191783Srmacklem	 * works through the sub-rpcs, otherwise just call the procedure.
426191783Srmacklem	 * The procedures are in three groups with different arguments.
427191783Srmacklem	 * The group is indicated by the value in nfs_retfh[].
428191783Srmacklem	 */
429191783Srmacklem	if (nd->nd_flag & ND_NFSV4) {
430191783Srmacklem		nfsrvd_compound(nd, isdgram, p);
431191783Srmacklem	} else {
432191783Srmacklem		if (nfs_retfh[nd->nd_procnum] == 1) {
433191783Srmacklem			if (vp)
434224080Szack				NFSVOPUNLOCK(vp, 0);
435191783Srmacklem			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
436191783Srmacklem			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
437191783Srmacklem		} else if (nfs_retfh[nd->nd_procnum] == 2) {
438191783Srmacklem			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
439191783Srmacklem			    vp, NULL, p, &nes, NULL);
440191783Srmacklem		} else {
441191783Srmacklem			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
442191783Srmacklem			    vp, p, &nes);
443191783Srmacklem		}
444217063Srmacklem		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
445217063Srmacklem			vn_finished_write(mp);
446191783Srmacklem		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
447191783Srmacklem	}
448191783Srmacklem	if (error) {
449191783Srmacklem		if (error != EBADRPC)
450191783Srmacklem			printf("nfs dorpc err2=%d\n", error);
451191783Srmacklem		nd->nd_repstat = NFSERR_GARBAGE;
452191783Srmacklem	}
453191783Srmacklem	*nd->nd_errp = nfsd_errmap(nd);
454191783Srmacklem
455191783Srmacklem	/*
456191783Srmacklem	 * Don't cache certain reply status values.
457191783Srmacklem	 */
458191783Srmacklem	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
459191783Srmacklem	    (nd->nd_repstat == NFSERR_GARBAGE ||
460191783Srmacklem	     nd->nd_repstat == NFSERR_BADXDR ||
461191783Srmacklem	     nd->nd_repstat == NFSERR_MOVED ||
462191783Srmacklem	     nd->nd_repstat == NFSERR_DELAY ||
463191783Srmacklem	     nd->nd_repstat == NFSERR_BADSEQID ||
464191783Srmacklem	     nd->nd_repstat == NFSERR_RESOURCE ||
465191783Srmacklem	     nd->nd_repstat == NFSERR_SERVERFAULT ||
466191783Srmacklem	     nd->nd_repstat == NFSERR_STALECLIENTID ||
467191783Srmacklem	     nd->nd_repstat == NFSERR_STALESTATEID ||
468191783Srmacklem	     nd->nd_repstat == NFSERR_OLDSTATEID ||
469191783Srmacklem	     nd->nd_repstat == NFSERR_BADSTATEID ||
470191783Srmacklem	     nd->nd_repstat == NFSERR_GRACE ||
471191783Srmacklem	     nd->nd_repstat == NFSERR_NOGRACE))
472191783Srmacklem		nd->nd_flag &= ~ND_SAVEREPLY;
473224086Szack
474224086Szackout:
475224086Szack	NFSEXITCODE2(0, nd);
476191783Srmacklem}
477191783Srmacklem
478191783Srmacklem/*
479191783Srmacklem * Breaks down a compound RPC request and calls the server routines for
480191783Srmacklem * the subprocedures.
481191783Srmacklem * Some suboperations are performed directly here to simplify file handle<-->
482191783Srmacklem * vnode pointer handling.
483191783Srmacklem */
484191783Srmacklemstatic void
485191783Srmacklemnfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
486191783Srmacklem    NFSPROC_T *p)
487191783Srmacklem{
488191783Srmacklem	int i, op;
489191783Srmacklem	u_int32_t *tl;
490191783Srmacklem	struct nfsclient *clp, *nclp;
491191783Srmacklem	int numops, taglen = -1, error = 0, igotlock;
492191783Srmacklem	u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp;
493191783Srmacklem	u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
494191783Srmacklem	vnode_t vp, nvp, savevp;
495191783Srmacklem	struct nfsrvfh fh;
496217063Srmacklem	mount_t new_mp, temp_mp = NULL;
497191783Srmacklem	struct ucred *credanon;
498191783Srmacklem	struct nfsexstuff nes, vpnes, savevpnes;
499217063Srmacklem	fsid_t cur_fsid, save_fsid;
500191783Srmacklem	static u_int64_t compref = 0;
501191783Srmacklem
502191783Srmacklem	NFSVNO_EXINIT(&vpnes);
503191783Srmacklem	NFSVNO_EXINIT(&savevpnes);
504191783Srmacklem	/*
505191783Srmacklem	 * Put the seq# of the current compound RPC in nfsrv_descript.
506191783Srmacklem	 * (This is used by nfsrv_checkgetattr(), to see if the write
507191783Srmacklem	 *  delegation was created by the same compound RPC as the one
508191783Srmacklem	 *  with that Getattr in it.)
509191783Srmacklem	 * Don't worry about the 64bit number wrapping around. It ain't
510191783Srmacklem	 * gonna happen before this server gets shut down/rebooted.
511191783Srmacklem	 */
512191783Srmacklem	nd->nd_compref = compref++;
513191783Srmacklem
514191783Srmacklem	/*
515191783Srmacklem	 * Check for and optionally get a lock on the root. This lock means that
516191783Srmacklem	 * no nfsd will be fiddling with the V4 file system and state stuff. It
517191783Srmacklem	 * is required when the V4 root is being changed, the stable storage
518191783Srmacklem	 * restart file is being updated, or callbacks are being done.
519191783Srmacklem	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
520191783Srmacklem	 * either hold a reference count (nfs_usecnt) or the lock. When
521191783Srmacklem	 * nfsrv_unlock() is called to release the lock, it can optionally
522191783Srmacklem	 * also get a reference count, which saves the need for a call to
523191783Srmacklem	 * nfsrv_getref() after nfsrv_unlock().
524191783Srmacklem	 */
525191783Srmacklem	/*
526191783Srmacklem	 * First, check to see if we need to wait for an update lock.
527191783Srmacklem	 */
528191783Srmacklem	igotlock = 0;
529191783Srmacklem	NFSLOCKV4ROOTMUTEX();
530191783Srmacklem	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
531191783Srmacklem		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
532222389Srmacklem		    NFSV4ROOTLOCKMUTEXPTR, NULL);
533191783Srmacklem	else
534191783Srmacklem		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
535222389Srmacklem		    NFSV4ROOTLOCKMUTEXPTR, NULL);
536191783Srmacklem	NFSUNLOCKV4ROOTMUTEX();
537191783Srmacklem	if (igotlock) {
538191783Srmacklem		/*
539191783Srmacklem		 * If I got the lock, I can update the stable storage file.
540191783Srmacklem		 * Done when the grace period is over or a client has long
541191783Srmacklem		 * since expired.
542191783Srmacklem		 */
543191783Srmacklem		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
544191783Srmacklem		if ((nfsrv_stablefirst.nsf_flags &
545191783Srmacklem		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
546191783Srmacklem			nfsrv_updatestable(p);
547191783Srmacklem
548191783Srmacklem		/*
549191783Srmacklem		 * If at least one client has long since expired, search
550191783Srmacklem		 * the client list for them, write a REVOKE record on the
551191783Srmacklem		 * stable storage file and then remove them from the client
552191783Srmacklem		 * list.
553191783Srmacklem		 */
554191783Srmacklem		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
555191783Srmacklem			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
556191783Srmacklem			for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
557191783Srmacklem			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
558191783Srmacklem				nclp) {
559191783Srmacklem				if (clp->lc_flags & LCL_EXPIREIT) {
560191783Srmacklem				    if (!LIST_EMPTY(&clp->lc_open) ||
561191783Srmacklem					!LIST_EMPTY(&clp->lc_deleg))
562191783Srmacklem					nfsrv_writestable(clp->lc_id,
563191783Srmacklem					    clp->lc_idlen, NFSNST_REVOKE, p);
564191783Srmacklem				    nfsrv_cleanclient(clp, p);
565191783Srmacklem				    nfsrv_freedeleglist(&clp->lc_deleg);
566191783Srmacklem				    nfsrv_freedeleglist(&clp->lc_olddeleg);
567191783Srmacklem				    LIST_REMOVE(clp, lc_hash);
568191783Srmacklem				    nfsrv_zapclient(clp, p);
569191783Srmacklem				}
570191783Srmacklem			    }
571191783Srmacklem			}
572191783Srmacklem		}
573191783Srmacklem		NFSLOCKV4ROOTMUTEX();
574191783Srmacklem		nfsv4_unlock(&nfsv4rootfs_lock, 1);
575191783Srmacklem		NFSUNLOCKV4ROOTMUTEX();
576191783Srmacklem	} else {
577191783Srmacklem		/*
578191783Srmacklem		 * If we didn't get the lock, we need to get a refcnt,
579191783Srmacklem		 * which also checks for and waits for the lock.
580191783Srmacklem		 */
581191783Srmacklem		NFSLOCKV4ROOTMUTEX();
582191783Srmacklem		nfsv4_getref(&nfsv4rootfs_lock, NULL,
583222389Srmacklem		    NFSV4ROOTLOCKMUTEXPTR, NULL);
584191783Srmacklem		NFSUNLOCKV4ROOTMUTEX();
585191783Srmacklem	}
586191783Srmacklem
587191783Srmacklem	/*
588191783Srmacklem	 * If flagged, search for open owners that haven't had any opens
589191783Srmacklem	 * for a long time.
590191783Srmacklem	 */
591191783Srmacklem	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
592191783Srmacklem		nfsrv_throwawayopens(p);
593191783Srmacklem	}
594191783Srmacklem
595191783Srmacklem	savevp = vp = NULL;
596217063Srmacklem	save_fsid.val[0] = save_fsid.val[1] = 0;
597217063Srmacklem	cur_fsid.val[0] = cur_fsid.val[1] = 0;
598191783Srmacklem	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
599191783Srmacklem	taglen = fxdr_unsigned(int, *tl);
600191783Srmacklem	if (taglen < 0) {
601191783Srmacklem		error = EBADRPC;
602191783Srmacklem		goto nfsmout;
603191783Srmacklem	}
604191783Srmacklem	if (taglen <= NFSV4_SMALLSTR)
605191783Srmacklem		tagstr = tag;
606191783Srmacklem	else
607191783Srmacklem		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
608191783Srmacklem	error = nfsrv_mtostr(nd, tagstr, taglen);
609191783Srmacklem	if (error) {
610191783Srmacklem		if (taglen > NFSV4_SMALLSTR)
611191783Srmacklem			free(tagstr, M_TEMP);
612191783Srmacklem		taglen = -1;
613191783Srmacklem		goto nfsmout;
614191783Srmacklem	}
615191783Srmacklem	(void) nfsm_strtom(nd, tag, taglen);
616191783Srmacklem	if (taglen > NFSV4_SMALLSTR) {
617191783Srmacklem		free(tagstr, M_TEMP);
618191783Srmacklem	}
619191783Srmacklem	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
620191783Srmacklem	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
621191783Srmacklem	minorvers = fxdr_unsigned(u_int32_t, *tl++);
622191783Srmacklem	if (minorvers != NFSV4_MINORVERSION)
623191783Srmacklem		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
624191783Srmacklem	if (nd->nd_repstat)
625191783Srmacklem		numops = 0;
626191783Srmacklem	else
627191783Srmacklem		numops = fxdr_unsigned(int, *tl);
628191783Srmacklem	/*
629191783Srmacklem	 * Loop around doing the sub ops.
630191783Srmacklem	 * vp - is an unlocked vnode pointer for the CFH
631191783Srmacklem	 * savevp - is an unlocked vnode pointer for the SAVEDFH
632191783Srmacklem	 * (at some future date, it might turn out to be more appropriate
633191783Srmacklem	 *  to keep the file handles instead of vnode pointers?)
634191783Srmacklem	 * savevpnes and vpnes - are the export flags for the above.
635191783Srmacklem	 */
636191783Srmacklem	for (i = 0; i < numops; i++) {
637191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
638191783Srmacklem		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
639192781Srmacklem		*repp = *tl;
640191783Srmacklem		op = fxdr_unsigned(int, *tl);
641191783Srmacklem		if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
642192781Srmacklem			nd->nd_repstat = NFSERR_OPILLEGAL;
643192781Srmacklem			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
644192781Srmacklem			*repp = nfsd_errmap(nd);
645192781Srmacklem			retops++;
646192781Srmacklem			break;
647192781Srmacklem		} else {
648192781Srmacklem			repp++;
649191783Srmacklem		}
650191783Srmacklem
651191783Srmacklem		/*
652191783Srmacklem		 * Check for a referral on the current FH and, if so, return
653191783Srmacklem		 * NFSERR_MOVED for all ops that allow it, except Getattr.
654191783Srmacklem		 */
655191783Srmacklem		if (vp != NULL && op != NFSV4OP_GETATTR &&
656191783Srmacklem		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
657191783Srmacklem		    nfsrv_errmoved(op)) {
658191783Srmacklem			nd->nd_repstat = NFSERR_MOVED;
659191783Srmacklem			*repp = nfsd_errmap(nd);
660191783Srmacklem			retops++;
661191783Srmacklem			break;
662191783Srmacklem		}
663191783Srmacklem
664191783Srmacklem		nd->nd_procnum = op;
665191783Srmacklem		/*
666191783Srmacklem		 * If over flood level, reply NFSERR_RESOURCE, if at the first
667191783Srmacklem		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
668191783Srmacklem		 * really nasty for certain Op sequences, I'll play it safe
669191783Srmacklem		 * and only return the error at the beginning.) The cache
670191783Srmacklem		 * will still function over flood level, but uses lots of
671191783Srmacklem		 * mbufs.)
672191783Srmacklem		 * If nfsrv_mallocmget_limit() returns True, the system is near
673191783Srmacklem		 * to its limit for memory that malloc()/mget() can allocate.
674191783Srmacklem		 */
675191783Srmacklem		if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
676191783Srmacklem		    (nfsrv_mallocmget_limit() ||
677191783Srmacklem		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
678191783Srmacklem			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
679191783Srmacklem				printf("nfsd server cache flooded, try to");
680191783Srmacklem				printf(" increase nfsrc_floodlevel\n");
681191783Srmacklem			}
682191783Srmacklem			nd->nd_repstat = NFSERR_RESOURCE;
683191783Srmacklem			*repp = nfsd_errmap(nd);
684191783Srmacklem			if (op == NFSV4OP_SETATTR) {
685192781Srmacklem				/*
686192781Srmacklem				 * Setattr replies require a bitmap.
687192781Srmacklem				 * even for errors like these.
688192781Srmacklem				 */
689192781Srmacklem				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
690192781Srmacklem				*tl = 0;
691191783Srmacklem			}
692191783Srmacklem			retops++;
693191783Srmacklem			break;
694191783Srmacklem		}
695191783Srmacklem		if (nfsv4_opflag[op].savereply)
696191783Srmacklem			nd->nd_flag |= ND_SAVEREPLY;
697191783Srmacklem		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
698191783Srmacklem		switch (op) {
699191783Srmacklem		case NFSV4OP_PUTFH:
700191783Srmacklem			error = nfsrv_mtofh(nd, &fh);
701191783Srmacklem			if (error)
702191783Srmacklem				goto nfsmout;
703217063Srmacklem			if (!nd->nd_repstat)
704217063Srmacklem				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
705217063Srmacklem				    NULL, 0, p);
706191783Srmacklem			/* For now, allow this for non-export FHs */
707191783Srmacklem			if (!nd->nd_repstat) {
708191783Srmacklem				if (vp)
709191783Srmacklem					vrele(vp);
710191783Srmacklem				vp = nvp;
711217063Srmacklem				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
712224082Szack				NFSVOPUNLOCK(vp, 0);
713191783Srmacklem				vpnes = nes;
714191783Srmacklem			}
715191783Srmacklem			break;
716191783Srmacklem		case NFSV4OP_PUTPUBFH:
717217063Srmacklem			if (nfs_pubfhset)
718216700Srmacklem			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
719217063Srmacklem				&nes, NULL, 0, p);
720217063Srmacklem			else
721191783Srmacklem			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
722191783Srmacklem			if (!nd->nd_repstat) {
723191783Srmacklem				if (vp)
724191783Srmacklem					vrele(vp);
725191783Srmacklem				vp = nvp;
726217063Srmacklem				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
727224082Szack				NFSVOPUNLOCK(vp, 0);
728191783Srmacklem				vpnes = nes;
729191783Srmacklem			}
730191783Srmacklem			break;
731191783Srmacklem		case NFSV4OP_PUTROOTFH:
732191783Srmacklem			if (nfs_rootfhset) {
733216700Srmacklem				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
734217063Srmacklem				    &nes, NULL, 0, p);
735191783Srmacklem				if (!nd->nd_repstat) {
736191783Srmacklem					if (vp)
737191783Srmacklem						vrele(vp);
738191783Srmacklem					vp = nvp;
739217063Srmacklem					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
740224082Szack					NFSVOPUNLOCK(vp, 0);
741191783Srmacklem					vpnes = nes;
742191783Srmacklem				}
743216894Srmacklem			} else
744191783Srmacklem				nd->nd_repstat = NFSERR_NOFILEHANDLE;
745191783Srmacklem			break;
746191783Srmacklem		case NFSV4OP_SAVEFH:
747191783Srmacklem			if (vp && NFSVNO_EXPORTED(&vpnes)) {
748191783Srmacklem				nd->nd_repstat = 0;
749191783Srmacklem				/* If vp == savevp, a no-op */
750191783Srmacklem				if (vp != savevp) {
751191783Srmacklem					if (savevp)
752191783Srmacklem						vrele(savevp);
753191783Srmacklem					VREF(vp);
754191783Srmacklem					savevp = vp;
755191783Srmacklem					savevpnes = vpnes;
756217063Srmacklem					save_fsid = cur_fsid;
757191783Srmacklem				}
758191783Srmacklem			} else {
759191783Srmacklem				nd->nd_repstat = NFSERR_NOFILEHANDLE;
760191783Srmacklem			}
761191783Srmacklem			break;
762191783Srmacklem		case NFSV4OP_RESTOREFH:
763191783Srmacklem			if (savevp) {
764191783Srmacklem				nd->nd_repstat = 0;
765191783Srmacklem				/* If vp == savevp, a no-op */
766191783Srmacklem				if (vp != savevp) {
767191783Srmacklem					VREF(savevp);
768191783Srmacklem					vrele(vp);
769191783Srmacklem					vp = savevp;
770191783Srmacklem					vpnes = savevpnes;
771217063Srmacklem					cur_fsid = save_fsid;
772191783Srmacklem				}
773191783Srmacklem			} else {
774191783Srmacklem				nd->nd_repstat = NFSERR_RESTOREFH;
775191783Srmacklem			}
776191783Srmacklem			break;
777191783Srmacklem		default:
778191783Srmacklem		    /*
779191783Srmacklem		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
780191783Srmacklem		     * non-exported directory if
781191783Srmacklem		     * nfs_rootfhset. Do I need to allow any other Ops?
782191783Srmacklem		     * (You can only have a non-exported vpnes if
783191783Srmacklem		     *  nfs_rootfhset is true. See nfsd_fhtovp())
784191783Srmacklem		     * Allow AUTH_SYS to be used for file systems
785191783Srmacklem		     * exported GSS only for certain Ops, to allow
786191783Srmacklem		     * clients to do mounts more easily.
787191783Srmacklem		     */
788191783Srmacklem		    if (nfsv4_opflag[op].needscfh && vp) {
789191783Srmacklem			if (!NFSVNO_EXPORTED(&vpnes) &&
790191783Srmacklem			    op != NFSV4OP_LOOKUP &&
791191783Srmacklem			    op != NFSV4OP_GETATTR &&
792191783Srmacklem			    op != NFSV4OP_GETFH &&
793223348Srmacklem			    op != NFSV4OP_ACCESS &&
794223348Srmacklem			    op != NFSV4OP_READLINK &&
795191783Srmacklem			    op != NFSV4OP_SECINFO)
796191783Srmacklem				nd->nd_repstat = NFSERR_NOFILEHANDLE;
797192121Srmacklem			else if (nfsvno_testexp(nd, &vpnes) &&
798191783Srmacklem			    op != NFSV4OP_LOOKUP &&
799191783Srmacklem			    op != NFSV4OP_GETFH &&
800191783Srmacklem			    op != NFSV4OP_GETATTR &&
801191783Srmacklem			    op != NFSV4OP_SECINFO)
802191783Srmacklem				nd->nd_repstat = NFSERR_WRONGSEC;
803191783Srmacklem			if (nd->nd_repstat) {
804191783Srmacklem				if (op == NFSV4OP_SETATTR) {
805191783Srmacklem				    /*
806191783Srmacklem				     * Setattr reply requires a bitmap
807191783Srmacklem				     * even for errors like these.
808191783Srmacklem				     */
809191783Srmacklem				    NFSM_BUILD(tl, u_int32_t *,
810191783Srmacklem					NFSX_UNSIGNED);
811191783Srmacklem				    *tl = 0;
812191783Srmacklem				}
813191783Srmacklem				break;
814191783Srmacklem			}
815191783Srmacklem		    }
816191783Srmacklem		    if (nfsv4_opflag[op].retfh == 1) {
817191783Srmacklem			if (!vp) {
818191783Srmacklem				nd->nd_repstat = NFSERR_NOFILEHANDLE;
819191783Srmacklem				break;
820191783Srmacklem			}
821191783Srmacklem			VREF(vp);
822191783Srmacklem			if (nfsv4_opflag[op].modifyfs)
823217023Srmacklem				vn_start_write(vp, &temp_mp, V_WAIT);
824191783Srmacklem			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
825191783Srmacklem			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
826191783Srmacklem			if (!error && !nd->nd_repstat) {
827217063Srmacklem			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
828217063Srmacklem				new_mp = nvp->v_mount;
829217063Srmacklem				if (cur_fsid.val[0] !=
830217063Srmacklem				    new_mp->mnt_stat.f_fsid.val[0] ||
831217063Srmacklem				    cur_fsid.val[1] !=
832217063Srmacklem				    new_mp->mnt_stat.f_fsid.val[1]) {
833217063Srmacklem				    /* crossed a server mount point */
834217063Srmacklem				    nd->nd_repstat = nfsvno_checkexp(new_mp,
835191783Srmacklem					nd->nd_nam, &nes, &credanon);
836191783Srmacklem				    if (!nd->nd_repstat)
837191783Srmacklem					nd->nd_repstat = nfsd_excred(nd,
838191783Srmacklem					    &nes, credanon);
839191940Skan				    if (credanon != NULL)
840191940Skan					crfree(credanon);
841191783Srmacklem				    if (!nd->nd_repstat) {
842191783Srmacklem					vpnes = nes;
843217063Srmacklem					cur_fsid = new_mp->mnt_stat.f_fsid;
844191783Srmacklem				    }
845217063Srmacklem				}
846217063Srmacklem				/* Lookup ops return a locked vnode */
847224082Szack				NFSVOPUNLOCK(nvp, 0);
848191783Srmacklem			    }
849191783Srmacklem			    if (!nd->nd_repstat) {
850191783Srmacklem				    vrele(vp);
851191783Srmacklem				    vp = nvp;
852216897Srmacklem			    } else
853216897Srmacklem				    vrele(nvp);
854191783Srmacklem			}
855191783Srmacklem			if (nfsv4_opflag[op].modifyfs)
856217023Srmacklem				vn_finished_write(temp_mp);
857191783Srmacklem		    } else if (nfsv4_opflag[op].retfh == 2) {
858191783Srmacklem			if (vp == NULL || savevp == NULL) {
859191783Srmacklem				nd->nd_repstat = NFSERR_NOFILEHANDLE;
860191783Srmacklem				break;
861217063Srmacklem			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
862217063Srmacklem			    cur_fsid.val[1] != save_fsid.val[1]) {
863191783Srmacklem				nd->nd_repstat = NFSERR_XDEV;
864191783Srmacklem				break;
865191783Srmacklem			}
866191783Srmacklem			if (nfsv4_opflag[op].modifyfs)
867217023Srmacklem				vn_start_write(savevp, &temp_mp, V_WAIT);
868224081Szack			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
869216893Srmacklem				VREF(vp);
870216893Srmacklem				VREF(savevp);
871216893Srmacklem				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
872216893Srmacklem				    savevp, vp, p, &savevpnes, &vpnes);
873216893Srmacklem			} else
874216893Srmacklem				nd->nd_repstat = NFSERR_PERM;
875191783Srmacklem			if (nfsv4_opflag[op].modifyfs)
876217023Srmacklem				vn_finished_write(temp_mp);
877191783Srmacklem		    } else {
878191783Srmacklem			if (nfsv4_opflag[op].retfh != 0)
879191783Srmacklem				panic("nfsrvd_compound");
880191783Srmacklem			if (nfsv4_opflag[op].needscfh) {
881216700Srmacklem				if (vp != NULL) {
882216893Srmacklem					if (nfsv4_opflag[op].modifyfs)
883217023Srmacklem						vn_start_write(vp, &temp_mp,
884217023Srmacklem						    V_WAIT);
885224081Szack					if (NFSVOPLOCK(vp, nfsv4_opflag[op].lktype)
886216893Srmacklem					    == 0)
887216893Srmacklem						VREF(vp);
888216893Srmacklem					else
889216700Srmacklem						nd->nd_repstat = NFSERR_PERM;
890216893Srmacklem				} else {
891191783Srmacklem					nd->nd_repstat = NFSERR_NOFILEHANDLE;
892191783Srmacklem					if (op == NFSV4OP_SETATTR) {
893216700Srmacklem						/*
894216700Srmacklem						 * Setattr reply requires a
895216700Srmacklem						 * bitmap even for errors like
896216700Srmacklem						 * these.
897216700Srmacklem						 */
898216700Srmacklem						NFSM_BUILD(tl, u_int32_t *,
899216700Srmacklem						    NFSX_UNSIGNED);
900216700Srmacklem						*tl = 0;
901191783Srmacklem					}
902191783Srmacklem					break;
903191783Srmacklem				}
904216893Srmacklem				if (nd->nd_repstat == 0)
905216893Srmacklem					error = (*(nfsrv4_ops0[op]))(nd,
906216893Srmacklem					    isdgram, vp, p, &vpnes);
907216700Srmacklem				if (nfsv4_opflag[op].modifyfs)
908217023Srmacklem					vn_finished_write(temp_mp);
909191783Srmacklem			} else {
910191783Srmacklem				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
911191783Srmacklem				    NULL, p, &vpnes);
912191783Srmacklem			}
913191783Srmacklem		    }
914191783Srmacklem		};
915191783Srmacklem		if (error) {
916191783Srmacklem			if (error == EBADRPC || error == NFSERR_BADXDR) {
917191783Srmacklem				nd->nd_repstat = NFSERR_BADXDR;
918191783Srmacklem			} else {
919191783Srmacklem				nd->nd_repstat = error;
920191783Srmacklem				printf("nfsv4 comperr0=%d\n", error);
921191783Srmacklem			}
922191783Srmacklem			error = 0;
923191783Srmacklem		}
924191783Srmacklem		retops++;
925191783Srmacklem		if (nd->nd_repstat) {
926191783Srmacklem			*repp = nfsd_errmap(nd);
927191783Srmacklem			break;
928191783Srmacklem		} else {
929191783Srmacklem			*repp = 0;	/* NFS4_OK */
930191783Srmacklem		}
931191783Srmacklem	}
932191783Srmacklemnfsmout:
933191783Srmacklem	if (error) {
934191783Srmacklem		if (error == EBADRPC || error == NFSERR_BADXDR)
935191783Srmacklem			nd->nd_repstat = NFSERR_BADXDR;
936191783Srmacklem		else
937191783Srmacklem			printf("nfsv4 comperr1=%d\n", error);
938191783Srmacklem	}
939191783Srmacklem	if (taglen == -1) {
940191783Srmacklem		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
941191783Srmacklem		*tl++ = 0;
942191783Srmacklem		*tl = 0;
943191783Srmacklem	} else {
944191783Srmacklem		*retopsp = txdr_unsigned(retops);
945191783Srmacklem	}
946191783Srmacklem	if (vp)
947191783Srmacklem		vrele(vp);
948191783Srmacklem	if (savevp)
949191783Srmacklem		vrele(savevp);
950191783Srmacklem	NFSLOCKV4ROOTMUTEX();
951191783Srmacklem	nfsv4_relref(&nfsv4rootfs_lock);
952191783Srmacklem	NFSUNLOCKV4ROOTMUTEX();
953224086Szack
954224086Szack	NFSEXITCODE2(0, nd);
955191783Srmacklem}
956