xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
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_notsupp,
192 	nfsrvd_sequence,
193 	nfsrvd_notsupp,
194 	nfsrvd_teststateid,
195 	nfsrvd_notsupp,
196 	nfsrvd_destroyclientid,
197 	nfsrvd_reclaimcomplete,
198 	nfsrvd_allocate,
199 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
200 	nfsrvd_notsupp,
201 	nfsrvd_notsupp,
202 	nfsrvd_ioadvise,
203 	nfsrvd_layouterror,
204 	nfsrvd_layoutstats,
205 	nfsrvd_notsupp,
206 	nfsrvd_notsupp,
207 	nfsrvd_notsupp,
208 	nfsrvd_seek,
209 	nfsrvd_notsupp,
210 	nfsrvd_notsupp,
211 	nfsrvd_getxattr,
212 	nfsrvd_setxattr,
213 	nfsrvd_listxattr,
214 	nfsrvd_rmxattr,
215 };
216 
217 int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *,
218     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
219 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
220 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
221 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
222 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
223 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
224 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
225 	nfsrvd_mknod,
226 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
227 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
228 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
229 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
230 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
231 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
232 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
233 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
234 	nfsrvd_lookup,
235 	nfsrvd_lookup,
236 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
237 	nfsrvd_open,
238 	nfsrvd_openattr,
239 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
240 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
241 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
242 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
243 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
244 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
245 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
246 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
247 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
248 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
249 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
250 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
251 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
252 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
253 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
254 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
255 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
256 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
257 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
258 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
259 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
260 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
261 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
262 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
263 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
264 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
265 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
266 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
267 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
268 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
269 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
270 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
271 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
272 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
273 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
274 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
275 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
276 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
277 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
278 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
279 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
280 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
281 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
282 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
283 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
284 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
285 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
286 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
287 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
288 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
289 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
290 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
291 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
292 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
293 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
294 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
295 };
296 
297 int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *,
298     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
299 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
300 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
301 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
302 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
303 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
304 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
305 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
306 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
307 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
308 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
309 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
310 	nfsrvd_link,
311 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
312 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
313 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
314 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
315 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
316 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
317 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
318 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
319 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
320 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
321 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
322 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
323 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
324 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
325 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
326 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
327 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
328 	nfsrvd_rename,
329 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
330 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
331 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
332 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
333 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
334 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
335 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
336 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
337 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
338 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
339 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
340 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
341 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
342 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
343 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
344 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
345 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
346 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
347 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
348 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
349 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
350 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
351 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
352 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
353 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
354 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
355 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
356 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
357 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
358 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
359 	nfsrvd_copy_file_range,
360 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
361 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
362 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
363 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
364 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
365 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
366 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
367 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
368 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
369 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
370 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
371 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
372 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
373 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
374 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
375 };
376 
377 /*
378  * Static array that defines which nfs rpc's are nonidempotent
379  */
380 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
381 	FALSE,
382 	FALSE,
383 	TRUE,
384 	FALSE,
385 	FALSE,
386 	FALSE,
387 	FALSE,
388 	TRUE,
389 	TRUE,
390 	TRUE,
391 	TRUE,
392 	TRUE,
393 	TRUE,
394 	TRUE,
395 	TRUE,
396 	TRUE,
397 	FALSE,
398 	FALSE,
399 	FALSE,
400 	FALSE,
401 	FALSE,
402 	FALSE,
403 };
404 
405 /*
406  * This static array indicates whether or not the RPC modifies the
407  * file system.
408  */
409 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
410     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
411     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
412 
413 SYSCTL_DECL(_vfs_nfsd);
414 static int	nfs_minminorv4 = NFSV4_MINORVERSION;
415 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN,
416     &nfs_minminorv4, 0,
417     "The lowest minor version of NFSv4 handled by the server");
418 
419 static int	nfs_maxminorv4 = NFSV42_MINORVERSION;
420 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN,
421     &nfs_maxminorv4, 0,
422     "The highest minor version of NFSv4 handled by the server");
423 
424 /* local functions */
425 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
426     u_char *tag, int taglen, u_int32_t minorvers);
427 
428 /*
429  * This static array indicates which server procedures require the extra
430  * arguments to return the current file handle for V2, 3.
431  */
432 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
433 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
434 
435 extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];
436 
437 static int nfsv3to4op[NFS_V3NPROCS] = {
438 	NFSPROC_NULL,
439 	NFSV4OP_GETATTR,
440 	NFSV4OP_SETATTR,
441 	NFSV4OP_LOOKUP,
442 	NFSV4OP_ACCESS,
443 	NFSV4OP_READLINK,
444 	NFSV4OP_READ,
445 	NFSV4OP_WRITE,
446 	NFSV4OP_V3CREATE,
447 	NFSV4OP_MKDIR,
448 	NFSV4OP_SYMLINK,
449 	NFSV4OP_MKNOD,
450 	NFSV4OP_REMOVE,
451 	NFSV4OP_RMDIR,
452 	NFSV4OP_RENAME,
453 	NFSV4OP_LINK,
454 	NFSV4OP_READDIR,
455 	NFSV4OP_READDIRPLUS,
456 	NFSV4OP_FSSTAT,
457 	NFSV4OP_FSINFO,
458 	NFSV4OP_PATHCONF,
459 	NFSV4OP_COMMIT,
460 };
461 
462 static struct mtx nfsrvd_statmtx;
463 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
464 
465 static void
466 nfsrvd_statstart(int op, struct bintime *now)
467 {
468 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
469 		printf("%s: op %d invalid\n", __func__, op);
470 		return;
471 	}
472 
473 	mtx_lock(&nfsrvd_statmtx);
474 	if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
475 		if (now != NULL)
476 			nfsstatsv1.busyfrom = *now;
477 		else
478 			binuptime(&nfsstatsv1.busyfrom);
479 
480 	}
481 	nfsstatsv1.srvrpccnt[op]++;
482 	nfsstatsv1.srvstartcnt++;
483 	mtx_unlock(&nfsrvd_statmtx);
484 
485 }
486 
487 static void
488 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
489     struct bintime *then)
490 {
491 	struct bintime dt, lnow;
492 
493 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
494 		printf("%s: op %d invalid\n", __func__, op);
495 		return;
496 	}
497 
498 	if (now == NULL) {
499 		now = &lnow;
500 		binuptime(now);
501 	}
502 
503 	mtx_lock(&nfsrvd_statmtx);
504 
505 	nfsstatsv1.srvbytes[op] += bytes;
506 	nfsstatsv1.srvops[op]++;
507 
508 	if (then != NULL) {
509 		dt = *now;
510 		bintime_sub(&dt, then);
511 		bintime_add(&nfsstatsv1.srvduration[op], &dt);
512 	}
513 
514 	dt = *now;
515 	bintime_sub(&dt, &nfsstatsv1.busyfrom);
516 	bintime_add(&nfsstatsv1.busytime, &dt);
517 	nfsstatsv1.busyfrom = *now;
518 
519 	nfsstatsv1.srvdonecnt++;
520 
521 	mtx_unlock(&nfsrvd_statmtx);
522 }
523 
524 /*
525  * Do an RPC. Basically, get the file handles translated to vnode pointers
526  * and then call the appropriate server routine. The server routines are
527  * split into groups, based on whether they use a file handle or file
528  * handle plus name or ...
529  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
530  */
531 void
532 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
533     u_int32_t minorvers)
534 {
535 	int error = 0, lktype;
536 	vnode_t vp;
537 	mount_t mp;
538 	struct nfsrvfh fh;
539 	struct nfsexstuff nes;
540 	struct mbuf *md;
541 	char *dpos;
542 
543 	/*
544 	 * Save the current position in the request mbuf list so
545 	 * that a rollback to this location can be done upon an
546 	 * ERELOOKUP error return from an RPC function.
547 	 */
548 	md = nd->nd_md;
549 	dpos = nd->nd_dpos;
550 tryagain:
551 	mp = NULL;
552 
553 	/*
554 	 * Get a locked vnode for the first file handle
555 	 */
556 	if (!(nd->nd_flag & ND_NFSV4)) {
557 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
558 		/*
559 		 * For NFSv3, if the malloc/mget allocation is near limits,
560 		 * return NFSERR_DELAY.
561 		 */
562 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
563 			nd->nd_repstat = NFSERR_DELAY;
564 			vp = NULL;
565 		} else {
566 			error = nfsrv_mtofh(nd, &fh);
567 			if (error) {
568 				if (error != EBADRPC)
569 					printf("nfs dorpc err1=%d\n", error);
570 				nd->nd_repstat = NFSERR_GARBAGE;
571 				goto out;
572 			}
573 			if (nd->nd_procnum == NFSPROC_READ ||
574 			    nd->nd_procnum == NFSPROC_WRITE ||
575 			    nd->nd_procnum == NFSPROC_READDIR ||
576 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
577 			    nd->nd_procnum == NFSPROC_READLINK ||
578 			    nd->nd_procnum == NFSPROC_GETATTR ||
579 			    nd->nd_procnum == NFSPROC_ACCESS ||
580 			    nd->nd_procnum == NFSPROC_FSSTAT ||
581 			    nd->nd_procnum == NFSPROC_FSINFO)
582 				lktype = LK_SHARED;
583 			else
584 				lktype = LK_EXCLUSIVE;
585 			if (nd->nd_flag & ND_PUBLOOKUP)
586 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
587 				    &mp, nfsrv_writerpc[nd->nd_procnum]);
588 			else
589 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
590 				    &mp, nfsrv_writerpc[nd->nd_procnum]);
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, statsinprog = 0;
706 	u_int32_t *tl;
707 	struct nfsclient *clp, *nclp;
708 	int numops, error = 0, igotlock;
709 	u_int32_t retops = 0, *retopsp = NULL, *repp;
710 	vnode_t vp, nvp, savevp;
711 	struct nfsrvfh fh;
712 	mount_t new_mp, temp_mp = NULL;
713 	struct ucred *credanon;
714 	struct nfsexstuff nes, vpnes, savevpnes;
715 	fsid_t cur_fsid, save_fsid;
716 	static u_int64_t compref = 0;
717 	struct bintime start_time;
718 	struct thread *p;
719 	struct mbuf *mb, *md;
720 	char *bpos, *dpos;
721 	int bextpg, bextpgsiz;
722 
723 	p = curthread;
724 
725 	NFSVNO_EXINIT(&vpnes);
726 	NFSVNO_EXINIT(&savevpnes);
727 	/*
728 	 * Put the seq# of the current compound RPC in nfsrv_descript.
729 	 * (This is used by nfsrv_checkgetattr(), to see if the write
730 	 *  delegation was created by the same compound RPC as the one
731 	 *  with that Getattr in it.)
732 	 * Don't worry about the 64bit number wrapping around. It ain't
733 	 * gonna happen before this server gets shut down/rebooted.
734 	 */
735 	nd->nd_compref = compref++;
736 
737 	/*
738 	 * Check for and optionally get a lock on the root. This lock means that
739 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
740 	 * is required when the V4 root is being changed, the stable storage
741 	 * restart file is being updated, or callbacks are being done.
742 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
743 	 * either hold a reference count (nfs_usecnt) or the lock. When
744 	 * nfsrv_unlock() is called to release the lock, it can optionally
745 	 * also get a reference count, which saves the need for a call to
746 	 * nfsrv_getref() after nfsrv_unlock().
747 	 */
748 	/*
749 	 * First, check to see if we need to wait for an update lock.
750 	 */
751 	igotlock = 0;
752 	NFSLOCKV4ROOTMUTEX();
753 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
754 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
755 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
756 	else
757 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
758 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
759 	NFSUNLOCKV4ROOTMUTEX();
760 	if (igotlock) {
761 		/*
762 		 * If I got the lock, I can update the stable storage file.
763 		 * Done when the grace period is over or a client has long
764 		 * since expired.
765 		 */
766 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
767 		if ((nfsrv_stablefirst.nsf_flags &
768 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
769 			nfsrv_updatestable(p);
770 
771 		/*
772 		 * If at least one client has long since expired, search
773 		 * the client list for them, write a REVOKE record on the
774 		 * stable storage file and then remove them from the client
775 		 * list.
776 		 */
777 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
778 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
779 			for (i = 0; i < nfsrv_clienthashsize; i++) {
780 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
781 				nclp) {
782 				if (clp->lc_flags & LCL_EXPIREIT) {
783 				    if (!LIST_EMPTY(&clp->lc_open) ||
784 					!LIST_EMPTY(&clp->lc_deleg))
785 					nfsrv_writestable(clp->lc_id,
786 					    clp->lc_idlen, NFSNST_REVOKE, p);
787 				    nfsrv_cleanclient(clp, p);
788 				    nfsrv_freedeleglist(&clp->lc_deleg);
789 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
790 				    LIST_REMOVE(clp, lc_hash);
791 				    nfsrv_zapclient(clp, p);
792 				}
793 			    }
794 			}
795 		}
796 		NFSLOCKV4ROOTMUTEX();
797 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
798 		NFSUNLOCKV4ROOTMUTEX();
799 	} else {
800 		/*
801 		 * If we didn't get the lock, we need to get a refcnt,
802 		 * which also checks for and waits for the lock.
803 		 */
804 		NFSLOCKV4ROOTMUTEX();
805 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
806 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
807 		NFSUNLOCKV4ROOTMUTEX();
808 	}
809 
810 	/*
811 	 * If flagged, search for open owners that haven't had any opens
812 	 * for a long time.
813 	 */
814 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
815 		nfsrv_throwawayopens(p);
816 	}
817 
818 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
819 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
820 		nfsrv_recalloldlayout(p);
821 
822 	savevp = vp = NULL;
823 	save_fsid.val[0] = save_fsid.val[1] = 0;
824 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
825 
826 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
827 	if (taglen < 0) {
828 		error = EBADRPC;
829 		goto nfsmout;
830 	}
831 
832 	(void) nfsm_strtom(nd, tag, taglen);
833 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
834 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
835 	if ((minorvers != NFSV4_MINORVERSION &&
836 	    minorvers != NFSV41_MINORVERSION &&
837 	    minorvers != NFSV42_MINORVERSION) ||
838 	    minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)
839 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
840 	if (nd->nd_repstat)
841 		numops = 0;
842 	else
843 		numops = fxdr_unsigned(int, *tl);
844 	/*
845 	 * Loop around doing the sub ops.
846 	 * vp - is an unlocked vnode pointer for the CFH
847 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
848 	 * (at some future date, it might turn out to be more appropriate
849 	 *  to keep the file handles instead of vnode pointers?)
850 	 * savevpnes and vpnes - are the export flags for the above.
851 	 */
852 	for (i = 0; i < numops; i++) {
853 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
854 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
855 		*repp = *tl;
856 		op = fxdr_unsigned(int, *tl);
857 		NFSD_DEBUG(4, "op=%d\n", op);
858 		if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
859 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
860 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {
861 			nd->nd_repstat = NFSERR_OPILLEGAL;
862 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
863 			*repp = nfsd_errmap(nd);
864 			retops++;
865 			break;
866 		} else {
867 			repp++;
868 		}
869 
870 		binuptime(&start_time);
871 		nfsrvd_statstart(op, &start_time);
872 		statsinprog = 1;
873 
874 		if (i == 0)
875 			op0 = op;
876 		if (i == numops - 1)
877 			nd->nd_flag |= ND_LASTOP;
878 
879 		/*
880 		 * Check for a referral on the current FH and, if so, return
881 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
882 		 */
883 		if (vp != NULL && op != NFSV4OP_GETATTR &&
884 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
885 		    nfsrv_errmoved(op)) {
886 			nd->nd_repstat = NFSERR_MOVED;
887 			*repp = nfsd_errmap(nd);
888 			retops++;
889 			break;
890 		}
891 
892 		/*
893 		 * For NFSv4.1, check for a Sequence Operation being first
894 		 * or one of the other allowed operations by itself.
895 		 */
896 		if ((nd->nd_flag & ND_NFSV41) != 0) {
897 			if (i != 0 && op == NFSV4OP_SEQUENCE)
898 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
899 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
900 			    op != NFSV4OP_EXCHANGEID &&
901 			    op != NFSV4OP_CREATESESSION &&
902 			    op != NFSV4OP_BINDCONNTOSESS &&
903 			    op != NFSV4OP_DESTROYCLIENTID &&
904 			    op != NFSV4OP_DESTROYSESSION)
905 				nd->nd_repstat = NFSERR_OPNOTINSESS;
906 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
907 				nd->nd_repstat = NFSERR_NOTONLYOP;
908 			if (nd->nd_repstat != 0) {
909 				*repp = nfsd_errmap(nd);
910 				retops++;
911 				break;
912 			}
913 		}
914 
915 		nd->nd_procnum = op;
916 		/*
917 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
918 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
919 		 * really nasty for certain Op sequences, I'll play it safe
920 		 * and only return the error at the beginning.) The cache
921 		 * will still function over flood level, but uses lots of
922 		 * mbufs.)
923 		 * If nfsrv_mallocmget_limit() returns True, the system is near
924 		 * to its limit for memory that malloc()/mget() can allocate.
925 		 */
926 		if (i == 0 && (nd->nd_rp == NULL ||
927 		    nd->nd_rp->rc_refcnt == 0) &&
928 		    (nfsrv_mallocmget_limit() ||
929 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
930 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
931 				printf("nfsd server cache flooded, try "
932 				    "increasing vfs.nfsd.tcphighwater\n");
933 			nd->nd_repstat = NFSERR_RESOURCE;
934 			*repp = nfsd_errmap(nd);
935 			if (op == NFSV4OP_SETATTR) {
936 				/*
937 				 * Setattr replies require a bitmap.
938 				 * even for errors like these.
939 				 */
940 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
941 				*tl = 0;
942 			}
943 			retops++;
944 			break;
945 		}
946 		if (nfsv4_opflag[op].savereply)
947 			nd->nd_flag |= ND_SAVEREPLY;
948 		switch (op) {
949 		case NFSV4OP_PUTFH:
950 			error = nfsrv_mtofh(nd, &fh);
951 			if (error)
952 				goto nfsmout;
953 			if (!nd->nd_repstat)
954 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
955 				    NULL, 0);
956 			/* For now, allow this for non-export FHs */
957 			if (!nd->nd_repstat) {
958 				if (vp)
959 					vrele(vp);
960 				vp = nvp;
961 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
962 				NFSVOPUNLOCK(vp);
963 				vpnes = nes;
964 			}
965 			break;
966 		case NFSV4OP_PUTPUBFH:
967 			if (nfs_pubfhset)
968 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
969 				&nes, NULL, 0);
970 			else
971 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
972 			if (!nd->nd_repstat) {
973 				if (vp)
974 					vrele(vp);
975 				vp = nvp;
976 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
977 				NFSVOPUNLOCK(vp);
978 				vpnes = nes;
979 			}
980 			break;
981 		case NFSV4OP_PUTROOTFH:
982 			if (nfs_rootfhset) {
983 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
984 				    &nes, NULL, 0);
985 				if (!nd->nd_repstat) {
986 					if (vp)
987 						vrele(vp);
988 					vp = nvp;
989 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
990 					NFSVOPUNLOCK(vp);
991 					vpnes = nes;
992 				}
993 			} else
994 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
995 			break;
996 		case NFSV4OP_SAVEFH:
997 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
998 				nd->nd_repstat = 0;
999 				/* If vp == savevp, a no-op */
1000 				if (vp != savevp) {
1001 					if (savevp)
1002 						vrele(savevp);
1003 					VREF(vp);
1004 					savevp = vp;
1005 					savevpnes = vpnes;
1006 					save_fsid = cur_fsid;
1007 				}
1008 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
1009 					nd->nd_savedcurstateid =
1010 					    nd->nd_curstateid;
1011 					nd->nd_flag |= ND_SAVEDCURSTATEID;
1012 				}
1013 			} else {
1014 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1015 			}
1016 			break;
1017 		case NFSV4OP_RESTOREFH:
1018 			if (savevp) {
1019 				nd->nd_repstat = 0;
1020 				/* If vp == savevp, a no-op */
1021 				if (vp != savevp) {
1022 					VREF(savevp);
1023 					vrele(vp);
1024 					vp = savevp;
1025 					vpnes = savevpnes;
1026 					cur_fsid = save_fsid;
1027 				}
1028 				if ((nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
1029 					nd->nd_curstateid =
1030 					    nd->nd_savedcurstateid;
1031 					nd->nd_flag |= ND_CURSTATEID;
1032 				}
1033 			} else {
1034 				nd->nd_repstat = NFSERR_RESTOREFH;
1035 			}
1036 			break;
1037 		default:
1038 		    /*
1039 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
1040 		     * non-exported directory if
1041 		     * nfs_rootfhset. Do I need to allow any other Ops?
1042 		     * (You can only have a non-exported vpnes if
1043 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
1044 		     * Allow AUTH_SYS to be used for file systems
1045 		     * exported GSS only for certain Ops, to allow
1046 		     * clients to do mounts more easily.
1047 		     */
1048 		    if (nfsv4_opflag[op].needscfh && vp) {
1049 			if (!NFSVNO_EXPORTED(&vpnes) &&
1050 			    op != NFSV4OP_LOOKUP &&
1051 			    op != NFSV4OP_GETATTR &&
1052 			    op != NFSV4OP_GETFH &&
1053 			    op != NFSV4OP_ACCESS &&
1054 			    op != NFSV4OP_READLINK &&
1055 			    op != NFSV4OP_SECINFO)
1056 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1057 			else if (nfsvno_testexp(nd, &vpnes) &&
1058 			    op != NFSV4OP_LOOKUP &&
1059 			    op != NFSV4OP_GETFH &&
1060 			    op != NFSV4OP_GETATTR &&
1061 			    op != NFSV4OP_SECINFO)
1062 				nd->nd_repstat = NFSERR_WRONGSEC;
1063 			if (nd->nd_repstat) {
1064 				if (op == NFSV4OP_SETATTR) {
1065 				    /*
1066 				     * Setattr reply requires a bitmap
1067 				     * even for errors like these.
1068 				     */
1069 				    NFSM_BUILD(tl, u_int32_t *,
1070 					NFSX_UNSIGNED);
1071 				    *tl = 0;
1072 				}
1073 				break;
1074 			}
1075 		    }
1076 
1077 		    /*
1078 		     * Save the current positions in the mbuf lists so
1079 		     * that a rollback to this location can be done upon a
1080 		     * redo due to a ERELOOKUP return for a operation.
1081 		     */
1082 		    mb = nd->nd_mb;
1083 		    bpos = nd->nd_bpos;
1084 		    bextpg = nd->nd_bextpg;
1085 		    bextpgsiz = nd->nd_bextpgsiz;
1086 		    md = nd->nd_md;
1087 		    dpos = nd->nd_dpos;
1088 tryagain:
1089 
1090 		    if (nfsv4_opflag[op].retfh == 1) {
1091 			if (!vp) {
1092 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1093 				break;
1094 			}
1095 			VREF(vp);
1096 			if (nfsv4_opflag[op].modifyfs)
1097 				vn_start_write(vp, &temp_mp, V_WAIT);
1098 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
1099 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
1100 			if (!error && !nd->nd_repstat) {
1101 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
1102 				new_mp = nvp->v_mount;
1103 				if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) {
1104 				    /* crossed a server mount point */
1105 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
1106 					nd->nd_nam, &nes, &credanon);
1107 				    if (!nd->nd_repstat)
1108 					nd->nd_repstat = nfsd_excred(nd,
1109 					    &nes, credanon);
1110 				    if (credanon != NULL)
1111 					crfree(credanon);
1112 				    if (!nd->nd_repstat) {
1113 					vpnes = nes;
1114 					cur_fsid = new_mp->mnt_stat.f_fsid;
1115 				    }
1116 				}
1117 				/* Lookup ops return a locked vnode */
1118 				NFSVOPUNLOCK(nvp);
1119 			    }
1120 			    if (!nd->nd_repstat) {
1121 				    vrele(vp);
1122 				    vp = nvp;
1123 			    } else
1124 				    vrele(nvp);
1125 			}
1126 			if (nfsv4_opflag[op].modifyfs)
1127 				vn_finished_write(temp_mp);
1128 		    } else if (nfsv4_opflag[op].retfh == 2) {
1129 			if (vp == NULL || savevp == NULL) {
1130 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1131 				break;
1132 			} else if (fsidcmp(&cur_fsid, &save_fsid) != 0) {
1133 				nd->nd_repstat = NFSERR_XDEV;
1134 				break;
1135 			}
1136 			if (nfsv4_opflag[op].modifyfs)
1137 				vn_start_write(savevp, &temp_mp, V_WAIT);
1138 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1139 				VREF(vp);
1140 				VREF(savevp);
1141 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1142 				    savevp, vp, &savevpnes, &vpnes);
1143 			} else
1144 				nd->nd_repstat = NFSERR_PERM;
1145 			if (nfsv4_opflag[op].modifyfs)
1146 				vn_finished_write(temp_mp);
1147 		    } else {
1148 			if (nfsv4_opflag[op].retfh != 0)
1149 				panic("nfsrvd_compound");
1150 			if (nfsv4_opflag[op].needscfh) {
1151 				if (vp != NULL) {
1152 					lktype = nfsv4_opflag[op].lktype;
1153 					if (nfsv4_opflag[op].modifyfs) {
1154 						vn_start_write(vp, &temp_mp,
1155 						    V_WAIT);
1156 						if (op == NFSV4OP_WRITE &&
1157 						    MNT_SHARED_WRITES(temp_mp))
1158 							lktype = LK_SHARED;
1159 					}
1160 					if (NFSVOPLOCK(vp, lktype) == 0)
1161 						VREF(vp);
1162 					else
1163 						nd->nd_repstat = NFSERR_PERM;
1164 				} else {
1165 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1166 					if (op == NFSV4OP_SETATTR) {
1167 						/*
1168 						 * Setattr reply requires a
1169 						 * bitmap even for errors like
1170 						 * these.
1171 						 */
1172 						NFSM_BUILD(tl, u_int32_t *,
1173 						    NFSX_UNSIGNED);
1174 						*tl = 0;
1175 					}
1176 					break;
1177 				}
1178 				if (nd->nd_repstat == 0)
1179 					error = (*(nfsrv4_ops0[op]))(nd,
1180 					    isdgram, vp, &vpnes);
1181 				if (nfsv4_opflag[op].modifyfs)
1182 					vn_finished_write(temp_mp);
1183 			} else {
1184 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1185 				    NULL, &vpnes);
1186 			}
1187 		    }
1188 		}
1189 		if (error) {
1190 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1191 				nd->nd_repstat = NFSERR_BADXDR;
1192 			} else {
1193 				nd->nd_repstat = error;
1194 				printf("nfsv4 comperr0=%d\n", error);
1195 			}
1196 			error = 0;
1197 		}
1198 
1199 		if (nd->nd_repstat == ERELOOKUP) {
1200 			/*
1201 			 * Roll back to the beginning of the operation
1202 			 * arguments.
1203 			 */
1204 			nd->nd_md = md;
1205 			nd->nd_dpos = dpos;
1206 
1207 			/*
1208 			 * Trim off the bogus reply for this operation
1209 			 * and redo the operation.
1210 			 */
1211 			nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);
1212 			nd->nd_repstat = 0;
1213 			nd->nd_flag |= ND_ERELOOKUP;
1214 			goto tryagain;
1215 		}
1216 		nd->nd_flag &= ~ND_ERELOOKUP;
1217 
1218 		if (statsinprog != 0) {
1219 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1220 			    /*then*/ &start_time);
1221 			statsinprog = 0;
1222 		}
1223 
1224 		retops++;
1225 		if (nd->nd_repstat) {
1226 			*repp = nfsd_errmap(nd);
1227 			break;
1228 		} else {
1229 			*repp = 0;	/* NFS4_OK */
1230 		}
1231 	}
1232 nfsmout:
1233 	if (statsinprog != 0) {
1234 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1235 		    /*then*/ &start_time);
1236 		statsinprog = 0;
1237 	}
1238 	if (error) {
1239 		if (error == EBADRPC || error == NFSERR_BADXDR)
1240 			nd->nd_repstat = NFSERR_BADXDR;
1241 		else
1242 			printf("nfsv4 comperr1=%d\n", error);
1243 	}
1244 	if (taglen == -1) {
1245 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1246 		*tl++ = 0;
1247 		*tl = 0;
1248 	} else {
1249 		*retopsp = txdr_unsigned(retops);
1250 	}
1251 	if (vp)
1252 		vrele(vp);
1253 	if (savevp)
1254 		vrele(savevp);
1255 	NFSLOCKV4ROOTMUTEX();
1256 	nfsv4_relref(&nfsv4rootfs_lock);
1257 	NFSUNLOCKV4ROOTMUTEX();
1258 
1259 	NFSEXITCODE2(0, nd);
1260 }
1261