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