xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 148a8da8)
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[NFSV41_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 };
200 
201 int (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
202     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
203 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
204 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
205 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
206 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
207 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
208 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
209 	nfsrvd_mknod,
210 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
211 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
212 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
213 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
214 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
215 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
216 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
217 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
218 	nfsrvd_lookup,
219 	nfsrvd_lookup,
220 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
221 	nfsrvd_open,
222 	nfsrvd_openattr,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
236 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
237 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
238 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
239 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
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 };
263 
264 int (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
265     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
266 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
267 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
268 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
269 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
270 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
271 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
272 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
273 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
274 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
275 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
276 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
277 	nfsrvd_link,
278 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
279 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
280 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
281 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
282 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
283 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
284 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
285 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
286 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
287 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
288 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
289 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
290 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
291 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
292 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
293 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
294 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
295 	nfsrvd_rename,
296 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
297 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
298 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
299 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
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 };
326 #endif	/* !APPLEKEXT */
327 
328 /*
329  * Static array that defines which nfs rpc's are nonidempotent
330  */
331 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
332 	FALSE,
333 	FALSE,
334 	TRUE,
335 	FALSE,
336 	FALSE,
337 	FALSE,
338 	FALSE,
339 	TRUE,
340 	TRUE,
341 	TRUE,
342 	TRUE,
343 	TRUE,
344 	TRUE,
345 	TRUE,
346 	TRUE,
347 	TRUE,
348 	FALSE,
349 	FALSE,
350 	FALSE,
351 	FALSE,
352 	FALSE,
353 	FALSE,
354 };
355 
356 /*
357  * This static array indicates whether or not the RPC modifies the
358  * file system.
359  */
360 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
361     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
362     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
363 
364 /* local functions */
365 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
366     u_char *tag, int taglen, u_int32_t minorvers);
367 
368 
369 /*
370  * This static array indicates which server procedures require the extra
371  * arguments to return the current file handle for V2, 3.
372  */
373 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
374 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
375 
376 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
377 
378 static int nfsv3to4op[NFS_V3NPROCS] = {
379 	NFSPROC_NULL,
380 	NFSV4OP_GETATTR,
381 	NFSV4OP_SETATTR,
382 	NFSV4OP_LOOKUP,
383 	NFSV4OP_ACCESS,
384 	NFSV4OP_READLINK,
385 	NFSV4OP_READ,
386 	NFSV4OP_WRITE,
387 	NFSV4OP_V3CREATE,
388 	NFSV4OP_MKDIR,
389 	NFSV4OP_SYMLINK,
390 	NFSV4OP_MKNOD,
391 	NFSV4OP_REMOVE,
392 	NFSV4OP_RMDIR,
393 	NFSV4OP_RENAME,
394 	NFSV4OP_LINK,
395 	NFSV4OP_READDIR,
396 	NFSV4OP_READDIRPLUS,
397 	NFSV4OP_FSSTAT,
398 	NFSV4OP_FSINFO,
399 	NFSV4OP_PATHCONF,
400 	NFSV4OP_COMMIT,
401 };
402 
403 static struct mtx nfsrvd_statmtx;
404 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
405 
406 static void
407 nfsrvd_statstart(int op, struct bintime *now)
408 {
409 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
410 		printf("%s: op %d invalid\n", __func__, op);
411 		return;
412 	}
413 
414 	mtx_lock(&nfsrvd_statmtx);
415 	if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
416 		if (now != NULL)
417 			nfsstatsv1.busyfrom = *now;
418 		else
419 			binuptime(&nfsstatsv1.busyfrom);
420 
421 	}
422 	nfsstatsv1.srvrpccnt[op]++;
423 	nfsstatsv1.srvstartcnt++;
424 	mtx_unlock(&nfsrvd_statmtx);
425 
426 }
427 
428 static void
429 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
430     struct bintime *then)
431 {
432 	struct bintime dt, lnow;
433 
434 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
435 		printf("%s: op %d invalid\n", __func__, op);
436 		return;
437 	}
438 
439 	if (now == NULL) {
440 		now = &lnow;
441 		binuptime(now);
442 	}
443 
444 	mtx_lock(&nfsrvd_statmtx);
445 
446 	nfsstatsv1.srvbytes[op] += bytes;
447 	nfsstatsv1.srvops[op]++;
448 
449 	if (then != NULL) {
450 		dt = *now;
451 		bintime_sub(&dt, then);
452 		bintime_add(&nfsstatsv1.srvduration[op], &dt);
453 	}
454 
455 	dt = *now;
456 	bintime_sub(&dt, &nfsstatsv1.busyfrom);
457 	bintime_add(&nfsstatsv1.busytime, &dt);
458 	nfsstatsv1.busyfrom = *now;
459 
460 	nfsstatsv1.srvdonecnt++;
461 
462 	mtx_unlock(&nfsrvd_statmtx);
463 }
464 
465 /*
466  * Do an RPC. Basically, get the file handles translated to vnode pointers
467  * and then call the appropriate server routine. The server routines are
468  * split into groups, based on whether they use a file handle or file
469  * handle plus name or ...
470  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
471  */
472 APPLESTATIC void
473 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
474     u_int32_t minorvers)
475 {
476 	int error = 0, lktype;
477 	vnode_t vp;
478 	mount_t mp = NULL;
479 	struct nfsrvfh fh;
480 	struct nfsexstuff nes;
481 
482 	/*
483 	 * Get a locked vnode for the first file handle
484 	 */
485 	if (!(nd->nd_flag & ND_NFSV4)) {
486 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
487 		/*
488 		 * For NFSv3, if the malloc/mget allocation is near limits,
489 		 * return NFSERR_DELAY.
490 		 */
491 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
492 			nd->nd_repstat = NFSERR_DELAY;
493 			vp = NULL;
494 		} else {
495 			error = nfsrv_mtofh(nd, &fh);
496 			if (error) {
497 				if (error != EBADRPC)
498 					printf("nfs dorpc err1=%d\n", error);
499 				nd->nd_repstat = NFSERR_GARBAGE;
500 				goto out;
501 			}
502 			if (nd->nd_procnum == NFSPROC_READ ||
503 			    nd->nd_procnum == NFSPROC_WRITE ||
504 			    nd->nd_procnum == NFSPROC_READDIR ||
505 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
506 			    nd->nd_procnum == NFSPROC_READLINK ||
507 			    nd->nd_procnum == NFSPROC_GETATTR ||
508 			    nd->nd_procnum == NFSPROC_ACCESS ||
509 			    nd->nd_procnum == NFSPROC_FSSTAT ||
510 			    nd->nd_procnum == NFSPROC_FSINFO)
511 				lktype = LK_SHARED;
512 			else
513 				lktype = LK_EXCLUSIVE;
514 			if (nd->nd_flag & ND_PUBLOOKUP)
515 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
516 				    &mp, nfsrv_writerpc[nd->nd_procnum]);
517 			else
518 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
519 				    &mp, nfsrv_writerpc[nd->nd_procnum]);
520 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
521 				goto out;
522 		}
523 	}
524 
525 	/*
526 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
527 	 * cache, as required.
528 	 * For V4, nfsrvd_compound() does this.
529 	 */
530 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
531 		nd->nd_flag |= ND_SAVEREPLY;
532 
533 	nfsrvd_rephead(nd);
534 	/*
535 	 * If nd_repstat is non-zero, just fill in the reply status
536 	 * to complete the RPC reply for V2. Otherwise, you must do
537 	 * the RPC.
538 	 */
539 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
540 		*nd->nd_errp = nfsd_errmap(nd);
541 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
542 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
543 		   /*now*/ NULL, /*then*/ NULL);
544 		if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
545 			vn_finished_write(mp);
546 		goto out;
547 	}
548 
549 	/*
550 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
551 	 * works through the sub-rpcs, otherwise just call the procedure.
552 	 * The procedures are in three groups with different arguments.
553 	 * The group is indicated by the value in nfs_retfh[].
554 	 */
555 	if (nd->nd_flag & ND_NFSV4) {
556 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers);
557 	} else {
558 		struct bintime start_time;
559 
560 		binuptime(&start_time);
561 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
562 
563 		if (nfs_retfh[nd->nd_procnum] == 1) {
564 			if (vp)
565 				NFSVOPUNLOCK(vp, 0);
566 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
567 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes);
568 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
569 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
570 			    vp, NULL, &nes, NULL);
571 		} else {
572 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
573 			    vp, &nes);
574 		}
575 		if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
576 			vn_finished_write(mp);
577 
578 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
579 		    /*now*/ NULL, /*then*/ &start_time);
580 	}
581 	if (error) {
582 		if (error != EBADRPC)
583 			printf("nfs dorpc err2=%d\n", error);
584 		nd->nd_repstat = NFSERR_GARBAGE;
585 	}
586 	*nd->nd_errp = nfsd_errmap(nd);
587 
588 	/*
589 	 * Don't cache certain reply status values.
590 	 */
591 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
592 	    (nd->nd_repstat == NFSERR_GARBAGE ||
593 	     nd->nd_repstat == NFSERR_BADXDR ||
594 	     nd->nd_repstat == NFSERR_MOVED ||
595 	     nd->nd_repstat == NFSERR_DELAY ||
596 	     nd->nd_repstat == NFSERR_BADSEQID ||
597 	     nd->nd_repstat == NFSERR_RESOURCE ||
598 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
599 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
600 	     nd->nd_repstat == NFSERR_STALESTATEID ||
601 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
602 	     nd->nd_repstat == NFSERR_BADSTATEID ||
603 	     nd->nd_repstat == NFSERR_GRACE ||
604 	     nd->nd_repstat == NFSERR_NOGRACE))
605 		nd->nd_flag &= ~ND_SAVEREPLY;
606 
607 out:
608 	NFSEXITCODE2(0, nd);
609 }
610 
611 /*
612  * Breaks down a compound RPC request and calls the server routines for
613  * the subprocedures.
614  * Some suboperations are performed directly here to simplify file handle<-->
615  * vnode pointer handling.
616  */
617 static void
618 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
619     int taglen, u_int32_t minorvers)
620 {
621 	int i, lktype, op, op0 = 0, statsinprog = 0;
622 	u_int32_t *tl;
623 	struct nfsclient *clp, *nclp;
624 	int numops, error = 0, igotlock;
625 	u_int32_t retops = 0, *retopsp = NULL, *repp;
626 	vnode_t vp, nvp, savevp;
627 	struct nfsrvfh fh;
628 	mount_t new_mp, temp_mp = NULL;
629 	struct ucred *credanon;
630 	struct nfsexstuff nes, vpnes, savevpnes;
631 	fsid_t cur_fsid, save_fsid;
632 	static u_int64_t compref = 0;
633 	struct bintime start_time;
634 	struct thread *p;
635 
636 	p = curthread;
637 
638 	NFSVNO_EXINIT(&vpnes);
639 	NFSVNO_EXINIT(&savevpnes);
640 	/*
641 	 * Put the seq# of the current compound RPC in nfsrv_descript.
642 	 * (This is used by nfsrv_checkgetattr(), to see if the write
643 	 *  delegation was created by the same compound RPC as the one
644 	 *  with that Getattr in it.)
645 	 * Don't worry about the 64bit number wrapping around. It ain't
646 	 * gonna happen before this server gets shut down/rebooted.
647 	 */
648 	nd->nd_compref = compref++;
649 
650 	/*
651 	 * Check for and optionally get a lock on the root. This lock means that
652 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
653 	 * is required when the V4 root is being changed, the stable storage
654 	 * restart file is being updated, or callbacks are being done.
655 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
656 	 * either hold a reference count (nfs_usecnt) or the lock. When
657 	 * nfsrv_unlock() is called to release the lock, it can optionally
658 	 * also get a reference count, which saves the need for a call to
659 	 * nfsrv_getref() after nfsrv_unlock().
660 	 */
661 	/*
662 	 * First, check to see if we need to wait for an update lock.
663 	 */
664 	igotlock = 0;
665 	NFSLOCKV4ROOTMUTEX();
666 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
667 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
668 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
669 	else
670 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
671 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
672 	NFSUNLOCKV4ROOTMUTEX();
673 	if (igotlock) {
674 		/*
675 		 * If I got the lock, I can update the stable storage file.
676 		 * Done when the grace period is over or a client has long
677 		 * since expired.
678 		 */
679 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
680 		if ((nfsrv_stablefirst.nsf_flags &
681 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
682 			nfsrv_updatestable(p);
683 
684 		/*
685 		 * If at least one client has long since expired, search
686 		 * the client list for them, write a REVOKE record on the
687 		 * stable storage file and then remove them from the client
688 		 * list.
689 		 */
690 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
691 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
692 			for (i = 0; i < nfsrv_clienthashsize; i++) {
693 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
694 				nclp) {
695 				if (clp->lc_flags & LCL_EXPIREIT) {
696 				    if (!LIST_EMPTY(&clp->lc_open) ||
697 					!LIST_EMPTY(&clp->lc_deleg))
698 					nfsrv_writestable(clp->lc_id,
699 					    clp->lc_idlen, NFSNST_REVOKE, p);
700 				    nfsrv_cleanclient(clp, p);
701 				    nfsrv_freedeleglist(&clp->lc_deleg);
702 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
703 				    LIST_REMOVE(clp, lc_hash);
704 				    nfsrv_zapclient(clp, p);
705 				}
706 			    }
707 			}
708 		}
709 		NFSLOCKV4ROOTMUTEX();
710 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
711 		NFSUNLOCKV4ROOTMUTEX();
712 	} else {
713 		/*
714 		 * If we didn't get the lock, we need to get a refcnt,
715 		 * which also checks for and waits for the lock.
716 		 */
717 		NFSLOCKV4ROOTMUTEX();
718 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
719 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
720 		NFSUNLOCKV4ROOTMUTEX();
721 	}
722 
723 	/*
724 	 * If flagged, search for open owners that haven't had any opens
725 	 * for a long time.
726 	 */
727 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
728 		nfsrv_throwawayopens(p);
729 	}
730 
731 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
732 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
733 		nfsrv_recalloldlayout(p);
734 
735 	savevp = vp = NULL;
736 	save_fsid.val[0] = save_fsid.val[1] = 0;
737 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
738 
739 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
740 	if (taglen < 0) {
741 		error = EBADRPC;
742 		goto nfsmout;
743 	}
744 
745 	(void) nfsm_strtom(nd, tag, taglen);
746 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
747 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
748 	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
749 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
750 	if (nd->nd_repstat)
751 		numops = 0;
752 	else
753 		numops = fxdr_unsigned(int, *tl);
754 	/*
755 	 * Loop around doing the sub ops.
756 	 * vp - is an unlocked vnode pointer for the CFH
757 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
758 	 * (at some future date, it might turn out to be more appropriate
759 	 *  to keep the file handles instead of vnode pointers?)
760 	 * savevpnes and vpnes - are the export flags for the above.
761 	 */
762 	for (i = 0; i < numops; i++) {
763 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
764 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
765 		*repp = *tl;
766 		op = fxdr_unsigned(int, *tl);
767 		NFSD_DEBUG(4, "op=%d\n", op);
768 		if (op < NFSV4OP_ACCESS ||
769 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
770 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
771 			nd->nd_repstat = NFSERR_OPILLEGAL;
772 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
773 			*repp = nfsd_errmap(nd);
774 			retops++;
775 			break;
776 		} else {
777 			repp++;
778 		}
779 
780 		binuptime(&start_time);
781 		nfsrvd_statstart(op, &start_time);
782 		statsinprog = 1;
783 
784 		if (i == 0)
785 			op0 = op;
786 		if (i == numops - 1)
787 			nd->nd_flag |= ND_LASTOP;
788 
789 		/*
790 		 * Check for a referral on the current FH and, if so, return
791 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
792 		 */
793 		if (vp != NULL && op != NFSV4OP_GETATTR &&
794 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
795 		    nfsrv_errmoved(op)) {
796 			nd->nd_repstat = NFSERR_MOVED;
797 			*repp = nfsd_errmap(nd);
798 			retops++;
799 			break;
800 		}
801 
802 		/*
803 		 * For NFSv4.1, check for a Sequence Operation being first
804 		 * or one of the other allowed operations by itself.
805 		 */
806 		if ((nd->nd_flag & ND_NFSV41) != 0) {
807 			if (i != 0 && op == NFSV4OP_SEQUENCE)
808 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
809 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
810 			    op != NFSV4OP_EXCHANGEID &&
811 			    op != NFSV4OP_CREATESESSION &&
812 			    op != NFSV4OP_BINDCONNTOSESS &&
813 			    op != NFSV4OP_DESTROYCLIENTID &&
814 			    op != NFSV4OP_DESTROYSESSION)
815 				nd->nd_repstat = NFSERR_OPNOTINSESS;
816 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
817 				nd->nd_repstat = NFSERR_NOTONLYOP;
818 			if (nd->nd_repstat != 0) {
819 				*repp = nfsd_errmap(nd);
820 				retops++;
821 				break;
822 			}
823 		}
824 
825 		nd->nd_procnum = op;
826 		/*
827 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
828 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
829 		 * really nasty for certain Op sequences, I'll play it safe
830 		 * and only return the error at the beginning.) The cache
831 		 * will still function over flood level, but uses lots of
832 		 * mbufs.)
833 		 * If nfsrv_mallocmget_limit() returns True, the system is near
834 		 * to its limit for memory that malloc()/mget() can allocate.
835 		 */
836 		if (i == 0 && (nd->nd_rp == NULL ||
837 		    nd->nd_rp->rc_refcnt == 0) &&
838 		    (nfsrv_mallocmget_limit() ||
839 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
840 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
841 				printf("nfsd server cache flooded, try "
842 				    "increasing vfs.nfsd.tcphighwater\n");
843 			nd->nd_repstat = NFSERR_RESOURCE;
844 			*repp = nfsd_errmap(nd);
845 			if (op == NFSV4OP_SETATTR) {
846 				/*
847 				 * Setattr replies require a bitmap.
848 				 * even for errors like these.
849 				 */
850 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
851 				*tl = 0;
852 			}
853 			retops++;
854 			break;
855 		}
856 		if (nfsv4_opflag[op].savereply)
857 			nd->nd_flag |= ND_SAVEREPLY;
858 		switch (op) {
859 		case NFSV4OP_PUTFH:
860 			error = nfsrv_mtofh(nd, &fh);
861 			if (error)
862 				goto nfsmout;
863 			if (!nd->nd_repstat)
864 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
865 				    NULL, 0);
866 			/* For now, allow this for non-export FHs */
867 			if (!nd->nd_repstat) {
868 				if (vp)
869 					vrele(vp);
870 				vp = nvp;
871 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
872 				NFSVOPUNLOCK(vp, 0);
873 				vpnes = nes;
874 			}
875 			break;
876 		case NFSV4OP_PUTPUBFH:
877 			if (nfs_pubfhset)
878 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
879 				&nes, NULL, 0);
880 			else
881 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
882 			if (!nd->nd_repstat) {
883 				if (vp)
884 					vrele(vp);
885 				vp = nvp;
886 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
887 				NFSVOPUNLOCK(vp, 0);
888 				vpnes = nes;
889 			}
890 			break;
891 		case NFSV4OP_PUTROOTFH:
892 			if (nfs_rootfhset) {
893 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
894 				    &nes, NULL, 0);
895 				if (!nd->nd_repstat) {
896 					if (vp)
897 						vrele(vp);
898 					vp = nvp;
899 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
900 					NFSVOPUNLOCK(vp, 0);
901 					vpnes = nes;
902 				}
903 			} else
904 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
905 			break;
906 		case NFSV4OP_SAVEFH:
907 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
908 				nd->nd_repstat = 0;
909 				/* If vp == savevp, a no-op */
910 				if (vp != savevp) {
911 					if (savevp)
912 						vrele(savevp);
913 					VREF(vp);
914 					savevp = vp;
915 					savevpnes = vpnes;
916 					save_fsid = cur_fsid;
917 				}
918 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
919 					nd->nd_savedcurstateid =
920 					    nd->nd_curstateid;
921 					nd->nd_flag |= ND_SAVEDCURSTATEID;
922 				}
923 			} else {
924 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
925 			}
926 			break;
927 		case NFSV4OP_RESTOREFH:
928 			if (savevp) {
929 				nd->nd_repstat = 0;
930 				/* If vp == savevp, a no-op */
931 				if (vp != savevp) {
932 					VREF(savevp);
933 					vrele(vp);
934 					vp = savevp;
935 					vpnes = savevpnes;
936 					cur_fsid = save_fsid;
937 				}
938 				if ((nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
939 					nd->nd_curstateid =
940 					    nd->nd_savedcurstateid;
941 					nd->nd_flag |= ND_CURSTATEID;
942 				}
943 			} else {
944 				nd->nd_repstat = NFSERR_RESTOREFH;
945 			}
946 			break;
947 		default:
948 		    /*
949 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
950 		     * non-exported directory if
951 		     * nfs_rootfhset. Do I need to allow any other Ops?
952 		     * (You can only have a non-exported vpnes if
953 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
954 		     * Allow AUTH_SYS to be used for file systems
955 		     * exported GSS only for certain Ops, to allow
956 		     * clients to do mounts more easily.
957 		     */
958 		    if (nfsv4_opflag[op].needscfh && vp) {
959 			if (!NFSVNO_EXPORTED(&vpnes) &&
960 			    op != NFSV4OP_LOOKUP &&
961 			    op != NFSV4OP_GETATTR &&
962 			    op != NFSV4OP_GETFH &&
963 			    op != NFSV4OP_ACCESS &&
964 			    op != NFSV4OP_READLINK &&
965 			    op != NFSV4OP_SECINFO)
966 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
967 			else if (nfsvno_testexp(nd, &vpnes) &&
968 			    op != NFSV4OP_LOOKUP &&
969 			    op != NFSV4OP_GETFH &&
970 			    op != NFSV4OP_GETATTR &&
971 			    op != NFSV4OP_SECINFO)
972 				nd->nd_repstat = NFSERR_WRONGSEC;
973 			if (nd->nd_repstat) {
974 				if (op == NFSV4OP_SETATTR) {
975 				    /*
976 				     * Setattr reply requires a bitmap
977 				     * even for errors like these.
978 				     */
979 				    NFSM_BUILD(tl, u_int32_t *,
980 					NFSX_UNSIGNED);
981 				    *tl = 0;
982 				}
983 				break;
984 			}
985 		    }
986 		    if (nfsv4_opflag[op].retfh == 1) {
987 			if (!vp) {
988 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
989 				break;
990 			}
991 			VREF(vp);
992 			if (nfsv4_opflag[op].modifyfs)
993 				vn_start_write(vp, &temp_mp, V_WAIT);
994 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
995 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
996 			if (!error && !nd->nd_repstat) {
997 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
998 				new_mp = nvp->v_mount;
999 				if (cur_fsid.val[0] !=
1000 				    new_mp->mnt_stat.f_fsid.val[0] ||
1001 				    cur_fsid.val[1] !=
1002 				    new_mp->mnt_stat.f_fsid.val[1]) {
1003 				    /* crossed a server mount point */
1004 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
1005 					nd->nd_nam, &nes, &credanon);
1006 				    if (!nd->nd_repstat)
1007 					nd->nd_repstat = nfsd_excred(nd,
1008 					    &nes, credanon);
1009 				    if (credanon != NULL)
1010 					crfree(credanon);
1011 				    if (!nd->nd_repstat) {
1012 					vpnes = nes;
1013 					cur_fsid = new_mp->mnt_stat.f_fsid;
1014 				    }
1015 				}
1016 				/* Lookup ops return a locked vnode */
1017 				NFSVOPUNLOCK(nvp, 0);
1018 			    }
1019 			    if (!nd->nd_repstat) {
1020 				    vrele(vp);
1021 				    vp = nvp;
1022 			    } else
1023 				    vrele(nvp);
1024 			}
1025 			if (nfsv4_opflag[op].modifyfs)
1026 				vn_finished_write(temp_mp);
1027 		    } else if (nfsv4_opflag[op].retfh == 2) {
1028 			if (vp == NULL || savevp == NULL) {
1029 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1030 				break;
1031 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
1032 			    cur_fsid.val[1] != save_fsid.val[1]) {
1033 				nd->nd_repstat = NFSERR_XDEV;
1034 				break;
1035 			}
1036 			if (nfsv4_opflag[op].modifyfs)
1037 				vn_start_write(savevp, &temp_mp, V_WAIT);
1038 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1039 				VREF(vp);
1040 				VREF(savevp);
1041 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1042 				    savevp, vp, &savevpnes, &vpnes);
1043 			} else
1044 				nd->nd_repstat = NFSERR_PERM;
1045 			if (nfsv4_opflag[op].modifyfs)
1046 				vn_finished_write(temp_mp);
1047 		    } else {
1048 			if (nfsv4_opflag[op].retfh != 0)
1049 				panic("nfsrvd_compound");
1050 			if (nfsv4_opflag[op].needscfh) {
1051 				if (vp != NULL) {
1052 					lktype = nfsv4_opflag[op].lktype;
1053 					if (nfsv4_opflag[op].modifyfs) {
1054 						vn_start_write(vp, &temp_mp,
1055 						    V_WAIT);
1056 						if (op == NFSV4OP_WRITE &&
1057 						    MNT_SHARED_WRITES(temp_mp))
1058 							lktype = LK_SHARED;
1059 					}
1060 					if (NFSVOPLOCK(vp, lktype) == 0)
1061 						VREF(vp);
1062 					else
1063 						nd->nd_repstat = NFSERR_PERM;
1064 				} else {
1065 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1066 					if (op == NFSV4OP_SETATTR) {
1067 						/*
1068 						 * Setattr reply requires a
1069 						 * bitmap even for errors like
1070 						 * these.
1071 						 */
1072 						NFSM_BUILD(tl, u_int32_t *,
1073 						    NFSX_UNSIGNED);
1074 						*tl = 0;
1075 					}
1076 					break;
1077 				}
1078 				if (nd->nd_repstat == 0)
1079 					error = (*(nfsrv4_ops0[op]))(nd,
1080 					    isdgram, vp, &vpnes);
1081 				if (nfsv4_opflag[op].modifyfs)
1082 					vn_finished_write(temp_mp);
1083 			} else {
1084 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1085 				    NULL, &vpnes);
1086 			}
1087 		    }
1088 		}
1089 		if (error) {
1090 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1091 				nd->nd_repstat = NFSERR_BADXDR;
1092 			} else {
1093 				nd->nd_repstat = error;
1094 				printf("nfsv4 comperr0=%d\n", error);
1095 			}
1096 			error = 0;
1097 		}
1098 
1099 		if (statsinprog != 0) {
1100 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1101 			    /*then*/ &start_time);
1102 			statsinprog = 0;
1103 		}
1104 
1105 		retops++;
1106 		if (nd->nd_repstat) {
1107 			*repp = nfsd_errmap(nd);
1108 			break;
1109 		} else {
1110 			*repp = 0;	/* NFS4_OK */
1111 		}
1112 	}
1113 nfsmout:
1114 	if (statsinprog != 0) {
1115 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1116 		    /*then*/ &start_time);
1117 		statsinprog = 0;
1118 	}
1119 	if (error) {
1120 		if (error == EBADRPC || error == NFSERR_BADXDR)
1121 			nd->nd_repstat = NFSERR_BADXDR;
1122 		else
1123 			printf("nfsv4 comperr1=%d\n", error);
1124 	}
1125 	if (taglen == -1) {
1126 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1127 		*tl++ = 0;
1128 		*tl = 0;
1129 	} else {
1130 		*retopsp = txdr_unsigned(retops);
1131 	}
1132 	if (vp)
1133 		vrele(vp);
1134 	if (savevp)
1135 		vrele(savevp);
1136 	NFSLOCKV4ROOTMUTEX();
1137 	nfsv4_relref(&nfsv4rootfs_lock);
1138 	NFSUNLOCKV4ROOTMUTEX();
1139 
1140 	NFSEXITCODE2(0, nd);
1141 }
1142