xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision a7dea1671b87c07d2d266f836bfa8b58efc7c134)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 /*
40  * Socket operations for use by the nfs server.
41  */
42 
43 #ifndef APPLEKEXT
44 #include <fs/nfs/nfsport.h>
45 
46 extern struct nfsstatsv1 nfsstatsv1;
47 extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
48 extern int nfs_pubfhset, nfs_rootfhset;
49 extern struct nfsv4lock nfsv4rootfs_lock;
50 extern struct nfsrv_stablefirst nfsrv_stablefirst;
51 extern struct nfsclienthashhead *nfsclienthash;
52 extern int nfsrv_clienthashsize;
53 extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
54 extern int nfsd_debuglevel;
55 extern int nfsrv_layouthighwater;
56 extern volatile int nfsrv_layoutcnt;
57 NFSV4ROOTLOCKMUTEX;
58 NFSSTATESPINLOCK;
59 
60 int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
61     int, vnode_t , struct nfsexstuff *) = {
62 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
63 	nfsrvd_getattr,
64 	nfsrvd_setattr,
65 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
66 	nfsrvd_access,
67 	nfsrvd_readlink,
68 	nfsrvd_read,
69 	nfsrvd_write,
70 	nfsrvd_create,
71 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
72 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
73 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
74 	nfsrvd_remove,
75 	nfsrvd_remove,
76 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
77 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
78 	nfsrvd_readdir,
79 	nfsrvd_readdirplus,
80 	nfsrvd_statfs,
81 	nfsrvd_fsinfo,
82 	nfsrvd_pathconf,
83 	nfsrvd_commit,
84 };
85 
86 int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
87     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
88 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
89 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
90 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
91 	nfsrvd_lookup,
92 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
93 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
94 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
95 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
96 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
97 	nfsrvd_mkdir,
98 	nfsrvd_symlink,
99 	nfsrvd_mknod,
100 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
101 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
102 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
103 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
104 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
105 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
106 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
107 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
108 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
109 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
110 };
111 
112 int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
113     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
114 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
115 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
116 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
117 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
118 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
119 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
120 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
121 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
122 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
123 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
124 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
125 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
126 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
127 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
128 	nfsrvd_rename,
129 	nfsrvd_link,
130 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
131 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
132 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
133 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
134 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
135 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
136 };
137 
138 int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *,
139     int, vnode_t , struct nfsexstuff *) = {
140 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
141 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
142 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
143 	nfsrvd_access,
144 	nfsrvd_close,
145 	nfsrvd_commit,
146 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
147 	nfsrvd_delegpurge,
148 	nfsrvd_delegreturn,
149 	nfsrvd_getattr,
150 	nfsrvd_getfh,
151 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
152 	nfsrvd_lock,
153 	nfsrvd_lockt,
154 	nfsrvd_locku,
155 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
156 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
157 	nfsrvd_verify,
158 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
159 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
160 	nfsrvd_openconfirm,
161 	nfsrvd_opendowngrade,
162 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
163 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
164 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
165 	nfsrvd_read,
166 	nfsrvd_readdirplus,
167 	nfsrvd_readlink,
168 	nfsrvd_remove,
169 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
170 	nfsrvd_renew,
171 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
172 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
173 	nfsrvd_secinfo,
174 	nfsrvd_setattr,
175 	nfsrvd_setclientid,
176 	nfsrvd_setclientidcfrm,
177 	nfsrvd_verify,
178 	nfsrvd_write,
179 	nfsrvd_releaselckown,
180 	nfsrvd_notsupp,
181 	nfsrvd_bindconnsess,
182 	nfsrvd_exchangeid,
183 	nfsrvd_createsession,
184 	nfsrvd_destroysession,
185 	nfsrvd_freestateid,
186 	nfsrvd_notsupp,
187 	nfsrvd_getdevinfo,
188 	nfsrvd_notsupp,
189 	nfsrvd_layoutcommit,
190 	nfsrvd_layoutget,
191 	nfsrvd_layoutreturn,
192 	nfsrvd_notsupp,
193 	nfsrvd_sequence,
194 	nfsrvd_notsupp,
195 	nfsrvd_teststateid,
196 	nfsrvd_notsupp,
197 	nfsrvd_destroyclientid,
198 	nfsrvd_reclaimcomplete,
199 	nfsrvd_allocate,
200 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
201 	nfsrvd_notsupp,
202 	nfsrvd_notsupp,
203 	nfsrvd_ioadvise,
204 	nfsrvd_layouterror,
205 	nfsrvd_layoutstats,
206 	nfsrvd_notsupp,
207 	nfsrvd_notsupp,
208 	nfsrvd_notsupp,
209 	nfsrvd_seek,
210 	nfsrvd_notsupp,
211 	nfsrvd_notsupp,
212 	nfsrvd_getxattr,
213 	nfsrvd_setxattr,
214 	nfsrvd_listxattr,
215 	nfsrvd_rmxattr,
216 };
217 
218 int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *,
219     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
220 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
221 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
222 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
223 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
224 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
225 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
226 	nfsrvd_mknod,
227 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
228 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
229 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
230 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
231 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
232 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
233 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
234 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
235 	nfsrvd_lookup,
236 	nfsrvd_lookup,
237 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
238 	nfsrvd_open,
239 	nfsrvd_openattr,
240 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
241 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
242 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
243 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
244 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
245 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
246 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
247 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
248 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
249 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
250 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
251 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
252 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
253 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
254 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
255 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
256 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
257 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
258 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
259 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
260 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
261 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
262 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
263 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
264 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
265 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
266 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
267 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
268 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
269 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
270 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
271 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
272 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
273 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
274 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
275 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
276 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
277 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
278 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
279 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
280 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
281 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
282 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
283 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
284 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
285 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
286 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
287 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
288 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
289 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
290 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
291 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
292 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
293 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
294 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
295 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
296 };
297 
298 int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *,
299     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
300 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
301 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
302 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
303 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
304 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
305 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
306 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
307 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
308 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
309 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
310 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
311 	nfsrvd_link,
312 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
313 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
314 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
315 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
316 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
317 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
318 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
319 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
320 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
321 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
322 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
323 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
324 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
325 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
326 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
327 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
328 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
329 	nfsrvd_rename,
330 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
331 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
332 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
333 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
334 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
335 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
336 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
337 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
338 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
339 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
340 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
341 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
342 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
343 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
344 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
345 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
346 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
347 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
348 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
349 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
350 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
351 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
352 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
353 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
354 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
355 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
356 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
357 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
358 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
359 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
360 	nfsrvd_copy_file_range,
361 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
362 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
363 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
364 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
365 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
366 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
367 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
368 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
369 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
370 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
371 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
372 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
373 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
374 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
375 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
376 };
377 #endif	/* !APPLEKEXT */
378 
379 /*
380  * Static array that defines which nfs rpc's are nonidempotent
381  */
382 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
383 	FALSE,
384 	FALSE,
385 	TRUE,
386 	FALSE,
387 	FALSE,
388 	FALSE,
389 	FALSE,
390 	TRUE,
391 	TRUE,
392 	TRUE,
393 	TRUE,
394 	TRUE,
395 	TRUE,
396 	TRUE,
397 	TRUE,
398 	TRUE,
399 	FALSE,
400 	FALSE,
401 	FALSE,
402 	FALSE,
403 	FALSE,
404 	FALSE,
405 };
406 
407 /*
408  * This static array indicates whether or not the RPC modifies the
409  * file system.
410  */
411 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
412     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
413     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
414 
415 SYSCTL_DECL(_vfs_nfsd);
416 static int	nfs_minminorv4 = NFSV4_MINORVERSION;
417 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN,
418     &nfs_minminorv4, 0,
419     "The lowest minor version of NFSv4 handled by the server");
420 
421 static int	nfs_maxminorv4 = NFSV42_MINORVERSION;
422 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN,
423     &nfs_maxminorv4, 0,
424     "The highest minor version of NFSv4 handled by the server");
425 
426 /* local functions */
427 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
428     u_char *tag, int taglen, u_int32_t minorvers);
429 
430 
431 /*
432  * This static array indicates which server procedures require the extra
433  * arguments to return the current file handle for V2, 3.
434  */
435 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
436 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
437 
438 extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];
439 
440 static int nfsv3to4op[NFS_V3NPROCS] = {
441 	NFSPROC_NULL,
442 	NFSV4OP_GETATTR,
443 	NFSV4OP_SETATTR,
444 	NFSV4OP_LOOKUP,
445 	NFSV4OP_ACCESS,
446 	NFSV4OP_READLINK,
447 	NFSV4OP_READ,
448 	NFSV4OP_WRITE,
449 	NFSV4OP_V3CREATE,
450 	NFSV4OP_MKDIR,
451 	NFSV4OP_SYMLINK,
452 	NFSV4OP_MKNOD,
453 	NFSV4OP_REMOVE,
454 	NFSV4OP_RMDIR,
455 	NFSV4OP_RENAME,
456 	NFSV4OP_LINK,
457 	NFSV4OP_READDIR,
458 	NFSV4OP_READDIRPLUS,
459 	NFSV4OP_FSSTAT,
460 	NFSV4OP_FSINFO,
461 	NFSV4OP_PATHCONF,
462 	NFSV4OP_COMMIT,
463 };
464 
465 static struct mtx nfsrvd_statmtx;
466 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
467 
468 static void
469 nfsrvd_statstart(int op, struct bintime *now)
470 {
471 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
472 		printf("%s: op %d invalid\n", __func__, op);
473 		return;
474 	}
475 
476 	mtx_lock(&nfsrvd_statmtx);
477 	if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
478 		if (now != NULL)
479 			nfsstatsv1.busyfrom = *now;
480 		else
481 			binuptime(&nfsstatsv1.busyfrom);
482 
483 	}
484 	nfsstatsv1.srvrpccnt[op]++;
485 	nfsstatsv1.srvstartcnt++;
486 	mtx_unlock(&nfsrvd_statmtx);
487 
488 }
489 
490 static void
491 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
492     struct bintime *then)
493 {
494 	struct bintime dt, lnow;
495 
496 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
497 		printf("%s: op %d invalid\n", __func__, op);
498 		return;
499 	}
500 
501 	if (now == NULL) {
502 		now = &lnow;
503 		binuptime(now);
504 	}
505 
506 	mtx_lock(&nfsrvd_statmtx);
507 
508 	nfsstatsv1.srvbytes[op] += bytes;
509 	nfsstatsv1.srvops[op]++;
510 
511 	if (then != NULL) {
512 		dt = *now;
513 		bintime_sub(&dt, then);
514 		bintime_add(&nfsstatsv1.srvduration[op], &dt);
515 	}
516 
517 	dt = *now;
518 	bintime_sub(&dt, &nfsstatsv1.busyfrom);
519 	bintime_add(&nfsstatsv1.busytime, &dt);
520 	nfsstatsv1.busyfrom = *now;
521 
522 	nfsstatsv1.srvdonecnt++;
523 
524 	mtx_unlock(&nfsrvd_statmtx);
525 }
526 
527 /*
528  * Do an RPC. Basically, get the file handles translated to vnode pointers
529  * and then call the appropriate server routine. The server routines are
530  * split into groups, based on whether they use a file handle or file
531  * handle plus name or ...
532  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
533  */
534 APPLESTATIC void
535 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
536     u_int32_t minorvers)
537 {
538 	int error = 0, lktype;
539 	vnode_t vp;
540 	mount_t mp = NULL;
541 	struct nfsrvfh fh;
542 	struct nfsexstuff nes;
543 
544 	/*
545 	 * Get a locked vnode for the first file handle
546 	 */
547 	if (!(nd->nd_flag & ND_NFSV4)) {
548 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
549 		/*
550 		 * For NFSv3, if the malloc/mget allocation is near limits,
551 		 * return NFSERR_DELAY.
552 		 */
553 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
554 			nd->nd_repstat = NFSERR_DELAY;
555 			vp = NULL;
556 		} else {
557 			error = nfsrv_mtofh(nd, &fh);
558 			if (error) {
559 				if (error != EBADRPC)
560 					printf("nfs dorpc err1=%d\n", error);
561 				nd->nd_repstat = NFSERR_GARBAGE;
562 				goto out;
563 			}
564 			if (nd->nd_procnum == NFSPROC_READ ||
565 			    nd->nd_procnum == NFSPROC_WRITE ||
566 			    nd->nd_procnum == NFSPROC_READDIR ||
567 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
568 			    nd->nd_procnum == NFSPROC_READLINK ||
569 			    nd->nd_procnum == NFSPROC_GETATTR ||
570 			    nd->nd_procnum == NFSPROC_ACCESS ||
571 			    nd->nd_procnum == NFSPROC_FSSTAT ||
572 			    nd->nd_procnum == NFSPROC_FSINFO)
573 				lktype = LK_SHARED;
574 			else
575 				lktype = LK_EXCLUSIVE;
576 			if (nd->nd_flag & ND_PUBLOOKUP)
577 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
578 				    &mp, nfsrv_writerpc[nd->nd_procnum]);
579 			else
580 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
581 				    &mp, nfsrv_writerpc[nd->nd_procnum]);
582 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
583 				goto out;
584 		}
585 	}
586 
587 	/*
588 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
589 	 * cache, as required.
590 	 * For V4, nfsrvd_compound() does this.
591 	 */
592 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
593 		nd->nd_flag |= ND_SAVEREPLY;
594 
595 	nfsrvd_rephead(nd);
596 	/*
597 	 * If nd_repstat is non-zero, just fill in the reply status
598 	 * to complete the RPC reply for V2. Otherwise, you must do
599 	 * the RPC.
600 	 */
601 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
602 		*nd->nd_errp = nfsd_errmap(nd);
603 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
604 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
605 		   /*now*/ NULL, /*then*/ NULL);
606 		if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
607 			vn_finished_write(mp);
608 		goto out;
609 	}
610 
611 	/*
612 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
613 	 * works through the sub-rpcs, otherwise just call the procedure.
614 	 * The procedures are in three groups with different arguments.
615 	 * The group is indicated by the value in nfs_retfh[].
616 	 */
617 	if (nd->nd_flag & ND_NFSV4) {
618 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers);
619 	} else {
620 		struct bintime start_time;
621 
622 		binuptime(&start_time);
623 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
624 
625 		if (nfs_retfh[nd->nd_procnum] == 1) {
626 			if (vp)
627 				NFSVOPUNLOCK(vp);
628 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
629 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes);
630 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
631 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
632 			    vp, NULL, &nes, NULL);
633 		} else {
634 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
635 			    vp, &nes);
636 		}
637 		if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
638 			vn_finished_write(mp);
639 
640 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
641 		    /*now*/ NULL, /*then*/ &start_time);
642 	}
643 	if (error) {
644 		if (error != EBADRPC)
645 			printf("nfs dorpc err2=%d\n", error);
646 		nd->nd_repstat = NFSERR_GARBAGE;
647 	}
648 	*nd->nd_errp = nfsd_errmap(nd);
649 
650 	/*
651 	 * Don't cache certain reply status values.
652 	 */
653 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
654 	    (nd->nd_repstat == NFSERR_GARBAGE ||
655 	     nd->nd_repstat == NFSERR_BADXDR ||
656 	     nd->nd_repstat == NFSERR_MOVED ||
657 	     nd->nd_repstat == NFSERR_DELAY ||
658 	     nd->nd_repstat == NFSERR_BADSEQID ||
659 	     nd->nd_repstat == NFSERR_RESOURCE ||
660 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
661 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
662 	     nd->nd_repstat == NFSERR_STALESTATEID ||
663 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
664 	     nd->nd_repstat == NFSERR_BADSTATEID ||
665 	     nd->nd_repstat == NFSERR_GRACE ||
666 	     nd->nd_repstat == NFSERR_NOGRACE))
667 		nd->nd_flag &= ~ND_SAVEREPLY;
668 
669 out:
670 	NFSEXITCODE2(0, nd);
671 }
672 
673 /*
674  * Breaks down a compound RPC request and calls the server routines for
675  * the subprocedures.
676  * Some suboperations are performed directly here to simplify file handle<-->
677  * vnode pointer handling.
678  */
679 static void
680 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
681     int taglen, u_int32_t minorvers)
682 {
683 	int i, lktype, op, op0 = 0, statsinprog = 0;
684 	u_int32_t *tl;
685 	struct nfsclient *clp, *nclp;
686 	int numops, error = 0, igotlock;
687 	u_int32_t retops = 0, *retopsp = NULL, *repp;
688 	vnode_t vp, nvp, savevp;
689 	struct nfsrvfh fh;
690 	mount_t new_mp, temp_mp = NULL;
691 	struct ucred *credanon;
692 	struct nfsexstuff nes, vpnes, savevpnes;
693 	fsid_t cur_fsid, save_fsid;
694 	static u_int64_t compref = 0;
695 	struct bintime start_time;
696 	struct thread *p;
697 
698 	p = curthread;
699 
700 	NFSVNO_EXINIT(&vpnes);
701 	NFSVNO_EXINIT(&savevpnes);
702 	/*
703 	 * Put the seq# of the current compound RPC in nfsrv_descript.
704 	 * (This is used by nfsrv_checkgetattr(), to see if the write
705 	 *  delegation was created by the same compound RPC as the one
706 	 *  with that Getattr in it.)
707 	 * Don't worry about the 64bit number wrapping around. It ain't
708 	 * gonna happen before this server gets shut down/rebooted.
709 	 */
710 	nd->nd_compref = compref++;
711 
712 	/*
713 	 * Check for and optionally get a lock on the root. This lock means that
714 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
715 	 * is required when the V4 root is being changed, the stable storage
716 	 * restart file is being updated, or callbacks are being done.
717 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
718 	 * either hold a reference count (nfs_usecnt) or the lock. When
719 	 * nfsrv_unlock() is called to release the lock, it can optionally
720 	 * also get a reference count, which saves the need for a call to
721 	 * nfsrv_getref() after nfsrv_unlock().
722 	 */
723 	/*
724 	 * First, check to see if we need to wait for an update lock.
725 	 */
726 	igotlock = 0;
727 	NFSLOCKV4ROOTMUTEX();
728 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
729 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
730 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
731 	else
732 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
733 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
734 	NFSUNLOCKV4ROOTMUTEX();
735 	if (igotlock) {
736 		/*
737 		 * If I got the lock, I can update the stable storage file.
738 		 * Done when the grace period is over or a client has long
739 		 * since expired.
740 		 */
741 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
742 		if ((nfsrv_stablefirst.nsf_flags &
743 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
744 			nfsrv_updatestable(p);
745 
746 		/*
747 		 * If at least one client has long since expired, search
748 		 * the client list for them, write a REVOKE record on the
749 		 * stable storage file and then remove them from the client
750 		 * list.
751 		 */
752 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
753 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
754 			for (i = 0; i < nfsrv_clienthashsize; i++) {
755 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
756 				nclp) {
757 				if (clp->lc_flags & LCL_EXPIREIT) {
758 				    if (!LIST_EMPTY(&clp->lc_open) ||
759 					!LIST_EMPTY(&clp->lc_deleg))
760 					nfsrv_writestable(clp->lc_id,
761 					    clp->lc_idlen, NFSNST_REVOKE, p);
762 				    nfsrv_cleanclient(clp, p);
763 				    nfsrv_freedeleglist(&clp->lc_deleg);
764 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
765 				    LIST_REMOVE(clp, lc_hash);
766 				    nfsrv_zapclient(clp, p);
767 				}
768 			    }
769 			}
770 		}
771 		NFSLOCKV4ROOTMUTEX();
772 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
773 		NFSUNLOCKV4ROOTMUTEX();
774 	} else {
775 		/*
776 		 * If we didn't get the lock, we need to get a refcnt,
777 		 * which also checks for and waits for the lock.
778 		 */
779 		NFSLOCKV4ROOTMUTEX();
780 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
781 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
782 		NFSUNLOCKV4ROOTMUTEX();
783 	}
784 
785 	/*
786 	 * If flagged, search for open owners that haven't had any opens
787 	 * for a long time.
788 	 */
789 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
790 		nfsrv_throwawayopens(p);
791 	}
792 
793 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
794 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
795 		nfsrv_recalloldlayout(p);
796 
797 	savevp = vp = NULL;
798 	save_fsid.val[0] = save_fsid.val[1] = 0;
799 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
800 
801 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
802 	if (taglen < 0) {
803 		error = EBADRPC;
804 		goto nfsmout;
805 	}
806 
807 	(void) nfsm_strtom(nd, tag, taglen);
808 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
809 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
810 	if ((minorvers != NFSV4_MINORVERSION &&
811 	    minorvers != NFSV41_MINORVERSION &&
812 	    minorvers != NFSV42_MINORVERSION) ||
813 	    minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)
814 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
815 	if (nd->nd_repstat)
816 		numops = 0;
817 	else
818 		numops = fxdr_unsigned(int, *tl);
819 	/*
820 	 * Loop around doing the sub ops.
821 	 * vp - is an unlocked vnode pointer for the CFH
822 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
823 	 * (at some future date, it might turn out to be more appropriate
824 	 *  to keep the file handles instead of vnode pointers?)
825 	 * savevpnes and vpnes - are the export flags for the above.
826 	 */
827 	for (i = 0; i < numops; i++) {
828 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
829 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
830 		*repp = *tl;
831 		op = fxdr_unsigned(int, *tl);
832 		NFSD_DEBUG(4, "op=%d\n", op);
833 		if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
834 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
835 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {
836 			nd->nd_repstat = NFSERR_OPILLEGAL;
837 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
838 			*repp = nfsd_errmap(nd);
839 			retops++;
840 			break;
841 		} else {
842 			repp++;
843 		}
844 
845 		binuptime(&start_time);
846 		nfsrvd_statstart(op, &start_time);
847 		statsinprog = 1;
848 
849 		if (i == 0)
850 			op0 = op;
851 		if (i == numops - 1)
852 			nd->nd_flag |= ND_LASTOP;
853 
854 		/*
855 		 * Check for a referral on the current FH and, if so, return
856 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
857 		 */
858 		if (vp != NULL && op != NFSV4OP_GETATTR &&
859 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
860 		    nfsrv_errmoved(op)) {
861 			nd->nd_repstat = NFSERR_MOVED;
862 			*repp = nfsd_errmap(nd);
863 			retops++;
864 			break;
865 		}
866 
867 		/*
868 		 * For NFSv4.1, check for a Sequence Operation being first
869 		 * or one of the other allowed operations by itself.
870 		 */
871 		if ((nd->nd_flag & ND_NFSV41) != 0) {
872 			if (i != 0 && op == NFSV4OP_SEQUENCE)
873 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
874 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
875 			    op != NFSV4OP_EXCHANGEID &&
876 			    op != NFSV4OP_CREATESESSION &&
877 			    op != NFSV4OP_BINDCONNTOSESS &&
878 			    op != NFSV4OP_DESTROYCLIENTID &&
879 			    op != NFSV4OP_DESTROYSESSION)
880 				nd->nd_repstat = NFSERR_OPNOTINSESS;
881 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
882 				nd->nd_repstat = NFSERR_NOTONLYOP;
883 			if (nd->nd_repstat != 0) {
884 				*repp = nfsd_errmap(nd);
885 				retops++;
886 				break;
887 			}
888 		}
889 
890 		nd->nd_procnum = op;
891 		/*
892 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
893 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
894 		 * really nasty for certain Op sequences, I'll play it safe
895 		 * and only return the error at the beginning.) The cache
896 		 * will still function over flood level, but uses lots of
897 		 * mbufs.)
898 		 * If nfsrv_mallocmget_limit() returns True, the system is near
899 		 * to its limit for memory that malloc()/mget() can allocate.
900 		 */
901 		if (i == 0 && (nd->nd_rp == NULL ||
902 		    nd->nd_rp->rc_refcnt == 0) &&
903 		    (nfsrv_mallocmget_limit() ||
904 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
905 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
906 				printf("nfsd server cache flooded, try "
907 				    "increasing vfs.nfsd.tcphighwater\n");
908 			nd->nd_repstat = NFSERR_RESOURCE;
909 			*repp = nfsd_errmap(nd);
910 			if (op == NFSV4OP_SETATTR) {
911 				/*
912 				 * Setattr replies require a bitmap.
913 				 * even for errors like these.
914 				 */
915 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
916 				*tl = 0;
917 			}
918 			retops++;
919 			break;
920 		}
921 		if (nfsv4_opflag[op].savereply)
922 			nd->nd_flag |= ND_SAVEREPLY;
923 		switch (op) {
924 		case NFSV4OP_PUTFH:
925 			error = nfsrv_mtofh(nd, &fh);
926 			if (error)
927 				goto nfsmout;
928 			if (!nd->nd_repstat)
929 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
930 				    NULL, 0);
931 			/* For now, allow this for non-export FHs */
932 			if (!nd->nd_repstat) {
933 				if (vp)
934 					vrele(vp);
935 				vp = nvp;
936 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
937 				NFSVOPUNLOCK(vp);
938 				vpnes = nes;
939 			}
940 			break;
941 		case NFSV4OP_PUTPUBFH:
942 			if (nfs_pubfhset)
943 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
944 				&nes, NULL, 0);
945 			else
946 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
947 			if (!nd->nd_repstat) {
948 				if (vp)
949 					vrele(vp);
950 				vp = nvp;
951 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
952 				NFSVOPUNLOCK(vp);
953 				vpnes = nes;
954 			}
955 			break;
956 		case NFSV4OP_PUTROOTFH:
957 			if (nfs_rootfhset) {
958 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
959 				    &nes, NULL, 0);
960 				if (!nd->nd_repstat) {
961 					if (vp)
962 						vrele(vp);
963 					vp = nvp;
964 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
965 					NFSVOPUNLOCK(vp);
966 					vpnes = nes;
967 				}
968 			} else
969 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
970 			break;
971 		case NFSV4OP_SAVEFH:
972 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
973 				nd->nd_repstat = 0;
974 				/* If vp == savevp, a no-op */
975 				if (vp != savevp) {
976 					if (savevp)
977 						vrele(savevp);
978 					VREF(vp);
979 					savevp = vp;
980 					savevpnes = vpnes;
981 					save_fsid = cur_fsid;
982 				}
983 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
984 					nd->nd_savedcurstateid =
985 					    nd->nd_curstateid;
986 					nd->nd_flag |= ND_SAVEDCURSTATEID;
987 				}
988 			} else {
989 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
990 			}
991 			break;
992 		case NFSV4OP_RESTOREFH:
993 			if (savevp) {
994 				nd->nd_repstat = 0;
995 				/* If vp == savevp, a no-op */
996 				if (vp != savevp) {
997 					VREF(savevp);
998 					vrele(vp);
999 					vp = savevp;
1000 					vpnes = savevpnes;
1001 					cur_fsid = save_fsid;
1002 				}
1003 				if ((nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
1004 					nd->nd_curstateid =
1005 					    nd->nd_savedcurstateid;
1006 					nd->nd_flag |= ND_CURSTATEID;
1007 				}
1008 			} else {
1009 				nd->nd_repstat = NFSERR_RESTOREFH;
1010 			}
1011 			break;
1012 		default:
1013 		    /*
1014 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
1015 		     * non-exported directory if
1016 		     * nfs_rootfhset. Do I need to allow any other Ops?
1017 		     * (You can only have a non-exported vpnes if
1018 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
1019 		     * Allow AUTH_SYS to be used for file systems
1020 		     * exported GSS only for certain Ops, to allow
1021 		     * clients to do mounts more easily.
1022 		     */
1023 		    if (nfsv4_opflag[op].needscfh && vp) {
1024 			if (!NFSVNO_EXPORTED(&vpnes) &&
1025 			    op != NFSV4OP_LOOKUP &&
1026 			    op != NFSV4OP_GETATTR &&
1027 			    op != NFSV4OP_GETFH &&
1028 			    op != NFSV4OP_ACCESS &&
1029 			    op != NFSV4OP_READLINK &&
1030 			    op != NFSV4OP_SECINFO)
1031 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1032 			else if (nfsvno_testexp(nd, &vpnes) &&
1033 			    op != NFSV4OP_LOOKUP &&
1034 			    op != NFSV4OP_GETFH &&
1035 			    op != NFSV4OP_GETATTR &&
1036 			    op != NFSV4OP_SECINFO)
1037 				nd->nd_repstat = NFSERR_WRONGSEC;
1038 			if (nd->nd_repstat) {
1039 				if (op == NFSV4OP_SETATTR) {
1040 				    /*
1041 				     * Setattr reply requires a bitmap
1042 				     * even for errors like these.
1043 				     */
1044 				    NFSM_BUILD(tl, u_int32_t *,
1045 					NFSX_UNSIGNED);
1046 				    *tl = 0;
1047 				}
1048 				break;
1049 			}
1050 		    }
1051 		    if (nfsv4_opflag[op].retfh == 1) {
1052 			if (!vp) {
1053 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1054 				break;
1055 			}
1056 			VREF(vp);
1057 			if (nfsv4_opflag[op].modifyfs)
1058 				vn_start_write(vp, &temp_mp, V_WAIT);
1059 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
1060 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
1061 			if (!error && !nd->nd_repstat) {
1062 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
1063 				new_mp = nvp->v_mount;
1064 				if (cur_fsid.val[0] !=
1065 				    new_mp->mnt_stat.f_fsid.val[0] ||
1066 				    cur_fsid.val[1] !=
1067 				    new_mp->mnt_stat.f_fsid.val[1]) {
1068 				    /* crossed a server mount point */
1069 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
1070 					nd->nd_nam, &nes, &credanon);
1071 				    if (!nd->nd_repstat)
1072 					nd->nd_repstat = nfsd_excred(nd,
1073 					    &nes, credanon);
1074 				    if (credanon != NULL)
1075 					crfree(credanon);
1076 				    if (!nd->nd_repstat) {
1077 					vpnes = nes;
1078 					cur_fsid = new_mp->mnt_stat.f_fsid;
1079 				    }
1080 				}
1081 				/* Lookup ops return a locked vnode */
1082 				NFSVOPUNLOCK(nvp);
1083 			    }
1084 			    if (!nd->nd_repstat) {
1085 				    vrele(vp);
1086 				    vp = nvp;
1087 			    } else
1088 				    vrele(nvp);
1089 			}
1090 			if (nfsv4_opflag[op].modifyfs)
1091 				vn_finished_write(temp_mp);
1092 		    } else if (nfsv4_opflag[op].retfh == 2) {
1093 			if (vp == NULL || savevp == NULL) {
1094 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1095 				break;
1096 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
1097 			    cur_fsid.val[1] != save_fsid.val[1]) {
1098 				nd->nd_repstat = NFSERR_XDEV;
1099 				break;
1100 			}
1101 			if (nfsv4_opflag[op].modifyfs)
1102 				vn_start_write(savevp, &temp_mp, V_WAIT);
1103 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1104 				VREF(vp);
1105 				VREF(savevp);
1106 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1107 				    savevp, vp, &savevpnes, &vpnes);
1108 			} else
1109 				nd->nd_repstat = NFSERR_PERM;
1110 			if (nfsv4_opflag[op].modifyfs)
1111 				vn_finished_write(temp_mp);
1112 		    } else {
1113 			if (nfsv4_opflag[op].retfh != 0)
1114 				panic("nfsrvd_compound");
1115 			if (nfsv4_opflag[op].needscfh) {
1116 				if (vp != NULL) {
1117 					lktype = nfsv4_opflag[op].lktype;
1118 					if (nfsv4_opflag[op].modifyfs) {
1119 						vn_start_write(vp, &temp_mp,
1120 						    V_WAIT);
1121 						if (op == NFSV4OP_WRITE &&
1122 						    MNT_SHARED_WRITES(temp_mp))
1123 							lktype = LK_SHARED;
1124 					}
1125 					if (NFSVOPLOCK(vp, lktype) == 0)
1126 						VREF(vp);
1127 					else
1128 						nd->nd_repstat = NFSERR_PERM;
1129 				} else {
1130 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1131 					if (op == NFSV4OP_SETATTR) {
1132 						/*
1133 						 * Setattr reply requires a
1134 						 * bitmap even for errors like
1135 						 * these.
1136 						 */
1137 						NFSM_BUILD(tl, u_int32_t *,
1138 						    NFSX_UNSIGNED);
1139 						*tl = 0;
1140 					}
1141 					break;
1142 				}
1143 				if (nd->nd_repstat == 0)
1144 					error = (*(nfsrv4_ops0[op]))(nd,
1145 					    isdgram, vp, &vpnes);
1146 				if (nfsv4_opflag[op].modifyfs)
1147 					vn_finished_write(temp_mp);
1148 			} else {
1149 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1150 				    NULL, &vpnes);
1151 			}
1152 		    }
1153 		}
1154 		if (error) {
1155 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1156 				nd->nd_repstat = NFSERR_BADXDR;
1157 			} else {
1158 				nd->nd_repstat = error;
1159 				printf("nfsv4 comperr0=%d\n", error);
1160 			}
1161 			error = 0;
1162 		}
1163 
1164 		if (statsinprog != 0) {
1165 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1166 			    /*then*/ &start_time);
1167 			statsinprog = 0;
1168 		}
1169 
1170 		retops++;
1171 		if (nd->nd_repstat) {
1172 			*repp = nfsd_errmap(nd);
1173 			break;
1174 		} else {
1175 			*repp = 0;	/* NFS4_OK */
1176 		}
1177 	}
1178 nfsmout:
1179 	if (statsinprog != 0) {
1180 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1181 		    /*then*/ &start_time);
1182 		statsinprog = 0;
1183 	}
1184 	if (error) {
1185 		if (error == EBADRPC || error == NFSERR_BADXDR)
1186 			nd->nd_repstat = NFSERR_BADXDR;
1187 		else
1188 			printf("nfsv4 comperr1=%d\n", error);
1189 	}
1190 	if (taglen == -1) {
1191 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1192 		*tl++ = 0;
1193 		*tl = 0;
1194 	} else {
1195 		*retopsp = txdr_unsigned(retops);
1196 	}
1197 	if (vp)
1198 		vrele(vp);
1199 	if (savevp)
1200 		vrele(savevp);
1201 	NFSLOCKV4ROOTMUTEX();
1202 	nfsv4_relref(&nfsv4rootfs_lock);
1203 	NFSUNLOCKV4ROOTMUTEX();
1204 
1205 	NFSEXITCODE2(0, nd);
1206 }
1207