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