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