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