xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 81ad6265)
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_deallocate,
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 	/* Check for and optionally clear the no space flags for DSs. */
726 	nfsrv_checknospc();
727 
728 	NFSVNO_EXINIT(&vpnes);
729 	NFSVNO_EXINIT(&savevpnes);
730 	/*
731 	 * Put the seq# of the current compound RPC in nfsrv_descript.
732 	 * (This is used by nfsrv_checkgetattr(), to see if the write
733 	 *  delegation was created by the same compound RPC as the one
734 	 *  with that Getattr in it.)
735 	 * Don't worry about the 64bit number wrapping around. It ain't
736 	 * gonna happen before this server gets shut down/rebooted.
737 	 */
738 	nd->nd_compref = compref++;
739 
740 	/*
741 	 * Check for and optionally get a lock on the root. This lock means that
742 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
743 	 * is required when the V4 root is being changed, the stable storage
744 	 * restart file is being updated, or callbacks are being done.
745 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
746 	 * either hold a reference count (nfs_usecnt) or the lock. When
747 	 * nfsrv_unlock() is called to release the lock, it can optionally
748 	 * also get a reference count, which saves the need for a call to
749 	 * nfsrv_getref() after nfsrv_unlock().
750 	 */
751 	/*
752 	 * First, check to see if we need to wait for an update lock.
753 	 */
754 	igotlock = 0;
755 	NFSLOCKV4ROOTMUTEX();
756 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
757 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
758 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
759 	else
760 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
761 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
762 	NFSUNLOCKV4ROOTMUTEX();
763 	if (igotlock) {
764 		/*
765 		 * If I got the lock, I can update the stable storage file.
766 		 * Done when the grace period is over or a client has long
767 		 * since expired.
768 		 */
769 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
770 		if ((nfsrv_stablefirst.nsf_flags &
771 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
772 			nfsrv_updatestable(p);
773 
774 		/*
775 		 * If at least one client has long since expired, search
776 		 * the client list for them, write a REVOKE record on the
777 		 * stable storage file and then remove them from the client
778 		 * list.
779 		 */
780 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
781 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
782 			for (i = 0; i < nfsrv_clienthashsize; i++) {
783 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
784 				nclp) {
785 				if (clp->lc_flags & LCL_EXPIREIT) {
786 				    if (!LIST_EMPTY(&clp->lc_open) ||
787 					!LIST_EMPTY(&clp->lc_deleg))
788 					nfsrv_writestable(clp->lc_id,
789 					    clp->lc_idlen, NFSNST_REVOKE, p);
790 				    nfsrv_cleanclient(clp, p);
791 				    nfsrv_freedeleglist(&clp->lc_deleg);
792 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
793 				    LIST_REMOVE(clp, lc_hash);
794 				    nfsrv_zapclient(clp, p);
795 				}
796 			    }
797 			}
798 		}
799 		NFSLOCKV4ROOTMUTEX();
800 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
801 		NFSUNLOCKV4ROOTMUTEX();
802 	} else {
803 		/*
804 		 * If we didn't get the lock, we need to get a refcnt,
805 		 * which also checks for and waits for the lock.
806 		 */
807 		NFSLOCKV4ROOTMUTEX();
808 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
809 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
810 		NFSUNLOCKV4ROOTMUTEX();
811 	}
812 
813 	/*
814 	 * If flagged, search for open owners that haven't had any opens
815 	 * for a long time.
816 	 */
817 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
818 		nfsrv_throwawayopens(p);
819 	}
820 
821 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
822 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
823 		nfsrv_recalloldlayout(p);
824 
825 	savevp = vp = NULL;
826 	save_fsid.val[0] = save_fsid.val[1] = 0;
827 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
828 	nextop = -1;
829 	savefhcnt = 0;
830 
831 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
832 	if (taglen < 0) {
833 		error = EBADRPC;
834 		goto nfsmout;
835 	}
836 
837 	(void) nfsm_strtom(nd, tag, taglen);
838 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
839 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
840 	if ((minorvers != NFSV4_MINORVERSION &&
841 	    minorvers != NFSV41_MINORVERSION &&
842 	    minorvers != NFSV42_MINORVERSION) ||
843 	    minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)
844 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
845 	if (nd->nd_repstat)
846 		numops = 0;
847 	else
848 		numops = fxdr_unsigned(int, *tl);
849 	/*
850 	 * Loop around doing the sub ops.
851 	 * vp - is an unlocked vnode pointer for the CFH
852 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
853 	 * (at some future date, it might turn out to be more appropriate
854 	 *  to keep the file handles instead of vnode pointers?)
855 	 * savevpnes and vpnes - are the export flags for the above.
856 	 */
857 	for (i = 0; i < numops; i++) {
858 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
859 		if (savefhcnt > 0) {
860 			op = NFSV4OP_SAVEFH;
861 			*repp = txdr_unsigned(op);
862 			savefhcnt--;
863 		} else if (nextop == -1) {
864 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
865 			*repp = *tl;
866 			op = fxdr_unsigned(int, *tl);
867 		} else {
868 			op = nextop;
869 			*repp = txdr_unsigned(op);
870 			nextop = -1;
871 		}
872 		NFSD_DEBUG(4, "op=%d\n", op);
873 		if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
874 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
875 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {
876 			nd->nd_repstat = NFSERR_OPILLEGAL;
877 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
878 			*repp = nfsd_errmap(nd);
879 			retops++;
880 			break;
881 		} else {
882 			repp++;
883 		}
884 
885 		binuptime(&start_time);
886 		nfsrvd_statstart(op, &start_time);
887 		statsinprog = 1;
888 
889 		if (i == 0)
890 			op0 = op;
891 		if (i == numops - 1)
892 			nd->nd_flag |= ND_LASTOP;
893 
894 		/*
895 		 * Check for a referral on the current FH and, if so, return
896 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
897 		 */
898 		if (vp != NULL && op != NFSV4OP_GETATTR &&
899 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
900 		    nfsrv_errmoved(op)) {
901 			nd->nd_repstat = NFSERR_MOVED;
902 			*repp = nfsd_errmap(nd);
903 			retops++;
904 			break;
905 		}
906 
907 		/*
908 		 * For NFSv4.1, check for a Sequence Operation being first
909 		 * or one of the other allowed operations by itself.
910 		 */
911 		if ((nd->nd_flag & ND_NFSV41) != 0) {
912 			if (i != 0 && op == NFSV4OP_SEQUENCE)
913 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
914 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
915 			    op != NFSV4OP_EXCHANGEID &&
916 			    op != NFSV4OP_CREATESESSION &&
917 			    op != NFSV4OP_BINDCONNTOSESS &&
918 			    op != NFSV4OP_DESTROYCLIENTID &&
919 			    op != NFSV4OP_DESTROYSESSION)
920 				nd->nd_repstat = NFSERR_OPNOTINSESS;
921 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
922 				nd->nd_repstat = NFSERR_NOTONLYOP;
923 			if (nd->nd_repstat != 0) {
924 				*repp = nfsd_errmap(nd);
925 				retops++;
926 				break;
927 			}
928 		}
929 
930 		nd->nd_procnum = op;
931 		/*
932 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
933 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
934 		 * really nasty for certain Op sequences, I'll play it safe
935 		 * and only return the error at the beginning.) The cache
936 		 * will still function over flood level, but uses lots of
937 		 * mbufs.)
938 		 * If nfsrv_mallocmget_limit() returns True, the system is near
939 		 * to its limit for memory that malloc()/mget() can allocate.
940 		 */
941 		if (i == 0 && (nd->nd_rp == NULL ||
942 		    nd->nd_rp->rc_refcnt == 0) &&
943 		    (nfsrv_mallocmget_limit() ||
944 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
945 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
946 				printf("nfsd server cache flooded, try "
947 				    "increasing vfs.nfsd.tcphighwater\n");
948 			nd->nd_repstat = NFSERR_RESOURCE;
949 			*repp = nfsd_errmap(nd);
950 			if (op == NFSV4OP_SETATTR) {
951 				/*
952 				 * Setattr replies require a bitmap.
953 				 * even for errors like these.
954 				 */
955 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
956 				*tl = 0;
957 			}
958 			retops++;
959 			break;
960 		}
961 		if (nfsv4_opflag[op].savereply)
962 			nd->nd_flag |= ND_SAVEREPLY;
963 		switch (op) {
964 		case NFSV4OP_PUTFH:
965 			error = nfsrv_mtofh(nd, &fh);
966 			if (error)
967 				goto nfsmout;
968 			if ((nd->nd_flag & ND_LASTOP) == 0) {
969 				/*
970 				 * Pre-parse the next op#.  If it is
971 				 * SaveFH, count it and skip to the
972 				 * next op#, if not the last op#.
973 				 * nextop is used to determine if
974 				 * NFSERR_WRONGSEC can be returned,
975 				 * per RFC5661 Sec. 2.6.
976 				 */
977 				do {
978 					NFSM_DISSECT(tl, uint32_t *,
979 					    NFSX_UNSIGNED);
980 					nextop = fxdr_unsigned(int, *tl);
981 					if (nextop == NFSV4OP_SAVEFH &&
982 					    i < numops - 1)
983 						savefhcnt++;
984 				} while (nextop == NFSV4OP_SAVEFH &&
985 				    i < numops - 1);
986 			}
987 			if (!nd->nd_repstat)
988 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
989 				    NULL, 0, nextop);
990 			/* For now, allow this for non-export FHs */
991 			if (!nd->nd_repstat) {
992 				if (vp)
993 					vrele(vp);
994 				vp = nvp;
995 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
996 				NFSVOPUNLOCK(vp);
997 				vpnes = nes;
998 			}
999 			break;
1000 		case NFSV4OP_PUTPUBFH:
1001 			if (nfs_pubfhset) {
1002 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1003 					/*
1004 					 * Pre-parse the next op#.  If it is
1005 					 * SaveFH, count it and skip to the
1006 					 * next op#, if not the last op#.
1007 					 * nextop is used to determine if
1008 					 * NFSERR_WRONGSEC can be returned,
1009 					 * per RFC5661 Sec. 2.6.
1010 					 */
1011 					do {
1012 						NFSM_DISSECT(tl, uint32_t *,
1013 						    NFSX_UNSIGNED);
1014 						nextop = fxdr_unsigned(int,
1015 						    *tl);
1016 						if (nextop == NFSV4OP_SAVEFH &&
1017 						    i < numops - 1)
1018 							savefhcnt++;
1019 					} while (nextop == NFSV4OP_SAVEFH &&
1020 					    i < numops - 1);
1021 				}
1022 				nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
1023 				    &nes, NULL, 0, nextop);
1024 			} else
1025 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1026 			if (!nd->nd_repstat) {
1027 				if (vp)
1028 					vrele(vp);
1029 				vp = nvp;
1030 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1031 				NFSVOPUNLOCK(vp);
1032 				vpnes = nes;
1033 			}
1034 			break;
1035 		case NFSV4OP_PUTROOTFH:
1036 			if (nfs_rootfhset) {
1037 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1038 					/*
1039 					 * Pre-parse the next op#.  If it is
1040 					 * SaveFH, count it and skip to the
1041 					 * next op#, if not the last op#.
1042 					 * nextop is used to determine if
1043 					 * NFSERR_WRONGSEC can be returned,
1044 					 * per RFC5661 Sec. 2.6.
1045 					 */
1046 					do {
1047 						NFSM_DISSECT(tl, uint32_t *,
1048 						    NFSX_UNSIGNED);
1049 						nextop = fxdr_unsigned(int,
1050 						    *tl);
1051 						if (nextop == NFSV4OP_SAVEFH &&
1052 						    i < numops - 1)
1053 							savefhcnt++;
1054 					} while (nextop == NFSV4OP_SAVEFH &&
1055 					    i < numops - 1);
1056 				}
1057 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
1058 				    &nes, NULL, 0, nextop);
1059 				if (!nd->nd_repstat) {
1060 					if (vp)
1061 						vrele(vp);
1062 					vp = nvp;
1063 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1064 					NFSVOPUNLOCK(vp);
1065 					vpnes = nes;
1066 				}
1067 			} else
1068 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1069 			break;
1070 		case NFSV4OP_SAVEFH:
1071 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
1072 				nd->nd_repstat = 0;
1073 				/* If vp == savevp, a no-op */
1074 				if (vp != savevp) {
1075 					if (savevp)
1076 						vrele(savevp);
1077 					VREF(vp);
1078 					savevp = vp;
1079 					savevpnes = vpnes;
1080 					save_fsid = cur_fsid;
1081 				}
1082 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
1083 					nd->nd_savedcurstateid =
1084 					    nd->nd_curstateid;
1085 					nd->nd_flag |= ND_SAVEDCURSTATEID;
1086 				}
1087 			} else {
1088 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1089 			}
1090 			break;
1091 		case NFSV4OP_RESTOREFH:
1092 			if (savevp) {
1093 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1094 					/*
1095 					 * Pre-parse the next op#.  If it is
1096 					 * SaveFH, count it and skip to the
1097 					 * next op#, if not the last op#.
1098 					 * nextop is used to determine if
1099 					 * NFSERR_WRONGSEC can be returned,
1100 					 * per RFC5661 Sec. 2.6.
1101 					 */
1102 					do {
1103 						NFSM_DISSECT(tl, uint32_t *,
1104 						    NFSX_UNSIGNED);
1105 						nextop = fxdr_unsigned(int,
1106 						    *tl);
1107 						if (nextop == NFSV4OP_SAVEFH &&
1108 						    i < numops - 1)
1109 							savefhcnt++;
1110 					} while (nextop == NFSV4OP_SAVEFH &&
1111 					    i < numops - 1);
1112 				}
1113 				nd->nd_repstat = 0;
1114 				/* If vp == savevp, a no-op */
1115 				if (vp != savevp) {
1116 					if (nfsrv_checkwrongsec(nd, nextop,
1117 					    savevp->v_type))
1118 						nd->nd_repstat =
1119 						    nfsvno_testexp(nd,
1120 						    &savevpnes);
1121 					if (nd->nd_repstat == 0) {
1122 						VREF(savevp);
1123 						vrele(vp);
1124 						vp = savevp;
1125 						vpnes = savevpnes;
1126 						cur_fsid = save_fsid;
1127 					}
1128 				}
1129 				if (nd->nd_repstat == 0 &&
1130 				     (nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
1131 					nd->nd_curstateid =
1132 					    nd->nd_savedcurstateid;
1133 					nd->nd_flag |= ND_CURSTATEID;
1134 				}
1135 			} else {
1136 				nd->nd_repstat = NFSERR_RESTOREFH;
1137 			}
1138 			break;
1139 		default:
1140 		    /*
1141 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
1142 		     * non-exported directory if
1143 		     * nfs_rootfhset. Do I need to allow any other Ops?
1144 		     * (You can only have a non-exported vpnes if
1145 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
1146 		     * Allow AUTH_SYS to be used for file systems
1147 		     * exported GSS only for certain Ops, to allow
1148 		     * clients to do mounts more easily.
1149 		     */
1150 		    if (nfsv4_opflag[op].needscfh && vp) {
1151 			if (!NFSVNO_EXPORTED(&vpnes) &&
1152 			    op != NFSV4OP_LOOKUP &&
1153 			    op != NFSV4OP_GETATTR &&
1154 			    op != NFSV4OP_GETFH &&
1155 			    op != NFSV4OP_ACCESS &&
1156 			    op != NFSV4OP_READLINK &&
1157 			    op != NFSV4OP_SECINFO &&
1158 			    op != NFSV4OP_SECINFONONAME)
1159 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1160 			if (nd->nd_repstat) {
1161 				if (op == NFSV4OP_SETATTR) {
1162 				    /*
1163 				     * Setattr reply requires a bitmap
1164 				     * even for errors like these.
1165 				     */
1166 				    NFSM_BUILD(tl, u_int32_t *,
1167 					NFSX_UNSIGNED);
1168 				    *tl = 0;
1169 				}
1170 				break;
1171 			}
1172 		    }
1173 
1174 		    /*
1175 		     * Save the current positions in the mbuf lists so
1176 		     * that a rollback to this location can be done upon a
1177 		     * redo due to a ERELOOKUP return for a operation.
1178 		     */
1179 		    mb = nd->nd_mb;
1180 		    bpos = nd->nd_bpos;
1181 		    bextpg = nd->nd_bextpg;
1182 		    bextpgsiz = nd->nd_bextpgsiz;
1183 		    md = nd->nd_md;
1184 		    dpos = nd->nd_dpos;
1185 tryagain:
1186 
1187 		    if (nfsv4_opflag[op].retfh == 1) {
1188 			if (!vp) {
1189 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1190 				break;
1191 			}
1192 			if (NFSVNO_EXPORTED(&vpnes) && (op == NFSV4OP_LOOKUP ||
1193 			    op == NFSV4OP_LOOKUPP || (op == NFSV4OP_OPEN &&
1194 			    vp->v_type == VDIR))) {
1195 				/* Check for wrong security. */
1196 				rstat = nfsvno_testexp(nd, &vpnes);
1197 				if (rstat != 0) {
1198 					nd->nd_repstat = rstat;
1199 					break;
1200 				}
1201 			}
1202 			VREF(vp);
1203 			if (nfsv4_opflag[op].modifyfs)
1204 				vn_start_write(vp, &temp_mp, V_WAIT);
1205 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
1206 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
1207 			if (!error && !nd->nd_repstat) {
1208 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
1209 				new_mp = nvp->v_mount;
1210 				if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) {
1211 				    /* crossed a server mount point */
1212 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
1213 					nd->nd_nam, &nes, &credanon);
1214 				    if (!nd->nd_repstat)
1215 					nd->nd_repstat = nfsd_excred(nd,
1216 					    &nes, credanon, true);
1217 				    if (credanon != NULL)
1218 					crfree(credanon);
1219 				    if (!nd->nd_repstat) {
1220 					vpnes = nes;
1221 					cur_fsid = new_mp->mnt_stat.f_fsid;
1222 				    }
1223 				}
1224 				/* Lookup ops return a locked vnode */
1225 				NFSVOPUNLOCK(nvp);
1226 			    }
1227 			    if (!nd->nd_repstat) {
1228 				    vrele(vp);
1229 				    vp = nvp;
1230 			    } else
1231 				    vrele(nvp);
1232 			}
1233 			if (nfsv4_opflag[op].modifyfs)
1234 				vn_finished_write(temp_mp);
1235 		    } else if (nfsv4_opflag[op].retfh == 2) {
1236 			if (vp == NULL || savevp == NULL) {
1237 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1238 				break;
1239 			} else if (fsidcmp(&cur_fsid, &save_fsid) != 0) {
1240 				nd->nd_repstat = NFSERR_XDEV;
1241 				break;
1242 			}
1243 			if (nfsv4_opflag[op].modifyfs)
1244 				vn_start_write(savevp, &temp_mp, V_WAIT);
1245 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1246 				VREF(vp);
1247 				VREF(savevp);
1248 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1249 				    savevp, vp, &savevpnes, &vpnes);
1250 			} else
1251 				nd->nd_repstat = NFSERR_PERM;
1252 			if (nfsv4_opflag[op].modifyfs)
1253 				vn_finished_write(temp_mp);
1254 		    } else {
1255 			if (nfsv4_opflag[op].retfh != 0)
1256 				panic("nfsrvd_compound");
1257 			if (nfsv4_opflag[op].needscfh) {
1258 				if (vp != NULL) {
1259 					lktype = nfsv4_opflag[op].lktype;
1260 					if (nfsv4_opflag[op].modifyfs) {
1261 						vn_start_write(vp, &temp_mp,
1262 						    V_WAIT);
1263 						if (op == NFSV4OP_WRITE &&
1264 						    MNT_SHARED_WRITES(temp_mp))
1265 							lktype = LK_SHARED;
1266 					}
1267 					if (NFSVOPLOCK(vp, lktype) == 0)
1268 						VREF(vp);
1269 					else
1270 						nd->nd_repstat = NFSERR_PERM;
1271 				} else {
1272 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1273 					if (op == NFSV4OP_SETATTR) {
1274 						/*
1275 						 * Setattr reply requires a
1276 						 * bitmap even for errors like
1277 						 * these.
1278 						 */
1279 						NFSM_BUILD(tl, u_int32_t *,
1280 						    NFSX_UNSIGNED);
1281 						*tl = 0;
1282 					}
1283 					break;
1284 				}
1285 				if (nd->nd_repstat == 0) {
1286 					error = (*(nfsrv4_ops0[op]))(nd,
1287 					    isdgram, vp, &vpnes);
1288 					if ((op == NFSV4OP_SECINFO ||
1289 					     op == NFSV4OP_SECINFONONAME) &&
1290 					    error == 0 && nd->nd_repstat == 0) {
1291 						/*
1292 						 * Secinfo and Secinfo_no_name
1293 						 * consume the current FH.
1294 						 */
1295 						vrele(vp);
1296 						vp = NULL;
1297 					}
1298 				}
1299 				if (nfsv4_opflag[op].modifyfs)
1300 					vn_finished_write(temp_mp);
1301 			} else {
1302 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1303 				    NULL, &vpnes);
1304 			}
1305 		    }
1306 		}
1307 		if (error) {
1308 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1309 				nd->nd_repstat = NFSERR_BADXDR;
1310 			} else {
1311 				nd->nd_repstat = error;
1312 				printf("nfsv4 comperr0=%d\n", error);
1313 			}
1314 			error = 0;
1315 		}
1316 
1317 		if (nd->nd_repstat == ERELOOKUP) {
1318 			/*
1319 			 * Roll back to the beginning of the operation
1320 			 * arguments.
1321 			 */
1322 			nd->nd_md = md;
1323 			nd->nd_dpos = dpos;
1324 
1325 			/*
1326 			 * Trim off the bogus reply for this operation
1327 			 * and redo the operation.
1328 			 */
1329 			nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);
1330 			nd->nd_repstat = 0;
1331 			nd->nd_flag |= ND_ERELOOKUP;
1332 			goto tryagain;
1333 		}
1334 		nd->nd_flag &= ~ND_ERELOOKUP;
1335 
1336 		if (statsinprog != 0) {
1337 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1338 			    /*then*/ &start_time);
1339 			statsinprog = 0;
1340 		}
1341 
1342 		retops++;
1343 		if (nd->nd_repstat) {
1344 			*repp = nfsd_errmap(nd);
1345 			break;
1346 		} else {
1347 			*repp = 0;	/* NFS4_OK */
1348 		}
1349 	}
1350 nfsmout:
1351 	if (statsinprog != 0) {
1352 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1353 		    /*then*/ &start_time);
1354 		statsinprog = 0;
1355 	}
1356 	if (error) {
1357 		if (error == EBADRPC || error == NFSERR_BADXDR)
1358 			nd->nd_repstat = NFSERR_BADXDR;
1359 		else
1360 			printf("nfsv4 comperr1=%d\n", error);
1361 	}
1362 	if (taglen == -1) {
1363 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1364 		*tl++ = 0;
1365 		*tl = 0;
1366 	} else {
1367 		*retopsp = txdr_unsigned(retops);
1368 	}
1369 	if (vp)
1370 		vrele(vp);
1371 	if (savevp)
1372 		vrele(savevp);
1373 	NFSLOCKV4ROOTMUTEX();
1374 	nfsv4_relref(&nfsv4rootfs_lock);
1375 	NFSUNLOCKV4ROOTMUTEX();
1376 
1377 	NFSEXITCODE2(0, nd);
1378 }
1379