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