nfs_nfsdsocket.c revision 336842
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/11/sys/fs/nfsserver/nfs_nfsdsocket.c 336842 2018-07-28 20:29:05Z 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 nfsstatsv1 nfsstatsv1;
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;
50extern int nfsrv_clienthashsize;
51extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
52extern int nfsd_debuglevel;
53NFSV4ROOTLOCKMUTEX;
54NFSSTATESPINLOCK;
55
56int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
57    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
58	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
59	nfsrvd_getattr,
60	nfsrvd_setattr,
61	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
62	nfsrvd_access,
63	nfsrvd_readlink,
64	nfsrvd_read,
65	nfsrvd_write,
66	nfsrvd_create,
67	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
68	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
69	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
70	nfsrvd_remove,
71	nfsrvd_remove,
72	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
73	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
74	nfsrvd_readdir,
75	nfsrvd_readdirplus,
76	nfsrvd_statfs,
77	nfsrvd_fsinfo,
78	nfsrvd_pathconf,
79	nfsrvd_commit,
80};
81
82int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
83    int, vnode_t , vnode_t *, fhandle_t *,
84    NFSPROC_T *, struct nfsexstuff *) = {
85	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
86	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
87	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
88	nfsrvd_lookup,
89	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
90	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
91	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
92	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
93	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
94	nfsrvd_mkdir,
95	nfsrvd_symlink,
96	nfsrvd_mknod,
97	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
98	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
99	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
100	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
101	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
102	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
103	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
104	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
105	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
106	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
107};
108
109int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
110    int, vnode_t , vnode_t , NFSPROC_T *,
111    struct nfsexstuff *, struct nfsexstuff *) = {
112	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
113	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
114	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
115	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
116	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
117	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
118	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
119	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
120	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
121	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
122	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
123	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
124	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
125	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
126	nfsrvd_rename,
127	nfsrvd_link,
128	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
129	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
130	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
131	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
132	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
133	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
134};
135
136int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *,
137    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
138	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
139	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
140	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
141	nfsrvd_access,
142	nfsrvd_close,
143	nfsrvd_commit,
144	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
145	nfsrvd_delegpurge,
146	nfsrvd_delegreturn,
147	nfsrvd_getattr,
148	nfsrvd_getfh,
149	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
150	nfsrvd_lock,
151	nfsrvd_lockt,
152	nfsrvd_locku,
153	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
154	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
155	nfsrvd_verify,
156	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
157	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
158	nfsrvd_openconfirm,
159	nfsrvd_opendowngrade,
160	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
161	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
162	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
163	nfsrvd_read,
164	nfsrvd_readdirplus,
165	nfsrvd_readlink,
166	nfsrvd_remove,
167	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
168	nfsrvd_renew,
169	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
170	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
171	nfsrvd_secinfo,
172	nfsrvd_setattr,
173	nfsrvd_setclientid,
174	nfsrvd_setclientidcfrm,
175	nfsrvd_verify,
176	nfsrvd_write,
177	nfsrvd_releaselckown,
178	nfsrvd_notsupp,
179	nfsrvd_bindconnsess,
180	nfsrvd_exchangeid,
181	nfsrvd_createsession,
182	nfsrvd_destroysession,
183	nfsrvd_freestateid,
184	nfsrvd_notsupp,
185	nfsrvd_notsupp,
186	nfsrvd_notsupp,
187	nfsrvd_notsupp,
188	nfsrvd_notsupp,
189	nfsrvd_notsupp,
190	nfsrvd_notsupp,
191	nfsrvd_sequence,
192	nfsrvd_notsupp,
193	nfsrvd_teststateid,
194	nfsrvd_notsupp,
195	nfsrvd_destroyclientid,
196	nfsrvd_reclaimcomplete,
197};
198
199int (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
200    int, vnode_t , vnode_t *, fhandle_t *,
201    NFSPROC_T *, struct nfsexstuff *) = {
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	nfsrvd_mknod,
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	nfsrvd_lookup,
218	nfsrvd_lookup,
219	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
220	nfsrvd_open,
221	nfsrvd_openattr,
222	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
223	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
224	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
225	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
226	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
227	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
228	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
229	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
230	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
231	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
232	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
233	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
234	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
235	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
236	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
237	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
238	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
239	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
240	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
241	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
242	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
243	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
244	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
245	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
246	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
247	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
248	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
249	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
250	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
251	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
252	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
253	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
254	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
255	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
256	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
257	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
258	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
259	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
260	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
261};
262
263int (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
264    int, vnode_t , vnode_t , NFSPROC_T *,
265    struct nfsexstuff *, struct nfsexstuff *) = {
266	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
267	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
268	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
269	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
270	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
271	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
272	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
273	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
274	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
275	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
276	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
277	nfsrvd_link,
278	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
279	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
280	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
281	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
282	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
283	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
284	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
285	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
286	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
287	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
288	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
289	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
290	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
291	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
292	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
293	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
294	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
295	nfsrvd_rename,
296	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
297	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
298	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
299	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
300	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
301	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
302	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
303	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
304	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
305	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
306	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
307	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
308	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
309	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
310	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
311	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
312	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
313	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
314	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
315	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
316	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
317	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
318	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
319	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
320	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
321	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
322	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
323	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
324	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
325};
326#endif	/* !APPLEKEXT */
327
328/*
329 * Static array that defines which nfs rpc's are nonidempotent
330 */
331static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
332	FALSE,
333	FALSE,
334	TRUE,
335	FALSE,
336	FALSE,
337	FALSE,
338	FALSE,
339	TRUE,
340	TRUE,
341	TRUE,
342	TRUE,
343	TRUE,
344	TRUE,
345	TRUE,
346	TRUE,
347	TRUE,
348	FALSE,
349	FALSE,
350	FALSE,
351	FALSE,
352	FALSE,
353	FALSE,
354};
355
356/*
357 * This static array indicates whether or not the RPC modifies the
358 * file system.
359 */
360static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
361    1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
362    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
363
364/* local functions */
365static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
366    u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p);
367
368
369/*
370 * This static array indicates which server procedures require the extra
371 * arguments to return the current file handle for V2, 3.
372 */
373static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
374	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
375
376extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
377
378static int nfsv3to4op[NFS_V3NPROCS] = {
379	NFSPROC_NULL,
380	NFSV4OP_GETATTR,
381	NFSV4OP_SETATTR,
382	NFSV4OP_LOOKUP,
383	NFSV4OP_ACCESS,
384	NFSV4OP_READLINK,
385	NFSV4OP_READ,
386	NFSV4OP_WRITE,
387	NFSV4OP_V3CREATE,
388	NFSV4OP_MKDIR,
389	NFSV4OP_SYMLINK,
390	NFSV4OP_MKNOD,
391	NFSV4OP_REMOVE,
392	NFSV4OP_RMDIR,
393	NFSV4OP_RENAME,
394	NFSV4OP_LINK,
395	NFSV4OP_READDIR,
396	NFSV4OP_READDIRPLUS,
397	NFSV4OP_FSSTAT,
398	NFSV4OP_FSINFO,
399	NFSV4OP_PATHCONF,
400	NFSV4OP_COMMIT,
401};
402
403static struct mtx nfsrvd_statmtx;
404MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
405
406static void
407nfsrvd_statstart(int op, struct bintime *now)
408{
409	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
410		printf("%s: op %d invalid\n", __func__, op);
411		return;
412	}
413
414	mtx_lock(&nfsrvd_statmtx);
415	if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
416		if (now != NULL)
417			nfsstatsv1.busyfrom = *now;
418		else
419			binuptime(&nfsstatsv1.busyfrom);
420
421	}
422	nfsstatsv1.srvrpccnt[op]++;
423	nfsstatsv1.srvstartcnt++;
424	mtx_unlock(&nfsrvd_statmtx);
425
426}
427
428static void
429nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
430    struct bintime *then)
431{
432	struct bintime dt, lnow;
433
434	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
435		printf("%s: op %d invalid\n", __func__, op);
436		return;
437	}
438
439	if (now == NULL) {
440		now = &lnow;
441		binuptime(now);
442	}
443
444	mtx_lock(&nfsrvd_statmtx);
445
446	nfsstatsv1.srvbytes[op] += bytes;
447	nfsstatsv1.srvops[op]++;
448
449	if (then != NULL) {
450		dt = *now;
451		bintime_sub(&dt, then);
452		bintime_add(&nfsstatsv1.srvduration[op], &dt);
453	}
454
455	dt = *now;
456	bintime_sub(&dt, &nfsstatsv1.busyfrom);
457	bintime_add(&nfsstatsv1.busytime, &dt);
458	nfsstatsv1.busyfrom = *now;
459
460	nfsstatsv1.srvdonecnt++;
461
462	mtx_unlock(&nfsrvd_statmtx);
463}
464
465/*
466 * Do an RPC. Basically, get the file handles translated to vnode pointers
467 * and then call the appropriate server routine. The server routines are
468 * split into groups, based on whether they use a file handle or file
469 * handle plus name or ...
470 * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
471 */
472APPLESTATIC void
473nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
474    u_int32_t minorvers, NFSPROC_T *p)
475{
476	int error = 0, lktype;
477	vnode_t vp;
478	mount_t mp = NULL;
479	struct nfsrvfh fh;
480	struct nfsexstuff nes;
481
482	/*
483	 * Get a locked vnode for the first file handle
484	 */
485	if (!(nd->nd_flag & ND_NFSV4)) {
486		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
487		/*
488		 * For NFSv3, if the malloc/mget allocation is near limits,
489		 * return NFSERR_DELAY.
490		 */
491		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
492			nd->nd_repstat = NFSERR_DELAY;
493			vp = NULL;
494		} else {
495			error = nfsrv_mtofh(nd, &fh);
496			if (error) {
497				if (error != EBADRPC)
498					printf("nfs dorpc err1=%d\n", error);
499				nd->nd_repstat = NFSERR_GARBAGE;
500				goto out;
501			}
502			if (nd->nd_procnum == NFSPROC_READ ||
503			    nd->nd_procnum == NFSPROC_WRITE ||
504			    nd->nd_procnum == NFSPROC_READDIR ||
505			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
506			    nd->nd_procnum == NFSPROC_READLINK ||
507			    nd->nd_procnum == NFSPROC_GETATTR ||
508			    nd->nd_procnum == NFSPROC_ACCESS ||
509			    nd->nd_procnum == NFSPROC_FSSTAT ||
510			    nd->nd_procnum == NFSPROC_FSINFO)
511				lktype = LK_SHARED;
512			else
513				lktype = LK_EXCLUSIVE;
514			if (nd->nd_flag & ND_PUBLOOKUP)
515				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
516				    &mp, nfs_writerpc[nd->nd_procnum], p);
517			else
518				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
519				    &mp, nfs_writerpc[nd->nd_procnum], p);
520			if (nd->nd_repstat == NFSERR_PROGNOTV4)
521				goto out;
522		}
523	}
524
525	/*
526	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
527	 * cache, as required.
528	 * For V4, nfsrvd_compound() does this.
529	 */
530	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
531		nd->nd_flag |= ND_SAVEREPLY;
532
533	nfsrvd_rephead(nd);
534	/*
535	 * If nd_repstat is non-zero, just fill in the reply status
536	 * to complete the RPC reply for V2. Otherwise, you must do
537	 * the RPC.
538	 */
539	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
540		*nd->nd_errp = nfsd_errmap(nd);
541		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
542		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
543		   /*now*/ NULL, /*then*/ NULL);
544		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
545			vn_finished_write(mp);
546		goto out;
547	}
548
549	/*
550	 * Now the procedure can be performed. For V4, nfsrvd_compound()
551	 * works through the sub-rpcs, otherwise just call the procedure.
552	 * The procedures are in three groups with different arguments.
553	 * The group is indicated by the value in nfs_retfh[].
554	 */
555	if (nd->nd_flag & ND_NFSV4) {
556		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
557	} else {
558		struct bintime start_time;
559
560		binuptime(&start_time);
561		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
562
563		if (nfs_retfh[nd->nd_procnum] == 1) {
564			if (vp)
565				NFSVOPUNLOCK(vp, 0);
566			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
567			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
568		} else if (nfs_retfh[nd->nd_procnum] == 2) {
569			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
570			    vp, NULL, p, &nes, NULL);
571		} else {
572			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
573			    vp, p, &nes);
574		}
575		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
576			vn_finished_write(mp);
577
578		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
579		    /*now*/ NULL, /*then*/ &start_time);
580	}
581	if (error) {
582		if (error != EBADRPC)
583			printf("nfs dorpc err2=%d\n", error);
584		nd->nd_repstat = NFSERR_GARBAGE;
585	}
586	*nd->nd_errp = nfsd_errmap(nd);
587
588	/*
589	 * Don't cache certain reply status values.
590	 */
591	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
592	    (nd->nd_repstat == NFSERR_GARBAGE ||
593	     nd->nd_repstat == NFSERR_BADXDR ||
594	     nd->nd_repstat == NFSERR_MOVED ||
595	     nd->nd_repstat == NFSERR_DELAY ||
596	     nd->nd_repstat == NFSERR_BADSEQID ||
597	     nd->nd_repstat == NFSERR_RESOURCE ||
598	     nd->nd_repstat == NFSERR_SERVERFAULT ||
599	     nd->nd_repstat == NFSERR_STALECLIENTID ||
600	     nd->nd_repstat == NFSERR_STALESTATEID ||
601	     nd->nd_repstat == NFSERR_OLDSTATEID ||
602	     nd->nd_repstat == NFSERR_BADSTATEID ||
603	     nd->nd_repstat == NFSERR_GRACE ||
604	     nd->nd_repstat == NFSERR_NOGRACE))
605		nd->nd_flag &= ~ND_SAVEREPLY;
606
607out:
608	NFSEXITCODE2(0, nd);
609}
610
611/*
612 * Breaks down a compound RPC request and calls the server routines for
613 * the subprocedures.
614 * Some suboperations are performed directly here to simplify file handle<-->
615 * vnode pointer handling.
616 */
617static void
618nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
619    int taglen, u_int32_t minorvers, NFSPROC_T *p)
620{
621	int i, lktype, op, op0 = 0, statsinprog = 0;
622	u_int32_t *tl;
623	struct nfsclient *clp, *nclp;
624	int numops, error = 0, igotlock;
625	u_int32_t retops = 0, *retopsp = NULL, *repp;
626	vnode_t vp, nvp, savevp;
627	struct nfsrvfh fh;
628	mount_t new_mp, temp_mp = NULL;
629	struct ucred *credanon;
630	struct nfsexstuff nes, vpnes, savevpnes;
631	fsid_t cur_fsid, save_fsid;
632	static u_int64_t compref = 0;
633	struct bintime start_time;
634
635	NFSVNO_EXINIT(&vpnes);
636	NFSVNO_EXINIT(&savevpnes);
637	/*
638	 * Put the seq# of the current compound RPC in nfsrv_descript.
639	 * (This is used by nfsrv_checkgetattr(), to see if the write
640	 *  delegation was created by the same compound RPC as the one
641	 *  with that Getattr in it.)
642	 * Don't worry about the 64bit number wrapping around. It ain't
643	 * gonna happen before this server gets shut down/rebooted.
644	 */
645	nd->nd_compref = compref++;
646
647	/*
648	 * Check for and optionally get a lock on the root. This lock means that
649	 * no nfsd will be fiddling with the V4 file system and state stuff. It
650	 * is required when the V4 root is being changed, the stable storage
651	 * restart file is being updated, or callbacks are being done.
652	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
653	 * either hold a reference count (nfs_usecnt) or the lock. When
654	 * nfsrv_unlock() is called to release the lock, it can optionally
655	 * also get a reference count, which saves the need for a call to
656	 * nfsrv_getref() after nfsrv_unlock().
657	 */
658	/*
659	 * First, check to see if we need to wait for an update lock.
660	 */
661	igotlock = 0;
662	NFSLOCKV4ROOTMUTEX();
663	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
664		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
665		    NFSV4ROOTLOCKMUTEXPTR, NULL);
666	else
667		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
668		    NFSV4ROOTLOCKMUTEXPTR, NULL);
669	NFSUNLOCKV4ROOTMUTEX();
670	if (igotlock) {
671		/*
672		 * If I got the lock, I can update the stable storage file.
673		 * Done when the grace period is over or a client has long
674		 * since expired.
675		 */
676		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
677		if ((nfsrv_stablefirst.nsf_flags &
678		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
679			nfsrv_updatestable(p);
680
681		/*
682		 * If at least one client has long since expired, search
683		 * the client list for them, write a REVOKE record on the
684		 * stable storage file and then remove them from the client
685		 * list.
686		 */
687		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
688			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
689			for (i = 0; i < nfsrv_clienthashsize; i++) {
690			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
691				nclp) {
692				if (clp->lc_flags & LCL_EXPIREIT) {
693				    if (!LIST_EMPTY(&clp->lc_open) ||
694					!LIST_EMPTY(&clp->lc_deleg))
695					nfsrv_writestable(clp->lc_id,
696					    clp->lc_idlen, NFSNST_REVOKE, p);
697				    nfsrv_cleanclient(clp, p);
698				    nfsrv_freedeleglist(&clp->lc_deleg);
699				    nfsrv_freedeleglist(&clp->lc_olddeleg);
700				    LIST_REMOVE(clp, lc_hash);
701				    nfsrv_zapclient(clp, p);
702				}
703			    }
704			}
705		}
706		NFSLOCKV4ROOTMUTEX();
707		nfsv4_unlock(&nfsv4rootfs_lock, 1);
708		NFSUNLOCKV4ROOTMUTEX();
709	} else {
710		/*
711		 * If we didn't get the lock, we need to get a refcnt,
712		 * which also checks for and waits for the lock.
713		 */
714		NFSLOCKV4ROOTMUTEX();
715		nfsv4_getref(&nfsv4rootfs_lock, NULL,
716		    NFSV4ROOTLOCKMUTEXPTR, NULL);
717		NFSUNLOCKV4ROOTMUTEX();
718	}
719
720	/*
721	 * If flagged, search for open owners that haven't had any opens
722	 * for a long time.
723	 */
724	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
725		nfsrv_throwawayopens(p);
726	}
727
728	savevp = vp = NULL;
729	save_fsid.val[0] = save_fsid.val[1] = 0;
730	cur_fsid.val[0] = cur_fsid.val[1] = 0;
731
732	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
733	if (taglen < 0) {
734		error = EBADRPC;
735		goto nfsmout;
736	}
737
738	(void) nfsm_strtom(nd, tag, taglen);
739	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
740	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
741	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
742		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
743	if (nd->nd_repstat)
744		numops = 0;
745	else
746		numops = fxdr_unsigned(int, *tl);
747	/*
748	 * Loop around doing the sub ops.
749	 * vp - is an unlocked vnode pointer for the CFH
750	 * savevp - is an unlocked vnode pointer for the SAVEDFH
751	 * (at some future date, it might turn out to be more appropriate
752	 *  to keep the file handles instead of vnode pointers?)
753	 * savevpnes and vpnes - are the export flags for the above.
754	 */
755	for (i = 0; i < numops; i++) {
756		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
757		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
758		*repp = *tl;
759		op = fxdr_unsigned(int, *tl);
760		NFSD_DEBUG(4, "op=%d\n", op);
761
762		binuptime(&start_time);
763		nfsrvd_statstart(op, &start_time);
764		statsinprog = 1;
765
766		if (op < NFSV4OP_ACCESS ||
767		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
768		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
769			nd->nd_repstat = NFSERR_OPILLEGAL;
770			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
771			*repp = nfsd_errmap(nd);
772			retops++;
773			break;
774		} else {
775			repp++;
776		}
777		if (i == 0)
778			op0 = op;
779		if (i == numops - 1)
780			nd->nd_flag |= ND_LASTOP;
781
782		/*
783		 * Check for a referral on the current FH and, if so, return
784		 * NFSERR_MOVED for all ops that allow it, except Getattr.
785		 */
786		if (vp != NULL && op != NFSV4OP_GETATTR &&
787		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
788		    nfsrv_errmoved(op)) {
789			nd->nd_repstat = NFSERR_MOVED;
790			*repp = nfsd_errmap(nd);
791			retops++;
792			break;
793		}
794
795		/*
796		 * For NFSv4.1, check for a Sequence Operation being first
797		 * or one of the other allowed operations by itself.
798		 */
799		if ((nd->nd_flag & ND_NFSV41) != 0) {
800			if (i != 0 && op == NFSV4OP_SEQUENCE)
801				nd->nd_repstat = NFSERR_SEQUENCEPOS;
802			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
803			    op != NFSV4OP_EXCHANGEID &&
804			    op != NFSV4OP_CREATESESSION &&
805			    op != NFSV4OP_BINDCONNTOSESS &&
806			    op != NFSV4OP_DESTROYCLIENTID &&
807			    op != NFSV4OP_DESTROYSESSION)
808				nd->nd_repstat = NFSERR_OPNOTINSESS;
809			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
810				nd->nd_repstat = NFSERR_NOTONLYOP;
811			if (nd->nd_repstat != 0) {
812				*repp = nfsd_errmap(nd);
813				retops++;
814				break;
815			}
816		}
817
818		nd->nd_procnum = op;
819		/*
820		 * If over flood level, reply NFSERR_RESOURCE, if at the first
821		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
822		 * really nasty for certain Op sequences, I'll play it safe
823		 * and only return the error at the beginning.) The cache
824		 * will still function over flood level, but uses lots of
825		 * mbufs.)
826		 * If nfsrv_mallocmget_limit() returns True, the system is near
827		 * to its limit for memory that malloc()/mget() can allocate.
828		 */
829		if (i == 0 && (nd->nd_rp == NULL ||
830		    nd->nd_rp->rc_refcnt == 0) &&
831		    (nfsrv_mallocmget_limit() ||
832		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
833			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
834				printf("nfsd server cache flooded, try "
835				    "increasing vfs.nfsd.tcphighwater\n");
836			nd->nd_repstat = NFSERR_RESOURCE;
837			*repp = nfsd_errmap(nd);
838			if (op == NFSV4OP_SETATTR) {
839				/*
840				 * Setattr replies require a bitmap.
841				 * even for errors like these.
842				 */
843				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
844				*tl = 0;
845			}
846			retops++;
847			break;
848		}
849		if (nfsv4_opflag[op].savereply)
850			nd->nd_flag |= ND_SAVEREPLY;
851		switch (op) {
852		case NFSV4OP_PUTFH:
853			error = nfsrv_mtofh(nd, &fh);
854			if (error)
855				goto nfsmout;
856			if (!nd->nd_repstat)
857				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
858				    NULL, 0, p);
859			/* For now, allow this for non-export FHs */
860			if (!nd->nd_repstat) {
861				if (vp)
862					vrele(vp);
863				vp = nvp;
864				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
865				NFSVOPUNLOCK(vp, 0);
866				vpnes = nes;
867			}
868			break;
869		case NFSV4OP_PUTPUBFH:
870			if (nfs_pubfhset)
871			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
872				&nes, NULL, 0, p);
873			else
874			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
875			if (!nd->nd_repstat) {
876				if (vp)
877					vrele(vp);
878				vp = nvp;
879				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
880				NFSVOPUNLOCK(vp, 0);
881				vpnes = nes;
882			}
883			break;
884		case NFSV4OP_PUTROOTFH:
885			if (nfs_rootfhset) {
886				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
887				    &nes, NULL, 0, p);
888				if (!nd->nd_repstat) {
889					if (vp)
890						vrele(vp);
891					vp = nvp;
892					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
893					NFSVOPUNLOCK(vp, 0);
894					vpnes = nes;
895				}
896			} else
897				nd->nd_repstat = NFSERR_NOFILEHANDLE;
898			break;
899		case NFSV4OP_SAVEFH:
900			if (vp && NFSVNO_EXPORTED(&vpnes)) {
901				nd->nd_repstat = 0;
902				/* If vp == savevp, a no-op */
903				if (vp != savevp) {
904					if (savevp)
905						vrele(savevp);
906					VREF(vp);
907					savevp = vp;
908					savevpnes = vpnes;
909					save_fsid = cur_fsid;
910				}
911			} else {
912				nd->nd_repstat = NFSERR_NOFILEHANDLE;
913			}
914			break;
915		case NFSV4OP_RESTOREFH:
916			if (savevp) {
917				nd->nd_repstat = 0;
918				/* If vp == savevp, a no-op */
919				if (vp != savevp) {
920					VREF(savevp);
921					vrele(vp);
922					vp = savevp;
923					vpnes = savevpnes;
924					cur_fsid = save_fsid;
925				}
926			} else {
927				nd->nd_repstat = NFSERR_RESTOREFH;
928			}
929			break;
930		default:
931		    /*
932		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
933		     * non-exported directory if
934		     * nfs_rootfhset. Do I need to allow any other Ops?
935		     * (You can only have a non-exported vpnes if
936		     *  nfs_rootfhset is true. See nfsd_fhtovp())
937		     * Allow AUTH_SYS to be used for file systems
938		     * exported GSS only for certain Ops, to allow
939		     * clients to do mounts more easily.
940		     */
941		    if (nfsv4_opflag[op].needscfh && vp) {
942			if (!NFSVNO_EXPORTED(&vpnes) &&
943			    op != NFSV4OP_LOOKUP &&
944			    op != NFSV4OP_GETATTR &&
945			    op != NFSV4OP_GETFH &&
946			    op != NFSV4OP_ACCESS &&
947			    op != NFSV4OP_READLINK &&
948			    op != NFSV4OP_SECINFO)
949				nd->nd_repstat = NFSERR_NOFILEHANDLE;
950			else if (nfsvno_testexp(nd, &vpnes) &&
951			    op != NFSV4OP_LOOKUP &&
952			    op != NFSV4OP_GETFH &&
953			    op != NFSV4OP_GETATTR &&
954			    op != NFSV4OP_SECINFO)
955				nd->nd_repstat = NFSERR_WRONGSEC;
956			if (nd->nd_repstat) {
957				if (op == NFSV4OP_SETATTR) {
958				    /*
959				     * Setattr reply requires a bitmap
960				     * even for errors like these.
961				     */
962				    NFSM_BUILD(tl, u_int32_t *,
963					NFSX_UNSIGNED);
964				    *tl = 0;
965				}
966				break;
967			}
968		    }
969		    if (nfsv4_opflag[op].retfh == 1) {
970			if (!vp) {
971				nd->nd_repstat = NFSERR_NOFILEHANDLE;
972				break;
973			}
974			VREF(vp);
975			if (nfsv4_opflag[op].modifyfs)
976				vn_start_write(vp, &temp_mp, V_WAIT);
977			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
978			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
979			if (!error && !nd->nd_repstat) {
980			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
981				new_mp = nvp->v_mount;
982				if (cur_fsid.val[0] !=
983				    new_mp->mnt_stat.f_fsid.val[0] ||
984				    cur_fsid.val[1] !=
985				    new_mp->mnt_stat.f_fsid.val[1]) {
986				    /* crossed a server mount point */
987				    nd->nd_repstat = nfsvno_checkexp(new_mp,
988					nd->nd_nam, &nes, &credanon);
989				    if (!nd->nd_repstat)
990					nd->nd_repstat = nfsd_excred(nd,
991					    &nes, credanon);
992				    if (credanon != NULL)
993					crfree(credanon);
994				    if (!nd->nd_repstat) {
995					vpnes = nes;
996					cur_fsid = new_mp->mnt_stat.f_fsid;
997				    }
998				}
999				/* Lookup ops return a locked vnode */
1000				NFSVOPUNLOCK(nvp, 0);
1001			    }
1002			    if (!nd->nd_repstat) {
1003				    vrele(vp);
1004				    vp = nvp;
1005			    } else
1006				    vrele(nvp);
1007			}
1008			if (nfsv4_opflag[op].modifyfs)
1009				vn_finished_write(temp_mp);
1010		    } else if (nfsv4_opflag[op].retfh == 2) {
1011			if (vp == NULL || savevp == NULL) {
1012				nd->nd_repstat = NFSERR_NOFILEHANDLE;
1013				break;
1014			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
1015			    cur_fsid.val[1] != save_fsid.val[1]) {
1016				nd->nd_repstat = NFSERR_XDEV;
1017				break;
1018			}
1019			if (nfsv4_opflag[op].modifyfs)
1020				vn_start_write(savevp, &temp_mp, V_WAIT);
1021			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1022				VREF(vp);
1023				VREF(savevp);
1024				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1025				    savevp, vp, p, &savevpnes, &vpnes);
1026			} else
1027				nd->nd_repstat = NFSERR_PERM;
1028			if (nfsv4_opflag[op].modifyfs)
1029				vn_finished_write(temp_mp);
1030		    } else {
1031			if (nfsv4_opflag[op].retfh != 0)
1032				panic("nfsrvd_compound");
1033			if (nfsv4_opflag[op].needscfh) {
1034				if (vp != NULL) {
1035					lktype = nfsv4_opflag[op].lktype;
1036					if (nfsv4_opflag[op].modifyfs) {
1037						vn_start_write(vp, &temp_mp,
1038						    V_WAIT);
1039						if (op == NFSV4OP_WRITE &&
1040						    MNT_SHARED_WRITES(temp_mp))
1041							lktype = LK_SHARED;
1042					}
1043					if (NFSVOPLOCK(vp, lktype) == 0)
1044						VREF(vp);
1045					else
1046						nd->nd_repstat = NFSERR_PERM;
1047				} else {
1048					nd->nd_repstat = NFSERR_NOFILEHANDLE;
1049					if (op == NFSV4OP_SETATTR) {
1050						/*
1051						 * Setattr reply requires a
1052						 * bitmap even for errors like
1053						 * these.
1054						 */
1055						NFSM_BUILD(tl, u_int32_t *,
1056						    NFSX_UNSIGNED);
1057						*tl = 0;
1058					}
1059					break;
1060				}
1061				if (nd->nd_repstat == 0)
1062					error = (*(nfsrv4_ops0[op]))(nd,
1063					    isdgram, vp, p, &vpnes);
1064				if (nfsv4_opflag[op].modifyfs)
1065					vn_finished_write(temp_mp);
1066			} else {
1067				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1068				    NULL, p, &vpnes);
1069			}
1070		    }
1071		}
1072		if (error) {
1073			if (error == EBADRPC || error == NFSERR_BADXDR) {
1074				nd->nd_repstat = NFSERR_BADXDR;
1075			} else {
1076				nd->nd_repstat = error;
1077				printf("nfsv4 comperr0=%d\n", error);
1078			}
1079			error = 0;
1080		}
1081
1082		if (statsinprog != 0) {
1083			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1084			    /*then*/ &start_time);
1085			statsinprog = 0;
1086		}
1087
1088		retops++;
1089		if (nd->nd_repstat) {
1090			*repp = nfsd_errmap(nd);
1091			break;
1092		} else {
1093			*repp = 0;	/* NFS4_OK */
1094		}
1095	}
1096nfsmout:
1097	if (statsinprog != 0) {
1098		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1099		    /*then*/ &start_time);
1100		statsinprog = 0;
1101	}
1102	if (error) {
1103		if (error == EBADRPC || error == NFSERR_BADXDR)
1104			nd->nd_repstat = NFSERR_BADXDR;
1105		else
1106			printf("nfsv4 comperr1=%d\n", error);
1107	}
1108	if (taglen == -1) {
1109		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1110		*tl++ = 0;
1111		*tl = 0;
1112	} else {
1113		*retopsp = txdr_unsigned(retops);
1114	}
1115	if (vp)
1116		vrele(vp);
1117	if (savevp)
1118		vrele(savevp);
1119	NFSLOCKV4ROOTMUTEX();
1120	nfsv4_relref(&nfsv4rootfs_lock);
1121	NFSUNLOCKV4ROOTMUTEX();
1122
1123	NFSEXITCODE2(0, nd);
1124}
1125