summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsserver/nfs_nfsdsocket.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsserver/nfs_nfsdsocket.c')
-rw-r--r--sys/fs/nfsserver/nfs_nfsdsocket.c979
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();
+}
OpenPOWER on IntegriCloud