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