xref: /netbsd-src/sys/fs/nfs/server/nfs_nfsdsocket.c (revision 6cf6fe02a981b55727c49c3d37b0d8191a98c0ee)
1 /*	$NetBSD: nfs_nfsdsocket.c,v 1.1.1.1 2013/09/30 07:19:47 dholland Exp $	*/
2 /*-
3  * Copyright (c) 1989, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Rick Macklem at The University of Guelph.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  */
34 
35 #include <sys/cdefs.h>
36 /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdsocket.c 249592 2013-04-17 21:00:22Z ken "); */
37 __RCSID("$NetBSD: nfs_nfsdsocket.c,v 1.1.1.1 2013/09/30 07:19:47 dholland Exp $");
38 
39 /*
40  * Socket operations for use by the nfs server.
41  */
42 
43 #ifndef APPLEKEXT
44 #include <fs/nfs/nfsport.h>
45 
46 extern struct nfsstats newnfsstats;
47 extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
48 extern int nfs_pubfhset, nfs_rootfhset;
49 extern struct nfsv4lock nfsv4rootfs_lock;
50 extern struct nfsrv_stablefirst nfsrv_stablefirst;
51 extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
52 extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
53 NFSV4ROOTLOCKMUTEX;
54 NFSSTATESPINLOCK;
55 
56 int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
57     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
58 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
59 	nfsrvd_getattr,
60 	nfsrvd_setattr,
61 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
62 	nfsrvd_access,
63 	nfsrvd_readlink,
64 	nfsrvd_read,
65 	nfsrvd_write,
66 	nfsrvd_create,
67 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
68 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
69 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
70 	nfsrvd_remove,
71 	nfsrvd_remove,
72 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
73 	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
74 	nfsrvd_readdir,
75 	nfsrvd_readdirplus,
76 	nfsrvd_statfs,
77 	nfsrvd_fsinfo,
78 	nfsrvd_pathconf,
79 	nfsrvd_commit,
80 };
81 
82 int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
83     int, vnode_t , vnode_t *, fhandle_t *,
84     NFSPROC_T *, struct nfsexstuff *) = {
85 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
86 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
87 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
88 	nfsrvd_lookup,
89 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
90 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
91 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
92 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
93 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
94 	nfsrvd_mkdir,
95 	nfsrvd_symlink,
96 	nfsrvd_mknod,
97 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
98 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
99 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
100 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
101 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
102 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
103 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
104 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
105 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
106 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
107 };
108 
109 int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
110     int, vnode_t , vnode_t , NFSPROC_T *,
111     struct nfsexstuff *, struct nfsexstuff *) = {
112 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
113 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
114 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
115 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
116 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
117 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
118 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
119 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
120 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
121 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
122 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
123 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
124 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
125 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
126 	nfsrvd_rename,
127 	nfsrvd_link,
128 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
129 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
130 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
131 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
132 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
133 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
134 };
135 
136 int (*nfsrv4_ops0[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, lktype;
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 				goto out;
382 			}
383 			if (nd->nd_procnum == NFSPROC_READ ||
384 			    nd->nd_procnum == NFSPROC_WRITE ||
385 			    nd->nd_procnum == NFSPROC_READDIR ||
386 			    nd->nd_procnum == NFSPROC_READLINK ||
387 			    nd->nd_procnum == NFSPROC_GETATTR ||
388 			    nd->nd_procnum == NFSPROC_ACCESS)
389 				lktype = LK_SHARED;
390 			else
391 				lktype = LK_EXCLUSIVE;
392 			if (nd->nd_flag & ND_PUBLOOKUP)
393 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
394 				    &mp, nfs_writerpc[nd->nd_procnum], p);
395 			else
396 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
397 				    &mp, nfs_writerpc[nd->nd_procnum], p);
398 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
399 				goto out;
400 		}
401 	}
402 
403 	/*
404 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
405 	 * cache, as required.
406 	 * For V4, nfsrvd_compound() does this.
407 	 */
408 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
409 		nd->nd_flag |= ND_SAVEREPLY;
410 
411 	nfsrvd_rephead(nd);
412 	/*
413 	 * If nd_repstat is non-zero, just fill in the reply status
414 	 * to complete the RPC reply for V2. Otherwise, you must do
415 	 * the RPC.
416 	 */
417 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
418 		*nd->nd_errp = nfsd_errmap(nd);
419 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
420 		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
421 			vn_finished_write(mp);
422 		goto out;
423 	}
424 
425 	/*
426 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
427 	 * works through the sub-rpcs, otherwise just call the procedure.
428 	 * The procedures are in three groups with different arguments.
429 	 * The group is indicated by the value in nfs_retfh[].
430 	 */
431 	if (nd->nd_flag & ND_NFSV4) {
432 		nfsrvd_compound(nd, isdgram, p);
433 	} else {
434 		if (nfs_retfh[nd->nd_procnum] == 1) {
435 			if (vp)
436 				NFSVOPUNLOCK(vp, 0);
437 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
438 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
439 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
440 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
441 			    vp, NULL, p, &nes, NULL);
442 		} else {
443 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
444 			    vp, p, &nes);
445 		}
446 		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
447 			vn_finished_write(mp);
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 out:
477 	NFSEXITCODE2(0, nd);
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 new_mp, temp_mp = NULL;
499 	struct ucred *credanon;
500 	struct nfsexstuff nes, vpnes, savevpnes;
501 	fsid_t cur_fsid, save_fsid;
502 	static u_int64_t compref = 0;
503 
504 	NFSVNO_EXINIT(&vpnes);
505 	NFSVNO_EXINIT(&savevpnes);
506 	/*
507 	 * Put the seq# of the current compound RPC in nfsrv_descript.
508 	 * (This is used by nfsrv_checkgetattr(), to see if the write
509 	 *  delegation was created by the same compound RPC as the one
510 	 *  with that Getattr in it.)
511 	 * Don't worry about the 64bit number wrapping around. It ain't
512 	 * gonna happen before this server gets shut down/rebooted.
513 	 */
514 	nd->nd_compref = compref++;
515 
516 	/*
517 	 * Check for and optionally get a lock on the root. This lock means that
518 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
519 	 * is required when the V4 root is being changed, the stable storage
520 	 * restart file is being updated, or callbacks are being done.
521 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
522 	 * either hold a reference count (nfs_usecnt) or the lock. When
523 	 * nfsrv_unlock() is called to release the lock, it can optionally
524 	 * also get a reference count, which saves the need for a call to
525 	 * nfsrv_getref() after nfsrv_unlock().
526 	 */
527 	/*
528 	 * First, check to see if we need to wait for an update lock.
529 	 */
530 	igotlock = 0;
531 	NFSLOCKV4ROOTMUTEX();
532 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
533 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
534 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
535 	else
536 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
537 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
538 	NFSUNLOCKV4ROOTMUTEX();
539 	if (igotlock) {
540 		/*
541 		 * If I got the lock, I can update the stable storage file.
542 		 * Done when the grace period is over or a client has long
543 		 * since expired.
544 		 */
545 		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
546 		if ((nfsrv_stablefirst.nsf_flags &
547 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
548 			nfsrv_updatestable(p);
549 
550 		/*
551 		 * If at least one client has long since expired, search
552 		 * the client list for them, write a REVOKE record on the
553 		 * stable storage file and then remove them from the client
554 		 * list.
555 		 */
556 		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
557 			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
558 			for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
559 			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
560 				nclp) {
561 				if (clp->lc_flags & LCL_EXPIREIT) {
562 				    if (!LIST_EMPTY(&clp->lc_open) ||
563 					!LIST_EMPTY(&clp->lc_deleg))
564 					nfsrv_writestable(clp->lc_id,
565 					    clp->lc_idlen, NFSNST_REVOKE, p);
566 				    nfsrv_cleanclient(clp, p);
567 				    nfsrv_freedeleglist(&clp->lc_deleg);
568 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
569 				    LIST_REMOVE(clp, lc_hash);
570 				    nfsrv_zapclient(clp, p);
571 				}
572 			    }
573 			}
574 		}
575 		NFSLOCKV4ROOTMUTEX();
576 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
577 		NFSUNLOCKV4ROOTMUTEX();
578 	} else {
579 		/*
580 		 * If we didn't get the lock, we need to get a refcnt,
581 		 * which also checks for and waits for the lock.
582 		 */
583 		NFSLOCKV4ROOTMUTEX();
584 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
585 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
586 		NFSUNLOCKV4ROOTMUTEX();
587 	}
588 
589 	/*
590 	 * If flagged, search for open owners that haven't had any opens
591 	 * for a long time.
592 	 */
593 	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
594 		nfsrv_throwawayopens(p);
595 	}
596 
597 	savevp = vp = NULL;
598 	save_fsid.val[0] = save_fsid.val[1] = 0;
599 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
600 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
601 	taglen = fxdr_unsigned(int, *tl);
602 	if (taglen < 0) {
603 		error = EBADRPC;
604 		goto nfsmout;
605 	}
606 	if (taglen <= NFSV4_SMALLSTR)
607 		tagstr = tag;
608 	else
609 		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
610 	error = nfsrv_mtostr(nd, tagstr, taglen);
611 	if (error) {
612 		if (taglen > NFSV4_SMALLSTR)
613 			free(tagstr, M_TEMP);
614 		taglen = -1;
615 		goto nfsmout;
616 	}
617 	(void) nfsm_strtom(nd, tag, taglen);
618 	if (taglen > NFSV4_SMALLSTR) {
619 		free(tagstr, M_TEMP);
620 	}
621 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
622 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
623 	minorvers = fxdr_unsigned(u_int32_t, *tl++);
624 	if (minorvers != NFSV4_MINORVERSION)
625 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
626 	if (nd->nd_repstat)
627 		numops = 0;
628 	else
629 		numops = fxdr_unsigned(int, *tl);
630 	/*
631 	 * Loop around doing the sub ops.
632 	 * vp - is an unlocked vnode pointer for the CFH
633 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
634 	 * (at some future date, it might turn out to be more appropriate
635 	 *  to keep the file handles instead of vnode pointers?)
636 	 * savevpnes and vpnes - are the export flags for the above.
637 	 */
638 	for (i = 0; i < numops; i++) {
639 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
640 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
641 		*repp = *tl;
642 		op = fxdr_unsigned(int, *tl);
643 		if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
644 			nd->nd_repstat = NFSERR_OPILLEGAL;
645 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
646 			*repp = nfsd_errmap(nd);
647 			retops++;
648 			break;
649 		} else {
650 			repp++;
651 		}
652 
653 		/*
654 		 * Check for a referral on the current FH and, if so, return
655 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
656 		 */
657 		if (vp != NULL && op != NFSV4OP_GETATTR &&
658 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
659 		    nfsrv_errmoved(op)) {
660 			nd->nd_repstat = NFSERR_MOVED;
661 			*repp = nfsd_errmap(nd);
662 			retops++;
663 			break;
664 		}
665 
666 		nd->nd_procnum = op;
667 		/*
668 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
669 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
670 		 * really nasty for certain Op sequences, I'll play it safe
671 		 * and only return the error at the beginning.) The cache
672 		 * will still function over flood level, but uses lots of
673 		 * mbufs.)
674 		 * If nfsrv_mallocmget_limit() returns True, the system is near
675 		 * to its limit for memory that malloc()/mget() can allocate.
676 		 */
677 		if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
678 		    (nfsrv_mallocmget_limit() ||
679 		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
680 			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
681 				printf("nfsd server cache flooded, try to");
682 				printf(" increase nfsrc_floodlevel\n");
683 			}
684 			nd->nd_repstat = NFSERR_RESOURCE;
685 			*repp = nfsd_errmap(nd);
686 			if (op == NFSV4OP_SETATTR) {
687 				/*
688 				 * Setattr replies require a bitmap.
689 				 * even for errors like these.
690 				 */
691 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
692 				*tl = 0;
693 			}
694 			retops++;
695 			break;
696 		}
697 		if (nfsv4_opflag[op].savereply)
698 			nd->nd_flag |= ND_SAVEREPLY;
699 		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
700 		switch (op) {
701 		case NFSV4OP_PUTFH:
702 			error = nfsrv_mtofh(nd, &fh);
703 			if (error)
704 				goto nfsmout;
705 			if (!nd->nd_repstat)
706 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
707 				    NULL, 0, p);
708 			/* For now, allow this for non-export FHs */
709 			if (!nd->nd_repstat) {
710 				if (vp)
711 					vrele(vp);
712 				vp = nvp;
713 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
714 				NFSVOPUNLOCK(vp, 0);
715 				vpnes = nes;
716 			}
717 			break;
718 		case NFSV4OP_PUTPUBFH:
719 			if (nfs_pubfhset)
720 			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
721 				&nes, NULL, 0, p);
722 			else
723 			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
724 			if (!nd->nd_repstat) {
725 				if (vp)
726 					vrele(vp);
727 				vp = nvp;
728 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
729 				NFSVOPUNLOCK(vp, 0);
730 				vpnes = nes;
731 			}
732 			break;
733 		case NFSV4OP_PUTROOTFH:
734 			if (nfs_rootfhset) {
735 				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
736 				    &nes, NULL, 0, p);
737 				if (!nd->nd_repstat) {
738 					if (vp)
739 						vrele(vp);
740 					vp = nvp;
741 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
742 					NFSVOPUNLOCK(vp, 0);
743 					vpnes = nes;
744 				}
745 			} else
746 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
747 			break;
748 		case NFSV4OP_SAVEFH:
749 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
750 				nd->nd_repstat = 0;
751 				/* If vp == savevp, a no-op */
752 				if (vp != savevp) {
753 					if (savevp)
754 						vrele(savevp);
755 					VREF(vp);
756 					savevp = vp;
757 					savevpnes = vpnes;
758 					save_fsid = cur_fsid;
759 				}
760 			} else {
761 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
762 			}
763 			break;
764 		case NFSV4OP_RESTOREFH:
765 			if (savevp) {
766 				nd->nd_repstat = 0;
767 				/* If vp == savevp, a no-op */
768 				if (vp != savevp) {
769 					VREF(savevp);
770 					vrele(vp);
771 					vp = savevp;
772 					vpnes = savevpnes;
773 					cur_fsid = save_fsid;
774 				}
775 			} else {
776 				nd->nd_repstat = NFSERR_RESTOREFH;
777 			}
778 			break;
779 		default:
780 		    /*
781 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
782 		     * non-exported directory if
783 		     * nfs_rootfhset. Do I need to allow any other Ops?
784 		     * (You can only have a non-exported vpnes if
785 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
786 		     * Allow AUTH_SYS to be used for file systems
787 		     * exported GSS only for certain Ops, to allow
788 		     * clients to do mounts more easily.
789 		     */
790 		    if (nfsv4_opflag[op].needscfh && vp) {
791 			if (!NFSVNO_EXPORTED(&vpnes) &&
792 			    op != NFSV4OP_LOOKUP &&
793 			    op != NFSV4OP_GETATTR &&
794 			    op != NFSV4OP_GETFH &&
795 			    op != NFSV4OP_ACCESS &&
796 			    op != NFSV4OP_READLINK &&
797 			    op != NFSV4OP_SECINFO)
798 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
799 			else if (nfsvno_testexp(nd, &vpnes) &&
800 			    op != NFSV4OP_LOOKUP &&
801 			    op != NFSV4OP_GETFH &&
802 			    op != NFSV4OP_GETATTR &&
803 			    op != NFSV4OP_SECINFO)
804 				nd->nd_repstat = NFSERR_WRONGSEC;
805 			if (nd->nd_repstat) {
806 				if (op == NFSV4OP_SETATTR) {
807 				    /*
808 				     * Setattr reply requires a bitmap
809 				     * even for errors like these.
810 				     */
811 				    NFSM_BUILD(tl, u_int32_t *,
812 					NFSX_UNSIGNED);
813 				    *tl = 0;
814 				}
815 				break;
816 			}
817 		    }
818 		    if (nfsv4_opflag[op].retfh == 1) {
819 			if (!vp) {
820 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
821 				break;
822 			}
823 			VREF(vp);
824 			if (nfsv4_opflag[op].modifyfs)
825 				vn_start_write(vp, &temp_mp, V_WAIT);
826 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
827 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
828 			if (!error && !nd->nd_repstat) {
829 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
830 				new_mp = nvp->v_mount;
831 				if (cur_fsid.val[0] !=
832 				    new_mp->mnt_stat.f_fsid.val[0] ||
833 				    cur_fsid.val[1] !=
834 				    new_mp->mnt_stat.f_fsid.val[1]) {
835 				    /* crossed a server mount point */
836 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
837 					nd->nd_nam, &nes, &credanon);
838 				    if (!nd->nd_repstat)
839 					nd->nd_repstat = nfsd_excred(nd,
840 					    &nes, credanon);
841 				    if (credanon != NULL)
842 					crfree(credanon);
843 				    if (!nd->nd_repstat) {
844 					vpnes = nes;
845 					cur_fsid = new_mp->mnt_stat.f_fsid;
846 				    }
847 				}
848 				/* Lookup ops return a locked vnode */
849 				NFSVOPUNLOCK(nvp, 0);
850 			    }
851 			    if (!nd->nd_repstat) {
852 				    vrele(vp);
853 				    vp = nvp;
854 			    } else
855 				    vrele(nvp);
856 			}
857 			if (nfsv4_opflag[op].modifyfs)
858 				vn_finished_write(temp_mp);
859 		    } else if (nfsv4_opflag[op].retfh == 2) {
860 			if (vp == NULL || savevp == NULL) {
861 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
862 				break;
863 			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
864 			    cur_fsid.val[1] != save_fsid.val[1]) {
865 				nd->nd_repstat = NFSERR_XDEV;
866 				break;
867 			}
868 			if (nfsv4_opflag[op].modifyfs)
869 				vn_start_write(savevp, &temp_mp, V_WAIT);
870 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
871 				VREF(vp);
872 				VREF(savevp);
873 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
874 				    savevp, vp, p, &savevpnes, &vpnes);
875 			} else
876 				nd->nd_repstat = NFSERR_PERM;
877 			if (nfsv4_opflag[op].modifyfs)
878 				vn_finished_write(temp_mp);
879 		    } else {
880 			if (nfsv4_opflag[op].retfh != 0)
881 				panic("nfsrvd_compound");
882 			if (nfsv4_opflag[op].needscfh) {
883 				if (vp != NULL) {
884 					if (nfsv4_opflag[op].modifyfs)
885 						vn_start_write(vp, &temp_mp,
886 						    V_WAIT);
887 					if (NFSVOPLOCK(vp, nfsv4_opflag[op].lktype)
888 					    == 0)
889 						VREF(vp);
890 					else
891 						nd->nd_repstat = NFSERR_PERM;
892 				} else {
893 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
894 					if (op == NFSV4OP_SETATTR) {
895 						/*
896 						 * Setattr reply requires a
897 						 * bitmap even for errors like
898 						 * these.
899 						 */
900 						NFSM_BUILD(tl, u_int32_t *,
901 						    NFSX_UNSIGNED);
902 						*tl = 0;
903 					}
904 					break;
905 				}
906 				if (nd->nd_repstat == 0)
907 					error = (*(nfsrv4_ops0[op]))(nd,
908 					    isdgram, vp, p, &vpnes);
909 				if (nfsv4_opflag[op].modifyfs)
910 					vn_finished_write(temp_mp);
911 			} else {
912 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
913 				    NULL, p, &vpnes);
914 			}
915 		    }
916 		};
917 		if (error) {
918 			if (error == EBADRPC || error == NFSERR_BADXDR) {
919 				nd->nd_repstat = NFSERR_BADXDR;
920 			} else {
921 				nd->nd_repstat = error;
922 				printf("nfsv4 comperr0=%d\n", error);
923 			}
924 			error = 0;
925 		}
926 		retops++;
927 		if (nd->nd_repstat) {
928 			*repp = nfsd_errmap(nd);
929 			break;
930 		} else {
931 			*repp = 0;	/* NFS4_OK */
932 		}
933 	}
934 nfsmout:
935 	if (error) {
936 		if (error == EBADRPC || error == NFSERR_BADXDR)
937 			nd->nd_repstat = NFSERR_BADXDR;
938 		else
939 			printf("nfsv4 comperr1=%d\n", error);
940 	}
941 	if (taglen == -1) {
942 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
943 		*tl++ = 0;
944 		*tl = 0;
945 	} else {
946 		*retopsp = txdr_unsigned(retops);
947 	}
948 	if (vp)
949 		vrele(vp);
950 	if (savevp)
951 		vrele(savevp);
952 	NFSLOCKV4ROOTMUTEX();
953 	nfsv4_relref(&nfsv4rootfs_lock);
954 	NFSUNLOCKV4ROOTMUTEX();
955 
956 	NFSEXITCODE2(0, nd);
957 }
958