nfs_nfsdsocket.c revision 211951
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 211951 2010-08-28 21:41:18Z 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		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		/*
537		 * If I got the lock, I can update the stable storage file.
538		 * Done when the grace period is over or a client has long
539		 * since expired.
540		 */
541		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
542		if ((nfsrv_stablefirst.nsf_flags &
543		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
544			nfsrv_updatestable(p);
545
546		/*
547		 * If at least one client has long since expired, search
548		 * the client list for them, write a REVOKE record on the
549		 * stable storage file and then remove them from the client
550		 * list.
551		 */
552		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
553			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
554			for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
555			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
556				nclp) {
557				if (clp->lc_flags & LCL_EXPIREIT) {
558				    if (!LIST_EMPTY(&clp->lc_open) ||
559					!LIST_EMPTY(&clp->lc_deleg))
560					nfsrv_writestable(clp->lc_id,
561					    clp->lc_idlen, NFSNST_REVOKE, p);
562				    nfsrv_cleanclient(clp, p);
563				    nfsrv_freedeleglist(&clp->lc_deleg);
564				    nfsrv_freedeleglist(&clp->lc_olddeleg);
565				    LIST_REMOVE(clp, lc_hash);
566				    nfsrv_zapclient(clp, p);
567				}
568			    }
569			}
570		}
571		NFSLOCKV4ROOTMUTEX();
572		nfsv4_unlock(&nfsv4rootfs_lock, 1);
573		NFSUNLOCKV4ROOTMUTEX();
574	} else {
575		/*
576		 * If we didn't get the lock, we need to get a refcnt,
577		 * which also checks for and waits for the lock.
578		 */
579		NFSLOCKV4ROOTMUTEX();
580		nfsv4_getref(&nfsv4rootfs_lock, NULL,
581		    NFSV4ROOTLOCKMUTEXPTR);
582		NFSUNLOCKV4ROOTMUTEX();
583	}
584
585	/*
586	 * If flagged, search for open owners that haven't had any opens
587	 * for a long time.
588	 */
589	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
590		nfsrv_throwawayopens(p);
591	}
592
593	savevp = vp = NULL;
594	savevpnes.nes_vfslocked = vpnes.nes_vfslocked = 0;
595	savemp = mp = NULL;
596	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
597	taglen = fxdr_unsigned(int, *tl);
598	if (taglen < 0) {
599		error = EBADRPC;
600		goto nfsmout;
601	}
602	if (taglen <= NFSV4_SMALLSTR)
603		tagstr = tag;
604	else
605		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
606	error = nfsrv_mtostr(nd, tagstr, taglen);
607	if (error) {
608		if (taglen > NFSV4_SMALLSTR)
609			free(tagstr, M_TEMP);
610		taglen = -1;
611		goto nfsmout;
612	}
613	(void) nfsm_strtom(nd, tag, taglen);
614	if (taglen > NFSV4_SMALLSTR) {
615		free(tagstr, M_TEMP);
616	}
617	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
618	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
619	minorvers = fxdr_unsigned(u_int32_t, *tl++);
620	if (minorvers != NFSV4_MINORVERSION)
621		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
622	if (nd->nd_repstat)
623		numops = 0;
624	else
625		numops = fxdr_unsigned(int, *tl);
626	/*
627	 * Loop around doing the sub ops.
628	 * vp - is an unlocked vnode pointer for the CFH
629	 * savevp - is an unlocked vnode pointer for the SAVEDFH
630	 * (at some future date, it might turn out to be more appropriate
631	 *  to keep the file handles instead of vnode pointers?)
632	 * savevpnes and vpnes - are the export flags for the above.
633	 */
634	for (i = 0; i < numops; i++) {
635		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
636		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
637		*repp = *tl;
638		op = fxdr_unsigned(int, *tl);
639		if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
640			nd->nd_repstat = NFSERR_OPILLEGAL;
641			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
642			*repp = nfsd_errmap(nd);
643			retops++;
644			break;
645		} else {
646			repp++;
647		}
648
649		/*
650		 * Check for a referral on the current FH and, if so, return
651		 * NFSERR_MOVED for all ops that allow it, except Getattr.
652		 */
653		if (vp != NULL && op != NFSV4OP_GETATTR &&
654		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
655		    nfsrv_errmoved(op)) {
656			nd->nd_repstat = NFSERR_MOVED;
657			*repp = nfsd_errmap(nd);
658			retops++;
659			break;
660		}
661
662		nd->nd_procnum = op;
663		/*
664		 * If over flood level, reply NFSERR_RESOURCE, if at the first
665		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
666		 * really nasty for certain Op sequences, I'll play it safe
667		 * and only return the error at the beginning.) The cache
668		 * will still function over flood level, but uses lots of
669		 * mbufs.)
670		 * If nfsrv_mallocmget_limit() returns True, the system is near
671		 * to its limit for memory that malloc()/mget() can allocate.
672		 */
673		if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
674		    (nfsrv_mallocmget_limit() ||
675		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
676			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
677				printf("nfsd server cache flooded, try to");
678				printf(" increase nfsrc_floodlevel\n");
679			}
680			nd->nd_repstat = NFSERR_RESOURCE;
681			*repp = nfsd_errmap(nd);
682			if (op == NFSV4OP_SETATTR) {
683				/*
684				 * Setattr replies require a bitmap.
685				 * even for errors like these.
686				 */
687				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
688				*tl = 0;
689			}
690			retops++;
691			break;
692		}
693		if (nfsv4_opflag[op].savereply)
694			nd->nd_flag |= ND_SAVEREPLY;
695		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
696		switch (op) {
697		case NFSV4OP_PUTFH:
698			error = nfsrv_mtofh(nd, &fh);
699			if (error)
700				goto nfsmout;
701			if (!nd->nd_repstat) {
702				nes.nes_vfslocked = vpnes.nes_vfslocked;
703				nfsd_fhtovp(nd, &fh, &nvp, &nes, &mp,
704				    0, p);
705			}
706			/* For now, allow this for non-export FHs */
707			if (!nd->nd_repstat) {
708				if (vp)
709					vrele(vp);
710				vp = nvp;
711				NFSVOPUNLOCK(vp, 0, p);
712				vpnes = nes;
713			}
714			break;
715		case NFSV4OP_PUTPUBFH:
716			if (nfs_pubfhset) {
717			    nes.nes_vfslocked = vpnes.nes_vfslocked;
718			    nfsd_fhtovp(nd, &nfs_pubfh, &nvp,
719				&nes, &mp, 0, p);
720			} else {
721			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
722			}
723			if (!nd->nd_repstat) {
724				if (vp)
725					vrele(vp);
726				vp = nvp;
727				NFSVOPUNLOCK(vp, 0, p);
728				vpnes = nes;
729			}
730			break;
731		case NFSV4OP_PUTROOTFH:
732			if (nfs_rootfhset) {
733				nes.nes_vfslocked = vpnes.nes_vfslocked;
734				nfsd_fhtovp(nd, &nfs_rootfh, &nvp,
735				    &nes, &mp, 0, p);
736				if (!nd->nd_repstat) {
737					if (vp)
738						vrele(vp);
739					vp = nvp;
740					NFSVOPUNLOCK(vp, 0, p);
741					vpnes = nes;
742				}
743			} else if (nfsv4root_vp && nfsv4root_set) {
744				if (vp) {
745					if (vpnes.nes_vfslocked)
746						nfsvno_unlockvfs(mp);
747					vrele(vp);
748				}
749				vp = nfsv4root_vp;
750				VREF(vp);
751				NFSVNO_SETEXRDONLY(&vpnes);
752				vpnes.nes_vfslocked = 0;
753				mp = vnode_mount(vp);
754			} else {
755				nd->nd_repstat = NFSERR_NOFILEHANDLE;
756			}
757			break;
758		case NFSV4OP_SAVEFH:
759			if (vp && NFSVNO_EXPORTED(&vpnes)) {
760				nd->nd_repstat = 0;
761				/* If vp == savevp, a no-op */
762				if (vp != savevp) {
763					if (savevp)
764						vrele(savevp);
765					VREF(vp);
766					savevp = vp;
767					savevpnes = vpnes;
768					savemp = mp;
769				}
770			} else {
771				nd->nd_repstat = NFSERR_NOFILEHANDLE;
772			}
773			break;
774		case NFSV4OP_RESTOREFH:
775			if (savevp) {
776				nd->nd_repstat = 0;
777				/* If vp == savevp, a no-op */
778				if (vp != savevp) {
779					VREF(savevp);
780					if (mp == NULL || savemp == NULL)
781						panic("nfscmpmp");
782					if (!savevpnes.nes_vfslocked &&
783					    vpnes.nes_vfslocked) {
784						if (mp == savemp)
785							panic("nfscmp2");
786						nfsvno_unlockvfs(mp);
787					} else if (savevpnes.nes_vfslocked &&
788					    !vpnes.nes_vfslocked) {
789						if (mp == savemp)
790							panic("nfscmp3");
791						savevpnes.nes_vfslocked = nfsvno_lockvfs(savemp);
792					}
793					vrele(vp);
794					vp = savevp;
795					vpnes = savevpnes;
796					mp = savemp;
797				}
798			} else {
799				nd->nd_repstat = NFSERR_RESTOREFH;
800			}
801			break;
802		default:
803		    /*
804		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
805		     * non-exported directory if
806		     * nfs_rootfhset. Do I need to allow any other Ops?
807		     * (You can only have a non-exported vpnes if
808		     *  nfs_rootfhset is true. See nfsd_fhtovp())
809		     * Allow AUTH_SYS to be used for file systems
810		     * exported GSS only for certain Ops, to allow
811		     * clients to do mounts more easily.
812		     */
813		    if (nfsv4_opflag[op].needscfh && vp) {
814			if (!NFSVNO_EXPORTED(&vpnes) &&
815			    op != NFSV4OP_LOOKUP &&
816			    op != NFSV4OP_GETATTR &&
817			    op != NFSV4OP_GETFH &&
818			    op != NFSV4OP_SECINFO)
819				nd->nd_repstat = NFSERR_NOFILEHANDLE;
820			else if (nfsvno_testexp(nd, &vpnes) &&
821			    op != NFSV4OP_LOOKUP &&
822			    op != NFSV4OP_GETFH &&
823			    op != NFSV4OP_GETATTR &&
824			    op != NFSV4OP_SECINFO)
825				nd->nd_repstat = NFSERR_WRONGSEC;
826			if (nd->nd_repstat) {
827				if (op == NFSV4OP_SETATTR) {
828				    /*
829				     * Setattr reply requires a bitmap
830				     * even for errors like these.
831				     */
832				    NFSM_BUILD(tl, u_int32_t *,
833					NFSX_UNSIGNED);
834				    *tl = 0;
835				}
836				break;
837			}
838		    }
839		    if (nfsv4_opflag[op].retfh == 1) {
840			if (!vp) {
841				nd->nd_repstat = NFSERR_NOFILEHANDLE;
842				break;
843			}
844			VREF(vp);
845			if (nfsv4_opflag[op].modifyfs)
846				NFS_STARTWRITE(NULL, &mp);
847			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
848			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
849			if (!error && !nd->nd_repstat) {
850			    if (vfs_statfs(mp)->f_fsid.val[0] !=
851				vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ||
852				vfs_statfs(mp)->f_fsid.val[1] !=
853				vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) {
854				if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ==
855				    NFSV4ROOT_FSID0 &&
856				    vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] ==
857				    NFSV4ROOT_FSID1) {
858				    if (vpnes.nes_vfslocked) {
859					nfsvno_unlockvfs(mp);
860					vpnes.nes_vfslocked = 0;
861				    }
862				    NFSVNO_SETEXRDONLY(&vpnes);
863				    mp = vnode_mount(nvp);
864				} else {
865				    nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp),
866					nd->nd_nam, &nes, &credanon);
867				    if (!nd->nd_repstat)
868					nd->nd_repstat = nfsd_excred(nd,
869					    &nes, credanon);
870				    if (credanon != NULL)
871					crfree(credanon);
872				    if (!nd->nd_repstat) {
873					if (vpnes.nes_vfslocked)
874					    nfsvno_unlockvfs(mp);
875					mp = vnode_mount(nvp);
876					vpnes = nes;
877					vpnes.nes_vfslocked =
878					    nfsvno_lockvfs(mp);
879				    }
880				}
881			    }
882			    if (!nd->nd_repstat) {
883				    vrele(vp);
884				    vp = nvp;
885			    }
886			}
887			if (nfsv4_opflag[op].modifyfs)
888				NFS_ENDWRITE(mp);
889		    } else if (nfsv4_opflag[op].retfh == 2) {
890			if (vp == NULL || savevp == NULL) {
891				nd->nd_repstat = NFSERR_NOFILEHANDLE;
892				break;
893			} else if (mp != savemp) {
894				nd->nd_repstat = NFSERR_XDEV;
895				break;
896			}
897			VREF(vp);
898			VREF(savevp);
899			if (nfsv4_opflag[op].modifyfs)
900				NFS_STARTWRITE(NULL, &mp);
901			NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
902			error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
903			    vp, p, &savevpnes, &vpnes);
904			if (nfsv4_opflag[op].modifyfs)
905				NFS_ENDWRITE(mp);
906		    } else {
907			if (nfsv4_opflag[op].retfh != 0)
908				panic("nfsrvd_compound");
909			if (nfsv4_opflag[op].needscfh) {
910				if (vp) {
911					VREF(vp);
912					if (nfsv4_opflag[op].modifyfs)
913						NFS_STARTWRITE(NULL, &mp);
914					NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
915				} else {
916					nd->nd_repstat = NFSERR_NOFILEHANDLE;
917					if (op == NFSV4OP_SETATTR) {
918					    /*
919					     * Setattr reply requires a bitmap
920					     * even for errors like these.
921					     */
922					    NFSM_BUILD(tl, u_int32_t *,
923						NFSX_UNSIGNED);
924					    *tl = 0;
925					}
926					break;
927				}
928				error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
929				    p, &vpnes);
930				if (nfsv4_opflag[op].modifyfs)
931					NFS_ENDWRITE(mp);
932			} else {
933				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
934				    NULL, p, &vpnes);
935			}
936		    }
937		};
938		if (error) {
939			if (error == EBADRPC || error == NFSERR_BADXDR) {
940				nd->nd_repstat = NFSERR_BADXDR;
941			} else {
942				nd->nd_repstat = error;
943				printf("nfsv4 comperr0=%d\n", error);
944			}
945			error = 0;
946		}
947		retops++;
948		if (nd->nd_repstat) {
949			*repp = nfsd_errmap(nd);
950			break;
951		} else {
952			*repp = 0;	/* NFS4_OK */
953		}
954	}
955nfsmout:
956	if (error) {
957		if (error == EBADRPC || error == NFSERR_BADXDR)
958			nd->nd_repstat = NFSERR_BADXDR;
959		else
960			printf("nfsv4 comperr1=%d\n", error);
961	}
962	if (taglen == -1) {
963		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
964		*tl++ = 0;
965		*tl = 0;
966	} else {
967		*retopsp = txdr_unsigned(retops);
968	}
969	if (mp && vpnes.nes_vfslocked)
970		nfsvno_unlockvfs(mp);
971	if (vp)
972		vrele(vp);
973	if (savevp)
974		vrele(savevp);
975	NFSLOCKV4ROOTMUTEX();
976	nfsv4_relref(&nfsv4rootfs_lock);
977	NFSUNLOCKV4ROOTMUTEX();
978}
979