nfs_nfsdsocket.c revision 284216
117200Swollman/*-
22742Swollman * Copyright (c) 1989, 1993
32742Swollman *	The Regents of the University of California.  All rights reserved.
42742Swollman *
52742Swollman * This code is derived from software contributed to Berkeley by
62742Swollman * Rick Macklem at The University of Guelph.
714343Swollman *
82742Swollman * Redistribution and use in source and binary forms, with or without
92742Swollman * modification, are permitted provided that the following conditions
102742Swollman * are met:
112742Swollman * 1. Redistributions of source code must retain the above copyright
122742Swollman *    notice, this list of conditions and the following disclaimer.
132742Swollman * 2. Redistributions in binary form must reproduce the above copyright
142742Swollman *    notice, this list of conditions and the following disclaimer in the
152742Swollman *    documentation and/or other materials provided with the distribution.
162742Swollman * 4. Neither the name of the University nor the names of its contributors
172742Swollman *    may be used to endorse or promote products derived from this software
182742Swollman *    without specific prior written permission.
192742Swollman *
202742Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
212742Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222742Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232742Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
242742Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
252742Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
262742Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
272742Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
282742Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
292742Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
302742Swollman * SUCH DAMAGE.
312742Swollman *
322742Swollman */
332742Swollman
342742Swollman#include <sys/cdefs.h>
3514343Swollman__FBSDID("$FreeBSD: stable/10/sys/fs/nfsserver/nfs_nfsdsocket.c 284216 2015-06-10 12:17:19Z rmacklem $");
3614343Swollman
3714343Swollman/*
3814343Swollman * Socket operations for use by the nfs server.
3917200Swollman */
4014343Swollman
4114343Swollman#ifndef APPLEKEXT
4214343Swollman#include <fs/nfs/nfsport.h>
4314343Swollman
4414343Swollmanextern struct nfsstats newnfsstats;
4514343Swollmanextern struct nfsrvfh nfs_pubfh, nfs_rootfh;
462742Swollmanextern int nfs_pubfhset, nfs_rootfhset;
472742Swollmanextern struct nfsv4lock nfsv4rootfs_lock;
482742Swollmanextern struct nfsrv_stablefirst nfsrv_stablefirst;
492742Swollmanextern struct nfsclienthashhead *nfsclienthash;
502742Swollmanextern int nfsrv_clienthashsize;
512742Swollmanextern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
522742Swollmanextern int nfsd_debuglevel;
532742SwollmanNFSV4ROOTLOCKMUTEX;
542742SwollmanNFSSTATESPINLOCK;
552742Swollman
569908Swollmanint (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
5714343Swollman    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
589908Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
599908Swollman	nfsrvd_getattr,
609908Swollman	nfsrvd_setattr,
619908Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
629908Swollman	nfsrvd_access,
639908Swollman	nfsrvd_readlink,
649908Swollman	nfsrvd_read,
659908Swollman	nfsrvd_write,
669908Swollman	nfsrvd_create,
679908Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
6814343Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
6914343Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
709908Swollman	nfsrvd_remove,
719908Swollman	nfsrvd_remove,
729908Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
739908Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
749908Swollman	nfsrvd_readdir,
759908Swollman	nfsrvd_readdirplus,
769908Swollman	nfsrvd_statfs,
772742Swollman	nfsrvd_fsinfo,
782742Swollman	nfsrvd_pathconf,
792742Swollman	nfsrvd_commit,
802742Swollman};
812742Swollman
822742Swollmanint (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
832742Swollman    int, vnode_t , vnode_t *, fhandle_t *,
842742Swollman    NFSPROC_T *, struct nfsexstuff *) = {
852742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
862742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
872742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
882742Swollman	nfsrvd_lookup,
892742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
902742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
912742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
922742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
932742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
942742Swollman	nfsrvd_mkdir,
952742Swollman	nfsrvd_symlink,
962742Swollman	nfsrvd_mknod,
972742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
982742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
992742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1002742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1012742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1022742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1032742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1042742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1052742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1062742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
1072742Swollman};
1082742Swollman
1092742Swollmanint (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
1102742Swollman    int, vnode_t , vnode_t , NFSPROC_T *,
1112742Swollman    struct nfsexstuff *, struct nfsexstuff *) = {
1122742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1132742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1142742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1152742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1162742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1172742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1182742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1192742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1202742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1212742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1222742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1232742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1242742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1252742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
1262742Swollman	nfsrvd_rename,
1272742Swollman	nfsrvd_link,
12817200Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
12917200Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
13017200Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
13117200Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
13217200Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
13317200Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
13417200Swollman};
13517200Swollman
13617200Swollmanint (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *,
1372742Swollman    int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
1382742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1392742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1402742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1412742Swollman	nfsrvd_access,
1422742Swollman	nfsrvd_close,
1432742Swollman	nfsrvd_commit,
1442742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1452742Swollman	nfsrvd_delegpurge,
1462742Swollman	nfsrvd_delegreturn,
1472742Swollman	nfsrvd_getattr,
1482742Swollman	nfsrvd_getfh,
1492742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1502742Swollman	nfsrvd_lock,
1512742Swollman	nfsrvd_lockt,
1522742Swollman	nfsrvd_locku,
1532742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1542742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1552742Swollman	nfsrvd_verify,
1562742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1572742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1582742Swollman	nfsrvd_openconfirm,
1592742Swollman	nfsrvd_opendowngrade,
1602742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1612742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1622742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1632742Swollman	nfsrvd_read,
1642742Swollman	nfsrvd_readdirplus,
1652742Swollman	nfsrvd_readlink,
1662742Swollman	nfsrvd_remove,
1672742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1682742Swollman	nfsrvd_renew,
1692742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1702742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
1712742Swollman	nfsrvd_secinfo,
1722742Swollman	nfsrvd_setattr,
1732742Swollman	nfsrvd_setclientid,
1742742Swollman	nfsrvd_setclientidcfrm,
1752742Swollman	nfsrvd_verify,
1762742Swollman	nfsrvd_write,
1772742Swollman	nfsrvd_releaselckown,
1782742Swollman	nfsrvd_notsupp,
1792742Swollman	nfsrvd_notsupp,
1802742Swollman	nfsrvd_exchangeid,
1812742Swollman	nfsrvd_createsession,
1822742Swollman	nfsrvd_destroysession,
1832742Swollman	nfsrvd_freestateid,
1842742Swollman	nfsrvd_notsupp,
1852742Swollman	nfsrvd_notsupp,
1862742Swollman	nfsrvd_notsupp,
1872742Swollman	nfsrvd_notsupp,
1882742Swollman	nfsrvd_notsupp,
1892742Swollman	nfsrvd_notsupp,
1902742Swollman	nfsrvd_notsupp,
1912742Swollman	nfsrvd_sequence,
1922742Swollman	nfsrvd_notsupp,
1932742Swollman	nfsrvd_notsupp,
1942742Swollman	nfsrvd_notsupp,
1952742Swollman	nfsrvd_destroyclientid,
1962742Swollman	nfsrvd_reclaimcomplete,
1972742Swollman};
1982742Swollman
1992742Swollmanint (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
2002742Swollman    int, vnode_t , vnode_t *, fhandle_t *,
2012742Swollman    NFSPROC_T *, struct nfsexstuff *) = {
2022742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2032742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2042742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2052742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2062742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2072742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2082742Swollman	nfsrvd_mknod,
2092742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2102742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2112742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2122742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2132742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2142742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2152742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2162742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2172742Swollman	nfsrvd_lookup,
2182742Swollman	nfsrvd_lookup,
2192742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2202742Swollman	nfsrvd_open,
2212742Swollman	nfsrvd_openattr,
2222742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2232742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2242742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2252742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2262742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2272742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2282742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2292742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2302742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2312742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2322742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2332742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2342742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2352742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2362742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2372742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2382742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2392742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2402742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2412742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2422742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2432742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2442742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2452742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2462742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2472742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2482742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2492742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2502742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2512742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2522742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2532742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2542742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2552742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2562742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2572742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2582742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2592742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2602742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
2612742Swollman};
2622742Swollman
2632742Swollmanint (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
2642742Swollman    int, vnode_t , vnode_t , NFSPROC_T *,
2652742Swollman    struct nfsexstuff *, struct nfsexstuff *) = {
2662742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2672742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2682742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2692742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2702742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2712742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2722742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2732742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2742742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2752742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2762742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2772742Swollman	nfsrvd_link,
2782742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2792742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2802742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2812742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2822742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2832742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2842742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2852742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2862742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2872742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2882742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2892742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2902742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2912742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2922742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2932742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2942742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2952742Swollman	nfsrvd_rename,
2962742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2972742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2982742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
2992742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3002742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3012742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3022742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3032742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3042742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3052742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3062742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3072742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3082742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3092742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3102742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3112742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3122742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3132742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3142742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3152742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3162742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3172742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3182742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3192742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3202742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3212742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3222742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3232742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3242742Swollman	(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
3252742Swollman};
3262742Swollman#endif	/* !APPLEKEXT */
3272742Swollman
3282742Swollman/*
3292742Swollman * Static array that defines which nfs rpc's are nonidempotent
3302742Swollman */
3312742Swollmanstatic int nfsrv_nonidempotent[NFS_V3NPROCS] = {
3322742Swollman	FALSE,
3332742Swollman	FALSE,
3342742Swollman	TRUE,
3352742Swollman	FALSE,
3362742Swollman	FALSE,
3372742Swollman	FALSE,
3382742Swollman	FALSE,
3392742Swollman	TRUE,
3402742Swollman	TRUE,
3412742Swollman	TRUE,
3422742Swollman	TRUE,
3432742Swollman	TRUE,
3442742Swollman	TRUE,
3452742Swollman	TRUE,
3462742Swollman	TRUE,
3472742Swollman	TRUE,
3482742Swollman	FALSE,
3492742Swollman	FALSE,
3502742Swollman	FALSE,
3512742Swollman	FALSE,
3522742Swollman	FALSE,
3532742Swollman	FALSE,
3542742Swollman};
3552742Swollman
3562742Swollman/*
3572742Swollman * This static array indicates whether or not the RPC modifies the
3582742Swollman * file system.
3592742Swollman */
3602742Swollmanstatic int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
3612742Swollman    1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
3622742Swollman    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
3632742Swollman
3642742Swollman/* local functions */
3652742Swollmanstatic void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
3662742Swollman    u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p);
3672742Swollman
3682742Swollman
3692742Swollman/*
3702742Swollman * This static array indicates which server procedures require the extra
3712742Swollman * arguments to return the current file handle for V2, 3.
3722742Swollman */
3732742Swollmanstatic int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
3742742Swollman	1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
3752742Swollman
3762742Swollmanextern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
3772742Swollman
3782742Swollmanstatic int nfsv3to4op[NFS_V3NPROCS] = {
3792742Swollman	NFSPROC_NULL,
3802742Swollman	NFSV4OP_GETATTR,
3812742Swollman	NFSV4OP_SETATTR,
3822742Swollman	NFSV4OP_LOOKUP,
3832742Swollman	NFSV4OP_ACCESS,
3842742Swollman	NFSV4OP_READLINK,
3852742Swollman	NFSV4OP_READ,
3862742Swollman	NFSV4OP_WRITE,
3872742Swollman	NFSV4OP_V3CREATE,
3882742Swollman	NFSV4OP_MKDIR,
3892742Swollman	NFSV4OP_SYMLINK,
3902742Swollman	NFSV4OP_MKNOD,
3912742Swollman	NFSV4OP_REMOVE,
3922742Swollman	NFSV4OP_RMDIR,
3932742Swollman	NFSV4OP_RENAME,
3942742Swollman	NFSV4OP_LINK,
3952742Swollman	NFSV4OP_READDIR,
3962742Swollman	NFSV4OP_READDIRPLUS,
3972742Swollman	NFSV4OP_FSSTAT,
3982742Swollman	NFSV4OP_FSINFO,
3992742Swollman	NFSV4OP_PATHCONF,
4002742Swollman	NFSV4OP_COMMIT,
4012742Swollman};
4022742Swollman
4032742Swollman/*
4042742Swollman * Do an RPC. Basically, get the file handles translated to vnode pointers
4052742Swollman * and then call the appropriate server routine. The server routines are
4062742Swollman * split into groups, based on whether they use a file handle or file
4072742Swollman * handle plus name or ...
4089908Swollman * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
4092742Swollman */
4102742SwollmanAPPLESTATIC void
4112742Swollmannfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
4122742Swollman    u_int32_t minorvers, NFSPROC_T *p)
4132742Swollman{
4142742Swollman	int error = 0, lktype;
4152742Swollman	vnode_t vp;
4162742Swollman	mount_t mp = NULL;
4172742Swollman	struct nfsrvfh fh;
4182742Swollman	struct nfsexstuff nes;
4192742Swollman
4202742Swollman	/*
4212742Swollman	 * Get a locked vnode for the first file handle
4222742Swollman	 */
4232742Swollman	if (!(nd->nd_flag & ND_NFSV4)) {
4242742Swollman		KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
4252742Swollman		/*
4262742Swollman		 * For NFSv3, if the malloc/mget allocation is near limits,
4272742Swollman		 * return NFSERR_DELAY.
4282742Swollman		 */
4292742Swollman		if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
43017200Swollman			nd->nd_repstat = NFSERR_DELAY;
43117200Swollman			vp = NULL;
43217200Swollman		} else {
43317200Swollman			error = nfsrv_mtofh(nd, &fh);
43417200Swollman			if (error) {
43517200Swollman				if (error != EBADRPC)
43617200Swollman					printf("nfs dorpc err1=%d\n", error);
43717200Swollman				nd->nd_repstat = NFSERR_GARBAGE;
43817200Swollman				goto out;
43917200Swollman			}
44017200Swollman			if (nd->nd_procnum == NFSPROC_READ ||
44117200Swollman			    nd->nd_procnum == NFSPROC_WRITE ||
44217200Swollman			    nd->nd_procnum == NFSPROC_READDIR ||
44317200Swollman			    nd->nd_procnum == NFSPROC_READLINK ||
44417200Swollman			    nd->nd_procnum == NFSPROC_GETATTR ||
44517200Swollman			    nd->nd_procnum == NFSPROC_ACCESS)
4462742Swollman				lktype = LK_SHARED;
4472742Swollman			else
4482742Swollman				lktype = LK_EXCLUSIVE;
4492742Swollman			if (nd->nd_flag & ND_PUBLOOKUP)
4502742Swollman				nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
4512742Swollman				    &mp, nfs_writerpc[nd->nd_procnum], p);
4522742Swollman			else
4532742Swollman				nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
4542742Swollman				    &mp, nfs_writerpc[nd->nd_procnum], p);
4552742Swollman			if (nd->nd_repstat == NFSERR_PROGNOTV4)
4562742Swollman				goto out;
4572742Swollman		}
4582742Swollman	}
4592742Swollman
4602742Swollman	/*
4612742Swollman	 * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
4622742Swollman	 * cache, as required.
4632742Swollman	 * For V4, nfsrvd_compound() does this.
4642742Swollman	 */
4652742Swollman	if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
4662742Swollman		nd->nd_flag |= ND_SAVEREPLY;
4672742Swollman
4682742Swollman	nfsrvd_rephead(nd);
4692742Swollman	/*
4702742Swollman	 * If nd_repstat is non-zero, just fill in the reply status
4712742Swollman	 * to complete the RPC reply for V2. Otherwise, you must do
4722742Swollman	 * the RPC.
4739908Swollman	 */
4742742Swollman	if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
4752742Swollman		*nd->nd_errp = nfsd_errmap(nd);
4762742Swollman		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
4772742Swollman		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
4782742Swollman			vn_finished_write(mp);
4792742Swollman		goto out;
4802742Swollman	}
4812742Swollman
4822742Swollman	/*
4832742Swollman	 * Now the procedure can be performed. For V4, nfsrvd_compound()
4842742Swollman	 * works through the sub-rpcs, otherwise just call the procedure.
4852742Swollman	 * The procedures are in three groups with different arguments.
4862742Swollman	 * The group is indicated by the value in nfs_retfh[].
4872742Swollman	 */
4882742Swollman	if (nd->nd_flag & ND_NFSV4) {
4892742Swollman		nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
4902742Swollman	} else {
4912742Swollman		if (nfs_retfh[nd->nd_procnum] == 1) {
4922742Swollman			if (vp)
4932742Swollman				NFSVOPUNLOCK(vp, 0);
4942742Swollman			error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
4952742Swollman			    vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
4962742Swollman		} else if (nfs_retfh[nd->nd_procnum] == 2) {
4972742Swollman			error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
4982742Swollman			    vp, NULL, p, &nes, NULL);
4992742Swollman		} else {
5002742Swollman			error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
5012742Swollman			    vp, p, &nes);
5022742Swollman		}
5032742Swollman		if (mp != NULL && nfs_writerpc[nd->nd_procnum] != 0)
5042742Swollman			vn_finished_write(mp);
5052742Swollman		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
5062742Swollman	}
5072742Swollman	if (error) {
5082742Swollman		if (error != EBADRPC)
5092742Swollman			printf("nfs dorpc err2=%d\n", error);
5102742Swollman		nd->nd_repstat = NFSERR_GARBAGE;
5112742Swollman	}
5122742Swollman	*nd->nd_errp = nfsd_errmap(nd);
5132742Swollman
5142742Swollman	/*
5152742Swollman	 * Don't cache certain reply status values.
5162742Swollman	 */
5172742Swollman	if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
5182742Swollman	    (nd->nd_repstat == NFSERR_GARBAGE ||
5192742Swollman	     nd->nd_repstat == NFSERR_BADXDR ||
5202742Swollman	     nd->nd_repstat == NFSERR_MOVED ||
5212742Swollman	     nd->nd_repstat == NFSERR_DELAY ||
5222742Swollman	     nd->nd_repstat == NFSERR_BADSEQID ||
5232742Swollman	     nd->nd_repstat == NFSERR_RESOURCE ||
5242742Swollman	     nd->nd_repstat == NFSERR_SERVERFAULT ||
5252742Swollman	     nd->nd_repstat == NFSERR_STALECLIENTID ||
5262742Swollman	     nd->nd_repstat == NFSERR_STALESTATEID ||
5272742Swollman	     nd->nd_repstat == NFSERR_OLDSTATEID ||
5282742Swollman	     nd->nd_repstat == NFSERR_BADSTATEID ||
5292742Swollman	     nd->nd_repstat == NFSERR_GRACE ||
5302742Swollman	     nd->nd_repstat == NFSERR_NOGRACE))
5312742Swollman		nd->nd_flag &= ~ND_SAVEREPLY;
5322742Swollman
5332742Swollmanout:
5342742Swollman	NFSEXITCODE2(0, nd);
5352742Swollman}
5362742Swollman
5372742Swollman/*
5382742Swollman * Breaks down a compound RPC request and calls the server routines for
5392742Swollman * the subprocedures.
5402742Swollman * Some suboperations are performed directly here to simplify file handle<-->
5412742Swollman * vnode pointer handling.
5422742Swollman */
5432742Swollmanstatic void
5442742Swollmannfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
5452742Swollman    int taglen, u_int32_t minorvers, NFSPROC_T *p)
5462742Swollman{
5472742Swollman	int i, op, op0 = 0;
5482742Swollman	u_int32_t *tl;
5492742Swollman	struct nfsclient *clp, *nclp;
5502742Swollman	int numops, error = 0, igotlock;
5512742Swollman	u_int32_t retops = 0, *retopsp = NULL, *repp;
5522742Swollman	vnode_t vp, nvp, savevp;
5532742Swollman	struct nfsrvfh fh;
5542742Swollman	mount_t new_mp, temp_mp = NULL;
5552742Swollman	struct ucred *credanon;
5562742Swollman	struct nfsexstuff nes, vpnes, savevpnes;
5572742Swollman	fsid_t cur_fsid, save_fsid;
5582742Swollman	static u_int64_t compref = 0;
5592742Swollman
5602742Swollman	NFSVNO_EXINIT(&vpnes);
5612742Swollman	NFSVNO_EXINIT(&savevpnes);
5622742Swollman	/*
5632742Swollman	 * Put the seq# of the current compound RPC in nfsrv_descript.
5642742Swollman	 * (This is used by nfsrv_checkgetattr(), to see if the write
5652742Swollman	 *  delegation was created by the same compound RPC as the one
5662742Swollman	 *  with that Getattr in it.)
5672742Swollman	 * Don't worry about the 64bit number wrapping around. It ain't
5682742Swollman	 * gonna happen before this server gets shut down/rebooted.
5692742Swollman	 */
5702742Swollman	nd->nd_compref = compref++;
5712742Swollman
5722742Swollman	/*
5732742Swollman	 * Check for and optionally get a lock on the root. This lock means that
5742742Swollman	 * no nfsd will be fiddling with the V4 file system and state stuff. It
5752742Swollman	 * is required when the V4 root is being changed, the stable storage
5762742Swollman	 * restart file is being updated, or callbacks are being done.
5772742Swollman	 * When any of the nfsd are processing an NFSv4 compound RPC, they must
5782742Swollman	 * either hold a reference count (nfs_usecnt) or the lock. When
5792742Swollman	 * nfsrv_unlock() is called to release the lock, it can optionally
5802742Swollman	 * also get a reference count, which saves the need for a call to
5812742Swollman	 * nfsrv_getref() after nfsrv_unlock().
5822742Swollman	 */
5832742Swollman	/*
5842742Swollman	 * First, check to see if we need to wait for an update lock.
5852742Swollman	 */
5862742Swollman	igotlock = 0;
5872742Swollman	NFSLOCKV4ROOTMUTEX();
5882742Swollman	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
5892742Swollman		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
5902742Swollman		    NFSV4ROOTLOCKMUTEXPTR, NULL);
5912742Swollman	else
5922742Swollman		igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
5932742Swollman		    NFSV4ROOTLOCKMUTEXPTR, NULL);
5942742Swollman	NFSUNLOCKV4ROOTMUTEX();
5952742Swollman	if (igotlock) {
5962742Swollman		/*
5972742Swollman		 * If I got the lock, I can update the stable storage file.
5982742Swollman		 * Done when the grace period is over or a client has long
5992742Swollman		 * since expired.
6002742Swollman		 */
6012742Swollman		nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
6022742Swollman		if ((nfsrv_stablefirst.nsf_flags &
6032742Swollman		    (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
6042742Swollman			nfsrv_updatestable(p);
6052742Swollman
6062742Swollman		/*
6072742Swollman		 * If at least one client has long since expired, search
6082742Swollman		 * the client list for them, write a REVOKE record on the
6092742Swollman		 * stable storage file and then remove them from the client
6102742Swollman		 * list.
6119908Swollman		 */
6129908Swollman		if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
6139908Swollman			nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
6149908Swollman			for (i = 0; i < nfsrv_clienthashsize; i++) {
6159908Swollman			    LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
6169908Swollman				nclp) {
6172742Swollman				if (clp->lc_flags & LCL_EXPIREIT) {
6182742Swollman				    if (!LIST_EMPTY(&clp->lc_open) ||
6192742Swollman					!LIST_EMPTY(&clp->lc_deleg))
6202742Swollman					nfsrv_writestable(clp->lc_id,
6212742Swollman					    clp->lc_idlen, NFSNST_REVOKE, p);
6229908Swollman				    nfsrv_cleanclient(clp, p);
6239908Swollman				    nfsrv_freedeleglist(&clp->lc_deleg);
6249908Swollman				    nfsrv_freedeleglist(&clp->lc_olddeleg);
6259908Swollman				    LIST_REMOVE(clp, lc_hash);
6269908Swollman				    nfsrv_zapclient(clp, p);
6279908Swollman				}
62817200Swollman			    }
62917200Swollman			}
63017200Swollman		}
63117200Swollman		NFSLOCKV4ROOTMUTEX();
63217200Swollman		nfsv4_unlock(&nfsv4rootfs_lock, 1);
6332742Swollman		NFSUNLOCKV4ROOTMUTEX();
6342742Swollman	} else {
63514343Swollman		/*
63614343Swollman		 * If we didn't get the lock, we need to get a refcnt,
6372742Swollman		 * which also checks for and waits for the lock.
6382742Swollman		 */
6392742Swollman		NFSLOCKV4ROOTMUTEX();
6402742Swollman		nfsv4_getref(&nfsv4rootfs_lock, NULL,
6412742Swollman		    NFSV4ROOTLOCKMUTEXPTR, NULL);
6422742Swollman		NFSUNLOCKV4ROOTMUTEX();
6432742Swollman	}
6442742Swollman
64517200Swollman	/*
6462742Swollman	 * If flagged, search for open owners that haven't had any opens
6472742Swollman	 * for a long time.
6482742Swollman	 */
6492742Swollman	if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
6502742Swollman		nfsrv_throwawayopens(p);
6512742Swollman	}
6522742Swollman
6532742Swollman	savevp = vp = NULL;
6542742Swollman	save_fsid.val[0] = save_fsid.val[1] = 0;
6552742Swollman	cur_fsid.val[0] = cur_fsid.val[1] = 0;
6562742Swollman
6572742Swollman	/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
6582742Swollman	if (taglen < 0) {
6592742Swollman		error = EBADRPC;
6602742Swollman		goto nfsmout;
6612742Swollman	}
6622742Swollman
6632742Swollman	(void) nfsm_strtom(nd, tag, taglen);
6642742Swollman	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
66517200Swollman	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
66617200Swollman	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
66717200Swollman		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
6682742Swollman	if (nd->nd_repstat)
66917200Swollman		numops = 0;
67017200Swollman	else
6712742Swollman		numops = fxdr_unsigned(int, *tl);
6722742Swollman	/*
6732742Swollman	 * Loop around doing the sub ops.
67417200Swollman	 * vp - is an unlocked vnode pointer for the CFH
6752742Swollman	 * savevp - is an unlocked vnode pointer for the SAVEDFH
67617200Swollman	 * (at some future date, it might turn out to be more appropriate
6772742Swollman	 *  to keep the file handles instead of vnode pointers?)
6782742Swollman	 * savevpnes and vpnes - are the export flags for the above.
67917200Swollman	 */
68017200Swollman	for (i = 0; i < numops; i++) {
68117200Swollman		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
68217200Swollman		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
68317200Swollman		*repp = *tl;
68417200Swollman		op = fxdr_unsigned(int, *tl);
68517200Swollman		NFSD_DEBUG(4, "op=%d\n", op);
68617200Swollman		if (op < NFSV4OP_ACCESS ||
6872742Swollman		    (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
6882742Swollman		    (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
6892742Swollman			nd->nd_repstat = NFSERR_OPILLEGAL;
6902742Swollman			*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
6912742Swollman			*repp = nfsd_errmap(nd);
6922742Swollman			retops++;
6932742Swollman			break;
6942742Swollman		} else {
6952742Swollman			repp++;
6962742Swollman		}
6972742Swollman		if (i == 0)
6982742Swollman			op0 = op;
6992742Swollman		if (i == numops - 1)
7002742Swollman			nd->nd_flag |= ND_LASTOP;
7012742Swollman
7022742Swollman		/*
7032742Swollman		 * Check for a referral on the current FH and, if so, return
7042742Swollman		 * NFSERR_MOVED for all ops that allow it, except Getattr.
7052742Swollman		 */
7062742Swollman		if (vp != NULL && op != NFSV4OP_GETATTR &&
7072742Swollman		    nfsv4root_getreferral(vp, NULL, 0) != NULL &&
7082742Swollman		    nfsrv_errmoved(op)) {
7092742Swollman			nd->nd_repstat = NFSERR_MOVED;
7102742Swollman			*repp = nfsd_errmap(nd);
7112742Swollman			retops++;
7122742Swollman			break;
7132742Swollman		}
7142742Swollman
7152742Swollman		/*
7162742Swollman		 * For NFSv4.1, check for a Sequence Operation being first
7172742Swollman		 * or one of the other allowed operations by itself.
7182742Swollman		 */
7192742Swollman		if ((nd->nd_flag & ND_NFSV41) != 0) {
7202742Swollman			if (i != 0 && op == NFSV4OP_SEQUENCE)
7212742Swollman				nd->nd_repstat = NFSERR_SEQUENCEPOS;
7222742Swollman			else if (i == 0 && op != NFSV4OP_SEQUENCE &&
7232742Swollman			    op != NFSV4OP_EXCHANGEID &&
7242742Swollman			    op != NFSV4OP_CREATESESSION &&
7252742Swollman			    op != NFSV4OP_BINDCONNTOSESS &&
7262742Swollman			    op != NFSV4OP_DESTROYCLIENTID &&
7272742Swollman			    op != NFSV4OP_DESTROYSESSION)
7282742Swollman				nd->nd_repstat = NFSERR_OPNOTINSESS;
7292742Swollman			else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
7302742Swollman				nd->nd_repstat = NFSERR_NOTONLYOP;
7312742Swollman			if (nd->nd_repstat != 0) {
7322742Swollman				*repp = nfsd_errmap(nd);
7332742Swollman				retops++;
7342742Swollman				break;
7352742Swollman			}
7362742Swollman		}
7372742Swollman
7382742Swollman		nd->nd_procnum = op;
7392742Swollman		/*
7402742Swollman		 * If over flood level, reply NFSERR_RESOURCE, if at the first
7412742Swollman		 * Op. (Since a client recovery from NFSERR_RESOURCE can get
7422742Swollman		 * really nasty for certain Op sequences, I'll play it safe
7432742Swollman		 * and only return the error at the beginning.) The cache
7442742Swollman		 * will still function over flood level, but uses lots of
7452742Swollman		 * mbufs.)
7462742Swollman		 * If nfsrv_mallocmget_limit() returns True, the system is near
7472742Swollman		 * to its limit for memory that malloc()/mget() can allocate.
7482742Swollman		 */
7492742Swollman		if (i == 0 && (nd->nd_rp == NULL ||
7502742Swollman		    nd->nd_rp->rc_refcnt == 0) &&
75117200Swollman		    (nfsrv_mallocmget_limit() ||
7522742Swollman		     nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
7532742Swollman			if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
7542742Swollman				printf("nfsd server cache flooded, try "
75517200Swollman				    "increasing vfs.nfsd.tcphighwater\n");
7562742Swollman			nd->nd_repstat = NFSERR_RESOURCE;
7579908Swollman			*repp = nfsd_errmap(nd);
7589908Swollman			if (op == NFSV4OP_SETATTR) {
7599908Swollman				/*
7609908Swollman				 * Setattr replies require a bitmap.
76117200Swollman				 * even for errors like these.
7622742Swollman				 */
7632742Swollman				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
7642742Swollman				*tl = 0;
76517200Swollman			}
76617200Swollman			retops++;
7679908Swollman			break;
76817200Swollman		}
7692742Swollman		if (nfsv4_opflag[op].savereply)
7702742Swollman			nd->nd_flag |= ND_SAVEREPLY;
7712742Swollman		NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
77217200Swollman		switch (op) {
77317200Swollman		case NFSV4OP_PUTFH:
7749908Swollman			error = nfsrv_mtofh(nd, &fh);
77517200Swollman			if (error)
7762742Swollman				goto nfsmout;
7772742Swollman			if (!nd->nd_repstat)
7782742Swollman				nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
77917200Swollman				    NULL, 0, p);
78017200Swollman			/* For now, allow this for non-export FHs */
78117200Swollman			if (!nd->nd_repstat) {
7822742Swollman				if (vp)
78317200Swollman					vrele(vp);
7842742Swollman				vp = nvp;
78517200Swollman				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
78617200Swollman				NFSVOPUNLOCK(vp, 0);
78717200Swollman				vpnes = nes;
78817200Swollman			}
7892742Swollman			break;
7908049Swollman		case NFSV4OP_PUTPUBFH:
7918049Swollman			if (nfs_pubfhset)
7928049Swollman			    nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
7938049Swollman				&nes, NULL, 0, p);
7942742Swollman			else
7952742Swollman			    nd->nd_repstat = NFSERR_NOFILEHANDLE;
7962742Swollman			if (!nd->nd_repstat) {
7972742Swollman				if (vp)
79817200Swollman					vrele(vp);
79917200Swollman				vp = nvp;
8009908Swollman				cur_fsid = vp->v_mount->mnt_stat.f_fsid;
8019908Swollman				NFSVOPUNLOCK(vp, 0);
80217200Swollman				vpnes = nes;
80317200Swollman			}
80417200Swollman			break;
80517200Swollman		case NFSV4OP_PUTROOTFH:
80617200Swollman			if (nfs_rootfhset) {
80717200Swollman				nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
8089908Swollman				    &nes, NULL, 0, p);
80917200Swollman				if (!nd->nd_repstat) {
8102742Swollman					if (vp)
8112742Swollman						vrele(vp);
8122742Swollman					vp = nvp;
8139908Swollman					cur_fsid = vp->v_mount->mnt_stat.f_fsid;
8142742Swollman					NFSVOPUNLOCK(vp, 0);
8159908Swollman					vpnes = nes;
8162742Swollman				}
8179908Swollman			} else
81817200Swollman				nd->nd_repstat = NFSERR_NOFILEHANDLE;
8192742Swollman			break;
8202742Swollman		case NFSV4OP_SAVEFH:
8212742Swollman			if (vp && NFSVNO_EXPORTED(&vpnes)) {
8222742Swollman				nd->nd_repstat = 0;
8232742Swollman				/* If vp == savevp, a no-op */
82417200Swollman				if (vp != savevp) {
8252742Swollman					if (savevp)
8262742Swollman						vrele(savevp);
8272742Swollman					VREF(vp);
8282742Swollman					savevp = vp;
8292742Swollman					savevpnes = vpnes;
8302742Swollman					save_fsid = cur_fsid;
8312742Swollman				}
8322742Swollman			} else {
8332742Swollman				nd->nd_repstat = NFSERR_NOFILEHANDLE;
8349908Swollman			}
8352742Swollman			break;
8369908Swollman		case NFSV4OP_RESTOREFH:
8372742Swollman			if (savevp) {
8382742Swollman				nd->nd_repstat = 0;
8392742Swollman				/* If vp == savevp, a no-op */
8402742Swollman				if (vp != savevp) {
8412742Swollman					VREF(savevp);
8422742Swollman					vrele(vp);
8432742Swollman					vp = savevp;
8442742Swollman					vpnes = savevpnes;
8452742Swollman					cur_fsid = save_fsid;
8462742Swollman				}
8472742Swollman			} else {
8482742Swollman				nd->nd_repstat = NFSERR_RESTOREFH;
8492742Swollman			}
8502742Swollman			break;
8512742Swollman		default:
8522742Swollman		    /*
8532742Swollman		     * Allow a Lookup, Getattr, GetFH, Secinfo on an
8542742Swollman		     * non-exported directory if
8552742Swollman		     * nfs_rootfhset. Do I need to allow any other Ops?
8562742Swollman		     * (You can only have a non-exported vpnes if
8572742Swollman		     *  nfs_rootfhset is true. See nfsd_fhtovp())
8582742Swollman		     * Allow AUTH_SYS to be used for file systems
8592742Swollman		     * exported GSS only for certain Ops, to allow
8602742Swollman		     * clients to do mounts more easily.
86117200Swollman		     */
8622742Swollman		    if (nfsv4_opflag[op].needscfh && vp) {
86317200Swollman			if (!NFSVNO_EXPORTED(&vpnes) &&
8642742Swollman			    op != NFSV4OP_LOOKUP &&
8652742Swollman			    op != NFSV4OP_GETATTR &&
8662742Swollman			    op != NFSV4OP_GETFH &&
8672742Swollman			    op != NFSV4OP_ACCESS &&
8682742Swollman			    op != NFSV4OP_READLINK &&
8692742Swollman			    op != NFSV4OP_SECINFO)
8702742Swollman				nd->nd_repstat = NFSERR_NOFILEHANDLE;
8712742Swollman			else if (nfsvno_testexp(nd, &vpnes) &&
8722742Swollman			    op != NFSV4OP_LOOKUP &&
8732742Swollman			    op != NFSV4OP_GETFH &&
8742742Swollman			    op != NFSV4OP_GETATTR &&
8752742Swollman			    op != NFSV4OP_SECINFO)
8762742Swollman				nd->nd_repstat = NFSERR_WRONGSEC;
8772742Swollman			if (nd->nd_repstat) {
8782742Swollman				if (op == NFSV4OP_SETATTR) {
8792742Swollman				    /*
8802742Swollman				     * Setattr reply requires a bitmap
8812742Swollman				     * even for errors like these.
8822742Swollman				     */
8832742Swollman				    NFSM_BUILD(tl, u_int32_t *,
8842742Swollman					NFSX_UNSIGNED);
8852742Swollman				    *tl = 0;
8862742Swollman				}
8872742Swollman				break;
8882742Swollman			}
8892742Swollman		    }
8902742Swollman		    if (nfsv4_opflag[op].retfh == 1) {
8912742Swollman			if (!vp) {
8922742Swollman				nd->nd_repstat = NFSERR_NOFILEHANDLE;
8932742Swollman				break;
8942742Swollman			}
8952742Swollman			VREF(vp);
8962742Swollman			if (nfsv4_opflag[op].modifyfs)
8972742Swollman				vn_start_write(vp, &temp_mp, V_WAIT);
8982742Swollman			error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
8992742Swollman			    &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
9002742Swollman			if (!error && !nd->nd_repstat) {
9012742Swollman			    if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
90217200Swollman				new_mp = nvp->v_mount;
9032742Swollman				if (cur_fsid.val[0] !=
9048049Swollman				    new_mp->mnt_stat.f_fsid.val[0] ||
9058049Swollman				    cur_fsid.val[1] !=
9062742Swollman				    new_mp->mnt_stat.f_fsid.val[1]) {
9072742Swollman				    /* crossed a server mount point */
9082742Swollman				    nd->nd_repstat = nfsvno_checkexp(new_mp,
9092742Swollman					nd->nd_nam, &nes, &credanon);
9102742Swollman				    if (!nd->nd_repstat)
91117200Swollman					nd->nd_repstat = nfsd_excred(nd,
9122742Swollman					    &nes, credanon);
9138049Swollman				    if (credanon != NULL)
9148049Swollman					crfree(credanon);
9152742Swollman				    if (!nd->nd_repstat) {
9162742Swollman					vpnes = nes;
9172742Swollman					cur_fsid = new_mp->mnt_stat.f_fsid;
9182742Swollman				    }
9192742Swollman				}
9202742Swollman				/* Lookup ops return a locked vnode */
9212742Swollman				NFSVOPUNLOCK(nvp, 0);
9222742Swollman			    }
9232742Swollman			    if (!nd->nd_repstat) {
9242742Swollman				    vrele(vp);
9252742Swollman				    vp = nvp;
9262742Swollman			    } else
9272742Swollman				    vrele(nvp);
9282742Swollman			}
9292742Swollman			if (nfsv4_opflag[op].modifyfs)
9309908Swollman				vn_finished_write(temp_mp);
93117200Swollman		    } else if (nfsv4_opflag[op].retfh == 2) {
9322742Swollman			if (vp == NULL || savevp == NULL) {
9338049Swollman				nd->nd_repstat = NFSERR_NOFILEHANDLE;
9348049Swollman				break;
9352742Swollman			} else if (cur_fsid.val[0] != save_fsid.val[0] ||
9362742Swollman			    cur_fsid.val[1] != save_fsid.val[1]) {
9372742Swollman				nd->nd_repstat = NFSERR_XDEV;
9382742Swollman				break;
9392742Swollman			}
9402742Swollman			if (nfsv4_opflag[op].modifyfs)
9412742Swollman				vn_start_write(savevp, &temp_mp, V_WAIT);
9422742Swollman			if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
94314343Swollman				VREF(vp);
94417200Swollman				VREF(savevp);
9452742Swollman				error = (*(nfsrv4_ops2[op]))(nd, isdgram,
9468049Swollman				    savevp, vp, p, &savevpnes, &vpnes);
9478049Swollman			} else
9482742Swollman				nd->nd_repstat = NFSERR_PERM;
9492742Swollman			if (nfsv4_opflag[op].modifyfs)
9502742Swollman				vn_finished_write(temp_mp);
9512742Swollman		    } else {
9522742Swollman			if (nfsv4_opflag[op].retfh != 0)
9532742Swollman				panic("nfsrvd_compound");
9542742Swollman			if (nfsv4_opflag[op].needscfh) {
9552742Swollman				if (vp != NULL) {
9562742Swollman					if (nfsv4_opflag[op].modifyfs)
9572742Swollman						vn_start_write(vp, &temp_mp,
9582742Swollman						    V_WAIT);
9592742Swollman					if (NFSVOPLOCK(vp, nfsv4_opflag[op].lktype)
9602742Swollman					    == 0)
9612742Swollman						VREF(vp);
9622742Swollman					else
9632742Swollman						nd->nd_repstat = NFSERR_PERM;
9642742Swollman				} else {
9652742Swollman					nd->nd_repstat = NFSERR_NOFILEHANDLE;
9662742Swollman					if (op == NFSV4OP_SETATTR) {
9672742Swollman						/*
9682742Swollman						 * Setattr reply requires a
9692742Swollman						 * bitmap even for errors like
9702742Swollman						 * these.
9712742Swollman						 */
9722742Swollman						NFSM_BUILD(tl, u_int32_t *,
9732742Swollman						    NFSX_UNSIGNED);
9742742Swollman						*tl = 0;
9752742Swollman					}
9762742Swollman					break;
9772742Swollman				}
9782742Swollman				if (nd->nd_repstat == 0)
9792742Swollman					error = (*(nfsrv4_ops0[op]))(nd,
9802742Swollman					    isdgram, vp, p, &vpnes);
9812742Swollman				if (nfsv4_opflag[op].modifyfs)
9822742Swollman					vn_finished_write(temp_mp);
9832742Swollman			} else {
9842742Swollman				error = (*(nfsrv4_ops0[op]))(nd, isdgram,
9852742Swollman				    NULL, p, &vpnes);
9862742Swollman			}
9872742Swollman		    }
9882742Swollman		};
9892742Swollman		if (error) {
9902742Swollman			if (error == EBADRPC || error == NFSERR_BADXDR) {
9912742Swollman				nd->nd_repstat = NFSERR_BADXDR;
9922742Swollman			} else {
9939908Swollman				nd->nd_repstat = error;
99417200Swollman				printf("nfsv4 comperr0=%d\n", error);
9952742Swollman			}
9968049Swollman			error = 0;
9978049Swollman		}
9982742Swollman		retops++;
9992742Swollman		if (nd->nd_repstat) {
10002742Swollman			*repp = nfsd_errmap(nd);
10012742Swollman			break;
10022742Swollman		} else {
10032742Swollman			*repp = 0;	/* NFS4_OK */
10042742Swollman		}
10059908Swollman	}
100617200Swollmannfsmout:
10072742Swollman	if (error) {
10088049Swollman		if (error == EBADRPC || error == NFSERR_BADXDR)
10098049Swollman			nd->nd_repstat = NFSERR_BADXDR;
10102742Swollman		else
10112742Swollman			printf("nfsv4 comperr1=%d\n", error);
10122742Swollman	}
10132742Swollman	if (taglen == -1) {
10142742Swollman		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
10152742Swollman		*tl++ = 0;
10162742Swollman		*tl = 0;
10172742Swollman	} else {
10182742Swollman		*retopsp = txdr_unsigned(retops);
10192742Swollman	}
10202742Swollman	if (vp)
10212742Swollman		vrele(vp);
10222742Swollman	if (savevp)
10232742Swollman		vrele(savevp);
10242742Swollman	NFSLOCKV4ROOTMUTEX();
10252742Swollman	nfsv4_relref(&nfsv4rootfs_lock);
10262742Swollman	NFSUNLOCKV4ROOTMUTEX();
102717200Swollman
10282742Swollman	NFSEXITCODE2(0, nd);
10298049Swollman}
10308049Swollman