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