diff options
Diffstat (limited to 'sys/fs/nfsserver/nfs_nfsdsocket.c')
-rw-r--r-- | sys/fs/nfsserver/nfs_nfsdsocket.c | 979 |
1 files changed, 979 insertions, 0 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c new file mode 100644 index 0000000..29592a9 --- /dev/null +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -0,0 +1,979 @@ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Socket operations for use by the nfs server. + */ + +#ifndef APPLEKEXT +#include <fs/nfs/nfsport.h> + +extern struct nfsstats newnfsstats; +extern struct nfsrvfh nfs_pubfh, nfs_rootfh; +extern int nfs_pubfhset, nfs_rootfhset; +extern struct nfsv4lock nfsv4rootfs_lock; +extern struct nfsrv_stablefirst nfsrv_stablefirst; +extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; +extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies; +NFSV4ROOTLOCKMUTEX; +NFSSTATESPINLOCK; +vnode_t nfsv4root_vp = NULL; +int nfsv4root_set = 0; + +int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *, + int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = { + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_getattr, + nfsrvd_setattr, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_access, + nfsrvd_readlink, + nfsrvd_read, + nfsrvd_write, + nfsrvd_create, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_remove, + nfsrvd_remove, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_readdir, + nfsrvd_readdirplus, + nfsrvd_statfs, + nfsrvd_fsinfo, + nfsrvd_pathconf, + nfsrvd_commit, +}; + +int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *, + int, vnode_t , vnode_t *, fhandle_t *, + NFSPROC_T *, struct nfsexstuff *) = { + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_lookup, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_mkdir, + nfsrvd_symlink, + nfsrvd_mknod, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, +}; + +int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *, + int, vnode_t , vnode_t , NFSPROC_T *, + struct nfsexstuff *, struct nfsexstuff *) = { + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + nfsrvd_rename, + nfsrvd_link, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, +}; + +int (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *, + int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = { + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_access, + nfsrvd_close, + nfsrvd_commit, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_delegpurge, + nfsrvd_delegreturn, + nfsrvd_getattr, + nfsrvd_getfh, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_lock, + nfsrvd_lockt, + nfsrvd_locku, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_verify, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_openconfirm, + nfsrvd_opendowngrade, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_read, + nfsrvd_readdirplus, + nfsrvd_readlink, + nfsrvd_remove, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_renew, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_secinfo, + nfsrvd_setattr, + nfsrvd_setclientid, + nfsrvd_setclientidcfrm, + nfsrvd_verify, + nfsrvd_write, + nfsrvd_releaselckown, +}; + +int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *, + int, vnode_t , vnode_t *, fhandle_t *, + NFSPROC_T *, struct nfsexstuff *) = { + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_mknod, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_lookup, + nfsrvd_lookup, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + nfsrvd_open, + nfsrvd_openattr, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0, +}; + +int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *, + int, vnode_t , vnode_t , NFSPROC_T *, + struct nfsexstuff *, struct nfsexstuff *) = { + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + nfsrvd_link, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + nfsrvd_rename, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, + (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0, +}; +#endif /* !APPLEKEXT */ + +/* + * Static array that defines which nfs rpc's are nonidempotent + */ +static int nfsrv_nonidempotent[NFS_V3NPROCS] = { + FALSE, + FALSE, + TRUE, + FALSE, + FALSE, + FALSE, + FALSE, + TRUE, + TRUE, + TRUE, + TRUE, + TRUE, + TRUE, + TRUE, + TRUE, + TRUE, + FALSE, + FALSE, + FALSE, + FALSE, + FALSE, + FALSE, +}; + +/* + * This static array indicates whether or not the RPC modifies the + * file system. + */ +static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +/* local functions */ +static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, + NFSPROC_T *p); + + +/* + * This static array indicates which server procedures require the extra + * arguments to return the current file handle for V2, 3. + */ +static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 }; + +extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS]; + +static int nfsv3to4op[NFS_V3NPROCS] = { + NFSPROC_NULL, + NFSV4OP_GETATTR, + NFSV4OP_SETATTR, + NFSV4OP_LOOKUP, + NFSV4OP_ACCESS, + NFSV4OP_READLINK, + NFSV4OP_READ, + NFSV4OP_WRITE, + NFSV4OP_V3CREATE, + NFSV4OP_MKDIR, + NFSV4OP_SYMLINK, + NFSV4OP_MKNOD, + NFSV4OP_REMOVE, + NFSV4OP_RMDIR, + NFSV4OP_RENAME, + NFSV4OP_LINK, + NFSV4OP_READDIR, + NFSV4OP_READDIRPLUS, + NFSV4OP_FSSTAT, + NFSV4OP_FSINFO, + NFSV4OP_PATHCONF, + NFSV4OP_COMMIT, +}; + +/* + * Do an RPC. Basically, get the file handles translated to vnode pointers + * and then call the appropriate server routine. The server routines are + * split into groups, based on whether they use a file handle or file + * handle plus name or ... + * The NFS V4 Compound RPC is performed separately by nfsrvd_compound(). + */ +APPLESTATIC void +nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, + NFSPROC_T *p) +{ + int error = 0; + vnode_t vp; + mount_t mp = NULL; + struct nfsrvfh fh; + struct nfsexstuff nes; + + /* + * Get a locked vnode for the first file handle + */ + if (!(nd->nd_flag & ND_NFSV4)) { +#ifdef DIAGNOSTIC + if (nd->nd_repstat) + panic("nfsrvd_dorpc"); +#endif + /* + * For NFSv3, if the malloc/mget allocation is near limits, + * return NFSERR_DELAY. + */ + if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) { + nd->nd_repstat = NFSERR_DELAY; + vp = NULL; + } else { + error = nfsrv_mtofh(nd, &fh); + if (error) { + if (error != EBADRPC) + printf("nfs dorpc err1=%d\n", error); + nd->nd_repstat = NFSERR_GARBAGE; + return; + } + nes.nes_vfslocked = 0; + if (nd->nd_flag & ND_PUBLOOKUP) + nfsd_fhtovp(nd, &nfs_pubfh, &vp, &nes, + &mp, nfs_writerpc[nd->nd_procnum], p); + else + nfsd_fhtovp(nd, &fh, &vp, &nes, + &mp, nfs_writerpc[nd->nd_procnum], p); + if (nd->nd_repstat == NFSERR_PROGNOTV4) + return; + } + } + + /* + * For V2 and 3, set the ND_SAVEREPLY flag for the recent request + * cache, as required. + * For V4, nfsrvd_compound() does this. + */ + if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum]) + nd->nd_flag |= ND_SAVEREPLY; + + nfsrvd_rephead(nd); + /* + * If nd_repstat is non-zero, just fill in the reply status + * to complete the RPC reply for V2. Otherwise, you must do + * the RPC. + */ + if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { + *nd->nd_errp = nfsd_errmap(nd); + NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]); + if (mp != NULL) { + if (nfs_writerpc[nd->nd_procnum]) + NFS_ENDWRITE(mp); + if (nes.nes_vfslocked) + nfsvno_unlockvfs(mp); + } + return; + } + + /* + * Now the procedure can be performed. For V4, nfsrvd_compound() + * works through the sub-rpcs, otherwise just call the procedure. + * The procedures are in three groups with different arguments. + * The group is indicated by the value in nfs_retfh[]. + */ + if (nd->nd_flag & ND_NFSV4) { + nfsrvd_compound(nd, isdgram, p); + } else { + if (nfs_retfh[nd->nd_procnum] == 1) { + if (vp) + NFSVOPUNLOCK(vp, 0, p); + error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram, + vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes); + } else if (nfs_retfh[nd->nd_procnum] == 2) { + error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram, + vp, NULL, p, &nes, NULL); + } else { + error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram, + vp, p, &nes); + } + if (mp) { + if (nfs_writerpc[nd->nd_procnum]) + NFS_ENDWRITE(mp); + if (nes.nes_vfslocked) + nfsvno_unlockvfs(mp); + } + NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]); + } + if (error) { + if (error != EBADRPC) + printf("nfs dorpc err2=%d\n", error); + nd->nd_repstat = NFSERR_GARBAGE; + } + *nd->nd_errp = nfsd_errmap(nd); + + /* + * Don't cache certain reply status values. + */ + if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) && + (nd->nd_repstat == NFSERR_GARBAGE || + nd->nd_repstat == NFSERR_BADXDR || + nd->nd_repstat == NFSERR_MOVED || + nd->nd_repstat == NFSERR_DELAY || + nd->nd_repstat == NFSERR_BADSEQID || + nd->nd_repstat == NFSERR_RESOURCE || + nd->nd_repstat == NFSERR_SERVERFAULT || + nd->nd_repstat == NFSERR_STALECLIENTID || + nd->nd_repstat == NFSERR_STALESTATEID || + nd->nd_repstat == NFSERR_OLDSTATEID || + nd->nd_repstat == NFSERR_BADSTATEID || + nd->nd_repstat == NFSERR_GRACE || + nd->nd_repstat == NFSERR_NOGRACE)) + nd->nd_flag &= ~ND_SAVEREPLY; +} + +/* + * Breaks down a compound RPC request and calls the server routines for + * the subprocedures. + * Some suboperations are performed directly here to simplify file handle<--> + * vnode pointer handling. + */ +static void +nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, + NFSPROC_T *p) +{ + int i, op; + u_int32_t *tl; + struct nfsclient *clp, *nclp; + int numops, taglen = -1, error = 0, igotlock; + u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp; + u_char tag[NFSV4_SMALLSTR + 1], *tagstr; + vnode_t vp, nvp, savevp; + struct nfsrvfh fh; + mount_t mp, savemp; + struct ucred *credanon; + struct nfsexstuff nes, vpnes, savevpnes; + static u_int64_t compref = 0; + + NFSVNO_EXINIT(&vpnes); + NFSVNO_EXINIT(&savevpnes); + /* + * Put the seq# of the current compound RPC in nfsrv_descript. + * (This is used by nfsrv_checkgetattr(), to see if the write + * delegation was created by the same compound RPC as the one + * with that Getattr in it.) + * Don't worry about the 64bit number wrapping around. It ain't + * gonna happen before this server gets shut down/rebooted. + */ + nd->nd_compref = compref++; + + /* + * Check for and optionally get a lock on the root. This lock means that + * no nfsd will be fiddling with the V4 file system and state stuff. It + * is required when the V4 root is being changed, the stable storage + * restart file is being updated, or callbacks are being done. + * When any of the nfsd are processing an NFSv4 compound RPC, they must + * either hold a reference count (nfs_usecnt) or the lock. When + * nfsrv_unlock() is called to release the lock, it can optionally + * also get a reference count, which saves the need for a call to + * nfsrv_getref() after nfsrv_unlock(). + */ + /* + * First, check to see if we need to wait for an update lock. + */ + igotlock = 0; + NFSLOCKV4ROOTMUTEX(); + if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK) + igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, + NFSV4ROOTLOCKMUTEXPTR); + else + igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL, + NFSV4ROOTLOCKMUTEXPTR); + NFSUNLOCKV4ROOTMUTEX(); + if (igotlock) { + NFSLOCKSTATE(); /* to avoid a race with */ + NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ + /* + * If I got the lock, I can update the stable storage file. + * Done when the grace period is over or a client has long + * since expired. + */ + nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK; + if ((nfsrv_stablefirst.nsf_flags & + (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER) + nfsrv_updatestable(p); + + /* + * If at least one client has long since expired, search + * the client list for them, write a REVOKE record on the + * stable storage file and then remove them from the client + * list. + */ + if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) { + nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT; + for (i = 0; i < NFSCLIENTHASHSIZE; i++) { + LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, + nclp) { + if (clp->lc_flags & LCL_EXPIREIT) { + if (!LIST_EMPTY(&clp->lc_open) || + !LIST_EMPTY(&clp->lc_deleg)) + nfsrv_writestable(clp->lc_id, + clp->lc_idlen, NFSNST_REVOKE, p); + nfsrv_cleanclient(clp, p); + nfsrv_freedeleglist(&clp->lc_deleg); + nfsrv_freedeleglist(&clp->lc_olddeleg); + LIST_REMOVE(clp, lc_hash); + nfsrv_zapclient(clp, p); + } + } + } + } + NFSLOCKV4ROOTMUTEX(); + nfsv4_unlock(&nfsv4rootfs_lock, 1); + NFSUNLOCKV4ROOTMUTEX(); + } else { + /* + * If we didn't get the lock, we need to get a refcnt, + * which also checks for and waits for the lock. + */ + NFSLOCKV4ROOTMUTEX(); + nfsv4_getref(&nfsv4rootfs_lock, NULL, + NFSV4ROOTLOCKMUTEXPTR); + NFSUNLOCKV4ROOTMUTEX(); + } + + /* + * If flagged, search for open owners that haven't had any opens + * for a long time. + */ + if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) { + nfsrv_throwawayopens(p); + } + + savevp = vp = NULL; + savevpnes.nes_vfslocked = vpnes.nes_vfslocked = 0; + savemp = mp = NULL; + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + taglen = fxdr_unsigned(int, *tl); + if (taglen < 0) { + error = EBADRPC; + goto nfsmout; + } + if (taglen <= NFSV4_SMALLSTR) + tagstr = tag; + else + tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK); + error = nfsrv_mtostr(nd, tagstr, taglen); + if (error) { + if (taglen > NFSV4_SMALLSTR) + free(tagstr, M_TEMP); + taglen = -1; + goto nfsmout; + } + (void) nfsm_strtom(nd, tag, taglen); + if (taglen > NFSV4_SMALLSTR) { + free(tagstr, M_TEMP); + } + NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED); + NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + minorvers = fxdr_unsigned(u_int32_t, *tl++); + if (minorvers != NFSV4_MINORVERSION) + nd->nd_repstat = NFSERR_MINORVERMISMATCH; + if (nd->nd_repstat) + numops = 0; + else + numops = fxdr_unsigned(int, *tl); + /* + * Loop around doing the sub ops. + * vp - is an unlocked vnode pointer for the CFH + * savevp - is an unlocked vnode pointer for the SAVEDFH + * (at some future date, it might turn out to be more appropriate + * to keep the file handles instead of vnode pointers?) + * savevpnes and vpnes - are the export flags for the above. + */ + for (i = 0; i < numops; i++) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED); + *repp++ = *tl; + op = fxdr_unsigned(int, *tl); + if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) { + nd->nd_repstat = NFSERR_OPILLEGAL; + *repp = nfsd_errmap(nd); + retops++; + break; + } + + /* + * Check for a referral on the current FH and, if so, return + * NFSERR_MOVED for all ops that allow it, except Getattr. + */ + if (vp != NULL && op != NFSV4OP_GETATTR && + nfsv4root_getreferral(vp, NULL, 0) != NULL && + nfsrv_errmoved(op)) { + nd->nd_repstat = NFSERR_MOVED; + *repp = nfsd_errmap(nd); + retops++; + break; + } + + nd->nd_procnum = op; + /* + * If over flood level, reply NFSERR_RESOURCE, if at the first + * Op. (Since a client recovery from NFSERR_RESOURCE can get + * really nasty for certain Op sequences, I'll play it safe + * and only return the error at the beginning.) The cache + * will still function over flood level, but uses lots of + * mbufs.) + * If nfsrv_mallocmget_limit() returns True, the system is near + * to its limit for memory that malloc()/mget() can allocate. + */ + if (i == 0 && nd->nd_rp->rc_refcnt == 0 && + (nfsrv_mallocmget_limit() || + nfsrc_tcpsavedreplies > nfsrc_floodlevel)) { + if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) { + printf("nfsd server cache flooded, try to"); + printf(" increase nfsrc_floodlevel\n"); + } + nd->nd_repstat = NFSERR_RESOURCE; + *repp = nfsd_errmap(nd); + if (op == NFSV4OP_SETATTR) { + /* + * Setattr replies require a bitmap. + * even for errors like these. + */ + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = 0; + } + retops++; + break; + } + if (nfsv4_opflag[op].savereply) + nd->nd_flag |= ND_SAVEREPLY; + NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]); + switch (op) { + case NFSV4OP_PUTFH: + error = nfsrv_mtofh(nd, &fh); + if (error) + goto nfsmout; + if (!nd->nd_repstat) { + nes.nes_vfslocked = vpnes.nes_vfslocked; + nfsd_fhtovp(nd, &fh, &nvp, &nes, &mp, + 0, p); + } + /* For now, allow this for non-export FHs */ + if (!nd->nd_repstat) { + if (vp) + vrele(vp); + vp = nvp; + NFSVOPUNLOCK(vp, 0, p); + vpnes = nes; + } + break; + case NFSV4OP_PUTPUBFH: + if (nfs_pubfhset) { + nes.nes_vfslocked = vpnes.nes_vfslocked; + nfsd_fhtovp(nd, &nfs_pubfh, &nvp, + &nes, &mp, 0, p); + } else { + nd->nd_repstat = NFSERR_NOFILEHANDLE; + } + if (!nd->nd_repstat) { + if (vp) + vrele(vp); + vp = nvp; + NFSVOPUNLOCK(vp, 0, p); + vpnes = nes; + } + break; + case NFSV4OP_PUTROOTFH: + if (nfs_rootfhset) { + nes.nes_vfslocked = vpnes.nes_vfslocked; + nfsd_fhtovp(nd, &nfs_rootfh, &nvp, + &nes, &mp, 0, p); + if (!nd->nd_repstat) { + if (vp) + vrele(vp); + vp = nvp; + NFSVOPUNLOCK(vp, 0, p); + vpnes = nes; + } + } else if (nfsv4root_vp && nfsv4root_set) { + if (vp) { + if (vpnes.nes_vfslocked) + nfsvno_unlockvfs(mp); + vrele(vp); + } + vp = nfsv4root_vp; + VREF(vp); + NFSVNO_SETEXRDONLY(&vpnes); + vpnes.nes_vfslocked = 0; + mp = vnode_mount(vp); + } else { + nd->nd_repstat = NFSERR_NOFILEHANDLE; + } + break; + case NFSV4OP_SAVEFH: + if (vp && NFSVNO_EXPORTED(&vpnes)) { + nd->nd_repstat = 0; + /* If vp == savevp, a no-op */ + if (vp != savevp) { + if (savevp) + vrele(savevp); + VREF(vp); + savevp = vp; + savevpnes = vpnes; + savemp = mp; + } + } else { + nd->nd_repstat = NFSERR_NOFILEHANDLE; + } + break; + case NFSV4OP_RESTOREFH: + if (savevp) { + nd->nd_repstat = 0; + /* If vp == savevp, a no-op */ + if (vp != savevp) { + VREF(savevp); + if (mp == NULL || savemp == NULL) + panic("nfscmpmp"); + if (!savevpnes.nes_vfslocked && + vpnes.nes_vfslocked) { + if (mp == savemp) + panic("nfscmp2"); + nfsvno_unlockvfs(mp); + } else if (savevpnes.nes_vfslocked && + !vpnes.nes_vfslocked) { + if (mp == savemp) + panic("nfscmp3"); + savevpnes.nes_vfslocked = nfsvno_lockvfs(savemp); + } + vrele(vp); + vp = savevp; + vpnes = savevpnes; + mp = savemp; + } + } else { + nd->nd_repstat = NFSERR_RESTOREFH; + } + break; + default: + /* + * Allow a Lookup, Getattr, GetFH, Secinfo on an + * non-exported directory if + * nfs_rootfhset. Do I need to allow any other Ops? + * (You can only have a non-exported vpnes if + * nfs_rootfhset is true. See nfsd_fhtovp()) + * Allow AUTH_SYS to be used for file systems + * exported GSS only for certain Ops, to allow + * clients to do mounts more easily. + */ + if (nfsv4_opflag[op].needscfh && vp) { + if (!NFSVNO_EXPORTED(&vpnes) && + op != NFSV4OP_LOOKUP && + op != NFSV4OP_GETATTR && + op != NFSV4OP_GETFH && + op != NFSV4OP_SECINFO) + nd->nd_repstat = NFSERR_NOFILEHANDLE; + else if (NFSVNO_EXGSSONLY(&vpnes) && + !(nd->nd_flag & ND_GSS) && + op != NFSV4OP_LOOKUP && + op != NFSV4OP_GETFH && + op != NFSV4OP_GETATTR && + op != NFSV4OP_SECINFO) + nd->nd_repstat = NFSERR_WRONGSEC; + if (nd->nd_repstat) { + if (op == NFSV4OP_SETATTR) { + /* + * Setattr reply requires a bitmap + * even for errors like these. + */ + NFSM_BUILD(tl, u_int32_t *, + NFSX_UNSIGNED); + *tl = 0; + } + break; + } + } + if (nfsv4_opflag[op].retfh == 1) { + if (!vp) { + nd->nd_repstat = NFSERR_NOFILEHANDLE; + break; + } + VREF(vp); + if (nfsv4_opflag[op].modifyfs) + NFS_STARTWRITE(NULL, &mp); + error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp, + &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes); + if (!error && !nd->nd_repstat) { + if (vfs_statfs(mp)->f_fsid.val[0] != + vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] || + vfs_statfs(mp)->f_fsid.val[1] != + vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) { + if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] == + NFSV4ROOT_FSID0 && + vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] == + NFSV4ROOT_FSID1) { + if (vpnes.nes_vfslocked) { + nfsvno_unlockvfs(mp); + vpnes.nes_vfslocked = 0; + } + NFSVNO_SETEXRDONLY(&vpnes); + mp = vnode_mount(nvp); + } else { + nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp), + nd->nd_nam, &nes, &credanon); + if (!nd->nd_repstat) + nd->nd_repstat = nfsd_excred(nd, + &nes, credanon); + if (!nd->nd_repstat) { + if (vpnes.nes_vfslocked) + nfsvno_unlockvfs(mp); + mp = vnode_mount(nvp); + vpnes = nes; + vpnes.nes_vfslocked = + nfsvno_lockvfs(mp); + } + } + } + if (!nd->nd_repstat) { + vrele(vp); + vp = nvp; + } + } + if (nfsv4_opflag[op].modifyfs) + NFS_ENDWRITE(mp); + } else if (nfsv4_opflag[op].retfh == 2) { + if (vp == NULL || savevp == NULL) { + nd->nd_repstat = NFSERR_NOFILEHANDLE; + break; + } else if (mp != savemp) { + nd->nd_repstat = NFSERR_XDEV; + break; + } + VREF(vp); + VREF(savevp); + if (nfsv4_opflag[op].modifyfs) + NFS_STARTWRITE(NULL, &mp); + NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p); + error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp, + vp, p, &savevpnes, &vpnes); + if (nfsv4_opflag[op].modifyfs) + NFS_ENDWRITE(mp); + } else { + if (nfsv4_opflag[op].retfh != 0) + panic("nfsrvd_compound"); + if (nfsv4_opflag[op].needscfh) { + if (vp) { + VREF(vp); + if (nfsv4_opflag[op].modifyfs) + NFS_STARTWRITE(NULL, &mp); + NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); + } else { + nd->nd_repstat = NFSERR_NOFILEHANDLE; + if (op == NFSV4OP_SETATTR) { + /* + * Setattr reply requires a bitmap + * even for errors like these. + */ + NFSM_BUILD(tl, u_int32_t *, + NFSX_UNSIGNED); + *tl = 0; + } + break; + } + error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp, + p, &vpnes); + if (nfsv4_opflag[op].modifyfs) + NFS_ENDWRITE(mp); + } else { + error = (*(nfsrv4_ops0[op]))(nd, isdgram, + NULL, p, &vpnes); + } + } + }; + if (error) { + if (error == EBADRPC || error == NFSERR_BADXDR) { + nd->nd_repstat = NFSERR_BADXDR; + } else { + nd->nd_repstat = error; + printf("nfsv4 comperr0=%d\n", error); + } + error = 0; + } + retops++; + if (nd->nd_repstat) { + *repp = nfsd_errmap(nd); + break; + } else { + *repp = 0; /* NFS4_OK */ + } + } +nfsmout: + if (error) { + if (error == EBADRPC || error == NFSERR_BADXDR) + nd->nd_repstat = NFSERR_BADXDR; + else + printf("nfsv4 comperr1=%d\n", error); + } + if (taglen == -1) { + NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + *tl++ = 0; + *tl = 0; + } else { + *retopsp = txdr_unsigned(retops); + } + if (mp && vpnes.nes_vfslocked) + nfsvno_unlockvfs(mp); + if (vp) + vrele(vp); + if (savevp) + vrele(savevp); + NFSLOCKV4ROOTMUTEX(); + nfsv4_relref(&nfsv4rootfs_lock); + NFSUNLOCKV4ROOTMUTEX(); +} |