nfs_nfsdsocket.c revision 299226
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 299226 2016-05-07 22:45:08Z 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		/*
775		 * For now, newnfsstats.srvrpccnt[] doesn't have entries
776		 * for the NFSv4.1 operations.
777		 */
778		if (nd->nd_procnum < NFSV4OP_NOPS)
779			NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
780		switch (op) {
781		case NFSV4OP_PUTFH:
782			error = nfsrv_mtofh(nd, &fh);
783			if (error)
784				goto nfsmout;
785			if (!nd->nd_repstat)
786				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
787				    NULL, 0, p);
788			/* For now, allow this for non-export FHs */
789			if (!nd->nd_repstat) {
790				if (vp)
791					vrele(vp);
792				vp = nvp;
793				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
794				NFSVOPUNLOCK(vp, 0);
795				vpnes = nes;
796			}
797			break;
798		case NFSV4OP_PUTPUBFH:
799			if (nfs_pubfhset)
800			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
801				&nes, NULL, 0, p);
802			else
803			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
804			if (!nd->nd_repstat) {
805				if (vp)
806					vrele(vp);
807				vp = nvp;
808				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
809				NFSVOPUNLOCK(vp, 0);
810				vpnes = nes;
811			}
812			break;
813		case NFSV4OP_PUTROOTFH:
814			if (nfs_rootfhset) {
815				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
816				    &nes, NULL, 0, p);
817				if (!nd->nd_repstat) {
818					if (vp)
819						vrele(vp);
820					vp = nvp;
821					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
822					NFSVOPUNLOCK(vp, 0);
823					vpnes = nes;
824				}
825			} else
826				nd->nd_repstat = NFSERR_NOFILEHANDLE;
827			break;
828		case NFSV4OP_SAVEFH:
829			if (vp && NFSVNO_EXPORTED(&vpnes)) {
830				nd->nd_repstat = 0;
831				/* If vp == savevp, a no-op */
832				if (vp != savevp) {
833					if (savevp)
834						vrele(savevp);
835					VREF(vp);
836					savevp = vp;
837					savevpnes = vpnes;
838					save_fsid = cur_fsid;
839				}
840			} else {
841				nd->nd_repstat = NFSERR_NOFILEHANDLE;
842			}
843			break;
844		case NFSV4OP_RESTOREFH:
845			if (savevp) {
846				nd->nd_repstat = 0;
847				/* If vp == savevp, a no-op */
848				if (vp != savevp) {
849					VREF(savevp);
850					vrele(vp);
851					vp = savevp;
852					vpnes = savevpnes;
853					cur_fsid = save_fsid;
854				}
855			} else {
856				nd->nd_repstat = NFSERR_RESTOREFH;
857			}
858			break;
859		default:
860		    /*
861		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
862		     * non-exported directory if
863		     * nfs_rootfhset. Do I need to allow any other Ops?
864		     * (You can only have a non-exported vpnes if
865		     *  nfs_rootfhset is true. See nfsd_fhtovp())
866		     * Allow AUTH_SYS to be used for file systems
867		     * exported GSS only for certain Ops, to allow
868		     * clients to do mounts more easily.
869		     */
870		    if (nfsv4_opflag[op].needscfh && vp) {
871			if (!NFSVNO_EXPORTED(&vpnes) &&
872			    op != NFSV4OP_LOOKUP &&
873			    op != NFSV4OP_GETATTR &&
874			    op != NFSV4OP_GETFH &&
875			    op != NFSV4OP_ACCESS &&
876			    op != NFSV4OP_READLINK &&
877			    op != NFSV4OP_SECINFO)
878				nd->nd_repstat = NFSERR_NOFILEHANDLE;
879			else if (nfsvno_testexp(nd, &vpnes) &&
880			    op != NFSV4OP_LOOKUP &&
881			    op != NFSV4OP_GETFH &&
882			    op != NFSV4OP_GETATTR &&
883			    op != NFSV4OP_SECINFO)
884				nd->nd_repstat = NFSERR_WRONGSEC;
885			if (nd->nd_repstat) {
886				if (op == NFSV4OP_SETATTR) {
887				    /*
888				     * Setattr reply requires a bitmap
889				     * even for errors like these.
890				     */
891				    NFSM_BUILD(tl, u_int32_t *,
892					NFSX_UNSIGNED);
893				    *tl = 0;
894				}
895				break;
896			}
897		    }
898		    if (nfsv4_opflag[op].retfh == 1) {
899			if (!vp) {
900				nd->nd_repstat = NFSERR_NOFILEHANDLE;
901				break;
902			}
903			VREF(vp);
904			if (nfsv4_opflag[op].modifyfs)
905				vn_start_write(vp, &temp_mp, V_WAIT);
906			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
907			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
908			if (!error && !nd->nd_repstat) {
909			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
910				new_mp = nvp->v_mount;
911				if (cur_fsid.val[0] !=
912				    new_mp->mnt_stat.f_fsid.val[0] ||
913				    cur_fsid.val[1] !=
914				    new_mp->mnt_stat.f_fsid.val[1]) {
915				    /* crossed a server mount point */
916				    nd->nd_repstat = nfsvno_checkexp(new_mp,
917					nd->nd_nam, &nes, &credanon);
918				    if (!nd->nd_repstat)
919					nd->nd_repstat = nfsd_excred(nd,
920					    &nes, credanon);
921				    if (credanon != NULL)
922					crfree(credanon);
923				    if (!nd->nd_repstat) {
924					vpnes = nes;
925					cur_fsid = new_mp->mnt_stat.f_fsid;
926				    }
927				}
928				/* Lookup ops return a locked vnode */
929				NFSVOPUNLOCK(nvp, 0);
930			    }
931			    if (!nd->nd_repstat) {
932				    vrele(vp);
933				    vp = nvp;
934			    } else
935				    vrele(nvp);
936			}
937			if (nfsv4_opflag[op].modifyfs)
938				vn_finished_write(temp_mp);
939		    } else if (nfsv4_opflag[op].retfh == 2) {
940			if (vp == NULL || savevp == NULL) {
941				nd->nd_repstat = NFSERR_NOFILEHANDLE;
942				break;
943			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
944			    cur_fsid.val[1] != save_fsid.val[1]) {
945				nd->nd_repstat = NFSERR_XDEV;
946				break;
947			}
948			if (nfsv4_opflag[op].modifyfs)
949				vn_start_write(savevp, &temp_mp, V_WAIT);
950			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
951				VREF(vp);
952				VREF(savevp);
953				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
954				    savevp, vp, p, &savevpnes, &vpnes);
955			} else
956				nd->nd_repstat = NFSERR_PERM;
957			if (nfsv4_opflag[op].modifyfs)
958				vn_finished_write(temp_mp);
959		    } else {
960			if (nfsv4_opflag[op].retfh != 0)
961				panic("nfsrvd_compound");
962			if (nfsv4_opflag[op].needscfh) {
963				if (vp != NULL) {
964					lktype = nfsv4_opflag[op].lktype;
965					if (nfsv4_opflag[op].modifyfs) {
966						vn_start_write(vp, &temp_mp,
967						    V_WAIT);
968						if (op == NFSV4OP_WRITE &&
969						    MNT_SHARED_WRITES(temp_mp))
970							lktype = LK_SHARED;
971					}
972					if (NFSVOPLOCK(vp, lktype) == 0)
973						VREF(vp);
974					else
975						nd->nd_repstat = NFSERR_PERM;
976				} else {
977					nd->nd_repstat = NFSERR_NOFILEHANDLE;
978					if (op == NFSV4OP_SETATTR) {
979						/*
980						 * Setattr reply requires a
981						 * bitmap even for errors like
982						 * these.
983						 */
984						NFSM_BUILD(tl, u_int32_t *,
985						    NFSX_UNSIGNED);
986						*tl = 0;
987					}
988					break;
989				}
990				if (nd->nd_repstat == 0)
991					error = (*(nfsrv4_ops0[op]))(nd,
992					    isdgram, vp, p, &vpnes);
993				if (nfsv4_opflag[op].modifyfs)
994					vn_finished_write(temp_mp);
995			} else {
996				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
997				    NULL, p, &vpnes);
998			}
999		    }
1000		}
1001		if (error) {
1002			if (error == EBADRPC || error == NFSERR_BADXDR) {
1003				nd->nd_repstat = NFSERR_BADXDR;
1004			} else {
1005				nd->nd_repstat = error;
1006				printf("nfsv4 comperr0=%d\n", error);
1007			}
1008			error = 0;
1009		}
1010		retops++;
1011		if (nd->nd_repstat) {
1012			*repp = nfsd_errmap(nd);
1013			break;
1014		} else {
1015			*repp = 0;	/* NFS4_OK */
1016		}
1017	}
1018nfsmout:
1019	if (error) {
1020		if (error == EBADRPC || error == NFSERR_BADXDR)
1021			nd->nd_repstat = NFSERR_BADXDR;
1022		else
1023			printf("nfsv4 comperr1=%d\n", error);
1024	}
1025	if (taglen == -1) {
1026		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1027		*tl++ = 0;
1028		*tl = 0;
1029	} else {
1030		*retopsp = txdr_unsigned(retops);
1031	}
1032	if (vp)
1033		vrele(vp);
1034	if (savevp)
1035		vrele(savevp);
1036	NFSLOCKV4ROOTMUTEX();
1037	nfsv4_relref(&nfsv4rootfs_lock);
1038	NFSUNLOCKV4ROOTMUTEX();
1039
1040	NFSEXITCODE2(0, nd);
1041}
1042