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