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