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