xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 8be96e101f2691b80ff9562b72f874da82e735aa)
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 vnode_t nfsv4root_vp = NULL;
54 int nfsv4root_set = 0;
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[NFSV4OP_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 };
179 
180 int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
181     int, vnode_t , vnode_t *, fhandle_t *,
182     NFSPROC_T *, struct nfsexstuff *) = {
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
188 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
189 	nfsrvd_mknod,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
197 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
198 	nfsrvd_lookup,
199 	nfsrvd_lookup,
200 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
201 	nfsrvd_open,
202 	nfsrvd_openattr,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
222 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
223 };
224 
225 int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
226     int, vnode_t , vnode_t , NFSPROC_T *,
227     struct nfsexstuff *, struct nfsexstuff *) = {
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
238 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
239 	nfsrvd_link,
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 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
256 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
257 	nfsrvd_rename,
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 	(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 };
269 #endif	/* !APPLEKEXT */
270 
271 /*
272  * Static array that defines which nfs rpc's are nonidempotent
273  */
274 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
275 	FALSE,
276 	FALSE,
277 	TRUE,
278 	FALSE,
279 	FALSE,
280 	FALSE,
281 	FALSE,
282 	TRUE,
283 	TRUE,
284 	TRUE,
285 	TRUE,
286 	TRUE,
287 	TRUE,
288 	TRUE,
289 	TRUE,
290 	TRUE,
291 	FALSE,
292 	FALSE,
293 	FALSE,
294 	FALSE,
295 	FALSE,
296 	FALSE,
297 };
298 
299 /*
300  * This static array indicates whether or not the RPC modifies the
301  * file system.
302  */
303 static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
304     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
305     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
306 
307 /* local functions */
308 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
309     NFSPROC_T *p);
310 
311 
312 /*
313  * This static array indicates which server procedures require the extra
314  * arguments to return the current file handle for V2, 3.
315  */
316 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
317 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
318 
319 extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
320 
321 static int nfsv3to4op[NFS_V3NPROCS] = {
322 	NFSPROC_NULL,
323 	NFSV4OP_GETATTR,
324 	NFSV4OP_SETATTR,
325 	NFSV4OP_LOOKUP,
326 	NFSV4OP_ACCESS,
327 	NFSV4OP_READLINK,
328 	NFSV4OP_READ,
329 	NFSV4OP_WRITE,
330 	NFSV4OP_V3CREATE,
331 	NFSV4OP_MKDIR,
332 	NFSV4OP_SYMLINK,
333 	NFSV4OP_MKNOD,
334 	NFSV4OP_REMOVE,
335 	NFSV4OP_RMDIR,
336 	NFSV4OP_RENAME,
337 	NFSV4OP_LINK,
338 	NFSV4OP_READDIR,
339 	NFSV4OP_READDIRPLUS,
340 	NFSV4OP_FSSTAT,
341 	NFSV4OP_FSINFO,
342 	NFSV4OP_PATHCONF,
343 	NFSV4OP_COMMIT,
344 };
345 
346 /*
347  * Do an RPC. Basically, get the file handles translated to vnode pointers
348  * and then call the appropriate server routine. The server routines are
349  * split into groups, based on whether they use a file handle or file
350  * handle plus name or ...
351  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
352  */
353 APPLESTATIC void
354 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
355     NFSPROC_T *p)
356 {
357 	int error = 0;
358 	vnode_t vp;
359 	mount_t mp = NULL;
360 	struct nfsrvfh fh;
361 	struct nfsexstuff nes;
362 
363 	/*
364 	 * Get a locked vnode for the first file handle
365 	 */
366 	if (!(nd->nd_flag & ND_NFSV4)) {
367 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
368 		/*
369 		 * For NFSv3, if the malloc/mget allocation is near limits,
370 		 * return NFSERR_DELAY.
371 		 */
372 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
373 			nd->nd_repstat = NFSERR_DELAY;
374 			vp = NULL;
375 		} else {
376 			error = nfsrv_mtofh(nd, &fh);
377 			if (error) {
378 				if (error != EBADRPC)
379 					printf("nfs dorpc err1=%d\n", error);
380 				nd->nd_repstat = NFSERR_GARBAGE;
381 				return;
382 			}
383 			nes.nes_vfslocked = 0;
384 			if (nd->nd_flag & ND_PUBLOOKUP)
385 				nfsd_fhtovp(nd, &nfs_pubfh, &vp, &nes,
386 				    &mp, nfs_writerpc[nd->nd_procnum], p);
387 			else
388 				nfsd_fhtovp(nd, &fh, &vp, &nes,
389 				    &mp, nfs_writerpc[nd->nd_procnum], p);
390 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
391 				return;
392 		}
393 	}
394 
395 	/*
396 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
397 	 * cache, as required.
398 	 * For V4, nfsrvd_compound() does this.
399 	 */
400 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
401 		nd->nd_flag |= ND_SAVEREPLY;
402 
403 	nfsrvd_rephead(nd);
404 	/*
405 	 * If nd_repstat is non-zero, just fill in the reply status
406 	 * to complete the RPC reply for V2. Otherwise, you must do
407 	 * the RPC.
408 	 */
409 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
410 		*nd->nd_errp = nfsd_errmap(nd);
411 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
412 		if (mp != NULL) {
413 			if (nfs_writerpc[nd->nd_procnum])
414 				NFS_ENDWRITE(mp);
415 			if (nes.nes_vfslocked)
416 				nfsvno_unlockvfs(mp);
417 		}
418 		return;
419 	}
420 
421 	/*
422 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
423 	 * works through the sub-rpcs, otherwise just call the procedure.
424 	 * The procedures are in three groups with different arguments.
425 	 * The group is indicated by the value in nfs_retfh[].
426 	 */
427 	if (nd->nd_flag & ND_NFSV4) {
428 		nfsrvd_compound(nd, isdgram, p);
429 	} else {
430 		if (nfs_retfh[nd->nd_procnum] == 1) {
431 			if (vp)
432 				NFSVOPUNLOCK(vp, 0, p);
433 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
434 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
435 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
436 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
437 			    vp, NULL, p, &nes, NULL);
438 		} else {
439 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
440 			    vp, p, &nes);
441 		}
442 		if (mp) {
443 			if (nfs_writerpc[nd->nd_procnum])
444 				NFS_ENDWRITE(mp);
445 			if (nes.nes_vfslocked)
446 				nfsvno_unlockvfs(mp);
447 		}
448 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
449 	}
450 	if (error) {
451 		if (error != EBADRPC)
452 			printf("nfs dorpc err2=%d\n", error);
453 		nd->nd_repstat = NFSERR_GARBAGE;
454 	}
455 	*nd->nd_errp = nfsd_errmap(nd);
456 
457 	/*
458 	 * Don't cache certain reply status values.
459 	 */
460 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
461 	    (nd->nd_repstat == NFSERR_GARBAGE ||
462 	     nd->nd_repstat == NFSERR_BADXDR ||
463 	     nd->nd_repstat == NFSERR_MOVED ||
464 	     nd->nd_repstat == NFSERR_DELAY ||
465 	     nd->nd_repstat == NFSERR_BADSEQID ||
466 	     nd->nd_repstat == NFSERR_RESOURCE ||
467 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
468 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
469 	     nd->nd_repstat == NFSERR_STALESTATEID ||
470 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
471 	     nd->nd_repstat == NFSERR_BADSTATEID ||
472 	     nd->nd_repstat == NFSERR_GRACE ||
473 	     nd->nd_repstat == NFSERR_NOGRACE))
474 		nd->nd_flag &= ~ND_SAVEREPLY;
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 mp, savemp;
496 	struct ucred *credanon;
497 	struct nfsexstuff nes, vpnes, savevpnes;
498 	static u_int64_t compref = 0;
499 
500 	NFSVNO_EXINIT(&vpnes);
501 	NFSVNO_EXINIT(&savevpnes);
502 	/*
503 	 * Put the seq# of the current compound RPC in nfsrv_descript.
504 	 * (This is used by nfsrv_checkgetattr(), to see if the write
505 	 *  delegation was created by the same compound RPC as the one
506 	 *  with that Getattr in it.)
507 	 * Don't worry about the 64bit number wrapping around. It ain't
508 	 * gonna happen before this server gets shut down/rebooted.
509 	 */
510 	nd->nd_compref = compref++;
511 
512 	/*
513 	 * Check for and optionally get a lock on the root. This lock means that
514 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
515 	 * is required when the V4 root is being changed, the stable storage
516 	 * restart file is being updated, or callbacks are being done.
517 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
518 	 * either hold a reference count (nfs_usecnt) or the lock. When
519 	 * nfsrv_unlock() is called to release the lock, it can optionally
520 	 * also get a reference count, which saves the need for a call to
521 	 * nfsrv_getref() after nfsrv_unlock().
522 	 */
523 	/*
524 	 * First, check to see if we need to wait for an update lock.
525 	 */
526 	igotlock = 0;
527 	NFSLOCKV4ROOTMUTEX();
528 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
529 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
530 		    NFSV4ROOTLOCKMUTEXPTR);
531 	else
532 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
533 		    NFSV4ROOTLOCKMUTEXPTR);
534 	NFSUNLOCKV4ROOTMUTEX();
535 	if (igotlock) {
536 		NFSLOCKSTATE();	/* to avoid a race with */
537 		NFSUNLOCKSTATE();	/* nfsrv_servertimer() */
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);
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 	savevpnes.nes_vfslocked = vpnes.nes_vfslocked = 0;
597 	savemp = mp = NULL;
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 				nes.nes_vfslocked = vpnes.nes_vfslocked;
705 				nfsd_fhtovp(nd, &fh, &nvp, &nes, &mp,
706 				    0, p);
707 			}
708 			/* For now, allow this for non-export FHs */
709 			if (!nd->nd_repstat) {
710 				if (vp)
711 					vrele(vp);
712 				vp = nvp;
713 				NFSVOPUNLOCK(vp, 0, p);
714 				vpnes = nes;
715 			}
716 			break;
717 		case NFSV4OP_PUTPUBFH:
718 			if (nfs_pubfhset) {
719 			    nes.nes_vfslocked = vpnes.nes_vfslocked;
720 			    nfsd_fhtovp(nd, &nfs_pubfh, &nvp,
721 				&nes, &mp, 0, p);
722 			} else {
723 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
724 			}
725 			if (!nd->nd_repstat) {
726 				if (vp)
727 					vrele(vp);
728 				vp = nvp;
729 				NFSVOPUNLOCK(vp, 0, p);
730 				vpnes = nes;
731 			}
732 			break;
733 		case NFSV4OP_PUTROOTFH:
734 			if (nfs_rootfhset) {
735 				nes.nes_vfslocked = vpnes.nes_vfslocked;
736 				nfsd_fhtovp(nd, &nfs_rootfh, &nvp,
737 				    &nes, &mp, 0, p);
738 				if (!nd->nd_repstat) {
739 					if (vp)
740 						vrele(vp);
741 					vp = nvp;
742 					NFSVOPUNLOCK(vp, 0, p);
743 					vpnes = nes;
744 				}
745 			} else if (nfsv4root_vp && nfsv4root_set) {
746 				if (vp) {
747 					if (vpnes.nes_vfslocked)
748 						nfsvno_unlockvfs(mp);
749 					vrele(vp);
750 				}
751 				vp = nfsv4root_vp;
752 				VREF(vp);
753 				NFSVNO_SETEXRDONLY(&vpnes);
754 				vpnes.nes_vfslocked = 0;
755 				mp = vnode_mount(vp);
756 			} else {
757 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
758 			}
759 			break;
760 		case NFSV4OP_SAVEFH:
761 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
762 				nd->nd_repstat = 0;
763 				/* If vp == savevp, a no-op */
764 				if (vp != savevp) {
765 					if (savevp)
766 						vrele(savevp);
767 					VREF(vp);
768 					savevp = vp;
769 					savevpnes = vpnes;
770 					savemp = mp;
771 				}
772 			} else {
773 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
774 			}
775 			break;
776 		case NFSV4OP_RESTOREFH:
777 			if (savevp) {
778 				nd->nd_repstat = 0;
779 				/* If vp == savevp, a no-op */
780 				if (vp != savevp) {
781 					VREF(savevp);
782 					if (mp == NULL || savemp == NULL)
783 						panic("nfscmpmp");
784 					if (!savevpnes.nes_vfslocked &&
785 					    vpnes.nes_vfslocked) {
786 						if (mp == savemp)
787 							panic("nfscmp2");
788 						nfsvno_unlockvfs(mp);
789 					} else if (savevpnes.nes_vfslocked &&
790 					    !vpnes.nes_vfslocked) {
791 						if (mp == savemp)
792 							panic("nfscmp3");
793 						savevpnes.nes_vfslocked = nfsvno_lockvfs(savemp);
794 					}
795 					vrele(vp);
796 					vp = savevp;
797 					vpnes = savevpnes;
798 					mp = savemp;
799 				}
800 			} else {
801 				nd->nd_repstat = NFSERR_RESTOREFH;
802 			}
803 			break;
804 		default:
805 		    /*
806 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
807 		     * non-exported directory if
808 		     * nfs_rootfhset. Do I need to allow any other Ops?
809 		     * (You can only have a non-exported vpnes if
810 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
811 		     * Allow AUTH_SYS to be used for file systems
812 		     * exported GSS only for certain Ops, to allow
813 		     * clients to do mounts more easily.
814 		     */
815 		    if (nfsv4_opflag[op].needscfh && vp) {
816 			if (!NFSVNO_EXPORTED(&vpnes) &&
817 			    op != NFSV4OP_LOOKUP &&
818 			    op != NFSV4OP_GETATTR &&
819 			    op != NFSV4OP_GETFH &&
820 			    op != NFSV4OP_SECINFO)
821 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
822 			else if (nfsvno_testexp(nd, &vpnes) &&
823 			    op != NFSV4OP_LOOKUP &&
824 			    op != NFSV4OP_GETFH &&
825 			    op != NFSV4OP_GETATTR &&
826 			    op != NFSV4OP_SECINFO)
827 				nd->nd_repstat = NFSERR_WRONGSEC;
828 			if (nd->nd_repstat) {
829 				if (op == NFSV4OP_SETATTR) {
830 				    /*
831 				     * Setattr reply requires a bitmap
832 				     * even for errors like these.
833 				     */
834 				    NFSM_BUILD(tl, u_int32_t *,
835 					NFSX_UNSIGNED);
836 				    *tl = 0;
837 				}
838 				break;
839 			}
840 		    }
841 		    if (nfsv4_opflag[op].retfh == 1) {
842 			if (!vp) {
843 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
844 				break;
845 			}
846 			VREF(vp);
847 			if (nfsv4_opflag[op].modifyfs)
848 				NFS_STARTWRITE(NULL, &mp);
849 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
850 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
851 			if (!error && !nd->nd_repstat) {
852 			    if (vfs_statfs(mp)->f_fsid.val[0] !=
853 				vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ||
854 				vfs_statfs(mp)->f_fsid.val[1] !=
855 				vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) {
856 				if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ==
857 				    NFSV4ROOT_FSID0 &&
858 				    vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] ==
859 				    NFSV4ROOT_FSID1) {
860 				    if (vpnes.nes_vfslocked) {
861 					nfsvno_unlockvfs(mp);
862 					vpnes.nes_vfslocked = 0;
863 				    }
864 				    NFSVNO_SETEXRDONLY(&vpnes);
865 				    mp = vnode_mount(nvp);
866 				} else {
867 				    nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp),
868 					nd->nd_nam, &nes, &credanon);
869 				    if (!nd->nd_repstat)
870 					nd->nd_repstat = nfsd_excred(nd,
871 					    &nes, credanon);
872 				    if (credanon != NULL)
873 					crfree(credanon);
874 				    if (!nd->nd_repstat) {
875 					if (vpnes.nes_vfslocked)
876 					    nfsvno_unlockvfs(mp);
877 					mp = vnode_mount(nvp);
878 					vpnes = nes;
879 					vpnes.nes_vfslocked =
880 					    nfsvno_lockvfs(mp);
881 				    }
882 				}
883 			    }
884 			    if (!nd->nd_repstat) {
885 				    vrele(vp);
886 				    vp = nvp;
887 			    }
888 			}
889 			if (nfsv4_opflag[op].modifyfs)
890 				NFS_ENDWRITE(mp);
891 		    } else if (nfsv4_opflag[op].retfh == 2) {
892 			if (vp == NULL || savevp == NULL) {
893 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
894 				break;
895 			} else if (mp != savemp) {
896 				nd->nd_repstat = NFSERR_XDEV;
897 				break;
898 			}
899 			VREF(vp);
900 			VREF(savevp);
901 			if (nfsv4_opflag[op].modifyfs)
902 				NFS_STARTWRITE(NULL, &mp);
903 			NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
904 			error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
905 			    vp, p, &savevpnes, &vpnes);
906 			if (nfsv4_opflag[op].modifyfs)
907 				NFS_ENDWRITE(mp);
908 		    } else {
909 			if (nfsv4_opflag[op].retfh != 0)
910 				panic("nfsrvd_compound");
911 			if (nfsv4_opflag[op].needscfh) {
912 				if (vp) {
913 					VREF(vp);
914 					if (nfsv4_opflag[op].modifyfs)
915 						NFS_STARTWRITE(NULL, &mp);
916 					NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
917 				} else {
918 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
919 					if (op == NFSV4OP_SETATTR) {
920 					    /*
921 					     * Setattr reply requires a bitmap
922 					     * even for errors like these.
923 					     */
924 					    NFSM_BUILD(tl, u_int32_t *,
925 						NFSX_UNSIGNED);
926 					    *tl = 0;
927 					}
928 					break;
929 				}
930 				error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
931 				    p, &vpnes);
932 				if (nfsv4_opflag[op].modifyfs)
933 					NFS_ENDWRITE(mp);
934 			} else {
935 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
936 				    NULL, p, &vpnes);
937 			}
938 		    }
939 		};
940 		if (error) {
941 			if (error == EBADRPC || error == NFSERR_BADXDR) {
942 				nd->nd_repstat = NFSERR_BADXDR;
943 			} else {
944 				nd->nd_repstat = error;
945 				printf("nfsv4 comperr0=%d\n", error);
946 			}
947 			error = 0;
948 		}
949 		retops++;
950 		if (nd->nd_repstat) {
951 			*repp = nfsd_errmap(nd);
952 			break;
953 		} else {
954 			*repp = 0;	/* NFS4_OK */
955 		}
956 	}
957 nfsmout:
958 	if (error) {
959 		if (error == EBADRPC || error == NFSERR_BADXDR)
960 			nd->nd_repstat = NFSERR_BADXDR;
961 		else
962 			printf("nfsv4 comperr1=%d\n", error);
963 	}
964 	if (taglen == -1) {
965 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
966 		*tl++ = 0;
967 		*tl = 0;
968 	} else {
969 		*retopsp = txdr_unsigned(retops);
970 	}
971 	if (mp && vpnes.nes_vfslocked)
972 		nfsvno_unlockvfs(mp);
973 	if (vp)
974 		vrele(vp);
975 	if (savevp)
976 		vrele(savevp);
977 	NFSLOCKV4ROOTMUTEX();
978 	nfsv4_relref(&nfsv4rootfs_lock);
979 	NFSUNLOCKV4ROOTMUTEX();
980 }
981