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