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