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