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