]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsserver/nfs_nfsdsocket.c
zfs: merge openzfs/zfs@57cfae4a2 (master)
[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 #include <fs/nfs/nfsport.h>
44
45 extern struct nfsrvfh nfs_pubfh;
46 extern int nfs_pubfhset;
47 extern struct nfsv4lock nfsv4rootfs_lock;
48 extern int nfsrv_clienthashsize;
49 extern int nfsd_debuglevel;
50 extern int nfsrv_layouthighwater;
51 extern volatile int nfsrv_layoutcnt;
52 NFSV4ROOTLOCKMUTEX;
53 NFSSTATESPINLOCK;
54
55 NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst);
56 NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash);
57 NFSD_VNET_DECLARE(int, nfsrc_floodlevel);
58 NFSD_VNET_DECLARE(int, nfsrc_tcpsavedreplies);
59 NFSD_VNET_DECLARE(struct nfsrvfh, nfs_rootfh);
60 NFSD_VNET_DECLARE(int, nfs_rootfhset);
61 NFSD_VNET_DECLARE(struct nfsstatsv1 *, nfsstatsv1_p);
62
63 int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
64     int, vnode_t , struct nfsexstuff *) = {
65         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
66         nfsrvd_getattr,
67         nfsrvd_setattr,
68         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
69         nfsrvd_access,
70         nfsrvd_readlink,
71         nfsrvd_read,
72         nfsrvd_write,
73         nfsrvd_create,
74         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
75         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
76         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
77         nfsrvd_remove,
78         nfsrvd_remove,
79         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
80         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
81         nfsrvd_readdir,
82         nfsrvd_readdirplus,
83         nfsrvd_statfs,
84         nfsrvd_fsinfo,
85         nfsrvd_pathconf,
86         nfsrvd_commit,
87 };
88
89 int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
90     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
91         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
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         nfsrvd_lookup,
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         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
98         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
99         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
100         nfsrvd_mkdir,
101         nfsrvd_symlink,
102         nfsrvd_mknod,
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         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
111         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
112         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
113 };
114
115 int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
116     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
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         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
129         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
130         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
131         nfsrvd_rename,
132         nfsrvd_link,
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         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
137         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
138         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
139 };
140
141 int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *,
142     int, vnode_t , struct nfsexstuff *) = {
143         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
144         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
145         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
146         nfsrvd_access,
147         nfsrvd_close,
148         nfsrvd_commit,
149         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
150         nfsrvd_delegpurge,
151         nfsrvd_delegreturn,
152         nfsrvd_getattr,
153         nfsrvd_getfh,
154         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
155         nfsrvd_lock,
156         nfsrvd_lockt,
157         nfsrvd_locku,
158         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
159         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
160         nfsrvd_verify,
161         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
162         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
163         nfsrvd_openconfirm,
164         nfsrvd_opendowngrade,
165         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
166         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
167         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
168         nfsrvd_read,
169         nfsrvd_readdirplus,
170         nfsrvd_readlink,
171         nfsrvd_remove,
172         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
173         nfsrvd_renew,
174         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
175         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
176         nfsrvd_secinfo,
177         nfsrvd_setattr,
178         nfsrvd_setclientid,
179         nfsrvd_setclientidcfrm,
180         nfsrvd_verify,
181         nfsrvd_write,
182         nfsrvd_releaselckown,
183         nfsrvd_notsupp,
184         nfsrvd_bindconnsess,
185         nfsrvd_exchangeid,
186         nfsrvd_createsession,
187         nfsrvd_destroysession,
188         nfsrvd_freestateid,
189         nfsrvd_notsupp,
190         nfsrvd_getdevinfo,
191         nfsrvd_notsupp,
192         nfsrvd_layoutcommit,
193         nfsrvd_layoutget,
194         nfsrvd_layoutreturn,
195         nfsrvd_secinfononame,
196         nfsrvd_sequence,
197         nfsrvd_notsupp,
198         nfsrvd_teststateid,
199         nfsrvd_notsupp,
200         nfsrvd_destroyclientid,
201         nfsrvd_reclaimcomplete,
202         nfsrvd_allocate,
203         (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
204         nfsrvd_notsupp,
205         nfsrvd_deallocate,
206         nfsrvd_ioadvise,
207         nfsrvd_layouterror,
208         nfsrvd_layoutstats,
209         nfsrvd_notsupp,
210         nfsrvd_notsupp,
211         nfsrvd_notsupp,
212         nfsrvd_seek,
213         nfsrvd_notsupp,
214         nfsrvd_notsupp,
215         nfsrvd_getxattr,
216         nfsrvd_setxattr,
217         nfsrvd_listxattr,
218         nfsrvd_rmxattr,
219 };
220
221 int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *,
222     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
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         nfsrvd_mknod,
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         nfsrvd_lookup,
239         nfsrvd_lookup,
240         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
241         nfsrvd_open,
242         nfsrvd_openattr,
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         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
263         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
264         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
265         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
266         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
267         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
268         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
269         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
270         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
271         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
272         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
273         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
274         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
275         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
276         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
277         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
278         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
279         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
280         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
281         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
282         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
283         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
284         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
285         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
286         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
287         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
288         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
289         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
290         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
291         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
292         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
293         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
294         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
295         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
296         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
297         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
298         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
299 };
300
301 int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *,
302     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
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         nfsrvd_link,
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         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
326         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
327         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
328         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
329         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
330         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
331         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
332         nfsrvd_rename,
333         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
334         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
335         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
336         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
337         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
338         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
339         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
340         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
341         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
342         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
343         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
344         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
345         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
346         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
347         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
348         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
349         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
350         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
351         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
352         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
353         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
354         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
355         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
356         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
357         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
358         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
359         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
360         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
361         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
362         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
363         nfsrvd_copy_file_range,
364         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
365         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
366         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
367         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
368         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
369         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
370         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
371         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
372         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
373         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
374         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
375         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
376         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
377         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
378         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
379 };
380
381 /*
382  * Static array that defines which nfs rpc's are nonidempotent
383  */
384 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
385         FALSE,
386         FALSE,
387         TRUE,
388         FALSE,
389         FALSE,
390         FALSE,
391         FALSE,
392         TRUE,
393         TRUE,
394         TRUE,
395         TRUE,
396         TRUE,
397         TRUE,
398         TRUE,
399         TRUE,
400         TRUE,
401         FALSE,
402         FALSE,
403         FALSE,
404         FALSE,
405         FALSE,
406         FALSE,
407 };
408
409 /*
410  * This static array indicates whether or not the RPC modifies the
411  * file system.
412  */
413 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
414     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
415     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
416
417 SYSCTL_DECL(_vfs_nfsd);
418 static int      nfs_minminorv4 = NFSV4_MINORVERSION;
419 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN,
420     &nfs_minminorv4, 0,
421     "The lowest minor version of NFSv4 handled by the server");
422
423 static int      nfs_maxminorv4 = NFSV42_MINORVERSION;
424 SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN,
425     &nfs_maxminorv4, 0,
426     "The highest minor version of NFSv4 handled by the server");
427
428 /* local functions */
429 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
430     u_char *tag, int taglen, u_int32_t minorvers);
431
432 /*
433  * This static array indicates which server procedures require the extra
434  * arguments to return the current file handle for V2, 3.
435  */
436 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
437         1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
438
439 extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];
440
441 static int nfsv3to4op[NFS_V3NPROCS] = {
442         NFSPROC_NULL,
443         NFSV4OP_GETATTR,
444         NFSV4OP_SETATTR,
445         NFSV4OP_LOOKUP,
446         NFSV4OP_ACCESS,
447         NFSV4OP_READLINK,
448         NFSV4OP_READ,
449         NFSV4OP_WRITE,
450         NFSV4OP_V3CREATE,
451         NFSV4OP_MKDIR,
452         NFSV4OP_SYMLINK,
453         NFSV4OP_MKNOD,
454         NFSV4OP_REMOVE,
455         NFSV4OP_RMDIR,
456         NFSV4OP_RENAME,
457         NFSV4OP_LINK,
458         NFSV4OP_READDIR,
459         NFSV4OP_READDIRPLUS,
460         NFSV4OP_FSSTAT,
461         NFSV4OP_FSINFO,
462         NFSV4OP_PATHCONF,
463         NFSV4OP_COMMIT,
464 };
465
466 static struct mtx nfsrvd_statmtx;
467 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
468
469 static void
470 nfsrvd_statstart(int op, struct bintime *now)
471 {
472         if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
473                 printf("%s: op %d invalid\n", __func__, op);
474                 return;
475         }
476
477         mtx_lock(&nfsrvd_statmtx);
478         if (NFSD_VNET(nfsstatsv1_p)->srvstartcnt ==
479             NFSD_VNET(nfsstatsv1_p)->srvdonecnt) {
480                 if (now != NULL)
481                         NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;
482                 else
483                         binuptime(&NFSD_VNET(nfsstatsv1_p)->busyfrom);
484                 
485         }
486         NFSD_VNET(nfsstatsv1_p)->srvrpccnt[op]++;
487         NFSD_VNET(nfsstatsv1_p)->srvstartcnt++;
488         mtx_unlock(&nfsrvd_statmtx);
489
490 }
491
492 static void
493 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
494     struct bintime *then)
495 {
496         struct bintime dt, lnow;
497
498         if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
499                 printf("%s: op %d invalid\n", __func__, op);
500                 return;
501         }
502
503         if (now == NULL) {
504                 now = &lnow;
505                 binuptime(now);
506         }
507
508         mtx_lock(&nfsrvd_statmtx);
509
510         NFSD_VNET(nfsstatsv1_p)->srvbytes[op] += bytes;
511         NFSD_VNET(nfsstatsv1_p)->srvops[op]++;
512
513         if (then != NULL) {
514                 dt = *now;
515                 bintime_sub(&dt, then);
516                 bintime_add(&NFSD_VNET(nfsstatsv1_p)->srvduration[op], &dt);
517         }
518
519         dt = *now;
520         bintime_sub(&dt, &NFSD_VNET(nfsstatsv1_p)->busyfrom);
521         bintime_add(&NFSD_VNET(nfsstatsv1_p)->busytime, &dt);
522         NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;
523
524         NFSD_VNET(nfsstatsv1_p)->srvdonecnt++;
525
526         mtx_unlock(&nfsrvd_statmtx);
527 }
528
529 /*
530  * Do an RPC. Basically, get the file handles translated to vnode pointers
531  * and then call the appropriate server routine. The server routines are
532  * split into groups, based on whether they use a file handle or file
533  * handle plus name or ...
534  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
535  */
536 void
537 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
538     u_int32_t minorvers)
539 {
540         int error = 0, lktype;
541         vnode_t vp;
542         mount_t mp;
543         struct nfsrvfh fh;
544         struct nfsexstuff nes;
545         struct mbuf *md;
546         char *dpos;
547
548         /*
549          * Save the current position in the request mbuf list so
550          * that a rollback to this location can be done upon an
551          * ERELOOKUP error return from an RPC function.
552          */
553         md = nd->nd_md;
554         dpos = nd->nd_dpos;
555 tryagain:
556         mp = NULL;
557
558         /*
559          * Get a locked vnode for the first file handle
560          */
561         if (!(nd->nd_flag & ND_NFSV4)) {
562                 KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
563                 /*
564                  * For NFSv3, if the malloc/mget allocation is near limits,
565                  * return NFSERR_DELAY.
566                  */
567                 if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
568                         nd->nd_repstat = NFSERR_DELAY;
569                         vp = NULL;
570                 } else {
571                         error = nfsrv_mtofh(nd, &fh);
572                         if (error) {
573                                 if (error != EBADRPC)
574                                         printf("nfs dorpc err1=%d\n", error);
575                                 nd->nd_repstat = NFSERR_GARBAGE;
576                                 goto out;
577                         }
578                         if (nd->nd_procnum == NFSPROC_READ ||
579                             nd->nd_procnum == NFSPROC_WRITE ||
580                             nd->nd_procnum == NFSPROC_READDIR ||
581                             nd->nd_procnum == NFSPROC_READDIRPLUS ||
582                             nd->nd_procnum == NFSPROC_READLINK ||
583                             nd->nd_procnum == NFSPROC_GETATTR ||
584                             nd->nd_procnum == NFSPROC_ACCESS ||
585                             nd->nd_procnum == NFSPROC_FSSTAT ||
586                             nd->nd_procnum == NFSPROC_FSINFO)
587                                 lktype = LK_SHARED;
588                         else
589                                 lktype = LK_EXCLUSIVE;
590                         if (nd->nd_flag & ND_PUBLOOKUP)
591                                 nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
592                                     &mp, nfsrv_writerpc[nd->nd_procnum], -1);
593                         else
594                                 nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
595                                     &mp, nfsrv_writerpc[nd->nd_procnum], -1);
596                         if (nd->nd_repstat == NFSERR_PROGNOTV4)
597                                 goto out;
598                 }
599         }
600
601         /*
602          * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
603          * cache, as required.
604          * For V4, nfsrvd_compound() does this.
605          */
606         if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
607                 nd->nd_flag |= ND_SAVEREPLY;
608
609         nfsrvd_rephead(nd);
610         /*
611          * If nd_repstat is non-zero, just fill in the reply status
612          * to complete the RPC reply for V2. Otherwise, you must do
613          * the RPC.
614          */
615         if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
616                 *nd->nd_errp = nfsd_errmap(nd);
617                 nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
618                 nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
619                    /*now*/ NULL, /*then*/ NULL);
620                 vn_finished_write(mp);
621                 goto out;
622         }
623
624         /*
625          * Now the procedure can be performed. For V4, nfsrvd_compound()
626          * works through the sub-rpcs, otherwise just call the procedure.
627          * The procedures are in three groups with different arguments.
628          * The group is indicated by the value in nfs_retfh[].
629          */
630         if (nd->nd_flag & ND_NFSV4) {
631                 nfsrvd_compound(nd, isdgram, tag, taglen, minorvers);
632         } else {
633                 struct bintime start_time;
634
635                 binuptime(&start_time);
636                 nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
637
638                 if (nfs_retfh[nd->nd_procnum] == 1) {
639                         if (vp)
640                                 NFSVOPUNLOCK(vp);
641                         error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
642                             vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes);
643                 } else if (nfs_retfh[nd->nd_procnum] == 2) {
644                         error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
645                             vp, NULL, &nes, NULL);
646                 } else {
647                         error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
648                             vp, &nes);
649                 }
650                 vn_finished_write(mp);
651
652                 if (error == 0 && nd->nd_repstat == ERELOOKUP) {
653                         /*
654                          * Roll back to the beginning of the RPC request
655                          * arguments.
656                          */
657                         nd->nd_md = md;
658                         nd->nd_dpos = dpos;
659
660                         /* Free the junk RPC reply and redo the RPC. */
661                         m_freem(nd->nd_mreq);
662                         nd->nd_mreq = nd->nd_mb = NULL;
663                         nd->nd_repstat = 0;
664                         goto tryagain;
665                 }
666
667                 nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
668                     /*now*/ NULL, /*then*/ &start_time);
669         }
670         if (error) {
671                 if (error != EBADRPC)
672                         printf("nfs dorpc err2=%d\n", error);
673                 nd->nd_repstat = NFSERR_GARBAGE;
674         }
675         *nd->nd_errp = nfsd_errmap(nd);
676
677         /*
678          * Don't cache certain reply status values.
679          */
680         if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
681             (nd->nd_repstat == NFSERR_GARBAGE ||
682              nd->nd_repstat == NFSERR_BADXDR ||
683              nd->nd_repstat == NFSERR_MOVED ||
684              nd->nd_repstat == NFSERR_DELAY ||
685              nd->nd_repstat == NFSERR_BADSEQID ||
686              nd->nd_repstat == NFSERR_RESOURCE ||
687              nd->nd_repstat == NFSERR_SERVERFAULT ||
688              nd->nd_repstat == NFSERR_STALECLIENTID ||
689              nd->nd_repstat == NFSERR_STALESTATEID ||
690              nd->nd_repstat == NFSERR_OLDSTATEID ||
691              nd->nd_repstat == NFSERR_BADSTATEID ||
692              nd->nd_repstat == NFSERR_GRACE ||
693              nd->nd_repstat == NFSERR_NOGRACE))
694                 nd->nd_flag &= ~ND_SAVEREPLY;
695
696 out:
697         NFSEXITCODE2(0, nd);
698 }
699
700 /*
701  * Breaks down a compound RPC request and calls the server routines for
702  * the subprocedures.
703  * Some suboperations are performed directly here to simplify file handle<-->
704  * vnode pointer handling.
705  */
706 static void
707 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
708     int taglen, u_int32_t minorvers)
709 {
710         int i, lktype, op, op0 = 0, rstat, statsinprog = 0;
711         u_int32_t *tl;
712         struct nfsclient *clp, *nclp;
713         int error = 0, igotlock, nextop, numops, savefhcnt;
714         u_int32_t retops = 0, *retopsp = NULL, *repp;
715         vnode_t vp, nvp, savevp;
716         struct nfsrvfh fh;
717         mount_t new_mp, temp_mp = NULL;
718         struct ucred *credanon;
719         struct nfsexstuff nes, vpnes, savevpnes;
720         fsid_t cur_fsid, save_fsid;
721         static u_int64_t compref = 0;
722         struct bintime start_time;
723         struct thread *p;
724         struct mbuf *mb, *md;
725         char *bpos, *dpos;
726         int bextpg, bextpgsiz;
727
728         p = curthread;
729
730         /* Check for and optionally clear the no space flags for DSs. */
731         nfsrv_checknospc();
732
733         NFSVNO_EXINIT(&vpnes);
734         NFSVNO_EXINIT(&savevpnes);
735         /*
736          * Put the seq# of the current compound RPC in nfsrv_descript.
737          * (This is used by nfsrv_checkgetattr(), to see if the write
738          *  delegation was created by the same compound RPC as the one
739          *  with that Getattr in it.)
740          * Don't worry about the 64bit number wrapping around. It ain't
741          * gonna happen before this server gets shut down/rebooted.
742          */
743         nd->nd_compref = compref++;
744
745         /*
746          * Check for and optionally get a lock on the root. This lock means that
747          * no nfsd will be fiddling with the V4 file system and state stuff. It
748          * is required when the V4 root is being changed, the stable storage
749          * restart file is being updated, or callbacks are being done.
750          * When any of the nfsd are processing an NFSv4 compound RPC, they must
751          * either hold a reference count (nfs_usecnt) or the lock. When
752          * nfsrv_unlock() is called to release the lock, it can optionally
753          * also get a reference count, which saves the need for a call to
754          * nfsrv_getref() after nfsrv_unlock().
755          */
756         /*
757          * First, check to see if we need to wait for an update lock.
758          */
759         igotlock = 0;
760         NFSLOCKV4ROOTMUTEX();
761         if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NEEDLOCK)
762                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
763                     NFSV4ROOTLOCKMUTEXPTR, NULL);
764         else
765                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
766                     NFSV4ROOTLOCKMUTEXPTR, NULL);
767         NFSUNLOCKV4ROOTMUTEX();
768         if (igotlock) {
769                 /*
770                  * If I got the lock, I can update the stable storage file.
771                  * Done when the grace period is over or a client has long
772                  * since expired.
773                  */
774                 NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_NEEDLOCK;
775                 if ((NFSD_VNET(nfsrv_stablefirst).nsf_flags &
776                     (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
777                         nfsrv_updatestable(p);
778
779                 /*
780                  * If at least one client has long since expired, search
781                  * the client list for them, write a REVOKE record on the
782                  * stable storage file and then remove them from the client
783                  * list.
784                  */
785                 if (NFSD_VNET(nfsrv_stablefirst).nsf_flags &
786                     NFSNSF_EXPIREDCLIENT) {
787                         NFSD_VNET(nfsrv_stablefirst).nsf_flags &=
788                             ~NFSNSF_EXPIREDCLIENT;
789                         for (i = 0; i < nfsrv_clienthashsize; i++) {
790                             LIST_FOREACH_SAFE(clp, &NFSD_VNET(nfsclienthash)[i],
791                                 lc_hash, nclp) {
792                                 if (clp->lc_flags & LCL_EXPIREIT) {
793                                     if (!LIST_EMPTY(&clp->lc_open) ||
794                                         !LIST_EMPTY(&clp->lc_deleg))
795                                         nfsrv_writestable(clp->lc_id,
796                                             clp->lc_idlen, NFSNST_REVOKE, p);
797                                     nfsrv_cleanclient(clp, p);
798                                     nfsrv_freedeleglist(&clp->lc_deleg);
799                                     nfsrv_freedeleglist(&clp->lc_olddeleg);
800                                     LIST_REMOVE(clp, lc_hash);
801                                     nfsrv_zapclient(clp, p);
802                                 }
803                             }
804                         }
805                 }
806                 NFSLOCKV4ROOTMUTEX();
807                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
808                 NFSUNLOCKV4ROOTMUTEX();
809         } else {
810                 /*
811                  * If we didn't get the lock, we need to get a refcnt,
812                  * which also checks for and waits for the lock.
813                  */
814                 NFSLOCKV4ROOTMUTEX();
815                 nfsv4_getref(&nfsv4rootfs_lock, NULL,
816                     NFSV4ROOTLOCKMUTEXPTR, NULL);
817                 NFSUNLOCKV4ROOTMUTEX();
818         }
819
820         /*
821          * If flagged, search for open owners that haven't had any opens
822          * for a long time.
823          */
824         if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NOOPENS) {
825                 nfsrv_throwawayopens(p);
826         }
827
828         /* Do a CBLAYOUTRECALL callback if over the high water mark. */
829         if (nfsrv_layoutcnt > nfsrv_layouthighwater)
830                 nfsrv_recalloldlayout(p);
831
832         savevp = vp = NULL;
833         save_fsid.val[0] = save_fsid.val[1] = 0;
834         cur_fsid.val[0] = cur_fsid.val[1] = 0;
835         nextop = -1;
836         savefhcnt = 0;
837
838         /* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
839         if (taglen < 0) {
840                 error = EBADRPC;
841                 goto nfsmout;
842         }
843
844         (void) nfsm_strtom(nd, tag, taglen);
845         NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
846         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
847         if ((minorvers != NFSV4_MINORVERSION &&
848             minorvers != NFSV41_MINORVERSION &&
849             minorvers != NFSV42_MINORVERSION) ||
850             minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)
851                 nd->nd_repstat = NFSERR_MINORVERMISMATCH;
852         if (nd->nd_repstat)
853                 numops = 0;
854         else
855                 numops = fxdr_unsigned(int, *tl);
856         /*
857          * Loop around doing the sub ops.
858          * vp - is an unlocked vnode pointer for the CFH
859          * savevp - is an unlocked vnode pointer for the SAVEDFH
860          * (at some future date, it might turn out to be more appropriate
861          *  to keep the file handles instead of vnode pointers?)
862          * savevpnes and vpnes - are the export flags for the above.
863          */
864         for (i = 0; i < numops; i++) {
865                 NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
866                 if (savefhcnt > 0) {
867                         op = NFSV4OP_SAVEFH;
868                         *repp = txdr_unsigned(op);
869                         savefhcnt--;
870                 } else if (nextop == -1) {
871                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
872                         *repp = *tl;
873                         op = fxdr_unsigned(int, *tl);
874                 } else {
875                         op = nextop;
876                         *repp = txdr_unsigned(op);
877                         nextop = -1;
878                 }
879                 NFSD_DEBUG(4, "op=%d\n", op);
880                 if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
881                     (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
882                     (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {
883                         nd->nd_repstat = NFSERR_OPILLEGAL;
884                         *repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
885                         *repp = nfsd_errmap(nd);
886                         retops++;
887                         break;
888                 } else {
889                         repp++;
890                 }
891
892                 binuptime(&start_time);
893                 nfsrvd_statstart(op, &start_time);
894                 statsinprog = 1;
895
896                 if (i == 0)
897                         op0 = op;
898                 if (i == numops - 1)
899                         nd->nd_flag |= ND_LASTOP;
900
901                 /*
902                  * Check for a referral on the current FH and, if so, return
903                  * NFSERR_MOVED for all ops that allow it, except Getattr.
904                  */
905                 if (vp != NULL && op != NFSV4OP_GETATTR &&
906                     nfsv4root_getreferral(vp, NULL, 0) != NULL &&
907                     nfsrv_errmoved(op)) {
908                         nd->nd_repstat = NFSERR_MOVED;
909                         *repp = nfsd_errmap(nd);
910                         retops++;
911                         break;
912                 }
913
914                 /*
915                  * For NFSv4.1, check for a Sequence Operation being first
916                  * or one of the other allowed operations by itself.
917                  */
918                 if ((nd->nd_flag & ND_NFSV41) != 0) {
919                         if (i != 0 && op == NFSV4OP_SEQUENCE)
920                                 nd->nd_repstat = NFSERR_SEQUENCEPOS;
921                         else if (i == 0 && op != NFSV4OP_SEQUENCE &&
922                             op != NFSV4OP_EXCHANGEID &&
923                             op != NFSV4OP_CREATESESSION &&
924                             op != NFSV4OP_BINDCONNTOSESS &&
925                             op != NFSV4OP_DESTROYCLIENTID &&
926                             op != NFSV4OP_DESTROYSESSION)
927                                 nd->nd_repstat = NFSERR_OPNOTINSESS;
928                         else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
929                                 nd->nd_repstat = NFSERR_NOTONLYOP;
930                         if (nd->nd_repstat != 0) {
931                                 *repp = nfsd_errmap(nd);
932                                 retops++;
933                                 break;
934                         }
935                 }
936
937                 nd->nd_procnum = op;
938                 /*
939                  * If over flood level, reply NFSERR_RESOURCE, if at the first
940                  * Op. (Since a client recovery from NFSERR_RESOURCE can get
941                  * really nasty for certain Op sequences, I'll play it safe
942                  * and only return the error at the beginning.) The cache
943                  * will still function over flood level, but uses lots of
944                  * mbufs.)
945                  * If nfsrv_mallocmget_limit() returns True, the system is near
946                  * to its limit for memory that malloc()/mget() can allocate.
947                  */
948                 if (i == 0 && (nd->nd_rp == NULL ||
949                     nd->nd_rp->rc_refcnt == 0) &&
950                     (nfsrv_mallocmget_limit() ||
951                      NFSD_VNET(nfsrc_tcpsavedreplies) >
952                      NFSD_VNET(nfsrc_floodlevel))) {
953                         if (NFSD_VNET(nfsrc_tcpsavedreplies) >
954                             NFSD_VNET(nfsrc_floodlevel))
955                                 printf("nfsd server cache flooded, try "
956                                     "increasing vfs.nfsd.tcphighwater\n");
957                         nd->nd_repstat = NFSERR_RESOURCE;
958                         *repp = nfsd_errmap(nd);
959                         if (op == NFSV4OP_SETATTR) {
960                                 /*
961                                  * Setattr replies require a bitmap.
962                                  * even for errors like these.
963                                  */
964                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
965                                 *tl = 0;
966                         }
967                         retops++;
968                         break;
969                 }
970                 if (nfsv4_opflag[op].savereply)
971                         nd->nd_flag |= ND_SAVEREPLY;
972                 switch (op) {
973                 case NFSV4OP_PUTFH:
974                         error = nfsrv_mtofh(nd, &fh);
975                         if (error)
976                                 goto nfsmout;
977                         if ((nd->nd_flag & ND_LASTOP) == 0) {
978                                 /*
979                                  * Pre-parse the next op#.  If it is
980                                  * SaveFH, count it and skip to the
981                                  * next op#, if not the last op#.
982                                  * nextop is used to determine if
983                                  * NFSERR_WRONGSEC can be returned,
984                                  * per RFC5661 Sec. 2.6.
985                                  */
986                                 do {
987                                         NFSM_DISSECT(tl, uint32_t *,
988                                             NFSX_UNSIGNED);
989                                         nextop = fxdr_unsigned(int, *tl);
990                                         if (nextop == NFSV4OP_SAVEFH &&
991                                             i < numops - 1)
992                                                 savefhcnt++;
993                                 } while (nextop == NFSV4OP_SAVEFH &&
994                                     i < numops - 1);
995                         }
996                         if (!nd->nd_repstat)
997                                 nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
998                                     NULL, 0, nextop);
999                         /* For now, allow this for non-export FHs */
1000                         if (!nd->nd_repstat) {
1001                                 if (vp)
1002                                         vrele(vp);
1003                                 vp = nvp;
1004                                 cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1005                                 NFSVOPUNLOCK(vp);
1006                                 vpnes = nes;
1007                         }
1008                         break;
1009                 case NFSV4OP_PUTPUBFH:
1010                         if (nfs_pubfhset) {
1011                                 if ((nd->nd_flag & ND_LASTOP) == 0) {
1012                                         /*
1013                                          * Pre-parse the next op#.  If it is
1014                                          * SaveFH, count it and skip to the
1015                                          * next op#, if not the last op#.
1016                                          * nextop is used to determine if
1017                                          * NFSERR_WRONGSEC can be returned,
1018                                          * per RFC5661 Sec. 2.6.
1019                                          */
1020                                         do {
1021                                                 NFSM_DISSECT(tl, uint32_t *,
1022                                                     NFSX_UNSIGNED);
1023                                                 nextop = fxdr_unsigned(int,
1024                                                     *tl);
1025                                                 if (nextop == NFSV4OP_SAVEFH &&
1026                                                     i < numops - 1)
1027                                                         savefhcnt++;
1028                                         } while (nextop == NFSV4OP_SAVEFH &&
1029                                             i < numops - 1);
1030                                 }
1031                                 nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
1032                                     &nes, NULL, 0, nextop);
1033                         } else
1034                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
1035                         if (!nd->nd_repstat) {
1036                                 if (vp)
1037                                         vrele(vp);
1038                                 vp = nvp;
1039                                 cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1040                                 NFSVOPUNLOCK(vp);
1041                                 vpnes = nes;
1042                         }
1043                         break;
1044                 case NFSV4OP_PUTROOTFH:
1045                         if (NFSD_VNET(nfs_rootfhset)) {
1046                                 if ((nd->nd_flag & ND_LASTOP) == 0) {
1047                                         /*
1048                                          * Pre-parse the next op#.  If it is
1049                                          * SaveFH, count it and skip to the
1050                                          * next op#, if not the last op#.
1051                                          * nextop is used to determine if
1052                                          * NFSERR_WRONGSEC can be returned,
1053                                          * per RFC5661 Sec. 2.6.
1054                                          */
1055                                         do {
1056                                                 NFSM_DISSECT(tl, uint32_t *,
1057                                                     NFSX_UNSIGNED);
1058                                                 nextop = fxdr_unsigned(int,
1059                                                     *tl);
1060                                                 if (nextop == NFSV4OP_SAVEFH &&
1061                                                     i < numops - 1)
1062                                                         savefhcnt++;
1063                                         } while (nextop == NFSV4OP_SAVEFH &&
1064                                             i < numops - 1);
1065                                 }
1066                                 nfsd_fhtovp(nd, &NFSD_VNET(nfs_rootfh),
1067                                     LK_SHARED, &nvp, &nes, NULL, 0, nextop);
1068                                 if (!nd->nd_repstat) {
1069                                         if (vp)
1070                                                 vrele(vp);
1071                                         vp = nvp;
1072                                         cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1073                                         NFSVOPUNLOCK(vp);
1074                                         vpnes = nes;
1075                                 }
1076                         } else
1077                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
1078                         break;
1079                 case NFSV4OP_SAVEFH:
1080                         if (vp && NFSVNO_EXPORTED(&vpnes)) {
1081                                 nd->nd_repstat = 0;
1082                                 /* If vp == savevp, a no-op */
1083                                 if (vp != savevp) {
1084                                         if (savevp)
1085                                                 vrele(savevp);
1086                                         VREF(vp);
1087                                         savevp = vp;
1088                                         savevpnes = vpnes;
1089                                         save_fsid = cur_fsid;
1090                                 }
1091                                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
1092                                         nd->nd_savedcurstateid =
1093                                             nd->nd_curstateid;
1094                                         nd->nd_flag |= ND_SAVEDCURSTATEID;
1095                                 }
1096                         } else {
1097                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
1098                         }
1099                         break;
1100                 case NFSV4OP_RESTOREFH:
1101                         if (savevp) {
1102                                 if ((nd->nd_flag & ND_LASTOP) == 0) {
1103                                         /*
1104                                          * Pre-parse the next op#.  If it is
1105                                          * SaveFH, count it and skip to the
1106                                          * next op#, if not the last op#.
1107                                          * nextop is used to determine if
1108                                          * NFSERR_WRONGSEC can be returned,
1109                                          * per RFC5661 Sec. 2.6.
1110                                          */
1111                                         do {
1112                                                 NFSM_DISSECT(tl, uint32_t *,
1113                                                     NFSX_UNSIGNED);
1114                                                 nextop = fxdr_unsigned(int,
1115                                                     *tl);
1116                                                 if (nextop == NFSV4OP_SAVEFH &&
1117                                                     i < numops - 1)
1118                                                         savefhcnt++;
1119                                         } while (nextop == NFSV4OP_SAVEFH &&
1120                                             i < numops - 1);
1121                                 }
1122                                 nd->nd_repstat = 0;
1123                                 /* If vp == savevp, a no-op */
1124                                 if (vp != savevp) {
1125                                         if (nfsrv_checkwrongsec(nd, nextop,
1126                                             savevp->v_type))
1127                                                 nd->nd_repstat =
1128                                                     nfsvno_testexp(nd,
1129                                                     &savevpnes);
1130                                         if (nd->nd_repstat == 0) {
1131                                                 VREF(savevp);
1132                                                 vrele(vp);
1133                                                 vp = savevp;
1134                                                 vpnes = savevpnes;
1135                                                 cur_fsid = save_fsid;
1136                                         }
1137                                 }
1138                                 if (nd->nd_repstat == 0 &&
1139                                      (nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
1140                                         nd->nd_curstateid =
1141                                             nd->nd_savedcurstateid;
1142                                         nd->nd_flag |= ND_CURSTATEID;
1143                                 }
1144                         } else {
1145                                 nd->nd_repstat = NFSERR_RESTOREFH;
1146                         }
1147                         break;
1148                 default:
1149                     /*
1150                      * Allow a Lookup, Getattr, GetFH, Secinfo on an
1151                      * non-exported directory if
1152                      * nfs_rootfhset. Do I need to allow any other Ops?
1153                      * (You can only have a non-exported vpnes if
1154                      *  nfs_rootfhset is true. See nfsd_fhtovp())
1155                      * Allow AUTH_SYS to be used for file systems
1156                      * exported GSS only for certain Ops, to allow
1157                      * clients to do mounts more easily.
1158                      */
1159                     if (nfsv4_opflag[op].needscfh && vp) {
1160                         if (!NFSVNO_EXPORTED(&vpnes) &&
1161                             op != NFSV4OP_LOOKUP &&
1162                             op != NFSV4OP_GETATTR &&
1163                             op != NFSV4OP_GETFH &&
1164                             op != NFSV4OP_ACCESS &&
1165                             op != NFSV4OP_READLINK &&
1166                             op != NFSV4OP_SECINFO &&
1167                             op != NFSV4OP_SECINFONONAME)
1168                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
1169                         if (nd->nd_repstat) {
1170                                 if (op == NFSV4OP_SETATTR) {
1171                                     /*
1172                                      * Setattr reply requires a bitmap
1173                                      * even for errors like these.
1174                                      */
1175                                     NFSM_BUILD(tl, u_int32_t *,
1176                                         NFSX_UNSIGNED);
1177                                     *tl = 0;
1178                                 }
1179                                 break;
1180                         }
1181                     }
1182
1183                     /*
1184                      * Save the current positions in the mbuf lists so
1185                      * that a rollback to this location can be done upon a
1186                      * redo due to a ERELOOKUP return for a operation.
1187                      */
1188                     mb = nd->nd_mb;
1189                     bpos = nd->nd_bpos;
1190                     bextpg = nd->nd_bextpg;
1191                     bextpgsiz = nd->nd_bextpgsiz;
1192                     md = nd->nd_md;
1193                     dpos = nd->nd_dpos;
1194 tryagain:
1195
1196                     if (nfsv4_opflag[op].retfh == 1) {
1197                         if (!vp) {
1198                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
1199                                 break;
1200                         }
1201                         if (NFSVNO_EXPORTED(&vpnes) && (op == NFSV4OP_LOOKUP ||
1202                             op == NFSV4OP_LOOKUPP || (op == NFSV4OP_OPEN &&
1203                             vp->v_type == VDIR))) {
1204                                 /* Check for wrong security. */
1205                                 rstat = nfsvno_testexp(nd, &vpnes);
1206                                 if (rstat != 0) {
1207                                         nd->nd_repstat = rstat;
1208                                         break;
1209                                 }
1210                         }
1211                         VREF(vp);
1212                         if (nfsv4_opflag[op].modifyfs)
1213                                 vn_start_write(vp, &temp_mp, V_WAIT);
1214                         error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
1215                             &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
1216                         if (!error && !nd->nd_repstat) {
1217                             if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
1218                                 new_mp = nvp->v_mount;
1219                                 if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) {
1220                                     /* crossed a server mount point */
1221                                     nd->nd_repstat = nfsvno_checkexp(new_mp,
1222                                         nd->nd_nam, &nes, &credanon);
1223                                     if (!nd->nd_repstat)
1224                                         nd->nd_repstat = nfsd_excred(nd,
1225                                             &nes, credanon, true);
1226                                     if (credanon != NULL)
1227                                         crfree(credanon);
1228                                     if (!nd->nd_repstat) {
1229                                         vpnes = nes;
1230                                         cur_fsid = new_mp->mnt_stat.f_fsid;
1231                                     }
1232                                 }
1233                                 /* Lookup ops return a locked vnode */
1234                                 NFSVOPUNLOCK(nvp);
1235                             }
1236                             if (!nd->nd_repstat) {
1237                                     vrele(vp);
1238                                     vp = nvp;
1239                             } else
1240                                     vrele(nvp);
1241                         }
1242                         if (nfsv4_opflag[op].modifyfs)
1243                                 vn_finished_write(temp_mp);
1244                     } else if (nfsv4_opflag[op].retfh == 2) {
1245                         if (vp == NULL || savevp == NULL) {
1246                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
1247                                 break;
1248                         } else if (fsidcmp(&cur_fsid, &save_fsid) != 0) {
1249                                 nd->nd_repstat = NFSERR_XDEV;
1250                                 break;
1251                         }
1252                         if (nfsv4_opflag[op].modifyfs)
1253                                 vn_start_write(savevp, &temp_mp, V_WAIT);
1254                         if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1255                                 VREF(vp);
1256                                 VREF(savevp);
1257                                 error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1258                                     savevp, vp, &savevpnes, &vpnes);
1259                         } else
1260                                 nd->nd_repstat = NFSERR_PERM;
1261                         if (nfsv4_opflag[op].modifyfs)
1262                                 vn_finished_write(temp_mp);
1263                     } else {
1264                         if (nfsv4_opflag[op].retfh != 0)
1265                                 panic("nfsrvd_compound");
1266                         if (nfsv4_opflag[op].needscfh) {
1267                                 if (vp != NULL) {
1268                                         lktype = nfsv4_opflag[op].lktype;
1269                                         if (nfsv4_opflag[op].modifyfs) {
1270                                                 vn_start_write(vp, &temp_mp,
1271                                                     V_WAIT);
1272                                                 if (op == NFSV4OP_WRITE &&
1273                                                     MNT_SHARED_WRITES(temp_mp))
1274                                                         lktype = LK_SHARED;
1275                                         }
1276                                         if (NFSVOPLOCK(vp, lktype) == 0)
1277                                                 VREF(vp);
1278                                         else
1279                                                 nd->nd_repstat = NFSERR_PERM;
1280                                 } else {
1281                                         nd->nd_repstat = NFSERR_NOFILEHANDLE;
1282                                         if (op == NFSV4OP_SETATTR) {
1283                                                 /*
1284                                                  * Setattr reply requires a
1285                                                  * bitmap even for errors like
1286                                                  * these.
1287                                                  */
1288                                                 NFSM_BUILD(tl, u_int32_t *,
1289                                                     NFSX_UNSIGNED);
1290                                                 *tl = 0;
1291                                         }
1292                                         break;
1293                                 }
1294                                 if (nd->nd_repstat == 0) {
1295                                         error = (*(nfsrv4_ops0[op]))(nd,
1296                                             isdgram, vp, &vpnes);
1297                                         if ((op == NFSV4OP_SECINFO ||
1298                                              op == NFSV4OP_SECINFONONAME) &&
1299                                             error == 0 && nd->nd_repstat == 0) {
1300                                                 /*
1301                                                  * Secinfo and Secinfo_no_name
1302                                                  * consume the current FH.
1303                                                  */
1304                                                 vrele(vp);
1305                                                 vp = NULL;
1306                                         }
1307                                 }
1308                                 if (nfsv4_opflag[op].modifyfs)
1309                                         vn_finished_write(temp_mp);
1310                         } else {
1311                                 error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1312                                     NULL, &vpnes);
1313                         }
1314                     }
1315                 }
1316                 if (error) {
1317                         if (error == EBADRPC || error == NFSERR_BADXDR) {
1318                                 nd->nd_repstat = NFSERR_BADXDR;
1319                         } else {
1320                                 nd->nd_repstat = error;
1321                                 printf("nfsv4 comperr0=%d\n", error);
1322                         }
1323                         error = 0;
1324                 }
1325
1326                 if (nd->nd_repstat == ERELOOKUP) {
1327                         /*
1328                          * Roll back to the beginning of the operation
1329                          * arguments.
1330                          */
1331                         nd->nd_md = md;
1332                         nd->nd_dpos = dpos;
1333
1334                         /*
1335                          * Trim off the bogus reply for this operation
1336                          * and redo the operation.
1337                          */
1338                         nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);
1339                         nd->nd_repstat = 0;
1340                         nd->nd_flag |= ND_ERELOOKUP;
1341                         goto tryagain;
1342                 }
1343                 nd->nd_flag &= ~ND_ERELOOKUP;
1344
1345                 if (statsinprog != 0) {
1346                         nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1347                             /*then*/ &start_time);
1348                         statsinprog = 0;
1349                 }
1350
1351                 retops++;
1352                 if (nd->nd_repstat) {
1353                         *repp = nfsd_errmap(nd);
1354                         break;
1355                 } else {
1356                         *repp = 0;      /* NFS4_OK */
1357                 }
1358         }
1359 nfsmout:
1360         if (statsinprog != 0) {
1361                 nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
1362                     /*then*/ &start_time);
1363                 statsinprog = 0;
1364         }
1365         if (error) {
1366                 if (error == EBADRPC || error == NFSERR_BADXDR)
1367                         nd->nd_repstat = NFSERR_BADXDR;
1368                 else
1369                         printf("nfsv4 comperr1=%d\n", error);
1370         }
1371         if (taglen == -1) {
1372                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1373                 *tl++ = 0;
1374                 *tl = 0;
1375         } else {
1376                 *retopsp = txdr_unsigned(retops);
1377         }
1378         if (vp)
1379                 vrele(vp);
1380         if (savevp)
1381                 vrele(savevp);
1382         NFSLOCKV4ROOTMUTEX();
1383         nfsv4_relref(&nfsv4rootfs_lock);
1384         NFSUNLOCKV4ROOTMUTEX();
1385
1386         NFSEXITCODE2(0, nd);
1387 }