nfs_nfsdsocket.c revision 191940
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 191940 2009-05-09 18:09:17Z kan $");
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 = nfsd_errmap(nd);
647		    retops++;
648		    break;
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_EXGSSONLY(&vpnes) &&
823			    !(nd->nd_flag & ND_GSS) &&
824			    op != NFSV4OP_LOOKUP &&
825			    op != NFSV4OP_GETFH &&
826			    op != NFSV4OP_GETATTR &&
827			    op != NFSV4OP_SECINFO)
828				nd->nd_repstat = NFSERR_WRONGSEC;
829			if (nd->nd_repstat) {
830				if (op == NFSV4OP_SETATTR) {
831				    /*
832				     * Setattr reply requires a bitmap
833				     * even for errors like these.
834				     */
835				    NFSM_BUILD(tl, u_int32_t *,
836					NFSX_UNSIGNED);
837				    *tl = 0;
838				}
839				break;
840			}
841		    }
842		    if (nfsv4_opflag[op].retfh == 1) {
843			if (!vp) {
844				nd->nd_repstat = NFSERR_NOFILEHANDLE;
845				break;
846			}
847			VREF(vp);
848			if (nfsv4_opflag[op].modifyfs)
849				NFS_STARTWRITE(NULL, &mp);
850			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
851			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
852			if (!error && !nd->nd_repstat) {
853			    if (vfs_statfs(mp)->f_fsid.val[0] !=
854				vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ||
855				vfs_statfs(mp)->f_fsid.val[1] !=
856				vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) {
857				if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ==
858				    NFSV4ROOT_FSID0 &&
859				    vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] ==
860				    NFSV4ROOT_FSID1) {
861				    if (vpnes.nes_vfslocked) {
862					nfsvno_unlockvfs(mp);
863					vpnes.nes_vfslocked = 0;
864				    }
865				    NFSVNO_SETEXRDONLY(&vpnes);
866				    mp = vnode_mount(nvp);
867				} else {
868				    nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp),
869					nd->nd_nam, &nes, &credanon);
870				    if (!nd->nd_repstat)
871					nd->nd_repstat = nfsd_excred(nd,
872					    &nes, credanon);
873				    if (credanon != NULL)
874					crfree(credanon);
875				    if (!nd->nd_repstat) {
876					if (vpnes.nes_vfslocked)
877					    nfsvno_unlockvfs(mp);
878					mp = vnode_mount(nvp);
879					vpnes = nes;
880					vpnes.nes_vfslocked =
881					    nfsvno_lockvfs(mp);
882				    }
883				}
884			    }
885			    if (!nd->nd_repstat) {
886				    vrele(vp);
887				    vp = nvp;
888			    }
889			}
890			if (nfsv4_opflag[op].modifyfs)
891				NFS_ENDWRITE(mp);
892		    } else if (nfsv4_opflag[op].retfh == 2) {
893			if (vp == NULL || savevp == NULL) {
894				nd->nd_repstat = NFSERR_NOFILEHANDLE;
895				break;
896			} else if (mp != savemp) {
897				nd->nd_repstat = NFSERR_XDEV;
898				break;
899			}
900			VREF(vp);
901			VREF(savevp);
902			if (nfsv4_opflag[op].modifyfs)
903				NFS_STARTWRITE(NULL, &mp);
904			NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
905			error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
906			    vp, p, &savevpnes, &vpnes);
907			if (nfsv4_opflag[op].modifyfs)
908				NFS_ENDWRITE(mp);
909		    } else {
910			if (nfsv4_opflag[op].retfh != 0)
911				panic("nfsrvd_compound");
912			if (nfsv4_opflag[op].needscfh) {
913				if (vp) {
914					VREF(vp);
915					if (nfsv4_opflag[op].modifyfs)
916						NFS_STARTWRITE(NULL, &mp);
917					NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
918				} else {
919					nd->nd_repstat = NFSERR_NOFILEHANDLE;
920					if (op == NFSV4OP_SETATTR) {
921					    /*
922					     * Setattr reply requires a bitmap
923					     * even for errors like these.
924					     */
925					    NFSM_BUILD(tl, u_int32_t *,
926						NFSX_UNSIGNED);
927					    *tl = 0;
928					}
929					break;
930				}
931				error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
932				    p, &vpnes);
933				if (nfsv4_opflag[op].modifyfs)
934					NFS_ENDWRITE(mp);
935			} else {
936				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
937				    NULL, p, &vpnes);
938			}
939		    }
940		};
941		if (error) {
942			if (error == EBADRPC || error == NFSERR_BADXDR) {
943				nd->nd_repstat = NFSERR_BADXDR;
944			} else {
945				nd->nd_repstat = error;
946				printf("nfsv4 comperr0=%d\n", error);
947			}
948			error = 0;
949		}
950		retops++;
951		if (nd->nd_repstat) {
952			*repp = nfsd_errmap(nd);
953			break;
954		} else {
955			*repp = 0;	/* NFS4_OK */
956		}
957	}
958nfsmout:
959	if (error) {
960		if (error == EBADRPC || error == NFSERR_BADXDR)
961			nd->nd_repstat = NFSERR_BADXDR;
962		else
963			printf("nfsv4 comperr1=%d\n", error);
964	}
965	if (taglen == -1) {
966		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
967		*tl++ = 0;
968		*tl = 0;
969	} else {
970		*retopsp = txdr_unsigned(retops);
971	}
972	if (mp && vpnes.nes_vfslocked)
973		nfsvno_unlockvfs(mp);
974	if (vp)
975		vrele(vp);
976	if (savevp)
977		vrele(savevp);
978	NFSLOCKV4ROOTMUTEX();
979	nfsv4_relref(&nfsv4rootfs_lock);
980	NFSUNLOCKV4ROOTMUTEX();
981}
982