xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 8df8b2d3e51d1b816201d8a1fe8bc29fe192e562)
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 #ifndef APPLEKEXT
44 #include <fs/nfs/nfsport.h>
45 
46 extern struct nfsstatsv1 nfsstatsv1;
47 extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
48 extern int nfs_pubfhset, nfs_rootfhset;
49 extern struct nfsv4lock nfsv4rootfs_lock;
50 extern struct nfsrv_stablefirst nfsrv_stablefirst;
51 extern struct nfsclienthashhead *nfsclienthash;
52 extern int nfsrv_clienthashsize;
53 extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
54 extern int nfsd_debuglevel;
55 extern int nfsrv_layouthighwater;
56 extern volatile int nfsrv_layoutcnt;
57 NFSV4ROOTLOCKMUTEX;
58 NFSSTATESPINLOCK;
59 
60 int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
61     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
62 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
63 	nfsrvd_getattr,
64 	nfsrvd_setattr,
65 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
66 	nfsrvd_access,
67 	nfsrvd_readlink,
68 	nfsrvd_read,
69 	nfsrvd_write,
70 	nfsrvd_create,
71 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
72 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
73 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
74 	nfsrvd_remove,
75 	nfsrvd_remove,
76 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
77 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
78 	nfsrvd_readdir,
79 	nfsrvd_readdirplus,
80 	nfsrvd_statfs,
81 	nfsrvd_fsinfo,
82 	nfsrvd_pathconf,
83 	nfsrvd_commit,
84 };
85 
86 int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
87     int, vnode_t , vnode_t *, fhandle_t *,
88     NFSPROC_T *, struct nfsexstuff *) = {
89 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
90 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
91 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
92 	nfsrvd_lookup,
93 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
94 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
95 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
96 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
97 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_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 *, NFSPROC_T *, struct nfsexstuff *))0,
102 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
103 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
104 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
105 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
106 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
107 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
108 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
109 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
110 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
111 };
112 
113 int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
114     int, vnode_t , vnode_t , NFSPROC_T *,
115     struct nfsexstuff *, struct nfsexstuff *) = {
116 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
117 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
118 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
119 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
120 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
121 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
122 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
123 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
124 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
125 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
126 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
127 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
128 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
129 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
130 	nfsrvd_rename,
131 	nfsrvd_link,
132 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
133 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
134 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
135 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
136 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
137 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
138 };
139 
140 int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *,
141     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
142 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
143 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
144 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
145 	nfsrvd_access,
146 	nfsrvd_close,
147 	nfsrvd_commit,
148 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
149 	nfsrvd_delegpurge,
150 	nfsrvd_delegreturn,
151 	nfsrvd_getattr,
152 	nfsrvd_getfh,
153 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
154 	nfsrvd_lock,
155 	nfsrvd_lockt,
156 	nfsrvd_locku,
157 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
158 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
159 	nfsrvd_verify,
160 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
161 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
162 	nfsrvd_openconfirm,
163 	nfsrvd_opendowngrade,
164 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
165 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
166 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
167 	nfsrvd_read,
168 	nfsrvd_readdirplus,
169 	nfsrvd_readlink,
170 	nfsrvd_remove,
171 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
172 	nfsrvd_renew,
173 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
174 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
175 	nfsrvd_secinfo,
176 	nfsrvd_setattr,
177 	nfsrvd_setclientid,
178 	nfsrvd_setclientidcfrm,
179 	nfsrvd_verify,
180 	nfsrvd_write,
181 	nfsrvd_releaselckown,
182 	nfsrvd_notsupp,
183 	nfsrvd_bindconnsess,
184 	nfsrvd_exchangeid,
185 	nfsrvd_createsession,
186 	nfsrvd_destroysession,
187 	nfsrvd_freestateid,
188 	nfsrvd_notsupp,
189 	nfsrvd_getdevinfo,
190 	nfsrvd_notsupp,
191 	nfsrvd_layoutcommit,
192 	nfsrvd_layoutget,
193 	nfsrvd_layoutreturn,
194 	nfsrvd_notsupp,
195 	nfsrvd_sequence,
196 	nfsrvd_notsupp,
197 	nfsrvd_teststateid,
198 	nfsrvd_notsupp,
199 	nfsrvd_destroyclientid,
200 	nfsrvd_reclaimcomplete,
201 };
202 
203 int (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
204     int, vnode_t , vnode_t *, fhandle_t *,
205     NFSPROC_T *, struct nfsexstuff *) = {
206 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
207 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
208 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
209 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
210 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
211 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
212 	nfsrvd_mknod,
213 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
214 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
215 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
216 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
217 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
218 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
219 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
220 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
221 	nfsrvd_lookup,
222 	nfsrvd_lookup,
223 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
224 	nfsrvd_open,
225 	nfsrvd_openattr,
226 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
227 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
228 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
229 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
230 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
231 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
232 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
233 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
234 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
235 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
236 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
237 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
238 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
239 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
240 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
241 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
242 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
243 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
244 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
245 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
246 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
247 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
248 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
249 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
250 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
251 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
252 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
253 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
254 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
255 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
256 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
257 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
258 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
259 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
260 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
261 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
262 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
263 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
264 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
265 };
266 
267 int (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
268     int, vnode_t , vnode_t , NFSPROC_T *,
269     struct nfsexstuff *, struct nfsexstuff *) = {
270 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
271 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
272 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
273 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
274 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
275 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
276 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
277 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
278 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
279 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
280 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
281 	nfsrvd_link,
282 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
283 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
284 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
285 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
286 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
287 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
288 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
289 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
290 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
291 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
292 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
293 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
294 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
295 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
296 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
297 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
298 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
299 	nfsrvd_rename,
300 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
301 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
302 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
303 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
304 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
305 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
306 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
307 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
308 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
309 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
310 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
311 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
312 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
313 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
314 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
315 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
316 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
317 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
318 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
319 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
320 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
321 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
322 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
323 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
324 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
325 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
326 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
327 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
328 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
329 };
330 #endif	/* !APPLEKEXT */
331 
332 /*
333  * Static array that defines which nfs rpc's are nonidempotent
334  */
335 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
336 	FALSE,
337 	FALSE,
338 	TRUE,
339 	FALSE,
340 	FALSE,
341 	FALSE,
342 	FALSE,
343 	TRUE,
344 	TRUE,
345 	TRUE,
346 	TRUE,
347 	TRUE,
348 	TRUE,
349 	TRUE,
350 	TRUE,
351 	TRUE,
352 	FALSE,
353 	FALSE,
354 	FALSE,
355 	FALSE,
356 	FALSE,
357 	FALSE,
358 };
359 
360 /*
361  * This static array indicates whether or not the RPC modifies the
362  * file system.
363  */
364 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
365     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
366     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
367 
368 /* local functions */
369 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
370     u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p);
371 
372 
373 /*
374  * This static array indicates which server procedures require the extra
375  * arguments to return the current file handle for V2, 3.
376  */
377 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
378 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
379 
380 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
381 
382 static int nfsv3to4op[NFS_V3NPROCS] = {
383 	NFSPROC_NULL,
384 	NFSV4OP_GETATTR,
385 	NFSV4OP_SETATTR,
386 	NFSV4OP_LOOKUP,
387 	NFSV4OP_ACCESS,
388 	NFSV4OP_READLINK,
389 	NFSV4OP_READ,
390 	NFSV4OP_WRITE,
391 	NFSV4OP_V3CREATE,
392 	NFSV4OP_MKDIR,
393 	NFSV4OP_SYMLINK,
394 	NFSV4OP_MKNOD,
395 	NFSV4OP_REMOVE,
396 	NFSV4OP_RMDIR,
397 	NFSV4OP_RENAME,
398 	NFSV4OP_LINK,
399 	NFSV4OP_READDIR,
400 	NFSV4OP_READDIRPLUS,
401 	NFSV4OP_FSSTAT,
402 	NFSV4OP_FSINFO,
403 	NFSV4OP_PATHCONF,
404 	NFSV4OP_COMMIT,
405 };
406 
407 static struct mtx nfsrvd_statmtx;
408 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
409 
410 static void
411 nfsrvd_statstart(int op, struct bintime *now)
412 {
413 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
414 		printf("%s: op %d invalid\n", __func__, op);
415 		return;
416 	}
417 
418 	mtx_lock(&nfsrvd_statmtx);
419 	if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
420 		if (now != NULL)
421 			nfsstatsv1.busyfrom = *now;
422 		else
423 			binuptime(&nfsstatsv1.busyfrom);
424 
425 	}
426 	nfsstatsv1.srvrpccnt[op]++;
427 	nfsstatsv1.srvstartcnt++;
428 	mtx_unlock(&nfsrvd_statmtx);
429 
430 }
431 
432 static void
433 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
434     struct bintime *then)
435 {
436 	struct bintime dt, lnow;
437 
438 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
439 		printf("%s: op %d invalid\n", __func__, op);
440 		return;
441 	}
442 
443 	if (now == NULL) {
444 		now = &lnow;
445 		binuptime(now);
446 	}
447 
448 	mtx_lock(&nfsrvd_statmtx);
449 
450 	nfsstatsv1.srvbytes[op] += bytes;
451 	nfsstatsv1.srvops[op]++;
452 
453 	if (then != NULL) {
454 		dt = *now;
455 		bintime_sub(&dt, then);
456 		bintime_add(&nfsstatsv1.srvduration[op], &dt);
457 	}
458 
459 	dt = *now;
460 	bintime_sub(&dt, &nfsstatsv1.busyfrom);
461 	bintime_add(&nfsstatsv1.busytime, &dt);
462 	nfsstatsv1.busyfrom = *now;
463 
464 	nfsstatsv1.srvdonecnt++;
465 
466 	mtx_unlock(&nfsrvd_statmtx);
467 }
468 
469 /*
470  * Do an RPC. Basically, get the file handles translated to vnode pointers
471  * and then call the appropriate server routine. The server routines are
472  * split into groups, based on whether they use a file handle or file
473  * handle plus name or ...
474  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
475  */
476 APPLESTATIC void
477 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
478     u_int32_t minorvers, NFSPROC_T *p)
479 {
480 	int error = 0, lktype;
481 	vnode_t vp;
482 	mount_t mp = NULL;
483 	struct nfsrvfh fh;
484 	struct nfsexstuff nes;
485 
486 	/*
487 	 * Get a locked vnode for the first file handle
488 	 */
489 	if (!(nd->nd_flag & ND_NFSV4)) {
490 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
491 		/*
492 		 * For NFSv3, if the malloc/mget allocation is near limits,
493 		 * return NFSERR_DELAY.
494 		 */
495 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
496 			nd->nd_repstat = NFSERR_DELAY;
497 			vp = NULL;
498 		} else {
499 			error = nfsrv_mtofh(nd, &fh);
500 			if (error) {
501 				if (error != EBADRPC)
502 					printf("nfs dorpc err1=%d\n", error);
503 				nd->nd_repstat = NFSERR_GARBAGE;
504 				goto out;
505 			}
506 			if (nd->nd_procnum == NFSPROC_READ ||
507 			    nd->nd_procnum == NFSPROC_WRITE ||
508 			    nd->nd_procnum == NFSPROC_READDIR ||
509 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
510 			    nd->nd_procnum == NFSPROC_READLINK ||
511 			    nd->nd_procnum == NFSPROC_GETATTR ||
512 			    nd->nd_procnum == NFSPROC_ACCESS ||
513 			    nd->nd_procnum == NFSPROC_FSSTAT ||
514 			    nd->nd_procnum == NFSPROC_FSINFO)
515 				lktype = LK_SHARED;
516 			else
517 				lktype = LK_EXCLUSIVE;
518 			if (nd->nd_flag & ND_PUBLOOKUP)
519 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
520 				    &mp, nfsrv_writerpc[nd->nd_procnum], p);
521 			else
522 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
523 				    &mp, nfsrv_writerpc[nd->nd_procnum], p);
524 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
525 				goto out;
526 		}
527 	}
528 
529 	/*
530 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
531 	 * cache, as required.
532 	 * For V4, nfsrvd_compound() does this.
533 	 */
534 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
535 		nd->nd_flag |= ND_SAVEREPLY;
536 
537 	nfsrvd_rephead(nd);
538 	/*
539 	 * If nd_repstat is non-zero, just fill in the reply status
540 	 * to complete the RPC reply for V2. Otherwise, you must do
541 	 * the RPC.
542 	 */
543 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
544 		*nd->nd_errp = nfsd_errmap(nd);
545 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
546 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
547 		   /*now*/ NULL, /*then*/ NULL);
548 		if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
549 			vn_finished_write(mp);
550 		goto out;
551 	}
552 
553 	/*
554 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
555 	 * works through the sub-rpcs, otherwise just call the procedure.
556 	 * The procedures are in three groups with different arguments.
557 	 * The group is indicated by the value in nfs_retfh[].
558 	 */
559 	if (nd->nd_flag & ND_NFSV4) {
560 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
561 	} else {
562 		struct bintime start_time;
563 
564 		binuptime(&start_time);
565 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
566 
567 		if (nfs_retfh[nd->nd_procnum] == 1) {
568 			if (vp)
569 				NFSVOPUNLOCK(vp, 0);
570 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
571 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
572 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
573 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
574 			    vp, NULL, p, &nes, NULL);
575 		} else {
576 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
577 			    vp, p, &nes);
578 		}
579 		if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
580 			vn_finished_write(mp);
581 
582 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
583 		    /*now*/ NULL, /*then*/ &start_time);
584 	}
585 	if (error) {
586 		if (error != EBADRPC)
587 			printf("nfs dorpc err2=%d\n", error);
588 		nd->nd_repstat = NFSERR_GARBAGE;
589 	}
590 	*nd->nd_errp = nfsd_errmap(nd);
591 
592 	/*
593 	 * Don't cache certain reply status values.
594 	 */
595 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
596 	    (nd->nd_repstat == NFSERR_GARBAGE ||
597 	     nd->nd_repstat == NFSERR_BADXDR ||
598 	     nd->nd_repstat == NFSERR_MOVED ||
599 	     nd->nd_repstat == NFSERR_DELAY ||
600 	     nd->nd_repstat == NFSERR_BADSEQID ||
601 	     nd->nd_repstat == NFSERR_RESOURCE ||
602 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
603 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
604 	     nd->nd_repstat == NFSERR_STALESTATEID ||
605 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
606 	     nd->nd_repstat == NFSERR_BADSTATEID ||
607 	     nd->nd_repstat == NFSERR_GRACE ||
608 	     nd->nd_repstat == NFSERR_NOGRACE))
609 		nd->nd_flag &= ~ND_SAVEREPLY;
610 
611 out:
612 	NFSEXITCODE2(0, nd);
613 }
614 
615 /*
616  * Breaks down a compound RPC request and calls the server routines for
617  * the subprocedures.
618  * Some suboperations are performed directly here to simplify file handle<-->
619  * vnode pointer handling.
620  */
621 static void
622 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
623     int taglen, u_int32_t minorvers, NFSPROC_T *p)
624 {
625 	int i, lktype, op, op0 = 0, statsinprog = 0;
626 	u_int32_t *tl;
627 	struct nfsclient *clp, *nclp;
628 	int numops, error = 0, igotlock;
629 	u_int32_t retops = 0, *retopsp = NULL, *repp;
630 	vnode_t vp, nvp, savevp;
631 	struct nfsrvfh fh;
632 	mount_t new_mp, temp_mp = NULL;
633 	struct ucred *credanon;
634 	struct nfsexstuff nes, vpnes, savevpnes;
635 	fsid_t cur_fsid, save_fsid;
636 	static u_int64_t compref = 0;
637 	struct bintime start_time;
638 
639 	NFSVNO_EXINIT(&vpnes);
640 	NFSVNO_EXINIT(&savevpnes);
641 	/*
642 	 * Put the seq# of the current compound RPC in nfsrv_descript.
643 	 * (This is used by nfsrv_checkgetattr(), to see if the write
644 	 *  delegation was created by the same compound RPC as the one
645 	 *  with that Getattr in it.)
646 	 * Don't worry about the 64bit number wrapping around. It ain't
647 	 * gonna happen before this server gets shut down/rebooted.
648 	 */
649 	nd->nd_compref = compref++;
650 
651 	/*
652 	 * Check for and optionally get a lock on the root. This lock means that
653 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
654 	 * is required when the V4 root is being changed, the stable storage
655 	 * restart file is being updated, or callbacks are being done.
656 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
657 	 * either hold a reference count (nfs_usecnt) or the lock. When
658 	 * nfsrv_unlock() is called to release the lock, it can optionally
659 	 * also get a reference count, which saves the need for a call to
660 	 * nfsrv_getref() after nfsrv_unlock().
661 	 */
662 	/*
663 	 * First, check to see if we need to wait for an update lock.
664 	 */
665 	igotlock = 0;
666 	NFSLOCKV4ROOTMUTEX();
667 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
668 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
669 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
670 	else
671 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
672 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
673 	NFSUNLOCKV4ROOTMUTEX();
674 	if (igotlock) {
675 		/*
676 		 * If I got the lock, I can update the stable storage file.
677 		 * Done when the grace period is over or a client has long
678 		 * since expired.
679 		 */
680 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
681 		if ((nfsrv_stablefirst.nsf_flags &
682 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
683 			nfsrv_updatestable(p);
684 
685 		/*
686 		 * If at least one client has long since expired, search
687 		 * the client list for them, write a REVOKE record on the
688 		 * stable storage file and then remove them from the client
689 		 * list.
690 		 */
691 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
692 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
693 			for (i = 0; i < nfsrv_clienthashsize; i++) {
694 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
695 				nclp) {
696 				if (clp->lc_flags & LCL_EXPIREIT) {
697 				    if (!LIST_EMPTY(&clp->lc_open) ||
698 					!LIST_EMPTY(&clp->lc_deleg))
699 					nfsrv_writestable(clp->lc_id,
700 					    clp->lc_idlen, NFSNST_REVOKE, p);
701 				    nfsrv_cleanclient(clp, p);
702 				    nfsrv_freedeleglist(&clp->lc_deleg);
703 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
704 				    LIST_REMOVE(clp, lc_hash);
705 				    nfsrv_zapclient(clp, p);
706 				}
707 			    }
708 			}
709 		}
710 		NFSLOCKV4ROOTMUTEX();
711 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
712 		NFSUNLOCKV4ROOTMUTEX();
713 	} else {
714 		/*
715 		 * If we didn't get the lock, we need to get a refcnt,
716 		 * which also checks for and waits for the lock.
717 		 */
718 		NFSLOCKV4ROOTMUTEX();
719 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
720 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
721 		NFSUNLOCKV4ROOTMUTEX();
722 	}
723 
724 	/*
725 	 * If flagged, search for open owners that haven't had any opens
726 	 * for a long time.
727 	 */
728 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
729 		nfsrv_throwawayopens(p);
730 	}
731 
732 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
733 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
734 		nfsrv_recalloldlayout(p);
735 
736 	savevp = vp = NULL;
737 	save_fsid.val[0] = save_fsid.val[1] = 0;
738 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
739 
740 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
741 	if (taglen < 0) {
742 		error = EBADRPC;
743 		goto nfsmout;
744 	}
745 
746 	(void) nfsm_strtom(nd, tag, taglen);
747 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
748 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
749 	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
750 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
751 	if (nd->nd_repstat)
752 		numops = 0;
753 	else
754 		numops = fxdr_unsigned(int, *tl);
755 	/*
756 	 * Loop around doing the sub ops.
757 	 * vp - is an unlocked vnode pointer for the CFH
758 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
759 	 * (at some future date, it might turn out to be more appropriate
760 	 *  to keep the file handles instead of vnode pointers?)
761 	 * savevpnes and vpnes - are the export flags for the above.
762 	 */
763 	for (i = 0; i < numops; i++) {
764 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
765 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
766 		*repp = *tl;
767 		op = fxdr_unsigned(int, *tl);
768 		NFSD_DEBUG(4, "op=%d\n", op);
769 		if (op < NFSV4OP_ACCESS ||
770 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
771 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
772 			nd->nd_repstat = NFSERR_OPILLEGAL;
773 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
774 			*repp = nfsd_errmap(nd);
775 			retops++;
776 			break;
777 		} else {
778 			repp++;
779 		}
780 
781 		binuptime(&start_time);
782 		nfsrvd_statstart(op, &start_time);
783 		statsinprog = 1;
784 
785 		if (i == 0)
786 			op0 = op;
787 		if (i == numops - 1)
788 			nd->nd_flag |= ND_LASTOP;
789 
790 		/*
791 		 * Check for a referral on the current FH and, if so, return
792 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
793 		 */
794 		if (vp != NULL && op != NFSV4OP_GETATTR &&
795 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
796 		    nfsrv_errmoved(op)) {
797 			nd->nd_repstat = NFSERR_MOVED;
798 			*repp = nfsd_errmap(nd);
799 			retops++;
800 			break;
801 		}
802 
803 		/*
804 		 * For NFSv4.1, check for a Sequence Operation being first
805 		 * or one of the other allowed operations by itself.
806 		 */
807 		if ((nd->nd_flag & ND_NFSV41) != 0) {
808 			if (i != 0 && op == NFSV4OP_SEQUENCE)
809 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
810 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
811 			    op != NFSV4OP_EXCHANGEID &&
812 			    op != NFSV4OP_CREATESESSION &&
813 			    op != NFSV4OP_BINDCONNTOSESS &&
814 			    op != NFSV4OP_DESTROYCLIENTID &&
815 			    op != NFSV4OP_DESTROYSESSION)
816 				nd->nd_repstat = NFSERR_OPNOTINSESS;
817 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
818 				nd->nd_repstat = NFSERR_NOTONLYOP;
819 			if (nd->nd_repstat != 0) {
820 				*repp = nfsd_errmap(nd);
821 				retops++;
822 				break;
823 			}
824 		}
825 
826 		nd->nd_procnum = op;
827 		/*
828 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
829 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
830 		 * really nasty for certain Op sequences, I'll play it safe
831 		 * and only return the error at the beginning.) The cache
832 		 * will still function over flood level, but uses lots of
833 		 * mbufs.)
834 		 * If nfsrv_mallocmget_limit() returns True, the system is near
835 		 * to its limit for memory that malloc()/mget() can allocate.
836 		 */
837 		if (i == 0 && (nd->nd_rp == NULL ||
838 		    nd->nd_rp->rc_refcnt == 0) &&
839 		    (nfsrv_mallocmget_limit() ||
840 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
841 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
842 				printf("nfsd server cache flooded, try "
843 				    "increasing vfs.nfsd.tcphighwater\n");
844 			nd->nd_repstat = NFSERR_RESOURCE;
845 			*repp = nfsd_errmap(nd);
846 			if (op == NFSV4OP_SETATTR) {
847 				/*
848 				 * Setattr replies require a bitmap.
849 				 * even for errors like these.
850 				 */
851 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
852 				*tl = 0;
853 			}
854 			retops++;
855 			break;
856 		}
857 		if (nfsv4_opflag[op].savereply)
858 			nd->nd_flag |= ND_SAVEREPLY;
859 		switch (op) {
860 		case NFSV4OP_PUTFH:
861 			error = nfsrv_mtofh(nd, &fh);
862 			if (error)
863 				goto nfsmout;
864 			if (!nd->nd_repstat)
865 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
866 				    NULL, 0, p);
867 			/* For now, allow this for non-export FHs */
868 			if (!nd->nd_repstat) {
869 				if (vp)
870 					vrele(vp);
871 				vp = nvp;
872 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
873 				NFSVOPUNLOCK(vp, 0);
874 				vpnes = nes;
875 			}
876 			break;
877 		case NFSV4OP_PUTPUBFH:
878 			if (nfs_pubfhset)
879 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
880 				&nes, NULL, 0, p);
881 			else
882 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
883 			if (!nd->nd_repstat) {
884 				if (vp)
885 					vrele(vp);
886 				vp = nvp;
887 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
888 				NFSVOPUNLOCK(vp, 0);
889 				vpnes = nes;
890 			}
891 			break;
892 		case NFSV4OP_PUTROOTFH:
893 			if (nfs_rootfhset) {
894 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
895 				    &nes, NULL, 0, p);
896 				if (!nd->nd_repstat) {
897 					if (vp)
898 						vrele(vp);
899 					vp = nvp;
900 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
901 					NFSVOPUNLOCK(vp, 0);
902 					vpnes = nes;
903 				}
904 			} else
905 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
906 			break;
907 		case NFSV4OP_SAVEFH:
908 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
909 				nd->nd_repstat = 0;
910 				/* If vp == savevp, a no-op */
911 				if (vp != savevp) {
912 					if (savevp)
913 						vrele(savevp);
914 					VREF(vp);
915 					savevp = vp;
916 					savevpnes = vpnes;
917 					save_fsid = cur_fsid;
918 				}
919 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
920 					nd->nd_savedcurstateid =
921 					    nd->nd_curstateid;
922 					nd->nd_flag |= ND_SAVEDCURSTATEID;
923 				}
924 			} else {
925 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
926 			}
927 			break;
928 		case NFSV4OP_RESTOREFH:
929 			if (savevp) {
930 				nd->nd_repstat = 0;
931 				/* If vp == savevp, a no-op */
932 				if (vp != savevp) {
933 					VREF(savevp);
934 					vrele(vp);
935 					vp = savevp;
936 					vpnes = savevpnes;
937 					cur_fsid = save_fsid;
938 				}
939 				if ((nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
940 					nd->nd_curstateid =
941 					    nd->nd_savedcurstateid;
942 					nd->nd_flag |= ND_CURSTATEID;
943 				}
944 			} else {
945 				nd->nd_repstat = NFSERR_RESTOREFH;
946 			}
947 			break;
948 		default:
949 		    /*
950 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
951 		     * non-exported directory if
952 		     * nfs_rootfhset. Do I need to allow any other Ops?
953 		     * (You can only have a non-exported vpnes if
954 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
955 		     * Allow AUTH_SYS to be used for file systems
956 		     * exported GSS only for certain Ops, to allow
957 		     * clients to do mounts more easily.
958 		     */
959 		    if (nfsv4_opflag[op].needscfh && vp) {
960 			if (!NFSVNO_EXPORTED(&vpnes) &&
961 			    op != NFSV4OP_LOOKUP &&
962 			    op != NFSV4OP_GETATTR &&
963 			    op != NFSV4OP_GETFH &&
964 			    op != NFSV4OP_ACCESS &&
965 			    op != NFSV4OP_READLINK &&
966 			    op != NFSV4OP_SECINFO)
967 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
968 			else if (nfsvno_testexp(nd, &vpnes) &&
969 			    op != NFSV4OP_LOOKUP &&
970 			    op != NFSV4OP_GETFH &&
971 			    op != NFSV4OP_GETATTR &&
972 			    op != NFSV4OP_SECINFO)
973 				nd->nd_repstat = NFSERR_WRONGSEC;
974 			if (nd->nd_repstat) {
975 				if (op == NFSV4OP_SETATTR) {
976 				    /*
977 				     * Setattr reply requires a bitmap
978 				     * even for errors like these.
979 				     */
980 				    NFSM_BUILD(tl, u_int32_t *,
981 					NFSX_UNSIGNED);
982 				    *tl = 0;
983 				}
984 				break;
985 			}
986 		    }
987 		    if (nfsv4_opflag[op].retfh == 1) {
988 			if (!vp) {
989 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
990 				break;
991 			}
992 			VREF(vp);
993 			if (nfsv4_opflag[op].modifyfs)
994 				vn_start_write(vp, &temp_mp, V_WAIT);
995 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
996 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
997 			if (!error && !nd->nd_repstat) {
998 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
999 				new_mp = nvp->v_mount;
1000 				if (cur_fsid.val[0] !=
1001 				    new_mp->mnt_stat.f_fsid.val[0] ||
1002 				    cur_fsid.val[1] !=
1003 				    new_mp->mnt_stat.f_fsid.val[1]) {
1004 				    /* crossed a server mount point */
1005 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
1006 					nd->nd_nam, &nes, &credanon);
1007 				    if (!nd->nd_repstat)
1008 					nd->nd_repstat = nfsd_excred(nd,
1009 					    &nes, credanon);
1010 				    if (credanon != NULL)
1011 					crfree(credanon);
1012 				    if (!nd->nd_repstat) {
1013 					vpnes = nes;
1014 					cur_fsid = new_mp->mnt_stat.f_fsid;
1015 				    }
1016 				}
1017 				/* Lookup ops return a locked vnode */
1018 				NFSVOPUNLOCK(nvp, 0);
1019 			    }
1020 			    if (!nd->nd_repstat) {
1021 				    vrele(vp);
1022 				    vp = nvp;
1023 			    } else
1024 				    vrele(nvp);
1025 			}
1026 			if (nfsv4_opflag[op].modifyfs)
1027 				vn_finished_write(temp_mp);
1028 		    } else if (nfsv4_opflag[op].retfh == 2) {
1029 			if (vp == NULL || savevp == NULL) {
1030 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1031 				break;
1032 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
1033 			    cur_fsid.val[1] != save_fsid.val[1]) {
1034 				nd->nd_repstat = NFSERR_XDEV;
1035 				break;
1036 			}
1037 			if (nfsv4_opflag[op].modifyfs)
1038 				vn_start_write(savevp, &temp_mp, V_WAIT);
1039 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1040 				VREF(vp);
1041 				VREF(savevp);
1042 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1043 				    savevp, vp, p, &savevpnes, &vpnes);
1044 			} else
1045 				nd->nd_repstat = NFSERR_PERM;
1046 			if (nfsv4_opflag[op].modifyfs)
1047 				vn_finished_write(temp_mp);
1048 		    } else {
1049 			if (nfsv4_opflag[op].retfh != 0)
1050 				panic("nfsrvd_compound");
1051 			if (nfsv4_opflag[op].needscfh) {
1052 				if (vp != NULL) {
1053 					lktype = nfsv4_opflag[op].lktype;
1054 					if (nfsv4_opflag[op].modifyfs) {
1055 						vn_start_write(vp, &temp_mp,
1056 						    V_WAIT);
1057 						if (op == NFSV4OP_WRITE &&
1058 						    MNT_SHARED_WRITES(temp_mp))
1059 							lktype = LK_SHARED;
1060 					}
1061 					if (NFSVOPLOCK(vp, lktype) == 0)
1062 						VREF(vp);
1063 					else
1064 						nd->nd_repstat = NFSERR_PERM;
1065 				} else {
1066 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1067 					if (op == NFSV4OP_SETATTR) {
1068 						/*
1069 						 * Setattr reply requires a
1070 						 * bitmap even for errors like
1071 						 * these.
1072 						 */
1073 						NFSM_BUILD(tl, u_int32_t *,
1074 						    NFSX_UNSIGNED);
1075 						*tl = 0;
1076 					}
1077 					break;
1078 				}
1079 				if (nd->nd_repstat == 0)
1080 					error = (*(nfsrv4_ops0[op]))(nd,
1081 					    isdgram, vp, p, &vpnes);
1082 				if (nfsv4_opflag[op].modifyfs)
1083 					vn_finished_write(temp_mp);
1084 			} else {
1085 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1086 				    NULL, p, &vpnes);
1087 			}
1088 		    }
1089 		}
1090 		if (error) {
1091 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1092 				nd->nd_repstat = NFSERR_BADXDR;
1093 			} else {
1094 				nd->nd_repstat = error;
1095 				printf("nfsv4 comperr0=%d\n", error);
1096 			}
1097 			error = 0;
1098 		}
1099 
1100 		if (statsinprog != 0) {
1101 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1102 			    /*then*/ &start_time);
1103 			statsinprog = 0;
1104 		}
1105 
1106 		retops++;
1107 		if (nd->nd_repstat) {
1108 			*repp = nfsd_errmap(nd);
1109 			break;
1110 		} else {
1111 			*repp = 0;	/* NFS4_OK */
1112 		}
1113 	}
1114 nfsmout:
1115 	if (statsinprog != 0) {
1116 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1117 		    /*then*/ &start_time);
1118 		statsinprog = 0;
1119 	}
1120 	if (error) {
1121 		if (error == EBADRPC || error == NFSERR_BADXDR)
1122 			nd->nd_repstat = NFSERR_BADXDR;
1123 		else
1124 			printf("nfsv4 comperr1=%d\n", error);
1125 	}
1126 	if (taglen == -1) {
1127 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1128 		*tl++ = 0;
1129 		*tl = 0;
1130 	} else {
1131 		*retopsp = txdr_unsigned(retops);
1132 	}
1133 	if (vp)
1134 		vrele(vp);
1135 	if (savevp)
1136 		vrele(savevp);
1137 	NFSLOCKV4ROOTMUTEX();
1138 	nfsv4_relref(&nfsv4rootfs_lock);
1139 	NFSUNLOCKV4ROOTMUTEX();
1140 
1141 	NFSEXITCODE2(0, nd);
1142 }
1143