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