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