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:
Rick Macklem 2014-12-23 00:47:46 +00:00
parent 6d514f104e
commit c15882f091
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=276096
32 changed files with 46 additions and 16656 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -248,14 +248,11 @@ SUBDIR= \
netfpga10g \
${_netgraph} \
${_nfe} \
nfs_common \
nfscl \
nfsclient \
nfscommon \
nfsd \
nfslock \
nfslockd \
nfsserver \
nfssvc \
nge \
nmdm \

View File

@ -4,7 +4,6 @@
SUBDIR= dtmalloc \
dtnfscl \
dtnfsclient \
dtrace \
dtraceall \
dtrace_test \

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -1735,9 +1735,6 @@ bootpc_init(void)
goto out;
}
rootdevnames[0] = "nfs:";
#ifdef NFSCLIENT
rootdevnames[1] = "oldnfs:";
#endif
nfs_diskless_valid = 3;
}

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,