]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/fs/nfsserver/nfs_nfsdsocket.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.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                 KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
368                 /*
369                  * For NFSv3, if the malloc/mget allocation is near limits,
370                  * return NFSERR_DELAY.
371                  */
372                 if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
373                         nd->nd_repstat = NFSERR_DELAY;
374                         vp = NULL;
375                 } else {
376                         error = nfsrv_mtofh(nd, &fh);
377                         if (error) {
378                                 if (error != EBADRPC)
379                                         printf("nfs dorpc err1=%d\n", error);
380                                 nd->nd_repstat = NFSERR_GARBAGE;
381                                 return;
382                         }
383                         nes.nes_vfslocked = 0;
384                         if (nd->nd_flag & ND_PUBLOOKUP)
385                                 nfsd_fhtovp(nd, &nfs_pubfh, &vp, &nes,
386                                     &mp, nfs_writerpc[nd->nd_procnum], p);
387                         else
388                                 nfsd_fhtovp(nd, &fh, &vp, &nes,
389                                     &mp, nfs_writerpc[nd->nd_procnum], p);
390                         if (nd->nd_repstat == NFSERR_PROGNOTV4)
391                                 return;
392                 }
393         }
394
395         /*
396          * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
397          * cache, as required.
398          * For V4, nfsrvd_compound() does this.
399          */
400         if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
401                 nd->nd_flag |= ND_SAVEREPLY;
402
403         nfsrvd_rephead(nd);
404         /*
405          * If nd_repstat is non-zero, just fill in the reply status
406          * to complete the RPC reply for V2. Otherwise, you must do
407          * the RPC.
408          */
409         if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
410                 *nd->nd_errp = nfsd_errmap(nd);
411                 NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
412                 if (mp != NULL) {
413                         if (nfs_writerpc[nd->nd_procnum])
414                                 NFS_ENDWRITE(mp);
415                         if (nes.nes_vfslocked)
416                                 nfsvno_unlockvfs(mp);
417                 }
418                 return;
419         }
420
421         /*
422          * Now the procedure can be performed. For V4, nfsrvd_compound()
423          * works through the sub-rpcs, otherwise just call the procedure.
424          * The procedures are in three groups with different arguments.
425          * The group is indicated by the value in nfs_retfh[].
426          */
427         if (nd->nd_flag & ND_NFSV4) {
428                 nfsrvd_compound(nd, isdgram, p);
429         } else {
430                 if (nfs_retfh[nd->nd_procnum] == 1) {
431                         if (vp)
432                                 NFSVOPUNLOCK(vp, 0, p);
433                         error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
434                             vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
435                 } else if (nfs_retfh[nd->nd_procnum] == 2) {
436                         error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
437                             vp, NULL, p, &nes, NULL);
438                 } else {
439                         error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
440                             vp, p, &nes);
441                 }
442                 if (mp) {
443                         if (nfs_writerpc[nd->nd_procnum])
444                                 NFS_ENDWRITE(mp);
445                         if (nes.nes_vfslocked)
446                                 nfsvno_unlockvfs(mp);
447                 }
448                 NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
449         }
450         if (error) {
451                 if (error != EBADRPC)
452                         printf("nfs dorpc err2=%d\n", error);
453                 nd->nd_repstat = NFSERR_GARBAGE;
454         }
455         *nd->nd_errp = nfsd_errmap(nd);
456
457         /*
458          * Don't cache certain reply status values.
459          */
460         if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
461             (nd->nd_repstat == NFSERR_GARBAGE ||
462              nd->nd_repstat == NFSERR_BADXDR ||
463              nd->nd_repstat == NFSERR_MOVED ||
464              nd->nd_repstat == NFSERR_DELAY ||
465              nd->nd_repstat == NFSERR_BADSEQID ||
466              nd->nd_repstat == NFSERR_RESOURCE ||
467              nd->nd_repstat == NFSERR_SERVERFAULT ||
468              nd->nd_repstat == NFSERR_STALECLIENTID ||
469              nd->nd_repstat == NFSERR_STALESTATEID ||
470              nd->nd_repstat == NFSERR_OLDSTATEID ||
471              nd->nd_repstat == NFSERR_BADSTATEID ||
472              nd->nd_repstat == NFSERR_GRACE ||
473              nd->nd_repstat == NFSERR_NOGRACE))
474                 nd->nd_flag &= ~ND_SAVEREPLY;
475 }
476
477 /*
478  * Breaks down a compound RPC request and calls the server routines for
479  * the subprocedures.
480  * Some suboperations are performed directly here to simplify file handle<-->
481  * vnode pointer handling.
482  */
483 static void
484 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
485     NFSPROC_T *p)
486 {
487         int i, op;
488         u_int32_t *tl;
489         struct nfsclient *clp, *nclp;
490         int numops, taglen = -1, error = 0, igotlock;
491         u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp;
492         u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
493         vnode_t vp, nvp, savevp;
494         struct nfsrvfh fh;
495         mount_t mp, savemp;
496         struct ucred *credanon;
497         struct nfsexstuff nes, vpnes, savevpnes;
498         static u_int64_t compref = 0;
499
500         NFSVNO_EXINIT(&vpnes);
501         NFSVNO_EXINIT(&savevpnes);
502         /*
503          * Put the seq# of the current compound RPC in nfsrv_descript.
504          * (This is used by nfsrv_checkgetattr(), to see if the write
505          *  delegation was created by the same compound RPC as the one
506          *  with that Getattr in it.)
507          * Don't worry about the 64bit number wrapping around. It ain't
508          * gonna happen before this server gets shut down/rebooted.
509          */
510         nd->nd_compref = compref++;
511
512         /*
513          * Check for and optionally get a lock on the root. This lock means that
514          * no nfsd will be fiddling with the V4 file system and state stuff. It
515          * is required when the V4 root is being changed, the stable storage
516          * restart file is being updated, or callbacks are being done.
517          * When any of the nfsd are processing an NFSv4 compound RPC, they must
518          * either hold a reference count (nfs_usecnt) or the lock. When
519          * nfsrv_unlock() is called to release the lock, it can optionally
520          * also get a reference count, which saves the need for a call to
521          * nfsrv_getref() after nfsrv_unlock().
522          */
523         /*
524          * First, check to see if we need to wait for an update lock.
525          */
526         igotlock = 0;
527         NFSLOCKV4ROOTMUTEX();
528         if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
529                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
530                     NFSV4ROOTLOCKMUTEXPTR);
531         else
532                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
533                     NFSV4ROOTLOCKMUTEXPTR);
534         NFSUNLOCKV4ROOTMUTEX();
535         if (igotlock) {
536                 /*
537                  * If I got the lock, I can update the stable storage file.
538                  * Done when the grace period is over or a client has long
539                  * since expired.
540                  */
541                 nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
542                 if ((nfsrv_stablefirst.nsf_flags &
543                     (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
544                         nfsrv_updatestable(p);
545
546                 /*
547                  * If at least one client has long since expired, search
548                  * the client list for them, write a REVOKE record on the
549                  * stable storage file and then remove them from the client
550                  * list.
551                  */
552                 if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
553                         nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
554                         for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
555                             LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
556                                 nclp) {
557                                 if (clp->lc_flags & LCL_EXPIREIT) {
558                                     if (!LIST_EMPTY(&clp->lc_open) ||
559                                         !LIST_EMPTY(&clp->lc_deleg))
560                                         nfsrv_writestable(clp->lc_id,
561                                             clp->lc_idlen, NFSNST_REVOKE, p);
562                                     nfsrv_cleanclient(clp, p);
563                                     nfsrv_freedeleglist(&clp->lc_deleg);
564                                     nfsrv_freedeleglist(&clp->lc_olddeleg);
565                                     LIST_REMOVE(clp, lc_hash);
566                                     nfsrv_zapclient(clp, p);
567                                 }
568                             }
569                         }
570                 }
571                 NFSLOCKV4ROOTMUTEX();
572                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
573                 NFSUNLOCKV4ROOTMUTEX();
574         } else {
575                 /*
576                  * If we didn't get the lock, we need to get a refcnt,
577                  * which also checks for and waits for the lock.
578                  */
579                 NFSLOCKV4ROOTMUTEX();
580                 nfsv4_getref(&nfsv4rootfs_lock, NULL,
581                     NFSV4ROOTLOCKMUTEXPTR);
582                 NFSUNLOCKV4ROOTMUTEX();
583         }
584
585         /*
586          * If flagged, search for open owners that haven't had any opens
587          * for a long time.
588          */
589         if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
590                 nfsrv_throwawayopens(p);
591         }
592
593         savevp = vp = NULL;
594         savevpnes.nes_vfslocked = vpnes.nes_vfslocked = 0;
595         savemp = mp = NULL;
596         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
597         taglen = fxdr_unsigned(int, *tl);
598         if (taglen < 0) {
599                 error = EBADRPC;
600                 goto nfsmout;
601         }
602         if (taglen <= NFSV4_SMALLSTR)
603                 tagstr = tag;
604         else
605                 tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
606         error = nfsrv_mtostr(nd, tagstr, taglen);
607         if (error) {
608                 if (taglen > NFSV4_SMALLSTR)
609                         free(tagstr, M_TEMP);
610                 taglen = -1;
611                 goto nfsmout;
612         }
613         (void) nfsm_strtom(nd, tag, taglen);
614         if (taglen > NFSV4_SMALLSTR) {
615                 free(tagstr, M_TEMP);
616         }
617         NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
618         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
619         minorvers = fxdr_unsigned(u_int32_t, *tl++);
620         if (minorvers != NFSV4_MINORVERSION)
621                 nd->nd_repstat = NFSERR_MINORVERMISMATCH;
622         if (nd->nd_repstat)
623                 numops = 0;
624         else
625                 numops = fxdr_unsigned(int, *tl);
626         /*
627          * Loop around doing the sub ops.
628          * vp - is an unlocked vnode pointer for the CFH
629          * savevp - is an unlocked vnode pointer for the SAVEDFH
630          * (at some future date, it might turn out to be more appropriate
631          *  to keep the file handles instead of vnode pointers?)
632          * savevpnes and vpnes - are the export flags for the above.
633          */
634         for (i = 0; i < numops; i++) {
635                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
636                 NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
637                 *repp = *tl;
638                 op = fxdr_unsigned(int, *tl);
639                 if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
640                         nd->nd_repstat = NFSERR_OPILLEGAL;
641                         *repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
642                         *repp = nfsd_errmap(nd);
643                         retops++;
644                         break;
645                 } else {
646                         repp++;
647                 }
648
649                 /*
650                  * Check for a referral on the current FH and, if so, return
651                  * NFSERR_MOVED for all ops that allow it, except Getattr.
652                  */
653                 if (vp != NULL && op != NFSV4OP_GETATTR &&
654                     nfsv4root_getreferral(vp, NULL, 0) != NULL &&
655                     nfsrv_errmoved(op)) {
656                         nd->nd_repstat = NFSERR_MOVED;
657                         *repp = nfsd_errmap(nd);
658                         retops++;
659                         break;
660                 }
661
662                 nd->nd_procnum = op;
663                 /*
664                  * If over flood level, reply NFSERR_RESOURCE, if at the first
665                  * Op. (Since a client recovery from NFSERR_RESOURCE can get
666                  * really nasty for certain Op sequences, I'll play it safe
667                  * and only return the error at the beginning.) The cache
668                  * will still function over flood level, but uses lots of
669                  * mbufs.)
670                  * If nfsrv_mallocmget_limit() returns True, the system is near
671                  * to its limit for memory that malloc()/mget() can allocate.
672                  */
673                 if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
674                     (nfsrv_mallocmget_limit() ||
675                      nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
676                         if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
677                                 printf("nfsd server cache flooded, try to");
678                                 printf(" increase nfsrc_floodlevel\n");
679                         }
680                         nd->nd_repstat = NFSERR_RESOURCE;
681                         *repp = nfsd_errmap(nd);
682                         if (op == NFSV4OP_SETATTR) {
683                                 /*
684                                  * Setattr replies require a bitmap.
685                                  * even for errors like these.
686                                  */
687                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
688                                 *tl = 0;
689                         }
690                         retops++;
691                         break;
692                 }
693                 if (nfsv4_opflag[op].savereply)
694                         nd->nd_flag |= ND_SAVEREPLY;
695                 NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
696                 switch (op) {
697                 case NFSV4OP_PUTFH:
698                         error = nfsrv_mtofh(nd, &fh);
699                         if (error)
700                                 goto nfsmout;
701                         if (!nd->nd_repstat) {
702                                 nes.nes_vfslocked = vpnes.nes_vfslocked;
703                                 nfsd_fhtovp(nd, &fh, &nvp, &nes, &mp,
704                                     0, p);
705                         }
706                         /* For now, allow this for non-export FHs */
707                         if (!nd->nd_repstat) {
708                                 if (vp)
709                                         vrele(vp);
710                                 vp = nvp;
711                                 NFSVOPUNLOCK(vp, 0, p);
712                                 vpnes = nes;
713                         }
714                         break;
715                 case NFSV4OP_PUTPUBFH:
716                         if (nfs_pubfhset) {
717                             nes.nes_vfslocked = vpnes.nes_vfslocked;
718                             nfsd_fhtovp(nd, &nfs_pubfh, &nvp,
719                                 &nes, &mp, 0, p);
720                         } else {
721                             nd->nd_repstat = NFSERR_NOFILEHANDLE;
722                         }
723                         if (!nd->nd_repstat) {
724                                 if (vp)
725                                         vrele(vp);
726                                 vp = nvp;
727                                 NFSVOPUNLOCK(vp, 0, p);
728                                 vpnes = nes;
729                         }
730                         break;
731                 case NFSV4OP_PUTROOTFH:
732                         if (nfs_rootfhset) {
733                                 nes.nes_vfslocked = vpnes.nes_vfslocked;
734                                 nfsd_fhtovp(nd, &nfs_rootfh, &nvp,
735                                     &nes, &mp, 0, p);
736                                 if (!nd->nd_repstat) {
737                                         if (vp)
738                                                 vrele(vp);
739                                         vp = nvp;
740                                         NFSVOPUNLOCK(vp, 0, p);
741                                         vpnes = nes;
742                                 }
743                         } else if (nfsv4root_vp && nfsv4root_set) {
744                                 if (vp) {
745                                         if (vpnes.nes_vfslocked)
746                                                 nfsvno_unlockvfs(mp);
747                                         vrele(vp);
748                                 }
749                                 vp = nfsv4root_vp;
750                                 VREF(vp);
751                                 NFSVNO_SETEXRDONLY(&vpnes);
752                                 vpnes.nes_vfslocked = 0;
753                                 mp = vnode_mount(vp);
754                         } else {
755                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
756                         }
757                         break;
758                 case NFSV4OP_SAVEFH:
759                         if (vp && NFSVNO_EXPORTED(&vpnes)) {
760                                 nd->nd_repstat = 0;
761                                 /* If vp == savevp, a no-op */
762                                 if (vp != savevp) {
763                                         if (savevp)
764                                                 vrele(savevp);
765                                         VREF(vp);
766                                         savevp = vp;
767                                         savevpnes = vpnes;
768                                         savemp = mp;
769                                 }
770                         } else {
771                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
772                         }
773                         break;
774                 case NFSV4OP_RESTOREFH:
775                         if (savevp) {
776                                 nd->nd_repstat = 0;
777                                 /* If vp == savevp, a no-op */
778                                 if (vp != savevp) {
779                                         VREF(savevp);
780                                         if (mp == NULL || savemp == NULL)
781                                                 panic("nfscmpmp");
782                                         if (!savevpnes.nes_vfslocked &&
783                                             vpnes.nes_vfslocked) {
784                                                 if (mp == savemp)
785                                                         panic("nfscmp2");
786                                                 nfsvno_unlockvfs(mp);
787                                         } else if (savevpnes.nes_vfslocked &&
788                                             !vpnes.nes_vfslocked) {
789                                                 if (mp == savemp)
790                                                         panic("nfscmp3");
791                                                 savevpnes.nes_vfslocked = nfsvno_lockvfs(savemp);
792                                         }
793                                         vrele(vp);
794                                         vp = savevp;
795                                         vpnes = savevpnes;
796                                         mp = savemp;
797                                 }
798                         } else {
799                                 nd->nd_repstat = NFSERR_RESTOREFH;
800                         }
801                         break;
802                 default:
803                     /*
804                      * Allow a Lookup, Getattr, GetFH, Secinfo on an
805                      * non-exported directory if
806                      * nfs_rootfhset. Do I need to allow any other Ops?
807                      * (You can only have a non-exported vpnes if
808                      *  nfs_rootfhset is true. See nfsd_fhtovp())
809                      * Allow AUTH_SYS to be used for file systems
810                      * exported GSS only for certain Ops, to allow
811                      * clients to do mounts more easily.
812                      */
813                     if (nfsv4_opflag[op].needscfh && vp) {
814                         if (!NFSVNO_EXPORTED(&vpnes) &&
815                             op != NFSV4OP_LOOKUP &&
816                             op != NFSV4OP_GETATTR &&
817                             op != NFSV4OP_GETFH &&
818                             op != NFSV4OP_SECINFO)
819                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
820                         else if (nfsvno_testexp(nd, &vpnes) &&
821                             op != NFSV4OP_LOOKUP &&
822                             op != NFSV4OP_GETFH &&
823                             op != NFSV4OP_GETATTR &&
824                             op != NFSV4OP_SECINFO)
825                                 nd->nd_repstat = NFSERR_WRONGSEC;
826                         if (nd->nd_repstat) {
827                                 if (op == NFSV4OP_SETATTR) {
828                                     /*
829                                      * Setattr reply requires a bitmap
830                                      * even for errors like these.
831                                      */
832                                     NFSM_BUILD(tl, u_int32_t *,
833                                         NFSX_UNSIGNED);
834                                     *tl = 0;
835                                 }
836                                 break;
837                         }
838                     }
839                     if (nfsv4_opflag[op].retfh == 1) {
840                         if (!vp) {
841                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
842                                 break;
843                         }
844                         VREF(vp);
845                         if (nfsv4_opflag[op].modifyfs)
846                                 NFS_STARTWRITE(NULL, &mp);
847                         error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
848                             &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
849                         if (!error && !nd->nd_repstat) {
850                             if (vfs_statfs(mp)->f_fsid.val[0] !=
851                                 vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ||
852                                 vfs_statfs(mp)->f_fsid.val[1] !=
853                                 vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) {
854                                 if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ==
855                                     NFSV4ROOT_FSID0 &&
856                                     vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] ==
857                                     NFSV4ROOT_FSID1) {
858                                     if (vpnes.nes_vfslocked) {
859                                         nfsvno_unlockvfs(mp);
860                                         vpnes.nes_vfslocked = 0;
861                                     }
862                                     NFSVNO_SETEXRDONLY(&vpnes);
863                                     mp = vnode_mount(nvp);
864                                 } else {
865                                     nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp),
866                                         nd->nd_nam, &nes, &credanon);
867                                     if (!nd->nd_repstat)
868                                         nd->nd_repstat = nfsd_excred(nd,
869                                             &nes, credanon);
870                                     if (credanon != NULL)
871                                         crfree(credanon);
872                                     if (!nd->nd_repstat) {
873                                         if (vpnes.nes_vfslocked)
874                                             nfsvno_unlockvfs(mp);
875                                         mp = vnode_mount(nvp);
876                                         vpnes = nes;
877                                         vpnes.nes_vfslocked =
878                                             nfsvno_lockvfs(mp);
879                                     }
880                                 }
881                             }
882                             if (!nd->nd_repstat) {
883                                     vrele(vp);
884                                     vp = nvp;
885                             }
886                         }
887                         if (nfsv4_opflag[op].modifyfs)
888                                 NFS_ENDWRITE(mp);
889                     } else if (nfsv4_opflag[op].retfh == 2) {
890                         if (vp == NULL || savevp == NULL) {
891                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
892                                 break;
893                         } else if (mp != savemp) {
894                                 nd->nd_repstat = NFSERR_XDEV;
895                                 break;
896                         }
897                         VREF(vp);
898                         VREF(savevp);
899                         if (nfsv4_opflag[op].modifyfs)
900                                 NFS_STARTWRITE(NULL, &mp);
901                         NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
902                         error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
903                             vp, p, &savevpnes, &vpnes);
904                         if (nfsv4_opflag[op].modifyfs)
905                                 NFS_ENDWRITE(mp);
906                     } else {
907                         if (nfsv4_opflag[op].retfh != 0)
908                                 panic("nfsrvd_compound");
909                         if (nfsv4_opflag[op].needscfh) {
910                                 if (vp) {
911                                         VREF(vp);
912                                         if (nfsv4_opflag[op].modifyfs)
913                                                 NFS_STARTWRITE(NULL, &mp);
914                                         NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
915                                 } else {
916                                         nd->nd_repstat = NFSERR_NOFILEHANDLE;
917                                         if (op == NFSV4OP_SETATTR) {
918                                             /*
919                                              * Setattr reply requires a bitmap
920                                              * even for errors like these.
921                                              */
922                                             NFSM_BUILD(tl, u_int32_t *,
923                                                 NFSX_UNSIGNED);
924                                             *tl = 0;
925                                         }
926                                         break;
927                                 }
928                                 error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
929                                     p, &vpnes);
930                                 if (nfsv4_opflag[op].modifyfs)
931                                         NFS_ENDWRITE(mp);
932                         } else {
933                                 error = (*(nfsrv4_ops0[op]))(nd, isdgram,
934                                     NULL, p, &vpnes);
935                         }
936                     }
937                 };
938                 if (error) {
939                         if (error == EBADRPC || error == NFSERR_BADXDR) {
940                                 nd->nd_repstat = NFSERR_BADXDR;
941                         } else {
942                                 nd->nd_repstat = error;
943                                 printf("nfsv4 comperr0=%d\n", error);
944                         }
945                         error = 0;
946                 }
947                 retops++;
948                 if (nd->nd_repstat) {
949                         *repp = nfsd_errmap(nd);
950                         break;
951                 } else {
952                         *repp = 0;      /* NFS4_OK */
953                 }
954         }
955 nfsmout:
956         if (error) {
957                 if (error == EBADRPC || error == NFSERR_BADXDR)
958                         nd->nd_repstat = NFSERR_BADXDR;
959                 else
960                         printf("nfsv4 comperr1=%d\n", error);
961         }
962         if (taglen == -1) {
963                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
964                 *tl++ = 0;
965                 *tl = 0;
966         } else {
967                 *retopsp = txdr_unsigned(retops);
968         }
969         if (mp && vpnes.nes_vfslocked)
970                 nfsvno_unlockvfs(mp);
971         if (vp)
972                 vrele(vp);
973         if (savevp)
974                 vrele(savevp);
975         NFSLOCKV4ROOTMUTEX();
976         nfsv4_relref(&nfsv4rootfs_lock);
977         NFSUNLOCKV4ROOTMUTEX();
978 }