xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 907b59d76938e654f0d040a888e8dfca3de1e222)
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 		/*
775 		 * For now, newnfsstats.srvrpccnt[] doesn't have entries
776 		 * for the NFSv4.1 operations.
777 		 */
778 		if (nd->nd_procnum < NFSV4OP_NOPS)
779 			NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
780 		switch (op) {
781 		case NFSV4OP_PUTFH:
782 			error = nfsrv_mtofh(nd, &fh);
783 			if (error)
784 				goto nfsmout;
785 			if (!nd->nd_repstat)
786 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
787 				    NULL, 0, p);
788 			/* For now, allow this for non-export FHs */
789 			if (!nd->nd_repstat) {
790 				if (vp)
791 					vrele(vp);
792 				vp = nvp;
793 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
794 				NFSVOPUNLOCK(vp, 0);
795 				vpnes = nes;
796 			}
797 			break;
798 		case NFSV4OP_PUTPUBFH:
799 			if (nfs_pubfhset)
800 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
801 				&nes, NULL, 0, p);
802 			else
803 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
804 			if (!nd->nd_repstat) {
805 				if (vp)
806 					vrele(vp);
807 				vp = nvp;
808 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
809 				NFSVOPUNLOCK(vp, 0);
810 				vpnes = nes;
811 			}
812 			break;
813 		case NFSV4OP_PUTROOTFH:
814 			if (nfs_rootfhset) {
815 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
816 				    &nes, NULL, 0, p);
817 				if (!nd->nd_repstat) {
818 					if (vp)
819 						vrele(vp);
820 					vp = nvp;
821 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
822 					NFSVOPUNLOCK(vp, 0);
823 					vpnes = nes;
824 				}
825 			} else
826 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
827 			break;
828 		case NFSV4OP_SAVEFH:
829 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
830 				nd->nd_repstat = 0;
831 				/* If vp == savevp, a no-op */
832 				if (vp != savevp) {
833 					if (savevp)
834 						vrele(savevp);
835 					VREF(vp);
836 					savevp = vp;
837 					savevpnes = vpnes;
838 					save_fsid = cur_fsid;
839 				}
840 			} else {
841 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
842 			}
843 			break;
844 		case NFSV4OP_RESTOREFH:
845 			if (savevp) {
846 				nd->nd_repstat = 0;
847 				/* If vp == savevp, a no-op */
848 				if (vp != savevp) {
849 					VREF(savevp);
850 					vrele(vp);
851 					vp = savevp;
852 					vpnes = savevpnes;
853 					cur_fsid = save_fsid;
854 				}
855 			} else {
856 				nd->nd_repstat = NFSERR_RESTOREFH;
857 			}
858 			break;
859 		default:
860 		    /*
861 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
862 		     * non-exported directory if
863 		     * nfs_rootfhset. Do I need to allow any other Ops?
864 		     * (You can only have a non-exported vpnes if
865 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
866 		     * Allow AUTH_SYS to be used for file systems
867 		     * exported GSS only for certain Ops, to allow
868 		     * clients to do mounts more easily.
869 		     */
870 		    if (nfsv4_opflag[op].needscfh && vp) {
871 			if (!NFSVNO_EXPORTED(&vpnes) &&
872 			    op != NFSV4OP_LOOKUP &&
873 			    op != NFSV4OP_GETATTR &&
874 			    op != NFSV4OP_GETFH &&
875 			    op != NFSV4OP_ACCESS &&
876 			    op != NFSV4OP_READLINK &&
877 			    op != NFSV4OP_SECINFO)
878 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
879 			else if (nfsvno_testexp(nd, &vpnes) &&
880 			    op != NFSV4OP_LOOKUP &&
881 			    op != NFSV4OP_GETFH &&
882 			    op != NFSV4OP_GETATTR &&
883 			    op != NFSV4OP_SECINFO)
884 				nd->nd_repstat = NFSERR_WRONGSEC;
885 			if (nd->nd_repstat) {
886 				if (op == NFSV4OP_SETATTR) {
887 				    /*
888 				     * Setattr reply requires a bitmap
889 				     * even for errors like these.
890 				     */
891 				    NFSM_BUILD(tl, u_int32_t *,
892 					NFSX_UNSIGNED);
893 				    *tl = 0;
894 				}
895 				break;
896 			}
897 		    }
898 		    if (nfsv4_opflag[op].retfh == 1) {
899 			if (!vp) {
900 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
901 				break;
902 			}
903 			VREF(vp);
904 			if (nfsv4_opflag[op].modifyfs)
905 				vn_start_write(vp, &temp_mp, V_WAIT);
906 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
907 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
908 			if (!error && !nd->nd_repstat) {
909 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
910 				new_mp = nvp->v_mount;
911 				if (cur_fsid.val[0] !=
912 				    new_mp->mnt_stat.f_fsid.val[0] ||
913 				    cur_fsid.val[1] !=
914 				    new_mp->mnt_stat.f_fsid.val[1]) {
915 				    /* crossed a server mount point */
916 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
917 					nd->nd_nam, &nes, &credanon);
918 				    if (!nd->nd_repstat)
919 					nd->nd_repstat = nfsd_excred(nd,
920 					    &nes, credanon);
921 				    if (credanon != NULL)
922 					crfree(credanon);
923 				    if (!nd->nd_repstat) {
924 					vpnes = nes;
925 					cur_fsid = new_mp->mnt_stat.f_fsid;
926 				    }
927 				}
928 				/* Lookup ops return a locked vnode */
929 				NFSVOPUNLOCK(nvp, 0);
930 			    }
931 			    if (!nd->nd_repstat) {
932 				    vrele(vp);
933 				    vp = nvp;
934 			    } else
935 				    vrele(nvp);
936 			}
937 			if (nfsv4_opflag[op].modifyfs)
938 				vn_finished_write(temp_mp);
939 		    } else if (nfsv4_opflag[op].retfh == 2) {
940 			if (vp == NULL || savevp == NULL) {
941 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
942 				break;
943 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
944 			    cur_fsid.val[1] != save_fsid.val[1]) {
945 				nd->nd_repstat = NFSERR_XDEV;
946 				break;
947 			}
948 			if (nfsv4_opflag[op].modifyfs)
949 				vn_start_write(savevp, &temp_mp, V_WAIT);
950 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
951 				VREF(vp);
952 				VREF(savevp);
953 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
954 				    savevp, vp, p, &savevpnes, &vpnes);
955 			} else
956 				nd->nd_repstat = NFSERR_PERM;
957 			if (nfsv4_opflag[op].modifyfs)
958 				vn_finished_write(temp_mp);
959 		    } else {
960 			if (nfsv4_opflag[op].retfh != 0)
961 				panic("nfsrvd_compound");
962 			if (nfsv4_opflag[op].needscfh) {
963 				if (vp != NULL) {
964 					lktype = nfsv4_opflag[op].lktype;
965 					if (nfsv4_opflag[op].modifyfs) {
966 						vn_start_write(vp, &temp_mp,
967 						    V_WAIT);
968 						if (op == NFSV4OP_WRITE &&
969 						    MNT_SHARED_WRITES(temp_mp))
970 							lktype = LK_SHARED;
971 					}
972 					if (NFSVOPLOCK(vp, lktype) == 0)
973 						VREF(vp);
974 					else
975 						nd->nd_repstat = NFSERR_PERM;
976 				} else {
977 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
978 					if (op == NFSV4OP_SETATTR) {
979 						/*
980 						 * Setattr reply requires a
981 						 * bitmap even for errors like
982 						 * these.
983 						 */
984 						NFSM_BUILD(tl, u_int32_t *,
985 						    NFSX_UNSIGNED);
986 						*tl = 0;
987 					}
988 					break;
989 				}
990 				if (nd->nd_repstat == 0)
991 					error = (*(nfsrv4_ops0[op]))(nd,
992 					    isdgram, vp, p, &vpnes);
993 				if (nfsv4_opflag[op].modifyfs)
994 					vn_finished_write(temp_mp);
995 			} else {
996 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
997 				    NULL, p, &vpnes);
998 			}
999 		    }
1000 		}
1001 		if (error) {
1002 			if (error == EBADRPC || error == NFSERR_BADXDR) {
1003 				nd->nd_repstat = NFSERR_BADXDR;
1004 			} else {
1005 				nd->nd_repstat = error;
1006 				printf("nfsv4 comperr0=%d\n", error);
1007 			}
1008 			error = 0;
1009 		}
1010 		retops++;
1011 		if (nd->nd_repstat) {
1012 			*repp = nfsd_errmap(nd);
1013 			break;
1014 		} else {
1015 			*repp = 0;	/* NFS4_OK */
1016 		}
1017 	}
1018 nfsmout:
1019 	if (error) {
1020 		if (error == EBADRPC || error == NFSERR_BADXDR)
1021 			nd->nd_repstat = NFSERR_BADXDR;
1022 		else
1023 			printf("nfsv4 comperr1=%d\n", error);
1024 	}
1025 	if (taglen == -1) {
1026 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1027 		*tl++ = 0;
1028 		*tl = 0;
1029 	} else {
1030 		*retopsp = txdr_unsigned(retops);
1031 	}
1032 	if (vp)
1033 		vrele(vp);
1034 	if (savevp)
1035 		vrele(savevp);
1036 	NFSLOCKV4ROOTMUTEX();
1037 	nfsv4_relref(&nfsv4rootfs_lock);
1038 	NFSUNLOCKV4ROOTMUTEX();
1039 
1040 	NFSEXITCODE2(0, nd);
1041 }
1042