Path: blob/main/sys/fs/nfsserver/nfs_nfsdsocket.c
105420 views
/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1989, 19934* The Regents of the University of California. All rights reserved.5*6* This code is derived from software contributed to Berkeley by7* Rick Macklem at The University of Guelph.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its contributors18* may be used to endorse or promote products derived from this software19* without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*33*/3435#include <sys/cdefs.h>36/*37* Socket operations for use by the nfs server.38*/3940#include <fs/nfs/nfsport.h>4142#include <security/mac/mac_framework.h>4344extern struct nfsrvfh nfs_pubfh;45extern int nfs_pubfhset;46extern struct nfsv4lock nfsv4rootfs_lock;47extern int nfsrv_clienthashsize;48extern int nfsd_debuglevel;49extern int nfsrv_layouthighwater;50extern volatile int nfsrv_layoutcnt;51NFSV4ROOTLOCKMUTEX;52NFSSTATESPINLOCK;5354NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst);55NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash);56NFSD_VNET_DECLARE(int, nfsrc_floodlevel);57NFSD_VNET_DECLARE(int, nfsrc_tcpsavedreplies);58NFSD_VNET_DECLARE(struct nfsrvfh, nfs_rootfh);59NFSD_VNET_DECLARE(int, nfs_rootfhset);60NFSD_VNET_DECLARE(struct nfsstatsv1 *, nfsstatsv1_p);6162int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,63int, vnode_t , struct nfsexstuff *) = {64(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,65nfsrvd_getattr,66nfsrvd_setattr,67(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,68nfsrvd_access,69nfsrvd_readlink,70nfsrvd_read,71nfsrvd_write,72nfsrvd_create,73(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,74(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,75(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,76nfsrvd_remove,77nfsrvd_remove,78(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,79(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,80nfsrvd_readdir,81nfsrvd_readdirplus,82nfsrvd_statfs,83nfsrvd_fsinfo,84nfsrvd_pathconf,85nfsrvd_commit,86};8788int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,89int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {90(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,91(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,92(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,93nfsrvd_lookup,94(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,95(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,96(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,97(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,98(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,99nfsrvd_mkdir,100nfsrvd_symlink,101nfsrvd_mknod,102(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,103(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,104(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,105(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,106(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,107(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,108(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,109(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,110(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,111(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,112};113114int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,115int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {116(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,117(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,118(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,119(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,120(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,121(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,122(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,123(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,124(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,125(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,126(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,127(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,128(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,129(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,130nfsrvd_rename,131nfsrvd_link,132(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,133(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,134(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,135(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,136(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,137(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,138};139140int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *,141int, vnode_t , struct nfsexstuff *) = {142(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,143(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,144(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,145nfsrvd_access,146nfsrvd_close,147nfsrvd_commit,148(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,149nfsrvd_delegpurge,150nfsrvd_delegreturn,151nfsrvd_getattr,152nfsrvd_getfh,153(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,154nfsrvd_lock,155nfsrvd_lockt,156nfsrvd_locku,157(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,158(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,159nfsrvd_verify,160(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,161(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,162nfsrvd_openconfirm,163nfsrvd_opendowngrade,164(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,165(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,166(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,167nfsrvd_read,168nfsrvd_readdirplus,169nfsrvd_readlink,170nfsrvd_remove,171(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,172nfsrvd_renew,173(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,174(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,175nfsrvd_secinfo,176nfsrvd_setattr,177nfsrvd_setclientid,178nfsrvd_setclientidcfrm,179nfsrvd_verify,180nfsrvd_write,181nfsrvd_releaselckown,182nfsrvd_notsupp,183nfsrvd_bindconnsess,184nfsrvd_exchangeid,185nfsrvd_createsession,186nfsrvd_destroysession,187nfsrvd_freestateid,188nfsrvd_notsupp,189nfsrvd_getdevinfo,190nfsrvd_notsupp,191nfsrvd_layoutcommit,192nfsrvd_layoutget,193nfsrvd_layoutreturn,194nfsrvd_secinfononame,195nfsrvd_sequence,196nfsrvd_notsupp,197nfsrvd_teststateid,198nfsrvd_notsupp,199nfsrvd_destroyclientid,200nfsrvd_reclaimcomplete,201nfsrvd_allocate,202(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,203nfsrvd_notsupp,204nfsrvd_deallocate,205nfsrvd_ioadvise,206nfsrvd_layouterror,207nfsrvd_layoutstats,208nfsrvd_notsupp,209nfsrvd_notsupp,210nfsrvd_notsupp,211nfsrvd_seek,212nfsrvd_notsupp,213nfsrvd_notsupp,214nfsrvd_getxattr,215nfsrvd_setxattr,216nfsrvd_listxattr,217nfsrvd_rmxattr,218};219220int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *,221int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = {222(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,223(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,224(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,225(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,226(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,227(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,228nfsrvd_mknod,229(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,230(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,231(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,232(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,233(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,234(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,235(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,236(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,237nfsrvd_lookup,238nfsrvd_lookup,239(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,240nfsrvd_open,241nfsrvd_openattr,242(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,243(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,244(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,245(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,246(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,247(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,248(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,249(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,250(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,251(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,252(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,253(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,254(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,255(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,256(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,257(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,258(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,259(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,260(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,261(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,262(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,263(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,264(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,265(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,266(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,267(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,268(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,269(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,270(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,271(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,272(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,273(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,274(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,275(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,276(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,277(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,278(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,279(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,280(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,281(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,282(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,283(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,284(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,285(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,286(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,287(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,288(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,289(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,290(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,291(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,292(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,293(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,294(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,295(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,296(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,297(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0,298};299300int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *,301int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = {302(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,303(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,304(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,305(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,306(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,307(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,308(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,309(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,310(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,311(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,312(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,313nfsrvd_link,314(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,315(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,316(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,317(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,318(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,319(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,320(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,321(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,322(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,323(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,324(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,325(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,326(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,327(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,328(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,329(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,330(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,331nfsrvd_rename,332(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,333(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,334(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,335(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,336(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,337(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,338(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,339(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,340(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,341(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,342(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,343(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,344(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,345(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,346(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,347(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,348(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,349(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,350(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,351(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,352(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,353(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,354(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,355(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,356(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,357(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,358(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,359(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,360(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,361(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,362nfsrvd_copy_file_range,363(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,364(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,365(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,366(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,367(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,368(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,369(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,370(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,371(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,372(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,373nfsrvd_clone,374(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,375(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,376(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,377(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,378};379380/*381* Static array that defines which nfs rpc's are nonidempotent382*/383static int nfsrv_nonidempotent[NFS_V3NPROCS] = {384FALSE,385FALSE,386TRUE,387FALSE,388FALSE,389FALSE,390FALSE,391TRUE,392TRUE,393TRUE,394TRUE,395TRUE,396TRUE,397TRUE,398TRUE,399TRUE,400FALSE,401FALSE,402FALSE,403FALSE,404FALSE,405FALSE,406};407408/*409* This static array indicates whether or not the RPC modifies the410* file system.411*/412int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,4131, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,4140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };415416SYSCTL_DECL(_vfs_nfsd);417static int nfs_minminorv4 = NFSV4_MINORVERSION;418SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN,419&nfs_minminorv4, 0,420"The lowest minor version of NFSv4 handled by the server");421422static int nfs_maxminorv4 = NFSV42_MINORVERSION;423SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN,424&nfs_maxminorv4, 0,425"The highest minor version of NFSv4 handled by the server");426427/* local functions */428static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,429u_char *tag, int taglen, u_int32_t minorvers);430431/*432* This static array indicates which server procedures require the extra433* arguments to return the current file handle for V2, 3.434*/435static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,4361, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };437438extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];439440static int nfsv3to4op[NFS_V3NPROCS] = {441NFSPROC_NULL,442NFSV4OP_GETATTR,443NFSV4OP_SETATTR,444NFSV4OP_LOOKUP,445NFSV4OP_ACCESS,446NFSV4OP_READLINK,447NFSV4OP_READ,448NFSV4OP_WRITE,449NFSV4OP_V3CREATE,450NFSV4OP_MKDIR,451NFSV4OP_SYMLINK,452NFSV4OP_MKNOD,453NFSV4OP_REMOVE,454NFSV4OP_RMDIR,455NFSV4OP_RENAME,456NFSV4OP_LINK,457NFSV4OP_READDIR,458NFSV4OP_READDIRPLUS,459NFSV4OP_FSSTAT,460NFSV4OP_FSINFO,461NFSV4OP_PATHCONF,462NFSV4OP_COMMIT,463};464465static struct mtx nfsrvd_statmtx;466MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);467468static struct ucred *nfsrv_createrootcred(void);469470static void471nfsrvd_statstart(int op, struct bintime *now)472{473if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {474printf("%s: op %d invalid\n", __func__, op);475return;476}477478mtx_lock(&nfsrvd_statmtx);479if (NFSD_VNET(nfsstatsv1_p)->srvstartcnt ==480NFSD_VNET(nfsstatsv1_p)->srvdonecnt) {481if (now != NULL)482NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;483else484binuptime(&NFSD_VNET(nfsstatsv1_p)->busyfrom);485486}487NFSD_VNET(nfsstatsv1_p)->srvrpccnt[op]++;488NFSD_VNET(nfsstatsv1_p)->srvstartcnt++;489mtx_unlock(&nfsrvd_statmtx);490491}492493static void494nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,495struct bintime *then)496{497struct bintime dt, lnow;498499if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {500printf("%s: op %d invalid\n", __func__, op);501return;502}503504if (now == NULL) {505now = &lnow;506binuptime(now);507}508509mtx_lock(&nfsrvd_statmtx);510511NFSD_VNET(nfsstatsv1_p)->srvbytes[op] += bytes;512NFSD_VNET(nfsstatsv1_p)->srvops[op]++;513514if (then != NULL) {515dt = *now;516bintime_sub(&dt, then);517bintime_add(&NFSD_VNET(nfsstatsv1_p)->srvduration[op], &dt);518}519520dt = *now;521bintime_sub(&dt, &NFSD_VNET(nfsstatsv1_p)->busyfrom);522bintime_add(&NFSD_VNET(nfsstatsv1_p)->busytime, &dt);523NFSD_VNET(nfsstatsv1_p)->busyfrom = *now;524525NFSD_VNET(nfsstatsv1_p)->srvdonecnt++;526527mtx_unlock(&nfsrvd_statmtx);528}529530/*531* Do an RPC. Basically, get the file handles translated to vnode pointers532* and then call the appropriate server routine. The server routines are533* split into groups, based on whether they use a file handle or file534* handle plus name or ...535* The NFS V4 Compound RPC is performed separately by nfsrvd_compound().536*/537void538nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,539u_int32_t minorvers)540{541int error = 0, lktype;542vnode_t vp;543mount_t mp;544struct nfsrvfh fh;545struct nfsexstuff nes;546struct mbuf *md;547char *dpos;548549/*550* Save the current position in the request mbuf list so551* that a rollback to this location can be done upon an552* ERELOOKUP error return from an RPC function.553*/554md = nd->nd_md;555dpos = nd->nd_dpos;556tryagain:557mp = NULL;558559/*560* Get a locked vnode for the first file handle561*/562if (!(nd->nd_flag & ND_NFSV4)) {563KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));564/*565* For NFSv3, if the malloc/mget allocation is near limits,566* return NFSERR_DELAY.567*/568if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {569nd->nd_repstat = NFSERR_DELAY;570vp = NULL;571} else {572error = nfsrv_mtofh(nd, &fh);573if (error) {574if (error != EBADRPC)575printf("nfs dorpc err1=%d\n", error);576nd->nd_repstat = NFSERR_GARBAGE;577goto out;578}579if (nd->nd_procnum == NFSPROC_READ ||580nd->nd_procnum == NFSPROC_WRITE ||581nd->nd_procnum == NFSPROC_READDIR ||582nd->nd_procnum == NFSPROC_READDIRPLUS ||583nd->nd_procnum == NFSPROC_READLINK ||584nd->nd_procnum == NFSPROC_GETATTR ||585nd->nd_procnum == NFSPROC_ACCESS ||586nd->nd_procnum == NFSPROC_FSSTAT ||587nd->nd_procnum == NFSPROC_FSINFO)588lktype = LK_SHARED;589else590lktype = LK_EXCLUSIVE;591if (nd->nd_flag & ND_PUBLOOKUP)592nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,593&mp, nfsrv_writerpc[nd->nd_procnum], -1);594else595nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,596&mp, nfsrv_writerpc[nd->nd_procnum], -1);597if (nd->nd_repstat == NFSERR_PROGNOTV4)598goto out;599}600}601602/*603* For V2 and 3, set the ND_SAVEREPLY flag for the recent request604* cache, as required.605* For V4, nfsrvd_compound() does this.606*/607if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])608nd->nd_flag |= ND_SAVEREPLY;609610nfsrvd_rephead(nd);611/*612* If nd_repstat is non-zero, just fill in the reply status613* to complete the RPC reply for V2. Otherwise, you must do614* the RPC.615*/616if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {617*nd->nd_errp = nfsd_errmap(nd);618nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);619nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,620/*now*/ NULL, /*then*/ NULL);621vn_finished_write(mp);622goto out;623}624625/*626* Now the procedure can be performed. For V4, nfsrvd_compound()627* works through the sub-rpcs, otherwise just call the procedure.628* The procedures are in three groups with different arguments.629* The group is indicated by the value in nfs_retfh[].630*/631if (nd->nd_flag & ND_NFSV4) {632nfsrvd_compound(nd, isdgram, tag, taglen, minorvers);633} else {634struct bintime start_time;635636binuptime(&start_time);637nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);638639if (nfs_retfh[nd->nd_procnum] == 1) {640if (vp)641NFSVOPUNLOCK(vp);642error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,643vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes);644} else if (nfs_retfh[nd->nd_procnum] == 2) {645error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,646vp, NULL, &nes, NULL);647} else {648error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,649vp, &nes);650}651vn_finished_write(mp);652653if (error == 0 && nd->nd_repstat == ERELOOKUP) {654/*655* Roll back to the beginning of the RPC request656* arguments.657*/658nd->nd_md = md;659nd->nd_dpos = dpos;660661/* Free the junk RPC reply and redo the RPC. */662m_freem(nd->nd_mreq);663nd->nd_mreq = nd->nd_mb = NULL;664nd->nd_repstat = 0;665goto tryagain;666}667668nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,669/*now*/ NULL, /*then*/ &start_time);670}671if (error) {672if (error != EBADRPC)673printf("nfs dorpc err2=%d\n", error);674nd->nd_repstat = NFSERR_GARBAGE;675}676*nd->nd_errp = nfsd_errmap(nd);677678/*679* Don't cache certain reply status values.680*/681if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&682(nd->nd_repstat == NFSERR_GARBAGE ||683nd->nd_repstat == NFSERR_BADXDR ||684nd->nd_repstat == NFSERR_MOVED ||685nd->nd_repstat == NFSERR_DELAY ||686nd->nd_repstat == NFSERR_BADSEQID ||687nd->nd_repstat == NFSERR_RESOURCE ||688nd->nd_repstat == NFSERR_SERVERFAULT ||689nd->nd_repstat == NFSERR_STALECLIENTID ||690nd->nd_repstat == NFSERR_STALESTATEID ||691nd->nd_repstat == NFSERR_OLDSTATEID ||692nd->nd_repstat == NFSERR_BADSTATEID ||693nd->nd_repstat == NFSERR_GRACE ||694nd->nd_repstat == NFSERR_NOGRACE))695nd->nd_flag &= ~ND_SAVEREPLY;696697out:698NFSEXITCODE2(0, nd);699}700701/*702* Breaks down a compound RPC request and calls the server routines for703* the subprocedures.704* Some suboperations are performed directly here to simplify file handle<-->705* vnode pointer handling.706*/707static void708nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,709int taglen, u_int32_t minorvers)710{711int i, lktype, op, op0 = 0, rstat, statsinprog = 0;712u_int32_t *tl;713struct nfsclient *clp, *nclp;714int error = 0, igotlock, nextop, numops, savefhcnt;715u_int32_t retops = 0, *retopsp = NULL, *repp;716vnode_t vp, nvp, savevp;717struct nfsrvfh fh;718mount_t new_mp, temp_mp = NULL;719struct ucred *credanon, *rootcred, *savecred;720struct nfsexstuff nes, vpnes, savevpnes;721fsid_t cur_fsid, save_fsid;722static u_int64_t compref = 0;723struct bintime start_time;724struct thread *p;725struct mbuf *mb, *md;726char *bpos, *dpos;727int bextpg, bextpgsiz;728729p = curthread;730rootcred = savecred = NULL;731732/* Check for and optionally clear the no space flags for DSs. */733nfsrv_checknospc();734735NFSVNO_EXINIT(&vpnes);736NFSVNO_EXINIT(&savevpnes);737/*738* Put the seq# of the current compound RPC in nfsrv_descript.739* (This is used by nfsrv_checkgetattr(), to see if the write740* delegation was created by the same compound RPC as the one741* with that Getattr in it.)742* Don't worry about the 64bit number wrapping around. It ain't743* gonna happen before this server gets shut down/rebooted.744*/745nd->nd_compref = compref++;746747/*748* Check for and optionally get a lock on the root. This lock means that749* no nfsd will be fiddling with the V4 file system and state stuff. It750* is required when the V4 root is being changed, the stable storage751* restart file is being updated, or callbacks are being done.752* When any of the nfsd are processing an NFSv4 compound RPC, they must753* either hold a reference count (nfs_usecnt) or the lock. When754* nfsrv_unlock() is called to release the lock, it can optionally755* also get a reference count, which saves the need for a call to756* nfsrv_getref() after nfsrv_unlock().757*/758/*759* First, check to see if we need to wait for an update lock.760*/761igotlock = 0;762NFSLOCKV4ROOTMUTEX();763if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NEEDLOCK)764igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,765NFSV4ROOTLOCKMUTEXPTR, NULL);766else767igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,768NFSV4ROOTLOCKMUTEXPTR, NULL);769NFSUNLOCKV4ROOTMUTEX();770if (igotlock) {771/*772* If I got the lock, I can update the stable storage file.773* Done when the grace period is over or a client has long774* since expired.775*/776NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_NEEDLOCK;777if ((NFSD_VNET(nfsrv_stablefirst).nsf_flags &778(NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)779nfsrv_updatestable(p);780781/*782* If at least one client has long since expired, search783* the client list for them, write a REVOKE record on the784* stable storage file and then remove them from the client785* list.786*/787if (NFSD_VNET(nfsrv_stablefirst).nsf_flags &788NFSNSF_EXPIREDCLIENT) {789NFSD_VNET(nfsrv_stablefirst).nsf_flags &=790~NFSNSF_EXPIREDCLIENT;791for (i = 0; i < nfsrv_clienthashsize; i++) {792LIST_FOREACH_SAFE(clp, &NFSD_VNET(nfsclienthash)[i],793lc_hash, nclp) {794if (clp->lc_flags & LCL_EXPIREIT) {795if (!LIST_EMPTY(&clp->lc_open) ||796!LIST_EMPTY(&clp->lc_deleg))797nfsrv_writestable(clp->lc_id,798clp->lc_idlen, NFSNST_REVOKE, p);799nfsrv_cleanclient(clp, p, false, NULL);800nfsrv_freedeleglist(&clp->lc_deleg);801nfsrv_freedeleglist(&clp->lc_olddeleg);802LIST_REMOVE(clp, lc_hash);803nfsrv_zapclient(clp, p);804}805}806}807}808NFSLOCKV4ROOTMUTEX();809nfsv4_unlock(&nfsv4rootfs_lock, 1);810NFSUNLOCKV4ROOTMUTEX();811} else {812/*813* If we didn't get the lock, we need to get a refcnt,814* which also checks for and waits for the lock.815*/816NFSLOCKV4ROOTMUTEX();817nfsv4_getref(&nfsv4rootfs_lock, NULL,818NFSV4ROOTLOCKMUTEXPTR, NULL);819NFSUNLOCKV4ROOTMUTEX();820}821822/*823* If flagged, search for open owners that haven't had any opens824* for a long time.825*/826if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NOOPENS) {827nfsrv_throwawayopens(p);828}829830/* Do a CBLAYOUTRECALL callback if over the high water mark. */831if (nfsrv_layoutcnt > nfsrv_layouthighwater)832nfsrv_recalloldlayout(p);833834savevp = vp = NULL;835save_fsid.val[0] = save_fsid.val[1] = 0;836cur_fsid.val[0] = cur_fsid.val[1] = 0;837nextop = -1;838savefhcnt = 0;839840/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */841if (taglen < 0) {842error = EBADRPC;843goto nfsmout;844}845846(void) nfsm_strtom(nd, tag, taglen);847NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);848NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);849if ((minorvers != NFSV4_MINORVERSION &&850minorvers != NFSV41_MINORVERSION &&851minorvers != NFSV42_MINORVERSION) ||852minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4)853nd->nd_repstat = NFSERR_MINORVERMISMATCH;854if (nd->nd_repstat)855numops = 0;856else857numops = fxdr_unsigned(int, *tl);858/*859* Loop around doing the sub ops.860* vp - is an unlocked vnode pointer for the CFH861* savevp - is an unlocked vnode pointer for the SAVEDFH862* (at some future date, it might turn out to be more appropriate863* to keep the file handles instead of vnode pointers?)864* savevpnes and vpnes - are the export flags for the above.865*/866for (i = 0; i < numops; i++) {867NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);868if (savefhcnt > 0) {869op = NFSV4OP_SAVEFH;870*repp = txdr_unsigned(op);871savefhcnt--;872} else if (nextop == -1) {873NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);874*repp = *tl;875op = fxdr_unsigned(int, *tl);876} else {877op = nextop;878*repp = txdr_unsigned(op);879nextop = -1;880}881NFSD_DEBUG(4, "op=%d\n", op);882if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||883(op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||884(op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) {885nd->nd_repstat = NFSERR_OPILLEGAL;886*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);887*repp = nfsd_errmap(nd);888retops++;889break;890} else {891repp++;892}893894binuptime(&start_time);895nfsrvd_statstart(op, &start_time);896statsinprog = 1;897898if (i == 0)899op0 = op;900if (i == numops - 1)901nd->nd_flag |= ND_LASTOP;902903/*904* Check for a referral on the current FH and, if so, return905* NFSERR_MOVED for all ops that allow it, except Getattr.906*/907if (vp != NULL && op != NFSV4OP_GETATTR &&908nfsv4root_getreferral(vp, NULL, 0) != NULL &&909nfsrv_errmoved(op)) {910nd->nd_repstat = NFSERR_MOVED;911*repp = nfsd_errmap(nd);912retops++;913break;914}915916/*917* For NFSv4.1, check for a Sequence Operation being first918* or one of the other allowed operations by itself.919*/920if ((nd->nd_flag & ND_NFSV41) != 0) {921if (i != 0 && op == NFSV4OP_SEQUENCE)922nd->nd_repstat = NFSERR_SEQUENCEPOS;923else if (i == 0 && op != NFSV4OP_SEQUENCE &&924op != NFSV4OP_EXCHANGEID &&925op != NFSV4OP_CREATESESSION &&926op != NFSV4OP_BINDCONNTOSESS &&927op != NFSV4OP_DESTROYCLIENTID &&928op != NFSV4OP_DESTROYSESSION)929nd->nd_repstat = NFSERR_OPNOTINSESS;930else if (i != 0 && op0 != NFSV4OP_SEQUENCE)931nd->nd_repstat = NFSERR_NOTONLYOP;932if (nd->nd_repstat != 0) {933*repp = nfsd_errmap(nd);934retops++;935break;936}937}938939nd->nd_procnum = op;940/*941* If over flood level, reply NFSERR_RESOURCE, if at the first942* Op. (Since a client recovery from NFSERR_RESOURCE can get943* really nasty for certain Op sequences, I'll play it safe944* and only return the error at the beginning.) The cache945* will still function over flood level, but uses lots of946* mbufs.)947* If nfsrv_mallocmget_limit() returns True, the system is near948* to its limit for memory that malloc()/mget() can allocate.949*/950if (i == 0 && (nd->nd_rp == NULL ||951nd->nd_rp->rc_refcnt == 0) &&952(nfsrv_mallocmget_limit() ||953NFSD_VNET(nfsrc_tcpsavedreplies) >954NFSD_VNET(nfsrc_floodlevel))) {955if (NFSD_VNET(nfsrc_tcpsavedreplies) >956NFSD_VNET(nfsrc_floodlevel))957printf("nfsd server cache flooded, try "958"increasing vfs.nfsd.tcphighwater\n");959nd->nd_repstat = NFSERR_RESOURCE;960*repp = nfsd_errmap(nd);961if (op == NFSV4OP_SETATTR) {962/*963* Setattr replies require a bitmap.964* even for errors like these.965*/966NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);967*tl = 0;968}969retops++;970break;971}972973/*974* Check for the case of SP4_MACH_CRED and an operation in975* the allow set. For these operations, replace nd_cred with976* root credentials so that the operation will not fail due977* to credentials.978* NB: ND_MACHCRED is set by Sequence when the ClientID979* specifies LCL_MACHCRED and the RPC is being performed980* via krb5i or krb5p using the machine principal.981*/982if ((nd->nd_flag & ND_MACHCRED) != 0) {983if (NFSISSET_OPBIT(&nd->nd_allowops, op)) {984/* Replace nd_cred with root creds. */985if (rootcred == NULL)986rootcred = nfsrv_createrootcred();987if (savecred == NULL)988savecred = nd->nd_cred;989nd->nd_cred = rootcred;990} else if (savecred != NULL) {991nd->nd_cred = savecred;992savecred = NULL;993}994}995996if (nfsv4_opflag[op].savereply)997nd->nd_flag |= ND_SAVEREPLY;998switch (op) {999case NFSV4OP_PUTFH:1000error = nfsrv_mtofh(nd, &fh);1001if (error)1002goto nfsmout;1003if ((nd->nd_flag & ND_LASTOP) == 0) {1004/*1005* Pre-parse the next op#. If it is1006* SaveFH, count it and skip to the1007* next op#, if not the last op#.1008* nextop is used to determine if1009* NFSERR_WRONGSEC can be returned,1010* per RFC5661 Sec. 2.6.1011*/1012do {1013NFSM_DISSECT(tl, uint32_t *,1014NFSX_UNSIGNED);1015nextop = fxdr_unsigned(int, *tl);1016if (nextop == NFSV4OP_SAVEFH &&1017i < numops - 1)1018savefhcnt++;1019} while (nextop == NFSV4OP_SAVEFH &&1020i < numops - 1);1021}1022if (!nd->nd_repstat)1023nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,1024NULL, 0, nextop);1025/* For now, allow this for non-export FHs */1026if (!nd->nd_repstat) {1027if (vp)1028vrele(vp);1029vp = nvp;1030cur_fsid = vp->v_mount->mnt_stat.f_fsid;1031NFSVOPUNLOCK(vp);1032vpnes = nes;1033}1034break;1035case NFSV4OP_PUTPUBFH:1036if (nfs_pubfhset) {1037if ((nd->nd_flag & ND_LASTOP) == 0) {1038/*1039* Pre-parse the next op#. If it is1040* SaveFH, count it and skip to the1041* next op#, if not the last op#.1042* nextop is used to determine if1043* NFSERR_WRONGSEC can be returned,1044* per RFC5661 Sec. 2.6.1045*/1046do {1047NFSM_DISSECT(tl, uint32_t *,1048NFSX_UNSIGNED);1049nextop = fxdr_unsigned(int,1050*tl);1051if (nextop == NFSV4OP_SAVEFH &&1052i < numops - 1)1053savefhcnt++;1054} while (nextop == NFSV4OP_SAVEFH &&1055i < numops - 1);1056}1057nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,1058&nes, NULL, 0, nextop);1059} else1060nd->nd_repstat = NFSERR_NOFILEHANDLE;1061if (!nd->nd_repstat) {1062if (vp)1063vrele(vp);1064vp = nvp;1065cur_fsid = vp->v_mount->mnt_stat.f_fsid;1066NFSVOPUNLOCK(vp);1067vpnes = nes;1068}1069break;1070case NFSV4OP_PUTROOTFH:1071if (NFSD_VNET(nfs_rootfhset)) {1072if ((nd->nd_flag & ND_LASTOP) == 0) {1073/*1074* Pre-parse the next op#. If it is1075* SaveFH, count it and skip to the1076* next op#, if not the last op#.1077* nextop is used to determine if1078* NFSERR_WRONGSEC can be returned,1079* per RFC5661 Sec. 2.6.1080*/1081do {1082NFSM_DISSECT(tl, uint32_t *,1083NFSX_UNSIGNED);1084nextop = fxdr_unsigned(int,1085*tl);1086if (nextop == NFSV4OP_SAVEFH &&1087i < numops - 1)1088savefhcnt++;1089} while (nextop == NFSV4OP_SAVEFH &&1090i < numops - 1);1091}1092nfsd_fhtovp(nd, &NFSD_VNET(nfs_rootfh),1093LK_SHARED, &nvp, &nes, NULL, 0, nextop);1094if (!nd->nd_repstat) {1095if (vp)1096vrele(vp);1097vp = nvp;1098cur_fsid = vp->v_mount->mnt_stat.f_fsid;1099NFSVOPUNLOCK(vp);1100vpnes = nes;1101}1102} else1103nd->nd_repstat = NFSERR_NOFILEHANDLE;1104break;1105case NFSV4OP_SAVEFH:1106if (vp && NFSVNO_EXPORTED(&vpnes)) {1107nd->nd_repstat = 0;1108/* If vp == savevp, a no-op */1109if (vp != savevp) {1110if (savevp)1111vrele(savevp);1112vref(vp);1113savevp = vp;1114savevpnes = vpnes;1115save_fsid = cur_fsid;1116}1117if ((nd->nd_flag & ND_CURSTATEID) != 0) {1118nd->nd_savedcurstateid =1119nd->nd_curstateid;1120nd->nd_flag |= ND_SAVEDCURSTATEID;1121}1122} else {1123nd->nd_repstat = NFSERR_NOFILEHANDLE;1124}1125break;1126case NFSV4OP_RESTOREFH:1127if (savevp) {1128if ((nd->nd_flag & ND_LASTOP) == 0) {1129/*1130* Pre-parse the next op#. If it is1131* SaveFH, count it and skip to the1132* next op#, if not the last op#.1133* nextop is used to determine if1134* NFSERR_WRONGSEC can be returned,1135* per RFC5661 Sec. 2.6.1136*/1137do {1138NFSM_DISSECT(tl, uint32_t *,1139NFSX_UNSIGNED);1140nextop = fxdr_unsigned(int,1141*tl);1142if (nextop == NFSV4OP_SAVEFH &&1143i < numops - 1)1144savefhcnt++;1145} while (nextop == NFSV4OP_SAVEFH &&1146i < numops - 1);1147}1148nd->nd_repstat = 0;1149/* If vp == savevp, a no-op */1150if (vp != savevp) {1151if (nfsrv_checkwrongsec(nd, nextop,1152savevp->v_type))1153nd->nd_repstat =1154nfsvno_testexp(nd,1155&savevpnes);1156if (nd->nd_repstat == 0) {1157vref(savevp);1158vrele(vp);1159vp = savevp;1160vpnes = savevpnes;1161cur_fsid = save_fsid;1162}1163}1164if (nd->nd_repstat == 0 &&1165(nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {1166nd->nd_curstateid =1167nd->nd_savedcurstateid;1168nd->nd_flag |= ND_CURSTATEID;1169}1170} else {1171nd->nd_repstat = NFSERR_RESTOREFH;1172}1173break;1174default:1175/*1176* Allow a Lookup, Getattr, GetFH, Secinfo on an1177* non-exported directory if1178* nfs_rootfhset. Do I need to allow any other Ops?1179* (You can only have a non-exported vpnes if1180* nfs_rootfhset is true. See nfsd_fhtovp())1181* Allow AUTH_SYS to be used for file systems1182* exported GSS only for certain Ops, to allow1183* clients to do mounts more easily.1184*/1185if (nfsv4_opflag[op].needscfh && vp) {1186if (!NFSVNO_EXPORTED(&vpnes) &&1187op != NFSV4OP_LOOKUP &&1188op != NFSV4OP_GETATTR &&1189op != NFSV4OP_GETFH &&1190op != NFSV4OP_ACCESS &&1191op != NFSV4OP_READLINK &&1192op != NFSV4OP_SECINFO &&1193op != NFSV4OP_SECINFONONAME)1194nd->nd_repstat = NFSERR_NOFILEHANDLE;1195if (nd->nd_repstat) {1196if (op == NFSV4OP_SETATTR) {1197/*1198* Setattr reply requires a bitmap1199* even for errors like these.1200*/1201NFSM_BUILD(tl, u_int32_t *,1202NFSX_UNSIGNED);1203*tl = 0;1204}1205break;1206}1207}12081209/*1210* Save the current positions in the mbuf lists so1211* that a rollback to this location can be done upon a1212* redo due to a ERELOOKUP return for a operation.1213*/1214mb = nd->nd_mb;1215bpos = nd->nd_bpos;1216bextpg = nd->nd_bextpg;1217bextpgsiz = nd->nd_bextpgsiz;1218md = nd->nd_md;1219dpos = nd->nd_dpos;1220tryagain:12211222if (nfsv4_opflag[op].retfh == 1) {1223if (!vp) {1224nd->nd_repstat = NFSERR_NOFILEHANDLE;1225break;1226}1227if (NFSVNO_EXPORTED(&vpnes) && (op == NFSV4OP_LOOKUP ||1228op == NFSV4OP_LOOKUPP || (op == NFSV4OP_OPEN &&1229vp->v_type == VDIR))) {1230/* Check for wrong security. */1231rstat = nfsvno_testexp(nd, &vpnes);1232if (rstat != 0) {1233nd->nd_repstat = rstat;1234break;1235}1236}1237vref(vp);1238if (nfsv4_opflag[op].modifyfs)1239vn_start_write(vp, &temp_mp, V_WAIT);1240error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,1241&nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes);1242if (!error && !nd->nd_repstat) {1243if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {1244new_mp = nvp->v_mount;1245if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) {1246/* crossed a server mount point */1247nd->nd_repstat = nfsvno_checkexp(new_mp,1248nd->nd_nam, &nes, &credanon);1249if (!nd->nd_repstat)1250nd->nd_repstat = nfsd_excred(nd,1251&nes, credanon, true);1252if (credanon != NULL)1253crfree(credanon);1254if (!nd->nd_repstat) {1255vpnes = nes;1256cur_fsid = new_mp->mnt_stat.f_fsid;1257}1258}1259/* Lookup ops return a locked vnode */1260NFSVOPUNLOCK(nvp);1261}1262if (!nd->nd_repstat) {1263vrele(vp);1264vp = nvp;1265} else1266vrele(nvp);1267}1268if (nfsv4_opflag[op].modifyfs)1269vn_finished_write(temp_mp);1270} else if (nfsv4_opflag[op].retfh == 2) {1271if (vp == NULL || savevp == NULL) {1272nd->nd_repstat = NFSERR_NOFILEHANDLE;1273break;1274} else if (fsidcmp(&cur_fsid, &save_fsid) != 0) {1275nd->nd_repstat = NFSERR_XDEV;1276break;1277}1278if (nfsv4_opflag[op].modifyfs)1279vn_start_write(savevp, &temp_mp, V_WAIT);1280if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {1281vref(vp);1282vref(savevp);1283error = (*(nfsrv4_ops2[op]))(nd, isdgram,1284savevp, vp, &savevpnes, &vpnes);1285} else1286nd->nd_repstat = NFSERR_PERM;1287if (nfsv4_opflag[op].modifyfs)1288vn_finished_write(temp_mp);1289} else {1290if (nfsv4_opflag[op].retfh != 0)1291panic("nfsrvd_compound");1292if (nfsv4_opflag[op].needscfh) {1293if (vp != NULL) {1294lktype = nfsv4_opflag[op].lktype;1295if (nfsv4_opflag[op].modifyfs) {1296vn_start_write(vp, &temp_mp,1297V_WAIT);1298if (op == NFSV4OP_WRITE &&1299MNT_SHARED_WRITES(temp_mp))1300lktype = LK_SHARED;1301}1302if (NFSVOPLOCK(vp, lktype) == 0)1303vref(vp);1304else1305nd->nd_repstat = NFSERR_PERM;1306} else {1307nd->nd_repstat = NFSERR_NOFILEHANDLE;1308if (op == NFSV4OP_SETATTR) {1309/*1310* Setattr reply requires a1311* bitmap even for errors like1312* these.1313*/1314NFSM_BUILD(tl, u_int32_t *,1315NFSX_UNSIGNED);1316*tl = 0;1317}1318break;1319}1320if (nd->nd_repstat == 0) {1321error = (*(nfsrv4_ops0[op]))(nd,1322isdgram, vp, &vpnes);1323if ((op == NFSV4OP_SECINFO ||1324op == NFSV4OP_SECINFONONAME) &&1325error == 0 && nd->nd_repstat == 0) {1326/*1327* Secinfo and Secinfo_no_name1328* consume the current FH.1329*/1330vrele(vp);1331vp = NULL;1332}1333}1334if (nfsv4_opflag[op].modifyfs)1335vn_finished_write(temp_mp);1336} else {1337error = (*(nfsrv4_ops0[op]))(nd, isdgram,1338NULL, &vpnes);1339}1340}1341}1342if (error) {1343if (error == EBADRPC || error == NFSERR_BADXDR) {1344nd->nd_repstat = NFSERR_BADXDR;1345} else {1346nd->nd_repstat = error;1347printf("nfsv4 comperr0=%d\n", error);1348}1349error = 0;1350}13511352if (nd->nd_repstat == ERELOOKUP) {1353/*1354* Roll back to the beginning of the operation1355* arguments.1356*/1357nd->nd_md = md;1358nd->nd_dpos = dpos;13591360/*1361* Trim off the bogus reply for this operation1362* and redo the operation.1363*/1364nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);1365nd->nd_repstat = 0;1366nd->nd_flag |= ND_ERELOOKUP;1367goto tryagain;1368}1369nd->nd_flag &= ~ND_ERELOOKUP;13701371if (statsinprog != 0) {1372nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,1373/*then*/ &start_time);1374statsinprog = 0;1375}13761377retops++;1378if (nd->nd_repstat) {1379*repp = nfsd_errmap(nd);1380break;1381} else {1382*repp = 0; /* NFS4_OK */1383}1384}1385nfsmout:1386if (statsinprog != 0) {1387nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,1388/*then*/ &start_time);1389statsinprog = 0;1390}1391if (error) {1392if (error == EBADRPC || error == NFSERR_BADXDR)1393nd->nd_repstat = NFSERR_BADXDR;1394else1395printf("nfsv4 comperr1=%d\n", error);1396}1397if (taglen == -1) {1398NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);1399*tl++ = 0;1400*tl = 0;1401} else {1402*retopsp = txdr_unsigned(retops);1403}1404if (vp)1405vrele(vp);1406if (savevp)1407vrele(savevp);1408if (savecred != NULL)1409nd->nd_cred = savecred;1410if (rootcred != NULL)1411crfree(rootcred);1412NFSLOCKV4ROOTMUTEX();1413nfsv4_relref(&nfsv4rootfs_lock);1414NFSUNLOCKV4ROOTMUTEX();14151416NFSEXITCODE2(0, nd);1417}14181419/* Create a credential for "root". */1420static struct ucred *1421nfsrv_createrootcred(void)1422{1423struct ucred *cr;14241425cr = crget();1426cr->cr_uid = cr->cr_ruid = cr->cr_svuid = UID_ROOT;1427crsetgroups_and_egid(cr, 0, NULL, GID_WHEEL);1428cr->cr_rgid = cr->cr_svgid = cr->cr_gid;1429cr->cr_prison = curthread->td_ucred->cr_prison;1430prison_hold(cr->cr_prison);1431#ifdef MAC1432mac_cred_associate_nfsd(cr);1433#endif1434return (cr);1435}143614371438