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