nfs_nfsdsocket.c revision 225736
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: stable/9/sys/fs/nfsserver/nfs_nfsdsocket.c 224086 2011-07-16 08:51:09Z zack $");
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;
53
54int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
55    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
56	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
57	nfsrvd_getattr,
58	nfsrvd_setattr,
59	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
60	nfsrvd_access,
61	nfsrvd_readlink,
62	nfsrvd_read,
63	nfsrvd_write,
64	nfsrvd_create,
65	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
66	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
67	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
68	nfsrvd_remove,
69	nfsrvd_remove,
70	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
71	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
72	nfsrvd_readdir,
73	nfsrvd_readdirplus,
74	nfsrvd_statfs,
75	nfsrvd_fsinfo,
76	nfsrvd_pathconf,
77	nfsrvd_commit,
78};
79
80int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
81    int, vnode_t , vnode_t *, fhandle_t *,
82    NFSPROC_T *, struct nfsexstuff *) = {
83	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
84	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
85	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
86	nfsrvd_lookup,
87	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
88	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
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	nfsrvd_mkdir,
93	nfsrvd_symlink,
94	nfsrvd_mknod,
95	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
96	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
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};
106
107int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
108    int, vnode_t , vnode_t , NFSPROC_T *,
109    struct nfsexstuff *, struct nfsexstuff *) = {
110	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
111	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
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	nfsrvd_rename,
125	nfsrvd_link,
126	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
127	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
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};
133
134int (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *,
135    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
136	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
137	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
138	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
139	nfsrvd_access,
140	nfsrvd_close,
141	nfsrvd_commit,
142	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
143	nfsrvd_delegpurge,
144	nfsrvd_delegreturn,
145	nfsrvd_getattr,
146	nfsrvd_getfh,
147	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
148	nfsrvd_lock,
149	nfsrvd_lockt,
150	nfsrvd_locku,
151	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
152	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
153	nfsrvd_verify,
154	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
155	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
156	nfsrvd_openconfirm,
157	nfsrvd_opendowngrade,
158	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
159	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
160	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
161	nfsrvd_read,
162	nfsrvd_readdirplus,
163	nfsrvd_readlink,
164	nfsrvd_remove,
165	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
166	nfsrvd_renew,
167	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
168	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
169	nfsrvd_secinfo,
170	nfsrvd_setattr,
171	nfsrvd_setclientid,
172	nfsrvd_setclientidcfrm,
173	nfsrvd_verify,
174	nfsrvd_write,
175	nfsrvd_releaselckown,
176};
177
178int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
179    int, vnode_t , vnode_t *, fhandle_t *,
180    NFSPROC_T *, struct nfsexstuff *) = {
181	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
182	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
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	nfsrvd_mknod,
188	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
189	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
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	nfsrvd_lookup,
197	nfsrvd_lookup,
198	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
199	nfsrvd_open,
200	nfsrvd_openattr,
201	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
202	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
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};
222
223int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
224    int, vnode_t , vnode_t , NFSPROC_T *,
225    struct nfsexstuff *, struct nfsexstuff *) = {
226	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
227	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
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	nfsrvd_link,
238	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
239	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
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	nfsrvd_rename,
256	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
257	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
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};
267#endif	/* !APPLEKEXT */
268
269/*
270 * Static array that defines which nfs rpc's are nonidempotent
271 */
272static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
273	FALSE,
274	FALSE,
275	TRUE,
276	FALSE,
277	FALSE,
278	FALSE,
279	FALSE,
280	TRUE,
281	TRUE,
282	TRUE,
283	TRUE,
284	TRUE,
285	TRUE,
286	TRUE,
287	TRUE,
288	TRUE,
289	FALSE,
290	FALSE,
291	FALSE,
292	FALSE,
293	FALSE,
294	FALSE,
295};
296
297/*
298 * This static array indicates whether or not the RPC modifies the
299 * file system.
300 */
301static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
302    1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
303    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
304
305/* local functions */
306static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
307    NFSPROC_T *p);
308
309
310/*
311 * This static array indicates which server procedures require the extra
312 * arguments to return the current file handle for V2, 3.
313 */
314static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
315	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
316
317extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
318
319static int nfsv3to4op[NFS_V3NPROCS] = {
320	NFSPROC_NULL,
321	NFSV4OP_GETATTR,
322	NFSV4OP_SETATTR,
323	NFSV4OP_LOOKUP,
324	NFSV4OP_ACCESS,
325	NFSV4OP_READLINK,
326	NFSV4OP_READ,
327	NFSV4OP_WRITE,
328	NFSV4OP_V3CREATE,
329	NFSV4OP_MKDIR,
330	NFSV4OP_SYMLINK,
331	NFSV4OP_MKNOD,
332	NFSV4OP_REMOVE,
333	NFSV4OP_RMDIR,
334	NFSV4OP_RENAME,
335	NFSV4OP_LINK,
336	NFSV4OP_READDIR,
337	NFSV4OP_READDIRPLUS,
338	NFSV4OP_FSSTAT,
339	NFSV4OP_FSINFO,
340	NFSV4OP_PATHCONF,
341	NFSV4OP_COMMIT,
342};
343
344/*
345 * Do an RPC. Basically, get the file handles translated to vnode pointers
346 * and then call the appropriate server routine. The server routines are
347 * split into groups, based on whether they use a file handle or file
348 * handle plus name or ...
349 * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
350 */
351APPLESTATIC void
352nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
353    NFSPROC_T *p)
354{
355	int error = 0, lktype;
356	vnode_t vp;
357	mount_t mp = NULL;
358	struct nfsrvfh fh;
359	struct nfsexstuff nes;
360
361	/*
362	 * Get a locked vnode for the first file handle
363	 */
364	if (!(nd->nd_flag & ND_NFSV4)) {
365		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
366		/*
367		 * For NFSv3, if the malloc/mget allocation is near limits,
368		 * return NFSERR_DELAY.
369		 */
370		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
371			nd->nd_repstat = NFSERR_DELAY;
372			vp = NULL;
373		} else {
374			error = nfsrv_mtofh(nd, &fh);
375			if (error) {
376				if (error != EBADRPC)
377					printf("nfs dorpc err1=%d\n", error);
378				nd->nd_repstat = NFSERR_GARBAGE;
379				goto out;
380			}
381			if (nd->nd_procnum == NFSPROC_READ ||
382			    nd->nd_procnum == NFSPROC_READDIR ||
383			    nd->nd_procnum == NFSPROC_READLINK ||
384			    nd->nd_procnum == NFSPROC_GETATTR ||
385			    nd->nd_procnum == NFSPROC_ACCESS)
386				lktype = LK_SHARED;
387			else
388				lktype = LK_EXCLUSIVE;
389			if (nd->nd_flag & ND_PUBLOOKUP)
390				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
391				    &mp, nfs_writerpc[nd->nd_procnum], p);
392			else
393				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
394				    &mp, nfs_writerpc[nd->nd_procnum], p);
395			if (nd->nd_repstat == NFSERR_PROGNOTV4)
396				goto out;
397		}
398	}
399
400	/*
401	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
402	 * cache, as required.
403	 * For V4, nfsrvd_compound() does this.
404	 */
405	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
406		nd->nd_flag |= ND_SAVEREPLY;
407
408	nfsrvd_rephead(nd);
409	/*
410	 * If nd_repstat is non-zero, just fill in the reply status
411	 * to complete the RPC reply for V2. Otherwise, you must do
412	 * the RPC.
413	 */
414	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
415		*nd->nd_errp = nfsd_errmap(nd);
416		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
417		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
418			vn_finished_write(mp);
419		goto out;
420	}
421
422	/*
423	 * Now the procedure can be performed. For V4, nfsrvd_compound()
424	 * works through the sub-rpcs, otherwise just call the procedure.
425	 * The procedures are in three groups with different arguments.
426	 * The group is indicated by the value in nfs_retfh[].
427	 */
428	if (nd->nd_flag & ND_NFSV4) {
429		nfsrvd_compound(nd, isdgram, p);
430	} else {
431		if (nfs_retfh[nd->nd_procnum] == 1) {
432			if (vp)
433				NFSVOPUNLOCK(vp, 0);
434			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
435			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
436		} else if (nfs_retfh[nd->nd_procnum] == 2) {
437			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
438			    vp, NULL, p, &nes, NULL);
439		} else {
440			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
441			    vp, p, &nes);
442		}
443		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
444			vn_finished_write(mp);
445		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
446	}
447	if (error) {
448		if (error != EBADRPC)
449			printf("nfs dorpc err2=%d\n", error);
450		nd->nd_repstat = NFSERR_GARBAGE;
451	}
452	*nd->nd_errp = nfsd_errmap(nd);
453
454	/*
455	 * Don't cache certain reply status values.
456	 */
457	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
458	    (nd->nd_repstat == NFSERR_GARBAGE ||
459	     nd->nd_repstat == NFSERR_BADXDR ||
460	     nd->nd_repstat == NFSERR_MOVED ||
461	     nd->nd_repstat == NFSERR_DELAY ||
462	     nd->nd_repstat == NFSERR_BADSEQID ||
463	     nd->nd_repstat == NFSERR_RESOURCE ||
464	     nd->nd_repstat == NFSERR_SERVERFAULT ||
465	     nd->nd_repstat == NFSERR_STALECLIENTID ||
466	     nd->nd_repstat == NFSERR_STALESTATEID ||
467	     nd->nd_repstat == NFSERR_OLDSTATEID ||
468	     nd->nd_repstat == NFSERR_BADSTATEID ||
469	     nd->nd_repstat == NFSERR_GRACE ||
470	     nd->nd_repstat == NFSERR_NOGRACE))
471		nd->nd_flag &= ~ND_SAVEREPLY;
472
473out:
474	NFSEXITCODE2(0, nd);
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 new_mp, temp_mp = NULL;
496	struct ucred *credanon;
497	struct nfsexstuff nes, vpnes, savevpnes;
498	fsid_t cur_fsid, save_fsid;
499	static u_int64_t compref = 0;
500
501	NFSVNO_EXINIT(&vpnes);
502	NFSVNO_EXINIT(&savevpnes);
503	/*
504	 * Put the seq# of the current compound RPC in nfsrv_descript.
505	 * (This is used by nfsrv_checkgetattr(), to see if the write
506	 *  delegation was created by the same compound RPC as the one
507	 *  with that Getattr in it.)
508	 * Don't worry about the 64bit number wrapping around. It ain't
509	 * gonna happen before this server gets shut down/rebooted.
510	 */
511	nd->nd_compref = compref++;
512
513	/*
514	 * Check for and optionally get a lock on the root. This lock means that
515	 * no nfsd will be fiddling with the V4 file system and state stuff. It
516	 * is required when the V4 root is being changed, the stable storage
517	 * restart file is being updated, or callbacks are being done.
518	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
519	 * either hold a reference count (nfs_usecnt) or the lock. When
520	 * nfsrv_unlock() is called to release the lock, it can optionally
521	 * also get a reference count, which saves the need for a call to
522	 * nfsrv_getref() after nfsrv_unlock().
523	 */
524	/*
525	 * First, check to see if we need to wait for an update lock.
526	 */
527	igotlock = 0;
528	NFSLOCKV4ROOTMUTEX();
529	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
530		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
531		    NFSV4ROOTLOCKMUTEXPTR, NULL);
532	else
533		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
534		    NFSV4ROOTLOCKMUTEXPTR, NULL);
535	NFSUNLOCKV4ROOTMUTEX();
536	if (igotlock) {
537		/*
538		 * If I got the lock, I can update the stable storage file.
539		 * Done when the grace period is over or a client has long
540		 * since expired.
541		 */
542		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
543		if ((nfsrv_stablefirst.nsf_flags &
544		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
545			nfsrv_updatestable(p);
546
547		/*
548		 * If at least one client has long since expired, search
549		 * the client list for them, write a REVOKE record on the
550		 * stable storage file and then remove them from the client
551		 * list.
552		 */
553		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
554			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
555			for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
556			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
557				nclp) {
558				if (clp->lc_flags & LCL_EXPIREIT) {
559				    if (!LIST_EMPTY(&clp->lc_open) ||
560					!LIST_EMPTY(&clp->lc_deleg))
561					nfsrv_writestable(clp->lc_id,
562					    clp->lc_idlen, NFSNST_REVOKE, p);
563				    nfsrv_cleanclient(clp, p);
564				    nfsrv_freedeleglist(&clp->lc_deleg);
565				    nfsrv_freedeleglist(&clp->lc_olddeleg);
566				    LIST_REMOVE(clp, lc_hash);
567				    nfsrv_zapclient(clp, p);
568				}
569			    }
570			}
571		}
572		NFSLOCKV4ROOTMUTEX();
573		nfsv4_unlock(&nfsv4rootfs_lock, 1);
574		NFSUNLOCKV4ROOTMUTEX();
575	} else {
576		/*
577		 * If we didn't get the lock, we need to get a refcnt,
578		 * which also checks for and waits for the lock.
579		 */
580		NFSLOCKV4ROOTMUTEX();
581		nfsv4_getref(&nfsv4rootfs_lock, NULL,
582		    NFSV4ROOTLOCKMUTEXPTR, NULL);
583		NFSUNLOCKV4ROOTMUTEX();
584	}
585
586	/*
587	 * If flagged, search for open owners that haven't had any opens
588	 * for a long time.
589	 */
590	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
591		nfsrv_throwawayopens(p);
592	}
593
594	savevp = vp = NULL;
595	save_fsid.val[0] = save_fsid.val[1] = 0;
596	cur_fsid.val[0] = cur_fsid.val[1] = 0;
597	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
598	taglen = fxdr_unsigned(int, *tl);
599	if (taglen < 0) {
600		error = EBADRPC;
601		goto nfsmout;
602	}
603	if (taglen <= NFSV4_SMALLSTR)
604		tagstr = tag;
605	else
606		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
607	error = nfsrv_mtostr(nd, tagstr, taglen);
608	if (error) {
609		if (taglen > NFSV4_SMALLSTR)
610			free(tagstr, M_TEMP);
611		taglen = -1;
612		goto nfsmout;
613	}
614	(void) nfsm_strtom(nd, tag, taglen);
615	if (taglen > NFSV4_SMALLSTR) {
616		free(tagstr, M_TEMP);
617	}
618	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
619	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
620	minorvers = fxdr_unsigned(u_int32_t, *tl++);
621	if (minorvers != NFSV4_MINORVERSION)
622		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
623	if (nd->nd_repstat)
624		numops = 0;
625	else
626		numops = fxdr_unsigned(int, *tl);
627	/*
628	 * Loop around doing the sub ops.
629	 * vp - is an unlocked vnode pointer for the CFH
630	 * savevp - is an unlocked vnode pointer for the SAVEDFH
631	 * (at some future date, it might turn out to be more appropriate
632	 *  to keep the file handles instead of vnode pointers?)
633	 * savevpnes and vpnes - are the export flags for the above.
634	 */
635	for (i = 0; i < numops; i++) {
636		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
637		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
638		*repp = *tl;
639		op = fxdr_unsigned(int, *tl);
640		if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
641			nd->nd_repstat = NFSERR_OPILLEGAL;
642			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
643			*repp = nfsd_errmap(nd);
644			retops++;
645			break;
646		} else {
647			repp++;
648		}
649
650		/*
651		 * Check for a referral on the current FH and, if so, return
652		 * NFSERR_MOVED for all ops that allow it, except Getattr.
653		 */
654		if (vp != NULL && op != NFSV4OP_GETATTR &&
655		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
656		    nfsrv_errmoved(op)) {
657			nd->nd_repstat = NFSERR_MOVED;
658			*repp = nfsd_errmap(nd);
659			retops++;
660			break;
661		}
662
663		nd->nd_procnum = op;
664		/*
665		 * If over flood level, reply NFSERR_RESOURCE, if at the first
666		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
667		 * really nasty for certain Op sequences, I'll play it safe
668		 * and only return the error at the beginning.) The cache
669		 * will still function over flood level, but uses lots of
670		 * mbufs.)
671		 * If nfsrv_mallocmget_limit() returns True, the system is near
672		 * to its limit for memory that malloc()/mget() can allocate.
673		 */
674		if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
675		    (nfsrv_mallocmget_limit() ||
676		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
677			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
678				printf("nfsd server cache flooded, try to");
679				printf(" increase nfsrc_floodlevel\n");
680			}
681			nd->nd_repstat = NFSERR_RESOURCE;
682			*repp = nfsd_errmap(nd);
683			if (op == NFSV4OP_SETATTR) {
684				/*
685				 * Setattr replies require a bitmap.
686				 * even for errors like these.
687				 */
688				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
689				*tl = 0;
690			}
691			retops++;
692			break;
693		}
694		if (nfsv4_opflag[op].savereply)
695			nd->nd_flag |= ND_SAVEREPLY;
696		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
697		switch (op) {
698		case NFSV4OP_PUTFH:
699			error = nfsrv_mtofh(nd, &fh);
700			if (error)
701				goto nfsmout;
702			if (!nd->nd_repstat)
703				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
704				    NULL, 0, p);
705			/* For now, allow this for non-export FHs */
706			if (!nd->nd_repstat) {
707				if (vp)
708					vrele(vp);
709				vp = nvp;
710				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
711				NFSVOPUNLOCK(vp, 0);
712				vpnes = nes;
713			}
714			break;
715		case NFSV4OP_PUTPUBFH:
716			if (nfs_pubfhset)
717			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
718				&nes, NULL, 0, p);
719			else
720			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
721			if (!nd->nd_repstat) {
722				if (vp)
723					vrele(vp);
724				vp = nvp;
725				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
726				NFSVOPUNLOCK(vp, 0);
727				vpnes = nes;
728			}
729			break;
730		case NFSV4OP_PUTROOTFH:
731			if (nfs_rootfhset) {
732				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
733				    &nes, NULL, 0, p);
734				if (!nd->nd_repstat) {
735					if (vp)
736						vrele(vp);
737					vp = nvp;
738					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
739					NFSVOPUNLOCK(vp, 0);
740					vpnes = nes;
741				}
742			} else
743				nd->nd_repstat = NFSERR_NOFILEHANDLE;
744			break;
745		case NFSV4OP_SAVEFH:
746			if (vp && NFSVNO_EXPORTED(&vpnes)) {
747				nd->nd_repstat = 0;
748				/* If vp == savevp, a no-op */
749				if (vp != savevp) {
750					if (savevp)
751						vrele(savevp);
752					VREF(vp);
753					savevp = vp;
754					savevpnes = vpnes;
755					save_fsid = cur_fsid;
756				}
757			} else {
758				nd->nd_repstat = NFSERR_NOFILEHANDLE;
759			}
760			break;
761		case NFSV4OP_RESTOREFH:
762			if (savevp) {
763				nd->nd_repstat = 0;
764				/* If vp == savevp, a no-op */
765				if (vp != savevp) {
766					VREF(savevp);
767					vrele(vp);
768					vp = savevp;
769					vpnes = savevpnes;
770					cur_fsid = save_fsid;
771				}
772			} else {
773				nd->nd_repstat = NFSERR_RESTOREFH;
774			}
775			break;
776		default:
777		    /*
778		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
779		     * non-exported directory if
780		     * nfs_rootfhset. Do I need to allow any other Ops?
781		     * (You can only have a non-exported vpnes if
782		     *  nfs_rootfhset is true. See nfsd_fhtovp())
783		     * Allow AUTH_SYS to be used for file systems
784		     * exported GSS only for certain Ops, to allow
785		     * clients to do mounts more easily.
786		     */
787		    if (nfsv4_opflag[op].needscfh && vp) {
788			if (!NFSVNO_EXPORTED(&vpnes) &&
789			    op != NFSV4OP_LOOKUP &&
790			    op != NFSV4OP_GETATTR &&
791			    op != NFSV4OP_GETFH &&
792			    op != NFSV4OP_ACCESS &&
793			    op != NFSV4OP_READLINK &&
794			    op != NFSV4OP_SECINFO)
795				nd->nd_repstat = NFSERR_NOFILEHANDLE;
796			else if (nfsvno_testexp(nd, &vpnes) &&
797			    op != NFSV4OP_LOOKUP &&
798			    op != NFSV4OP_GETFH &&
799			    op != NFSV4OP_GETATTR &&
800			    op != NFSV4OP_SECINFO)
801				nd->nd_repstat = NFSERR_WRONGSEC;
802			if (nd->nd_repstat) {
803				if (op == NFSV4OP_SETATTR) {
804				    /*
805				     * Setattr reply requires a bitmap
806				     * even for errors like these.
807				     */
808				    NFSM_BUILD(tl, u_int32_t *,
809					NFSX_UNSIGNED);
810				    *tl = 0;
811				}
812				break;
813			}
814		    }
815		    if (nfsv4_opflag[op].retfh == 1) {
816			if (!vp) {
817				nd->nd_repstat = NFSERR_NOFILEHANDLE;
818				break;
819			}
820			VREF(vp);
821			if (nfsv4_opflag[op].modifyfs)
822				vn_start_write(vp, &temp_mp, V_WAIT);
823			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
824			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
825			if (!error && !nd->nd_repstat) {
826			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
827				new_mp = nvp->v_mount;
828				if (cur_fsid.val[0] !=
829				    new_mp->mnt_stat.f_fsid.val[0] ||
830				    cur_fsid.val[1] !=
831				    new_mp->mnt_stat.f_fsid.val[1]) {
832				    /* crossed a server mount point */
833				    nd->nd_repstat = nfsvno_checkexp(new_mp,
834					nd->nd_nam, &nes, &credanon);
835				    if (!nd->nd_repstat)
836					nd->nd_repstat = nfsd_excred(nd,
837					    &nes, credanon);
838				    if (credanon != NULL)
839					crfree(credanon);
840				    if (!nd->nd_repstat) {
841					vpnes = nes;
842					cur_fsid = new_mp->mnt_stat.f_fsid;
843				    }
844				}
845				/* Lookup ops return a locked vnode */
846				NFSVOPUNLOCK(nvp, 0);
847			    }
848			    if (!nd->nd_repstat) {
849				    vrele(vp);
850				    vp = nvp;
851			    } else
852				    vrele(nvp);
853			}
854			if (nfsv4_opflag[op].modifyfs)
855				vn_finished_write(temp_mp);
856		    } else if (nfsv4_opflag[op].retfh == 2) {
857			if (vp == NULL || savevp == NULL) {
858				nd->nd_repstat = NFSERR_NOFILEHANDLE;
859				break;
860			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
861			    cur_fsid.val[1] != save_fsid.val[1]) {
862				nd->nd_repstat = NFSERR_XDEV;
863				break;
864			}
865			if (nfsv4_opflag[op].modifyfs)
866				vn_start_write(savevp, &temp_mp, V_WAIT);
867			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
868				VREF(vp);
869				VREF(savevp);
870				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
871				    savevp, vp, p, &savevpnes, &vpnes);
872			} else
873				nd->nd_repstat = NFSERR_PERM;
874			if (nfsv4_opflag[op].modifyfs)
875				vn_finished_write(temp_mp);
876		    } else {
877			if (nfsv4_opflag[op].retfh != 0)
878				panic("nfsrvd_compound");
879			if (nfsv4_opflag[op].needscfh) {
880				if (vp != NULL) {
881					if (nfsv4_opflag[op].modifyfs)
882						vn_start_write(vp, &temp_mp,
883						    V_WAIT);
884					if (NFSVOPLOCK(vp, nfsv4_opflag[op].lktype)
885					    == 0)
886						VREF(vp);
887					else
888						nd->nd_repstat = NFSERR_PERM;
889				} else {
890					nd->nd_repstat = NFSERR_NOFILEHANDLE;
891					if (op == NFSV4OP_SETATTR) {
892						/*
893						 * Setattr reply requires a
894						 * bitmap even for errors like
895						 * these.
896						 */
897						NFSM_BUILD(tl, u_int32_t *,
898						    NFSX_UNSIGNED);
899						*tl = 0;
900					}
901					break;
902				}
903				if (nd->nd_repstat == 0)
904					error = (*(nfsrv4_ops0[op]))(nd,
905					    isdgram, vp, p, &vpnes);
906				if (nfsv4_opflag[op].modifyfs)
907					vn_finished_write(temp_mp);
908			} else {
909				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
910				    NULL, p, &vpnes);
911			}
912		    }
913		};
914		if (error) {
915			if (error == EBADRPC || error == NFSERR_BADXDR) {
916				nd->nd_repstat = NFSERR_BADXDR;
917			} else {
918				nd->nd_repstat = error;
919				printf("nfsv4 comperr0=%d\n", error);
920			}
921			error = 0;
922		}
923		retops++;
924		if (nd->nd_repstat) {
925			*repp = nfsd_errmap(nd);
926			break;
927		} else {
928			*repp = 0;	/* NFS4_OK */
929		}
930	}
931nfsmout:
932	if (error) {
933		if (error == EBADRPC || error == NFSERR_BADXDR)
934			nd->nd_repstat = NFSERR_BADXDR;
935		else
936			printf("nfsv4 comperr1=%d\n", error);
937	}
938	if (taglen == -1) {
939		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
940		*tl++ = 0;
941		*tl = 0;
942	} else {
943		*retopsp = txdr_unsigned(retops);
944	}
945	if (vp)
946		vrele(vp);
947	if (savevp)
948		vrele(savevp);
949	NFSLOCKV4ROOTMUTEX();
950	nfsv4_relref(&nfsv4rootfs_lock);
951	NFSUNLOCKV4ROOTMUTEX();
952
953	NFSEXITCODE2(0, nd);
954}
955