xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
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 #include <fs/nfs/nfsport.h>
44 
45 extern struct nfsrvfh nfs_pubfh;
46 extern int nfs_pubfhset;
47 extern struct nfsv4lock nfsv4rootfs_lock;
48 extern int nfsrv_clienthashsize;
49 extern int nfsd_debuglevel;
50 extern int nfsrv_layouthighwater;
51 extern volatile int nfsrv_layoutcnt;
52 NFSV4ROOTLOCKMUTEX;
53 NFSSTATESPINLOCK;
54 
55 NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst);
56 NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash);
57 NFSD_VNET_DECLARE(int, nfsrc_floodlevel);
58 NFSD_VNET_DECLARE(int, nfsrc_tcpsavedreplies);
59 NFSD_VNET_DECLARE(struct nfsrvfh, nfs_rootfh);
60 NFSD_VNET_DECLARE(int, nfs_rootfhset);
61 NFSD_VNET_DECLARE(struct nfsstatsv1 *, nfsstatsv1_p);
62 
63 int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
64     int, vnode_t , struct nfsexstuff *) = {
65 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
66 	nfsrvd_getattr,
67 	nfsrvd_setattr,
68 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
69 	nfsrvd_access,
70 	nfsrvd_readlink,
71 	nfsrvd_read,
72 	nfsrvd_write,
73 	nfsrvd_create,
74 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
75 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
76 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
77 	nfsrvd_remove,
78 	nfsrvd_remove,
79 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
80 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
81 	nfsrvd_readdir,
82 	nfsrvd_readdirplus,
83 	nfsrvd_statfs,
84 	nfsrvd_fsinfo,
85 	nfsrvd_pathconf,
86 	nfsrvd_commit,
87 };
88 
89 int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
90     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
91 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
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 	nfsrvd_lookup,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
98 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
99 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
100 	nfsrvd_mkdir,
101 	nfsrvd_symlink,
102 	nfsrvd_mknod,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
111 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
112 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
113 };
114 
115 int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
116     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
129 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
130 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
131 	nfsrvd_rename,
132 	nfsrvd_link,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
137 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
138 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
139 };
140 
141 int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *,
142     int, vnode_t , struct nfsexstuff *) = {
143 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
144 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
145 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
146 	nfsrvd_access,
147 	nfsrvd_close,
148 	nfsrvd_commit,
149 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
150 	nfsrvd_delegpurge,
151 	nfsrvd_delegreturn,
152 	nfsrvd_getattr,
153 	nfsrvd_getfh,
154 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
155 	nfsrvd_lock,
156 	nfsrvd_lockt,
157 	nfsrvd_locku,
158 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
159 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
160 	nfsrvd_verify,
161 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
162 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
163 	nfsrvd_openconfirm,
164 	nfsrvd_opendowngrade,
165 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
166 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
167 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
168 	nfsrvd_read,
169 	nfsrvd_readdirplus,
170 	nfsrvd_readlink,
171 	nfsrvd_remove,
172 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
173 	nfsrvd_renew,
174 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
175 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
176 	nfsrvd_secinfo,
177 	nfsrvd_setattr,
178 	nfsrvd_setclientid,
179 	nfsrvd_setclientidcfrm,
180 	nfsrvd_verify,
181 	nfsrvd_write,
182 	nfsrvd_releaselckown,
183 	nfsrvd_notsupp,
184 	nfsrvd_bindconnsess,
185 	nfsrvd_exchangeid,
186 	nfsrvd_createsession,
187 	nfsrvd_destroysession,
188 	nfsrvd_freestateid,
189 	nfsrvd_notsupp,
190 	nfsrvd_getdevinfo,
191 	nfsrvd_notsupp,
192 	nfsrvd_layoutcommit,
193 	nfsrvd_layoutget,
194 	nfsrvd_layoutreturn,
195 	nfsrvd_secinfononame,
196 	nfsrvd_sequence,
197 	nfsrvd_notsupp,
198 	nfsrvd_teststateid,
199 	nfsrvd_notsupp,
200 	nfsrvd_destroyclientid,
201 	nfsrvd_reclaimcomplete,
202 	nfsrvd_allocate,
203 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
204 	nfsrvd_notsupp,
205 	nfsrvd_deallocate,
206 	nfsrvd_ioadvise,
207 	nfsrvd_layouterror,
208 	nfsrvd_layoutstats,
209 	nfsrvd_notsupp,
210 	nfsrvd_notsupp,
211 	nfsrvd_notsupp,
212 	nfsrvd_seek,
213 	nfsrvd_notsupp,
214 	nfsrvd_notsupp,
215 	nfsrvd_getxattr,
216 	nfsrvd_setxattr,
217 	nfsrvd_listxattr,
218 	nfsrvd_rmxattr,
219 };
220 
221 int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *,
222     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
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 	nfsrvd_mknod,
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 	nfsrvd_lookup,
239 	nfsrvd_lookup,
240 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
241 	nfsrvd_open,
242 	nfsrvd_openattr,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
297 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
298 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
299 };
300 
301 int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *,
302     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
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 	nfsrvd_link,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
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 	nfsrvd_rename,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
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 	nfsrvd_copy_file_range,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
377 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
378 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
379 };
380 
381 /*
382  * Static array that defines which nfs rpc's are nonidempotent
383  */
384 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
385 	FALSE,
386 	FALSE,
387 	TRUE,
388 	FALSE,
389 	FALSE,
390 	FALSE,
391 	FALSE,
392 	TRUE,
393 	TRUE,
394 	TRUE,
395 	TRUE,
396 	TRUE,
397 	TRUE,
398 	TRUE,
399 	TRUE,
400 	TRUE,
401 	FALSE,
402 	FALSE,
403 	FALSE,
404 	FALSE,
405 	FALSE,
406 	FALSE,
407 };
408 
409 /*
410  * This static array indicates whether or not the RPC modifies the
411  * file system.
412  */
413 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
414     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
415     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
416 
417 SYSCTL_DECL(_vfs_nfsd);
418 static int	nfs_minminorv4 = NFSV4_MINORVERSION;
419 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN,
420     &nfs_minminorv4, 0,
421     "The lowest minor version of NFSv4 handled by the server");
422 
423 static int	nfs_maxminorv4 = NFSV42_MINORVERSION;
424 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN,
425     &nfs_maxminorv4, 0,
426     "The highest minor version of NFSv4 handled by the server");
427 
428 /* local functions */
429 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
430     u_char *tag, int taglen, u_int32_t minorvers);
431 
432 /*
433  * This static array indicates which server procedures require the extra
434  * arguments to return the current file handle for V2, 3.
435  */
436 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
437 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
438 
439 extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];
440 
441 static int nfsv3to4op[NFS_V3NPROCS] = {
442 	NFSPROC_NULL,
443 	NFSV4OP_GETATTR,
444 	NFSV4OP_SETATTR,
445 	NFSV4OP_LOOKUP,
446 	NFSV4OP_ACCESS,
447 	NFSV4OP_READLINK,
448 	NFSV4OP_READ,
449 	NFSV4OP_WRITE,
450 	NFSV4OP_V3CREATE,
451 	NFSV4OP_MKDIR,
452 	NFSV4OP_SYMLINK,
453 	NFSV4OP_MKNOD,
454 	NFSV4OP_REMOVE,
455 	NFSV4OP_RMDIR,
456 	NFSV4OP_RENAME,
457 	NFSV4OP_LINK,
458 	NFSV4OP_READDIR,
459 	NFSV4OP_READDIRPLUS,
460 	NFSV4OP_FSSTAT,
461 	NFSV4OP_FSINFO,
462 	NFSV4OP_PATHCONF,
463 	NFSV4OP_COMMIT,
464 };
465 
466 static struct mtx nfsrvd_statmtx;
467 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
468 
469 static void
470 nfsrvd_statstart(int op, struct bintime *now)
471 {
472 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
473 		printf("%s: op %d invalid\n", __func__, op);
474 		return;
475 	}
476 
477 	mtx_lock(&nfsrvd_statmtx);
478 	if (NFSD_VNET(nfsstatsv1_p)->srvstartcnt ==
479 	    NFSD_VNET(nfsstatsv1_p)->srvdonecnt) {
480 		if (now != NULL)
481 			NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;
482 		else
483 			binuptime(&NFSD_VNET(nfsstatsv1_p)->busyfrom);
484 
485 	}
486 	NFSD_VNET(nfsstatsv1_p)->srvrpccnt[op]++;
487 	NFSD_VNET(nfsstatsv1_p)->srvstartcnt++;
488 	mtx_unlock(&nfsrvd_statmtx);
489 
490 }
491 
492 static void
493 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
494     struct bintime *then)
495 {
496 	struct bintime dt, lnow;
497 
498 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
499 		printf("%s: op %d invalid\n", __func__, op);
500 		return;
501 	}
502 
503 	if (now == NULL) {
504 		now = &lnow;
505 		binuptime(now);
506 	}
507 
508 	mtx_lock(&nfsrvd_statmtx);
509 
510 	NFSD_VNET(nfsstatsv1_p)->srvbytes[op] += bytes;
511 	NFSD_VNET(nfsstatsv1_p)->srvops[op]++;
512 
513 	if (then != NULL) {
514 		dt = *now;
515 		bintime_sub(&dt, then);
516 		bintime_add(&NFSD_VNET(nfsstatsv1_p)->srvduration[op], &dt);
517 	}
518 
519 	dt = *now;
520 	bintime_sub(&dt, &NFSD_VNET(nfsstatsv1_p)->busyfrom);
521 	bintime_add(&NFSD_VNET(nfsstatsv1_p)->busytime, &dt);
522 	NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;
523 
524 	NFSD_VNET(nfsstatsv1_p)->srvdonecnt++;
525 
526 	mtx_unlock(&nfsrvd_statmtx);
527 }
528 
529 /*
530  * Do an RPC. Basically, get the file handles translated to vnode pointers
531  * and then call the appropriate server routine. The server routines are
532  * split into groups, based on whether they use a file handle or file
533  * handle plus name or ...
534  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
535  */
536 void
537 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
538     u_int32_t minorvers)
539 {
540 	int error = 0, lktype;
541 	vnode_t vp;
542 	mount_t mp;
543 	struct nfsrvfh fh;
544 	struct nfsexstuff nes;
545 	struct mbuf *md;
546 	char *dpos;
547 
548 	/*
549 	 * Save the current position in the request mbuf list so
550 	 * that a rollback to this location can be done upon an
551 	 * ERELOOKUP error return from an RPC function.
552 	 */
553 	md = nd->nd_md;
554 	dpos = nd->nd_dpos;
555 tryagain:
556 	mp = NULL;
557 
558 	/*
559 	 * Get a locked vnode for the first file handle
560 	 */
561 	if (!(nd->nd_flag & ND_NFSV4)) {
562 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
563 		/*
564 		 * For NFSv3, if the malloc/mget allocation is near limits,
565 		 * return NFSERR_DELAY.
566 		 */
567 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
568 			nd->nd_repstat = NFSERR_DELAY;
569 			vp = NULL;
570 		} else {
571 			error = nfsrv_mtofh(nd, &fh);
572 			if (error) {
573 				if (error != EBADRPC)
574 					printf("nfs dorpc err1=%d\n", error);
575 				nd->nd_repstat = NFSERR_GARBAGE;
576 				goto out;
577 			}
578 			if (nd->nd_procnum == NFSPROC_READ ||
579 			    nd->nd_procnum == NFSPROC_WRITE ||
580 			    nd->nd_procnum == NFSPROC_READDIR ||
581 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
582 			    nd->nd_procnum == NFSPROC_READLINK ||
583 			    nd->nd_procnum == NFSPROC_GETATTR ||
584 			    nd->nd_procnum == NFSPROC_ACCESS ||
585 			    nd->nd_procnum == NFSPROC_FSSTAT ||
586 			    nd->nd_procnum == NFSPROC_FSINFO)
587 				lktype = LK_SHARED;
588 			else
589 				lktype = LK_EXCLUSIVE;
590 			if (nd->nd_flag & ND_PUBLOOKUP)
591 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
592 				    &mp, nfsrv_writerpc[nd->nd_procnum], -1);
593 			else
594 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
595 				    &mp, nfsrv_writerpc[nd->nd_procnum], -1);
596 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
597 				goto out;
598 		}
599 	}
600 
601 	/*
602 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
603 	 * cache, as required.
604 	 * For V4, nfsrvd_compound() does this.
605 	 */
606 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
607 		nd->nd_flag |= ND_SAVEREPLY;
608 
609 	nfsrvd_rephead(nd);
610 	/*
611 	 * If nd_repstat is non-zero, just fill in the reply status
612 	 * to complete the RPC reply for V2. Otherwise, you must do
613 	 * the RPC.
614 	 */
615 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
616 		*nd->nd_errp = nfsd_errmap(nd);
617 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
618 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
619 		   /*now*/ NULL, /*then*/ NULL);
620 		vn_finished_write(mp);
621 		goto out;
622 	}
623 
624 	/*
625 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
626 	 * works through the sub-rpcs, otherwise just call the procedure.
627 	 * The procedures are in three groups with different arguments.
628 	 * The group is indicated by the value in nfs_retfh[].
629 	 */
630 	if (nd->nd_flag & ND_NFSV4) {
631 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers);
632 	} else {
633 		struct bintime start_time;
634 
635 		binuptime(&start_time);
636 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
637 
638 		if (nfs_retfh[nd->nd_procnum] == 1) {
639 			if (vp)
640 				NFSVOPUNLOCK(vp);
641 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
642 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes);
643 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
644 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
645 			    vp, NULL, &nes, NULL);
646 		} else {
647 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
648 			    vp, &nes);
649 		}
650 		vn_finished_write(mp);
651 
652 		if (error == 0 && nd->nd_repstat == ERELOOKUP) {
653 			/*
654 			 * Roll back to the beginning of the RPC request
655 			 * arguments.
656 			 */
657 			nd->nd_md = md;
658 			nd->nd_dpos = dpos;
659 
660 			/* Free the junk RPC reply and redo the RPC. */
661 			m_freem(nd->nd_mreq);
662 			nd->nd_mreq = nd->nd_mb = NULL;
663 			nd->nd_repstat = 0;
664 			goto tryagain;
665 		}
666 
667 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
668 		    /*now*/ NULL, /*then*/ &start_time);
669 	}
670 	if (error) {
671 		if (error != EBADRPC)
672 			printf("nfs dorpc err2=%d\n", error);
673 		nd->nd_repstat = NFSERR_GARBAGE;
674 	}
675 	*nd->nd_errp = nfsd_errmap(nd);
676 
677 	/*
678 	 * Don't cache certain reply status values.
679 	 */
680 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
681 	    (nd->nd_repstat == NFSERR_GARBAGE ||
682 	     nd->nd_repstat == NFSERR_BADXDR ||
683 	     nd->nd_repstat == NFSERR_MOVED ||
684 	     nd->nd_repstat == NFSERR_DELAY ||
685 	     nd->nd_repstat == NFSERR_BADSEQID ||
686 	     nd->nd_repstat == NFSERR_RESOURCE ||
687 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
688 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
689 	     nd->nd_repstat == NFSERR_STALESTATEID ||
690 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
691 	     nd->nd_repstat == NFSERR_BADSTATEID ||
692 	     nd->nd_repstat == NFSERR_GRACE ||
693 	     nd->nd_repstat == NFSERR_NOGRACE))
694 		nd->nd_flag &= ~ND_SAVEREPLY;
695 
696 out:
697 	NFSEXITCODE2(0, nd);
698 }
699 
700 /*
701  * Breaks down a compound RPC request and calls the server routines for
702  * the subprocedures.
703  * Some suboperations are performed directly here to simplify file handle<-->
704  * vnode pointer handling.
705  */
706 static void
707 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
708     int taglen, u_int32_t minorvers)
709 {
710 	int i, lktype, op, op0 = 0, rstat, statsinprog = 0;
711 	u_int32_t *tl;
712 	struct nfsclient *clp, *nclp;
713 	int error = 0, igotlock, nextop, numops, savefhcnt;
714 	u_int32_t retops = 0, *retopsp = NULL, *repp;
715 	vnode_t vp, nvp, savevp;
716 	struct nfsrvfh fh;
717 	mount_t new_mp, temp_mp = NULL;
718 	struct ucred *credanon;
719 	struct nfsexstuff nes, vpnes, savevpnes;
720 	fsid_t cur_fsid, save_fsid;
721 	static u_int64_t compref = 0;
722 	struct bintime start_time;
723 	struct thread *p;
724 	struct mbuf *mb, *md;
725 	char *bpos, *dpos;
726 	int bextpg, bextpgsiz;
727 
728 	p = curthread;
729 
730 	/* Check for and optionally clear the no space flags for DSs. */
731 	nfsrv_checknospc();
732 
733 	NFSVNO_EXINIT(&vpnes);
734 	NFSVNO_EXINIT(&savevpnes);
735 	/*
736 	 * Put the seq# of the current compound RPC in nfsrv_descript.
737 	 * (This is used by nfsrv_checkgetattr(), to see if the write
738 	 *  delegation was created by the same compound RPC as the one
739 	 *  with that Getattr in it.)
740 	 * Don't worry about the 64bit number wrapping around. It ain't
741 	 * gonna happen before this server gets shut down/rebooted.
742 	 */
743 	nd->nd_compref = compref++;
744 
745 	/*
746 	 * Check for and optionally get a lock on the root. This lock means that
747 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
748 	 * is required when the V4 root is being changed, the stable storage
749 	 * restart file is being updated, or callbacks are being done.
750 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
751 	 * either hold a reference count (nfs_usecnt) or the lock. When
752 	 * nfsrv_unlock() is called to release the lock, it can optionally
753 	 * also get a reference count, which saves the need for a call to
754 	 * nfsrv_getref() after nfsrv_unlock().
755 	 */
756 	/*
757 	 * First, check to see if we need to wait for an update lock.
758 	 */
759 	igotlock = 0;
760 	NFSLOCKV4ROOTMUTEX();
761 	if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NEEDLOCK)
762 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
763 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
764 	else
765 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
766 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
767 	NFSUNLOCKV4ROOTMUTEX();
768 	if (igotlock) {
769 		/*
770 		 * If I got the lock, I can update the stable storage file.
771 		 * Done when the grace period is over or a client has long
772 		 * since expired.
773 		 */
774 		NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_NEEDLOCK;
775 		if ((NFSD_VNET(nfsrv_stablefirst).nsf_flags &
776 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
777 			nfsrv_updatestable(p);
778 
779 		/*
780 		 * If at least one client has long since expired, search
781 		 * the client list for them, write a REVOKE record on the
782 		 * stable storage file and then remove them from the client
783 		 * list.
784 		 */
785 		if (NFSD_VNET(nfsrv_stablefirst).nsf_flags &
786 		    NFSNSF_EXPIREDCLIENT) {
787 			NFSD_VNET(nfsrv_stablefirst).nsf_flags &=
788 			    ~NFSNSF_EXPIREDCLIENT;
789 			for (i = 0; i < nfsrv_clienthashsize; i++) {
790 			    LIST_FOREACH_SAFE(clp, &NFSD_VNET(nfsclienthash)[i],
791 				lc_hash, nclp) {
792 				if (clp->lc_flags & LCL_EXPIREIT) {
793 				    if (!LIST_EMPTY(&clp->lc_open) ||
794 					!LIST_EMPTY(&clp->lc_deleg))
795 					nfsrv_writestable(clp->lc_id,
796 					    clp->lc_idlen, NFSNST_REVOKE, p);
797 				    nfsrv_cleanclient(clp, p);
798 				    nfsrv_freedeleglist(&clp->lc_deleg);
799 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
800 				    LIST_REMOVE(clp, lc_hash);
801 				    nfsrv_zapclient(clp, p);
802 				}
803 			    }
804 			}
805 		}
806 		NFSLOCKV4ROOTMUTEX();
807 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
808 		NFSUNLOCKV4ROOTMUTEX();
809 	} else {
810 		/*
811 		 * If we didn't get the lock, we need to get a refcnt,
812 		 * which also checks for and waits for the lock.
813 		 */
814 		NFSLOCKV4ROOTMUTEX();
815 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
816 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
817 		NFSUNLOCKV4ROOTMUTEX();
818 	}
819 
820 	/*
821 	 * If flagged, search for open owners that haven't had any opens
822 	 * for a long time.
823 	 */
824 	if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NOOPENS) {
825 		nfsrv_throwawayopens(p);
826 	}
827 
828 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
829 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
830 		nfsrv_recalloldlayout(p);
831 
832 	savevp = vp = NULL;
833 	save_fsid.val[0] = save_fsid.val[1] = 0;
834 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
835 	nextop = -1;
836 	savefhcnt = 0;
837 
838 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
839 	if (taglen < 0) {
840 		error = EBADRPC;
841 		goto nfsmout;
842 	}
843 
844 	(void) nfsm_strtom(nd, tag, taglen);
845 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
846 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
847 	if ((minorvers != NFSV4_MINORVERSION &&
848 	    minorvers != NFSV41_MINORVERSION &&
849 	    minorvers != NFSV42_MINORVERSION) ||
850 	    minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)
851 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
852 	if (nd->nd_repstat)
853 		numops = 0;
854 	else
855 		numops = fxdr_unsigned(int, *tl);
856 	/*
857 	 * Loop around doing the sub ops.
858 	 * vp - is an unlocked vnode pointer for the CFH
859 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
860 	 * (at some future date, it might turn out to be more appropriate
861 	 *  to keep the file handles instead of vnode pointers?)
862 	 * savevpnes and vpnes - are the export flags for the above.
863 	 */
864 	for (i = 0; i < numops; i++) {
865 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
866 		if (savefhcnt > 0) {
867 			op = NFSV4OP_SAVEFH;
868 			*repp = txdr_unsigned(op);
869 			savefhcnt--;
870 		} else if (nextop == -1) {
871 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
872 			*repp = *tl;
873 			op = fxdr_unsigned(int, *tl);
874 		} else {
875 			op = nextop;
876 			*repp = txdr_unsigned(op);
877 			nextop = -1;
878 		}
879 		NFSD_DEBUG(4, "op=%d\n", op);
880 		if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
881 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
882 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {
883 			nd->nd_repstat = NFSERR_OPILLEGAL;
884 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
885 			*repp = nfsd_errmap(nd);
886 			retops++;
887 			break;
888 		} else {
889 			repp++;
890 		}
891 
892 		binuptime(&start_time);
893 		nfsrvd_statstart(op, &start_time);
894 		statsinprog = 1;
895 
896 		if (i == 0)
897 			op0 = op;
898 		if (i == numops - 1)
899 			nd->nd_flag |= ND_LASTOP;
900 
901 		/*
902 		 * Check for a referral on the current FH and, if so, return
903 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
904 		 */
905 		if (vp != NULL && op != NFSV4OP_GETATTR &&
906 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
907 		    nfsrv_errmoved(op)) {
908 			nd->nd_repstat = NFSERR_MOVED;
909 			*repp = nfsd_errmap(nd);
910 			retops++;
911 			break;
912 		}
913 
914 		/*
915 		 * For NFSv4.1, check for a Sequence Operation being first
916 		 * or one of the other allowed operations by itself.
917 		 */
918 		if ((nd->nd_flag & ND_NFSV41) != 0) {
919 			if (i != 0 && op == NFSV4OP_SEQUENCE)
920 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
921 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
922 			    op != NFSV4OP_EXCHANGEID &&
923 			    op != NFSV4OP_CREATESESSION &&
924 			    op != NFSV4OP_BINDCONNTOSESS &&
925 			    op != NFSV4OP_DESTROYCLIENTID &&
926 			    op != NFSV4OP_DESTROYSESSION)
927 				nd->nd_repstat = NFSERR_OPNOTINSESS;
928 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
929 				nd->nd_repstat = NFSERR_NOTONLYOP;
930 			if (nd->nd_repstat != 0) {
931 				*repp = nfsd_errmap(nd);
932 				retops++;
933 				break;
934 			}
935 		}
936 
937 		nd->nd_procnum = op;
938 		/*
939 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
940 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
941 		 * really nasty for certain Op sequences, I'll play it safe
942 		 * and only return the error at the beginning.) The cache
943 		 * will still function over flood level, but uses lots of
944 		 * mbufs.)
945 		 * If nfsrv_mallocmget_limit() returns True, the system is near
946 		 * to its limit for memory that malloc()/mget() can allocate.
947 		 */
948 		if (i == 0 && (nd->nd_rp == NULL ||
949 		    nd->nd_rp->rc_refcnt == 0) &&
950 		    (nfsrv_mallocmget_limit() ||
951 		     NFSD_VNET(nfsrc_tcpsavedreplies) >
952 		     NFSD_VNET(nfsrc_floodlevel))) {
953 			if (NFSD_VNET(nfsrc_tcpsavedreplies) >
954 			    NFSD_VNET(nfsrc_floodlevel))
955 				printf("nfsd server cache flooded, try "
956 				    "increasing vfs.nfsd.tcphighwater\n");
957 			nd->nd_repstat = NFSERR_RESOURCE;
958 			*repp = nfsd_errmap(nd);
959 			if (op == NFSV4OP_SETATTR) {
960 				/*
961 				 * Setattr replies require a bitmap.
962 				 * even for errors like these.
963 				 */
964 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
965 				*tl = 0;
966 			}
967 			retops++;
968 			break;
969 		}
970 		if (nfsv4_opflag[op].savereply)
971 			nd->nd_flag |= ND_SAVEREPLY;
972 		switch (op) {
973 		case NFSV4OP_PUTFH:
974 			error = nfsrv_mtofh(nd, &fh);
975 			if (error)
976 				goto nfsmout;
977 			if ((nd->nd_flag & ND_LASTOP) == 0) {
978 				/*
979 				 * Pre-parse the next op#.  If it is
980 				 * SaveFH, count it and skip to the
981 				 * next op#, if not the last op#.
982 				 * nextop is used to determine if
983 				 * NFSERR_WRONGSEC can be returned,
984 				 * per RFC5661 Sec. 2.6.
985 				 */
986 				do {
987 					NFSM_DISSECT(tl, uint32_t *,
988 					    NFSX_UNSIGNED);
989 					nextop = fxdr_unsigned(int, *tl);
990 					if (nextop == NFSV4OP_SAVEFH &&
991 					    i < numops - 1)
992 						savefhcnt++;
993 				} while (nextop == NFSV4OP_SAVEFH &&
994 				    i < numops - 1);
995 			}
996 			if (!nd->nd_repstat)
997 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
998 				    NULL, 0, nextop);
999 			/* For now, allow this for non-export FHs */
1000 			if (!nd->nd_repstat) {
1001 				if (vp)
1002 					vrele(vp);
1003 				vp = nvp;
1004 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1005 				NFSVOPUNLOCK(vp);
1006 				vpnes = nes;
1007 			}
1008 			break;
1009 		case NFSV4OP_PUTPUBFH:
1010 			if (nfs_pubfhset) {
1011 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1012 					/*
1013 					 * Pre-parse the next op#.  If it is
1014 					 * SaveFH, count it and skip to the
1015 					 * next op#, if not the last op#.
1016 					 * nextop is used to determine if
1017 					 * NFSERR_WRONGSEC can be returned,
1018 					 * per RFC5661 Sec. 2.6.
1019 					 */
1020 					do {
1021 						NFSM_DISSECT(tl, uint32_t *,
1022 						    NFSX_UNSIGNED);
1023 						nextop = fxdr_unsigned(int,
1024 						    *tl);
1025 						if (nextop == NFSV4OP_SAVEFH &&
1026 						    i < numops - 1)
1027 							savefhcnt++;
1028 					} while (nextop == NFSV4OP_SAVEFH &&
1029 					    i < numops - 1);
1030 				}
1031 				nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
1032 				    &nes, NULL, 0, nextop);
1033 			} else
1034 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1035 			if (!nd->nd_repstat) {
1036 				if (vp)
1037 					vrele(vp);
1038 				vp = nvp;
1039 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1040 				NFSVOPUNLOCK(vp);
1041 				vpnes = nes;
1042 			}
1043 			break;
1044 		case NFSV4OP_PUTROOTFH:
1045 			if (NFSD_VNET(nfs_rootfhset)) {
1046 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1047 					/*
1048 					 * Pre-parse the next op#.  If it is
1049 					 * SaveFH, count it and skip to the
1050 					 * next op#, if not the last op#.
1051 					 * nextop is used to determine if
1052 					 * NFSERR_WRONGSEC can be returned,
1053 					 * per RFC5661 Sec. 2.6.
1054 					 */
1055 					do {
1056 						NFSM_DISSECT(tl, uint32_t *,
1057 						    NFSX_UNSIGNED);
1058 						nextop = fxdr_unsigned(int,
1059 						    *tl);
1060 						if (nextop == NFSV4OP_SAVEFH &&
1061 						    i < numops - 1)
1062 							savefhcnt++;
1063 					} while (nextop == NFSV4OP_SAVEFH &&
1064 					    i < numops - 1);
1065 				}
1066 				nfsd_fhtovp(nd, &NFSD_VNET(nfs_rootfh),
1067 				    LK_SHARED, &nvp, &nes, NULL, 0, nextop);
1068 				if (!nd->nd_repstat) {
1069 					if (vp)
1070 						vrele(vp);
1071 					vp = nvp;
1072 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1073 					NFSVOPUNLOCK(vp);
1074 					vpnes = nes;
1075 				}
1076 			} else
1077 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1078 			break;
1079 		case NFSV4OP_SAVEFH:
1080 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
1081 				nd->nd_repstat = 0;
1082 				/* If vp == savevp, a no-op */
1083 				if (vp != savevp) {
1084 					if (savevp)
1085 						vrele(savevp);
1086 					VREF(vp);
1087 					savevp = vp;
1088 					savevpnes = vpnes;
1089 					save_fsid = cur_fsid;
1090 				}
1091 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
1092 					nd->nd_savedcurstateid =
1093 					    nd->nd_curstateid;
1094 					nd->nd_flag |= ND_SAVEDCURSTATEID;
1095 				}
1096 			} else {
1097 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1098 			}
1099 			break;
1100 		case NFSV4OP_RESTOREFH:
1101 			if (savevp) {
1102 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1103 					/*
1104 					 * Pre-parse the next op#.  If it is
1105 					 * SaveFH, count it and skip to the
1106 					 * next op#, if not the last op#.
1107 					 * nextop is used to determine if
1108 					 * NFSERR_WRONGSEC can be returned,
1109 					 * per RFC5661 Sec. 2.6.
1110 					 */
1111 					do {
1112 						NFSM_DISSECT(tl, uint32_t *,
1113 						    NFSX_UNSIGNED);
1114 						nextop = fxdr_unsigned(int,
1115 						    *tl);
1116 						if (nextop == NFSV4OP_SAVEFH &&
1117 						    i < numops - 1)
1118 							savefhcnt++;
1119 					} while (nextop == NFSV4OP_SAVEFH &&
1120 					    i < numops - 1);
1121 				}
1122 				nd->nd_repstat = 0;
1123 				/* If vp == savevp, a no-op */
1124 				if (vp != savevp) {
1125 					if (nfsrv_checkwrongsec(nd, nextop,
1126 					    savevp->v_type))
1127 						nd->nd_repstat =
1128 						    nfsvno_testexp(nd,
1129 						    &savevpnes);
1130 					if (nd->nd_repstat == 0) {
1131 						VREF(savevp);
1132 						vrele(vp);
1133 						vp = savevp;
1134 						vpnes = savevpnes;
1135 						cur_fsid = save_fsid;
1136 					}
1137 				}
1138 				if (nd->nd_repstat == 0 &&
1139 				     (nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
1140 					nd->nd_curstateid =
1141 					    nd->nd_savedcurstateid;
1142 					nd->nd_flag |= ND_CURSTATEID;
1143 				}
1144 			} else {
1145 				nd->nd_repstat = NFSERR_RESTOREFH;
1146 			}
1147 			break;
1148 		default:
1149 		    /*
1150 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
1151 		     * non-exported directory if
1152 		     * nfs_rootfhset. Do I need to allow any other Ops?
1153 		     * (You can only have a non-exported vpnes if
1154 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
1155 		     * Allow AUTH_SYS to be used for file systems
1156 		     * exported GSS only for certain Ops, to allow
1157 		     * clients to do mounts more easily.
1158 		     */
1159 		    if (nfsv4_opflag[op].needscfh && vp) {
1160 			if (!NFSVNO_EXPORTED(&vpnes) &&
1161 			    op != NFSV4OP_LOOKUP &&
1162 			    op != NFSV4OP_GETATTR &&
1163 			    op != NFSV4OP_GETFH &&
1164 			    op != NFSV4OP_ACCESS &&
1165 			    op != NFSV4OP_READLINK &&
1166 			    op != NFSV4OP_SECINFO &&
1167 			    op != NFSV4OP_SECINFONONAME)
1168 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1169 			if (nd->nd_repstat) {
1170 				if (op == NFSV4OP_SETATTR) {
1171 				    /*
1172 				     * Setattr reply requires a bitmap
1173 				     * even for errors like these.
1174 				     */
1175 				    NFSM_BUILD(tl, u_int32_t *,
1176 					NFSX_UNSIGNED);
1177 				    *tl = 0;
1178 				}
1179 				break;
1180 			}
1181 		    }
1182 
1183 		    /*
1184 		     * Save the current positions in the mbuf lists so
1185 		     * that a rollback to this location can be done upon a
1186 		     * redo due to a ERELOOKUP return for a operation.
1187 		     */
1188 		    mb = nd->nd_mb;
1189 		    bpos = nd->nd_bpos;
1190 		    bextpg = nd->nd_bextpg;
1191 		    bextpgsiz = nd->nd_bextpgsiz;
1192 		    md = nd->nd_md;
1193 		    dpos = nd->nd_dpos;
1194 tryagain:
1195 
1196 		    if (nfsv4_opflag[op].retfh == 1) {
1197 			if (!vp) {
1198 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1199 				break;
1200 			}
1201 			if (NFSVNO_EXPORTED(&vpnes) && (op == NFSV4OP_LOOKUP ||
1202 			    op == NFSV4OP_LOOKUPP || (op == NFSV4OP_OPEN &&
1203 			    vp->v_type == VDIR))) {
1204 				/* Check for wrong security. */
1205 				rstat = nfsvno_testexp(nd, &vpnes);
1206 				if (rstat != 0) {
1207 					nd->nd_repstat = rstat;
1208 					break;
1209 				}
1210 			}
1211 			VREF(vp);
1212 			if (nfsv4_opflag[op].modifyfs)
1213 				vn_start_write(vp, &temp_mp, V_WAIT);
1214 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
1215 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
1216 			if (!error && !nd->nd_repstat) {
1217 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
1218 				new_mp = nvp->v_mount;
1219 				if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) {
1220 				    /* crossed a server mount point */
1221 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
1222 					nd->nd_nam, &nes, &credanon);
1223 				    if (!nd->nd_repstat)
1224 					nd->nd_repstat = nfsd_excred(nd,
1225 					    &nes, credanon, true);
1226 				    if (credanon != NULL)
1227 					crfree(credanon);
1228 				    if (!nd->nd_repstat) {
1229 					vpnes = nes;
1230 					cur_fsid = new_mp->mnt_stat.f_fsid;
1231 				    }
1232 				}
1233 				/* Lookup ops return a locked vnode */
1234 				NFSVOPUNLOCK(nvp);
1235 			    }
1236 			    if (!nd->nd_repstat) {
1237 				    vrele(vp);
1238 				    vp = nvp;
1239 			    } else
1240 				    vrele(nvp);
1241 			}
1242 			if (nfsv4_opflag[op].modifyfs)
1243 				vn_finished_write(temp_mp);
1244 		    } else if (nfsv4_opflag[op].retfh == 2) {
1245 			if (vp == NULL || savevp == NULL) {
1246 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1247 				break;
1248 			} else if (fsidcmp(&cur_fsid, &save_fsid) != 0) {
1249 				nd->nd_repstat = NFSERR_XDEV;
1250 				break;
1251 			}
1252 			if (nfsv4_opflag[op].modifyfs)
1253 				vn_start_write(savevp, &temp_mp, V_WAIT);
1254 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1255 				VREF(vp);
1256 				VREF(savevp);
1257 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1258 				    savevp, vp, &savevpnes, &vpnes);
1259 			} else
1260 				nd->nd_repstat = NFSERR_PERM;
1261 			if (nfsv4_opflag[op].modifyfs)
1262 				vn_finished_write(temp_mp);
1263 		    } else {
1264 			if (nfsv4_opflag[op].retfh != 0)
1265 				panic("nfsrvd_compound");
1266 			if (nfsv4_opflag[op].needscfh) {
1267 				if (vp != NULL) {
1268 					lktype = nfsv4_opflag[op].lktype;
1269 					if (nfsv4_opflag[op].modifyfs) {
1270 						vn_start_write(vp, &temp_mp,
1271 						    V_WAIT);
1272 						if (op == NFSV4OP_WRITE &&
1273 						    MNT_SHARED_WRITES(temp_mp))
1274 							lktype = LK_SHARED;
1275 					}
1276 					if (NFSVOPLOCK(vp, lktype) == 0)
1277 						VREF(vp);
1278 					else
1279 						nd->nd_repstat = NFSERR_PERM;
1280 				} else {
1281 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1282 					if (op == NFSV4OP_SETATTR) {
1283 						/*
1284 						 * Setattr reply requires a
1285 						 * bitmap even for errors like
1286 						 * these.
1287 						 */
1288 						NFSM_BUILD(tl, u_int32_t *,
1289 						    NFSX_UNSIGNED);
1290 						*tl = 0;
1291 					}
1292 					break;
1293 				}
1294 				if (nd->nd_repstat == 0) {
1295 					error = (*(nfsrv4_ops0[op]))(nd,
1296 					    isdgram, vp, &vpnes);
1297 					if ((op == NFSV4OP_SECINFO ||
1298 					     op == NFSV4OP_SECINFONONAME) &&
1299 					    error == 0 && nd->nd_repstat == 0) {
1300 						/*
1301 						 * Secinfo and Secinfo_no_name
1302 						 * consume the current FH.
1303 						 */
1304 						vrele(vp);
1305 						vp = NULL;
1306 					}
1307 				}
1308 				if (nfsv4_opflag[op].modifyfs)
1309 					vn_finished_write(temp_mp);
1310 			} else {
1311 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1312 				    NULL, &vpnes);
1313 			}
1314 		    }
1315 		}
1316 		if (error) {
1317 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1318 				nd->nd_repstat = NFSERR_BADXDR;
1319 			} else {
1320 				nd->nd_repstat = error;
1321 				printf("nfsv4 comperr0=%d\n", error);
1322 			}
1323 			error = 0;
1324 		}
1325 
1326 		if (nd->nd_repstat == ERELOOKUP) {
1327 			/*
1328 			 * Roll back to the beginning of the operation
1329 			 * arguments.
1330 			 */
1331 			nd->nd_md = md;
1332 			nd->nd_dpos = dpos;
1333 
1334 			/*
1335 			 * Trim off the bogus reply for this operation
1336 			 * and redo the operation.
1337 			 */
1338 			nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);
1339 			nd->nd_repstat = 0;
1340 			nd->nd_flag |= ND_ERELOOKUP;
1341 			goto tryagain;
1342 		}
1343 		nd->nd_flag &= ~ND_ERELOOKUP;
1344 
1345 		if (statsinprog != 0) {
1346 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1347 			    /*then*/ &start_time);
1348 			statsinprog = 0;
1349 		}
1350 
1351 		retops++;
1352 		if (nd->nd_repstat) {
1353 			*repp = nfsd_errmap(nd);
1354 			break;
1355 		} else {
1356 			*repp = 0;	/* NFS4_OK */
1357 		}
1358 	}
1359 nfsmout:
1360 	if (statsinprog != 0) {
1361 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1362 		    /*then*/ &start_time);
1363 		statsinprog = 0;
1364 	}
1365 	if (error) {
1366 		if (error == EBADRPC || error == NFSERR_BADXDR)
1367 			nd->nd_repstat = NFSERR_BADXDR;
1368 		else
1369 			printf("nfsv4 comperr1=%d\n", error);
1370 	}
1371 	if (taglen == -1) {
1372 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1373 		*tl++ = 0;
1374 		*tl = 0;
1375 	} else {
1376 		*retopsp = txdr_unsigned(retops);
1377 	}
1378 	if (vp)
1379 		vrele(vp);
1380 	if (savevp)
1381 		vrele(savevp);
1382 	NFSLOCKV4ROOTMUTEX();
1383 	nfsv4_relref(&nfsv4rootfs_lock);
1384 	NFSUNLOCKV4ROOTMUTEX();
1385 
1386 	NFSEXITCODE2(0, nd);
1387 }
1388