xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
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;
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 /*
404  * Do an RPC. Basically, get the file handles translated to vnode pointers
405  * and then call the appropriate server routine. The server routines are
406  * split into groups, based on whether they use a file handle or file
407  * handle plus name or ...
408  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
409  */
410 APPLESTATIC void
411 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
412     u_int32_t minorvers, NFSPROC_T *p)
413 {
414 	int error = 0, lktype;
415 	vnode_t vp;
416 	mount_t mp = NULL;
417 	struct nfsrvfh fh;
418 	struct nfsexstuff nes;
419 
420 	/*
421 	 * Get a locked vnode for the first file handle
422 	 */
423 	if (!(nd->nd_flag & ND_NFSV4)) {
424 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
425 		/*
426 		 * For NFSv3, if the malloc/mget allocation is near limits,
427 		 * return NFSERR_DELAY.
428 		 */
429 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
430 			nd->nd_repstat = NFSERR_DELAY;
431 			vp = NULL;
432 		} else {
433 			error = nfsrv_mtofh(nd, &fh);
434 			if (error) {
435 				if (error != EBADRPC)
436 					printf("nfs dorpc err1=%d\n", error);
437 				nd->nd_repstat = NFSERR_GARBAGE;
438 				goto out;
439 			}
440 			if (nd->nd_procnum == NFSPROC_READ ||
441 			    nd->nd_procnum == NFSPROC_WRITE ||
442 			    nd->nd_procnum == NFSPROC_READDIR ||
443 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
444 			    nd->nd_procnum == NFSPROC_READLINK ||
445 			    nd->nd_procnum == NFSPROC_GETATTR ||
446 			    nd->nd_procnum == NFSPROC_ACCESS ||
447 			    nd->nd_procnum == NFSPROC_FSSTAT ||
448 			    nd->nd_procnum == NFSPROC_FSINFO)
449 				lktype = LK_SHARED;
450 			else
451 				lktype = LK_EXCLUSIVE;
452 			if (nd->nd_flag & ND_PUBLOOKUP)
453 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
454 				    &mp, nfs_writerpc[nd->nd_procnum], p);
455 			else
456 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
457 				    &mp, nfs_writerpc[nd->nd_procnum], p);
458 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
459 				goto out;
460 		}
461 	}
462 
463 	/*
464 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
465 	 * cache, as required.
466 	 * For V4, nfsrvd_compound() does this.
467 	 */
468 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
469 		nd->nd_flag |= ND_SAVEREPLY;
470 
471 	nfsrvd_rephead(nd);
472 	/*
473 	 * If nd_repstat is non-zero, just fill in the reply status
474 	 * to complete the RPC reply for V2. Otherwise, you must do
475 	 * the RPC.
476 	 */
477 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
478 		*nd->nd_errp = nfsd_errmap(nd);
479 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
480 		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
481 			vn_finished_write(mp);
482 		goto out;
483 	}
484 
485 	/*
486 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
487 	 * works through the sub-rpcs, otherwise just call the procedure.
488 	 * The procedures are in three groups with different arguments.
489 	 * The group is indicated by the value in nfs_retfh[].
490 	 */
491 	if (nd->nd_flag & ND_NFSV4) {
492 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
493 	} else {
494 		if (nfs_retfh[nd->nd_procnum] == 1) {
495 			if (vp)
496 				NFSVOPUNLOCK(vp, 0);
497 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
498 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
499 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
500 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
501 			    vp, NULL, p, &nes, NULL);
502 		} else {
503 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
504 			    vp, p, &nes);
505 		}
506 		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
507 			vn_finished_write(mp);
508 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
509 	}
510 	if (error) {
511 		if (error != EBADRPC)
512 			printf("nfs dorpc err2=%d\n", error);
513 		nd->nd_repstat = NFSERR_GARBAGE;
514 	}
515 	*nd->nd_errp = nfsd_errmap(nd);
516 
517 	/*
518 	 * Don't cache certain reply status values.
519 	 */
520 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
521 	    (nd->nd_repstat == NFSERR_GARBAGE ||
522 	     nd->nd_repstat == NFSERR_BADXDR ||
523 	     nd->nd_repstat == NFSERR_MOVED ||
524 	     nd->nd_repstat == NFSERR_DELAY ||
525 	     nd->nd_repstat == NFSERR_BADSEQID ||
526 	     nd->nd_repstat == NFSERR_RESOURCE ||
527 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
528 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
529 	     nd->nd_repstat == NFSERR_STALESTATEID ||
530 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
531 	     nd->nd_repstat == NFSERR_BADSTATEID ||
532 	     nd->nd_repstat == NFSERR_GRACE ||
533 	     nd->nd_repstat == NFSERR_NOGRACE))
534 		nd->nd_flag &= ~ND_SAVEREPLY;
535 
536 out:
537 	NFSEXITCODE2(0, nd);
538 }
539 
540 /*
541  * Breaks down a compound RPC request and calls the server routines for
542  * the subprocedures.
543  * Some suboperations are performed directly here to simplify file handle<-->
544  * vnode pointer handling.
545  */
546 static void
547 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
548     int taglen, u_int32_t minorvers, NFSPROC_T *p)
549 {
550 	int i, lktype, op, op0 = 0;
551 	u_int32_t *tl;
552 	struct nfsclient *clp, *nclp;
553 	int numops, error = 0, igotlock;
554 	u_int32_t retops = 0, *retopsp = NULL, *repp;
555 	vnode_t vp, nvp, savevp;
556 	struct nfsrvfh fh;
557 	mount_t new_mp, temp_mp = NULL;
558 	struct ucred *credanon;
559 	struct nfsexstuff nes, vpnes, savevpnes;
560 	fsid_t cur_fsid, save_fsid;
561 	static u_int64_t compref = 0;
562 
563 	NFSVNO_EXINIT(&vpnes);
564 	NFSVNO_EXINIT(&savevpnes);
565 	/*
566 	 * Put the seq# of the current compound RPC in nfsrv_descript.
567 	 * (This is used by nfsrv_checkgetattr(), to see if the write
568 	 *  delegation was created by the same compound RPC as the one
569 	 *  with that Getattr in it.)
570 	 * Don't worry about the 64bit number wrapping around. It ain't
571 	 * gonna happen before this server gets shut down/rebooted.
572 	 */
573 	nd->nd_compref = compref++;
574 
575 	/*
576 	 * Check for and optionally get a lock on the root. This lock means that
577 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
578 	 * is required when the V4 root is being changed, the stable storage
579 	 * restart file is being updated, or callbacks are being done.
580 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
581 	 * either hold a reference count (nfs_usecnt) or the lock. When
582 	 * nfsrv_unlock() is called to release the lock, it can optionally
583 	 * also get a reference count, which saves the need for a call to
584 	 * nfsrv_getref() after nfsrv_unlock().
585 	 */
586 	/*
587 	 * First, check to see if we need to wait for an update lock.
588 	 */
589 	igotlock = 0;
590 	NFSLOCKV4ROOTMUTEX();
591 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
592 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
593 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
594 	else
595 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
596 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
597 	NFSUNLOCKV4ROOTMUTEX();
598 	if (igotlock) {
599 		/*
600 		 * If I got the lock, I can update the stable storage file.
601 		 * Done when the grace period is over or a client has long
602 		 * since expired.
603 		 */
604 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
605 		if ((nfsrv_stablefirst.nsf_flags &
606 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
607 			nfsrv_updatestable(p);
608 
609 		/*
610 		 * If at least one client has long since expired, search
611 		 * the client list for them, write a REVOKE record on the
612 		 * stable storage file and then remove them from the client
613 		 * list.
614 		 */
615 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
616 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
617 			for (i = 0; i < nfsrv_clienthashsize; i++) {
618 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
619 				nclp) {
620 				if (clp->lc_flags & LCL_EXPIREIT) {
621 				    if (!LIST_EMPTY(&clp->lc_open) ||
622 					!LIST_EMPTY(&clp->lc_deleg))
623 					nfsrv_writestable(clp->lc_id,
624 					    clp->lc_idlen, NFSNST_REVOKE, p);
625 				    nfsrv_cleanclient(clp, p);
626 				    nfsrv_freedeleglist(&clp->lc_deleg);
627 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
628 				    LIST_REMOVE(clp, lc_hash);
629 				    nfsrv_zapclient(clp, p);
630 				}
631 			    }
632 			}
633 		}
634 		NFSLOCKV4ROOTMUTEX();
635 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
636 		NFSUNLOCKV4ROOTMUTEX();
637 	} else {
638 		/*
639 		 * If we didn't get the lock, we need to get a refcnt,
640 		 * which also checks for and waits for the lock.
641 		 */
642 		NFSLOCKV4ROOTMUTEX();
643 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
644 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
645 		NFSUNLOCKV4ROOTMUTEX();
646 	}
647 
648 	/*
649 	 * If flagged, search for open owners that haven't had any opens
650 	 * for a long time.
651 	 */
652 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
653 		nfsrv_throwawayopens(p);
654 	}
655 
656 	savevp = vp = NULL;
657 	save_fsid.val[0] = save_fsid.val[1] = 0;
658 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
659 
660 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
661 	if (taglen < 0) {
662 		error = EBADRPC;
663 		goto nfsmout;
664 	}
665 
666 	(void) nfsm_strtom(nd, tag, taglen);
667 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
668 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
669 	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
670 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
671 	if (nd->nd_repstat)
672 		numops = 0;
673 	else
674 		numops = fxdr_unsigned(int, *tl);
675 	/*
676 	 * Loop around doing the sub ops.
677 	 * vp - is an unlocked vnode pointer for the CFH
678 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
679 	 * (at some future date, it might turn out to be more appropriate
680 	 *  to keep the file handles instead of vnode pointers?)
681 	 * savevpnes and vpnes - are the export flags for the above.
682 	 */
683 	for (i = 0; i < numops; i++) {
684 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
685 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
686 		*repp = *tl;
687 		op = fxdr_unsigned(int, *tl);
688 		NFSD_DEBUG(4, "op=%d\n", op);
689 		if (op < NFSV4OP_ACCESS ||
690 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
691 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
692 			nd->nd_repstat = NFSERR_OPILLEGAL;
693 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
694 			*repp = nfsd_errmap(nd);
695 			retops++;
696 			break;
697 		} else {
698 			repp++;
699 		}
700 		if (i == 0)
701 			op0 = op;
702 		if (i == numops - 1)
703 			nd->nd_flag |= ND_LASTOP;
704 
705 		/*
706 		 * Check for a referral on the current FH and, if so, return
707 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
708 		 */
709 		if (vp != NULL && op != NFSV4OP_GETATTR &&
710 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
711 		    nfsrv_errmoved(op)) {
712 			nd->nd_repstat = NFSERR_MOVED;
713 			*repp = nfsd_errmap(nd);
714 			retops++;
715 			break;
716 		}
717 
718 		/*
719 		 * For NFSv4.1, check for a Sequence Operation being first
720 		 * or one of the other allowed operations by itself.
721 		 */
722 		if ((nd->nd_flag & ND_NFSV41) != 0) {
723 			if (i != 0 && op == NFSV4OP_SEQUENCE)
724 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
725 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
726 			    op != NFSV4OP_EXCHANGEID &&
727 			    op != NFSV4OP_CREATESESSION &&
728 			    op != NFSV4OP_BINDCONNTOSESS &&
729 			    op != NFSV4OP_DESTROYCLIENTID &&
730 			    op != NFSV4OP_DESTROYSESSION)
731 				nd->nd_repstat = NFSERR_OPNOTINSESS;
732 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
733 				nd->nd_repstat = NFSERR_NOTONLYOP;
734 			if (nd->nd_repstat != 0) {
735 				*repp = nfsd_errmap(nd);
736 				retops++;
737 				break;
738 			}
739 		}
740 
741 		nd->nd_procnum = op;
742 		/*
743 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
744 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
745 		 * really nasty for certain Op sequences, I'll play it safe
746 		 * and only return the error at the beginning.) The cache
747 		 * will still function over flood level, but uses lots of
748 		 * mbufs.)
749 		 * If nfsrv_mallocmget_limit() returns True, the system is near
750 		 * to its limit for memory that malloc()/mget() can allocate.
751 		 */
752 		if (i == 0 && (nd->nd_rp == NULL ||
753 		    nd->nd_rp->rc_refcnt == 0) &&
754 		    (nfsrv_mallocmget_limit() ||
755 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
756 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
757 				printf("nfsd server cache flooded, try "
758 				    "increasing vfs.nfsd.tcphighwater\n");
759 			nd->nd_repstat = NFSERR_RESOURCE;
760 			*repp = nfsd_errmap(nd);
761 			if (op == NFSV4OP_SETATTR) {
762 				/*
763 				 * Setattr replies require a bitmap.
764 				 * even for errors like these.
765 				 */
766 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
767 				*tl = 0;
768 			}
769 			retops++;
770 			break;
771 		}
772 		if (nfsv4_opflag[op].savereply)
773 			nd->nd_flag |= ND_SAVEREPLY;
774 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
775 		switch (op) {
776 		case NFSV4OP_PUTFH:
777 			error = nfsrv_mtofh(nd, &fh);
778 			if (error)
779 				goto nfsmout;
780 			if (!nd->nd_repstat)
781 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
782 				    NULL, 0, p);
783 			/* For now, allow this for non-export FHs */
784 			if (!nd->nd_repstat) {
785 				if (vp)
786 					vrele(vp);
787 				vp = nvp;
788 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
789 				NFSVOPUNLOCK(vp, 0);
790 				vpnes = nes;
791 			}
792 			break;
793 		case NFSV4OP_PUTPUBFH:
794 			if (nfs_pubfhset)
795 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
796 				&nes, NULL, 0, p);
797 			else
798 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
799 			if (!nd->nd_repstat) {
800 				if (vp)
801 					vrele(vp);
802 				vp = nvp;
803 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
804 				NFSVOPUNLOCK(vp, 0);
805 				vpnes = nes;
806 			}
807 			break;
808 		case NFSV4OP_PUTROOTFH:
809 			if (nfs_rootfhset) {
810 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
811 				    &nes, NULL, 0, p);
812 				if (!nd->nd_repstat) {
813 					if (vp)
814 						vrele(vp);
815 					vp = nvp;
816 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
817 					NFSVOPUNLOCK(vp, 0);
818 					vpnes = nes;
819 				}
820 			} else
821 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
822 			break;
823 		case NFSV4OP_SAVEFH:
824 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
825 				nd->nd_repstat = 0;
826 				/* If vp == savevp, a no-op */
827 				if (vp != savevp) {
828 					if (savevp)
829 						vrele(savevp);
830 					VREF(vp);
831 					savevp = vp;
832 					savevpnes = vpnes;
833 					save_fsid = cur_fsid;
834 				}
835 			} else {
836 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
837 			}
838 			break;
839 		case NFSV4OP_RESTOREFH:
840 			if (savevp) {
841 				nd->nd_repstat = 0;
842 				/* If vp == savevp, a no-op */
843 				if (vp != savevp) {
844 					VREF(savevp);
845 					vrele(vp);
846 					vp = savevp;
847 					vpnes = savevpnes;
848 					cur_fsid = save_fsid;
849 				}
850 			} else {
851 				nd->nd_repstat = NFSERR_RESTOREFH;
852 			}
853 			break;
854 		default:
855 		    /*
856 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
857 		     * non-exported directory if
858 		     * nfs_rootfhset. Do I need to allow any other Ops?
859 		     * (You can only have a non-exported vpnes if
860 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
861 		     * Allow AUTH_SYS to be used for file systems
862 		     * exported GSS only for certain Ops, to allow
863 		     * clients to do mounts more easily.
864 		     */
865 		    if (nfsv4_opflag[op].needscfh && vp) {
866 			if (!NFSVNO_EXPORTED(&vpnes) &&
867 			    op != NFSV4OP_LOOKUP &&
868 			    op != NFSV4OP_GETATTR &&
869 			    op != NFSV4OP_GETFH &&
870 			    op != NFSV4OP_ACCESS &&
871 			    op != NFSV4OP_READLINK &&
872 			    op != NFSV4OP_SECINFO)
873 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
874 			else if (nfsvno_testexp(nd, &vpnes) &&
875 			    op != NFSV4OP_LOOKUP &&
876 			    op != NFSV4OP_GETFH &&
877 			    op != NFSV4OP_GETATTR &&
878 			    op != NFSV4OP_SECINFO)
879 				nd->nd_repstat = NFSERR_WRONGSEC;
880 			if (nd->nd_repstat) {
881 				if (op == NFSV4OP_SETATTR) {
882 				    /*
883 				     * Setattr reply requires a bitmap
884 				     * even for errors like these.
885 				     */
886 				    NFSM_BUILD(tl, u_int32_t *,
887 					NFSX_UNSIGNED);
888 				    *tl = 0;
889 				}
890 				break;
891 			}
892 		    }
893 		    if (nfsv4_opflag[op].retfh == 1) {
894 			if (!vp) {
895 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
896 				break;
897 			}
898 			VREF(vp);
899 			if (nfsv4_opflag[op].modifyfs)
900 				vn_start_write(vp, &temp_mp, V_WAIT);
901 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
902 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
903 			if (!error && !nd->nd_repstat) {
904 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
905 				new_mp = nvp->v_mount;
906 				if (cur_fsid.val[0] !=
907 				    new_mp->mnt_stat.f_fsid.val[0] ||
908 				    cur_fsid.val[1] !=
909 				    new_mp->mnt_stat.f_fsid.val[1]) {
910 				    /* crossed a server mount point */
911 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
912 					nd->nd_nam, &nes, &credanon);
913 				    if (!nd->nd_repstat)
914 					nd->nd_repstat = nfsd_excred(nd,
915 					    &nes, credanon);
916 				    if (credanon != NULL)
917 					crfree(credanon);
918 				    if (!nd->nd_repstat) {
919 					vpnes = nes;
920 					cur_fsid = new_mp->mnt_stat.f_fsid;
921 				    }
922 				}
923 				/* Lookup ops return a locked vnode */
924 				NFSVOPUNLOCK(nvp, 0);
925 			    }
926 			    if (!nd->nd_repstat) {
927 				    vrele(vp);
928 				    vp = nvp;
929 			    } else
930 				    vrele(nvp);
931 			}
932 			if (nfsv4_opflag[op].modifyfs)
933 				vn_finished_write(temp_mp);
934 		    } else if (nfsv4_opflag[op].retfh == 2) {
935 			if (vp == NULL || savevp == NULL) {
936 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
937 				break;
938 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
939 			    cur_fsid.val[1] != save_fsid.val[1]) {
940 				nd->nd_repstat = NFSERR_XDEV;
941 				break;
942 			}
943 			if (nfsv4_opflag[op].modifyfs)
944 				vn_start_write(savevp, &temp_mp, V_WAIT);
945 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
946 				VREF(vp);
947 				VREF(savevp);
948 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
949 				    savevp, vp, p, &savevpnes, &vpnes);
950 			} else
951 				nd->nd_repstat = NFSERR_PERM;
952 			if (nfsv4_opflag[op].modifyfs)
953 				vn_finished_write(temp_mp);
954 		    } else {
955 			if (nfsv4_opflag[op].retfh != 0)
956 				panic("nfsrvd_compound");
957 			if (nfsv4_opflag[op].needscfh) {
958 				if (vp != NULL) {
959 					lktype = nfsv4_opflag[op].lktype;
960 					if (nfsv4_opflag[op].modifyfs) {
961 						vn_start_write(vp, &temp_mp,
962 						    V_WAIT);
963 						if (op == NFSV4OP_WRITE &&
964 						    MNT_SHARED_WRITES(temp_mp))
965 							lktype = LK_SHARED;
966 					}
967 					if (NFSVOPLOCK(vp, lktype) == 0)
968 						VREF(vp);
969 					else
970 						nd->nd_repstat = NFSERR_PERM;
971 				} else {
972 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
973 					if (op == NFSV4OP_SETATTR) {
974 						/*
975 						 * Setattr reply requires a
976 						 * bitmap even for errors like
977 						 * these.
978 						 */
979 						NFSM_BUILD(tl, u_int32_t *,
980 						    NFSX_UNSIGNED);
981 						*tl = 0;
982 					}
983 					break;
984 				}
985 				if (nd->nd_repstat == 0)
986 					error = (*(nfsrv4_ops0[op]))(nd,
987 					    isdgram, vp, p, &vpnes);
988 				if (nfsv4_opflag[op].modifyfs)
989 					vn_finished_write(temp_mp);
990 			} else {
991 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
992 				    NULL, p, &vpnes);
993 			}
994 		    }
995 		};
996 		if (error) {
997 			if (error == EBADRPC || error == NFSERR_BADXDR) {
998 				nd->nd_repstat = NFSERR_BADXDR;
999 			} else {
1000 				nd->nd_repstat = error;
1001 				printf("nfsv4 comperr0=%d\n", error);
1002 			}
1003 			error = 0;
1004 		}
1005 		retops++;
1006 		if (nd->nd_repstat) {
1007 			*repp = nfsd_errmap(nd);
1008 			break;
1009 		} else {
1010 			*repp = 0;	/* NFS4_OK */
1011 		}
1012 	}
1013 nfsmout:
1014 	if (error) {
1015 		if (error == EBADRPC || error == NFSERR_BADXDR)
1016 			nd->nd_repstat = NFSERR_BADXDR;
1017 		else
1018 			printf("nfsv4 comperr1=%d\n", error);
1019 	}
1020 	if (taglen == -1) {
1021 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1022 		*tl++ = 0;
1023 		*tl = 0;
1024 	} else {
1025 		*retopsp = txdr_unsigned(retops);
1026 	}
1027 	if (vp)
1028 		vrele(vp);
1029 	if (savevp)
1030 		vrele(savevp);
1031 	NFSLOCKV4ROOTMUTEX();
1032 	nfsv4_relref(&nfsv4rootfs_lock);
1033 	NFSUNLOCKV4ROOTMUTEX();
1034 
1035 	NFSEXITCODE2(0, nd);
1036 }
1037