Remove the old NFS client and server from head,
which means that the NFSCLIENT and NFSSERVER kernel options will no longer work. This commit only removes the kernel components. Removal of unused code in the user utilities will be done later. This commit does not include an addition to UPDATING, but that will be committed in a few minutes. Discussed on: freebsd-fs
This commit is contained in:
parent
6d514f104e
commit
c15882f091
@ -154,7 +154,7 @@ options INVARIANT_SUPPORT # Extra sanity checks of internal structures, require
|
||||
# Enable these options for nfs root configured via BOOTP.
|
||||
options NFSCL # Network Filesystem Client
|
||||
options NFSLOCKD # Network Lock Manager
|
||||
#options NFS_ROOT # NFS usable as /, requires NFSCLIENT
|
||||
#options NFS_ROOT # NFS usable as /, requires NFSCL
|
||||
#options BOOTP
|
||||
#options BOOTP_NFSROOT
|
||||
#options BOOTP_NFSV3
|
||||
|
@ -162,7 +162,7 @@ options INVARIANT_SUPPORT # Extra sanity checks of internal structures, require
|
||||
# Enable these options for nfs root configured via BOOTP.
|
||||
options NFSCL # Network Filesystem Client
|
||||
options NFSLOCKD # Network Lock Manager
|
||||
#options NFS_ROOT # NFS usable as /, requires NFSCLIENT
|
||||
#options NFS_ROOT # NFS usable as /, requires NFSCL
|
||||
#options BOOTP
|
||||
#options BOOTP_NFSROOT
|
||||
#options BOOTP_NFSV3
|
||||
|
@ -19,7 +19,7 @@ options INET6 # IPv6 communications protocols
|
||||
options FFS # Berkeley Fast Filesystem
|
||||
options NFSCL # Network Filesystem Client
|
||||
options NFSLOCKD # Network Lock Manager
|
||||
options NFS_ROOT # NFS usable as /, requires NFSCLIENT
|
||||
options NFS_ROOT # NFS usable as /, requires NFSCL
|
||||
options GEOM_PART_BSD # BSD partition scheme
|
||||
options GEOM_PART_MBR # MBR partition scheme
|
||||
options TMPFS # Efficient memory filesystem
|
||||
|
@ -1019,7 +1019,7 @@ options DUMMYNET
|
||||
|
||||
# One of these is mandatory:
|
||||
options FFS #Fast filesystem
|
||||
options NFSCLIENT #Network File System client
|
||||
options NFSCL #Network File System client
|
||||
|
||||
# The rest are optional:
|
||||
options AUTOFS #Automounter filesystem
|
||||
@ -1027,7 +1027,6 @@ options CD9660 #ISO 9660 filesystem
|
||||
options FDESCFS #File descriptor filesystem
|
||||
options FUSE #FUSE support module
|
||||
options MSDOSFS #MS DOS File System (FAT, FAT32)
|
||||
options NFSSERVER #Network File System server
|
||||
options NFSLOCKD #Network Lock Manager
|
||||
options NFSCL #New Network Filesystem Client
|
||||
options NFSD #New Network Filesystem Server
|
||||
@ -2596,7 +2595,7 @@ device pcfclock
|
||||
# Kernel BOOTP support
|
||||
|
||||
options BOOTP # Use BOOTP to obtain IP address/hostname
|
||||
# Requires NFSCLIENT and NFS_ROOT
|
||||
# Requires NFSCL and NFS_ROOT
|
||||
options BOOTP_NFSROOT # NFS mount root filesystem using BOOTP info
|
||||
options BOOTP_NFSV3 # Use NFS v3 to NFS mount root
|
||||
options BOOTP_COMPAT # Workaround for broken bootp daemons.
|
||||
|
@ -3559,24 +3559,12 @@ netsmb/smb_smb.c optional netsmb
|
||||
netsmb/smb_subr.c optional netsmb
|
||||
netsmb/smb_trantcp.c optional netsmb
|
||||
netsmb/smb_usr.c optional netsmb
|
||||
nfs/bootp_subr.c optional bootp nfsclient | bootp nfscl
|
||||
nfs/krpc_subr.c optional bootp nfsclient | bootp nfscl
|
||||
nfs/nfs_common.c optional nfsclient | nfsserver
|
||||
nfs/nfs_diskless.c optional nfsclient nfs_root | nfscl nfs_root
|
||||
nfs/nfs_fha.c optional nfsserver | nfsd
|
||||
nfs/nfs_lock.c optional nfsclient | nfscl | nfslockd | nfsd
|
||||
nfsclient/nfs_bio.c optional nfsclient
|
||||
nfsclient/nfs_node.c optional nfsclient
|
||||
nfsclient/nfs_krpc.c optional nfsclient
|
||||
nfsclient/nfs_subs.c optional nfsclient
|
||||
nfsclient/nfs_nfsiod.c optional nfsclient
|
||||
nfsclient/nfs_vfsops.c optional nfsclient
|
||||
nfsclient/nfs_vnops.c optional nfsclient
|
||||
nfsserver/nfs_fha_old.c optional nfsserver
|
||||
nfsserver/nfs_serv.c optional nfsserver
|
||||
nfsserver/nfs_srvkrpc.c optional nfsserver
|
||||
nfsserver/nfs_srvsubs.c optional nfsserver
|
||||
nfs/nfs_nfssvc.c optional nfsserver | nfscl | nfsd
|
||||
nfs/bootp_subr.c optional bootp nfscl
|
||||
nfs/krpc_subr.c optional bootp nfscl
|
||||
nfs/nfs_diskless.c optional nfscl nfs_root
|
||||
nfs/nfs_fha.c optional nfsd
|
||||
nfs/nfs_lock.c optional nfscl | nfslockd | nfsd
|
||||
nfs/nfs_nfssvc.c optional nfscl | nfsd
|
||||
nlm/nlm_advlock.c optional nfslockd | nfsd
|
||||
nlm/nlm_prot_clnt.c optional nfslockd | nfsd
|
||||
nlm/nlm_prot_impl.c optional nfslockd | nfsd
|
||||
@ -3887,26 +3875,26 @@ opencrypto/gfmult.c optional crypto
|
||||
opencrypto/rmd160.c optional crypto | ipsec
|
||||
opencrypto/skipjack.c optional crypto
|
||||
opencrypto/xform.c optional crypto
|
||||
rpc/auth_none.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/auth_unix.c optional krpc | nfslockd | nfsclient | nfscl | nfsd
|
||||
rpc/authunix_prot.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/clnt_bck.c optional krpc | nfslockd | nfsserver | nfscl | nfsd
|
||||
rpc/clnt_dg.c optional krpc | nfslockd | nfsclient | nfscl | nfsd
|
||||
rpc/clnt_rc.c optional krpc | nfslockd | nfsclient | nfscl | nfsd
|
||||
rpc/clnt_vc.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/getnetconfig.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/replay.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/rpc_callmsg.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/rpc_generic.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/rpc_prot.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/rpcb_clnt.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/rpcb_prot.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/svc.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/svc_auth.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/svc_auth_unix.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
rpc/svc_dg.c optional krpc | nfslockd | nfsserver | nfscl | nfsd
|
||||
rpc/svc_generic.c optional krpc | nfslockd | nfsserver | nfscl | nfsd
|
||||
rpc/svc_vc.c optional krpc | nfslockd | nfsserver | nfscl | nfsd
|
||||
rpc/auth_none.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/auth_unix.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/authunix_prot.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/clnt_bck.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/clnt_dg.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/clnt_rc.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/clnt_vc.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/getnetconfig.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/replay.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/rpc_callmsg.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/rpc_generic.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/rpc_prot.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/rpcb_clnt.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/rpcb_prot.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/svc.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/svc_auth.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/svc_auth_unix.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/svc_dg.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/svc_generic.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/svc_vc.c optional krpc | nfslockd | nfscl | nfsd
|
||||
rpc/rpcsec_gss/rpcsec_gss.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi
|
||||
rpc/rpcsec_gss/rpcsec_gss_conf.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi
|
||||
rpc/rpcsec_gss/rpcsec_gss_misc.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi
|
||||
@ -4012,9 +4000,9 @@ xen/xenbus/xenbusb_if.m optional xen | xenhvm
|
||||
xen/xenbus/xenbusb.c optional xen | xenhvm
|
||||
xen/xenbus/xenbusb_front.c optional xen | xenhvm
|
||||
xen/xenbus/xenbusb_back.c optional xen | xenhvm
|
||||
xdr/xdr.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
xdr/xdr_array.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
xdr/xdr_mbuf.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
xdr/xdr_mem.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
xdr/xdr_reference.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
xdr/xdr_sizeof.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
|
||||
xdr/xdr.c optional krpc | nfslockd | nfscl | nfsd
|
||||
xdr/xdr_array.c optional krpc | nfslockd | nfscl | nfsd
|
||||
xdr/xdr_mbuf.c optional krpc | nfslockd | nfscl | nfsd
|
||||
xdr/xdr_mem.c optional krpc | nfslockd | nfscl | nfsd
|
||||
xdr/xdr_reference.c optional krpc | nfslockd | nfscl | nfsd
|
||||
xdr/xdr_sizeof.c optional krpc | nfslockd | nfscl | nfsd
|
||||
|
@ -253,11 +253,6 @@ KGSSAPI_DEBUG opt_kgssapi.h
|
||||
# sys/i386/i386/autoconf.c. If any of these filesystems are
|
||||
# statically compiled into the kernel, code for mounting them as root
|
||||
# filesystems will be enabled - but look below.
|
||||
NFSCLIENT opt_nfs.h
|
||||
NFSSERVER opt_nfs.h
|
||||
|
||||
# Use these options to compile the experimental nfs client and/or
|
||||
# server that supports NFSv4 into a kernel.
|
||||
# NFSCL - client
|
||||
# NFSD - server
|
||||
NFSCL opt_nfs.h
|
||||
|
@ -260,7 +260,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
|
||||
|
||||
client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog,
|
||||
nrp->nr_vers, sndreserve, rcvreserve);
|
||||
CLNT_CONTROL(client, CLSET_WAITCHAN, "newnfsreq");
|
||||
CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
|
||||
if (nmp != NULL) {
|
||||
if ((nmp->nm_flag & NFSMNT_INT))
|
||||
CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
|
||||
@ -1166,10 +1166,10 @@ nfs_msg(struct thread *td, const char *server, const char *msg, int error)
|
||||
|
||||
p = td ? td->td_proc : NULL;
|
||||
if (error) {
|
||||
tprintf(p, LOG_INFO, "newnfs server %s: %s, error %d\n",
|
||||
tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n",
|
||||
server, msg, error);
|
||||
} else {
|
||||
tprintf(p, LOG_INFO, "newnfs server %s: %s\n", server, msg);
|
||||
tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp,
|
||||
}
|
||||
np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
|
||||
|
||||
error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
|
||||
error = getnewvnode("nfs", mntp, &newnfs_vnodeops, &nvp);
|
||||
if (error) {
|
||||
uma_zfree(newnfsnode_zone, np);
|
||||
return (error);
|
||||
|
@ -198,7 +198,7 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp,
|
||||
}
|
||||
np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
|
||||
|
||||
error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
|
||||
error = getnewvnode("nfs", mntp, &newnfs_vnodeops, &nvp);
|
||||
if (error) {
|
||||
uma_zfree(newnfsnode_zone, np);
|
||||
FREE((caddr_t)nfhp, M_NFSFH);
|
||||
|
@ -152,7 +152,7 @@ MODULE_DEPEND(nfs, nfslock, 1, 1, 1);
|
||||
* will be defined for kernels built without NFS_ROOT, although it
|
||||
* isn't used in that case.
|
||||
*/
|
||||
#if !defined(NFS_ROOT) && !defined(NFSCLIENT)
|
||||
#if !defined(NFS_ROOT)
|
||||
struct nfs_diskless nfs_diskless = { { { 0 } } };
|
||||
struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
|
||||
int nfs_diskless_valid = 0;
|
||||
@ -704,7 +704,7 @@ nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
|
||||
while (newnfs_connect(nmp, &nmp->nm_sockreq,
|
||||
cred, td, 0)) {
|
||||
printf("newnfs_args: retrying connect\n");
|
||||
(void) nfs_catnap(PSOCK, 0, "newnfscon");
|
||||
(void) nfs_catnap(PSOCK, 0, "nfscon");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1063,7 +1063,7 @@ nfs_mount(struct mount *mp)
|
||||
* greater than NFS_MAXDGRAMDATA, those thread(s) will be
|
||||
* hung, retrying the RPC(s) forever. Usually these threads
|
||||
* will be seen doing an uninterruptible sleep on wait channel
|
||||
* "newnfsreq" (truncated to "newnfsre" by procstat).
|
||||
* "nfsreq".
|
||||
*/
|
||||
if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
|
||||
tprintf(td->td_proc, LOG_WARNING,
|
||||
|
@ -248,14 +248,11 @@ SUBDIR= \
|
||||
netfpga10g \
|
||||
${_netgraph} \
|
||||
${_nfe} \
|
||||
nfs_common \
|
||||
nfscl \
|
||||
nfsclient \
|
||||
nfscommon \
|
||||
nfsd \
|
||||
nfslock \
|
||||
nfslockd \
|
||||
nfsserver \
|
||||
nfssvc \
|
||||
nge \
|
||||
nmdm \
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
SUBDIR= dtmalloc \
|
||||
dtnfscl \
|
||||
dtnfsclient \
|
||||
dtrace \
|
||||
dtraceall \
|
||||
dtrace_test \
|
||||
|
@ -1,17 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SYSDIR?= ${.CURDIR}/../../..
|
||||
|
||||
.PATH: ${SYSDIR}/nfsclient
|
||||
|
||||
KMOD= dtnfsclient
|
||||
SRCS= nfs_kdtrace.c
|
||||
SRCS+= vnode_if.h
|
||||
|
||||
CFLAGS+= -I${SYSDIR}/cddl/compat/opensolaris \
|
||||
-I${SYSDIR}/cddl/contrib/opensolaris/uts/common \
|
||||
-I${SYSDIR}
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
||||
CFLAGS+= -include ${SYSDIR}/cddl/compat/opensolaris/sys/debug_compat.h
|
@ -69,9 +69,6 @@ MODULE_DEPEND(dtraceall, dtmalloc, 1, 1, 1);
|
||||
#if defined(NFSCLIENT)
|
||||
MODULE_DEPEND(dtraceall, dtnfscl, 1, 1, 1);
|
||||
#endif
|
||||
#if defined(NFSCLIENT)
|
||||
MODULE_DEPEND(dtraceall, dtnfsclient, 1, 1, 1);
|
||||
#endif
|
||||
#if defined(__amd64__) || defined(__i386__) || defined(__powerpc__)
|
||||
MODULE_DEPEND(dtraceall, fbt, 1, 1, 1);
|
||||
#endif
|
||||
|
@ -1,8 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../nfs
|
||||
|
||||
KMOD= nfs_common
|
||||
SRCS= nfs_common.c opt_nfs.h vnode_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
@ -1,32 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../nfsclient ${.CURDIR}/../../nfs ${.CURDIR}/../../rpc
|
||||
|
||||
KMOD= nfsclient
|
||||
SRCS= vnode_if.h \
|
||||
nfs_bio.c nfs_node.c nfs_subs.c nfs_nfsiod.c \
|
||||
nfs_vfsops.c nfs_vnops.c nfs_krpc.c \
|
||||
opt_inet.h opt_nfs.h opt_bootp.h opt_nfsroot.h
|
||||
SRCS+= opt_inet6.h opt_kgssapi.h
|
||||
|
||||
.if !defined(KERNBUILDDIR)
|
||||
NFS_ROOT?= 1 # 0/1 - requires NFS_ROOT to be configured in kernel
|
||||
|
||||
.if ${NFS_ROOT} > 0
|
||||
opt_nfsroot.h:
|
||||
echo "#define NFS_ROOT 1" > ${.TARGET}
|
||||
.endif
|
||||
.else
|
||||
OPT_NFS_ROOT!= cat ${KERNBUILDDIR}/opt_nfsroot.h
|
||||
.if empty(OPT_NFS_ROOT)
|
||||
NFS_ROOT= 0
|
||||
.else
|
||||
NFS_ROOT= 1
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.if ${NFS_ROOT} > 0
|
||||
SRCS+= nfs_diskless.c
|
||||
.endif
|
||||
|
||||
.include <bsd.kmod.mk>
|
@ -1,12 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../nfsserver ${.CURDIR}/../../nfs
|
||||
KMOD= nfsserver
|
||||
SRCS= vnode_if.h \
|
||||
nfs_fha.c nfs_fha_old.c nfs_serv.c nfs_srvkrpc.c nfs_srvsubs.c \
|
||||
opt_mac.h \
|
||||
opt_kgssapi.h \
|
||||
opt_nfs.h
|
||||
SRCS+= opt_inet6.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
@ -1735,9 +1735,6 @@ bootpc_init(void)
|
||||
goto out;
|
||||
}
|
||||
rootdevnames[0] = "nfs:";
|
||||
#ifdef NFSCLIENT
|
||||
rootdevnames[1] = "oldnfs:";
|
||||
#endif
|
||||
nfs_diskless_valid = 3;
|
||||
}
|
||||
|
||||
|
@ -1,407 +0,0 @@
|
||||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* These functions support the macros and help fiddle mbuf chains for
|
||||
* the nfs op functions. They do things like create the rpc header and
|
||||
* copy data between mbuf chains and uio lists.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfsserver/nfs.h>
|
||||
#include <nfs/xdr_subs.h>
|
||||
#include <nfs/nfs_common.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
enum vtype nv3tov_type[8]= {
|
||||
VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
|
||||
};
|
||||
nfstype nfsv3_type[9] = {
|
||||
NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON
|
||||
};
|
||||
|
||||
static void *nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos,
|
||||
int how);
|
||||
|
||||
SYSCTL_NODE(_vfs, OID_AUTO, nfs_common, CTLFLAG_RD, 0, "NFS common support");
|
||||
|
||||
static int nfs_realign_test;
|
||||
SYSCTL_INT(_vfs_nfs_common, OID_AUTO, realign_test, CTLFLAG_RD,
|
||||
&nfs_realign_test, 0, "Number of realign tests done");
|
||||
|
||||
static int nfs_realign_count;
|
||||
SYSCTL_INT(_vfs_nfs_common, OID_AUTO, realign_count, CTLFLAG_RD,
|
||||
&nfs_realign_count, 0, "Number of mbuf realignments done");
|
||||
|
||||
/*
|
||||
* copies mbuf chain to the uio scatter/gather list
|
||||
*/
|
||||
int
|
||||
nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
|
||||
{
|
||||
char *mbufcp, *uiocp;
|
||||
int xfer, left, len;
|
||||
struct mbuf *mp;
|
||||
long uiosiz, rem;
|
||||
int error = 0;
|
||||
|
||||
mp = *mrep;
|
||||
mbufcp = *dpos;
|
||||
len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
|
||||
rem = nfsm_rndup(siz)-siz;
|
||||
while (siz > 0) {
|
||||
if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
|
||||
return (EFBIG);
|
||||
left = uiop->uio_iov->iov_len;
|
||||
uiocp = uiop->uio_iov->iov_base;
|
||||
if (left > siz)
|
||||
left = siz;
|
||||
uiosiz = left;
|
||||
while (left > 0) {
|
||||
while (len == 0) {
|
||||
mp = mp->m_next;
|
||||
if (mp == NULL)
|
||||
return (EBADRPC);
|
||||
mbufcp = mtod(mp, caddr_t);
|
||||
len = mp->m_len;
|
||||
}
|
||||
xfer = (left > len) ? len : left;
|
||||
#ifdef notdef
|
||||
/* Not Yet.. */
|
||||
if (uiop->uio_iov->iov_op != NULL)
|
||||
(*(uiop->uio_iov->iov_op))
|
||||
(mbufcp, uiocp, xfer);
|
||||
else
|
||||
#endif
|
||||
if (uiop->uio_segflg == UIO_SYSSPACE)
|
||||
bcopy(mbufcp, uiocp, xfer);
|
||||
else
|
||||
copyout(mbufcp, uiocp, xfer);
|
||||
left -= xfer;
|
||||
len -= xfer;
|
||||
mbufcp += xfer;
|
||||
uiocp += xfer;
|
||||
uiop->uio_offset += xfer;
|
||||
uiop->uio_resid -= xfer;
|
||||
}
|
||||
if (uiop->uio_iov->iov_len <= siz) {
|
||||
uiop->uio_iovcnt--;
|
||||
uiop->uio_iov++;
|
||||
} else {
|
||||
uiop->uio_iov->iov_base =
|
||||
(char *)uiop->uio_iov->iov_base + uiosiz;
|
||||
uiop->uio_iov->iov_len -= uiosiz;
|
||||
}
|
||||
siz -= uiosiz;
|
||||
}
|
||||
*dpos = mbufcp;
|
||||
*mrep = mp;
|
||||
if (rem > 0) {
|
||||
if (len < rem)
|
||||
error = nfs_adv(mrep, dpos, rem, len);
|
||||
else
|
||||
*dpos += rem;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Help break down an mbuf chain by setting the first siz bytes contiguous
|
||||
* pointed to by returned val.
|
||||
* This is used by the macros nfsm_dissect for tough
|
||||
* cases. (The macros use the vars. dpos and dpos2)
|
||||
*/
|
||||
void *
|
||||
nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, int how)
|
||||
{
|
||||
struct mbuf *mp, *mp2;
|
||||
int siz2, xfer;
|
||||
caddr_t ptr, npos = NULL;
|
||||
void *ret;
|
||||
|
||||
mp = *mdp;
|
||||
while (left == 0) {
|
||||
*mdp = mp = mp->m_next;
|
||||
if (mp == NULL)
|
||||
return (NULL);
|
||||
left = mp->m_len;
|
||||
*dposp = mtod(mp, caddr_t);
|
||||
}
|
||||
if (left >= siz) {
|
||||
ret = *dposp;
|
||||
*dposp += siz;
|
||||
} else if (mp->m_next == NULL) {
|
||||
return (NULL);
|
||||
} else if (siz > MHLEN) {
|
||||
panic("nfs S too big");
|
||||
} else {
|
||||
mp2 = m_get(how, MT_DATA);
|
||||
if (mp2 == NULL)
|
||||
return (NULL);
|
||||
mp2->m_len = siz;
|
||||
mp2->m_next = mp->m_next;
|
||||
mp->m_next = mp2;
|
||||
mp->m_len -= left;
|
||||
mp = mp2;
|
||||
ptr = mtod(mp, caddr_t);
|
||||
ret = ptr;
|
||||
bcopy(*dposp, ptr, left); /* Copy what was left */
|
||||
siz2 = siz-left;
|
||||
ptr += left;
|
||||
mp2 = mp->m_next;
|
||||
npos = mtod(mp2, caddr_t);
|
||||
/* Loop around copying up the siz2 bytes */
|
||||
while (siz2 > 0) {
|
||||
if (mp2 == NULL)
|
||||
return (NULL);
|
||||
xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
|
||||
if (xfer > 0) {
|
||||
bcopy(mtod(mp2, caddr_t), ptr, xfer);
|
||||
mp2->m_data += xfer;
|
||||
mp2->m_len -= xfer;
|
||||
ptr += xfer;
|
||||
siz2 -= xfer;
|
||||
}
|
||||
if (siz2 > 0) {
|
||||
mp2 = mp2->m_next;
|
||||
if (mp2 != NULL)
|
||||
npos = mtod(mp2, caddr_t);
|
||||
}
|
||||
}
|
||||
*mdp = mp2;
|
||||
*dposp = mtod(mp2, caddr_t);
|
||||
if (!nfsm_aligned(*dposp, u_int32_t)) {
|
||||
bcopy(*dposp, npos, mp2->m_len);
|
||||
mp2->m_data = npos;
|
||||
*dposp = npos;
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance the position in the mbuf chain.
|
||||
*/
|
||||
int
|
||||
nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
|
||||
{
|
||||
struct mbuf *m;
|
||||
int s;
|
||||
|
||||
m = *mdp;
|
||||
s = left;
|
||||
while (s < offs) {
|
||||
offs -= s;
|
||||
m = m->m_next;
|
||||
if (m == NULL)
|
||||
return (EBADRPC);
|
||||
s = m->m_len;
|
||||
}
|
||||
*mdp = m;
|
||||
*dposp = mtod(m, caddr_t)+offs;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void *
|
||||
nfsm_build_xx(int s, struct mbuf **mb, caddr_t *bpos)
|
||||
{
|
||||
struct mbuf *mb2;
|
||||
void *ret;
|
||||
|
||||
if (s > M_TRAILINGSPACE(*mb)) {
|
||||
mb2 = m_get(M_WAITOK, MT_DATA);
|
||||
if (s > MLEN)
|
||||
panic("build > MLEN");
|
||||
(*mb)->m_next = mb2;
|
||||
*mb = mb2;
|
||||
(*mb)->m_len = 0;
|
||||
*bpos = mtod(*mb, caddr_t);
|
||||
}
|
||||
ret = *bpos;
|
||||
(*mb)->m_len += s;
|
||||
*bpos += s;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void *
|
||||
nfsm_dissect_xx(int s, struct mbuf **md, caddr_t *dpos)
|
||||
{
|
||||
|
||||
return (nfsm_dissect_xx_sub(s, md, dpos, M_WAITOK));
|
||||
}
|
||||
|
||||
void *
|
||||
nfsm_dissect_xx_nonblock(int s, struct mbuf **md, caddr_t *dpos)
|
||||
{
|
||||
|
||||
return (nfsm_dissect_xx_sub(s, md, dpos, M_NOWAIT));
|
||||
}
|
||||
|
||||
static void *
|
||||
nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos, int how)
|
||||
{
|
||||
int t1;
|
||||
char *cp2;
|
||||
void *ret;
|
||||
|
||||
t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
|
||||
if (t1 >= s) {
|
||||
ret = *dpos;
|
||||
*dpos += s;
|
||||
return (ret);
|
||||
}
|
||||
cp2 = nfsm_disct(md, dpos, s, t1, how);
|
||||
return (cp2);
|
||||
}
|
||||
|
||||
int
|
||||
nfsm_strsiz_xx(int *s, int m, struct mbuf **mb, caddr_t *bpos)
|
||||
{
|
||||
u_int32_t *tl;
|
||||
|
||||
tl = nfsm_dissect_xx(NFSX_UNSIGNED, mb, bpos);
|
||||
if (tl == NULL)
|
||||
return (EBADRPC);
|
||||
*s = fxdr_unsigned(int32_t, *tl);
|
||||
if (*s > m)
|
||||
return (EBADRPC);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
nfsm_adv_xx(int s, struct mbuf **md, caddr_t *dpos)
|
||||
{
|
||||
int t1;
|
||||
|
||||
t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
|
||||
if (t1 >= s) {
|
||||
*dpos += s;
|
||||
return (0);
|
||||
}
|
||||
t1 = nfs_adv(md, dpos, s, t1);
|
||||
if (t1)
|
||||
return (t1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for badly aligned mbuf data and realign by copying the unaligned
|
||||
* portion of the data into a new mbuf chain and freeing the portions of the
|
||||
* old chain that were replaced.
|
||||
*
|
||||
* We cannot simply realign the data within the existing mbuf chain because
|
||||
* the underlying buffers may contain other rpc commands and we cannot afford
|
||||
* to overwrite them.
|
||||
*
|
||||
* We would prefer to avoid this situation entirely. The situation does not
|
||||
* occur with NFS/UDP and is supposed to only occassionally occur with TCP.
|
||||
* Use vfs.nfs_common.realign_count and realign_test to check this.
|
||||
*/
|
||||
int
|
||||
nfs_realign(struct mbuf **pm, int how)
|
||||
{
|
||||
struct mbuf *m, *n;
|
||||
int off;
|
||||
|
||||
++nfs_realign_test;
|
||||
while ((m = *pm) != NULL) {
|
||||
if (!nfsm_aligned(m->m_len, u_int32_t) ||
|
||||
!nfsm_aligned(mtod(m, intptr_t), u_int32_t)) {
|
||||
/*
|
||||
* NB: we can't depend on m_pkthdr.len to help us
|
||||
* decide what to do here. May not be worth doing
|
||||
* the m_length calculation as m_copyback will
|
||||
* expand the mbuf chain below as needed.
|
||||
*/
|
||||
if (m_length(m, NULL) >= MINCLSIZE) {
|
||||
/* NB: m_copyback handles space > MCLBYTES */
|
||||
n = m_getcl(how, MT_DATA, 0);
|
||||
} else
|
||||
n = m_get(how, MT_DATA);
|
||||
if (n == NULL)
|
||||
return (ENOMEM);
|
||||
/*
|
||||
* Align the remainder of the mbuf chain.
|
||||
*/
|
||||
n->m_len = 0;
|
||||
off = 0;
|
||||
while (m != NULL) {
|
||||
m_copyback(n, off, m->m_len, mtod(m, caddr_t));
|
||||
off += m->m_len;
|
||||
m = m->m_next;
|
||||
}
|
||||
m_freem(*pm);
|
||||
*pm = n;
|
||||
++nfs_realign_count;
|
||||
break;
|
||||
}
|
||||
pm = &m->m_next;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static moduledata_t nfs_common_mod = {
|
||||
"nfs_common",
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
DECLARE_MODULE(nfs_common, nfs_common_mod, SI_SUB_VFS, SI_ORDER_ANY);
|
||||
MODULE_VERSION(nfs_common, 1);
|
File diff suppressed because it is too large
Load Diff
@ -1,542 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2009 Robert N. M. Watson
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed at the University of Cambridge Computer
|
||||
* Laboratory with support from a grant from Google, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
#include <sys/dtrace.h>
|
||||
#include <sys/dtrace_bsd.h>
|
||||
|
||||
#include <nfs/nfsproto.h>
|
||||
|
||||
/*
|
||||
* dtnfsclient is a DTrace provider that tracks the intent to perform RPCs
|
||||
* in the NFS client, as well as acess to and maintenance of the access and
|
||||
* attribute caches. This is not quite the same as RPCs, because NFS may
|
||||
* issue multiple RPC transactions in the event that authentication fails,
|
||||
* there's a jukebox error, or none at all if the access or attribute cache
|
||||
* hits. However, it cleanly represents the logical layer between RPC
|
||||
* transmission and vnode/vfs operations, providing access to state linking
|
||||
* the two.
|
||||
*/
|
||||
|
||||
static int dtnfsclient_unload(void);
|
||||
static void dtnfsclient_getargdesc(void *, dtrace_id_t, void *,
|
||||
dtrace_argdesc_t *);
|
||||
static void dtnfsclient_provide(void *, dtrace_probedesc_t *);
|
||||
static void dtnfsclient_destroy(void *, dtrace_id_t, void *);
|
||||
static void dtnfsclient_enable(void *, dtrace_id_t, void *);
|
||||
static void dtnfsclient_disable(void *, dtrace_id_t, void *);
|
||||
static void dtnfsclient_load(void *);
|
||||
|
||||
static dtrace_pattr_t dtnfsclient_attr = {
|
||||
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
|
||||
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
|
||||
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
|
||||
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
|
||||
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
|
||||
};
|
||||
|
||||
/*
|
||||
* Description of NFSv3 and (optional) NFSv2 probes for a procedure.
|
||||
*/
|
||||
struct dtnfsclient_rpc {
|
||||
char *nr_v3_name;
|
||||
char *nr_v2_name; /* Or NULL if none. */
|
||||
|
||||
/*
|
||||
* IDs for the start and done cases, for both NFSv2 and NFSv3.
|
||||
*/
|
||||
uint32_t nr_v2_id_start, nr_v2_id_done;
|
||||
uint32_t nr_v3_id_start, nr_v3_id_done;
|
||||
};
|
||||
|
||||
/*
|
||||
* This table is indexed by NFSv3 procedure number, but also used for NFSv2
|
||||
* procedure names.
|
||||
*/
|
||||
static struct dtnfsclient_rpc dtnfsclient_rpcs[NFS_NPROCS] = {
|
||||
{ "null", "null" },
|
||||
{ "getattr", "getattr" },
|
||||
{ "setattr", "setattr" },
|
||||
{ "lookup", "lookup" },
|
||||
{ "access" },
|
||||
{ "readlink", "readlink" },
|
||||
{ "read", "read" },
|
||||
{ "write", "write" },
|
||||
{ "create", "create" },
|
||||
{ "mkdir", "mkdir" },
|
||||
{ "symlink", "symlink" },
|
||||
{ "mknod" },
|
||||
{ "remove", "remove" },
|
||||
{ "rmdir", "rmdir" },
|
||||
{ "rename", "rename" },
|
||||
{ "link", "link" },
|
||||
{ "readdir", "readdir" },
|
||||
{ "readdirplus" },
|
||||
{ "fsstat", "statfs" },
|
||||
{ "fsinfo" },
|
||||
{ "pathconf" },
|
||||
{ "commit" },
|
||||
{ "noop" },
|
||||
};
|
||||
|
||||
/*
|
||||
* Module name strings.
|
||||
*/
|
||||
static char *dtnfsclient_accesscache_str = "accesscache";
|
||||
static char *dtnfsclient_attrcache_str = "attrcache";
|
||||
static char *dtnfsclient_nfs2_str = "nfs2";
|
||||
static char *dtnfsclient_nfs3_str = "nfs3";
|
||||
|
||||
/*
|
||||
* Function name strings.
|
||||
*/
|
||||
static char *dtnfsclient_flush_str = "flush";
|
||||
static char *dtnfsclient_load_str = "load";
|
||||
static char *dtnfsclient_get_str = "get";
|
||||
|
||||
/*
|
||||
* Name strings.
|
||||
*/
|
||||
static char *dtnfsclient_done_str = "done";
|
||||
static char *dtnfsclient_hit_str = "hit";
|
||||
static char *dtnfsclient_miss_str = "miss";
|
||||
static char *dtnfsclient_start_str = "start";
|
||||
|
||||
static dtrace_pops_t dtnfsclient_pops = {
|
||||
dtnfsclient_provide,
|
||||
NULL,
|
||||
dtnfsclient_enable,
|
||||
dtnfsclient_disable,
|
||||
NULL,
|
||||
NULL,
|
||||
dtnfsclient_getargdesc,
|
||||
NULL,
|
||||
NULL,
|
||||
dtnfsclient_destroy
|
||||
};
|
||||
|
||||
static dtrace_provider_id_t dtnfsclient_id;
|
||||
|
||||
/*
|
||||
* Most probes are generated from the above RPC table, but for access and
|
||||
* attribute caches, we have specific IDs we recognize and handle specially
|
||||
* in various spots.
|
||||
*/
|
||||
extern uint32_t nfsclient_accesscache_flush_done_id;
|
||||
extern uint32_t nfsclient_accesscache_get_hit_id;
|
||||
extern uint32_t nfsclient_accesscache_get_miss_id;
|
||||
extern uint32_t nfsclient_accesscache_load_done_id;
|
||||
|
||||
extern uint32_t nfsclient_attrcache_flush_done_id;
|
||||
extern uint32_t nfsclient_attrcache_get_hit_id;
|
||||
extern uint32_t nfsclient_attrcache_get_miss_id;
|
||||
extern uint32_t nfsclient_attrcache_load_done_id;
|
||||
|
||||
/*
|
||||
* When tracing on a procedure is enabled, the DTrace ID for an RPC event is
|
||||
* stored in one of these two NFS client-allocated arrays; 0 indicates that
|
||||
* the event is not being traced so probes should not be called.
|
||||
*
|
||||
* For simplicity, we allocate both v2 and v3 arrays as NFS_NPROCS, and the
|
||||
* v2 array is simply sparse.
|
||||
*/
|
||||
extern uint32_t nfsclient_nfs2_start_probes[NFS_NPROCS];
|
||||
extern uint32_t nfsclient_nfs2_done_probes[NFS_NPROCS];
|
||||
|
||||
extern uint32_t nfsclient_nfs3_start_probes[NFS_NPROCS];
|
||||
extern uint32_t nfsclient_nfs3_done_probes[NFS_NPROCS];
|
||||
|
||||
/*
|
||||
* Look up a DTrace probe ID to see if it's associated with a "done" event --
|
||||
* if so, we will return a fourth argument type of "int".
|
||||
*/
|
||||
static int
|
||||
dtnfs23_isdoneprobe(dtrace_id_t id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NFS_NPROCS; i++) {
|
||||
if (dtnfsclient_rpcs[i].nr_v3_id_done == id ||
|
||||
dtnfsclient_rpcs[i].nr_v2_id_done == id)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dtnfsclient_getargdesc(void *arg, dtrace_id_t id, void *parg,
|
||||
dtrace_argdesc_t *desc)
|
||||
{
|
||||
const char *p = NULL;
|
||||
|
||||
if (id == nfsclient_accesscache_flush_done_id ||
|
||||
id == nfsclient_attrcache_flush_done_id ||
|
||||
id == nfsclient_attrcache_get_miss_id) {
|
||||
switch (desc->dtargd_ndx) {
|
||||
case 0:
|
||||
p = "struct vnode *";
|
||||
break;
|
||||
default:
|
||||
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||
break;
|
||||
}
|
||||
} else if (id == nfsclient_accesscache_get_hit_id ||
|
||||
id == nfsclient_accesscache_get_miss_id) {
|
||||
switch (desc->dtargd_ndx) {
|
||||
case 0:
|
||||
p = "struct vnode *";
|
||||
break;
|
||||
case 1:
|
||||
p = "uid_t";
|
||||
break;
|
||||
case 2:
|
||||
p = "uint32_t";
|
||||
break;
|
||||
default:
|
||||
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||
break;
|
||||
}
|
||||
} else if (id == nfsclient_accesscache_load_done_id) {
|
||||
switch (desc->dtargd_ndx) {
|
||||
case 0:
|
||||
p = "struct vnode *";
|
||||
break;
|
||||
case 1:
|
||||
p = "uid_t";
|
||||
break;
|
||||
case 2:
|
||||
p = "uint32_t";
|
||||
break;
|
||||
case 3:
|
||||
p = "int";
|
||||
break;
|
||||
default:
|
||||
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||
break;
|
||||
}
|
||||
} else if (id == nfsclient_attrcache_get_hit_id) {
|
||||
switch (desc->dtargd_ndx) {
|
||||
case 0:
|
||||
p = "struct vnode *";
|
||||
break;
|
||||
case 1:
|
||||
p = "struct vattr *";
|
||||
break;
|
||||
default:
|
||||
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||
break;
|
||||
}
|
||||
} else if (id == nfsclient_attrcache_load_done_id) {
|
||||
switch (desc->dtargd_ndx) {
|
||||
case 0:
|
||||
p = "struct vnode *";
|
||||
break;
|
||||
case 1:
|
||||
p = "struct vattr *";
|
||||
break;
|
||||
case 2:
|
||||
p = "int";
|
||||
break;
|
||||
default:
|
||||
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (desc->dtargd_ndx) {
|
||||
case 0:
|
||||
p = "struct vnode *";
|
||||
break;
|
||||
case 1:
|
||||
p = "struct mbuf *";
|
||||
break;
|
||||
case 2:
|
||||
p = "struct ucred *";
|
||||
break;
|
||||
case 3:
|
||||
p = "int";
|
||||
break;
|
||||
case 4:
|
||||
if (dtnfs23_isdoneprobe(id)) {
|
||||
p = "int";
|
||||
break;
|
||||
}
|
||||
/* FALLSTHROUGH */
|
||||
default:
|
||||
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p != NULL)
|
||||
strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
|
||||
}
|
||||
|
||||
static void
|
||||
dtnfsclient_provide(void *arg, dtrace_probedesc_t *desc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (desc != NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Register access cache probes.
|
||||
*/
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
|
||||
nfsclient_accesscache_flush_done_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
|
||||
nfsclient_accesscache_get_hit_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
|
||||
nfsclient_accesscache_get_miss_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
|
||||
nfsclient_accesscache_load_done_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_accesscache_str,
|
||||
dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register attribute cache probes.
|
||||
*/
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
|
||||
nfsclient_attrcache_flush_done_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
|
||||
nfsclient_attrcache_get_hit_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
|
||||
nfsclient_attrcache_get_miss_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
|
||||
nfsclient_attrcache_load_done_id = dtrace_probe_create(
|
||||
dtnfsclient_id, dtnfsclient_attrcache_str,
|
||||
dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register NFSv2 RPC procedures; note sparseness check for each slot
|
||||
* in the NFSv3 procnum-indexed array.
|
||||
*/
|
||||
for (i = 0; i < NFS_NPROCS; i++) {
|
||||
if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
|
||||
dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
|
||||
dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) ==
|
||||
0) {
|
||||
dtnfsclient_rpcs[i].nr_v2_id_start =
|
||||
dtrace_probe_create(dtnfsclient_id,
|
||||
dtnfsclient_nfs2_str,
|
||||
dtnfsclient_rpcs[i].nr_v2_name,
|
||||
dtnfsclient_start_str, 0,
|
||||
&nfsclient_nfs2_start_probes[i]);
|
||||
}
|
||||
if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
|
||||
dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
|
||||
dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) ==
|
||||
0) {
|
||||
dtnfsclient_rpcs[i].nr_v2_id_done =
|
||||
dtrace_probe_create(dtnfsclient_id,
|
||||
dtnfsclient_nfs2_str,
|
||||
dtnfsclient_rpcs[i].nr_v2_name,
|
||||
dtnfsclient_done_str, 0,
|
||||
&nfsclient_nfs2_done_probes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Register NFSv3 RPC procedures.
|
||||
*/
|
||||
for (i = 0; i < NFS_NPROCS; i++) {
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
|
||||
dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) ==
|
||||
0) {
|
||||
dtnfsclient_rpcs[i].nr_v3_id_start =
|
||||
dtrace_probe_create(dtnfsclient_id,
|
||||
dtnfsclient_nfs3_str,
|
||||
dtnfsclient_rpcs[i].nr_v3_name,
|
||||
dtnfsclient_start_str, 0,
|
||||
&nfsclient_nfs3_start_probes[i]);
|
||||
}
|
||||
if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
|
||||
dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) ==
|
||||
0) {
|
||||
dtnfsclient_rpcs[i].nr_v3_id_done =
|
||||
dtrace_probe_create(dtnfsclient_id,
|
||||
dtnfsclient_nfs3_str,
|
||||
dtnfsclient_rpcs[i].nr_v3_name,
|
||||
dtnfsclient_done_str, 0,
|
||||
&nfsclient_nfs3_done_probes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
dtnfsclient_enable(void *arg, dtrace_id_t id, void *parg)
|
||||
{
|
||||
uint32_t *p = parg;
|
||||
void *f = dtrace_probe;
|
||||
|
||||
if (id == nfsclient_accesscache_flush_done_id)
|
||||
dtrace_nfsclient_accesscache_flush_done_probe = f;
|
||||
else if (id == nfsclient_accesscache_get_hit_id)
|
||||
dtrace_nfsclient_accesscache_get_hit_probe = f;
|
||||
else if (id == nfsclient_accesscache_get_miss_id)
|
||||
dtrace_nfsclient_accesscache_get_miss_probe = f;
|
||||
else if (id == nfsclient_accesscache_load_done_id)
|
||||
dtrace_nfsclient_accesscache_load_done_probe = f;
|
||||
else if (id == nfsclient_attrcache_flush_done_id)
|
||||
dtrace_nfsclient_attrcache_flush_done_probe = f;
|
||||
else if (id == nfsclient_attrcache_get_hit_id)
|
||||
dtrace_nfsclient_attrcache_get_hit_probe = f;
|
||||
else if (id == nfsclient_attrcache_get_miss_id)
|
||||
dtrace_nfsclient_attrcache_get_miss_probe = f;
|
||||
else if (id == nfsclient_attrcache_load_done_id)
|
||||
dtrace_nfsclient_attrcache_load_done_probe = f;
|
||||
else
|
||||
*p = id;
|
||||
}
|
||||
|
||||
static void
|
||||
dtnfsclient_disable(void *arg, dtrace_id_t id, void *parg)
|
||||
{
|
||||
uint32_t *p = parg;
|
||||
|
||||
if (id == nfsclient_accesscache_flush_done_id)
|
||||
dtrace_nfsclient_accesscache_flush_done_probe = NULL;
|
||||
else if (id == nfsclient_accesscache_get_hit_id)
|
||||
dtrace_nfsclient_accesscache_get_hit_probe = NULL;
|
||||
else if (id == nfsclient_accesscache_get_miss_id)
|
||||
dtrace_nfsclient_accesscache_get_miss_probe = NULL;
|
||||
else if (id == nfsclient_accesscache_load_done_id)
|
||||
dtrace_nfsclient_accesscache_load_done_probe = NULL;
|
||||
else if (id == nfsclient_attrcache_flush_done_id)
|
||||
dtrace_nfsclient_attrcache_flush_done_probe = NULL;
|
||||
else if (id == nfsclient_attrcache_get_hit_id)
|
||||
dtrace_nfsclient_attrcache_get_hit_probe = NULL;
|
||||
else if (id == nfsclient_attrcache_get_miss_id)
|
||||
dtrace_nfsclient_attrcache_get_miss_probe = NULL;
|
||||
else if (id == nfsclient_attrcache_load_done_id)
|
||||
dtrace_nfsclient_attrcache_load_done_probe = NULL;
|
||||
else
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dtnfsclient_load(void *dummy)
|
||||
{
|
||||
|
||||
if (dtrace_register("nfsclient", &dtnfsclient_attr,
|
||||
DTRACE_PRIV_USER, NULL, &dtnfsclient_pops, NULL,
|
||||
&dtnfsclient_id) != 0)
|
||||
return;
|
||||
|
||||
dtrace_nfsclient_nfs23_start_probe =
|
||||
(dtrace_nfsclient_nfs23_start_probe_func_t)dtrace_probe;
|
||||
dtrace_nfsclient_nfs23_done_probe =
|
||||
(dtrace_nfsclient_nfs23_done_probe_func_t)dtrace_probe;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dtnfsclient_unload()
|
||||
{
|
||||
|
||||
dtrace_nfsclient_nfs23_start_probe = NULL;
|
||||
dtrace_nfsclient_nfs23_done_probe = NULL;
|
||||
|
||||
return (dtrace_unregister(dtnfsclient_id));
|
||||
}
|
||||
|
||||
static int
|
||||
dtnfsclient_modevent(module_t mod __unused, int type, void *data __unused)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
break;
|
||||
|
||||
case MOD_UNLOAD:
|
||||
break;
|
||||
|
||||
case MOD_SHUTDOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSINIT(dtnfsclient_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
|
||||
dtnfsclient_load, NULL);
|
||||
SYSUNINIT(dtnfsclient_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
|
||||
dtnfsclient_unload, NULL);
|
||||
|
||||
DEV_MODULE(dtnfsclient, dtnfsclient_modevent, NULL);
|
||||
MODULE_VERSION(dtnfsclient, 1);
|
||||
MODULE_DEPEND(dtnfsclient, dtrace, 1, 1, 1);
|
||||
MODULE_DEPEND(dtnfsclient, opensolaris, 1, 1, 1);
|
||||
MODULE_DEPEND(dtnfsclient, oldnfs, 1, 1, 1);
|
@ -1,887 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1989, 1991, 1993, 1995
|
||||
* 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.
|
||||
*
|
||||
* @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Socket operations for use by nfs
|
||||
*/
|
||||
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_kgssapi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfsclient/nfs.h>
|
||||
#include <nfs/xdr_subs.h>
|
||||
#include <nfsclient/nfsm_subs.h>
|
||||
#include <nfsclient/nfsmount.h>
|
||||
#include <nfsclient/nfsnode.h>
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
#include <sys/dtrace_bsd.h>
|
||||
|
||||
dtrace_nfsclient_nfs23_start_probe_func_t
|
||||
dtrace_nfsclient_nfs23_start_probe;
|
||||
|
||||
dtrace_nfsclient_nfs23_done_probe_func_t
|
||||
dtrace_nfsclient_nfs23_done_probe;
|
||||
|
||||
/*
|
||||
* Registered probes by RPC type.
|
||||
*/
|
||||
uint32_t nfsclient_nfs2_start_probes[NFS_NPROCS];
|
||||
uint32_t nfsclient_nfs2_done_probes[NFS_NPROCS];
|
||||
|
||||
uint32_t nfsclient_nfs3_start_probes[NFS_NPROCS];
|
||||
uint32_t nfsclient_nfs3_done_probes[NFS_NPROCS];
|
||||
#endif
|
||||
|
||||
static int nfs_bufpackets = 4;
|
||||
static int nfs_reconnects;
|
||||
static int nfs3_jukebox_delay = 10;
|
||||
static int nfs_skip_wcc_data_onerr = 1;
|
||||
static int fake_wchan;
|
||||
|
||||
SYSCTL_DECL(_vfs_oldnfs);
|
||||
|
||||
SYSCTL_INT(_vfs_oldnfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0,
|
||||
"Buffer reservation size 2 < x < 64");
|
||||
SYSCTL_INT(_vfs_oldnfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0,
|
||||
"Number of times the nfs client has had to reconnect");
|
||||
SYSCTL_INT(_vfs_oldnfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW,
|
||||
&nfs3_jukebox_delay, 0,
|
||||
"Number of seconds to delay a retry after receiving EJUKEBOX");
|
||||
SYSCTL_INT(_vfs_oldnfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW,
|
||||
&nfs_skip_wcc_data_onerr, 0,
|
||||
"Disable weak cache consistency checking when server returns an error");
|
||||
|
||||
static void nfs_down(struct nfsmount *, struct thread *, const char *,
|
||||
int, int);
|
||||
static void nfs_up(struct nfsmount *, struct thread *, const char *,
|
||||
int, int);
|
||||
static int nfs_msg(struct thread *, const char *, const char *, int);
|
||||
|
||||
extern int nfsv2_procid[];
|
||||
|
||||
struct nfs_cached_auth {
|
||||
int ca_refs; /* refcount, including 1 from the cache */
|
||||
uid_t ca_uid; /* uid that corresponds to this auth */
|
||||
AUTH *ca_auth; /* RPC auth handle */
|
||||
};
|
||||
|
||||
/*
|
||||
* RTT estimator
|
||||
*/
|
||||
|
||||
static enum nfs_rto_timer_t nfs_proct[NFS_NPROCS] = {
|
||||
NFS_DEFAULT_TIMER, /* NULL */
|
||||
NFS_GETATTR_TIMER, /* GETATTR */
|
||||
NFS_DEFAULT_TIMER, /* SETATTR */
|
||||
NFS_LOOKUP_TIMER, /* LOOKUP */
|
||||
NFS_GETATTR_TIMER, /* ACCESS */
|
||||
NFS_READ_TIMER, /* READLINK */
|
||||
NFS_READ_TIMER, /* READ */
|
||||
NFS_WRITE_TIMER, /* WRITE */
|
||||
NFS_DEFAULT_TIMER, /* CREATE */
|
||||
NFS_DEFAULT_TIMER, /* MKDIR */
|
||||
NFS_DEFAULT_TIMER, /* SYMLINK */
|
||||
NFS_DEFAULT_TIMER, /* MKNOD */
|
||||
NFS_DEFAULT_TIMER, /* REMOVE */
|
||||
NFS_DEFAULT_TIMER, /* RMDIR */
|
||||
NFS_DEFAULT_TIMER, /* RENAME */
|
||||
NFS_DEFAULT_TIMER, /* LINK */
|
||||
NFS_READ_TIMER, /* READDIR */
|
||||
NFS_READ_TIMER, /* READDIRPLUS */
|
||||
NFS_DEFAULT_TIMER, /* FSSTAT */
|
||||
NFS_DEFAULT_TIMER, /* FSINFO */
|
||||
NFS_DEFAULT_TIMER, /* PATHCONF */
|
||||
NFS_DEFAULT_TIMER, /* COMMIT */
|
||||
NFS_DEFAULT_TIMER, /* NOOP */
|
||||
};
|
||||
|
||||
/*
|
||||
* Choose the correct RTT timer for this NFS procedure.
|
||||
*/
|
||||
static inline enum nfs_rto_timer_t
|
||||
nfs_rto_timer(u_int32_t procnum)
|
||||
{
|
||||
|
||||
return (nfs_proct[procnum]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the RTT estimator state for a new mount point.
|
||||
*/
|
||||
static void
|
||||
nfs_init_rtt(struct nfsmount *nmp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NFS_MAX_TIMER; i++) {
|
||||
nmp->nm_timers[i].rt_srtt = hz;
|
||||
nmp->nm_timers[i].rt_deviate = 0;
|
||||
nmp->nm_timers[i].rt_rtxcur = hz;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize sockets and congestion for a new NFS connection.
|
||||
* We do not free the sockaddr if error.
|
||||
*/
|
||||
int
|
||||
nfs_connect(struct nfsmount *nmp)
|
||||
{
|
||||
int rcvreserve, sndreserve;
|
||||
int pktscale;
|
||||
struct sockaddr *saddr;
|
||||
struct ucred *origcred;
|
||||
struct thread *td = curthread;
|
||||
CLIENT *client;
|
||||
struct netconfig *nconf;
|
||||
rpcvers_t vers;
|
||||
int one = 1, retries;
|
||||
struct timeval timo;
|
||||
|
||||
/*
|
||||
* We need to establish the socket using the credentials of
|
||||
* the mountpoint. Some parts of this process (such as
|
||||
* sobind() and soconnect()) will use the curent thread's
|
||||
* credential instead of the socket credential. To work
|
||||
* around this, temporarily change the current thread's
|
||||
* credential to that of the mountpoint.
|
||||
*
|
||||
* XXX: It would be better to explicitly pass the correct
|
||||
* credential to sobind() and soconnect().
|
||||
*/
|
||||
origcred = td->td_ucred;
|
||||
td->td_ucred = nmp->nm_mountp->mnt_cred;
|
||||
saddr = nmp->nm_nam;
|
||||
|
||||
vers = NFS_VER2;
|
||||
if (nmp->nm_flag & NFSMNT_NFSV3)
|
||||
vers = NFS_VER3;
|
||||
else if (nmp->nm_flag & NFSMNT_NFSV4)
|
||||
vers = NFS_VER4;
|
||||
if (saddr->sa_family == AF_INET)
|
||||
if (nmp->nm_sotype == SOCK_DGRAM)
|
||||
nconf = getnetconfigent("udp");
|
||||
else
|
||||
nconf = getnetconfigent("tcp");
|
||||
else
|
||||
if (nmp->nm_sotype == SOCK_DGRAM)
|
||||
nconf = getnetconfigent("udp6");
|
||||
else
|
||||
nconf = getnetconfigent("tcp6");
|
||||
|
||||
/*
|
||||
* Get buffer reservation size from sysctl, but impose reasonable
|
||||
* limits.
|
||||
*/
|
||||
pktscale = nfs_bufpackets;
|
||||
if (pktscale < 2)
|
||||
pktscale = 2;
|
||||
if (pktscale > 64)
|
||||
pktscale = 64;
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if (nmp->nm_sotype == SOCK_DGRAM) {
|
||||
sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
|
||||
rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
|
||||
NFS_MAXPKTHDR) * pktscale;
|
||||
} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
|
||||
sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
|
||||
rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
|
||||
NFS_MAXPKTHDR) * pktscale;
|
||||
} else {
|
||||
if (nmp->nm_sotype != SOCK_STREAM)
|
||||
panic("nfscon sotype");
|
||||
sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
|
||||
sizeof (u_int32_t)) * pktscale;
|
||||
rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
|
||||
sizeof (u_int32_t)) * pktscale;
|
||||
}
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
|
||||
client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers,
|
||||
sndreserve, rcvreserve);
|
||||
CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
|
||||
if (nmp->nm_flag & NFSMNT_INT)
|
||||
CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
|
||||
if (nmp->nm_flag & NFSMNT_RESVPORT)
|
||||
CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
|
||||
if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
|
||||
if (nmp->nm_sotype == SOCK_DGRAM)
|
||||
/*
|
||||
* For UDP, the large timeout for a reconnect will
|
||||
* be set to "nm_retry * nm_timeo / 2", so we only
|
||||
* want to do 2 reconnect timeout retries.
|
||||
*/
|
||||
retries = 2;
|
||||
else
|
||||
retries = nmp->nm_retry;
|
||||
} else
|
||||
retries = INT_MAX;
|
||||
CLNT_CONTROL(client, CLSET_RETRIES, &retries);
|
||||
|
||||
/*
|
||||
* For UDP, there are 2 timeouts:
|
||||
* - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer
|
||||
* that does a retransmit of an RPC request using the same socket
|
||||
* and xid. This is what you normally want to do, since NFS
|
||||
* servers depend on "same xid" for their Duplicate Request Cache.
|
||||
* - timeout specified in CLNT_CALL_MBUF(), which specifies when
|
||||
* retransmits on the same socket should fail and a fresh socket
|
||||
* created. Each of these timeouts counts as one CLSET_RETRIES,
|
||||
* as set above.
|
||||
* Set the initial retransmit timeout for UDP. This timeout doesn't
|
||||
* exist for TCP and the following call just fails, which is ok.
|
||||
*/
|
||||
timo.tv_sec = nmp->nm_timeo / NFS_HZ;
|
||||
timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
|
||||
CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo);
|
||||
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if (nmp->nm_client) {
|
||||
/*
|
||||
* Someone else already connected.
|
||||
*/
|
||||
CLNT_RELEASE(client);
|
||||
} else
|
||||
nmp->nm_client = client;
|
||||
|
||||
/*
|
||||
* Protocols that do not require connections may be optionally left
|
||||
* unconnected for servers that reply from a port other than NFS_PORT.
|
||||
*/
|
||||
if (!(nmp->nm_flag & NFSMNT_NOCONN)) {
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
CLNT_CONTROL(client, CLSET_CONNECT, &one);
|
||||
} else
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
|
||||
/* Restore current thread's credentials. */
|
||||
td->td_ucred = origcred;
|
||||
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
/* Initialize other non-zero congestion variables. */
|
||||
nfs_init_rtt(nmp);
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* NFS disconnect. Clean up and unlink.
|
||||
*/
|
||||
void
|
||||
nfs_disconnect(struct nfsmount *nmp)
|
||||
{
|
||||
CLIENT *client;
|
||||
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if (nmp->nm_client) {
|
||||
client = nmp->nm_client;
|
||||
nmp->nm_client = NULL;
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
rpc_gss_secpurge_call(client);
|
||||
CLNT_CLOSE(client);
|
||||
CLNT_RELEASE(client);
|
||||
} else
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
}
|
||||
|
||||
void
|
||||
nfs_safedisconnect(struct nfsmount *nmp)
|
||||
{
|
||||
|
||||
nfs_disconnect(nmp);
|
||||
}
|
||||
|
||||
static AUTH *
|
||||
nfs_getauth(struct nfsmount *nmp, struct ucred *cred)
|
||||
{
|
||||
rpc_gss_service_t svc;
|
||||
AUTH *auth;
|
||||
|
||||
switch (nmp->nm_secflavor) {
|
||||
case RPCSEC_GSS_KRB5:
|
||||
case RPCSEC_GSS_KRB5I:
|
||||
case RPCSEC_GSS_KRB5P:
|
||||
if (!nmp->nm_mech_oid)
|
||||
if (!rpc_gss_mech_to_oid_call("kerberosv5",
|
||||
&nmp->nm_mech_oid))
|
||||
return (NULL);
|
||||
if (nmp->nm_secflavor == RPCSEC_GSS_KRB5)
|
||||
svc = rpc_gss_svc_none;
|
||||
else if (nmp->nm_secflavor == RPCSEC_GSS_KRB5I)
|
||||
svc = rpc_gss_svc_integrity;
|
||||
else
|
||||
svc = rpc_gss_svc_privacy;
|
||||
auth = rpc_gss_secfind_call(nmp->nm_client, cred,
|
||||
nmp->nm_principal, nmp->nm_mech_oid, svc);
|
||||
if (auth)
|
||||
return (auth);
|
||||
/* fallthrough */
|
||||
case AUTH_SYS:
|
||||
default:
|
||||
return (authunix_create(cred));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback from the RPC code to generate up/down notifications.
|
||||
*/
|
||||
|
||||
struct nfs_feedback_arg {
|
||||
struct nfsmount *nf_mount;
|
||||
int nf_lastmsg; /* last tprintf */
|
||||
int nf_tprintfmsg;
|
||||
struct thread *nf_td;
|
||||
};
|
||||
|
||||
static void
|
||||
nfs_feedback(int type, int proc, void *arg)
|
||||
{
|
||||
struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg;
|
||||
struct nfsmount *nmp = nf->nf_mount;
|
||||
time_t now;
|
||||
|
||||
switch (type) {
|
||||
case FEEDBACK_REXMIT2:
|
||||
case FEEDBACK_RECONNECT:
|
||||
now = time_uptime;
|
||||
if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now) {
|
||||
nfs_down(nmp, nf->nf_td,
|
||||
"not responding", 0, NFSSTA_TIMEO);
|
||||
nf->nf_tprintfmsg = TRUE;
|
||||
nf->nf_lastmsg = now;
|
||||
}
|
||||
break;
|
||||
|
||||
case FEEDBACK_OK:
|
||||
nfs_up(nf->nf_mount, nf->nf_td,
|
||||
"is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_request - goes something like this
|
||||
* - fill in request struct
|
||||
* - links it into list
|
||||
* - calls nfs_send() for first transmit
|
||||
* - calls nfs_receive() to get reply
|
||||
* - break down rpc header and return with nfs reply pointed to
|
||||
* by mrep or error
|
||||
* nb: always frees up mreq mbuf list
|
||||
*/
|
||||
int
|
||||
nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum,
|
||||
struct thread *td, struct ucred *cred, struct mbuf **mrp,
|
||||
struct mbuf **mdp, caddr_t *dposp)
|
||||
{
|
||||
struct mbuf *mrep;
|
||||
u_int32_t *tl;
|
||||
struct nfsmount *nmp;
|
||||
struct mbuf *md;
|
||||
time_t waituntil;
|
||||
caddr_t dpos;
|
||||
int error = 0, timeo;
|
||||
AUTH *auth = NULL;
|
||||
enum nfs_rto_timer_t timer;
|
||||
struct nfs_feedback_arg nf;
|
||||
struct rpc_callextra ext;
|
||||
enum clnt_stat stat;
|
||||
struct timeval timo;
|
||||
|
||||
/* Reject requests while attempting a forced unmount. */
|
||||
if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) {
|
||||
m_freem(mreq);
|
||||
return (ESTALE);
|
||||
}
|
||||
nmp = VFSTONFS(vp->v_mount);
|
||||
bzero(&nf, sizeof(struct nfs_feedback_arg));
|
||||
nf.nf_mount = nmp;
|
||||
nf.nf_td = td;
|
||||
nf.nf_lastmsg = time_uptime -
|
||||
((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay));
|
||||
|
||||
/*
|
||||
* XXX if not already connected call nfs_connect now. Longer
|
||||
* term, change nfs_mount to call nfs_connect unconditionally
|
||||
* and let clnt_reconnect_create handle reconnects.
|
||||
*/
|
||||
if (!nmp->nm_client)
|
||||
nfs_connect(nmp);
|
||||
|
||||
auth = nfs_getauth(nmp, cred);
|
||||
if (!auth) {
|
||||
m_freem(mreq);
|
||||
return (EACCES);
|
||||
}
|
||||
bzero(&ext, sizeof(ext));
|
||||
ext.rc_auth = auth;
|
||||
|
||||
ext.rc_feedback = nfs_feedback;
|
||||
ext.rc_feedback_arg = &nf;
|
||||
|
||||
/*
|
||||
* Use a conservative timeout for RPCs other than getattr,
|
||||
* lookup, read or write. The justification for doing "other"
|
||||
* this way is that these RPCs happen so infrequently that
|
||||
* timer est. would probably be stale. Also, since many of
|
||||
* these RPCs are non-idempotent, a conservative timeout is
|
||||
* desired.
|
||||
*/
|
||||
timer = nfs_rto_timer(procnum);
|
||||
if (timer != NFS_DEFAULT_TIMER)
|
||||
ext.rc_timers = &nmp->nm_timers[timer - 1];
|
||||
else
|
||||
ext.rc_timers = NULL;
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
if (dtrace_nfsclient_nfs23_start_probe != NULL) {
|
||||
uint32_t probe_id;
|
||||
int probe_procnum;
|
||||
|
||||
if (nmp->nm_flag & NFSMNT_NFSV3) {
|
||||
probe_id = nfsclient_nfs3_start_probes[procnum];
|
||||
probe_procnum = procnum;
|
||||
} else {
|
||||
probe_id = nfsclient_nfs2_start_probes[procnum];
|
||||
probe_procnum = nfsv2_procid[procnum];
|
||||
}
|
||||
if (probe_id != 0)
|
||||
(dtrace_nfsclient_nfs23_start_probe)(probe_id, vp,
|
||||
mreq, cred, probe_procnum);
|
||||
}
|
||||
#endif
|
||||
|
||||
nfsstats.rpcrequests++;
|
||||
tryagain:
|
||||
/*
|
||||
* This timeout specifies when a new socket should be created,
|
||||
* along with new xid values. For UDP, this should be done
|
||||
* infrequently, since retransmits of RPC requests should normally
|
||||
* use the same xid.
|
||||
*/
|
||||
if (nmp->nm_sotype == SOCK_DGRAM) {
|
||||
if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
|
||||
/*
|
||||
* CLSET_RETRIES is set to 2, so this should be half
|
||||
* of the total timeout required.
|
||||
*/
|
||||
timeo = nmp->nm_retry * nmp->nm_timeo / 2;
|
||||
if (timeo < 1)
|
||||
timeo = 1;
|
||||
timo.tv_sec = timeo / NFS_HZ;
|
||||
timo.tv_usec = (timeo % NFS_HZ) * 1000000 / NFS_HZ;
|
||||
} else {
|
||||
/* For UDP hard mounts, use a large value. */
|
||||
timo.tv_sec = NFS_MAXTIMEO / NFS_HZ;
|
||||
timo.tv_usec = 0;
|
||||
}
|
||||
} else {
|
||||
timo.tv_sec = nmp->nm_timeo / NFS_HZ;
|
||||
timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
|
||||
}
|
||||
mrep = NULL;
|
||||
stat = CLNT_CALL_MBUF(nmp->nm_client, &ext,
|
||||
(nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum],
|
||||
mreq, &mrep, timo);
|
||||
|
||||
/*
|
||||
* If there was a successful reply and a tprintf msg.
|
||||
* tprintf a response.
|
||||
*/
|
||||
if (stat == RPC_SUCCESS)
|
||||
error = 0;
|
||||
else if (stat == RPC_TIMEDOUT) {
|
||||
nfsstats.rpctimeouts++;
|
||||
error = ETIMEDOUT;
|
||||
} else if (stat == RPC_VERSMISMATCH) {
|
||||
nfsstats.rpcinvalid++;
|
||||
error = EOPNOTSUPP;
|
||||
} else if (stat == RPC_PROGVERSMISMATCH) {
|
||||
nfsstats.rpcinvalid++;
|
||||
error = EPROTONOSUPPORT;
|
||||
} else if (stat == RPC_INTR) {
|
||||
error = EINTR;
|
||||
} else {
|
||||
nfsstats.rpcinvalid++;
|
||||
error = EACCES;
|
||||
}
|
||||
if (error)
|
||||
goto nfsmout;
|
||||
|
||||
KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n"));
|
||||
|
||||
/*
|
||||
* Search for any mbufs that are not a multiple of 4 bytes long
|
||||
* or with m_data not longword aligned.
|
||||
* These could cause pointer alignment problems, so copy them to
|
||||
* well aligned mbufs.
|
||||
*/
|
||||
error = nfs_realign(&mrep, M_NOWAIT);
|
||||
if (error == ENOMEM) {
|
||||
m_freem(mrep);
|
||||
AUTH_DESTROY(auth);
|
||||
nfsstats.rpcinvalid++;
|
||||
return (error);
|
||||
}
|
||||
|
||||
md = mrep;
|
||||
dpos = mtod(mrep, caddr_t);
|
||||
tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
|
||||
if (*tl != 0) {
|
||||
error = fxdr_unsigned(int, *tl);
|
||||
if ((nmp->nm_flag & NFSMNT_NFSV3) &&
|
||||
error == NFSERR_TRYLATER) {
|
||||
m_freem(mrep);
|
||||
error = 0;
|
||||
waituntil = time_second + nfs3_jukebox_delay;
|
||||
while (time_second < waituntil)
|
||||
(void)tsleep(&fake_wchan, PSOCK, "nqnfstry",
|
||||
hz);
|
||||
goto tryagain;
|
||||
}
|
||||
/*
|
||||
* Make sure NFSERR_RETERR isn't bogusly set by a server
|
||||
* such as amd. (No actual NFS error has bit 31 set.)
|
||||
*/
|
||||
error &= ~NFSERR_RETERR;
|
||||
|
||||
/*
|
||||
* If the File Handle was stale, invalidate the lookup
|
||||
* cache, just in case.
|
||||
*/
|
||||
if (error == ESTALE)
|
||||
nfs_purgecache(vp);
|
||||
/*
|
||||
* Skip wcc data on non-ENOENT NFS errors for now.
|
||||
* NetApp filers return corrupt postop attrs in the
|
||||
* wcc data for NFS err EROFS. Not sure if they could
|
||||
* return corrupt postop attrs for others errors.
|
||||
* Blocking ENOENT post-op attributes breaks negative
|
||||
* name caching, so always allow it through.
|
||||
*/
|
||||
if ((nmp->nm_flag & NFSMNT_NFSV3) &&
|
||||
(!nfs_skip_wcc_data_onerr || error == ENOENT)) {
|
||||
*mrp = mrep;
|
||||
*mdp = md;
|
||||
*dposp = dpos;
|
||||
error |= NFSERR_RETERR;
|
||||
} else
|
||||
m_freem(mrep);
|
||||
goto nfsmout;
|
||||
}
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
if (dtrace_nfsclient_nfs23_done_probe != NULL) {
|
||||
uint32_t probe_id;
|
||||
int probe_procnum;
|
||||
|
||||
if (nmp->nm_flag & NFSMNT_NFSV3) {
|
||||
probe_id = nfsclient_nfs3_done_probes[procnum];
|
||||
probe_procnum = procnum;
|
||||
} else {
|
||||
probe_id = nfsclient_nfs2_done_probes[procnum];
|
||||
probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ?
|
||||
procnum : nfsv2_procid[procnum];
|
||||
}
|
||||
if (probe_id != 0)
|
||||
(dtrace_nfsclient_nfs23_done_probe)(probe_id, vp,
|
||||
mreq, cred, probe_procnum, 0);
|
||||
}
|
||||
#endif
|
||||
m_freem(mreq);
|
||||
*mrp = mrep;
|
||||
*mdp = md;
|
||||
*dposp = dpos;
|
||||
AUTH_DESTROY(auth);
|
||||
return (0);
|
||||
|
||||
nfsmout:
|
||||
#ifdef KDTRACE_HOOKS
|
||||
if (dtrace_nfsclient_nfs23_done_probe != NULL) {
|
||||
uint32_t probe_id;
|
||||
int probe_procnum;
|
||||
|
||||
if (nmp->nm_flag & NFSMNT_NFSV3) {
|
||||
probe_id = nfsclient_nfs3_done_probes[procnum];
|
||||
probe_procnum = procnum;
|
||||
} else {
|
||||
probe_id = nfsclient_nfs2_done_probes[procnum];
|
||||
probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ?
|
||||
procnum : nfsv2_procid[procnum];
|
||||
}
|
||||
if (probe_id != 0)
|
||||
(dtrace_nfsclient_nfs23_done_probe)(probe_id, vp,
|
||||
mreq, cred, probe_procnum, error);
|
||||
}
|
||||
#endif
|
||||
m_freem(mreq);
|
||||
if (auth)
|
||||
AUTH_DESTROY(auth);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
|
||||
* wait for all requests to complete. This is used by forced unmounts
|
||||
* to terminate any outstanding RPCs.
|
||||
*/
|
||||
int
|
||||
nfs_nmcancelreqs(struct nfsmount *nmp)
|
||||
{
|
||||
|
||||
if (nmp->nm_client)
|
||||
CLNT_CLOSE(nmp->nm_client);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Any signal that can interrupt an NFS operation in an intr mount
|
||||
* should be added to this set. SIGSTOP and SIGKILL cannot be masked.
|
||||
*/
|
||||
int nfs_sig_set[] = {
|
||||
SIGINT,
|
||||
SIGTERM,
|
||||
SIGHUP,
|
||||
SIGKILL,
|
||||
SIGQUIT
|
||||
};
|
||||
|
||||
/*
|
||||
* Check to see if one of the signals in our subset is pending on
|
||||
* the process (in an intr mount).
|
||||
*/
|
||||
static int
|
||||
nfs_sig_pending(sigset_t set)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++)
|
||||
if (SIGISMEMBER(set, nfs_sig_set[i]))
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The set/restore sigmask functions are used to (temporarily) overwrite
|
||||
* the thread td_sigmask during an RPC call (for example). These are also
|
||||
* used in other places in the NFS client that might tsleep().
|
||||
*/
|
||||
void
|
||||
nfs_set_sigmask(struct thread *td, sigset_t *oldset)
|
||||
{
|
||||
sigset_t newset;
|
||||
int i;
|
||||
struct proc *p;
|
||||
|
||||
SIGFILLSET(newset);
|
||||
if (td == NULL)
|
||||
td = curthread; /* XXX */
|
||||
p = td->td_proc;
|
||||
/* Remove the NFS set of signals from newset. */
|
||||
PROC_LOCK(p);
|
||||
mtx_lock(&p->p_sigacts->ps_mtx);
|
||||
for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) {
|
||||
/*
|
||||
* But make sure we leave the ones already masked
|
||||
* by the process, i.e. remove the signal from the
|
||||
* temporary signalmask only if it wasn't already
|
||||
* in p_sigmask.
|
||||
*/
|
||||
if (!SIGISMEMBER(td->td_sigmask, nfs_sig_set[i]) &&
|
||||
!SIGISMEMBER(p->p_sigacts->ps_sigignore, nfs_sig_set[i]))
|
||||
SIGDELSET(newset, nfs_sig_set[i]);
|
||||
}
|
||||
mtx_unlock(&p->p_sigacts->ps_mtx);
|
||||
kern_sigprocmask(td, SIG_SETMASK, &newset, oldset,
|
||||
SIGPROCMASK_PROC_LOCKED);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
|
||||
void
|
||||
nfs_restore_sigmask(struct thread *td, sigset_t *set)
|
||||
{
|
||||
if (td == NULL)
|
||||
td = curthread; /* XXX */
|
||||
kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* NFS wrapper to msleep(), that shoves a new p_sigmask and restores the
|
||||
* old one after msleep() returns.
|
||||
*/
|
||||
int
|
||||
nfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority,
|
||||
char *wmesg, int timo)
|
||||
{
|
||||
sigset_t oldset;
|
||||
int error;
|
||||
struct proc *p;
|
||||
|
||||
if ((priority & PCATCH) == 0)
|
||||
return msleep(ident, mtx, priority, wmesg, timo);
|
||||
if (td == NULL)
|
||||
td = curthread; /* XXX */
|
||||
nfs_set_sigmask(td, &oldset);
|
||||
error = msleep(ident, mtx, priority, wmesg, timo);
|
||||
nfs_restore_sigmask(td, &oldset);
|
||||
p = td->td_proc;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for a termination condition pending on the process.
|
||||
* This is used for NFSMNT_INT mounts.
|
||||
*/
|
||||
int
|
||||
nfs_sigintr(struct nfsmount *nmp, struct thread *td)
|
||||
{
|
||||
struct proc *p;
|
||||
sigset_t tmpset;
|
||||
|
||||
/* Terminate all requests while attempting a forced unmount. */
|
||||
if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
|
||||
return (EIO);
|
||||
if (!(nmp->nm_flag & NFSMNT_INT))
|
||||
return (0);
|
||||
if (td == NULL)
|
||||
return (0);
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
tmpset = p->p_siglist;
|
||||
SIGSETOR(tmpset, td->td_siglist);
|
||||
SIGSETNAND(tmpset, td->td_sigmask);
|
||||
mtx_lock(&p->p_sigacts->ps_mtx);
|
||||
SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
|
||||
mtx_unlock(&p->p_sigacts->ps_mtx);
|
||||
if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist))
|
||||
&& nfs_sig_pending(tmpset)) {
|
||||
PROC_UNLOCK(p);
|
||||
return (EINTR);
|
||||
}
|
||||
PROC_UNLOCK(p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
nfs_msg(struct thread *td, const char *server, const char *msg, int error)
|
||||
{
|
||||
struct proc *p;
|
||||
|
||||
p = td ? td->td_proc : NULL;
|
||||
if (error)
|
||||
tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", server,
|
||||
msg, error);
|
||||
else
|
||||
tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg,
|
||||
int error, int flags)
|
||||
{
|
||||
if (nmp == NULL)
|
||||
return;
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) {
|
||||
nmp->nm_state |= NFSSTA_TIMEO;
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
|
||||
VQ_NOTRESP, 0);
|
||||
} else
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if ((flags & NFSSTA_LOCKTIMEO) &&
|
||||
!(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
|
||||
nmp->nm_state |= NFSSTA_LOCKTIMEO;
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
|
||||
VQ_NOTRESPLOCK, 0);
|
||||
} else
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg,
|
||||
int flags, int tprintfmsg)
|
||||
{
|
||||
if (nmp == NULL)
|
||||
return;
|
||||
if (tprintfmsg)
|
||||
nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0);
|
||||
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) {
|
||||
nmp->nm_state &= ~NFSSTA_TIMEO;
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
|
||||
VQ_NOTRESP, 1);
|
||||
} else
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
|
||||
mtx_lock(&nmp->nm_mtx);
|
||||
if ((flags & NFSSTA_LOCKTIMEO) &&
|
||||
(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
|
||||
nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
|
||||
VQ_NOTRESPLOCK, 1);
|
||||
} else
|
||||
mtx_unlock(&nmp->nm_mtx);
|
||||
}
|
@ -1,346 +0,0 @@
|
||||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/lockf.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <nfs/xdr_subs.h>
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfsclient/nfs.h>
|
||||
#include <nfsclient/nfsm_subs.h>
|
||||
#include <nfsclient/nfsmount.h>
|
||||
#include <nfsclient/nfsnode.h>
|
||||
#include <nfs/nfs_lock.h>
|
||||
|
||||
static MALLOC_DEFINE(M_NFSSVC, "nfsclient_srvsock", "Nfs server structure");
|
||||
|
||||
static void nfssvc_iod(void *);
|
||||
|
||||
static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
|
||||
|
||||
SYSCTL_DECL(_vfs_oldnfs);
|
||||
|
||||
/* Maximum number of seconds a nfsiod kthread will sleep before exiting */
|
||||
static unsigned int nfs_iodmaxidle = 120;
|
||||
SYSCTL_UINT(_vfs_oldnfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &nfs_iodmaxidle, 0,
|
||||
"Max number of seconds an nfsiod kthread will sleep before exiting");
|
||||
|
||||
/* Maximum number of nfsiod kthreads */
|
||||
unsigned int nfs_iodmax = 20;
|
||||
|
||||
/* Minimum number of nfsiod kthreads to keep as spares */
|
||||
static unsigned int nfs_iodmin = 0;
|
||||
|
||||
static int nfs_nfsiodnew_sync(void);
|
||||
|
||||
static int
|
||||
sysctl_iodmin(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error, i;
|
||||
int newmin;
|
||||
|
||||
newmin = nfs_iodmin;
|
||||
error = sysctl_handle_int(oidp, &newmin, 0, req);
|
||||
if (error || (req->newptr == NULL))
|
||||
return (error);
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
if (newmin > nfs_iodmax) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
nfs_iodmin = newmin;
|
||||
if (nfs_numasync >= nfs_iodmin)
|
||||
goto out;
|
||||
/*
|
||||
* If the current number of nfsiod is lower
|
||||
* than the new minimum, create some more.
|
||||
*/
|
||||
for (i = nfs_iodmin - nfs_numasync; i > 0; i--)
|
||||
nfs_nfsiodnew_sync();
|
||||
out:
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
return (0);
|
||||
}
|
||||
SYSCTL_PROC(_vfs_oldnfs, OID_AUTO, iodmin, CTLTYPE_UINT | CTLFLAG_RW, 0,
|
||||
sizeof (nfs_iodmin), sysctl_iodmin, "IU",
|
||||
"Min number of nfsiod kthreads to keep as spares");
|
||||
|
||||
|
||||
static int
|
||||
sysctl_iodmax(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error, i;
|
||||
int iod, newmax;
|
||||
|
||||
newmax = nfs_iodmax;
|
||||
error = sysctl_handle_int(oidp, &newmax, 0, req);
|
||||
if (error || (req->newptr == NULL))
|
||||
return (error);
|
||||
if (newmax > NFS_MAXASYNCDAEMON)
|
||||
return (EINVAL);
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
nfs_iodmax = newmax;
|
||||
if (nfs_numasync <= nfs_iodmax)
|
||||
goto out;
|
||||
/*
|
||||
* If there are some asleep nfsiods that should
|
||||
* exit, wakeup() them so that they check nfs_iodmax
|
||||
* and exit. Those who are active will exit as
|
||||
* soon as they finish I/O.
|
||||
*/
|
||||
iod = nfs_numasync - 1;
|
||||
for (i = 0; i < nfs_numasync - nfs_iodmax; i++) {
|
||||
if (nfs_iodwant[iod] == NFSIOD_AVAILABLE)
|
||||
wakeup(&nfs_iodwant[iod]);
|
||||
iod--;
|
||||
}
|
||||
out:
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
return (0);
|
||||
}
|
||||
SYSCTL_PROC(_vfs_oldnfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0,
|
||||
sizeof (nfs_iodmax), sysctl_iodmax, "IU",
|
||||
"Max number of nfsiod kthreads");
|
||||
|
||||
static int
|
||||
nfs_nfsiodnew_sync(void)
|
||||
{
|
||||
int error, i;
|
||||
|
||||
mtx_assert(&nfs_iod_mtx, MA_OWNED);
|
||||
for (i = 0; i < nfs_iodmax; i++) {
|
||||
if (nfs_asyncdaemon[i] == 0) {
|
||||
nfs_asyncdaemon[i] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == nfs_iodmax)
|
||||
return (0);
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL,
|
||||
RFHIGHPID, 0, "nfsiod %d", i);
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
if (error == 0) {
|
||||
nfs_numasync++;
|
||||
nfs_iodwant[i] = NFSIOD_AVAILABLE;
|
||||
} else
|
||||
nfs_asyncdaemon[i] = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
nfs_nfsiodnew_tq(__unused void *arg, int pending)
|
||||
{
|
||||
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
while (pending > 0) {
|
||||
pending--;
|
||||
nfs_nfsiodnew_sync();
|
||||
}
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
}
|
||||
|
||||
void
|
||||
nfs_nfsiodnew(void)
|
||||
{
|
||||
|
||||
mtx_assert(&nfs_iod_mtx, MA_OWNED);
|
||||
taskqueue_enqueue(taskqueue_thread, &nfs_nfsiodnew_task);
|
||||
}
|
||||
|
||||
static void
|
||||
nfsiod_setup(void *dummy)
|
||||
{
|
||||
int error;
|
||||
|
||||
TUNABLE_INT_FETCH("vfs.oldnfs.iodmin", &nfs_iodmin);
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
/* Silently limit the start number of nfsiod's */
|
||||
if (nfs_iodmin > NFS_MAXASYNCDAEMON)
|
||||
nfs_iodmin = NFS_MAXASYNCDAEMON;
|
||||
|
||||
while (nfs_numasync < nfs_iodmin) {
|
||||
error = nfs_nfsiodnew_sync();
|
||||
if (error == -1)
|
||||
panic("nfsiod_setup: nfs_nfsiodnew failed");
|
||||
}
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
}
|
||||
SYSINIT(nfsiod, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, nfsiod_setup, NULL);
|
||||
|
||||
static int nfs_defect = 0;
|
||||
SYSCTL_INT(_vfs_oldnfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0,
|
||||
"Allow nfsiods to migrate serving different mounts");
|
||||
|
||||
/*
|
||||
* Asynchronous I/O daemons for client nfs.
|
||||
* They do read-ahead and write-behind operations on the block I/O cache.
|
||||
* Returns if we hit the timeout defined by the iodmaxidle sysctl.
|
||||
*/
|
||||
static void
|
||||
nfssvc_iod(void *instance)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct nfsmount *nmp;
|
||||
int myiod, timo;
|
||||
int error = 0;
|
||||
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
myiod = (int *)instance - nfs_asyncdaemon;
|
||||
/*
|
||||
* Main loop
|
||||
*/
|
||||
for (;;) {
|
||||
while (((nmp = nfs_iodmount[myiod]) == NULL)
|
||||
|| !TAILQ_FIRST(&nmp->nm_bufq)) {
|
||||
if (myiod >= nfs_iodmax)
|
||||
goto finish;
|
||||
if (nmp)
|
||||
nmp->nm_bufqiods--;
|
||||
if (nfs_iodwant[myiod] == NFSIOD_NOT_AVAILABLE)
|
||||
nfs_iodwant[myiod] = NFSIOD_AVAILABLE;
|
||||
nfs_iodmount[myiod] = NULL;
|
||||
/*
|
||||
* Always keep at least nfs_iodmin kthreads.
|
||||
*/
|
||||
timo = (myiod < nfs_iodmin) ? 0 : nfs_iodmaxidle * hz;
|
||||
error = msleep(&nfs_iodwant[myiod], &nfs_iod_mtx, PWAIT | PCATCH,
|
||||
"-", timo);
|
||||
if (error) {
|
||||
nmp = nfs_iodmount[myiod];
|
||||
/*
|
||||
* Rechecking the nm_bufq closes a rare race where the
|
||||
* nfsiod is woken up at the exact time the idle timeout
|
||||
* fires
|
||||
*/
|
||||
if (nmp && TAILQ_FIRST(&nmp->nm_bufq))
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
|
||||
int giant_locked = 0;
|
||||
|
||||
/* Take one off the front of the list */
|
||||
TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
|
||||
nmp->nm_bufqlen--;
|
||||
if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) {
|
||||
nmp->nm_bufqwant = 0;
|
||||
wakeup(&nmp->nm_bufq);
|
||||
}
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
if (NFS_ISV4(bp->b_vp)) {
|
||||
giant_locked = 1;
|
||||
mtx_lock(&Giant);
|
||||
}
|
||||
if (bp->b_flags & B_DIRECT) {
|
||||
KASSERT((bp->b_iocmd == BIO_WRITE), ("nfscvs_iod: BIO_WRITE not set"));
|
||||
(void)nfs_doio_directwrite(bp);
|
||||
} else {
|
||||
if (bp->b_iocmd == BIO_READ)
|
||||
(void) nfs_doio(bp->b_vp, bp, bp->b_rcred, NULL);
|
||||
else
|
||||
(void) nfs_doio(bp->b_vp, bp, bp->b_wcred, NULL);
|
||||
}
|
||||
if (giant_locked)
|
||||
mtx_unlock(&Giant);
|
||||
mtx_lock(&nfs_iod_mtx);
|
||||
/*
|
||||
* Make sure the nmp hasn't been dismounted as soon as
|
||||
* nfs_doio() completes for the last buffer.
|
||||
*/
|
||||
nmp = nfs_iodmount[myiod];
|
||||
if (nmp == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If there are more than one iod on this mount, then defect
|
||||
* so that the iods can be shared out fairly between the mounts
|
||||
*/
|
||||
if (nfs_defect && nmp->nm_bufqiods > 1) {
|
||||
NFS_DPF(ASYNCIO,
|
||||
("nfssvc_iod: iod %d defecting from mount %p\n",
|
||||
myiod, nmp));
|
||||
nfs_iodmount[myiod] = NULL;
|
||||
nmp->nm_bufqiods--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finish:
|
||||
nfs_asyncdaemon[myiod] = 0;
|
||||
if (nmp)
|
||||
nmp->nm_bufqiods--;
|
||||
nfs_iodwant[myiod] = NFSIOD_NOT_AVAILABLE;
|
||||
nfs_iodmount[myiod] = NULL;
|
||||
/* Someone may be waiting for the last nfsiod to terminate. */
|
||||
if (--nfs_numasync == 0)
|
||||
wakeup(&nfs_numasync);
|
||||
mtx_unlock(&nfs_iod_mtx);
|
||||
if ((error == 0) || (error == EWOULDBLOCK))
|
||||
kproc_exit(0);
|
||||
/* Abnormal termination */
|
||||
kproc_exit(1);
|
||||
}
|
@ -1,276 +0,0 @@
|
||||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/fnv_hash.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/taskqueue.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfs/nfs_lock.h>
|
||||
#include <nfsclient/nfs.h>
|
||||
#include <nfsclient/nfsnode.h>
|
||||
#include <nfsclient/nfsmount.h>
|
||||
|
||||
static uma_zone_t nfsnode_zone;
|
||||
|
||||
static void nfs_freesillyrename(void *arg, __unused int pending);
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
void
|
||||
nfs_nhinit(void)
|
||||
{
|
||||
|
||||
nfsnode_zone = uma_zcreate("NFSNODE", sizeof(struct nfsnode), NULL,
|
||||
NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
||||
}
|
||||
|
||||
void
|
||||
nfs_nhuninit(void)
|
||||
{
|
||||
uma_zdestroy(nfsnode_zone);
|
||||
}
|
||||
|
||||
struct nfs_vncmp {
|
||||
int fhsize;
|
||||
void *fh;
|
||||
};
|
||||
|
||||
static int
|
||||
nfs_vncmpf(struct vnode *vp, void *arg)
|
||||
{
|
||||
struct nfs_vncmp *a;
|
||||
struct nfsnode *np;
|
||||
|
||||
a = arg;
|
||||
np = VTONFS(vp);
|
||||
return (bcmp(a->fh, np->n_fhp, a->fhsize));
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up a vnode/nfsnode by file handle.
|
||||
* Callers must check for mount points!!
|
||||
* In all cases, a pointer to a
|
||||
* nfsnode structure is returned.
|
||||
*/
|
||||
int
|
||||
nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int flags)
|
||||
{
|
||||
struct thread *td = curthread; /* XXX */
|
||||
struct nfsnode *np;
|
||||
struct vnode *vp;
|
||||
struct vnode *nvp;
|
||||
int error;
|
||||
u_int hash;
|
||||
struct nfsmount *nmp;
|
||||
struct nfs_vncmp ncmp;
|
||||
|
||||
nmp = VFSTONFS(mntp);
|
||||
*npp = NULL;
|
||||
|
||||
hash = fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT);
|
||||
ncmp.fhsize = fhsize;
|
||||
ncmp.fh = fhp;
|
||||
|
||||
error = vfs_hash_get(mntp, hash, flags,
|
||||
td, &nvp, nfs_vncmpf, &ncmp);
|
||||
if (error)
|
||||
return (error);
|
||||
if (nvp != NULL) {
|
||||
*npp = VTONFS(nvp);
|
||||
return (0);
|
||||
}
|
||||
np = uma_zalloc(nfsnode_zone, M_WAITOK | M_ZERO);
|
||||
|
||||
error = getnewvnode("nfs", mntp, &nfs_vnodeops, &nvp);
|
||||
if (error) {
|
||||
uma_zfree(nfsnode_zone, np);
|
||||
return (error);
|
||||
}
|
||||
vp = nvp;
|
||||
vp->v_bufobj.bo_ops = &buf_ops_nfs;
|
||||
vp->v_data = np;
|
||||
np->n_vnode = vp;
|
||||
/*
|
||||
* Initialize the mutex even if the vnode is going to be a loser.
|
||||
* This simplifies the logic in reclaim, which can then unconditionally
|
||||
* destroy the mutex (in the case of the loser, or if hash_insert happened
|
||||
* to return an error no special casing is needed).
|
||||
*/
|
||||
mtx_init(&np->n_mtx, "NFSnode lock", NULL, MTX_DEF);
|
||||
/*
|
||||
* NFS supports recursive and shared locking.
|
||||
*/
|
||||
lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
|
||||
VN_LOCK_AREC(vp);
|
||||
VN_LOCK_ASHARE(vp);
|
||||
if (fhsize > NFS_SMALLFH) {
|
||||
np->n_fhp = malloc(fhsize, M_NFSBIGFH, M_WAITOK);
|
||||
} else
|
||||
np->n_fhp = &np->n_fh;
|
||||
bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
|
||||
np->n_fhsize = fhsize;
|
||||
error = insmntque(vp, mntp);
|
||||
if (error != 0) {
|
||||
*npp = NULL;
|
||||
if (np->n_fhsize > NFS_SMALLFH) {
|
||||
free((caddr_t)np->n_fhp, M_NFSBIGFH);
|
||||
}
|
||||
mtx_destroy(&np->n_mtx);
|
||||
uma_zfree(nfsnode_zone, np);
|
||||
return (error);
|
||||
}
|
||||
error = vfs_hash_insert(vp, hash, flags,
|
||||
td, &nvp, nfs_vncmpf, &ncmp);
|
||||
if (error)
|
||||
return (error);
|
||||
if (nvp != NULL) {
|
||||
*npp = VTONFS(nvp);
|
||||
/* vfs_hash_insert() vput()'s the losing vnode */
|
||||
return (0);
|
||||
}
|
||||
*npp = np;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the vrele(sp->s_dvp) as a separate task in order to avoid a
|
||||
* deadlock because of a LOR when vrele() locks the directory vnode.
|
||||
*/
|
||||
static void
|
||||
nfs_freesillyrename(void *arg, __unused int pending)
|
||||
{
|
||||
struct sillyrename *sp;
|
||||
|
||||
sp = arg;
|
||||
vrele(sp->s_dvp);
|
||||
free(sp, M_NFSREQ);
|
||||
}
|
||||
|
||||
int
|
||||
nfs_inactive(struct vop_inactive_args *ap)
|
||||
{
|
||||
struct nfsnode *np;
|
||||
struct sillyrename *sp;
|
||||
struct thread *td = curthread; /* XXX */
|
||||
|
||||
np = VTONFS(ap->a_vp);
|
||||
mtx_lock(&np->n_mtx);
|
||||
if (ap->a_vp->v_type != VDIR) {
|
||||
sp = np->n_sillyrename;
|
||||
np->n_sillyrename = NULL;
|
||||
} else
|
||||
sp = NULL;
|
||||
if (sp) {
|
||||
mtx_unlock(&np->n_mtx);
|
||||
(void)nfs_vinvalbuf(ap->a_vp, 0, td, 1);
|
||||
/*
|
||||
* Remove the silly file that was rename'd earlier
|
||||
*/
|
||||
(sp->s_removeit)(sp);
|
||||
crfree(sp->s_cred);
|
||||
TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp);
|
||||
taskqueue_enqueue(taskqueue_thread, &sp->s_task);
|
||||
mtx_lock(&np->n_mtx);
|
||||
}
|
||||
np->n_flag &= NMODIFIED;
|
||||
mtx_unlock(&np->n_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim an nfsnode so that it can be used for other purposes.
|
||||
*/
|
||||
int
|
||||
nfs_reclaim(struct vop_reclaim_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct nfsnode *np = VTONFS(vp);
|
||||
struct nfsdmap *dp, *dp2;
|
||||
|
||||
/*
|
||||
* If the NLM is running, give it a chance to abort pending
|
||||
* locks.
|
||||
*/
|
||||
if (nfs_reclaim_p)
|
||||
nfs_reclaim_p(ap);
|
||||
|
||||
/*
|
||||
* Destroy the vm object and flush associated pages.
|
||||
*/
|
||||
vnode_destroy_vobject(vp);
|
||||
|
||||
vfs_hash_remove(vp);
|
||||
|
||||
/*
|
||||
* Free up any directory cookie structures and
|
||||
* large file handle structures that might be associated with
|
||||
* this nfs node.
|
||||
*/
|
||||
if (vp->v_type == VDIR) {
|
||||
dp = LIST_FIRST(&np->n_cookies);
|
||||
while (dp) {
|
||||
dp2 = dp;
|
||||
dp = LIST_NEXT(dp, ndm_list);
|
||||
free((caddr_t)dp2, M_NFSDIROFF);
|
||||
}
|
||||
}
|
||||
if (np->n_writecred != NULL)
|
||||
crfree(np->n_writecred);
|
||||
if (np->n_fhsize > NFS_SMALLFH) {
|
||||
free((caddr_t)np->n_fhp, M_NFSBIGFH);
|
||||
}
|
||||
mtx_destroy(&np->n_mtx);
|
||||
uma_zfree(nfsnode_zone, vp->v_data);
|
||||
vp->v_data = NULL;
|
||||
return (0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,265 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
|
||||
* Copyright (c) 2013 Spectra Logic Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <nfs/xdr_subs.h>
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfs/nfs_fha.h>
|
||||
#include <nfsserver/nfs.h>
|
||||
#include <nfsserver/nfsm_subs.h>
|
||||
#include <nfsserver/nfs_fha_old.h>
|
||||
|
||||
static void fhaold_init(void *foo);
|
||||
static void fhaold_uninit(void *foo);
|
||||
rpcproc_t fhaold_get_procnum(rpcproc_t procnum);
|
||||
int fhaold_realign(struct mbuf **mb, int malloc_flags);
|
||||
int fhaold_get_fh(uint64_t *fh, int v3, struct mbuf **md, caddr_t *dpos);
|
||||
int fhaold_is_read(rpcproc_t procnum);
|
||||
int fhaold_is_write(rpcproc_t procnum);
|
||||
int fhaold_get_offset(struct mbuf **md, caddr_t *dpos, int v3,
|
||||
struct fha_info *info);
|
||||
int fhaold_no_offset(rpcproc_t procnum);
|
||||
void fhaold_set_locktype(rpcproc_t procnum, struct fha_info *info);
|
||||
static int fheold_stats_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
static struct fha_params fhaold_softc;
|
||||
|
||||
SYSCTL_DECL(_vfs_nfsrv);
|
||||
|
||||
extern SVCPOOL *nfsrv_pool;
|
||||
|
||||
SYSINIT(nfs_fhaold, SI_SUB_ROOT_CONF, SI_ORDER_ANY, fhaold_init, NULL);
|
||||
SYSUNINIT(nfs_fhaold, SI_SUB_ROOT_CONF, SI_ORDER_ANY, fhaold_uninit, NULL);
|
||||
|
||||
static void
|
||||
fhaold_init(void *foo)
|
||||
{
|
||||
struct fha_params *softc;
|
||||
|
||||
softc = &fhaold_softc;
|
||||
|
||||
bzero(softc, sizeof(*softc));
|
||||
|
||||
/*
|
||||
* Setup the callbacks for this FHA personality.
|
||||
*/
|
||||
softc->callbacks.get_procnum = fhaold_get_procnum;
|
||||
softc->callbacks.realign = fhaold_realign;
|
||||
softc->callbacks.get_fh = fhaold_get_fh;
|
||||
softc->callbacks.is_read = fhaold_is_read;
|
||||
softc->callbacks.is_write = fhaold_is_write;
|
||||
softc->callbacks.get_offset = fhaold_get_offset;
|
||||
softc->callbacks.no_offset = fhaold_no_offset;
|
||||
softc->callbacks.set_locktype = fhaold_set_locktype;
|
||||
softc->callbacks.fhe_stats_sysctl = fheold_stats_sysctl;
|
||||
|
||||
snprintf(softc->server_name, sizeof(softc->server_name),
|
||||
FHAOLD_SERVER_NAME);
|
||||
|
||||
softc->pool = &nfsrv_pool;
|
||||
|
||||
/*
|
||||
* Initialize the sysctl context list for the fha module.
|
||||
*/
|
||||
sysctl_ctx_init(&softc->sysctl_ctx);
|
||||
softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
|
||||
SYSCTL_STATIC_CHILDREN(_vfs_nfsrv), OID_AUTO, "fha", CTLFLAG_RD,
|
||||
0, "fha node");
|
||||
if (softc->sysctl_tree == NULL) {
|
||||
printf("%s: unable to allocate sysctl tree\n", __func__);
|
||||
return;
|
||||
}
|
||||
fha_init(softc);
|
||||
}
|
||||
|
||||
static void
|
||||
fhaold_uninit(void *foo)
|
||||
{
|
||||
struct fha_params *softc;
|
||||
|
||||
softc = &fhaold_softc;
|
||||
|
||||
fha_uninit(softc);
|
||||
}
|
||||
|
||||
|
||||
rpcproc_t
|
||||
fhaold_get_procnum(rpcproc_t procnum)
|
||||
{
|
||||
if (procnum > NFSV2PROC_STATFS)
|
||||
return (-1);
|
||||
|
||||
return (nfsrv_nfsv3_procid[procnum]);
|
||||
}
|
||||
|
||||
int
|
||||
fhaold_realign(struct mbuf **mb, int malloc_flags)
|
||||
{
|
||||
return (nfs_realign(mb, malloc_flags));
|
||||
}
|
||||
|
||||
int
|
||||
fhaold_get_fh(uint64_t *fh, int v3, struct mbuf **md, caddr_t *dpos)
|
||||
{
|
||||
u_int32_t *tl;
|
||||
uint8_t *buf;
|
||||
uint64_t t;
|
||||
int fhlen, i;
|
||||
|
||||
if (v3) {
|
||||
tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
|
||||
if (tl == NULL)
|
||||
return EBADRPC;
|
||||
fhlen = fxdr_unsigned(int, *tl);
|
||||
if (fhlen != 0 && fhlen != NFSX_V3FH)
|
||||
return EBADRPC;
|
||||
} else {
|
||||
fhlen = NFSX_V2FH;
|
||||
}
|
||||
t = 0;
|
||||
if (fhlen != 0) {
|
||||
buf = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
|
||||
if (buf == NULL)
|
||||
return EBADRPC;
|
||||
for (i = 0; i < fhlen; i++)
|
||||
t ^= ((uint64_t)buf[i] << (i & 7) * 8);
|
||||
}
|
||||
*fh = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fhaold_is_read(rpcproc_t procnum)
|
||||
{
|
||||
if (procnum == NFSPROC_READ)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fhaold_is_write(rpcproc_t procnum)
|
||||
{
|
||||
if (procnum == NFSPROC_WRITE)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fhaold_get_offset(struct mbuf **md, caddr_t *dpos, int v3,
|
||||
struct fha_info *info)
|
||||
{
|
||||
uint32_t *tl;
|
||||
|
||||
if (v3) {
|
||||
tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
|
||||
if (tl == NULL)
|
||||
goto out;
|
||||
info->offset = fxdr_hyper(tl);
|
||||
} else {
|
||||
tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
|
||||
if (tl == NULL)
|
||||
goto out;
|
||||
info->offset = fxdr_unsigned(uint32_t, *tl);
|
||||
}
|
||||
|
||||
return (0);
|
||||
out:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
fhaold_no_offset(rpcproc_t procnum)
|
||||
{
|
||||
if (procnum == NFSPROC_FSSTAT ||
|
||||
procnum == NFSPROC_FSINFO ||
|
||||
procnum == NFSPROC_PATHCONF ||
|
||||
procnum == NFSPROC_NOOP ||
|
||||
procnum == NFSPROC_NULL)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
fhaold_set_locktype(rpcproc_t procnum, struct fha_info *info)
|
||||
{
|
||||
switch (procnum) {
|
||||
case NFSPROC_NULL:
|
||||
case NFSPROC_GETATTR:
|
||||
case NFSPROC_LOOKUP:
|
||||
case NFSPROC_ACCESS:
|
||||
case NFSPROC_READLINK:
|
||||
case NFSPROC_READ:
|
||||
case NFSPROC_READDIR:
|
||||
case NFSPROC_READDIRPLUS:
|
||||
case NFSPROC_WRITE:
|
||||
info->locktype = LK_SHARED;
|
||||
break;
|
||||
case NFSPROC_SETATTR:
|
||||
case NFSPROC_CREATE:
|
||||
case NFSPROC_MKDIR:
|
||||
case NFSPROC_SYMLINK:
|
||||
case NFSPROC_MKNOD:
|
||||
case NFSPROC_REMOVE:
|
||||
case NFSPROC_RMDIR:
|
||||
case NFSPROC_RENAME:
|
||||
case NFSPROC_LINK:
|
||||
case NFSPROC_FSSTAT:
|
||||
case NFSPROC_FSINFO:
|
||||
case NFSPROC_PATHCONF:
|
||||
case NFSPROC_COMMIT:
|
||||
case NFSPROC_NOOP:
|
||||
info->locktype = LK_EXCLUSIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
fheold_stats_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
return (fhe_stats_sysctl(oidp, arg1, arg2, req, &fhaold_softc));
|
||||
}
|
||||
|
||||
SVCTHREAD *
|
||||
fhaold_assign(SVCTHREAD *this_thread, struct svc_req *req)
|
||||
{
|
||||
return (fha_assign(this_thread, req, &fhaold_softc));
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,545 +0,0 @@
|
||||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_kgssapi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/capsicum.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/lockf.h>
|
||||
#include <sys/eventhandler.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#ifdef INET6
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h> /* XXX: for in6_var.h */
|
||||
#include <netinet6/in6_var.h> /* XXX: for ip6_sprintf */
|
||||
#endif
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpc/rpcsec_gss.h>
|
||||
#include <rpc/replay.h>
|
||||
|
||||
#include <nfs/xdr_subs.h>
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfs/nfs_fha.h>
|
||||
#include <nfsserver/nfs.h>
|
||||
#include <nfsserver/nfsm_subs.h>
|
||||
#include <nfsserver/nfsrvcache.h>
|
||||
#include <nfsserver/nfs_fha_old.h>
|
||||
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
static MALLOC_DEFINE(M_NFSSVC, "nfss_srvsock", "Nfs server structure");
|
||||
|
||||
MALLOC_DEFINE(M_NFSRVDESC, "nfss_srvdesc", "NFS server socket descriptor");
|
||||
MALLOC_DEFINE(M_NFSD, "nfss_daemon", "Nfs server daemon structure");
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
SYSCTL_DECL(_vfs_nfsrv);
|
||||
|
||||
SVCPOOL *nfsrv_pool;
|
||||
int nfsd_waiting = 0;
|
||||
int nfsrv_numnfsd = 0;
|
||||
struct callout nfsrv_callout;
|
||||
static eventhandler_tag nfsrv_nmbclusters_tag;
|
||||
|
||||
static int nfs_privport = 0;
|
||||
SYSCTL_INT(_vfs_nfsrv, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW,
|
||||
&nfs_privport, 0,
|
||||
"Only allow clients using a privileged port");
|
||||
SYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay, CTLFLAG_RW,
|
||||
&nfsrvw_procrastinate, 0,
|
||||
"Delay value for write gathering");
|
||||
SYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay_v3, CTLFLAG_RW,
|
||||
&nfsrvw_procrastinate_v3, 0,
|
||||
"Delay in seconds for NFSv3 write gathering");
|
||||
|
||||
static int nfssvc_addsock(struct file *, struct thread *);
|
||||
static int nfssvc_nfsd(struct thread *, struct nfsd_nfsd_args *);
|
||||
|
||||
extern u_long sb_max_adj;
|
||||
|
||||
int32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
|
||||
struct nfssvc_sock *slp, struct mbuf **mreqp) = {
|
||||
nfsrv_null,
|
||||
nfsrv_getattr,
|
||||
nfsrv_setattr,
|
||||
nfsrv_lookup,
|
||||
nfsrv3_access,
|
||||
nfsrv_readlink,
|
||||
nfsrv_read,
|
||||
nfsrv_write,
|
||||
nfsrv_create,
|
||||
nfsrv_mkdir,
|
||||
nfsrv_symlink,
|
||||
nfsrv_mknod,
|
||||
nfsrv_remove,
|
||||
nfsrv_rmdir,
|
||||
nfsrv_rename,
|
||||
nfsrv_link,
|
||||
nfsrv_readdir,
|
||||
nfsrv_readdirplus,
|
||||
nfsrv_statfs,
|
||||
nfsrv_fsinfo,
|
||||
nfsrv_pathconf,
|
||||
nfsrv_commit,
|
||||
nfsrv_noop
|
||||
};
|
||||
|
||||
/*
|
||||
* NFS server system calls
|
||||
*/
|
||||
/*
|
||||
* This is now called from nfssvc() in nfs/nfs_nfssvc.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Nfs server psuedo system call for the nfsd's
|
||||
* Based on the flag value it either:
|
||||
* - adds a socket to the selection list
|
||||
* - remains in the kernel as an nfsd
|
||||
* - remains in the kernel as an nfsiod
|
||||
* For INET6 we suppose that nfsd provides only IN6P_IPV6_V6ONLY sockets
|
||||
* and that mountd provides
|
||||
* - sockaddr with no IPv4-mapped addresses
|
||||
* - mask for both INET and INET6 families if there is IPv4-mapped overlap
|
||||
*/
|
||||
int
|
||||
nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap)
|
||||
{
|
||||
struct file *fp;
|
||||
struct nfsd_addsock_args addsockarg;
|
||||
struct nfsd_nfsd_args nfsdarg;
|
||||
cap_rights_t rights;
|
||||
int error;
|
||||
|
||||
if (uap->flag & NFSSVC_ADDSOCK) {
|
||||
error = copyin(uap->argp, (caddr_t)&addsockarg,
|
||||
sizeof(addsockarg));
|
||||
if (error)
|
||||
return (error);
|
||||
error = fget(td, addsockarg.sock,
|
||||
cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
|
||||
if (error)
|
||||
return (error);
|
||||
if (fp->f_type != DTYPE_SOCKET) {
|
||||
fdrop(fp, td);
|
||||
return (error); /* XXXRW: Should be EINVAL? */
|
||||
}
|
||||
error = nfssvc_addsock(fp, td);
|
||||
fdrop(fp, td);
|
||||
} else if (uap->flag & NFSSVC_OLDNFSD)
|
||||
error = nfssvc_nfsd(td, NULL);
|
||||
else if (uap->flag & NFSSVC_NFSD) {
|
||||
if (!uap->argp)
|
||||
return (EINVAL);
|
||||
error = copyin(uap->argp, (caddr_t)&nfsdarg,
|
||||
sizeof(nfsdarg));
|
||||
if (error)
|
||||
return (error);
|
||||
error = nfssvc_nfsd(td, &nfsdarg);
|
||||
} else
|
||||
error = ENXIO;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the rpc reply header
|
||||
* siz arg. is used to decide if adding a cluster is worthwhile
|
||||
*/
|
||||
struct mbuf *
|
||||
nfs_rephead(int siz, struct nfsrv_descript *nd, int err,
|
||||
struct mbuf **mbp, caddr_t *bposp)
|
||||
{
|
||||
u_int32_t *tl;
|
||||
struct mbuf *mreq;
|
||||
caddr_t bpos;
|
||||
struct mbuf *mb;
|
||||
|
||||
if (err == EBADRPC)
|
||||
return (NULL);
|
||||
|
||||
nd->nd_repstat = err;
|
||||
if (err && (nd->nd_flag & ND_NFSV3) == 0) /* XXX recheck */
|
||||
siz = 0;
|
||||
|
||||
MGET(mreq, M_WAITOK, MT_DATA);
|
||||
|
||||
/*
|
||||
* If this is a big reply, use a cluster
|
||||
*/
|
||||
mreq->m_len = 0;
|
||||
if (siz >= MINCLSIZE) {
|
||||
MCLGET(mreq, M_WAITOK);
|
||||
}
|
||||
mb = mreq;
|
||||
bpos = mtod(mb, caddr_t);
|
||||
|
||||
if (err != NFSERR_RETVOID) {
|
||||
tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
|
||||
if (err)
|
||||
*tl = txdr_unsigned(nfsrv_errmap(nd, err));
|
||||
else
|
||||
*tl = 0;
|
||||
}
|
||||
|
||||
*mbp = mb;
|
||||
*bposp = bpos;
|
||||
if (err != 0 && err != NFSERR_RETVOID)
|
||||
nfsrvstats.srvrpc_errs++;
|
||||
|
||||
return (mreq);
|
||||
}
|
||||
|
||||
static void
|
||||
nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
|
||||
{
|
||||
rpcproc_t procnum;
|
||||
int32_t (*proc)(struct nfsrv_descript *nd, struct nfssvc_sock *slp,
|
||||
struct mbuf **mreqp);
|
||||
int flag;
|
||||
struct nfsrv_descript nd;
|
||||
struct mbuf *mreq, *mrep;
|
||||
int error;
|
||||
|
||||
if (rqst->rq_vers == NFS_VER2) {
|
||||
if (rqst->rq_proc > NFSV2PROC_STATFS) {
|
||||
svcerr_noproc(rqst);
|
||||
svc_freereq(rqst);
|
||||
return;
|
||||
}
|
||||
procnum = nfsrv_nfsv3_procid[rqst->rq_proc];
|
||||
flag = 0;
|
||||
} else {
|
||||
if (rqst->rq_proc >= NFS_NPROCS) {
|
||||
svcerr_noproc(rqst);
|
||||
svc_freereq(rqst);
|
||||
return;
|
||||
}
|
||||
procnum = rqst->rq_proc;
|
||||
flag = ND_NFSV3;
|
||||
}
|
||||
proc = nfsrv3_procs[procnum];
|
||||
|
||||
mreq = mrep = NULL;
|
||||
mreq = rqst->rq_args;
|
||||
rqst->rq_args = NULL;
|
||||
(void)nfs_realign(&mreq, M_WAITOK);
|
||||
|
||||
/*
|
||||
* Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
|
||||
* NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
|
||||
* mounts.
|
||||
*/
|
||||
memset(&nd, 0, sizeof(nd));
|
||||
nd.nd_md = nd.nd_mrep = mreq;
|
||||
nd.nd_dpos = mtod(mreq, caddr_t);
|
||||
nd.nd_nam = svc_getrpccaller(rqst);
|
||||
nd.nd_nam2 = rqst->rq_addr;
|
||||
nd.nd_procnum = procnum;
|
||||
nd.nd_cr = NULL;
|
||||
nd.nd_flag = flag;
|
||||
|
||||
if (nfs_privport) {
|
||||
/* Check if source port is privileged */
|
||||
u_short port;
|
||||
struct sockaddr *nam = nd.nd_nam;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)nam;
|
||||
/*
|
||||
* INET/INET6 - same code:
|
||||
* sin_port and sin6_port are at same offset
|
||||
*/
|
||||
port = ntohs(sin->sin_port);
|
||||
if (port >= IPPORT_RESERVED &&
|
||||
nd.nd_procnum != NFSPROC_NULL) {
|
||||
#ifdef INET6
|
||||
char b6[INET6_ADDRSTRLEN];
|
||||
#if defined(KLD_MODULE)
|
||||
/* Do not use ip6_sprintf: the nfs module should work without INET6. */
|
||||
#define ip6_sprintf(buf, a) \
|
||||
(sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x", \
|
||||
(a)->s6_addr16[0], (a)->s6_addr16[1], \
|
||||
(a)->s6_addr16[2], (a)->s6_addr16[3], \
|
||||
(a)->s6_addr16[4], (a)->s6_addr16[5], \
|
||||
(a)->s6_addr16[6], (a)->s6_addr16[7]), \
|
||||
(buf))
|
||||
#endif
|
||||
#endif
|
||||
printf("NFS request from unprivileged port (%s:%d)\n",
|
||||
#ifdef INET6
|
||||
sin->sin_family == AF_INET6 ?
|
||||
ip6_sprintf(b6, &satosin6(sin)->sin6_addr) :
|
||||
#if defined(KLD_MODULE)
|
||||
#undef ip6_sprintf
|
||||
#endif
|
||||
#endif
|
||||
inet_ntoa(sin->sin_addr), port);
|
||||
m_freem(mreq);
|
||||
svcerr_weakauth(rqst);
|
||||
svc_freereq(rqst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc != nfsrv_null) {
|
||||
if (!svc_getcred(rqst, &nd.nd_cr, &nd.nd_credflavor)) {
|
||||
m_freem(mreq);
|
||||
svcerr_weakauth(rqst);
|
||||
svc_freereq(rqst);
|
||||
return;
|
||||
}
|
||||
#ifdef MAC
|
||||
mac_cred_associate_nfsd(nd.nd_cr);
|
||||
#endif
|
||||
}
|
||||
nfsrvstats.srvrpccnt[nd.nd_procnum]++;
|
||||
|
||||
error = proc(&nd, NULL, &mrep);
|
||||
|
||||
if (nd.nd_cr)
|
||||
crfree(nd.nd_cr);
|
||||
|
||||
if (mrep == NULL) {
|
||||
svcerr_decode(rqst);
|
||||
svc_freereq(rqst);
|
||||
return;
|
||||
}
|
||||
if (error && error != NFSERR_RETVOID) {
|
||||
svcerr_systemerr(rqst);
|
||||
svc_freereq(rqst);
|
||||
return;
|
||||
}
|
||||
if (nd.nd_repstat & NFSERR_AUTHERR) {
|
||||
svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
|
||||
m_freem(mrep);
|
||||
} else {
|
||||
if (!svc_sendreply_mbuf(rqst, mrep))
|
||||
svcerr_systemerr(rqst);
|
||||
}
|
||||
svc_freereq(rqst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a socket to the list for servicing by nfsds.
|
||||
*/
|
||||
static int
|
||||
nfssvc_addsock(struct file *fp, struct thread *td)
|
||||
{
|
||||
int siz;
|
||||
struct socket *so;
|
||||
int error;
|
||||
SVCXPRT *xprt;
|
||||
|
||||
so = fp->f_data;
|
||||
|
||||
siz = sb_max_adj;
|
||||
error = soreserve(so, siz, siz);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Steal the socket from userland so that it doesn't close
|
||||
* unexpectedly.
|
||||
*/
|
||||
if (so->so_type == SOCK_DGRAM)
|
||||
xprt = svc_dg_create(nfsrv_pool, so, 0, 0);
|
||||
else
|
||||
xprt = svc_vc_create(nfsrv_pool, so, 0, 0);
|
||||
if (xprt) {
|
||||
fp->f_ops = &badfileops;
|
||||
fp->f_data = NULL;
|
||||
svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, NULL);
|
||||
svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, NULL);
|
||||
SVC_RELEASE(xprt);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by nfssvc() for nfsds. Just loops around servicing rpc requests
|
||||
* until it is killed by a signal.
|
||||
*/
|
||||
static int
|
||||
nfssvc_nfsd(struct thread *td, struct nfsd_nfsd_args *args)
|
||||
{
|
||||
char principal[128];
|
||||
int error;
|
||||
|
||||
if (args) {
|
||||
error = copyinstr(args->principal, principal,
|
||||
sizeof(principal), NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
} else {
|
||||
memcpy(principal, "nfs@", 4);
|
||||
getcredhostname(td->td_ucred, principal + 4,
|
||||
sizeof(principal) - 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only the first nfsd actually does any work. The RPC code
|
||||
* adds threads to it as needed. Any extra processes offered
|
||||
* by nfsd just exit. If nfsd is new enough, it will call us
|
||||
* once with a structure that specifies how many threads to
|
||||
* use.
|
||||
*/
|
||||
NFSD_LOCK();
|
||||
if (nfsrv_numnfsd == 0) {
|
||||
nfsrv_numnfsd++;
|
||||
|
||||
NFSD_UNLOCK();
|
||||
|
||||
rpc_gss_set_svc_name_call(principal, "kerberosv5",
|
||||
GSS_C_INDEFINITE, NFS_PROG, NFS_VER2);
|
||||
rpc_gss_set_svc_name_call(principal, "kerberosv5",
|
||||
GSS_C_INDEFINITE, NFS_PROG, NFS_VER3);
|
||||
|
||||
if (args) {
|
||||
nfsrv_pool->sp_minthreads = args->minthreads;
|
||||
nfsrv_pool->sp_maxthreads = args->maxthreads;
|
||||
} else {
|
||||
nfsrv_pool->sp_minthreads = 4;
|
||||
nfsrv_pool->sp_maxthreads = 4;
|
||||
}
|
||||
|
||||
svc_run(nfsrv_pool);
|
||||
|
||||
rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER2);
|
||||
rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER3);
|
||||
|
||||
NFSD_LOCK();
|
||||
nfsrv_numnfsd--;
|
||||
nfsrv_init(TRUE);
|
||||
}
|
||||
NFSD_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Size the NFS server's duplicate request cache at 1/2 the
|
||||
* nmbclusters, floating within a (64, 2048) range. This is to
|
||||
* prevent all mbuf clusters being tied up in the NFS dupreq
|
||||
* cache for small values of nmbclusters.
|
||||
*/
|
||||
static size_t
|
||||
nfsrv_replay_size(void)
|
||||
{
|
||||
size_t replaysiz;
|
||||
|
||||
replaysiz = nmbclusters / 2;
|
||||
if (replaysiz > NFSRVCACHE_MAX_SIZE)
|
||||
replaysiz = NFSRVCACHE_MAX_SIZE;
|
||||
if (replaysiz < NFSRVCACHE_MIN_SIZE)
|
||||
replaysiz = NFSRVCACHE_MIN_SIZE;
|
||||
replaysiz *= MCLBYTES;
|
||||
|
||||
return (replaysiz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when nmbclusters changes - we resize the replay cache
|
||||
* accordingly.
|
||||
*/
|
||||
static void
|
||||
nfsrv_nmbclusters_change(void *tag)
|
||||
{
|
||||
|
||||
if (nfsrv_pool)
|
||||
replay_setsize(nfsrv_pool->sp_rcache, nfsrv_replay_size());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the data structures for the server.
|
||||
* Handshake with any new nfsds starting up to avoid any chance of
|
||||
* corruption.
|
||||
*/
|
||||
void
|
||||
nfsrv_init(int terminating)
|
||||
{
|
||||
|
||||
NFSD_LOCK_ASSERT();
|
||||
|
||||
if (terminating) {
|
||||
NFSD_UNLOCK();
|
||||
EVENTHANDLER_DEREGISTER(nmbclusters_change,
|
||||
nfsrv_nmbclusters_tag);
|
||||
svcpool_destroy(nfsrv_pool);
|
||||
nfsrv_pool = NULL;
|
||||
NFSD_LOCK();
|
||||
} else
|
||||
nfs_pub.np_valid = 0;
|
||||
|
||||
NFSD_UNLOCK();
|
||||
|
||||
nfsrv_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_nfsrv));
|
||||
nfsrv_pool->sp_rcache = replay_newcache(nfsrv_replay_size());
|
||||
nfsrv_pool->sp_assign = fhaold_assign;
|
||||
nfsrv_pool->sp_done = fha_nd_complete;
|
||||
nfsrv_nmbclusters_tag = EVENTHANDLER_REGISTER(nmbclusters_change,
|
||||
nfsrv_nmbclusters_change, NULL, EVENTHANDLER_PRI_FIRST);
|
||||
|
||||
NFSD_LOCK();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1100050 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1100051 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
Loading…
Reference in New Issue
Block a user