xref: /freebsd/sys/fs/nfsserver/nfs_nfsdsocket.c (revision 685dc743)
19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
49ec7b004SRick Macklem  * Copyright (c) 1989, 1993
59ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
69ec7b004SRick Macklem  *
79ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem  *
109ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem  * are met:
139ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem  *    without specific prior written permission.
219ec7b004SRick Macklem  *
229ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem  * SUCH DAMAGE.
339ec7b004SRick Macklem  *
349ec7b004SRick Macklem  */
359ec7b004SRick Macklem 
369ec7b004SRick Macklem #include <sys/cdefs.h>
379ec7b004SRick Macklem /*
389ec7b004SRick Macklem  * Socket operations for use by the nfs server.
399ec7b004SRick Macklem  */
409ec7b004SRick Macklem 
419ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
429ec7b004SRick Macklem 
43ff2f1f69SRick Macklem #include <security/mac/mac_framework.h>
44ff2f1f69SRick Macklem 
457e44856eSRick Macklem extern struct nfsrvfh nfs_pubfh;
467e44856eSRick Macklem extern int nfs_pubfhset;
479ec7b004SRick Macklem extern struct nfsv4lock nfsv4rootfs_lock;
481f54e596SRick Macklem extern int nfsrv_clienthashsize;
49c59e4cc3SRick Macklem extern int nfsd_debuglevel;
5090d2dfabSRick Macklem extern int nfsrv_layouthighwater;
5190d2dfabSRick Macklem extern volatile int nfsrv_layoutcnt;
529ec7b004SRick Macklem NFSV4ROOTLOCKMUTEX;
539ec7b004SRick Macklem NFSSTATESPINLOCK;
549ec7b004SRick Macklem 
557e44856eSRick Macklem NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst);
567e44856eSRick Macklem NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash);
577e44856eSRick Macklem NFSD_VNET_DECLARE(int, nfsrc_floodlevel);
587e44856eSRick Macklem NFSD_VNET_DECLARE(int, nfsrc_tcpsavedreplies);
597e44856eSRick Macklem NFSD_VNET_DECLARE(struct nfsrvfh, nfs_rootfh);
607e44856eSRick Macklem NFSD_VNET_DECLARE(int, nfs_rootfhset);
617e44856eSRick Macklem NFSD_VNET_DECLARE(struct nfsstatsv1 *, nfsstatsv1_p);
627e44856eSRick Macklem 
639ec7b004SRick Macklem int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
64af444b18SEdward Tomasz Napierala     int, vnode_t , struct nfsexstuff *) = {
65af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
669ec7b004SRick Macklem 	nfsrvd_getattr,
679ec7b004SRick Macklem 	nfsrvd_setattr,
68af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
699ec7b004SRick Macklem 	nfsrvd_access,
709ec7b004SRick Macklem 	nfsrvd_readlink,
719ec7b004SRick Macklem 	nfsrvd_read,
729ec7b004SRick Macklem 	nfsrvd_write,
739ec7b004SRick Macklem 	nfsrvd_create,
74af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
75af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
76af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
779ec7b004SRick Macklem 	nfsrvd_remove,
789ec7b004SRick Macklem 	nfsrvd_remove,
79af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
80af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
819ec7b004SRick Macklem 	nfsrvd_readdir,
829ec7b004SRick Macklem 	nfsrvd_readdirplus,
839ec7b004SRick Macklem 	nfsrvd_statfs,
849ec7b004SRick Macklem 	nfsrvd_fsinfo,
859ec7b004SRick Macklem 	nfsrvd_pathconf,
869ec7b004SRick Macklem 	nfsrvd_commit,
879ec7b004SRick Macklem };
889ec7b004SRick Macklem 
899ec7b004SRick Macklem int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
90af444b18SEdward Tomasz Napierala     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
91af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
92af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
93af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
949ec7b004SRick Macklem 	nfsrvd_lookup,
95af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
96af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
97af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
98af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
99af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
1009ec7b004SRick Macklem 	nfsrvd_mkdir,
1019ec7b004SRick Macklem 	nfsrvd_symlink,
1029ec7b004SRick Macklem 	nfsrvd_mknod,
103af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
104af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
105af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
106af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
107af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
108af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
109af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
110af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
111af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
112af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
1139ec7b004SRick Macklem };
1149ec7b004SRick Macklem 
1159ec7b004SRick Macklem int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
116af444b18SEdward Tomasz Napierala     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
117af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
118af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
119af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
120af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
121af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
122af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
123af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
124af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
125af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
126af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
127af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
128af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
129af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
130af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
1319ec7b004SRick Macklem 	nfsrvd_rename,
1329ec7b004SRick Macklem 	nfsrvd_link,
133af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
134af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
135af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
136af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
137af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
138af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
1399ec7b004SRick Macklem };
1409ec7b004SRick Macklem 
141c057a378SRick Macklem int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *,
142af444b18SEdward Tomasz Napierala     int, vnode_t , struct nfsexstuff *) = {
143af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
144af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
145af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1469ec7b004SRick Macklem 	nfsrvd_access,
1479ec7b004SRick Macklem 	nfsrvd_close,
1489ec7b004SRick Macklem 	nfsrvd_commit,
149af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1509ec7b004SRick Macklem 	nfsrvd_delegpurge,
1519ec7b004SRick Macklem 	nfsrvd_delegreturn,
1529ec7b004SRick Macklem 	nfsrvd_getattr,
1539ec7b004SRick Macklem 	nfsrvd_getfh,
154af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1559ec7b004SRick Macklem 	nfsrvd_lock,
1569ec7b004SRick Macklem 	nfsrvd_lockt,
1579ec7b004SRick Macklem 	nfsrvd_locku,
158af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
159af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1609ec7b004SRick Macklem 	nfsrvd_verify,
161af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
162af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1639ec7b004SRick Macklem 	nfsrvd_openconfirm,
1649ec7b004SRick Macklem 	nfsrvd_opendowngrade,
165af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
166af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
167af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1689ec7b004SRick Macklem 	nfsrvd_read,
1699ec7b004SRick Macklem 	nfsrvd_readdirplus,
1709ec7b004SRick Macklem 	nfsrvd_readlink,
1719ec7b004SRick Macklem 	nfsrvd_remove,
172af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1739ec7b004SRick Macklem 	nfsrvd_renew,
174af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
175af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
1769ec7b004SRick Macklem 	nfsrvd_secinfo,
1779ec7b004SRick Macklem 	nfsrvd_setattr,
1789ec7b004SRick Macklem 	nfsrvd_setclientid,
1799ec7b004SRick Macklem 	nfsrvd_setclientidcfrm,
1809ec7b004SRick Macklem 	nfsrvd_verify,
1819ec7b004SRick Macklem 	nfsrvd_write,
1829ec7b004SRick Macklem 	nfsrvd_releaselckown,
183c59e4cc3SRick Macklem 	nfsrvd_notsupp,
1849442a64eSRick Macklem 	nfsrvd_bindconnsess,
185c59e4cc3SRick Macklem 	nfsrvd_exchangeid,
186c59e4cc3SRick Macklem 	nfsrvd_createsession,
187c59e4cc3SRick Macklem 	nfsrvd_destroysession,
188c59e4cc3SRick Macklem 	nfsrvd_freestateid,
189c59e4cc3SRick Macklem 	nfsrvd_notsupp,
19090d2dfabSRick Macklem 	nfsrvd_getdevinfo,
191c59e4cc3SRick Macklem 	nfsrvd_notsupp,
19290d2dfabSRick Macklem 	nfsrvd_layoutcommit,
19390d2dfabSRick Macklem 	nfsrvd_layoutget,
19490d2dfabSRick Macklem 	nfsrvd_layoutreturn,
195947bd247SRick Macklem 	nfsrvd_secinfononame,
196c59e4cc3SRick Macklem 	nfsrvd_sequence,
197c59e4cc3SRick Macklem 	nfsrvd_notsupp,
1985d4835e4SRick Macklem 	nfsrvd_teststateid,
199c59e4cc3SRick Macklem 	nfsrvd_notsupp,
200c59e4cc3SRick Macklem 	nfsrvd_destroyclientid,
201c59e4cc3SRick Macklem 	nfsrvd_reclaimcomplete,
202c057a378SRick Macklem 	nfsrvd_allocate,
203c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
204c057a378SRick Macklem 	nfsrvd_notsupp,
205bb958dcfSRick Macklem 	nfsrvd_deallocate,
206c057a378SRick Macklem 	nfsrvd_ioadvise,
207c057a378SRick Macklem 	nfsrvd_layouterror,
208c057a378SRick Macklem 	nfsrvd_layoutstats,
209c057a378SRick Macklem 	nfsrvd_notsupp,
210c057a378SRick Macklem 	nfsrvd_notsupp,
211c057a378SRick Macklem 	nfsrvd_notsupp,
212c057a378SRick Macklem 	nfsrvd_seek,
213c057a378SRick Macklem 	nfsrvd_notsupp,
214c057a378SRick Macklem 	nfsrvd_notsupp,
215c057a378SRick Macklem 	nfsrvd_getxattr,
216c057a378SRick Macklem 	nfsrvd_setxattr,
217c057a378SRick Macklem 	nfsrvd_listxattr,
218c057a378SRick Macklem 	nfsrvd_rmxattr,
2199ec7b004SRick Macklem };
2209ec7b004SRick Macklem 
221c057a378SRick Macklem int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *,
222af444b18SEdward Tomasz Napierala     int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {
223af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
224af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
225af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
226af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
227af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
228af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
2299ec7b004SRick Macklem 	nfsrvd_mknod,
230af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
231af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
232af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
233af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
234af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
235af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
236af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
237af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
2389ec7b004SRick Macklem 	nfsrvd_lookup,
2399ec7b004SRick Macklem 	nfsrvd_lookup,
240af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
2419ec7b004SRick Macklem 	nfsrvd_open,
2429ec7b004SRick Macklem 	nfsrvd_openattr,
243af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
244af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
245af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
246af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
247af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
248af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
249af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
250af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
251af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
252af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
253af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
254af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
255af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
256af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
257af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
258af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
259af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
260af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
261af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
262af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
263af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
264af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
265af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
266af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
267af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
268af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
269af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
270af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
271af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
272af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
273af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
274af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
275af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
276af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
277af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
278af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
279af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
280af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
281af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
282c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
283c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
284c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
285c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
286c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
287c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
288c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
289c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
290c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
291c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
292c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
293c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
294c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
295c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
296c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
297c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
298c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,
2999ec7b004SRick Macklem };
3009ec7b004SRick Macklem 
301c057a378SRick Macklem int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *,
302af444b18SEdward Tomasz Napierala     int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {
303af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
304af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
305af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
306af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
307af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
308af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
309af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
310af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
311af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
312af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
313af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
3149ec7b004SRick Macklem 	nfsrvd_link,
315af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
316af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
317af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
318af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
319af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
320af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
321af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
322af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
323af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
324af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
325af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
326af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
327af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
328af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
329af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
330af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
331af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
3329ec7b004SRick Macklem 	nfsrvd_rename,
333af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
334af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
335af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
336af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
337af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
338af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
339af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
340af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
341af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
342af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
343af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
344af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
345af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
346af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
347af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
348af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
349af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
350af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
351af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
352af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
353af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
354af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
355af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
356af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
357af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
358af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
359af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
360af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
361af444b18SEdward Tomasz Napierala 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
362c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
363c057a378SRick Macklem 	nfsrvd_copy_file_range,
364c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
365c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
366c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
367c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
368c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
369c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
370c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
371c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
372c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
373c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
374c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
375c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
376c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
377c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
378c057a378SRick Macklem 	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
3799ec7b004SRick Macklem };
3809ec7b004SRick Macklem 
3819ec7b004SRick Macklem /*
3829ec7b004SRick Macklem  * Static array that defines which nfs rpc's are nonidempotent
3839ec7b004SRick Macklem  */
3849ec7b004SRick Macklem static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
3859ec7b004SRick Macklem 	FALSE,
3869ec7b004SRick Macklem 	FALSE,
3879ec7b004SRick Macklem 	TRUE,
3889ec7b004SRick Macklem 	FALSE,
3899ec7b004SRick Macklem 	FALSE,
3909ec7b004SRick Macklem 	FALSE,
3919ec7b004SRick Macklem 	FALSE,
3929ec7b004SRick Macklem 	TRUE,
3939ec7b004SRick Macklem 	TRUE,
3949ec7b004SRick Macklem 	TRUE,
3959ec7b004SRick Macklem 	TRUE,
3969ec7b004SRick Macklem 	TRUE,
3979ec7b004SRick Macklem 	TRUE,
3989ec7b004SRick Macklem 	TRUE,
3999ec7b004SRick Macklem 	TRUE,
4009ec7b004SRick Macklem 	TRUE,
4019ec7b004SRick Macklem 	FALSE,
4029ec7b004SRick Macklem 	FALSE,
4039ec7b004SRick Macklem 	FALSE,
4049ec7b004SRick Macklem 	FALSE,
4059ec7b004SRick Macklem 	FALSE,
4069ec7b004SRick Macklem 	FALSE,
4079ec7b004SRick Macklem };
4089ec7b004SRick Macklem 
4099ec7b004SRick Macklem /*
4109ec7b004SRick Macklem  * This static array indicates whether or not the RPC modifies the
4119ec7b004SRick Macklem  * file system.
4129ec7b004SRick Macklem  */
4133e5ba2e1SRick Macklem int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
4149ec7b004SRick Macklem     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
4159ec7b004SRick Macklem     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
4169ec7b004SRick Macklem 
417c057a378SRick Macklem SYSCTL_DECL(_vfs_nfsd);
418c057a378SRick Macklem static int	nfs_minminorv4 = NFSV4_MINORVERSION;
419c057a378SRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN,
420c057a378SRick Macklem     &nfs_minminorv4, 0,
421c057a378SRick Macklem     "The lowest minor version of NFSv4 handled by the server");
422c057a378SRick Macklem 
423c057a378SRick Macklem static int	nfs_maxminorv4 = NFSV42_MINORVERSION;
424c057a378SRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN,
425c057a378SRick Macklem     &nfs_maxminorv4, 0,
426c057a378SRick Macklem     "The highest minor version of NFSv4 handled by the server");
427c057a378SRick Macklem 
4289ec7b004SRick Macklem /* local functions */
4299ec7b004SRick Macklem static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
430113aa933SEdward Tomasz Napierala     u_char *tag, int taglen, u_int32_t minorvers);
4319ec7b004SRick Macklem 
4329ec7b004SRick Macklem /*
4339ec7b004SRick Macklem  * This static array indicates which server procedures require the extra
4349ec7b004SRick Macklem  * arguments to return the current file handle for V2, 3.
4359ec7b004SRick Macklem  */
4369ec7b004SRick Macklem static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
4379ec7b004SRick Macklem 	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
4389ec7b004SRick Macklem 
439c057a378SRick Macklem extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];
4409ec7b004SRick Macklem 
4419ec7b004SRick Macklem static int nfsv3to4op[NFS_V3NPROCS] = {
4429ec7b004SRick Macklem 	NFSPROC_NULL,
4439ec7b004SRick Macklem 	NFSV4OP_GETATTR,
4449ec7b004SRick Macklem 	NFSV4OP_SETATTR,
4459ec7b004SRick Macklem 	NFSV4OP_LOOKUP,
4469ec7b004SRick Macklem 	NFSV4OP_ACCESS,
4479ec7b004SRick Macklem 	NFSV4OP_READLINK,
4489ec7b004SRick Macklem 	NFSV4OP_READ,
4499ec7b004SRick Macklem 	NFSV4OP_WRITE,
4509ec7b004SRick Macklem 	NFSV4OP_V3CREATE,
4519ec7b004SRick Macklem 	NFSV4OP_MKDIR,
4529ec7b004SRick Macklem 	NFSV4OP_SYMLINK,
4539ec7b004SRick Macklem 	NFSV4OP_MKNOD,
4549ec7b004SRick Macklem 	NFSV4OP_REMOVE,
4559ec7b004SRick Macklem 	NFSV4OP_RMDIR,
4569ec7b004SRick Macklem 	NFSV4OP_RENAME,
4579ec7b004SRick Macklem 	NFSV4OP_LINK,
4589ec7b004SRick Macklem 	NFSV4OP_READDIR,
4599ec7b004SRick Macklem 	NFSV4OP_READDIRPLUS,
4609ec7b004SRick Macklem 	NFSV4OP_FSSTAT,
4619ec7b004SRick Macklem 	NFSV4OP_FSINFO,
4629ec7b004SRick Macklem 	NFSV4OP_PATHCONF,
4639ec7b004SRick Macklem 	NFSV4OP_COMMIT,
4649ec7b004SRick Macklem };
4659ec7b004SRick Macklem 
4661b819cf2SRick Macklem static struct mtx nfsrvd_statmtx;
4671b819cf2SRick Macklem MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
4681b819cf2SRick Macklem 
469ff2f1f69SRick Macklem static struct ucred *nfsrv_createrootcred(void);
470ff2f1f69SRick Macklem 
4711b819cf2SRick Macklem static void
nfsrvd_statstart(int op,struct bintime * now)4721b819cf2SRick Macklem nfsrvd_statstart(int op, struct bintime *now)
4731b819cf2SRick Macklem {
4741b819cf2SRick Macklem 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
4751b819cf2SRick Macklem 		printf("%s: op %d invalid\n", __func__, op);
4761b819cf2SRick Macklem 		return;
4771b819cf2SRick Macklem 	}
4781b819cf2SRick Macklem 
4791b819cf2SRick Macklem 	mtx_lock(&nfsrvd_statmtx);
480b039ca07SRick Macklem 	if (NFSD_VNET(nfsstatsv1_p)->srvstartcnt ==
481b039ca07SRick Macklem 	    NFSD_VNET(nfsstatsv1_p)->srvdonecnt) {
4821b819cf2SRick Macklem 		if (now != NULL)
483b039ca07SRick Macklem 			NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;
4841b819cf2SRick Macklem 		else
485b039ca07SRick Macklem 			binuptime(&NFSD_VNET(nfsstatsv1_p)->busyfrom);
4861b819cf2SRick Macklem 
4871b819cf2SRick Macklem 	}
488b039ca07SRick Macklem 	NFSD_VNET(nfsstatsv1_p)->srvrpccnt[op]++;
489b039ca07SRick Macklem 	NFSD_VNET(nfsstatsv1_p)->srvstartcnt++;
4901b819cf2SRick Macklem 	mtx_unlock(&nfsrvd_statmtx);
4911b819cf2SRick Macklem 
4921b819cf2SRick Macklem }
4931b819cf2SRick Macklem 
4941b819cf2SRick Macklem static void
nfsrvd_statend(int op,uint64_t bytes,struct bintime * now,struct bintime * then)4951b819cf2SRick Macklem nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
4961b819cf2SRick Macklem     struct bintime *then)
4971b819cf2SRick Macklem {
4981b819cf2SRick Macklem 	struct bintime dt, lnow;
4991b819cf2SRick Macklem 
5001b819cf2SRick Macklem 	if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
5011b819cf2SRick Macklem 		printf("%s: op %d invalid\n", __func__, op);
5021b819cf2SRick Macklem 		return;
5031b819cf2SRick Macklem 	}
5041b819cf2SRick Macklem 
5051b819cf2SRick Macklem 	if (now == NULL) {
5061b819cf2SRick Macklem 		now = &lnow;
5071b819cf2SRick Macklem 		binuptime(now);
5081b819cf2SRick Macklem 	}
5091b819cf2SRick Macklem 
5101b819cf2SRick Macklem 	mtx_lock(&nfsrvd_statmtx);
5111b819cf2SRick Macklem 
512b039ca07SRick Macklem 	NFSD_VNET(nfsstatsv1_p)->srvbytes[op] += bytes;
513b039ca07SRick Macklem 	NFSD_VNET(nfsstatsv1_p)->srvops[op]++;
5141b819cf2SRick Macklem 
5151b819cf2SRick Macklem 	if (then != NULL) {
5161b819cf2SRick Macklem 		dt = *now;
5171b819cf2SRick Macklem 		bintime_sub(&dt, then);
518b039ca07SRick Macklem 		bintime_add(&NFSD_VNET(nfsstatsv1_p)->srvduration[op], &dt);
5191b819cf2SRick Macklem 	}
5201b819cf2SRick Macklem 
5211b819cf2SRick Macklem 	dt = *now;
522b039ca07SRick Macklem 	bintime_sub(&dt, &NFSD_VNET(nfsstatsv1_p)->busyfrom);
523b039ca07SRick Macklem 	bintime_add(&NFSD_VNET(nfsstatsv1_p)->busytime, &dt);
524b039ca07SRick Macklem 	NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;
5251b819cf2SRick Macklem 
526b039ca07SRick Macklem 	NFSD_VNET(nfsstatsv1_p)->srvdonecnt++;
5271b819cf2SRick Macklem 
5281b819cf2SRick Macklem 	mtx_unlock(&nfsrvd_statmtx);
5291b819cf2SRick Macklem }
5301b819cf2SRick Macklem 
5319ec7b004SRick Macklem /*
5329ec7b004SRick Macklem  * Do an RPC. Basically, get the file handles translated to vnode pointers
5339ec7b004SRick Macklem  * and then call the appropriate server routine. The server routines are
5349ec7b004SRick Macklem  * split into groups, based on whether they use a file handle or file
5359ec7b004SRick Macklem  * handle plus name or ...
5369ec7b004SRick Macklem  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
5379ec7b004SRick Macklem  */
538b9cc3262SRyan Moeller void
nfsrvd_dorpc(struct nfsrv_descript * nd,int isdgram,u_char * tag,int taglen,u_int32_t minorvers)539c59e4cc3SRick Macklem nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
540113aa933SEdward Tomasz Napierala     u_int32_t minorvers)
5419ec7b004SRick Macklem {
54217891d00SRick Macklem 	int error = 0, lktype;
5439ec7b004SRick Macklem 	vnode_t vp;
544774a3685SRick Macklem 	mount_t mp;
5459ec7b004SRick Macklem 	struct nfsrvfh fh;
5469ec7b004SRick Macklem 	struct nfsexstuff nes;
547774a3685SRick Macklem 	struct mbuf *md;
548774a3685SRick Macklem 	char *dpos;
549774a3685SRick Macklem 
550774a3685SRick Macklem 	/*
551774a3685SRick Macklem 	 * Save the current position in the request mbuf list so
552774a3685SRick Macklem 	 * that a rollback to this location can be done upon an
553774a3685SRick Macklem 	 * ERELOOKUP error return from an RPC function.
554774a3685SRick Macklem 	 */
555774a3685SRick Macklem 	md = nd->nd_md;
556774a3685SRick Macklem 	dpos = nd->nd_dpos;
557774a3685SRick Macklem tryagain:
558774a3685SRick Macklem 	mp = NULL;
5599ec7b004SRick Macklem 
5609ec7b004SRick Macklem 	/*
5619ec7b004SRick Macklem 	 * Get a locked vnode for the first file handle
5629ec7b004SRick Macklem 	 */
5639ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4)) {
564b38f7723SKonstantin Belousov 		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
5659ec7b004SRick Macklem 		/*
5669ec7b004SRick Macklem 		 * For NFSv3, if the malloc/mget allocation is near limits,
5679ec7b004SRick Macklem 		 * return NFSERR_DELAY.
5689ec7b004SRick Macklem 		 */
5699ec7b004SRick Macklem 		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
5709ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_DELAY;
5719ec7b004SRick Macklem 			vp = NULL;
5729ec7b004SRick Macklem 		} else {
5739ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &fh);
5749ec7b004SRick Macklem 			if (error) {
5759ec7b004SRick Macklem 				if (error != EBADRPC)
5769ec7b004SRick Macklem 					printf("nfs dorpc err1=%d\n", error);
5779ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_GARBAGE;
578a9285ae5SZack Kirsch 				goto out;
5799ec7b004SRick Macklem 			}
58017891d00SRick Macklem 			if (nd->nd_procnum == NFSPROC_READ ||
581d96b98a3SKenneth D. Merry 			    nd->nd_procnum == NFSPROC_WRITE ||
58217891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_READDIR ||
5830c419e22SRick Macklem 			    nd->nd_procnum == NFSPROC_READDIRPLUS ||
58417891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_READLINK ||
58517891d00SRick Macklem 			    nd->nd_procnum == NFSPROC_GETATTR ||
5860c419e22SRick Macklem 			    nd->nd_procnum == NFSPROC_ACCESS ||
5870c419e22SRick Macklem 			    nd->nd_procnum == NFSPROC_FSSTAT ||
5880c419e22SRick Macklem 			    nd->nd_procnum == NFSPROC_FSINFO)
58917891d00SRick Macklem 				lktype = LK_SHARED;
59017891d00SRick Macklem 			else
59117891d00SRick Macklem 				lktype = LK_EXCLUSIVE;
5929ec7b004SRick Macklem 			if (nd->nd_flag & ND_PUBLOOKUP)
59317891d00SRick Macklem 				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
594a5df139eSRick Macklem 				    &mp, nfsrv_writerpc[nd->nd_procnum], -1);
5959ec7b004SRick Macklem 			else
59617891d00SRick Macklem 				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
597a5df139eSRick Macklem 				    &mp, nfsrv_writerpc[nd->nd_procnum], -1);
5989ec7b004SRick Macklem 			if (nd->nd_repstat == NFSERR_PROGNOTV4)
599a9285ae5SZack Kirsch 				goto out;
6009ec7b004SRick Macklem 		}
6019ec7b004SRick Macklem 	}
6029ec7b004SRick Macklem 
6039ec7b004SRick Macklem 	/*
6049ec7b004SRick Macklem 	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
6059ec7b004SRick Macklem 	 * cache, as required.
6069ec7b004SRick Macklem 	 * For V4, nfsrvd_compound() does this.
6079ec7b004SRick Macklem 	 */
6089ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
6099ec7b004SRick Macklem 		nd->nd_flag |= ND_SAVEREPLY;
6109ec7b004SRick Macklem 
6119ec7b004SRick Macklem 	nfsrvd_rephead(nd);
6129ec7b004SRick Macklem 	/*
6139ec7b004SRick Macklem 	 * If nd_repstat is non-zero, just fill in the reply status
6149ec7b004SRick Macklem 	 * to complete the RPC reply for V2. Otherwise, you must do
6159ec7b004SRick Macklem 	 * the RPC.
6169ec7b004SRick Macklem 	 */
6179ec7b004SRick Macklem 	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
6189ec7b004SRick Macklem 		*nd->nd_errp = nfsd_errmap(nd);
6191b819cf2SRick Macklem 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
6201b819cf2SRick Macklem 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
6211b819cf2SRick Macklem 		   /*now*/ NULL, /*then*/ NULL);
6228974bc2fSRick Macklem 		vn_finished_write(mp);
623a9285ae5SZack Kirsch 		goto out;
6249ec7b004SRick Macklem 	}
6259ec7b004SRick Macklem 
6269ec7b004SRick Macklem 	/*
6279ec7b004SRick Macklem 	 * Now the procedure can be performed. For V4, nfsrvd_compound()
6289ec7b004SRick Macklem 	 * works through the sub-rpcs, otherwise just call the procedure.
6299ec7b004SRick Macklem 	 * The procedures are in three groups with different arguments.
6309ec7b004SRick Macklem 	 * The group is indicated by the value in nfs_retfh[].
6319ec7b004SRick Macklem 	 */
6329ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
633113aa933SEdward Tomasz Napierala 		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers);
6349ec7b004SRick Macklem 	} else {
6351b819cf2SRick Macklem 		struct bintime start_time;
6361b819cf2SRick Macklem 
6371b819cf2SRick Macklem 		binuptime(&start_time);
6381b819cf2SRick Macklem 		nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
6391b819cf2SRick Macklem 
6409ec7b004SRick Macklem 		if (nfs_retfh[nd->nd_procnum] == 1) {
6419ec7b004SRick Macklem 			if (vp)
642b249ce48SMateusz Guzik 				NFSVOPUNLOCK(vp);
6439ec7b004SRick Macklem 			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
644af444b18SEdward Tomasz Napierala 			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes);
6459ec7b004SRick Macklem 		} else if (nfs_retfh[nd->nd_procnum] == 2) {
6469ec7b004SRick Macklem 			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
647af444b18SEdward Tomasz Napierala 			    vp, NULL, &nes, NULL);
6489ec7b004SRick Macklem 		} else {
6499ec7b004SRick Macklem 			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
650af444b18SEdward Tomasz Napierala 			    vp, &nes);
6519ec7b004SRick Macklem 		}
6528974bc2fSRick Macklem 		vn_finished_write(mp);
6531b819cf2SRick Macklem 
654774a3685SRick Macklem 		if (error == 0 && nd->nd_repstat == ERELOOKUP) {
655774a3685SRick Macklem 			/*
656774a3685SRick Macklem 			 * Roll back to the beginning of the RPC request
657774a3685SRick Macklem 			 * arguments.
658774a3685SRick Macklem 			 */
659774a3685SRick Macklem 			nd->nd_md = md;
660774a3685SRick Macklem 			nd->nd_dpos = dpos;
661774a3685SRick Macklem 
662774a3685SRick Macklem 			/* Free the junk RPC reply and redo the RPC. */
663774a3685SRick Macklem 			m_freem(nd->nd_mreq);
664774a3685SRick Macklem 			nd->nd_mreq = nd->nd_mb = NULL;
665774a3685SRick Macklem 			nd->nd_repstat = 0;
666774a3685SRick Macklem 			goto tryagain;
667774a3685SRick Macklem 		}
668774a3685SRick Macklem 
6691b819cf2SRick Macklem 		nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
6701b819cf2SRick Macklem 		    /*now*/ NULL, /*then*/ &start_time);
6719ec7b004SRick Macklem 	}
6729ec7b004SRick Macklem 	if (error) {
6739ec7b004SRick Macklem 		if (error != EBADRPC)
6749ec7b004SRick Macklem 			printf("nfs dorpc err2=%d\n", error);
6759ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_GARBAGE;
6769ec7b004SRick Macklem 	}
6779ec7b004SRick Macklem 	*nd->nd_errp = nfsd_errmap(nd);
6789ec7b004SRick Macklem 
6799ec7b004SRick Macklem 	/*
6809ec7b004SRick Macklem 	 * Don't cache certain reply status values.
6819ec7b004SRick Macklem 	 */
6829ec7b004SRick Macklem 	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
6839ec7b004SRick Macklem 	    (nd->nd_repstat == NFSERR_GARBAGE ||
6849ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_BADXDR ||
6859ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_MOVED ||
6869ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_DELAY ||
6879ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_BADSEQID ||
6889ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_RESOURCE ||
6899ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_SERVERFAULT ||
6909ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_STALECLIENTID ||
6919ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_STALESTATEID ||
6929ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_OLDSTATEID ||
6939ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_BADSTATEID ||
6949ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_GRACE ||
6959ec7b004SRick Macklem 	     nd->nd_repstat == NFSERR_NOGRACE))
6969ec7b004SRick Macklem 		nd->nd_flag &= ~ND_SAVEREPLY;
697a9285ae5SZack Kirsch 
698a9285ae5SZack Kirsch out:
699a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
7009ec7b004SRick Macklem }
7019ec7b004SRick Macklem 
7029ec7b004SRick Macklem /*
7039ec7b004SRick Macklem  * Breaks down a compound RPC request and calls the server routines for
7049ec7b004SRick Macklem  * the subprocedures.
7059ec7b004SRick Macklem  * Some suboperations are performed directly here to simplify file handle<-->
7069ec7b004SRick Macklem  * vnode pointer handling.
7079ec7b004SRick Macklem  */
7089ec7b004SRick Macklem static void
nfsrvd_compound(struct nfsrv_descript * nd,int isdgram,u_char * tag,int taglen,u_int32_t minorvers)709c59e4cc3SRick Macklem nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
710113aa933SEdward Tomasz Napierala     int taglen, u_int32_t minorvers)
7119ec7b004SRick Macklem {
712a5df139eSRick Macklem 	int i, lktype, op, op0 = 0, rstat, statsinprog = 0;
7139ec7b004SRick Macklem 	u_int32_t *tl;
7149ec7b004SRick Macklem 	struct nfsclient *clp, *nclp;
715d224f05fSRick Macklem 	int error = 0, igotlock, nextop, numops, savefhcnt;
716c59e4cc3SRick Macklem 	u_int32_t retops = 0, *retopsp = NULL, *repp;
7179ec7b004SRick Macklem 	vnode_t vp, nvp, savevp;
7189ec7b004SRick Macklem 	struct nfsrvfh fh;
7198974bc2fSRick Macklem 	mount_t new_mp, temp_mp = NULL;
720ff2f1f69SRick Macklem 	struct ucred *credanon, *rootcred, *savecred;
7219ec7b004SRick Macklem 	struct nfsexstuff nes, vpnes, savevpnes;
7228974bc2fSRick Macklem 	fsid_t cur_fsid, save_fsid;
7239ec7b004SRick Macklem 	static u_int64_t compref = 0;
7241b819cf2SRick Macklem 	struct bintime start_time;
725113aa933SEdward Tomasz Napierala 	struct thread *p;
726774a3685SRick Macklem 	struct mbuf *mb, *md;
727774a3685SRick Macklem 	char *bpos, *dpos;
728774a3685SRick Macklem 	int bextpg, bextpgsiz;
729113aa933SEdward Tomasz Napierala 
730113aa933SEdward Tomasz Napierala 	p = curthread;
731ff2f1f69SRick Macklem 	rootcred = savecred = NULL;
7329ec7b004SRick Macklem 
733f8dc0630SRick Macklem 	/* Check for and optionally clear the no space flags for DSs. */
734f8dc0630SRick Macklem 	nfsrv_checknospc();
735f8dc0630SRick Macklem 
7369ec7b004SRick Macklem 	NFSVNO_EXINIT(&vpnes);
7379ec7b004SRick Macklem 	NFSVNO_EXINIT(&savevpnes);
7389ec7b004SRick Macklem 	/*
7399ec7b004SRick Macklem 	 * Put the seq# of the current compound RPC in nfsrv_descript.
7409ec7b004SRick Macklem 	 * (This is used by nfsrv_checkgetattr(), to see if the write
7419ec7b004SRick Macklem 	 *  delegation was created by the same compound RPC as the one
7429ec7b004SRick Macklem 	 *  with that Getattr in it.)
7439ec7b004SRick Macklem 	 * Don't worry about the 64bit number wrapping around. It ain't
7449ec7b004SRick Macklem 	 * gonna happen before this server gets shut down/rebooted.
7459ec7b004SRick Macklem 	 */
7469ec7b004SRick Macklem 	nd->nd_compref = compref++;
7479ec7b004SRick Macklem 
7489ec7b004SRick Macklem 	/*
7499ec7b004SRick Macklem 	 * Check for and optionally get a lock on the root. This lock means that
7509ec7b004SRick Macklem 	 * no nfsd will be fiddling with the V4 file system and state stuff. It
7519ec7b004SRick Macklem 	 * is required when the V4 root is being changed, the stable storage
7529ec7b004SRick Macklem 	 * restart file is being updated, or callbacks are being done.
7539ec7b004SRick Macklem 	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
7549ec7b004SRick Macklem 	 * either hold a reference count (nfs_usecnt) or the lock. When
7559ec7b004SRick Macklem 	 * nfsrv_unlock() is called to release the lock, it can optionally
7569ec7b004SRick Macklem 	 * also get a reference count, which saves the need for a call to
7579ec7b004SRick Macklem 	 * nfsrv_getref() after nfsrv_unlock().
7589ec7b004SRick Macklem 	 */
7599ec7b004SRick Macklem 	/*
7609ec7b004SRick Macklem 	 * First, check to see if we need to wait for an update lock.
7619ec7b004SRick Macklem 	 */
7629ec7b004SRick Macklem 	igotlock = 0;
7639ec7b004SRick Macklem 	NFSLOCKV4ROOTMUTEX();
7647e44856eSRick Macklem 	if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NEEDLOCK)
7659ec7b004SRick Macklem 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
766ff29f3b2SRick Macklem 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
7679ec7b004SRick Macklem 	else
7689ec7b004SRick Macklem 		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
769ff29f3b2SRick Macklem 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
7709ec7b004SRick Macklem 	NFSUNLOCKV4ROOTMUTEX();
7719ec7b004SRick Macklem 	if (igotlock) {
7729ec7b004SRick Macklem 		/*
7739ec7b004SRick Macklem 		 * If I got the lock, I can update the stable storage file.
7749ec7b004SRick Macklem 		 * Done when the grace period is over or a client has long
7759ec7b004SRick Macklem 		 * since expired.
7769ec7b004SRick Macklem 		 */
7777e44856eSRick Macklem 		NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_NEEDLOCK;
7787e44856eSRick Macklem 		if ((NFSD_VNET(nfsrv_stablefirst).nsf_flags &
7799ec7b004SRick Macklem 		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
7809ec7b004SRick Macklem 			nfsrv_updatestable(p);
7819ec7b004SRick Macklem 
7829ec7b004SRick Macklem 		/*
7839ec7b004SRick Macklem 		 * If at least one client has long since expired, search
7849ec7b004SRick Macklem 		 * the client list for them, write a REVOKE record on the
7859ec7b004SRick Macklem 		 * stable storage file and then remove them from the client
7869ec7b004SRick Macklem 		 * list.
7879ec7b004SRick Macklem 		 */
7887e44856eSRick Macklem 		if (NFSD_VNET(nfsrv_stablefirst).nsf_flags &
7897e44856eSRick Macklem 		    NFSNSF_EXPIREDCLIENT) {
7907e44856eSRick Macklem 			NFSD_VNET(nfsrv_stablefirst).nsf_flags &=
7917e44856eSRick Macklem 			    ~NFSNSF_EXPIREDCLIENT;
7921f54e596SRick Macklem 			for (i = 0; i < nfsrv_clienthashsize; i++) {
7937e44856eSRick Macklem 			    LIST_FOREACH_SAFE(clp, &NFSD_VNET(nfsclienthash)[i],
7947e44856eSRick Macklem 				lc_hash, nclp) {
7959ec7b004SRick Macklem 				if (clp->lc_flags & LCL_EXPIREIT) {
7969ec7b004SRick Macklem 				    if (!LIST_EMPTY(&clp->lc_open) ||
7979ec7b004SRick Macklem 					!LIST_EMPTY(&clp->lc_deleg))
7989ec7b004SRick Macklem 					nfsrv_writestable(clp->lc_id,
7999ec7b004SRick Macklem 					    clp->lc_idlen, NFSNST_REVOKE, p);
8009ec7b004SRick Macklem 				    nfsrv_cleanclient(clp, p);
8019ec7b004SRick Macklem 				    nfsrv_freedeleglist(&clp->lc_deleg);
8029ec7b004SRick Macklem 				    nfsrv_freedeleglist(&clp->lc_olddeleg);
8039ec7b004SRick Macklem 				    LIST_REMOVE(clp, lc_hash);
8049ec7b004SRick Macklem 				    nfsrv_zapclient(clp, p);
8059ec7b004SRick Macklem 				}
8069ec7b004SRick Macklem 			    }
8079ec7b004SRick Macklem 			}
8089ec7b004SRick Macklem 		}
8099ec7b004SRick Macklem 		NFSLOCKV4ROOTMUTEX();
8109ec7b004SRick Macklem 		nfsv4_unlock(&nfsv4rootfs_lock, 1);
8119ec7b004SRick Macklem 		NFSUNLOCKV4ROOTMUTEX();
8129ec7b004SRick Macklem 	} else {
8139ec7b004SRick Macklem 		/*
8149ec7b004SRick Macklem 		 * If we didn't get the lock, we need to get a refcnt,
8159ec7b004SRick Macklem 		 * which also checks for and waits for the lock.
8169ec7b004SRick Macklem 		 */
8179ec7b004SRick Macklem 		NFSLOCKV4ROOTMUTEX();
8189ec7b004SRick Macklem 		nfsv4_getref(&nfsv4rootfs_lock, NULL,
819ff29f3b2SRick Macklem 		    NFSV4ROOTLOCKMUTEXPTR, NULL);
8209ec7b004SRick Macklem 		NFSUNLOCKV4ROOTMUTEX();
8219ec7b004SRick Macklem 	}
8229ec7b004SRick Macklem 
8239ec7b004SRick Macklem 	/*
8249ec7b004SRick Macklem 	 * If flagged, search for open owners that haven't had any opens
8259ec7b004SRick Macklem 	 * for a long time.
8269ec7b004SRick Macklem 	 */
8277e44856eSRick Macklem 	if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NOOPENS) {
8289ec7b004SRick Macklem 		nfsrv_throwawayopens(p);
8299ec7b004SRick Macklem 	}
8309ec7b004SRick Macklem 
83190d2dfabSRick Macklem 	/* Do a CBLAYOUTRECALL callback if over the high water mark. */
83290d2dfabSRick Macklem 	if (nfsrv_layoutcnt > nfsrv_layouthighwater)
83390d2dfabSRick Macklem 		nfsrv_recalloldlayout(p);
83490d2dfabSRick Macklem 
8359ec7b004SRick Macklem 	savevp = vp = NULL;
8368974bc2fSRick Macklem 	save_fsid.val[0] = save_fsid.val[1] = 0;
8378974bc2fSRick Macklem 	cur_fsid.val[0] = cur_fsid.val[1] = 0;
838d224f05fSRick Macklem 	nextop = -1;
839d224f05fSRick Macklem 	savefhcnt = 0;
840c59e4cc3SRick Macklem 
841c59e4cc3SRick Macklem 	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
8429ec7b004SRick Macklem 	if (taglen < 0) {
8439ec7b004SRick Macklem 		error = EBADRPC;
8449ec7b004SRick Macklem 		goto nfsmout;
8459ec7b004SRick Macklem 	}
846c59e4cc3SRick Macklem 
8479ec7b004SRick Macklem 	(void) nfsm_strtom(nd, tag, taglen);
8489ec7b004SRick Macklem 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
849c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
850c057a378SRick Macklem 	if ((minorvers != NFSV4_MINORVERSION &&
851c057a378SRick Macklem 	    minorvers != NFSV41_MINORVERSION &&
852c057a378SRick Macklem 	    minorvers != NFSV42_MINORVERSION) ||
853c057a378SRick Macklem 	    minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)
8549ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
8559ec7b004SRick Macklem 	if (nd->nd_repstat)
8569ec7b004SRick Macklem 		numops = 0;
8579ec7b004SRick Macklem 	else
8589ec7b004SRick Macklem 		numops = fxdr_unsigned(int, *tl);
8599ec7b004SRick Macklem 	/*
8609ec7b004SRick Macklem 	 * Loop around doing the sub ops.
8619ec7b004SRick Macklem 	 * vp - is an unlocked vnode pointer for the CFH
8629ec7b004SRick Macklem 	 * savevp - is an unlocked vnode pointer for the SAVEDFH
8639ec7b004SRick Macklem 	 * (at some future date, it might turn out to be more appropriate
8649ec7b004SRick Macklem 	 *  to keep the file handles instead of vnode pointers?)
8659ec7b004SRick Macklem 	 * savevpnes and vpnes - are the export flags for the above.
8669ec7b004SRick Macklem 	 */
8679ec7b004SRick Macklem 	for (i = 0; i < numops; i++) {
8689ec7b004SRick Macklem 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
869d224f05fSRick Macklem 		if (savefhcnt > 0) {
870d224f05fSRick Macklem 			op = NFSV4OP_SAVEFH;
871d224f05fSRick Macklem 			*repp = txdr_unsigned(op);
872d224f05fSRick Macklem 			savefhcnt--;
873d224f05fSRick Macklem 		} else if (nextop == -1) {
874d224f05fSRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
8759183a2a3SRick Macklem 			*repp = *tl;
8769ec7b004SRick Macklem 			op = fxdr_unsigned(int, *tl);
877d224f05fSRick Macklem 		} else {
878d224f05fSRick Macklem 			op = nextop;
879d224f05fSRick Macklem 			*repp = txdr_unsigned(op);
880d224f05fSRick Macklem 			nextop = -1;
881d224f05fSRick Macklem 		}
882c59e4cc3SRick Macklem 		NFSD_DEBUG(4, "op=%d\n", op);
883c057a378SRick Macklem 		if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
884c59e4cc3SRick Macklem 		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
885c057a378SRick Macklem 		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {
8869ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_OPILLEGAL;
8879183a2a3SRick Macklem 			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
8889ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
8899ec7b004SRick Macklem 			retops++;
8909ec7b004SRick Macklem 			break;
8919183a2a3SRick Macklem 		} else {
8929183a2a3SRick Macklem 			repp++;
8939ec7b004SRick Macklem 		}
8941d171e79SRick Macklem 
8951d171e79SRick Macklem 		binuptime(&start_time);
8961d171e79SRick Macklem 		nfsrvd_statstart(op, &start_time);
8971d171e79SRick Macklem 		statsinprog = 1;
8981d171e79SRick Macklem 
899c59e4cc3SRick Macklem 		if (i == 0)
900c59e4cc3SRick Macklem 			op0 = op;
901c59e4cc3SRick Macklem 		if (i == numops - 1)
902c59e4cc3SRick Macklem 			nd->nd_flag |= ND_LASTOP;
9039ec7b004SRick Macklem 
9049ec7b004SRick Macklem 		/*
9059ec7b004SRick Macklem 		 * Check for a referral on the current FH and, if so, return
9069ec7b004SRick Macklem 		 * NFSERR_MOVED for all ops that allow it, except Getattr.
9079ec7b004SRick Macklem 		 */
9089ec7b004SRick Macklem 		if (vp != NULL && op != NFSV4OP_GETATTR &&
9099ec7b004SRick Macklem 		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
9109ec7b004SRick Macklem 		    nfsrv_errmoved(op)) {
9119ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_MOVED;
9129ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
9139ec7b004SRick Macklem 			retops++;
9149ec7b004SRick Macklem 			break;
9159ec7b004SRick Macklem 		}
9169ec7b004SRick Macklem 
917c59e4cc3SRick Macklem 		/*
918c59e4cc3SRick Macklem 		 * For NFSv4.1, check for a Sequence Operation being first
919c59e4cc3SRick Macklem 		 * or one of the other allowed operations by itself.
920c59e4cc3SRick Macklem 		 */
921c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0) {
922c59e4cc3SRick Macklem 			if (i != 0 && op == NFSV4OP_SEQUENCE)
923c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_SEQUENCEPOS;
924c59e4cc3SRick Macklem 			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
925c59e4cc3SRick Macklem 			    op != NFSV4OP_EXCHANGEID &&
926c59e4cc3SRick Macklem 			    op != NFSV4OP_CREATESESSION &&
927c59e4cc3SRick Macklem 			    op != NFSV4OP_BINDCONNTOSESS &&
928c59e4cc3SRick Macklem 			    op != NFSV4OP_DESTROYCLIENTID &&
929c59e4cc3SRick Macklem 			    op != NFSV4OP_DESTROYSESSION)
930c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_OPNOTINSESS;
931c59e4cc3SRick Macklem 			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
932c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_NOTONLYOP;
933c59e4cc3SRick Macklem 			if (nd->nd_repstat != 0) {
934c59e4cc3SRick Macklem 				*repp = nfsd_errmap(nd);
935c59e4cc3SRick Macklem 				retops++;
936c59e4cc3SRick Macklem 				break;
937c59e4cc3SRick Macklem 			}
938c59e4cc3SRick Macklem 		}
939c59e4cc3SRick Macklem 
9409ec7b004SRick Macklem 		nd->nd_procnum = op;
9419ec7b004SRick Macklem 		/*
9429ec7b004SRick Macklem 		 * If over flood level, reply NFSERR_RESOURCE, if at the first
9439ec7b004SRick Macklem 		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
9449ec7b004SRick Macklem 		 * really nasty for certain Op sequences, I'll play it safe
9459ec7b004SRick Macklem 		 * and only return the error at the beginning.) The cache
9469ec7b004SRick Macklem 		 * will still function over flood level, but uses lots of
9479ec7b004SRick Macklem 		 * mbufs.)
9489ec7b004SRick Macklem 		 * If nfsrv_mallocmget_limit() returns True, the system is near
9499ec7b004SRick Macklem 		 * to its limit for memory that malloc()/mget() can allocate.
9509ec7b004SRick Macklem 		 */
951c59e4cc3SRick Macklem 		if (i == 0 && (nd->nd_rp == NULL ||
952c59e4cc3SRick Macklem 		    nd->nd_rp->rc_refcnt == 0) &&
9539ec7b004SRick Macklem 		    (nfsrv_mallocmget_limit() ||
9547e44856eSRick Macklem 		     NFSD_VNET(nfsrc_tcpsavedreplies) >
9557e44856eSRick Macklem 		     NFSD_VNET(nfsrc_floodlevel))) {
9567e44856eSRick Macklem 			if (NFSD_VNET(nfsrc_tcpsavedreplies) >
9577e44856eSRick Macklem 			    NFSD_VNET(nfsrc_floodlevel))
95803738f60SRick Macklem 				printf("nfsd server cache flooded, try "
95903738f60SRick Macklem 				    "increasing vfs.nfsd.tcphighwater\n");
9609ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_RESOURCE;
9619ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
9629ec7b004SRick Macklem 			if (op == NFSV4OP_SETATTR) {
9639ec7b004SRick Macklem 				/*
9649ec7b004SRick Macklem 				 * Setattr replies require a bitmap.
9659ec7b004SRick Macklem 				 * even for errors like these.
9669ec7b004SRick Macklem 				 */
9679ec7b004SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
9689ec7b004SRick Macklem 				*tl = 0;
9699ec7b004SRick Macklem 			}
9709ec7b004SRick Macklem 			retops++;
9719ec7b004SRick Macklem 			break;
9729ec7b004SRick Macklem 		}
973ff2f1f69SRick Macklem 
974ff2f1f69SRick Macklem 		/*
975ff2f1f69SRick Macklem 		 * Check for the case of SP4_MACH_CRED and an operation in
976ff2f1f69SRick Macklem 		 * the allow set.  For these operations, replace nd_cred with
977ff2f1f69SRick Macklem 		 * root credentials so that the operation will not fail due
978ff2f1f69SRick Macklem 		 * to credentials.
979ff2f1f69SRick Macklem 		 * NB: ND_MACHCRED is set by Sequence when the ClientID
980ff2f1f69SRick Macklem 		 * specifies LCL_MACHCRED and the RPC is being performed
981ff2f1f69SRick Macklem 		 * via krb5i or krb5p using the machine principal.
982ff2f1f69SRick Macklem 		 */
983ff2f1f69SRick Macklem 		if ((nd->nd_flag & ND_MACHCRED) != 0) {
984ff2f1f69SRick Macklem 			if (NFSISSET_OPBIT(&nd->nd_allowops, op)) {
985ff2f1f69SRick Macklem 				/* Replace nd_cred with root creds. */
986ff2f1f69SRick Macklem 				if (rootcred == NULL)
987ff2f1f69SRick Macklem 					rootcred = nfsrv_createrootcred();
988ff2f1f69SRick Macklem 				if (savecred == NULL)
989ff2f1f69SRick Macklem 					savecred = nd->nd_cred;
990ff2f1f69SRick Macklem 				nd->nd_cred = rootcred;
991ff2f1f69SRick Macklem 			} else if (savecred != NULL) {
992ff2f1f69SRick Macklem 				nd->nd_cred = savecred;
993ff2f1f69SRick Macklem 				savecred = NULL;
994ff2f1f69SRick Macklem 			}
995ff2f1f69SRick Macklem 		}
996ff2f1f69SRick Macklem 
9979ec7b004SRick Macklem 		if (nfsv4_opflag[op].savereply)
9989ec7b004SRick Macklem 			nd->nd_flag |= ND_SAVEREPLY;
9999ec7b004SRick Macklem 		switch (op) {
10009ec7b004SRick Macklem 		case NFSV4OP_PUTFH:
10019ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &fh);
10029ec7b004SRick Macklem 			if (error)
10039ec7b004SRick Macklem 				goto nfsmout;
1004d224f05fSRick Macklem 			if ((nd->nd_flag & ND_LASTOP) == 0) {
1005d224f05fSRick Macklem 				/*
1006d224f05fSRick Macklem 				 * Pre-parse the next op#.  If it is
1007d224f05fSRick Macklem 				 * SaveFH, count it and skip to the
1008d224f05fSRick Macklem 				 * next op#, if not the last op#.
1009d224f05fSRick Macklem 				 * nextop is used to determine if
1010d224f05fSRick Macklem 				 * NFSERR_WRONGSEC can be returned,
1011d224f05fSRick Macklem 				 * per RFC5661 Sec. 2.6.
1012d224f05fSRick Macklem 				 */
1013d224f05fSRick Macklem 				do {
1014d224f05fSRick Macklem 					NFSM_DISSECT(tl, uint32_t *,
1015d224f05fSRick Macklem 					    NFSX_UNSIGNED);
1016d224f05fSRick Macklem 					nextop = fxdr_unsigned(int, *tl);
1017d224f05fSRick Macklem 					if (nextop == NFSV4OP_SAVEFH &&
1018d224f05fSRick Macklem 					    i < numops - 1)
1019d224f05fSRick Macklem 						savefhcnt++;
1020d224f05fSRick Macklem 				} while (nextop == NFSV4OP_SAVEFH &&
1021d224f05fSRick Macklem 				    i < numops - 1);
1022d224f05fSRick Macklem 			}
10238974bc2fSRick Macklem 			if (!nd->nd_repstat)
10248974bc2fSRick Macklem 				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
1025a5df139eSRick Macklem 				    NULL, 0, nextop);
10269ec7b004SRick Macklem 			/* For now, allow this for non-export FHs */
10279ec7b004SRick Macklem 			if (!nd->nd_repstat) {
10289ec7b004SRick Macklem 				if (vp)
10299ec7b004SRick Macklem 					vrele(vp);
10309ec7b004SRick Macklem 				vp = nvp;
10318974bc2fSRick Macklem 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1032b249ce48SMateusz Guzik 				NFSVOPUNLOCK(vp);
10339ec7b004SRick Macklem 				vpnes = nes;
10349ec7b004SRick Macklem 			}
10359ec7b004SRick Macklem 			break;
10369ec7b004SRick Macklem 		case NFSV4OP_PUTPUBFH:
1037d224f05fSRick Macklem 			if (nfs_pubfhset) {
1038d224f05fSRick Macklem 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1039d224f05fSRick Macklem 					/*
1040d224f05fSRick Macklem 					 * Pre-parse the next op#.  If it is
1041d224f05fSRick Macklem 					 * SaveFH, count it and skip to the
1042d224f05fSRick Macklem 					 * next op#, if not the last op#.
1043d224f05fSRick Macklem 					 * nextop is used to determine if
1044d224f05fSRick Macklem 					 * NFSERR_WRONGSEC can be returned,
1045d224f05fSRick Macklem 					 * per RFC5661 Sec. 2.6.
1046d224f05fSRick Macklem 					 */
1047d224f05fSRick Macklem 					do {
1048d224f05fSRick Macklem 						NFSM_DISSECT(tl, uint32_t *,
1049d224f05fSRick Macklem 						    NFSX_UNSIGNED);
1050d224f05fSRick Macklem 						nextop = fxdr_unsigned(int,
1051d224f05fSRick Macklem 						    *tl);
1052d224f05fSRick Macklem 						if (nextop == NFSV4OP_SAVEFH &&
1053d224f05fSRick Macklem 						    i < numops - 1)
1054d224f05fSRick Macklem 							savefhcnt++;
1055d224f05fSRick Macklem 					} while (nextop == NFSV4OP_SAVEFH &&
1056d224f05fSRick Macklem 					    i < numops - 1);
1057d224f05fSRick Macklem 				}
105817891d00SRick Macklem 				nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
1059a5df139eSRick Macklem 				    &nes, NULL, 0, nextop);
1060d224f05fSRick Macklem 			} else
10619ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
10629ec7b004SRick Macklem 			if (!nd->nd_repstat) {
10639ec7b004SRick Macklem 				if (vp)
10649ec7b004SRick Macklem 					vrele(vp);
10659ec7b004SRick Macklem 				vp = nvp;
10668974bc2fSRick Macklem 				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1067b249ce48SMateusz Guzik 				NFSVOPUNLOCK(vp);
10689ec7b004SRick Macklem 				vpnes = nes;
10699ec7b004SRick Macklem 			}
10709ec7b004SRick Macklem 			break;
10719ec7b004SRick Macklem 		case NFSV4OP_PUTROOTFH:
10727e44856eSRick Macklem 			if (NFSD_VNET(nfs_rootfhset)) {
1073d224f05fSRick Macklem 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1074d224f05fSRick Macklem 					/*
1075d224f05fSRick Macklem 					 * Pre-parse the next op#.  If it is
1076d224f05fSRick Macklem 					 * SaveFH, count it and skip to the
1077d224f05fSRick Macklem 					 * next op#, if not the last op#.
1078d224f05fSRick Macklem 					 * nextop is used to determine if
1079d224f05fSRick Macklem 					 * NFSERR_WRONGSEC can be returned,
1080d224f05fSRick Macklem 					 * per RFC5661 Sec. 2.6.
1081d224f05fSRick Macklem 					 */
1082d224f05fSRick Macklem 					do {
1083d224f05fSRick Macklem 						NFSM_DISSECT(tl, uint32_t *,
1084d224f05fSRick Macklem 						    NFSX_UNSIGNED);
1085d224f05fSRick Macklem 						nextop = fxdr_unsigned(int,
1086d224f05fSRick Macklem 						    *tl);
1087d224f05fSRick Macklem 						if (nextop == NFSV4OP_SAVEFH &&
1088d224f05fSRick Macklem 						    i < numops - 1)
1089d224f05fSRick Macklem 							savefhcnt++;
1090d224f05fSRick Macklem 					} while (nextop == NFSV4OP_SAVEFH &&
1091d224f05fSRick Macklem 					    i < numops - 1);
1092d224f05fSRick Macklem 				}
10937e44856eSRick Macklem 				nfsd_fhtovp(nd, &NFSD_VNET(nfs_rootfh),
10947e44856eSRick Macklem 				    LK_SHARED, &nvp, &nes, NULL, 0, nextop);
10959ec7b004SRick Macklem 				if (!nd->nd_repstat) {
10969ec7b004SRick Macklem 					if (vp)
10979ec7b004SRick Macklem 						vrele(vp);
10989ec7b004SRick Macklem 					vp = nvp;
10998974bc2fSRick Macklem 					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
1100b249ce48SMateusz Guzik 					NFSVOPUNLOCK(vp);
11019ec7b004SRick Macklem 					vpnes = nes;
11029ec7b004SRick Macklem 				}
1103c9aad40fSRick Macklem 			} else
11049ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
11059ec7b004SRick Macklem 			break;
11069ec7b004SRick Macklem 		case NFSV4OP_SAVEFH:
11079ec7b004SRick Macklem 			if (vp && NFSVNO_EXPORTED(&vpnes)) {
11089ec7b004SRick Macklem 				nd->nd_repstat = 0;
11099ec7b004SRick Macklem 				/* If vp == savevp, a no-op */
11109ec7b004SRick Macklem 				if (vp != savevp) {
11119ec7b004SRick Macklem 					if (savevp)
11129ec7b004SRick Macklem 						vrele(savevp);
11139ec7b004SRick Macklem 					VREF(vp);
11149ec7b004SRick Macklem 					savevp = vp;
11159ec7b004SRick Macklem 					savevpnes = vpnes;
11168974bc2fSRick Macklem 					save_fsid = cur_fsid;
11179ec7b004SRick Macklem 				}
111890d2dfabSRick Macklem 				if ((nd->nd_flag & ND_CURSTATEID) != 0) {
111990d2dfabSRick Macklem 					nd->nd_savedcurstateid =
112090d2dfabSRick Macklem 					    nd->nd_curstateid;
112190d2dfabSRick Macklem 					nd->nd_flag |= ND_SAVEDCURSTATEID;
112290d2dfabSRick Macklem 				}
11239ec7b004SRick Macklem 			} else {
11249ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
11259ec7b004SRick Macklem 			}
11269ec7b004SRick Macklem 			break;
11279ec7b004SRick Macklem 		case NFSV4OP_RESTOREFH:
11289ec7b004SRick Macklem 			if (savevp) {
1129d224f05fSRick Macklem 				if ((nd->nd_flag & ND_LASTOP) == 0) {
1130d224f05fSRick Macklem 					/*
1131d224f05fSRick Macklem 					 * Pre-parse the next op#.  If it is
1132d224f05fSRick Macklem 					 * SaveFH, count it and skip to the
1133d224f05fSRick Macklem 					 * next op#, if not the last op#.
1134d224f05fSRick Macklem 					 * nextop is used to determine if
1135d224f05fSRick Macklem 					 * NFSERR_WRONGSEC can be returned,
1136d224f05fSRick Macklem 					 * per RFC5661 Sec. 2.6.
1137d224f05fSRick Macklem 					 */
1138d224f05fSRick Macklem 					do {
1139d224f05fSRick Macklem 						NFSM_DISSECT(tl, uint32_t *,
1140d224f05fSRick Macklem 						    NFSX_UNSIGNED);
1141d224f05fSRick Macklem 						nextop = fxdr_unsigned(int,
1142d224f05fSRick Macklem 						    *tl);
1143d224f05fSRick Macklem 						if (nextop == NFSV4OP_SAVEFH &&
1144d224f05fSRick Macklem 						    i < numops - 1)
1145d224f05fSRick Macklem 							savefhcnt++;
1146d224f05fSRick Macklem 					} while (nextop == NFSV4OP_SAVEFH &&
1147d224f05fSRick Macklem 					    i < numops - 1);
1148d224f05fSRick Macklem 				}
11499ec7b004SRick Macklem 				nd->nd_repstat = 0;
11509ec7b004SRick Macklem 				/* If vp == savevp, a no-op */
11519ec7b004SRick Macklem 				if (vp != savevp) {
1152a5df139eSRick Macklem 					if (nfsrv_checkwrongsec(nd, nextop,
1153a5df139eSRick Macklem 					    savevp->v_type))
1154a5df139eSRick Macklem 						nd->nd_repstat =
1155a5df139eSRick Macklem 						    nfsvno_testexp(nd,
1156a5df139eSRick Macklem 						    &savevpnes);
1157a5df139eSRick Macklem 					if (nd->nd_repstat == 0) {
11589ec7b004SRick Macklem 						VREF(savevp);
11599ec7b004SRick Macklem 						vrele(vp);
11609ec7b004SRick Macklem 						vp = savevp;
11619ec7b004SRick Macklem 						vpnes = savevpnes;
11628974bc2fSRick Macklem 						cur_fsid = save_fsid;
11639ec7b004SRick Macklem 					}
1164a5df139eSRick Macklem 				}
1165a5df139eSRick Macklem 				if (nd->nd_repstat == 0 &&
1166a5df139eSRick Macklem 				     (nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
116790d2dfabSRick Macklem 					nd->nd_curstateid =
116890d2dfabSRick Macklem 					    nd->nd_savedcurstateid;
116990d2dfabSRick Macklem 					nd->nd_flag |= ND_CURSTATEID;
117090d2dfabSRick Macklem 				}
11719ec7b004SRick Macklem 			} else {
11729ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_RESTOREFH;
11739ec7b004SRick Macklem 			}
11749ec7b004SRick Macklem 			break;
11759ec7b004SRick Macklem 		default:
11769ec7b004SRick Macklem 		    /*
11779ec7b004SRick Macklem 		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
11789ec7b004SRick Macklem 		     * non-exported directory if
11799ec7b004SRick Macklem 		     * nfs_rootfhset. Do I need to allow any other Ops?
11809ec7b004SRick Macklem 		     * (You can only have a non-exported vpnes if
11819ec7b004SRick Macklem 		     *  nfs_rootfhset is true. See nfsd_fhtovp())
11829ec7b004SRick Macklem 		     * Allow AUTH_SYS to be used for file systems
11839ec7b004SRick Macklem 		     * exported GSS only for certain Ops, to allow
11849ec7b004SRick Macklem 		     * clients to do mounts more easily.
11859ec7b004SRick Macklem 		     */
11869ec7b004SRick Macklem 		    if (nfsv4_opflag[op].needscfh && vp) {
11879ec7b004SRick Macklem 			if (!NFSVNO_EXPORTED(&vpnes) &&
11889ec7b004SRick Macklem 			    op != NFSV4OP_LOOKUP &&
11899ec7b004SRick Macklem 			    op != NFSV4OP_GETATTR &&
11909ec7b004SRick Macklem 			    op != NFSV4OP_GETFH &&
11915a55e04fSRick Macklem 			    op != NFSV4OP_ACCESS &&
11925a55e04fSRick Macklem 			    op != NFSV4OP_READLINK &&
1193a5df139eSRick Macklem 			    op != NFSV4OP_SECINFO &&
1194a5df139eSRick Macklem 			    op != NFSV4OP_SECINFONONAME)
11959ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
11969ec7b004SRick Macklem 			if (nd->nd_repstat) {
11979ec7b004SRick Macklem 				if (op == NFSV4OP_SETATTR) {
11989ec7b004SRick Macklem 				    /*
11999ec7b004SRick Macklem 				     * Setattr reply requires a bitmap
12009ec7b004SRick Macklem 				     * even for errors like these.
12019ec7b004SRick Macklem 				     */
12029ec7b004SRick Macklem 				    NFSM_BUILD(tl, u_int32_t *,
12039ec7b004SRick Macklem 					NFSX_UNSIGNED);
12049ec7b004SRick Macklem 				    *tl = 0;
12059ec7b004SRick Macklem 				}
12069ec7b004SRick Macklem 				break;
12079ec7b004SRick Macklem 			}
12089ec7b004SRick Macklem 		    }
1209774a3685SRick Macklem 
1210774a3685SRick Macklem 		    /*
1211774a3685SRick Macklem 		     * Save the current positions in the mbuf lists so
1212774a3685SRick Macklem 		     * that a rollback to this location can be done upon a
1213774a3685SRick Macklem 		     * redo due to a ERELOOKUP return for a operation.
1214774a3685SRick Macklem 		     */
1215774a3685SRick Macklem 		    mb = nd->nd_mb;
1216774a3685SRick Macklem 		    bpos = nd->nd_bpos;
1217774a3685SRick Macklem 		    bextpg = nd->nd_bextpg;
1218774a3685SRick Macklem 		    bextpgsiz = nd->nd_bextpgsiz;
1219774a3685SRick Macklem 		    md = nd->nd_md;
1220774a3685SRick Macklem 		    dpos = nd->nd_dpos;
1221774a3685SRick Macklem tryagain:
1222774a3685SRick Macklem 
12239ec7b004SRick Macklem 		    if (nfsv4_opflag[op].retfh == 1) {
12249ec7b004SRick Macklem 			if (!vp) {
12259ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
12269ec7b004SRick Macklem 				break;
12279ec7b004SRick Macklem 			}
1228a5df139eSRick Macklem 			if (NFSVNO_EXPORTED(&vpnes) && (op == NFSV4OP_LOOKUP ||
1229a5df139eSRick Macklem 			    op == NFSV4OP_LOOKUPP || (op == NFSV4OP_OPEN &&
1230a5df139eSRick Macklem 			    vp->v_type == VDIR))) {
1231a5df139eSRick Macklem 				/* Check for wrong security. */
1232a5df139eSRick Macklem 				rstat = nfsvno_testexp(nd, &vpnes);
1233a5df139eSRick Macklem 				if (rstat != 0) {
1234a5df139eSRick Macklem 					nd->nd_repstat = rstat;
1235a5df139eSRick Macklem 					break;
1236a5df139eSRick Macklem 				}
1237a5df139eSRick Macklem 			}
12389ec7b004SRick Macklem 			VREF(vp);
12399ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
1240785f073bSRick Macklem 				vn_start_write(vp, &temp_mp, V_WAIT);
12419ec7b004SRick Macklem 			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
1242af444b18SEdward Tomasz Napierala 			    &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);
12439ec7b004SRick Macklem 			if (!error && !nd->nd_repstat) {
12448974bc2fSRick Macklem 			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
12458974bc2fSRick Macklem 				new_mp = nvp->v_mount;
1246245bfd34SRyan Moeller 				if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) {
12478974bc2fSRick Macklem 				    /* crossed a server mount point */
12488974bc2fSRick Macklem 				    nd->nd_repstat = nfsvno_checkexp(new_mp,
12499ec7b004SRick Macklem 					nd->nd_nam, &nes, &credanon);
12509ec7b004SRick Macklem 				    if (!nd->nd_repstat)
12519ec7b004SRick Macklem 					nd->nd_repstat = nfsd_excred(nd,
1252a5df139eSRick Macklem 					    &nes, credanon, true);
12535679fe19SAlexander Kabaev 				    if (credanon != NULL)
12545679fe19SAlexander Kabaev 					crfree(credanon);
12559ec7b004SRick Macklem 				    if (!nd->nd_repstat) {
12569ec7b004SRick Macklem 					vpnes = nes;
12578974bc2fSRick Macklem 					cur_fsid = new_mp->mnt_stat.f_fsid;
12589ec7b004SRick Macklem 				    }
12599ec7b004SRick Macklem 				}
126081f78d99SRick Macklem 				/* Lookup ops return a locked vnode */
1261b249ce48SMateusz Guzik 				NFSVOPUNLOCK(nvp);
12628974bc2fSRick Macklem 			    }
12639ec7b004SRick Macklem 			    if (!nd->nd_repstat) {
12649ec7b004SRick Macklem 				    vrele(vp);
12659ec7b004SRick Macklem 				    vp = nvp;
126681f78d99SRick Macklem 			    } else
126781f78d99SRick Macklem 				    vrele(nvp);
12689ec7b004SRick Macklem 			}
12699ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
1270785f073bSRick Macklem 				vn_finished_write(temp_mp);
12719ec7b004SRick Macklem 		    } else if (nfsv4_opflag[op].retfh == 2) {
12729ec7b004SRick Macklem 			if (vp == NULL || savevp == NULL) {
12739ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_NOFILEHANDLE;
12749ec7b004SRick Macklem 				break;
1275245bfd34SRyan Moeller 			} else if (fsidcmp(&cur_fsid, &save_fsid) != 0) {
12769ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_XDEV;
12779ec7b004SRick Macklem 				break;
12789ec7b004SRick Macklem 			}
12799ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
1280785f073bSRick Macklem 				vn_start_write(savevp, &temp_mp, V_WAIT);
128198f234f3SZack Kirsch 			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
1282629fa50eSRick Macklem 				VREF(vp);
1283629fa50eSRick Macklem 				VREF(savevp);
1284629fa50eSRick Macklem 				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
1285af444b18SEdward Tomasz Napierala 				    savevp, vp, &savevpnes, &vpnes);
1286629fa50eSRick Macklem 			} else
1287629fa50eSRick Macklem 				nd->nd_repstat = NFSERR_PERM;
12889ec7b004SRick Macklem 			if (nfsv4_opflag[op].modifyfs)
1289785f073bSRick Macklem 				vn_finished_write(temp_mp);
12909ec7b004SRick Macklem 		    } else {
12919ec7b004SRick Macklem 			if (nfsv4_opflag[op].retfh != 0)
12929ec7b004SRick Macklem 				panic("nfsrvd_compound");
12939ec7b004SRick Macklem 			if (nfsv4_opflag[op].needscfh) {
129417891d00SRick Macklem 				if (vp != NULL) {
12950c419e22SRick Macklem 					lktype = nfsv4_opflag[op].lktype;
12960c419e22SRick Macklem 					if (nfsv4_opflag[op].modifyfs) {
1297785f073bSRick Macklem 						vn_start_write(vp, &temp_mp,
1298785f073bSRick Macklem 						    V_WAIT);
12990c419e22SRick Macklem 						if (op == NFSV4OP_WRITE &&
13000c419e22SRick Macklem 						    MNT_SHARED_WRITES(temp_mp))
13010c419e22SRick Macklem 							lktype = LK_SHARED;
13020c419e22SRick Macklem 					}
13030c419e22SRick Macklem 					if (NFSVOPLOCK(vp, lktype) == 0)
1304629fa50eSRick Macklem 						VREF(vp);
1305629fa50eSRick Macklem 					else
130617891d00SRick Macklem 						nd->nd_repstat = NFSERR_PERM;
1307629fa50eSRick Macklem 				} else {
13089ec7b004SRick Macklem 					nd->nd_repstat = NFSERR_NOFILEHANDLE;
13099ec7b004SRick Macklem 					if (op == NFSV4OP_SETATTR) {
13109ec7b004SRick Macklem 						/*
131117891d00SRick Macklem 						 * Setattr reply requires a
131217891d00SRick Macklem 						 * bitmap even for errors like
131317891d00SRick Macklem 						 * these.
13149ec7b004SRick Macklem 						 */
13159ec7b004SRick Macklem 						NFSM_BUILD(tl, u_int32_t *,
13169ec7b004SRick Macklem 						    NFSX_UNSIGNED);
13179ec7b004SRick Macklem 						*tl = 0;
13189ec7b004SRick Macklem 					}
13199ec7b004SRick Macklem 					break;
13209ec7b004SRick Macklem 				}
1321947bd247SRick Macklem 				if (nd->nd_repstat == 0) {
1322629fa50eSRick Macklem 					error = (*(nfsrv4_ops0[op]))(nd,
1323af444b18SEdward Tomasz Napierala 					    isdgram, vp, &vpnes);
1324947bd247SRick Macklem 					if ((op == NFSV4OP_SECINFO ||
1325947bd247SRick Macklem 					     op == NFSV4OP_SECINFONONAME) &&
1326947bd247SRick Macklem 					    error == 0 && nd->nd_repstat == 0) {
1327947bd247SRick Macklem 						/*
1328947bd247SRick Macklem 						 * Secinfo and Secinfo_no_name
1329947bd247SRick Macklem 						 * consume the current FH.
1330947bd247SRick Macklem 						 */
1331947bd247SRick Macklem 						vrele(vp);
1332947bd247SRick Macklem 						vp = NULL;
1333947bd247SRick Macklem 					}
1334947bd247SRick Macklem 				}
13359ec7b004SRick Macklem 				if (nfsv4_opflag[op].modifyfs)
1336785f073bSRick Macklem 					vn_finished_write(temp_mp);
13379ec7b004SRick Macklem 			} else {
13389ec7b004SRick Macklem 				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
1339af444b18SEdward Tomasz Napierala 				    NULL, &vpnes);
13409ec7b004SRick Macklem 			}
13419ec7b004SRick Macklem 		    }
134274b8d63dSPedro F. Giffuni 		}
13439ec7b004SRick Macklem 		if (error) {
13449ec7b004SRick Macklem 			if (error == EBADRPC || error == NFSERR_BADXDR) {
13459ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_BADXDR;
13469ec7b004SRick Macklem 			} else {
13479ec7b004SRick Macklem 				nd->nd_repstat = error;
13489ec7b004SRick Macklem 				printf("nfsv4 comperr0=%d\n", error);
13499ec7b004SRick Macklem 			}
13509ec7b004SRick Macklem 			error = 0;
13519ec7b004SRick Macklem 		}
13521b819cf2SRick Macklem 
1353774a3685SRick Macklem 		if (nd->nd_repstat == ERELOOKUP) {
1354774a3685SRick Macklem 			/*
1355774a3685SRick Macklem 			 * Roll back to the beginning of the operation
1356774a3685SRick Macklem 			 * arguments.
1357774a3685SRick Macklem 			 */
1358774a3685SRick Macklem 			nd->nd_md = md;
1359774a3685SRick Macklem 			nd->nd_dpos = dpos;
1360774a3685SRick Macklem 
1361774a3685SRick Macklem 			/*
1362774a3685SRick Macklem 			 * Trim off the bogus reply for this operation
1363774a3685SRick Macklem 			 * and redo the operation.
1364774a3685SRick Macklem 			 */
1365774a3685SRick Macklem 			nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);
1366774a3685SRick Macklem 			nd->nd_repstat = 0;
1367dc78533aSRick Macklem 			nd->nd_flag |= ND_ERELOOKUP;
1368774a3685SRick Macklem 			goto tryagain;
1369774a3685SRick Macklem 		}
1370dc78533aSRick Macklem 		nd->nd_flag &= ~ND_ERELOOKUP;
1371774a3685SRick Macklem 
13721b819cf2SRick Macklem 		if (statsinprog != 0) {
13731b819cf2SRick Macklem 			nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
13741b819cf2SRick Macklem 			    /*then*/ &start_time);
13751b819cf2SRick Macklem 			statsinprog = 0;
13761b819cf2SRick Macklem 		}
13771b819cf2SRick Macklem 
13789ec7b004SRick Macklem 		retops++;
13799ec7b004SRick Macklem 		if (nd->nd_repstat) {
13809ec7b004SRick Macklem 			*repp = nfsd_errmap(nd);
13819ec7b004SRick Macklem 			break;
13829ec7b004SRick Macklem 		} else {
13839ec7b004SRick Macklem 			*repp = 0;	/* NFS4_OK */
13849ec7b004SRick Macklem 		}
13859ec7b004SRick Macklem 	}
13869ec7b004SRick Macklem nfsmout:
13871b819cf2SRick Macklem 	if (statsinprog != 0) {
13881b819cf2SRick Macklem 		nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
13891b819cf2SRick Macklem 		    /*then*/ &start_time);
13901b819cf2SRick Macklem 		statsinprog = 0;
13911b819cf2SRick Macklem 	}
13929ec7b004SRick Macklem 	if (error) {
13939ec7b004SRick Macklem 		if (error == EBADRPC || error == NFSERR_BADXDR)
13949ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
13959ec7b004SRick Macklem 		else
13969ec7b004SRick Macklem 			printf("nfsv4 comperr1=%d\n", error);
13979ec7b004SRick Macklem 	}
13989ec7b004SRick Macklem 	if (taglen == -1) {
13999ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
14009ec7b004SRick Macklem 		*tl++ = 0;
14019ec7b004SRick Macklem 		*tl = 0;
14029ec7b004SRick Macklem 	} else {
14039ec7b004SRick Macklem 		*retopsp = txdr_unsigned(retops);
14049ec7b004SRick Macklem 	}
14059ec7b004SRick Macklem 	if (vp)
14069ec7b004SRick Macklem 		vrele(vp);
14079ec7b004SRick Macklem 	if (savevp)
14089ec7b004SRick Macklem 		vrele(savevp);
1409ff2f1f69SRick Macklem 	if (savecred != NULL)
1410ff2f1f69SRick Macklem 		nd->nd_cred = savecred;
1411ff2f1f69SRick Macklem 	if (rootcred != NULL)
1412ff2f1f69SRick Macklem 		crfree(rootcred);
14139ec7b004SRick Macklem 	NFSLOCKV4ROOTMUTEX();
14149ec7b004SRick Macklem 	nfsv4_relref(&nfsv4rootfs_lock);
14159ec7b004SRick Macklem 	NFSUNLOCKV4ROOTMUTEX();
1416a9285ae5SZack Kirsch 
1417a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
14189ec7b004SRick Macklem }
1419ff2f1f69SRick Macklem 
1420ff2f1f69SRick Macklem /* Create a credential for "root". */
1421ff2f1f69SRick Macklem static struct ucred *
nfsrv_createrootcred(void)1422ff2f1f69SRick Macklem nfsrv_createrootcred(void)
1423ff2f1f69SRick Macklem {
1424ff2f1f69SRick Macklem 	struct ucred *cr;
1425ff2f1f69SRick Macklem 	gid_t grp;
1426ff2f1f69SRick Macklem 
1427ff2f1f69SRick Macklem 	cr = crget();
1428ff2f1f69SRick Macklem 	cr->cr_uid = cr->cr_ruid = cr->cr_svuid = UID_ROOT;
1429ff2f1f69SRick Macklem 	grp = GID_WHEEL;
1430ff2f1f69SRick Macklem 	crsetgroups(cr, 1, &grp);
1431ff2f1f69SRick Macklem 	cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
1432ff2f1f69SRick Macklem 	cr->cr_prison = curthread->td_ucred->cr_prison;
1433ff2f1f69SRick Macklem 	prison_hold(cr->cr_prison);
1434ff2f1f69SRick Macklem #ifdef MAC
1435ff2f1f69SRick Macklem 	mac_cred_associate_nfsd(cr);
1436ff2f1f69SRick Macklem #endif
1437ff2f1f69SRick Macklem 	return (cr);
1438ff2f1f69SRick Macklem }
1439