nfs_nfsdsocket.c revision 224080
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 224080 2011-07-16 08:05:26Z 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				return;
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				return;
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		return;
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}
473
474/*
475 * Breaks down a compound RPC request and calls the server routines for
476 * the subprocedures.
477 * Some suboperations are performed directly here to simplify file handle<-->
478 * vnode pointer handling.
479 */
480static void
481nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
482    NFSPROC_T *p)
483{
484	int i, op;
485	u_int32_t *tl;
486	struct nfsclient *clp, *nclp;
487	int numops, taglen = -1, error = 0, igotlock;
488	u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp;
489	u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
490	vnode_t vp, nvp, savevp;
491	struct nfsrvfh fh;
492	mount_t new_mp, temp_mp = NULL;
493	struct ucred *credanon;
494	struct nfsexstuff nes, vpnes, savevpnes;
495	fsid_t cur_fsid, save_fsid;
496	static u_int64_t compref = 0;
497
498	NFSVNO_EXINIT(&vpnes);
499	NFSVNO_EXINIT(&savevpnes);
500	/*
501	 * Put the seq# of the current compound RPC in nfsrv_descript.
502	 * (This is used by nfsrv_checkgetattr(), to see if the write
503	 *  delegation was created by the same compound RPC as the one
504	 *  with that Getattr in it.)
505	 * Don't worry about the 64bit number wrapping around. It ain't
506	 * gonna happen before this server gets shut down/rebooted.
507	 */
508	nd->nd_compref = compref++;
509
510	/*
511	 * Check for and optionally get a lock on the root. This lock means that
512	 * no nfsd will be fiddling with the V4 file system and state stuff. It
513	 * is required when the V4 root is being changed, the stable storage
514	 * restart file is being updated, or callbacks are being done.
515	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
516	 * either hold a reference count (nfs_usecnt) or the lock. When
517	 * nfsrv_unlock() is called to release the lock, it can optionally
518	 * also get a reference count, which saves the need for a call to
519	 * nfsrv_getref() after nfsrv_unlock().
520	 */
521	/*
522	 * First, check to see if we need to wait for an update lock.
523	 */
524	igotlock = 0;
525	NFSLOCKV4ROOTMUTEX();
526	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
527		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
528		    NFSV4ROOTLOCKMUTEXPTR, NULL);
529	else
530		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
531		    NFSV4ROOTLOCKMUTEXPTR, NULL);
532	NFSUNLOCKV4ROOTMUTEX();
533	if (igotlock) {
534		/*
535		 * If I got the lock, I can update the stable storage file.
536		 * Done when the grace period is over or a client has long
537		 * since expired.
538		 */
539		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
540		if ((nfsrv_stablefirst.nsf_flags &
541		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
542			nfsrv_updatestable(p);
543
544		/*
545		 * If at least one client has long since expired, search
546		 * the client list for them, write a REVOKE record on the
547		 * stable storage file and then remove them from the client
548		 * list.
549		 */
550		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
551			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
552			for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
553			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
554				nclp) {
555				if (clp->lc_flags & LCL_EXPIREIT) {
556				    if (!LIST_EMPTY(&clp->lc_open) ||
557					!LIST_EMPTY(&clp->lc_deleg))
558					nfsrv_writestable(clp->lc_id,
559					    clp->lc_idlen, NFSNST_REVOKE, p);
560				    nfsrv_cleanclient(clp, p);
561				    nfsrv_freedeleglist(&clp->lc_deleg);
562				    nfsrv_freedeleglist(&clp->lc_olddeleg);
563				    LIST_REMOVE(clp, lc_hash);
564				    nfsrv_zapclient(clp, p);
565				}
566			    }
567			}
568		}
569		NFSLOCKV4ROOTMUTEX();
570		nfsv4_unlock(&nfsv4rootfs_lock, 1);
571		NFSUNLOCKV4ROOTMUTEX();
572	} else {
573		/*
574		 * If we didn't get the lock, we need to get a refcnt,
575		 * which also checks for and waits for the lock.
576		 */
577		NFSLOCKV4ROOTMUTEX();
578		nfsv4_getref(&nfsv4rootfs_lock, NULL,
579		    NFSV4ROOTLOCKMUTEXPTR, NULL);
580		NFSUNLOCKV4ROOTMUTEX();
581	}
582
583	/*
584	 * If flagged, search for open owners that haven't had any opens
585	 * for a long time.
586	 */
587	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
588		nfsrv_throwawayopens(p);
589	}
590
591	savevp = vp = NULL;
592	save_fsid.val[0] = save_fsid.val[1] = 0;
593	cur_fsid.val[0] = cur_fsid.val[1] = 0;
594	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
595	taglen = fxdr_unsigned(int, *tl);
596	if (taglen < 0) {
597		error = EBADRPC;
598		goto nfsmout;
599	}
600	if (taglen <= NFSV4_SMALLSTR)
601		tagstr = tag;
602	else
603		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
604	error = nfsrv_mtostr(nd, tagstr, taglen);
605	if (error) {
606		if (taglen > NFSV4_SMALLSTR)
607			free(tagstr, M_TEMP);
608		taglen = -1;
609		goto nfsmout;
610	}
611	(void) nfsm_strtom(nd, tag, taglen);
612	if (taglen > NFSV4_SMALLSTR) {
613		free(tagstr, M_TEMP);
614	}
615	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
616	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
617	minorvers = fxdr_unsigned(u_int32_t, *tl++);
618	if (minorvers != NFSV4_MINORVERSION)
619		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
620	if (nd->nd_repstat)
621		numops = 0;
622	else
623		numops = fxdr_unsigned(int, *tl);
624	/*
625	 * Loop around doing the sub ops.
626	 * vp - is an unlocked vnode pointer for the CFH
627	 * savevp - is an unlocked vnode pointer for the SAVEDFH
628	 * (at some future date, it might turn out to be more appropriate
629	 *  to keep the file handles instead of vnode pointers?)
630	 * savevpnes and vpnes - are the export flags for the above.
631	 */
632	for (i = 0; i < numops; i++) {
633		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
634		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
635		*repp = *tl;
636		op = fxdr_unsigned(int, *tl);
637		if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
638			nd->nd_repstat = NFSERR_OPILLEGAL;
639			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
640			*repp = nfsd_errmap(nd);
641			retops++;
642			break;
643		} else {
644			repp++;
645		}
646
647		/*
648		 * Check for a referral on the current FH and, if so, return
649		 * NFSERR_MOVED for all ops that allow it, except Getattr.
650		 */
651		if (vp != NULL && op != NFSV4OP_GETATTR &&
652		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
653		    nfsrv_errmoved(op)) {
654			nd->nd_repstat = NFSERR_MOVED;
655			*repp = nfsd_errmap(nd);
656			retops++;
657			break;
658		}
659
660		nd->nd_procnum = op;
661		/*
662		 * If over flood level, reply NFSERR_RESOURCE, if at the first
663		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
664		 * really nasty for certain Op sequences, I'll play it safe
665		 * and only return the error at the beginning.) The cache
666		 * will still function over flood level, but uses lots of
667		 * mbufs.)
668		 * If nfsrv_mallocmget_limit() returns True, the system is near
669		 * to its limit for memory that malloc()/mget() can allocate.
670		 */
671		if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
672		    (nfsrv_mallocmget_limit() ||
673		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
674			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
675				printf("nfsd server cache flooded, try to");
676				printf(" increase nfsrc_floodlevel\n");
677			}
678			nd->nd_repstat = NFSERR_RESOURCE;
679			*repp = nfsd_errmap(nd);
680			if (op == NFSV4OP_SETATTR) {
681				/*
682				 * Setattr replies require a bitmap.
683				 * even for errors like these.
684				 */
685				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
686				*tl = 0;
687			}
688			retops++;
689			break;
690		}
691		if (nfsv4_opflag[op].savereply)
692			nd->nd_flag |= ND_SAVEREPLY;
693		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
694		switch (op) {
695		case NFSV4OP_PUTFH:
696			error = nfsrv_mtofh(nd, &fh);
697			if (error)
698				goto nfsmout;
699			if (!nd->nd_repstat)
700				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
701				    NULL, 0, p);
702			/* For now, allow this for non-export FHs */
703			if (!nd->nd_repstat) {
704				if (vp)
705					vrele(vp);
706				vp = nvp;
707				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
708				VOP_UNLOCK(vp, 0);
709				vpnes = nes;
710			}
711			break;
712		case NFSV4OP_PUTPUBFH:
713			if (nfs_pubfhset)
714			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
715				&nes, NULL, 0, p);
716			else
717			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
718			if (!nd->nd_repstat) {
719				if (vp)
720					vrele(vp);
721				vp = nvp;
722				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
723				VOP_UNLOCK(vp, 0);
724				vpnes = nes;
725			}
726			break;
727		case NFSV4OP_PUTROOTFH:
728			if (nfs_rootfhset) {
729				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
730				    &nes, NULL, 0, p);
731				if (!nd->nd_repstat) {
732					if (vp)
733						vrele(vp);
734					vp = nvp;
735					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
736					VOP_UNLOCK(vp, 0);
737					vpnes = nes;
738				}
739			} else
740				nd->nd_repstat = NFSERR_NOFILEHANDLE;
741			break;
742		case NFSV4OP_SAVEFH:
743			if (vp && NFSVNO_EXPORTED(&vpnes)) {
744				nd->nd_repstat = 0;
745				/* If vp == savevp, a no-op */
746				if (vp != savevp) {
747					if (savevp)
748						vrele(savevp);
749					VREF(vp);
750					savevp = vp;
751					savevpnes = vpnes;
752					save_fsid = cur_fsid;
753				}
754			} else {
755				nd->nd_repstat = NFSERR_NOFILEHANDLE;
756			}
757			break;
758		case NFSV4OP_RESTOREFH:
759			if (savevp) {
760				nd->nd_repstat = 0;
761				/* If vp == savevp, a no-op */
762				if (vp != savevp) {
763					VREF(savevp);
764					vrele(vp);
765					vp = savevp;
766					vpnes = savevpnes;
767					cur_fsid = save_fsid;
768				}
769			} else {
770				nd->nd_repstat = NFSERR_RESTOREFH;
771			}
772			break;
773		default:
774		    /*
775		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
776		     * non-exported directory if
777		     * nfs_rootfhset. Do I need to allow any other Ops?
778		     * (You can only have a non-exported vpnes if
779		     *  nfs_rootfhset is true. See nfsd_fhtovp())
780		     * Allow AUTH_SYS to be used for file systems
781		     * exported GSS only for certain Ops, to allow
782		     * clients to do mounts more easily.
783		     */
784		    if (nfsv4_opflag[op].needscfh && vp) {
785			if (!NFSVNO_EXPORTED(&vpnes) &&
786			    op != NFSV4OP_LOOKUP &&
787			    op != NFSV4OP_GETATTR &&
788			    op != NFSV4OP_GETFH &&
789			    op != NFSV4OP_ACCESS &&
790			    op != NFSV4OP_READLINK &&
791			    op != NFSV4OP_SECINFO)
792				nd->nd_repstat = NFSERR_NOFILEHANDLE;
793			else if (nfsvno_testexp(nd, &vpnes) &&
794			    op != NFSV4OP_LOOKUP &&
795			    op != NFSV4OP_GETFH &&
796			    op != NFSV4OP_GETATTR &&
797			    op != NFSV4OP_SECINFO)
798				nd->nd_repstat = NFSERR_WRONGSEC;
799			if (nd->nd_repstat) {
800				if (op == NFSV4OP_SETATTR) {
801				    /*
802				     * Setattr reply requires a bitmap
803				     * even for errors like these.
804				     */
805				    NFSM_BUILD(tl, u_int32_t *,
806					NFSX_UNSIGNED);
807				    *tl = 0;
808				}
809				break;
810			}
811		    }
812		    if (nfsv4_opflag[op].retfh == 1) {
813			if (!vp) {
814				nd->nd_repstat = NFSERR_NOFILEHANDLE;
815				break;
816			}
817			VREF(vp);
818			if (nfsv4_opflag[op].modifyfs)
819				vn_start_write(vp, &temp_mp, V_WAIT);
820			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
821			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
822			if (!error && !nd->nd_repstat) {
823			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
824				new_mp = nvp->v_mount;
825				if (cur_fsid.val[0] !=
826				    new_mp->mnt_stat.f_fsid.val[0] ||
827				    cur_fsid.val[1] !=
828				    new_mp->mnt_stat.f_fsid.val[1]) {
829				    /* crossed a server mount point */
830				    nd->nd_repstat = nfsvno_checkexp(new_mp,
831					nd->nd_nam, &nes, &credanon);
832				    if (!nd->nd_repstat)
833					nd->nd_repstat = nfsd_excred(nd,
834					    &nes, credanon);
835				    if (credanon != NULL)
836					crfree(credanon);
837				    if (!nd->nd_repstat) {
838					vpnes = nes;
839					cur_fsid = new_mp->mnt_stat.f_fsid;
840				    }
841				}
842				/* Lookup ops return a locked vnode */
843				VOP_UNLOCK(nvp, 0);
844			    }
845			    if (!nd->nd_repstat) {
846				    vrele(vp);
847				    vp = nvp;
848			    } else
849				    vrele(nvp);
850			}
851			if (nfsv4_opflag[op].modifyfs)
852				vn_finished_write(temp_mp);
853		    } else if (nfsv4_opflag[op].retfh == 2) {
854			if (vp == NULL || savevp == NULL) {
855				nd->nd_repstat = NFSERR_NOFILEHANDLE;
856				break;
857			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
858			    cur_fsid.val[1] != save_fsid.val[1]) {
859				nd->nd_repstat = NFSERR_XDEV;
860				break;
861			}
862			if (nfsv4_opflag[op].modifyfs)
863				vn_start_write(savevp, &temp_mp, V_WAIT);
864			if (vn_lock(savevp, LK_EXCLUSIVE) == 0) {
865				VREF(vp);
866				VREF(savevp);
867				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
868				    savevp, vp, p, &savevpnes, &vpnes);
869			} else
870				nd->nd_repstat = NFSERR_PERM;
871			if (nfsv4_opflag[op].modifyfs)
872				vn_finished_write(temp_mp);
873		    } else {
874			if (nfsv4_opflag[op].retfh != 0)
875				panic("nfsrvd_compound");
876			if (nfsv4_opflag[op].needscfh) {
877				if (vp != NULL) {
878					if (nfsv4_opflag[op].modifyfs)
879						vn_start_write(vp, &temp_mp,
880						    V_WAIT);
881					if (vn_lock(vp, nfsv4_opflag[op].lktype)
882					    == 0)
883						VREF(vp);
884					else
885						nd->nd_repstat = NFSERR_PERM;
886				} else {
887					nd->nd_repstat = NFSERR_NOFILEHANDLE;
888					if (op == NFSV4OP_SETATTR) {
889						/*
890						 * Setattr reply requires a
891						 * bitmap even for errors like
892						 * these.
893						 */
894						NFSM_BUILD(tl, u_int32_t *,
895						    NFSX_UNSIGNED);
896						*tl = 0;
897					}
898					break;
899				}
900				if (nd->nd_repstat == 0)
901					error = (*(nfsrv4_ops0[op]))(nd,
902					    isdgram, vp, p, &vpnes);
903				if (nfsv4_opflag[op].modifyfs)
904					vn_finished_write(temp_mp);
905			} else {
906				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
907				    NULL, p, &vpnes);
908			}
909		    }
910		};
911		if (error) {
912			if (error == EBADRPC || error == NFSERR_BADXDR) {
913				nd->nd_repstat = NFSERR_BADXDR;
914			} else {
915				nd->nd_repstat = error;
916				printf("nfsv4 comperr0=%d\n", error);
917			}
918			error = 0;
919		}
920		retops++;
921		if (nd->nd_repstat) {
922			*repp = nfsd_errmap(nd);
923			break;
924		} else {
925			*repp = 0;	/* NFS4_OK */
926		}
927	}
928nfsmout:
929	if (error) {
930		if (error == EBADRPC || error == NFSERR_BADXDR)
931			nd->nd_repstat = NFSERR_BADXDR;
932		else
933			printf("nfsv4 comperr1=%d\n", error);
934	}
935	if (taglen == -1) {
936		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
937		*tl++ = 0;
938		*tl = 0;
939	} else {
940		*retopsp = txdr_unsigned(retops);
941	}
942	if (vp)
943		vrele(vp);
944	if (savevp)
945		vrele(savevp);
946	NFSLOCKV4ROOTMUTEX();
947	nfsv4_relref(&nfsv4rootfs_lock);
948	NFSUNLOCKV4ROOTMUTEX();
949}
950