nfs_nfsdsocket.c revision 192781
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: head/sys/fs/nfsserver/nfs_nfsdsocket.c 192781 2009-05-26 01:16:09Z rmacklem $");
36
37/*
38 * Socket operations for use by the nfs server.
39 */
40
41#ifndef APPLEKEXT
42#include <fs/nfs/nfsport.h>
43
44extern struct nfsstats newnfsstats;
45extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
46extern int nfs_pubfhset, nfs_rootfhset;
47extern struct nfsv4lock nfsv4rootfs_lock;
48extern struct nfsrv_stablefirst nfsrv_stablefirst;
49extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
50extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
51NFSV4ROOTLOCKMUTEX;
52NFSSTATESPINLOCK;
53vnode_t nfsv4root_vp = NULL;
54int nfsv4root_set = 0;
55
56int (*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
82int (*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
109int (*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
136int (*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
180int (*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
225int (*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 */
274static 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 */
303static 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 */
308static 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 */
316static 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
319extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
320
321static 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 */
353APPLESTATIC void
354nfsrvd_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 */
486static void
487nfsrvd_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	}
960nfsmout:
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