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