diff options
author | dfr <dfr@FreeBSD.org> | 2009-06-30 19:03:27 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 2009-06-30 19:03:27 +0000 |
commit | 5d248bb05f33623d905b8b5a72d90e459d23be96 (patch) | |
tree | b34567acfe860cb1978c433954c8376efa8a9fbb /sys | |
parent | 92b2f1511851bf5a137742d90131b79d0ff4c1ff (diff) | |
download | FreeBSD-src-5d248bb05f33623d905b8b5a72d90e459d23be96.zip FreeBSD-src-5d248bb05f33623d905b8b5a72d90e459d23be96.tar.gz |
Remove the old kernel RPC implementation and the NFS_LEGACYRPC option.
Approved by: re
Diffstat (limited to 'sys')
31 files changed, 23 insertions, 4969 deletions
diff --git a/sys/conf/files b/sys/conf/files index 4e7bb5f..c582d56 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2490,7 +2490,6 @@ nfsclient/krpc_subr.c optional bootp nfsclient nfsclient/nfs_bio.c optional nfsclient nfsclient/nfs_diskless.c optional nfsclient nfs_root nfsclient/nfs_node.c optional nfsclient -nfsclient/nfs_socket.c optional nfsclient nfsclient/nfs_krpc.c optional nfsclient nfsclient/nfs_subs.c optional nfsclient nfsclient/nfs_nfsiod.c optional nfsclient @@ -2500,10 +2499,7 @@ nfsclient/nfs_lock.c optional nfsclient nfsserver/nfs_fha.c optional nfsserver nfsserver/nfs_serv.c optional nfsserver nfsserver/nfs_srvkrpc.c optional nfsserver -nfsserver/nfs_srvsock.c optional nfsserver -nfsserver/nfs_srvcache.c optional nfsserver nfsserver/nfs_srvsubs.c optional nfsserver -nfsserver/nfs_syscalls.c optional nfsserver nfs/nfs_nfssvc.c optional nfsserver | nfscl | nfsd nlm/nlm_advlock.c optional nfslockd nfsclient | nfsd nfsclient nlm/nlm_prot_clnt.c optional nfslockd | nfsd diff --git a/sys/conf/options b/sys/conf/options index 1995420..be59f53 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -228,11 +228,6 @@ KGSSAPI_DEBUG opt_kgssapi.h NFSCLIENT opt_nfs.h NFSSERVER opt_nfs.h -# Use this option to compile both NFS client and server using the -# legacy RPC implementation instead of the newer KRPC system (which -# supports modern features such as RPCSEC_GSS -NFS_LEGACYRPC opt_nfs.h - # Use these options to compile the experimental nfs client and/or # server that supports NFSv4 into a kernel. # NFSCL - client diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index 7c6acf0..46fd67e 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <netinet/in.h> #include <nfs/nfsproto.h> -#include <nfs/rpcv2.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsdiskless.h> #ifdef DEV_APIC diff --git a/sys/modules/nfsclient/Makefile b/sys/modules/nfsclient/Makefile index cab161f..c53e3d5 100644 --- a/sys/modules/nfsclient/Makefile +++ b/sys/modules/nfsclient/Makefile @@ -4,7 +4,7 @@ KMOD= nfsclient SRCS= vnode_if.h \ - nfs_bio.c nfs_lock.c nfs_node.c nfs_socket.c nfs_subs.c nfs_nfsiod.c \ + nfs_bio.c nfs_lock.c nfs_node.c nfs_subs.c nfs_nfsiod.c \ nfs_vfsops.c nfs_vnops.c nfs_common.c nfs_krpc.c \ opt_inet.h opt_nfs.h opt_bootp.h opt_nfsroot.h SRCS+= opt_inet6.h opt_kdtrace.h opt_kgssapi.h diff --git a/sys/modules/nfsserver/Makefile b/sys/modules/nfsserver/Makefile index a85d29c..692179b 100644 --- a/sys/modules/nfsserver/Makefile +++ b/sys/modules/nfsserver/Makefile @@ -3,8 +3,8 @@ .PATH: ${.CURDIR}/../../nfsserver ${.CURDIR}/../../nfs KMOD= nfsserver SRCS= vnode_if.h \ - nfs_fha.c nfs_serv.c nfs_srvkrpc.c nfs_srvsock.c nfs_srvcache.c \ - nfs_srvsubs.c nfs_syscalls.c nfs_common.c \ + nfs_fha.c nfs_serv.c nfs_srvkrpc.c nfs_srvsubs.c nfs_common.c \ + opt_mac.h \ opt_kgssapi.h \ opt_nfs.h SRCS+= opt_inet6.h diff --git a/sys/nfs/nfs_common.c b/sys/nfs/nfs_common.c index faa9302..0869309 100644 --- a/sys/nfs/nfs_common.c +++ b/sys/nfs/nfs_common.c @@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_extern.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsserver/nfs.h> #include <nfs/xdr_subs.h> diff --git a/sys/nfs/rpcv2.h b/sys/nfs/rpcv2.h deleted file mode 100644 index 0d7935f..0000000 --- a/sys/nfs/rpcv2.h +++ /dev/null @@ -1,108 +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. - * - * @(#)rpcv2.h 8.2 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#ifndef _NFS_RPCV2_H_ -#define _NFS_RPCV2_H_ - -/* - * Definitions for Sun RPC Version 2, from - * "RPC: Remote Procedure Call Protocol Specification" RFC1057 - */ - -/* Version # */ -#define RPC_VER2 2 - -/* Authentication */ -#define RPCAUTH_NULL 0 -#define RPCAUTH_UNIX 1 -#define RPCAUTH_SHORT 2 -#define RPCAUTH_KERB4 4 -#define RPCAUTH_MAXSIZ 400 -#define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */ -#define RPCAUTH_UNIXGIDS 16 - -/* - * Constants associated with authentication flavours. - */ -#define RPCAKN_FULLNAME 0 -#define RPCAKN_NICKNAME 1 - -/* msg type */ -#define RPC_CALL 0 -#define RPC_REPLY 1 - -/* reply status */ -#define RPC_MSGACCEPTED 0 -#define RPC_MSGDENIED 1 - -/* accepted status */ -#define RPC_SUCCESS 0 -#define RPC_PROGUNAVAIL 1 -#define RPC_PROGMISMATCH 2 -#define RPC_PROCUNAVAIL 3 -#define RPC_GARBAGE 4 /* I like this one */ -#define RPC_SYSTEMERR 5 - -/* rejected status */ -#define RPC_MISMATCH 0 -#define RPC_AUTHERR 1 - -/* Authentication failures */ -#define AUTH_OK 0 -#define AUTH_BADCRED 1 -#define AUTH_REJECTCRED 2 -#define AUTH_BADVERF 3 -#define AUTH_REJECTVERF 4 -#define AUTH_TOOWEAK 5 /* Give em wheaties */ - -/* Sizes of rpc header parts */ -#define RPC_SIZ 24 -#define RPC_REPLYSIZ 28 - -/* RPC Prog definitions */ -#define RPCPROG_MNT 100005 -#define RPCMNT_VER1 1 -#define RPCMNT_VER3 3 -#define RPCMNT_MOUNT 1 -#define RPCMNT_DUMP 2 -#define RPCMNT_UMOUNT 3 -#define RPCMNT_UMNTALL 4 -#define RPCMNT_EXPORT 5 -#define RPCMNT_NAMELEN 255 -#define RPCMNT_PATHLEN 1024 -#define RPCPROG_NFS 100003 - -#endif diff --git a/sys/nfsclient/bootp_subr.c b/sys/nfsclient/bootp_subr.c index 10fc8c4..4a4847a 100644 --- a/sys/nfsclient/bootp_subr.c +++ b/sys/nfsclient/bootp_subr.c @@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$"); #include <net/if_dl.h> #include <net/vnet.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsdiskless.h> @@ -1776,6 +1775,13 @@ md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep, int authcount; int authver; +#define RPCPROG_MNT 100005 +#define RPCMNT_VER1 1 +#define RPCMNT_VER3 3 +#define RPCMNT_MOUNT 1 +#define AUTH_SYS 1 /* unix style (uid, gids) */ +#define AUTH_UNIX AUTH_SYS + /* XXX honor v2/v3 flags in args->flags? */ #ifdef BOOTP_NFSV3 /* First try NFS v3 */ @@ -1836,7 +1842,7 @@ md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep, while (authcount > 0) { if (xdr_int_decode(&m, &authver) != 0) goto bad; - if (authver == RPCAUTH_UNIX) + if (authver == AUTH_UNIX) authunixok = 1; authcount--; } diff --git a/sys/nfsclient/krpc_subr.c b/sys/nfsclient/krpc_subr.c index 2023904..996cb05 100644 --- a/sys/nfsclient/krpc_subr.c +++ b/sys/nfsclient/krpc_subr.c @@ -57,7 +57,9 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <netinet/in.h> -#include <nfs/rpcv2.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/rpc_msg.h> #include <nfsclient/krpc.h> #include <nfs/xdr_subs.h> @@ -284,7 +286,7 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, call->rp_vers = txdr_unsigned(vers); call->rp_proc = txdr_unsigned(func); /* rpc_auth part (auth_unix as root) */ - call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); + call->rpc_auth.authtype = txdr_unsigned(AUTH_UNIX); call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); /* rpc_verf part (auth_null) */ call->rpc_verf.authtype = 0; @@ -359,7 +361,7 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, reply = mtod(m, struct krpc_reply *); /* Is it the right reply? */ - if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) + if (reply->rp_direction != txdr_unsigned(REPLY)) continue; if (reply->rp_xid != txdr_unsigned(xid)) @@ -375,7 +377,7 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, /* Did the call succeed? */ if (reply->rp_status != 0) { error = fxdr_unsigned(u_int32_t, reply->rp_status); - if (error == RPC_PROGMISMATCH) { + if (error == PROG_MISMATCH) { error = EBADRPC; goto out; } diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index 845f826..fa7d5ba 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -123,9 +123,6 @@ MALLOC_DECLARE(M_NFSDIRECTIO); extern struct uma_zone *nfsmount_zone; -#ifdef NFS_LEGACYRPC -extern struct callout nfs_callout; -#endif extern struct nfsstats nfsstats; extern struct mtx nfs_iod_mtx; @@ -150,49 +147,6 @@ extern int nfsv3_procid[NFS_NPROCS]; (e) != ERESTART && (e) != EWOULDBLOCK && \ ((s) & PR_CONNREQUIRED) == 0) -#ifdef NFS_LEGACYRPC - -/* - * Nfs outstanding request list element - */ -struct nfsreq { - TAILQ_ENTRY(nfsreq) r_chain; - struct mbuf *r_mreq; - struct mbuf *r_mrep; - struct mbuf *r_md; - caddr_t r_dpos; - struct nfsmount *r_nmp; - struct vnode *r_vp; - u_int32_t r_xid; - int r_flags; /* flags on request, see below */ - int r_retry; /* max retransmission count */ - int r_rexmit; /* current retrans count */ - int r_timer; /* tick counter on reply */ - u_int32_t r_procnum; /* NFS procedure number */ - int r_rtt; /* RTT for rpc */ - int r_lastmsg; /* last tprintf */ - struct thread *r_td; /* Proc that did I/O system call */ - struct mtx r_mtx; /* Protects nfsreq fields */ -}; - -/* - * Queue head for nfsreq's - */ -extern TAILQ_HEAD(nfs_reqq, nfsreq) nfs_reqq; - -/* Flag values for r_flags */ -#define R_TIMING 0x01 /* timing request (in mntp) */ -#define R_SENT 0x02 /* request has been sent */ -#define R_SOFTTERM 0x04 /* soft mnt, too many retries */ -#define R_RESENDERR 0x08 /* Resend failed */ -#define R_SOCKERR 0x10 /* Fatal error on socket */ -#define R_TPRINTFMSG 0x20 /* Did a tprintf msg. */ -#define R_MUSTRESEND 0x40 /* Must resend request */ -#define R_GETONEREP 0x80 /* Probe for one reply only */ -#define R_PIN_REQ 0x100 /* Pin request down (rexmit in prog or other) */ - -#else - /* * This is only needed to keep things working while we support * compiling for both RPC implementations. @@ -200,8 +154,6 @@ extern TAILQ_HEAD(nfs_reqq, nfsreq) nfs_reqq; struct nfsreq; struct nfsmount; -#endif - struct buf; struct socket; struct uio; @@ -297,19 +249,6 @@ vfs_init_t nfs_init; vfs_uninit_t nfs_uninit; int nfs_mountroot(struct mount *mp); -#ifdef NFS_LEGACYRPC -#ifndef NFS4_USE_RPCCLNT -int nfs_send(struct socket *, struct sockaddr *, struct mbuf *, - struct nfsreq *); -int nfs_connect_lock(struct nfsreq *); -void nfs_connect_unlock(struct nfsreq *); -void nfs_up(struct nfsreq *, struct nfsmount *, struct thread *, - const char *, int); -void nfs_down(struct nfsreq *, struct nfsmount *, struct thread *, - const char *, int, int); -#endif /* ! NFS4_USE_RPCCLNT */ -#endif - void nfs_purgecache(struct vnode *); int nfs_vinvalbuf(struct vnode *, int, struct thread *, int); int nfs_readrpc(struct vnode *, struct uio *, struct ucred *); diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index 22e2a79..95d6e2f 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_pager.h> #include <vm/vnode_pager.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsmount.h> diff --git a/sys/nfsclient/nfs_diskless.c b/sys/nfsclient/nfs_diskless.c index e67b073..ba7a7a1 100644 --- a/sys/nfsclient/nfs_diskless.c +++ b/sys/nfsclient/nfs_diskless.c @@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$"); #include <net/vnet.h> #include <netinet/in.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsdiskless.h> diff --git a/sys/nfsclient/nfs_krpc.c b/sys/nfsclient/nfs_krpc.c index 4cd6986..44b852d 100644 --- a/sys/nfsclient/nfs_krpc.c +++ b/sys/nfsclient/nfs_krpc.c @@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$"); #include <rpc/rpc.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfs/xdr_subs.h> @@ -69,8 +68,6 @@ __FBSDID("$FreeBSD$"); #include <nfsclient/nfsmount.h> #include <nfsclient/nfsnode.h> -#ifndef NFS_LEGACYRPC - #ifdef KDTRACE_HOOKS #include <sys/dtrace_bsd.h> @@ -899,5 +896,3 @@ nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, } else mtx_unlock(&nmp->nm_mtx); } - -#endif /* !NFS_LEGACYRPC */ diff --git a/sys/nfsclient/nfs_lock.c b/sys/nfsclient/nfs_lock.c index ea6649e..6bd126a 100644 --- a/sys/nfsclient/nfs_lock.c +++ b/sys/nfsclient/nfs_lock.c @@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsmount.h> diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c index 7dc3f19..3fafa1e 100644 --- a/sys/nfsclient/nfs_nfsiod.c +++ b/sys/nfsclient/nfs_nfsiod.c @@ -64,7 +64,6 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcp.h> #include <nfs/xdr_subs.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsm_subs.h> diff --git a/sys/nfsclient/nfs_node.c b/sys/nfsclient/nfs_node.c index a7f00ca..f536127 100644 --- a/sys/nfsclient/nfs_node.c +++ b/sys/nfsclient/nfs_node.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include <vm/uma.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsnode.h> diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c deleted file mode 100644 index 26b365c..0000000 --- a/sys/nfsclient/nfs_socket.c +++ /dev/null @@ -1,1977 +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 <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.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/protosw.h> -#include <sys/signalvar.h> -#include <sys/syscallsubr.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/sysctl.h> -#include <sys/syslog.h> -#include <sys/vnode.h> - -#include <netinet/in.h> -#include <netinet/tcp.h> - -#include <nfs/rpcv2.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 NFS_LEGACYRPC - -#define TRUE 1 -#define FALSE 0 - -static int nfs_realign_test; -static int nfs_realign_count; -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_nfs); - -SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, - "Number of realign tests done"); -SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, - "Number of mbuf realignments done"); -SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, - "Buffer reservation size 2 < x < 64"); -SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, - "Number of times the nfs client has had to reconnect"); -SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0, - "Number of seconds to delay a retry after receiving EJUKEBOX"); -SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0, - "Disable weak cache consistency checking when server returns an error"); - -/* - * There is a congestion window for outstanding rpcs maintained per mount - * point. The cwnd size is adjusted in roughly the way that: - * Van Jacobson, Congestion avoidance and Control, In "Proceedings of - * SIGCOMM '88". ACM, August 1988. - * describes for TCP. The cwnd size is chopped in half on a retransmit timeout - * and incremented by 1/cwnd when each rpc reply is received and a full cwnd - * of rpcs is in progress. - * (The sent count and cwnd are scaled for integer arith.) - * Variants of "slow start" were tried and were found to be too much of a - * performance hit (ave. rtt 3 times larger), - * I suspect due to the large rtt that nfs rpcs have. - */ -#define NFS_CWNDSCALE 256 -#define NFS_MAXCWND (NFS_CWNDSCALE * 32) -#define NFS_NBACKOFF 8 -static int nfs_backoff[NFS_NBACKOFF] = { 2, 4, 8, 16, 32, 64, 128, 256, }; -struct callout nfs_callout; - -static int nfs_msg(struct thread *, const char *, const char *, int); -static int nfs_realign(struct mbuf **pm, int hsiz); -static int nfs_reply(struct nfsreq *); -static void nfs_softterm(struct nfsreq *rep); -static int nfs_reconnect(struct nfsreq *rep); -static int nfs_clnt_tcp_soupcall(struct socket *so, void *arg, int waitflag); -static int nfs_clnt_udp_soupcall(struct socket *so, void *arg, int waitflag); - -extern struct mtx nfs_reqq_mtx; - -/* - * 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_srtt[i] = NFS_INITRTT; - for (i = 0; i < NFS_MAX_TIMER; i++) - nmp->nm_sdrtt[i] = 0; -} - -/* - * Update a mount point's RTT estimator state using data from the - * passed-in request. - * - * Use a gain of 0.125 on the mean and a gain of 0.25 on the deviation. - * - * NB: Since the timer resolution of NFS_HZ is so course, it can often - * result in r_rtt == 0. Since r_rtt == N means that the actual RTT is - * between N + dt and N + 2 - dt ticks, add 1 before calculating the - * update values. - */ -static void -nfs_update_rtt(struct nfsreq *rep) -{ - int t1 = rep->r_rtt + 1; - int index = nfs_rto_timer(rep->r_procnum) - 1; - int *srtt = &rep->r_nmp->nm_srtt[index]; - int *sdrtt = &rep->r_nmp->nm_sdrtt[index]; - - t1 -= *srtt >> 3; - *srtt += t1; - if (t1 < 0) - t1 = -t1; - t1 -= *sdrtt >> 2; - *sdrtt += t1; -} - -/* - * Estimate RTO for an NFS RPC sent via an unreliable datagram. - * - * Use the mean and mean deviation of RTT for the appropriate type - * of RPC for the frequent RPCs and a default for the others. - * 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. - * - * getattr, lookup - A+2D - * read, write - A+4D - * other - nm_timeo - */ -static int -nfs_estimate_rto(struct nfsmount *nmp, u_int32_t procnum) -{ - enum nfs_rto_timer_t timer = nfs_rto_timer(procnum); - int index = timer - 1; - int rto; - - switch (timer) { - case NFS_GETATTR_TIMER: - case NFS_LOOKUP_TIMER: - rto = ((nmp->nm_srtt[index] + 3) >> 2) + - ((nmp->nm_sdrtt[index] + 1) >> 1); - break; - case NFS_READ_TIMER: - case NFS_WRITE_TIMER: - rto = ((nmp->nm_srtt[index] + 7) >> 3) + - (nmp->nm_sdrtt[index] + 1); - break; - default: - rto = nmp->nm_timeo; - return (rto); - } - - if (rto < NFS_MINRTO) - rto = NFS_MINRTO; - else if (rto > NFS_MAXRTO) - rto = NFS_MAXRTO; - - return (rto); -} - - -/* - * Initialize sockets and congestion for a new NFS connection. - * We do not free the sockaddr if error. - */ -int -nfs_connect(struct nfsmount *nmp, struct nfsreq *rep) -{ - struct socket *so; - int error, rcvreserve, sndreserve; - int pktscale; - struct sockaddr *saddr; - struct ucred *origcred; - struct thread *td = curthread; - - /* - * 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; - - if (nmp->nm_sotype == SOCK_STREAM) { - mtx_lock(&nmp->nm_mtx); - nmp->nm_nfstcpstate.flags |= NFS_TCP_EXPECT_RPCMARKER; - nmp->nm_nfstcpstate.rpcresid = 0; - mtx_unlock(&nmp->nm_mtx); - } - nmp->nm_so = NULL; - saddr = nmp->nm_nam; - error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, - nmp->nm_soproto, nmp->nm_mountp->mnt_cred, td); - if (error) - goto bad; - so = nmp->nm_so; - nmp->nm_soflags = so->so_proto->pr_flags; - - /* - * Some servers require that the client port be a reserved port number. - */ - if (nmp->nm_flag & NFSMNT_RESVPORT) { - struct sockopt sopt; - int ip, ip2, len; - struct sockaddr_in6 ssin; - struct sockaddr *sa; - - bzero(&sopt, sizeof sopt); - switch(saddr->sa_family) { - case AF_INET: - sopt.sopt_level = IPPROTO_IP; - sopt.sopt_name = IP_PORTRANGE; - ip = IP_PORTRANGE_LOW; - ip2 = IP_PORTRANGE_DEFAULT; - len = sizeof (struct sockaddr_in); - break; -#ifdef INET6 - case AF_INET6: - sopt.sopt_level = IPPROTO_IPV6; - sopt.sopt_name = IPV6_PORTRANGE; - ip = IPV6_PORTRANGE_LOW; - ip2 = IPV6_PORTRANGE_DEFAULT; - len = sizeof (struct sockaddr_in6); - break; -#endif - default: - goto noresvport; - } - sa = (struct sockaddr *)&ssin; - bzero(sa, len); - sa->sa_len = len; - sa->sa_family = saddr->sa_family; - sopt.sopt_dir = SOPT_SET; - sopt.sopt_val = (void *)&ip; - sopt.sopt_valsize = sizeof(ip); - error = sosetopt(so, &sopt); - if (error) - goto bad; - error = sobind(so, sa, td); - if (error) - goto bad; - ip = ip2; - error = sosetopt(so, &sopt); - if (error) - goto bad; - noresvport: ; - } - - /* - * Protocols that do not require connections may be optionally left - * unconnected for servers that reply from a port other than NFS_PORT. - */ - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_flag & NFSMNT_NOCONN) { - if (nmp->nm_soflags & PR_CONNREQUIRED) { - error = ENOTCONN; - mtx_unlock(&nmp->nm_mtx); - goto bad; - } else - mtx_unlock(&nmp->nm_mtx); - } else { - mtx_unlock(&nmp->nm_mtx); - error = soconnect(so, nmp->nm_nam, td); - if (error) - goto bad; - - /* - * Wait for the connection to complete. Cribbed from the - * connect system call but with the wait timing out so - * that interruptible mounts don't hang here for a long time. - */ - SOCK_LOCK(so); - while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - (void) msleep(&so->so_timeo, SOCK_MTX(so), - PSOCK, "nfscon", 2 * hz); - if ((so->so_state & SS_ISCONNECTING) && - so->so_error == 0 && rep && - (error = nfs_sigintr(nmp, rep, rep->r_td)) != 0) { - so->so_state &= ~SS_ISCONNECTING; - SOCK_UNLOCK(so); - goto bad; - } - } - if (so->so_error) { - error = so->so_error; - so->so_error = 0; - SOCK_UNLOCK(so); - goto bad; - } - SOCK_UNLOCK(so); - } - so->so_rcv.sb_timeo = 12 * hz; - if (nmp->nm_sotype == SOCK_STREAM) - so->so_snd.sb_timeo = 1 * hz; /* 1s snd timeout for NFS/TCP */ - else - so->so_snd.sb_timeo = 5 * hz; - - /* - * 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"); - if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = SOL_SOCKET; - sopt.sopt_name = SO_KEEPALIVE; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - mtx_unlock(&nmp->nm_mtx); - sosetopt(so, &sopt); - mtx_lock(&nmp->nm_mtx); - } - if (so->so_proto->pr_protocol == IPPROTO_TCP) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = IPPROTO_TCP; - sopt.sopt_name = TCP_NODELAY; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - mtx_unlock(&nmp->nm_mtx); - sosetopt(so, &sopt); - mtx_lock(&nmp->nm_mtx); - } - 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); - error = soreserve(so, sndreserve, rcvreserve); - if (error) - goto bad; - SOCKBUF_LOCK(&so->so_rcv); - so->so_rcv.sb_flags |= SB_NOINTR; - if (so->so_type == SOCK_STREAM) - soupcall_set(so, SO_RCV, nfs_clnt_tcp_soupcall, nmp); - else - soupcall_set(so, SO_RCV, nfs_clnt_udp_soupcall, nmp); - SOCKBUF_UNLOCK(&so->so_rcv); - SOCKBUF_LOCK(&so->so_snd); - so->so_snd.sb_flags |= SB_NOINTR; - SOCKBUF_UNLOCK(&so->so_snd); - - /* Restore current thread's credentials. */ - td->td_ucred = origcred; - - mtx_lock(&nmp->nm_mtx); - /* Initialize other non-zero congestion variables */ - nfs_init_rtt(nmp); - nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */ - nmp->nm_sent = 0; - nmp->nm_timeouts = 0; - mtx_unlock(&nmp->nm_mtx); - return (0); - -bad: - /* Restore current thread's credentials. */ - td->td_ucred = origcred; - - nfs_disconnect(nmp); - return (error); -} - -static void -nfs_wakup_reconnectors(struct nfsmount *nmp) -{ - KASSERT(mtx_owned(&nmp->nm_mtx), ("NFS mnt lock not owned !")); - if (--nmp->nm_nfstcpstate.sock_send_inprog == 0 && - (nmp->nm_nfstcpstate.flags & NFS_TCP_WAIT_WRITE_DRAIN)) { - nmp->nm_nfstcpstate.flags &= ~NFS_TCP_WAIT_WRITE_DRAIN; - wakeup((caddr_t)&nmp->nm_nfstcpstate.sock_send_inprog); - } -} - -/* - * Reconnect routine: - * Called when a connection is broken on a reliable protocol. - * - clean up the old socket - * - nfs_connect() again - * - set R_MUSTRESEND for all outstanding requests on mount point - * If this fails the mount point is DEAD! - * nb: Must be called with the nfs_sndlock() set on the mount point. - */ -static int -nfs_reconnect(struct nfsreq *rep) -{ - struct nfsreq *rp; - struct nfsmount *nmp = rep->r_nmp; - int error; - int slpflag = 0; - - KASSERT(mtx_owned(&nmp->nm_mtx), ("NFS mnt lock not owned !")); - if (nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - /* - * Wait for any pending writes to this socket to drain (or timeout). - */ - while (nmp->nm_nfstcpstate.sock_send_inprog > 0) { - nmp->nm_nfstcpstate.flags |= NFS_TCP_WAIT_WRITE_DRAIN; - error = msleep((caddr_t)&nmp->nm_nfstcpstate.sock_send_inprog, - &nmp->nm_mtx, slpflag | (PZERO - 1), "nfscon", 0); - } - /* - * Grab the nfs_connect_lock to serialize connects. - * After grabbing the nfs_connect_lock, check if a reconnect is necessary or - * if someone else beat us to the connect ! - */ - error = nfs_connect_lock(rep); - if (error) - goto unlock_exit; - if ((nmp->nm_nfstcpstate.flags & NFS_TCP_FORCE_RECONNECT) == 0) - goto unlock_exit; - else - mtx_unlock(&nmp->nm_mtx); - - nfs_reconnects++; - nfs_disconnect(nmp); - while ((error = nfs_connect(nmp, rep)) != 0) { - if (error == ERESTART) - error = EINTR; - if (error == EIO || error == EINTR) { - mtx_lock(&nmp->nm_mtx); - goto unlock_exit; - } - (void) tsleep(&fake_wchan, PSOCK, "nfscon", hz); - } - - /* - * Clear the FORCE_RECONNECT flag only after the connect - * succeeds. To prevent races between multiple processes - * waiting on the mountpoint where the connection is being - * torn down. The first one to acquire the sndlock will - * retry the connection. The others block on the sndlock - * until the connection is established successfully, and - * then re-transmit the request. - */ - mtx_lock(&nmp->nm_mtx); - nmp->nm_nfstcpstate.flags &= ~NFS_TCP_FORCE_RECONNECT; - nmp->nm_nfstcpstate.rpcresid = 0; - mtx_unlock(&nmp->nm_mtx); - - /* - * Loop through outstanding request list and fix up all requests - * on old socket. - */ - mtx_lock(&nfs_reqq_mtx); - TAILQ_FOREACH(rp, &nfs_reqq, r_chain) { - if (rp->r_nmp == nmp) { - mtx_lock(&rp->r_mtx); - rp->r_flags |= R_MUSTRESEND; - mtx_unlock(&rp->r_mtx); - } - } - mtx_unlock(&nfs_reqq_mtx); - mtx_lock(&nmp->nm_mtx); -unlock_exit: - nfs_connect_unlock(rep); - mtx_unlock(&nmp->nm_mtx); - return (error); -} - -/* - * NFS disconnect. Clean up and unlink. - */ -void -nfs_disconnect(struct nfsmount *nmp) -{ - struct socket *so; - - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_so) { - so = nmp->nm_so; - nmp->nm_so = NULL; - mtx_unlock(&nmp->nm_mtx); - SOCKBUF_LOCK(&so->so_rcv); - soupcall_clear(so, SO_RCV); - SOCKBUF_UNLOCK(&so->so_rcv); - soshutdown(so, SHUT_WR); - soclose(so); - } else - mtx_unlock(&nmp->nm_mtx); -} - -void -nfs_safedisconnect(struct nfsmount *nmp) -{ - struct nfsreq dummyreq; - - bzero(&dummyreq, sizeof(dummyreq)); - dummyreq.r_nmp = nmp; - nfs_disconnect(nmp); -} - -/* - * This is the nfs send routine. For connection based socket types, it - * must be called with an nfs_sndlock() on the socket. - * - return EINTR if the RPC is terminated, 0 otherwise - * - set R_MUSTRESEND if the send fails for any reason - * - do any cleanup required by recoverable socket errors (?) - */ -int -nfs_send(struct socket *so, struct sockaddr *nam, struct mbuf *top, - struct nfsreq *rep) -{ - struct sockaddr *sendnam; - int error, error2, soflags, flags; - - KASSERT(rep, ("nfs_send: called with rep == NULL")); - - error = nfs_sigintr(rep->r_nmp, rep, rep->r_td); - if (error) { - m_freem(top); - return (error); - } - mtx_lock(&rep->r_nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - if ((so = rep->r_nmp->nm_so) == NULL) { - rep->r_flags |= R_MUSTRESEND; - mtx_unlock(&rep->r_mtx); - mtx_unlock(&rep->r_nmp->nm_mtx); - m_freem(top); - return (EPIPE); - } - rep->r_flags &= ~R_MUSTRESEND; - soflags = rep->r_nmp->nm_soflags; - mtx_unlock(&rep->r_mtx); - mtx_unlock(&rep->r_nmp->nm_mtx); - - if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) - sendnam = NULL; - else - sendnam = nam; - if (so->so_type == SOCK_SEQPACKET) - flags = MSG_EOR; - else - flags = 0; - - error = sosend(so, sendnam, 0, top, 0, flags, curthread /*XXX*/); - if (error == ENOBUFS && so->so_type == SOCK_DGRAM) { - error = 0; - mtx_lock(&rep->r_mtx); - rep->r_flags |= R_MUSTRESEND; - mtx_unlock(&rep->r_mtx); - } - - if (error) { - /* - * Don't report EPIPE errors on nfs sockets. - * These can be due to idle tcp mounts which will be closed by - * netapp, solaris, etc. if left idle too long. - */ - if (error != EPIPE) { - log(LOG_INFO, "nfs send error %d for server %s\n", - error, - rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); - } - /* - * Deal with errors for the client side. - */ - error2 = NFS_SIGREP(rep); - if (error2) - error = error2; - else { - mtx_lock(&rep->r_mtx); - rep->r_flags |= R_MUSTRESEND; - mtx_unlock(&rep->r_mtx); - } - - /* - * Handle any recoverable (soft) socket errors here. (?) - * Make EWOULDBLOCK a recoverable error, we'll rexmit from nfs_timer(). - */ - if (error != EINTR && error != ERESTART && error != EIO && error != EPIPE) - error = 0; - } - return (error); -} - -int -nfs_reply(struct nfsreq *rep) -{ - register struct socket *so; - register struct mbuf *m; - int error = 0, sotype, slpflag; - struct nfsmount *nmp = rep->r_nmp; - - sotype = nmp->nm_sotype; - /* - * For reliable protocols, lock against other senders/receivers - * in case a reconnect is necessary. - */ - if (sotype != SOCK_DGRAM) { -tryagain: - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - if (rep->r_mrep) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - return (0); - } - if (rep->r_flags & R_SOFTTERM) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - return (EINTR); - } - so = nmp->nm_so; - if (!so || - (nmp->nm_nfstcpstate.flags & NFS_TCP_FORCE_RECONNECT)) { - mtx_unlock(&rep->r_mtx); - nmp->nm_nfstcpstate.flags |= NFS_TCP_FORCE_RECONNECT; - error = nfs_reconnect(rep); - if (error) - return (error); - goto tryagain; - } - while (rep->r_flags & R_MUSTRESEND) { - mtx_unlock(&rep->r_mtx); - nmp->nm_nfstcpstate.sock_send_inprog++; - mtx_unlock(&nmp->nm_mtx); - m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT); - nfsstats.rpcretries++; - error = nfs_send(so, nmp->nm_nam, m, rep); - if (error) { - mtx_lock(&nmp->nm_mtx); - nfs_wakup_reconnectors(nmp); - if (!(error == EINTR || error == ERESTART)) { - nmp->nm_nfstcpstate.flags |= NFS_TCP_FORCE_RECONNECT; - error = nfs_reconnect(rep); - } else - mtx_unlock(&nmp->nm_mtx); - if (error) - return (error); - goto tryagain; - } else { - mtx_lock(&nmp->nm_mtx); - nfs_wakup_reconnectors(nmp); - mtx_lock(&rep->r_mtx); - } - } - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - } - slpflag = 0; - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - mtx_unlock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - while ((rep->r_mrep == NULL) && (error == 0) && - ((rep->r_flags & R_SOFTTERM) == 0) && - ((sotype == SOCK_DGRAM) || ((rep->r_flags & R_MUSTRESEND) == 0))) - error = msleep((caddr_t)rep, &rep->r_mtx, - slpflag | (PZERO - 1), "nfsreq", 0); - if (error == EINTR || error == ERESTART) { - /* NFS operations aren't restartable. Map ERESTART to EINTR */ - mtx_unlock(&rep->r_mtx); - return (EINTR); - } - if (rep->r_flags & R_SOFTTERM) { - /* Request was terminated because we exceeded the retries (soft mount) */ - mtx_unlock(&rep->r_mtx); - return (ETIMEDOUT); - } - mtx_unlock(&rep->r_mtx); - if (sotype == SOCK_STREAM) { - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - if (((nmp->nm_nfstcpstate.flags & NFS_TCP_FORCE_RECONNECT) || - (rep->r_flags & R_MUSTRESEND))) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - goto tryagain; - } else { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - } - } - return (error); -} - -/* - * XXX TO DO - * Make nfs_realign() non-blocking. Also make nfsm_dissect() nonblocking. - */ -static void -nfs_clnt_match_xid(struct socket *so, - struct nfsmount *nmp, - struct mbuf *mrep) -{ - struct mbuf *md; - caddr_t dpos; - u_int32_t rxid, *tl; - struct nfsreq *rep; - int error; - - /* - * 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. - */ - if (nfs_realign(&mrep, 5 * NFSX_UNSIGNED) == ENOMEM) { - m_freem(mrep); - nfsstats.rpcinvalid++; - return; - } - - /* - * Get the xid and check that it is an rpc reply - */ - md = mrep; - dpos = mtod(md, caddr_t); - tl = nfsm_dissect_nonblock(u_int32_t *, 2*NFSX_UNSIGNED); - rxid = *tl++; - if (*tl != rpc_reply) { - m_freem(mrep); -nfsmout: - nfsstats.rpcinvalid++; - return; - } - - mtx_lock(&nfs_reqq_mtx); - /* - * Loop through the request list to match up the reply - * Iff no match, just drop the datagram - */ - TAILQ_FOREACH(rep, &nfs_reqq, r_chain) { - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - if (rep->r_mrep == NULL && rxid == rep->r_xid) { - /* Found it.. */ - rep->r_mrep = mrep; - rep->r_md = md; - rep->r_dpos = dpos; - /* - * Update congestion window. - * Do the additive increase of - * one rpc/rtt. - */ - if (nmp->nm_cwnd <= nmp->nm_sent) { - nmp->nm_cwnd += - (NFS_CWNDSCALE * NFS_CWNDSCALE + - (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd; - if (nmp->nm_cwnd > NFS_MAXCWND) - nmp->nm_cwnd = NFS_MAXCWND; - } - if (rep->r_flags & R_SENT) { - rep->r_flags &= ~R_SENT; - nmp->nm_sent -= NFS_CWNDSCALE; - } - if (rep->r_flags & R_TIMING) - nfs_update_rtt(rep); - nmp->nm_timeouts = 0; - wakeup((caddr_t)rep); - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - break; - } - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - } - /* - * If not matched to a request, drop it. - * If it's mine, wake up requestor. - */ - if (rep == 0) { - nfsstats.rpcunexpected++; - m_freem(mrep); - } - mtx_unlock(&nfs_reqq_mtx); -} - -static void -nfs_mark_for_reconnect(struct nfsmount *nmp) -{ - struct nfsreq *rp; - - mtx_lock(&nmp->nm_mtx); - nmp->nm_nfstcpstate.flags |= NFS_TCP_FORCE_RECONNECT; - mtx_unlock(&nmp->nm_mtx); - /* - * Wakeup all processes that are waiting for replies - * on this mount point. One of them does the reconnect. - */ - mtx_lock(&nfs_reqq_mtx); - TAILQ_FOREACH(rp, &nfs_reqq, r_chain) { - if (rp->r_nmp == nmp) { - mtx_lock(&rp->r_mtx); - rp->r_flags |= R_MUSTRESEND; - wakeup((caddr_t)rp); - mtx_unlock(&rp->r_mtx); - } - } - mtx_unlock(&nfs_reqq_mtx); -} - -static int -nfstcp_readable(struct socket *so, int bytes) -{ - int retval; - - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - retval = (so->so_rcv.sb_cc >= (bytes) || - (so->so_rcv.sb_state & SBS_CANTRCVMORE) || - so->so_error); - return (retval); -} - -#define nfstcp_marker_readable(so) nfstcp_readable(so, sizeof(u_int32_t)) - -static int -nfs_copy_len(struct mbuf *mp, char *buf, int len) -{ - while (len > 0 && mp != NULL) { - int copylen = min(len, mp->m_len); - - bcopy(mp->m_data, buf, copylen); - buf += copylen; - len -= copylen; - mp = mp->m_next; - } - return (len); -} - -static int -nfs_clnt_tcp_soupcall(struct socket *so, void *arg, int waitflag) -{ - struct nfsmount *nmp = (struct nfsmount *)arg; - struct mbuf *mp = NULL; - struct uio auio; - int error; - u_int32_t len; - int rcvflg; - - /* - * Don't pick any more data from the socket if we've marked the - * mountpoint for reconnect. - */ - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_nfstcpstate.flags & NFS_TCP_FORCE_RECONNECT) { - mtx_unlock(&nmp->nm_mtx); - return (SU_OK); - } else - mtx_unlock(&nmp->nm_mtx); - auio.uio_td = curthread; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - for ( ; ; ) { - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_nfstcpstate.flags & NFS_TCP_EXPECT_RPCMARKER) { - int resid; - - mtx_unlock(&nmp->nm_mtx); - if (!nfstcp_marker_readable(so)) { - /* Marker is not readable */ - return (SU_OK); - } - SOCKBUF_UNLOCK(&so->so_rcv); - auio.uio_resid = sizeof(u_int32_t); - auio.uio_iov = NULL; - auio.uio_iovcnt = 0; - mp = NULL; - rcvflg = (MSG_DONTWAIT | MSG_SOCALLBCK); - error = soreceive(so, (struct sockaddr **)0, &auio, - &mp, (struct mbuf **)0, &rcvflg); - SOCKBUF_LOCK(&so->so_rcv); - /* - * We've already tested that the socket is readable. 2 cases - * here, we either read 0 bytes (client closed connection), - * or got some other error. In both cases, we tear down the - * connection. - */ - if (error || auio.uio_resid > 0) { - if (error && error != ECONNRESET) { - log(LOG_ERR, - "nfs/tcp clnt: Error %d reading socket, tearing down TCP connection\n", - error); - } - goto mark_reconnect; - } - if (mp == NULL) - panic("nfs_clnt_tcp_soupcall: Got empty mbuf chain from sorecv\n"); - /* - * Sigh. We can't do the obvious thing here (which would - * be to have soreceive copy the length from mbufs for us). - * Calling uiomove() from the context of a socket callback - * (even for kernel-kernel copies) leads to LORs (since - * we hold network locks at this point). - */ - if ((resid = nfs_copy_len(mp, (char *)&len, - sizeof(u_int32_t)))) { - log(LOG_ERR, "%s (%d) from nfs server %s\n", - "Bad RPC HDR length", - (int)(sizeof(u_int32_t) - resid), - nmp->nm_mountp->mnt_stat.f_mntfromname); - goto mark_reconnect; - } - len = ntohl(len) & ~0x80000000; - m_freem(mp); - /* - * This is SERIOUS! We are out of sync with the sender - * and forcing a disconnect/reconnect is all I can do. - */ - if (len > NFS_MAXPACKET || len == 0) { - log(LOG_ERR, "%s (%d) from nfs server %s\n", - "impossible packet length", - len, - nmp->nm_mountp->mnt_stat.f_mntfromname); - goto mark_reconnect; - } - mtx_lock(&nmp->nm_mtx); - nmp->nm_nfstcpstate.rpcresid = len; - nmp->nm_nfstcpstate.flags &= ~(NFS_TCP_EXPECT_RPCMARKER); - mtx_unlock(&nmp->nm_mtx); - } else - mtx_unlock(&nmp->nm_mtx); - - /* - * Processed RPC marker or no RPC marker to process. - * Pull in and process data. - */ - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_nfstcpstate.rpcresid > 0) { - mtx_unlock(&nmp->nm_mtx); - if (!nfstcp_readable(so, nmp->nm_nfstcpstate.rpcresid)) { - /* All data not readable */ - return (SU_OK); - } - SOCKBUF_UNLOCK(&so->so_rcv); - auio.uio_resid = nmp->nm_nfstcpstate.rpcresid; - auio.uio_iov = NULL; - auio.uio_iovcnt = 0; - mp = NULL; - rcvflg = (MSG_DONTWAIT | MSG_SOCALLBCK); - error = soreceive(so, (struct sockaddr **)0, &auio, - &mp, (struct mbuf **)0, &rcvflg); - SOCKBUF_LOCK(&so->so_rcv); - if (error || auio.uio_resid > 0) { - if (error && error != ECONNRESET) { - log(LOG_ERR, - "nfs/tcp clnt: Error %d reading socket, tearing down TCP connection\n", - error); - } - goto mark_reconnect; - } - if (mp == NULL) - panic("nfs_clnt_tcp_soupcall: Got empty mbuf chain from sorecv\n"); - mtx_lock(&nmp->nm_mtx); - nmp->nm_nfstcpstate.rpcresid = 0; - nmp->nm_nfstcpstate.flags |= NFS_TCP_EXPECT_RPCMARKER; - mtx_unlock(&nmp->nm_mtx); - /* We got the entire RPC reply. Match XIDs and wake up requestor */ - nfs_clnt_match_xid(so, nmp, mp); - } else - mtx_unlock(&nmp->nm_mtx); - } - -mark_reconnect: - nfs_mark_for_reconnect(nmp); - return (SU_OK); -} - -static int -nfs_clnt_udp_soupcall(struct socket *so, void *arg, int waitflag) -{ - struct nfsmount *nmp = (struct nfsmount *)arg; - struct uio auio; - struct mbuf *mp = NULL; - struct mbuf *control = NULL; - int error, rcvflag; - - SOCKBUF_UNLOCK(&so->so_rcv); - auio.uio_resid = 1000000; - auio.uio_td = curthread; - rcvflag = MSG_DONTWAIT; - auio.uio_resid = 1000000000; - do { - mp = control = NULL; - error = soreceive(so, NULL, &auio, &mp, &control, &rcvflag); - if (control) - m_freem(control); - if (mp) - nfs_clnt_match_xid(so, nmp, mp); - } while (mp && !error); - SOCKBUF_LOCK(&so->so_rcv); - return (SU_OK); -} - -/* - * 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 *mrest, int procnum, - struct thread *td, struct ucred *cred, struct mbuf **mrp, - struct mbuf **mdp, caddr_t *dposp) -{ - struct mbuf *mrep, *m2; - struct nfsreq *rep; - u_int32_t *tl; - int i; - struct nfsmount *nmp; - struct mbuf *m, *md, *mheadend; - time_t waituntil; - caddr_t dpos; - int error = 0, mrest_len, auth_len, auth_type; - struct timeval now; - u_int32_t *xidp; - - /* Reject requests while attempting a forced unmount. */ - if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) { - m_freem(mrest); - return (ESTALE); - } - nmp = VFSTONFS(vp->v_mount); - rep = malloc(sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); - bzero(rep, sizeof(struct nfsreq)); - rep->r_nmp = nmp; - rep->r_vp = vp; - rep->r_td = td; - rep->r_procnum = procnum; - mtx_init(&rep->r_mtx, "NFSrep lock", NULL, MTX_DEF); - - getmicrouptime(&now); - rep->r_lastmsg = now.tv_sec - - ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay)); - mrest_len = m_length(mrest, NULL); - - /* - * Get the RPC header with authorization. - */ - auth_type = RPCAUTH_UNIX; - if (cred->cr_ngroups < 1) - panic("nfsreq nogrps"); - auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ? - nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + - 5 * NFSX_UNSIGNED; - m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, - mrest, mrest_len, &mheadend, &xidp); - - /* - * For stream protocols, insert a Sun RPC Record Mark. - */ - if (nmp->nm_sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | - (m->m_pkthdr.len - NFSX_UNSIGNED)); - } - rep->r_mreq = m; - rep->r_xid = *xidp; -tryagain: - if (nmp->nm_flag & NFSMNT_SOFT) - rep->r_retry = nmp->nm_retry; - else - rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */ - rep->r_rtt = rep->r_rexmit = 0; - if (nfs_rto_timer(procnum) != NFS_DEFAULT_TIMER) - rep->r_flags = R_TIMING; - else - rep->r_flags = 0; - rep->r_mrep = NULL; - - /* - * Do the client side RPC. - */ - nfsstats.rpcrequests++; - /* - * Chain request into list of outstanding requests. Be sure - * to put it LAST so timer finds oldest requests first. - */ - mtx_lock(&nfs_reqq_mtx); - if (TAILQ_EMPTY(&nfs_reqq)) - callout_reset(&nfs_callout, nfs_ticks, nfs_timer, NULL); - TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain); - mtx_unlock(&nfs_reqq_mtx); - - /* - * If backing off another request or avoiding congestion, don't - * send this one now but let timer do it. If not timing a request, - * do it now. - */ - mtx_lock(&nmp->nm_mtx); - if (nmp->nm_so && - (((nmp->nm_sotype == SOCK_STREAM) && !(nmp->nm_nfstcpstate.flags & NFS_TCP_FORCE_RECONNECT)) || - (nmp->nm_flag & NFSMNT_DUMBTIMR) || nmp->nm_sent < nmp->nm_cwnd)) { - if (nmp->nm_sotype == SOCK_STREAM) - nmp->nm_nfstcpstate.sock_send_inprog++; - mtx_unlock(&nmp->nm_mtx); - m2 = m_copym(m, 0, M_COPYALL, M_WAIT); - error = nfs_send(nmp->nm_so, nmp->nm_nam, m2, rep); - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - /* - * nfs_timer() could've re-transmitted the request if we ended up - * blocking on nfs_send() too long, so check for R_SENT here. - */ - if (!error && (rep->r_flags & (R_SENT | R_MUSTRESEND)) == 0) { - nmp->nm_sent += NFS_CWNDSCALE; - rep->r_flags |= R_SENT; - } - mtx_unlock(&rep->r_mtx); - if (nmp->nm_sotype == SOCK_STREAM) - nfs_wakup_reconnectors(rep->r_nmp); - mtx_unlock(&nmp->nm_mtx); - } else { - mtx_unlock(&nmp->nm_mtx); - rep->r_rtt = -1; - } - - /* - * Wait for the reply from our send or the timer's. - */ - if (!error || error == EPIPE) - error = nfs_reply(rep); - - /* - * nfs_timer() may be in the process of re-transmitting this request. - * nfs_timer() drops the nfs_reqq_mtx before the pru_send() (to avoid LORs). - * Wait till nfs_timer() completes the re-transmission. When the reply - * comes back, it will be discarded (since the req struct for it no longer - * exists). - */ -wait_for_pinned_req: - mtx_lock(&rep->r_mtx); - while (rep->r_flags & R_PIN_REQ) { - msleep((caddr_t)&rep->r_flags, &rep->r_mtx, - (PZERO - 1), "nfsrxmt", 0); - } - mtx_unlock(&rep->r_mtx); - - mtx_lock(&nfs_reqq_mtx); - /* Have to check for R_PIN_REQ after grabbing wlock again */ - mtx_lock(&rep->r_mtx); - if (rep->r_flags & R_PIN_REQ) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nfs_reqq_mtx); - goto wait_for_pinned_req; - } else - mtx_unlock(&rep->r_mtx); - /* RPC done (timer not active, request not pinned), unlink the request */ - TAILQ_REMOVE(&nfs_reqq, rep, r_chain); - if (TAILQ_EMPTY(&nfs_reqq)) - callout_stop(&nfs_callout); - mtx_unlock(&nfs_reqq_mtx); - - /* - * Decrement the outstanding request count. - */ - mtx_lock(&rep->r_mtx); - if (rep->r_flags & R_SENT) { - rep->r_flags &= ~R_SENT; /* paranoia */ - mtx_unlock(&rep->r_mtx); - mtx_lock(&nmp->nm_mtx); - nmp->nm_sent -= NFS_CWNDSCALE; - mtx_unlock(&nmp->nm_mtx); - } else - mtx_unlock(&rep->r_mtx); - - /* - * If there was a successful reply and a tprintf msg. - * tprintf a response. - */ - if (!error) { - nfs_up(rep, nmp, rep->r_td, "is alive again", NFSSTA_TIMEO); - } - mrep = rep->r_mrep; - md = rep->r_md; - dpos = rep->r_dpos; - if (error) { - /* - * If we got interrupted by a signal in nfs_reply(), there's - * a very small window where the reply could've come in before - * this process got scheduled in. To handle that case, we need - * to free the reply if it was delivered. - */ - if (rep->r_mrep != NULL) - m_freem(rep->r_mrep); - m_freem(rep->r_mreq); - mtx_destroy(&rep->r_mtx); - free((caddr_t)rep, M_NFSREQ); - return (error); - } - - if (rep->r_mrep == NULL) - panic("nfs_request: rep->r_mrep shouldn't be NULL if no error\n"); - - /* - * break down the rpc header and check if ok - */ - tl = nfsm_dissect(u_int32_t *, 3 * NFSX_UNSIGNED); - if (*tl++ == rpc_msgdenied) { - if (*tl == rpc_mismatch) - error = EOPNOTSUPP; - else - error = EACCES; - m_freem(mrep); - m_freem(rep->r_mreq); - mtx_destroy(&rep->r_mtx); - free((caddr_t)rep, M_NFSREQ); - return (error); - } - - /* - * Just throw away any verifyer (ie: kerberos etc). - */ - i = fxdr_unsigned(int, *tl++); /* verf type */ - i = fxdr_unsigned(int32_t, *tl); /* len */ - if (i > 0) - nfsm_adv(nfsm_rndup(i)); - tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED); - /* 0 == ok */ - if (*tl == 0) { - 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); - } - rep->r_xid = *xidp = txdr_unsigned(nfs_xid_gen()); - goto tryagain; - } - - /* - * If the File Handle was stale, invalidate the - * lookup cache, just in case. - */ - if (error == ESTALE) - nfs_purgecache(vp); - /* - * Skip wcc data on 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. - */ - if ((nmp->nm_flag & NFSMNT_NFSV3) && !nfs_skip_wcc_data_onerr) { - *mrp = mrep; - *mdp = md; - *dposp = dpos; - error |= NFSERR_RETERR; - } else - m_freem(mrep); - m_freem(rep->r_mreq); - mtx_destroy(&rep->r_mtx); - free((caddr_t)rep, M_NFSREQ); - return (error); - } - - *mrp = mrep; - *mdp = md; - *dposp = dpos; - m_freem(rep->r_mreq); - mtx_destroy(&rep->r_mtx); - free((caddr_t)rep, M_NFSREQ); - return (0); - } - m_freem(mrep); - error = EPROTONOSUPPORT; -nfsmout: - m_freem(rep->r_mreq); - mtx_destroy(&rep->r_mtx); - free((caddr_t)rep, M_NFSREQ); - return (error); -} - -/* - * Nfs timer routine - * Scan the nfsreq list and retranmit any requests that have timed out - * To avoid retransmission attempts on STREAM sockets (in the future) make - * sure to set the r_retry field to 0 (implies nm_retry == 0). - * - * The nfs reqq lock cannot be held while we do the pru_send() because of a - * lock ordering violation. The NFS client socket callback acquires - * inp_lock->nfsreq mutex and pru_send acquires inp_lock. So we drop the - * reqq mutex (and reacquire it after the pru_send()). The req structure - * (for the rexmit) is prevented from being removed by the R_PIN_REQ flag. - */ -void -nfs_timer(void *arg) -{ - struct nfsreq *rep; - struct mbuf *m; - struct socket *so; - struct nfsmount *nmp; - int timeo; - int error; - struct timeval now; - - getmicrouptime(&now); - mtx_lock(&nfs_reqq_mtx); - TAILQ_FOREACH(rep, &nfs_reqq, r_chain) { - nmp = rep->r_nmp; - mtx_lock(&rep->r_mtx); - if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) { - mtx_unlock(&rep->r_mtx); - continue; - } else { - /* - * Terminate request if force-unmount in progress. - * Note that NFS could have vfs_busy'ed the mount, - * causing the unmount to wait and making this bit - * of logic necessary. - */ - if (rep->r_nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) { - nfs_softterm(rep); - mtx_unlock(&rep->r_mtx); - continue; - } - mtx_unlock(&rep->r_mtx); - } - if (nfs_sigintr(nmp, rep, rep->r_td)) - continue; - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - if (nmp->nm_tprintf_initial_delay != 0 && - (rep->r_rexmit > 2 || (rep->r_flags & R_RESENDERR)) && - rep->r_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) { - rep->r_lastmsg = now.tv_sec; - /* - * Pin down the request and drop locks for the acquisition - * of Giant from tprintf() in nfs_down(). - */ - rep->r_flags |= R_PIN_REQ; - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - mtx_unlock(&nfs_reqq_mtx); - nfs_down(rep, nmp, rep->r_td, "not responding", - 0, NFSSTA_TIMEO); - mtx_lock(&nfs_reqq_mtx); - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - rep->r_flags &= ~R_PIN_REQ; - wakeup((caddr_t)&rep->r_flags); - } - if (rep->r_rtt >= 0) { - rep->r_rtt++; - if (nmp->nm_flag & NFSMNT_DUMBTIMR) - timeo = nmp->nm_timeo; - else - timeo = nfs_estimate_rto(nmp, rep->r_procnum); - if (nmp->nm_timeouts > 0) - timeo *= nfs_backoff[nmp->nm_timeouts - 1]; - if (rep->r_rtt <= timeo) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - continue; - } - if (nmp->nm_timeouts < NFS_NBACKOFF) - nmp->nm_timeouts++; - } - if (rep->r_rexmit >= rep->r_retry) { /* too many */ - nfsstats.rpctimeouts++; - nfs_softterm(rep); - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - continue; - } - if (nmp->nm_sotype != SOCK_DGRAM) { - if (++rep->r_rexmit > NFS_MAXREXMIT) - rep->r_rexmit = NFS_MAXREXMIT; - /* - * For NFS/TCP, setting R_MUSTRESEND and waking up - * the requester will cause the request to be - * retransmitted (in nfs_reply()), re-connecting - * if necessary. - */ - rep->r_flags |= R_MUSTRESEND; - wakeup((caddr_t)rep); - rep->r_rtt = 0; - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - continue; - } - if ((so = nmp->nm_so) == NULL) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - continue; - } - /* - * If there is enough space and the window allows.. - * Resend it - * Set r_rtt to -1 in case we fail to send it now. - */ - rep->r_rtt = -1; - if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && - ((nmp->nm_flag & NFSMNT_DUMBTIMR) || (rep->r_flags & R_SENT) || - nmp->nm_sent < nmp->nm_cwnd)) { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - if ((m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))) { - /* - * Mark the request to indicate that a XMIT is in - * progress to prevent the req structure being - * removed in nfs_request(). - */ - mtx_lock(&rep->r_mtx); - rep->r_flags |= R_PIN_REQ; - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nfs_reqq_mtx); - if ((nmp->nm_flag & NFSMNT_NOCONN) == 0) - error = (*so->so_proto->pr_usrreqs->pru_send) - (so, 0, m, NULL, NULL, curthread); - else - error = (*so->so_proto->pr_usrreqs->pru_send) - (so, 0, m, nmp->nm_nam, NULL, - curthread); - mtx_lock(&nfs_reqq_mtx); - mtx_lock(&nmp->nm_mtx); - mtx_lock(&rep->r_mtx); - rep->r_flags &= ~R_PIN_REQ; - wakeup((caddr_t)&rep->r_flags); - if (error) { - if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) - so->so_error = 0; - rep->r_flags |= R_RESENDERR; - } else { - /* - * Iff first send, start timing - * else turn timing off, backoff timer - * and divide congestion window by 2. - */ - rep->r_flags &= ~R_RESENDERR; - if (rep->r_flags & R_SENT) { - rep->r_flags &= ~R_TIMING; - if (++rep->r_rexmit > NFS_MAXREXMIT) - rep->r_rexmit = NFS_MAXREXMIT; - nmp->nm_cwnd >>= 1; - if (nmp->nm_cwnd < NFS_CWNDSCALE) - nmp->nm_cwnd = NFS_CWNDSCALE; - nfsstats.rpcretries++; - } else { - rep->r_flags |= R_SENT; - nmp->nm_sent += NFS_CWNDSCALE; - } - rep->r_rtt = 0; - } - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - } - } else { - mtx_unlock(&rep->r_mtx); - mtx_unlock(&nmp->nm_mtx); - } - } - mtx_unlock(&nfs_reqq_mtx); - callout_reset(&nfs_callout, nfs_ticks, nfs_timer, NULL); -} - -/* - * 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(nmp) - struct nfsmount *nmp; -{ - struct nfsreq *req; - int i; - - mtx_lock(&nfs_reqq_mtx); - TAILQ_FOREACH(req, &nfs_reqq, r_chain) { - mtx_lock(&req->r_mtx); - if (nmp != req->r_nmp || req->r_mrep != NULL || - (req->r_flags & R_SOFTTERM)) { - mtx_unlock(&req->r_mtx); - continue; - } - nfs_softterm(req); - mtx_unlock(&req->r_mtx); - } - mtx_unlock(&nfs_reqq_mtx); - - for (i = 0; i < 30; i++) { - mtx_lock(&nfs_reqq_mtx); - TAILQ_FOREACH(req, &nfs_reqq, r_chain) { - if (nmp == req->r_nmp) - break; - } - mtx_unlock(&nfs_reqq_mtx); - if (req == NULL) - return (0); - tsleep(&fake_wchan, PSOCK, "nfscancel", hz); - } - return (EBUSY); -} - -/* - * Flag a request as being about to terminate (due to NFSMNT_INT/NFSMNT_SOFT). - * The nm_send count is decremented now to avoid deadlocks when the process in - * soreceive() hasn't yet managed to send its own request. - */ - -static void -nfs_softterm(struct nfsreq *rep) -{ - KASSERT(mtx_owned(&rep->r_mtx), ("NFS req lock not owned !")); - rep->r_flags |= R_SOFTTERM; - if (rep->r_flags & R_SENT) { - rep->r_nmp->nm_sent -= NFS_CWNDSCALE; - rep->r_flags &= ~R_SENT; - } - /* - * Request terminated, wakeup the blocked process, so that we - * can return EINTR back. - */ - wakeup((caddr_t)rep); -} - -/* - * 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, - SIGSTOP, - 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 process p_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, ie. 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); - PROC_UNLOCK(p); - kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); -} - -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 nfsreq *rep, struct thread *td) -{ - struct proc *p; - sigset_t tmpset; - - if (rep) { - mtx_lock(&rep->r_mtx); - if (rep->r_flags & R_SOFTTERM) { - mtx_unlock(&rep->r_mtx); - return (EIO); - } else - mtx_unlock(&rep->r_mtx); - } - /* 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); -} - -/* - * Lock a socket against others. - * Necessary for STREAM sockets to ensure you get an entire rpc request/reply - * and also to avoid race conditions between the processes with nfs requests - * in progress when a reconnect is necessary. - */ -int -nfs_connect_lock(struct nfsreq *rep) -{ - int *statep = &rep->r_nmp->nm_state; - struct thread *td; - int error, slpflag = 0, slptimeo = 0; - - td = rep->r_td; - if (rep->r_nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - while (*statep & NFSSTA_SNDLOCK) { - error = nfs_sigintr(rep->r_nmp, rep, td); - if (error) { - return (error); - } - *statep |= NFSSTA_WANTSND; - (void) msleep(statep, &rep->r_nmp->nm_mtx, - slpflag | (PZERO - 1), "nfsndlck", slptimeo); - if (slpflag == PCATCH) { - slpflag = 0; - slptimeo = 2 * hz; - } - } - *statep |= NFSSTA_SNDLOCK; - return (0); -} - -/* - * Unlock the stream socket for others. - */ -void -nfs_connect_unlock(struct nfsreq *rep) -{ - int *statep = &rep->r_nmp->nm_state; - - if ((*statep & NFSSTA_SNDLOCK) == 0) - panic("nfs sndunlock"); - *statep &= ~NFSSTA_SNDLOCK; - if (*statep & NFSSTA_WANTSND) { - *statep &= ~NFSSTA_WANTSND; - wakeup(statep); - } -} - -/* - * nfs_realign: - * - * 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.realign_count and realign_test to check this. - * - */ -static int -nfs_realign(struct mbuf **pm, int hsiz) -{ - struct mbuf *m; - struct mbuf *n = NULL; - int off = 0; - - ++nfs_realign_test; - while ((m = *pm) != NULL) { - if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { - MGET(n, M_DONTWAIT, MT_DATA); - if (n == NULL) - return (ENOMEM); - if (m->m_len >= MINCLSIZE) { - MCLGET(n, M_DONTWAIT); - if (n->m_ext.ext_buf == NULL) { - m_freem(n); - return (ENOMEM); - } - } - n->m_len = 0; - break; - } - pm = &m->m_next; - } - /* - * If n is non-NULL, loop on m copying data, then replace the - * portion of the chain that had to be realigned. - */ - if (n != NULL) { - ++nfs_realign_count; - while (m) { - m_copyback(n, off, m->m_len, mtod(m, caddr_t)); - off += m->m_len; - m = m->m_next; - } - m_freem(*pm); - *pm = n; - } - 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); -} - -void -nfs_down(rep, nmp, td, msg, error, flags) - struct nfsreq *rep; - struct nfsmount *nmp; - struct thread *td; - const char *msg; - int error, 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); -#ifdef NFSSTA_LOCKTIMEO - 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); -#endif - if (rep != NULL) { - mtx_lock(&rep->r_mtx); - rep->r_flags |= R_TPRINTFMSG; - mtx_unlock(&rep->r_mtx); - } - nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); -} - -void -nfs_up(rep, nmp, td, msg, flags) - struct nfsreq *rep; - struct nfsmount *nmp; - struct thread *td; - const char *msg; - int flags; -{ - if (nmp == NULL || rep == NULL) - return; - mtx_lock(&rep->r_mtx); - if ((rep->r_flags & R_TPRINTFMSG) != 0) { - mtx_unlock(&rep->r_mtx); - nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); - } else - mtx_unlock(&rep->r_mtx); - - 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); - -#ifdef NFSSTA_LOCKTIMEO - 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); -#endif -} - -#endif /* NFS_LEGACYRPC */ diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c index 71d4fb1..6f4ef7b 100644 --- a/sys/nfsclient/nfs_subs.c +++ b/sys/nfsclient/nfs_subs.c @@ -65,7 +65,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_extern.h> #include <vm/uma.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsnode.h> @@ -105,8 +104,6 @@ uint32_t nfsclient_attrcache_load_done_id; * This is kinda hokey, but may save a little time doing byte swaps */ u_int32_t nfs_xdrneg1; -u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, - rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; u_int32_t nfs_true, nfs_false; /* And other global data */ @@ -118,10 +115,6 @@ static enum vtype nv2tov_type[8]= { int nfs_ticks; int nfs_pbuf_freecnt = -1; /* start out unlimited */ -#ifdef NFS_LEGACYRPC -struct nfs_reqq nfs_reqq; -struct mtx nfs_reqq_mtx; -#endif struct nfs_bufq nfs_bufq; static struct mtx nfs_xid_mtx; @@ -194,87 +187,6 @@ nfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) } /* - * Build the RPC header and fill in the authorization info. - * The authorization string argument is only used when the credentials - * come from outside of the kernel. - * Returns the head of the mbuf list. - */ -struct mbuf * -nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, - int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, - u_int32_t **xidpp) -{ - struct mbuf *mb; - u_int32_t *tl; - caddr_t bpos; - int i; - struct mbuf *mreq; - int grpsiz, authsiz; - - authsiz = nfsm_rndup(auth_len); - MGETHDR(mb, M_WAIT, MT_DATA); - if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { - MCLGET(mb, M_WAIT); - } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { - MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); - } else { - MH_ALIGN(mb, 8 * NFSX_UNSIGNED); - } - mb->m_len = 0; - mreq = mb; - bpos = mtod(mb, caddr_t); - - /* - * First the RPC header. - */ - tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); - - *xidpp = tl; - *tl++ = txdr_unsigned(nfs_xid_gen()); - *tl++ = rpc_call; - *tl++ = rpc_vers; - *tl++ = txdr_unsigned(NFS_PROG); - if (nmflag & NFSMNT_NFSV3) { - *tl++ = txdr_unsigned(NFS_VER3); - *tl++ = txdr_unsigned(procid); - } else { - *tl++ = txdr_unsigned(NFS_VER2); - *tl++ = txdr_unsigned(nfsv2_procid[procid]); - } - - /* - * And then the authorization cred. - */ - *tl++ = txdr_unsigned(auth_type); - *tl = txdr_unsigned(authsiz); - switch (auth_type) { - case RPCAUTH_UNIX: - tl = nfsm_build(u_int32_t *, auth_len); - *tl++ = 0; /* stamp ?? */ - *tl++ = 0; /* NULL hostname */ - *tl++ = txdr_unsigned(cr->cr_uid); - *tl++ = txdr_unsigned(cr->cr_groups[0]); - grpsiz = (auth_len >> 2) - 5; - *tl++ = txdr_unsigned(grpsiz); - for (i = 1; i <= grpsiz; i++) - *tl++ = txdr_unsigned(cr->cr_groups[i]); - break; - } - - /* - * And the verifier... - */ - tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(RPCAUTH_NULL); - *tl = 0; - mb->m_next = mrest; - mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; - mreq->m_pkthdr.rcvif = NULL; - *mbp = mb; - return (mreq); -} - -/* * copies a uio scatter/gather list to an mbuf chain. * NOTE: can ony handle iovcnt == 1 */ @@ -427,14 +339,6 @@ nfs_init(struct vfsconf *vfsp) nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - rpc_vers = txdr_unsigned(RPC_VER2); - rpc_call = txdr_unsigned(RPC_CALL); - rpc_reply = txdr_unsigned(RPC_REPLY); - rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); - rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); - rpc_mismatch = txdr_unsigned(RPC_MISMATCH); - rpc_autherr = txdr_unsigned(RPC_AUTHERR); - rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); nfs_true = txdr_unsigned(TRUE); nfs_false = txdr_unsigned(FALSE); nfs_xdrneg1 = txdr_unsigned(-1); @@ -451,11 +355,6 @@ nfs_init(struct vfsconf *vfsp) /* * Initialize reply list and start timer */ -#ifdef NFS_LEGACYRPC - TAILQ_INIT(&nfs_reqq); - mtx_init(&nfs_reqq_mtx, "NFS reqq lock", NULL, MTX_DEF); - callout_init(&nfs_callout, CALLOUT_MPSAFE); -#endif mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF); @@ -469,13 +368,6 @@ nfs_uninit(struct vfsconf *vfsp) { int i; -#ifdef NFS_LEGACYRPC - callout_stop(&nfs_callout); - - KASSERT(TAILQ_EMPTY(&nfs_reqq), - ("nfs_uninit: request queue not empty")); -#endif - /* * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup * any sleeping nfsiods so they check nfs_iodmax and exit. diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index 6a28eab..599aea0 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$"); #include <rpc/rpc.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsnode.h> @@ -142,9 +141,7 @@ VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_VERSION(nfs, 1); -#ifndef NFS_LEGACYRPC MODULE_DEPEND(nfs, krpc, 1, 1, 1); -#endif #ifdef KGSSAPI MODULE_DEPEND(nfs, kgssapi, 1, 1, 1); #endif @@ -551,7 +548,6 @@ nfs_mountdiskless(char *path, return (0); } -#ifndef NFS_LEGACYRPC static int nfs_sec_name_to_num(char *sec) { @@ -569,7 +565,6 @@ nfs_sec_name_to_num(char *sec) */ return (AUTH_SYS); } -#endif static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, @@ -579,10 +574,8 @@ nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, int adjsock; int maxio; char *p; -#ifndef NFS_LEGACYRPC char *secname; char *principal; -#endif s = splnet(); @@ -734,13 +727,7 @@ nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, nmp->nm_sotype = argp->sotype; nmp->nm_soproto = argp->proto; - if ( -#ifdef NFS_LEGACYRPC - nmp->nm_so -#else - nmp->nm_client -#endif - && adjsock) { + if (nmp->nm_client && adjsock) { nfs_safedisconnect(nmp); if (nmp->nm_sotype == SOCK_DGRAM) while (nfs_connect(nmp, NULL)) { @@ -757,7 +744,6 @@ nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, *p = '\0'; } -#ifndef NFS_LEGACYRPC if (vfs_getopt(mp->mnt_optnew, "sec", (void **) &secname, NULL) == 0) { nmp->nm_secflavor = nfs_sec_name_to_num(secname); @@ -773,7 +759,6 @@ nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, snprintf(nmp->nm_principal, sizeof(nmp->nm_principal), "nfs@%s", nmp->nm_hostname); } -#endif } static const char *nfs_opts[] = { "from", "nfs_args", diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index bc6936d..e557321 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -70,7 +70,6 @@ __FBSDID("$FreeBSD$"); #include <fs/fifofs/fifo.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsclient/nfs.h> #include <nfsclient/nfsnode.h> @@ -3193,7 +3192,7 @@ loop: &np->n_mtx, slpflag | (PRIBIO + 1), "nfsfsync", 0); if (error) { - if (nfs_sigintr(nmp, (struct nfsreq *)0, td)) { + if (nfs_sigintr(nmp, NULL, td)) { mtx_unlock(&np->n_mtx); error = EINTR; goto done; diff --git a/sys/nfsclient/nfsm_subs.h b/sys/nfsclient/nfsm_subs.h index 51d2611..583aec1 100644 --- a/sys/nfsclient/nfsm_subs.h +++ b/sys/nfsclient/nfsm_subs.h @@ -54,10 +54,6 @@ struct vnode; */ u_int32_t nfs_xid_gen(void); struct mbuf *nfsm_reqhead(struct vnode *vp, u_long procid, int hsiz); -struct mbuf *nfsm_rpchead(struct ucred *cr, int nmflag, int procid, - int auth_type, int auth_len, - struct mbuf *mrest, int mrest_len, - struct mbuf **mbp, u_int32_t **xidpp); #define M_HASCL(m) ((m)->m_flags & M_EXT) #define NFSMINOFF(m) \ diff --git a/sys/nfsclient/nfsmount.h b/sys/nfsclient/nfsmount.h index 85f8501..99d12d9 100644 --- a/sys/nfsclient/nfsmount.h +++ b/sys/nfsclient/nfsmount.h @@ -36,36 +36,11 @@ #ifndef _NFSCLIENT_NFSMOUNT_H_ #define _NFSCLIENT_NFSMOUNT_H_ -#ifndef NFS_LEGACYRPC - -#undef RPC_SUCCESS -#undef RPC_PROGUNAVAIL -#undef RPC_PROCUNAVAIL -#undef AUTH_OK -#undef AUTH_BADCRED -#undef AUTH_BADVERF -#undef AUTH_TOOWEAK - #include <rpc/types.h> #include <rpc/auth.h> #include <rpc/clnt.h> #include <rpc/rpcsec_gss.h> -#endif - -#ifdef NFS_LEGACYRPC - -struct nfs_tcp_mountstate { - int rpcresid; -#define NFS_TCP_EXPECT_RPCMARKER 0x0001 /* Expect to see a RPC/TCP marker next */ -#define NFS_TCP_FORCE_RECONNECT 0x0002 /* Force a TCP reconnect */ -#define NFS_TCP_WAIT_WRITE_DRAIN 0x0004 /* Waiting for socket writers to finish */ - int flags; - int sock_send_inprog; -}; - -#endif - /* * Mount structure. * One allocated on every NFS mount. @@ -79,22 +54,12 @@ struct nfsmount { int nm_numgrps; /* Max. size of groupslist */ u_char nm_fh[NFSX_V4FH]; /* File handle of root dir */ int nm_fhsize; /* Size of root file handle */ -#ifdef NFS_LEGACYRPC - struct socket *nm_so; /* Rpc socket */ -#endif int nm_sotype; /* Type of socket */ int nm_soproto; /* and protocol */ int nm_soflags; /* pr_flags for socket protocol */ struct sockaddr *nm_nam; /* Addr of server */ int nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */ int nm_retry; /* Max retries */ -#ifdef NFS_LEGACYRPC - int nm_srtt[NFS_MAX_TIMER], /* RTT Timers for rpcs */ - nm_sdrtt[NFS_MAX_TIMER]; - int nm_sent; /* Request send count */ - int nm_cwnd; /* Request send window */ - int nm_timeouts; /* Request timeouts */ -#endif int nm_deadthresh; /* Threshold of timeouts-->dead server*/ int nm_rsize; /* Max size of read rpc */ int nm_wsize; /* Max size of write rpc */ @@ -114,17 +79,12 @@ struct nfsmount { struct nfs_rpcops *nm_rpcops; int nm_tprintf_initial_delay; /* initial delay */ int nm_tprintf_delay; /* interval for messages */ -#ifdef NFS_LEGACYRPC - struct nfs_tcp_mountstate nm_nfstcpstate; -#endif char nm_hostname[MNAMELEN]; /* server's name */ -#ifndef NFS_LEGACYRPC int nm_secflavor; /* auth flavor to use for rpc */ struct __rpc_client *nm_client; struct rpc_timers nm_timers[NFS_MAX_TIMER]; /* RTT Timers for rpcs */ char nm_principal[MNAMELEN]; /* GSS-API principal of server */ gss_OID nm_mech_oid; /* OID of selected GSS-API mechanism */ -#endif /* NFSv4 */ uint64_t nm_clientid; diff --git a/sys/nfsserver/nfs.h b/sys/nfsserver/nfs.h index 25fe8ae..b907a06 100644 --- a/sys/nfsserver/nfs.h +++ b/sys/nfsserver/nfs.h @@ -176,102 +176,6 @@ extern int32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd, #define NWDELAYHASH(sock, f) \ (&(sock)->ns_wdelayhashtbl[(*((u_int32_t *)(f))) % NFS_WDELAYHASHSIZ]) -#ifdef NFS_LEGACYRPC -/* - * Network address hash list element - */ -union nethostaddr { - u_int32_t had_inetaddr; - struct sockaddr *had_nam; -}; - -struct nfsrv_rec { - STAILQ_ENTRY(nfsrv_rec) nr_link; - struct sockaddr *nr_address; - struct mbuf *nr_packet; -}; - -struct nfssvc_sock { - TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */ - struct file *ns_fp; - struct socket *ns_so; - struct sockaddr *ns_nam; - struct mbuf *ns_raw; - struct mbuf *ns_rawend; - STAILQ_HEAD(, nfsrv_rec) ns_rec; - struct mbuf *ns_frag; - int ns_flag; - int ns_solock; - int ns_cc; - int ns_reclen; - u_int32_t ns_sref; - LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */ - LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ]; -}; - -/* Bits for "ns_flag" */ -#define SLP_VALID 0x01 /* Socket valid for use (XXX) */ -#define SLP_DOREC 0x02 /* Socket ready for processing */ -#define SLP_NEEDQ 0x04 /* Socket has request queued */ -#define SLP_DISCONN 0x08 /* Error received from stream socket */ -#define SLP_GETSTREAM 0x10 /* nfsrv_getstream in prog on sock */ -#define SLP_LASTFRAG 0x20 /* Socket received end-of-record */ -#define SLP_ALLFLAGS 0xff - -extern TAILQ_HEAD(nfssvc_sockhead, nfssvc_sock) nfssvc_sockhead; -extern int nfssvc_sockhead_flag; -#define SLP_INIT 0x01 -#define SLP_WANTINIT 0x02 - -/* - * One of these structures is allocated for each nfsd. - */ -struct nfsd { - TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */ - int nfsd_flag; /* NFSD_ flags */ - struct nfssvc_sock *nfsd_slp; /* Current socket */ - int nfsd_authlen; /* Authenticator len */ - u_char nfsd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */ - int nfsd_verflen; /* and the Verifier */ - u_char nfsd_verfstr[RPCVERF_MAXSIZ]; - struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */ -}; - -/* Bits for "nfsd_flag" */ -#define NFSD_WAITING 0x01 -#define NFSD_REQINPROG 0x02 - -/* - * This structure is used by the server for describing each request. - * Some fields are used only when write request gathering is performed. - */ -struct nfsrv_descript { - u_quad_t nd_time; /* Write deadline (usec) */ - off_t nd_off; /* Start byte offset */ - off_t nd_eoff; /* and end byte offset */ - LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */ - LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */ - LIST_HEAD(, nfsrv_descript) nd_coalesce;/* coalesced writes */ - struct mbuf *nd_mrep; /* Request mbuf list */ - struct mbuf *nd_md; /* Current dissect mbuf */ - struct mbuf *nd_mreq; /* Reply mbuf list */ - struct sockaddr *nd_nam; /* and socket addr */ - struct sockaddr *nd_nam2; /* return socket addr */ - caddr_t nd_dpos; /* Current dissect pos */ - u_int32_t nd_procnum; /* RPC # */ - int nd_stable; /* storage type */ - int nd_flag; /* nd_flag */ - int nd_len; /* Length of this write */ - int nd_repstat; /* Reply status */ - u_int32_t nd_retxid; /* Reply xid */ - struct timeval nd_starttime; /* Time RPC initiated */ - fhandle_t nd_fh; /* File handle */ - struct ucred *nd_cr; /* Credentials */ - int nd_credflavor; /* Security flavor */ -}; - -#else - /* * This structure is used by the server for describing each request. */ @@ -291,26 +195,9 @@ struct nfsrv_descript { int nd_credflavor; /* Security flavor */ }; -#endif - /* Bits for "nd_flag" */ #define ND_NFSV3 0x08 -#ifdef NFS_LEGACYRPC - -extern TAILQ_HEAD(nfsd_head, nfsd) nfsd_head; -extern int nfsd_head_flag; -#define NFSD_CHECKSLP 0x01 - -/* - * These macros compare nfsrv_descript structures. - */ -#define NFSW_CONTIG(o, n) \ - ((o)->nd_eoff >= (n)->nd_off && \ - !bcmp((caddr_t)&(o)->nd_fh, (caddr_t)&(n)->nd_fh, NFSX_V3FH)) - -#endif - /* * Defines for WebNFS */ @@ -353,26 +240,6 @@ extern int nfs_debug; #endif -#ifdef NFS_LEGACYRPC -int netaddr_match(int, union nethostaddr *, struct sockaddr *); -int nfs_getreq(struct nfsrv_descript *, struct nfsd *, int); -int nfsrv_send(struct socket *, struct sockaddr *, struct mbuf *); -int nfsrv_dorec(struct nfssvc_sock *, struct nfsd *, - struct nfsrv_descript **); -int nfs_slplock(struct nfssvc_sock *, int); -void nfs_slpunlock(struct nfssvc_sock *); -void nfsrv_initcache(void); -void nfsrv_destroycache(void); -void nfsrv_timer(void *); -int nfsrv_getcache(struct nfsrv_descript *, struct mbuf **); -void nfsrv_updatecache(struct nfsrv_descript *, int, struct mbuf *); -void nfsrv_cleancache(void); -int nfsrv_rcv(struct socket *so, void *arg, int waitflag); -void nfsrv_slpderef(struct nfssvc_sock *slp); -void nfsrv_wakenfsd(struct nfssvc_sock *slp); -int nfsrv_writegather(struct nfsrv_descript **, struct nfssvc_sock *, - struct mbuf **); -#endif struct mbuf *nfs_rephead(int, struct nfsrv_descript *, int, struct mbuf **, caddr_t *); void nfsm_srvfattr(struct nfsrv_descript *, struct vattr *, diff --git a/sys/nfsserver/nfs_fha.c b/sys/nfsserver/nfs_fha.c index 27dc9b3..901a0ce 100644 --- a/sys/nfsserver/nfs_fha.c +++ b/sys/nfsserver/nfs_fha.c @@ -39,14 +39,11 @@ __FBSDID("$FreeBSD$"); #include <rpc/rpc.h> #include <nfs/xdr_subs.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsserver/nfs.h> #include <nfsserver/nfsm_subs.h> #include <nfsserver/nfs_fha.h> -#ifndef NFS_LEGACYRPC - static MALLOC_DEFINE(M_NFS_FHA, "NFS FHA", "NFS FHA"); /* Sysctl defaults. */ @@ -598,5 +595,3 @@ fhe_stats_sysctl(SYSCTL_HANDLER_ARGS) sbuf_delete(&sb); return (error); } - -#endif /* !NFS_LEGACYRPC */ diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index b6a61a8..00be15e 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -93,7 +93,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <nfs/nfsproto.h> -#include <nfs/rpcv2.h> #include <nfsserver/nfs.h> #include <nfs/xdr_subs.h> #include <nfsserver/nfsm_subs.h> @@ -142,10 +141,6 @@ SYSCTL_STRUCT(_vfs_nfsrv, NFS_NFSRVSTATS, nfsrvstats, CTLFLAG_RW, static int nfsrv_access(struct vnode *, accmode_t, struct ucred *, int, int); -#ifdef NFS_LEGACYRPC -static void nfsrvw_coalesce(struct nfsrv_descript *, - struct nfsrv_descript *); -#endif /* * Clear nameidata fields that are tested in nsfmout cleanup code prior @@ -1229,425 +1224,6 @@ nfsmout: return(error); } -#ifdef NFS_LEGACYRPC - -/* - * XXX dfr - write gathering isn't supported by the new RPC code since - * its really only useful for NFSv2. If there is a real need, we could - * attempt to fit it into the filehandle affinity system, e.g. by - * looking to see if there are queued write requests that overlap this - * one. - */ - -/* - * For the purposes of write gathering, we must decide if the credential - * associated with two pending requests have equivilent privileges. Since - * NFS only uses a subset of the BSD ucred -- the effective uid and group - * IDs -- we have a compare routine that checks only the relevant fields. - */ -static int -nfsrv_samecred(struct ucred *cr1, struct ucred *cr2) -{ - int i; - - if (cr1->cr_uid != cr2->cr_uid) - return (0); - if (cr1->cr_ngroups != cr2->cr_ngroups) - return (0); - for (i = 0; i < cr1->cr_ngroups; i++) { - if (cr1->cr_groups[i] != cr2->cr_groups[i]) - return (0); - } - return (1); -} - -/* - * NFS write service with write gathering support. Called when - * nfsrvw_procrastinate > 0. - * See: Chet Juszczak, "Improving the Write Performance of an NFS Server", - * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco, - * Jan. 1994. - */ -int -nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp, - struct mbuf **mrq) -{ - struct iovec *ivp; - struct mbuf *mp; - struct nfsrv_descript *wp, *nfsd, *owp, *swp; - struct nfs_fattr *fp; - int i; - struct iovec *iov; - struct nfsrvw_delayhash *wpp; - struct ucred *cred; - struct vattr va, forat; - u_int32_t *tl; - caddr_t bpos, dpos; - int error = 0, rdonly, len, forat_ret = 1; - int ioflags, aftat_ret = 1, s, adjust, v3, zeroing; - struct mbuf *mb, *mreq, *mrep, *md; - struct vnode *vp = NULL; - struct uio io, *uiop = &io; - u_quad_t cur_usec; - struct mount *mntp = NULL; - int mvfslocked; - int vfslocked; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - i = 0; - len = 0; -#endif - vfslocked = 0; - *mrq = NULL; - if (*ndp) { - nfsd = *ndp; - *ndp = NULL; - mrep = nfsd->nd_mrep; - md = nfsd->nd_md; - dpos = nfsd->nd_dpos; - cred = nfsd->nd_cr; - v3 = (nfsd->nd_flag & ND_NFSV3); - LIST_INIT(&nfsd->nd_coalesce); - nfsd->nd_mreq = NULL; - nfsd->nd_stable = NFSV3WRITE_FILESYNC; - cur_usec = nfs_curusec(); - nfsd->nd_time = cur_usec + - (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate); - - /* - * Now, get the write header.. - */ - nfsm_srvmtofh(&nfsd->nd_fh); - if (v3) { - tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED); - nfsd->nd_off = fxdr_hyper(tl); - tl += 3; - nfsd->nd_stable = fxdr_unsigned(int, *tl++); - } else { - tl = nfsm_dissect_nonblock(u_int32_t *, 4 * NFSX_UNSIGNED); - nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl); - tl += 2; - if (nfs_async) - nfsd->nd_stable = NFSV3WRITE_UNSTABLE; - } - len = fxdr_unsigned(int32_t, *tl); - nfsd->nd_len = len; - nfsd->nd_eoff = nfsd->nd_off + len; - - /* - * Trim the header out of the mbuf list and trim off any trailing - * junk so that the mbuf list has only the write data. - */ - zeroing = 1; - i = 0; - mp = mrep; - while (mp) { - if (mp == md) { - zeroing = 0; - adjust = dpos - mtod(mp, caddr_t); - mp->m_len -= adjust; - if (mp->m_len > 0 && adjust > 0) - mp->m_data += adjust; - } - if (zeroing) - mp->m_len = 0; - else { - i += mp->m_len; - if (i > len) { - mp->m_len -= (i - len); - zeroing = 1; - } - } - mp = mp->m_next; - } - if (len > NFS_MAXDATA || len < 0 || i < len) { -nfsmout: - m_freem(mrep); - error = EIO; - nfsm_writereply(2 * NFSX_UNSIGNED); - if (v3) - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - nfsd->nd_mreq = mreq; - nfsd->nd_mrep = NULL; - nfsd->nd_time = 0; - } - - /* - * Add this entry to the hash and time queues. - */ - s = splsoftclock(); - owp = NULL; - wp = LIST_FIRST(&slp->ns_tq); - while (wp && wp->nd_time < nfsd->nd_time) { - owp = wp; - wp = LIST_NEXT(wp, nd_tq); - } - NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff)); - if (owp) { - LIST_INSERT_AFTER(owp, nfsd, nd_tq); - } else { - LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); - } - if (nfsd->nd_mrep) { - wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data); - owp = NULL; - wp = LIST_FIRST(wpp); - while (wp && - bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh, NFSX_V3FH)){ - owp = wp; - wp = LIST_NEXT(wp, nd_hash); - } - while (wp && wp->nd_off < nfsd->nd_off && - !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh, NFSX_V3FH)) { - owp = wp; - wp = LIST_NEXT(wp, nd_hash); - } - if (owp) { - LIST_INSERT_AFTER(owp, nfsd, nd_hash); - - /* - * Search the hash list for overlapping entries and - * coalesce. - */ - for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) { - wp = LIST_NEXT(nfsd, nd_hash); - if (nfsrv_samecred(owp->nd_cr, nfsd->nd_cr)) - nfsrvw_coalesce(owp, nfsd); - } - } else { - LIST_INSERT_HEAD(wpp, nfsd, nd_hash); - } - } - splx(s); - } - - /* - * Now, do VOP_WRITE()s for any one(s) that need to be done now - * and generate the associated reply mbuf list(s). - */ -loop1: - cur_usec = nfs_curusec(); - s = splsoftclock(); - for (nfsd = LIST_FIRST(&slp->ns_tq); nfsd; nfsd = owp) { - owp = LIST_NEXT(nfsd, nd_tq); - if (nfsd->nd_time > cur_usec) - break; - if (nfsd->nd_mreq) - continue; - NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff)); - LIST_REMOVE(nfsd, nd_tq); - LIST_REMOVE(nfsd, nd_hash); - splx(s); - mrep = nfsd->nd_mrep; - nfsd->nd_mrep = NULL; - cred = nfsd->nd_cr; - v3 = (nfsd->nd_flag & ND_NFSV3); - forat_ret = aftat_ret = 1; - error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, &vfslocked, nfsd, - slp, nfsd->nd_nam, &rdonly, TRUE); - if (!error) { - if (v3) - forat_ret = VOP_GETATTR(vp, &forat, cred); - if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - } - } else { - vp = NULL; - } - if (!error) - error = nfsrv_access(vp, VWRITE, cred, rdonly, 1); - if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) - ioflags = IO_NODELOCKED; - else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) - ioflags = (IO_SYNC | IO_NODELOCKED); - else - ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); - uiop->uio_rw = UIO_WRITE; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_td = NULL; - uiop->uio_offset = nfsd->nd_off; - uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; - if (uiop->uio_resid > 0) { - mp = mrep; - i = 0; - while (mp) { - if (mp->m_len > 0) - i++; - mp = mp->m_next; - } - uiop->uio_iovcnt = i; - iov = malloc(i * sizeof (struct iovec), - M_TEMP, M_WAITOK); - uiop->uio_iov = ivp = iov; - mp = mrep; - while (mp) { - if (mp->m_len > 0) { - ivp->iov_base = mtod(mp, caddr_t); - ivp->iov_len = mp->m_len; - ivp++; - } - mp = mp->m_next; - } - mvfslocked = 0; - if (!error) { - if (vn_start_write(vp, &mntp, V_NOWAIT) != 0) { - VOP_UNLOCK(vp, 0); - error = vn_start_write(NULL, &mntp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - } - mvfslocked = VFS_LOCK_GIANT(mntp); - } - if (!error) { - error = VOP_WRITE(vp, uiop, ioflags, cred); - /* Unlocked write. */ - nfsrvstats.srvvop_writes++; - vn_finished_write(mntp); - } - VFS_UNLOCK_GIANT(mvfslocked); - free((caddr_t)iov, M_TEMP); - } - m_freem(mrep); - if (vp) { - aftat_ret = VOP_GETATTR(vp, &va, cred); - vput(vp); - vp = NULL; - } - VFS_UNLOCK_GIANT(vfslocked); - /* - * Loop around generating replies for all write rpcs that have - * now been completed. - */ - swp = nfsd; - do { - NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff)); - if (error) { - nfsm_writereply(NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - } - } else { - nfsm_writereply(NFSX_PREOPATTR(v3) + - NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + - NFSX_WRITEVERF(v3)); - if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - tl = nfsm_build(u_int32_t *, 4 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nfsd->nd_len); - *tl++ = txdr_unsigned(swp->nd_stable); - /* - * Actually, there is no need to txdr these fields, - * but it may make the values more human readable, - * for debugging purposes. - */ - if (nfsver.tv_sec == 0) - nfsver = boottime; - *tl++ = txdr_unsigned(nfsver.tv_sec); - *tl = txdr_unsigned(nfsver.tv_usec); - } else { - fp = nfsm_build(struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(&va, fp); - } - } - nfsd->nd_mreq = mreq; - if (nfsd->nd_mrep) - panic("nfsrv_write: nd_mrep not free"); - - /* - * Done. Put it at the head of the timer queue so that - * the final phase can return the reply. - */ - s = splsoftclock(); - if (nfsd != swp) { - nfsd->nd_time = 0; - LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); - } - nfsd = LIST_FIRST(&swp->nd_coalesce); - if (nfsd) { - LIST_REMOVE(nfsd, nd_tq); - } - splx(s); - } while (nfsd); - s = splsoftclock(); - swp->nd_time = 0; - LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq); - splx(s); - goto loop1; - } - splx(s); - - /* - * Search for a reply to return. - */ - s = splsoftclock(); - LIST_FOREACH(nfsd, &slp->ns_tq, nd_tq) - if (nfsd->nd_mreq) { - NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff)); - LIST_REMOVE(nfsd, nd_tq); - *mrq = nfsd->nd_mreq; - *ndp = nfsd; - break; - } - splx(s); - return (0); -} - -/* - * Coalesce the write request nfsd into owp. To do this we must: - * - remove nfsd from the queues - * - merge nfsd->nd_mrep into owp->nd_mrep - * - update the nd_eoff and nd_stable for owp - * - put nfsd on owp's nd_coalesce list - * NB: Must be called at splsoftclock(). - */ -static void -nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd) -{ - int overlap; - struct mbuf *mp; - struct nfsrv_descript *p; - - NFS_DPF(WG, ("C%03x-%03x", - nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff)); - LIST_REMOVE(nfsd, nd_hash); - LIST_REMOVE(nfsd, nd_tq); - if (owp->nd_eoff < nfsd->nd_eoff) { - overlap = owp->nd_eoff - nfsd->nd_off; - if (overlap < 0) - panic("nfsrv_coalesce: bad off"); - if (overlap > 0) - m_adj(nfsd->nd_mrep, overlap); - mp = owp->nd_mrep; - while (mp->m_next) - mp = mp->m_next; - mp->m_next = nfsd->nd_mrep; - owp->nd_eoff = nfsd->nd_eoff; - } else - m_freem(nfsd->nd_mrep); - nfsd->nd_mrep = NULL; - if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) - owp->nd_stable = NFSV3WRITE_FILESYNC; - else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && - owp->nd_stable == NFSV3WRITE_UNSTABLE) - owp->nd_stable = NFSV3WRITE_DATASYNC; - LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq); - - /* - * If nfsd had anything else coalesced into it, transfer them - * to owp, otherwise their replies will never get sent. - */ - for (p = LIST_FIRST(&nfsd->nd_coalesce); p; - p = LIST_FIRST(&nfsd->nd_coalesce)) { - LIST_REMOVE(p, nd_tq); - LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq); - } -} - -#endif - /* * nfs create service * now does a truncate to 0 length via. setattr if it already exists diff --git a/sys/nfsserver/nfs_srvcache.c b/sys/nfsserver/nfs_srvcache.c deleted file mode 100644 index 5121690..0000000 --- a/sys/nfsserver/nfs_srvcache.c +++ /dev/null @@ -1,391 +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_srvcache.c 8.3 (Berkeley) 3/30/95 - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * Reference: Chet Juszczak, "Improving the Performance and Correctness - * of an NFS Server", in Proc. Winter 1989 USENIX Conference, - * pages 53-63. San Diego, February 1989. - */ -#include <sys/param.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/systm.h> -#include <sys/lock.h> -#include <sys/mbuf.h> -#include <sys/mutex.h> -#include <sys/socket.h> -#include <sys/socketvar.h> /* for sodupsockaddr */ -#include <sys/eventhandler.h> - -#include <netinet/in.h> -#include <nfs/rpcv2.h> -#include <nfs/nfsproto.h> -#include <nfsserver/nfs.h> -#include <nfsserver/nfsrvcache.h> - -#ifdef NFS_LEGACYRPC - -static long numnfsrvcache; -static long desirednfsrvcache; - -#define NFSRCHASH(xid) \ - (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash]) -static LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl; -static TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead; -static u_long nfsrvhash; -static eventhandler_tag nfsrv_nmbclusters_tag; - -#define TRUE 1 -#define FALSE 0 - -#define NETFAMILY(rp) \ - (((rp)->rc_flag & RC_NAM) ? (rp)->rc_nam->sa_family : AF_INET) - -/* - * Static array that defines which nfs rpc's are nonidempotent - */ -static const int nonidempotent[NFS_NPROCS] = { - FALSE, - FALSE, - TRUE, - FALSE, - FALSE, - FALSE, - FALSE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, -}; - -/* True iff the rpc reply is an nfs status ONLY! */ -static const int nfsv2_repstat[NFS_NPROCS] = { - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - TRUE, - TRUE, - TRUE, - TRUE, - FALSE, - TRUE, - FALSE, - FALSE, -}; - -/* - * Size the NFS server's duplicate request cache at 1/2 the nmbclsters, 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 void -nfsrvcache_size_change(void *tag) -{ - desirednfsrvcache = nmbclusters /2; - if (desirednfsrvcache > NFSRVCACHE_MAX_SIZE) - desirednfsrvcache = NFSRVCACHE_MAX_SIZE; - if (desirednfsrvcache < NFSRVCACHE_MIN_SIZE) - desirednfsrvcache = NFSRVCACHE_MIN_SIZE; -} - -/* - * Initialize the server request cache list - */ -void -nfsrv_initcache(void) -{ - nfsrvcache_size_change(NULL); - nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash); - TAILQ_INIT(&nfsrvlruhead); - nfsrv_nmbclusters_tag = EVENTHANDLER_REGISTER(nmbclusters_change, - nfsrvcache_size_change, NULL, EVENTHANDLER_PRI_FIRST); -} - -/* - * Teardown the server request cache list - */ -void -nfsrv_destroycache(void) -{ - KASSERT(TAILQ_EMPTY(&nfsrvlruhead), ("%s: pending requests", __func__)); - EVENTHANDLER_DEREGISTER(nmbclusters_change, nfsrv_nmbclusters_tag); - hashdestroy(nfsrvhashtbl, M_NFSD, nfsrvhash); -} - -/* - * Look for the request in the cache - * If found then - * return action and optionally reply - * else - * insert it in the cache - * - * The rules are as follows: - * - if in progress, return DROP request - * - if completed within DELAY of the current time, return DROP it - * - if completed a longer time ago return REPLY if the reply was cached or - * return DOIT - * Update/add new request at end of lru list - */ -int -nfsrv_getcache(struct nfsrv_descript *nd, struct mbuf **repp) -{ - struct nfsrvcache *rp; - struct mbuf *mb; - struct sockaddr_in *saddr; - caddr_t bpos; - int ret; - - NFSD_LOCK_ASSERT(); - - /* - * Don't cache recent requests for reliable transport protocols. - * (Maybe we should for the case of a reconnect, but..) - */ - if (!nd->nd_nam2) - return (RC_DOIT); -loop: - LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) { - if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc && - netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) { - NFS_DPF(RC, ("H%03x", rp->rc_xid & 0xfff)); - if ((rp->rc_flag & RC_LOCKED) != 0) { - rp->rc_flag |= RC_WANTED; - (void) msleep(rp, &nfsd_mtx, PZERO-1, - "nfsrc", 0); - goto loop; - } - rp->rc_flag |= RC_LOCKED; - /* If not at end of LRU chain, move it there */ - if (TAILQ_NEXT(rp, rc_lru)) { - TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); - TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru); - } - if (rp->rc_state == RC_UNUSED) - panic("nfsrv cache"); - if (rp->rc_state == RC_INPROG) { - nfsrvstats.srvcache_inproghits++; - ret = RC_DROPIT; - } else if (rp->rc_flag & RC_REPSTATUS) { - nfsrvstats.srvcache_nonidemdonehits++; - NFSD_UNLOCK(); - *repp = nfs_rephead(0, nd, rp->rc_status, - &mb, &bpos); - ret = RC_REPLY; - NFSD_LOCK(); - } else if (rp->rc_flag & RC_REPMBUF) { - nfsrvstats.srvcache_nonidemdonehits++; - NFSD_UNLOCK(); - *repp = m_copym(rp->rc_reply, 0, M_COPYALL, - M_WAIT); - NFSD_LOCK(); - ret = RC_REPLY; - } else { - nfsrvstats.srvcache_idemdonehits++; - rp->rc_state = RC_INPROG; - ret = RC_DOIT; - } - rp->rc_flag &= ~RC_LOCKED; - if (rp->rc_flag & RC_WANTED) { - rp->rc_flag &= ~RC_WANTED; - wakeup(rp); - } - return (ret); - } - } - nfsrvstats.srvcache_misses++; - NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff)); - if (numnfsrvcache < desirednfsrvcache) { - NFSD_UNLOCK(); - rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp, - M_NFSD, M_WAITOK | M_ZERO); - NFSD_LOCK(); - numnfsrvcache++; - rp->rc_flag = RC_LOCKED; - } else { - rp = TAILQ_FIRST(&nfsrvlruhead); - while ((rp->rc_flag & RC_LOCKED) != 0) { - rp->rc_flag |= RC_WANTED; - (void) msleep(rp, &nfsd_mtx, PZERO-1, "nfsrc", 0); - rp = TAILQ_FIRST(&nfsrvlruhead); - } - rp->rc_flag |= RC_LOCKED; - LIST_REMOVE(rp, rc_hash); - TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); - if (rp->rc_flag & RC_REPMBUF) - m_freem(rp->rc_reply); - if (rp->rc_flag & RC_NAM) - free(rp->rc_nam, M_SONAME); - rp->rc_flag &= (RC_LOCKED | RC_WANTED); - } - TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru); - rp->rc_state = RC_INPROG; - rp->rc_xid = nd->nd_retxid; - saddr = (struct sockaddr_in *)nd->nd_nam; - switch (saddr->sin_family) { - case AF_INET: - rp->rc_flag |= RC_INETADDR; - rp->rc_inetaddr = saddr->sin_addr.s_addr; - break; -/* case AF_INET6: */ -/* case AF_ISO: */ - default: - /* - * XXXRW: Seems like we should only set RC_NAM if we - * actually manage to set rc_nam to something non-NULL. - */ - rp->rc_flag |= RC_NAM; - rp->rc_nam = sodupsockaddr(nd->nd_nam, M_NOWAIT); - break; - }; - rp->rc_proc = nd->nd_procnum; - LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash); - rp->rc_flag &= ~RC_LOCKED; - if (rp->rc_flag & RC_WANTED) { - rp->rc_flag &= ~RC_WANTED; - wakeup(rp); - } - return (RC_DOIT); -} - -/* - * Update a request cache entry after the rpc has been done - */ -void -nfsrv_updatecache(struct nfsrv_descript *nd, int repvalid, struct mbuf *repmbuf) -{ - struct nfsrvcache *rp; - - NFSD_LOCK_ASSERT(); - - if (!nd->nd_nam2) - return; -loop: - LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) { - if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc && - netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) { - NFS_DPF(RC, ("U%03x", rp->rc_xid & 0xfff)); - if ((rp->rc_flag & RC_LOCKED) != 0) { - rp->rc_flag |= RC_WANTED; - (void) msleep(rp, &nfsd_mtx, PZERO-1, - "nfsrc", 0); - goto loop; - } - rp->rc_flag |= RC_LOCKED; - if (rp->rc_state == RC_DONE) { - /* - * This can occur if the cache is too small. - * Retransmits of the same request aren't - * dropped so we may see the operation - * complete more then once. - */ - if (rp->rc_flag & RC_REPMBUF) { - m_freem(rp->rc_reply); - rp->rc_flag &= ~RC_REPMBUF; - } - } - rp->rc_state = RC_DONE; - /* - * If we have a valid reply update status and save - * the reply for non-idempotent rpc's. - */ - if (repvalid && nonidempotent[nd->nd_procnum]) { - if ((nd->nd_flag & ND_NFSV3) == 0 && - nfsv2_repstat[ - nfsrvv2_procid[nd->nd_procnum]]) { - rp->rc_status = nd->nd_repstat; - rp->rc_flag |= RC_REPSTATUS; - } else { - NFSD_UNLOCK(); - rp->rc_reply = m_copym(repmbuf, - 0, M_COPYALL, M_WAIT); - NFSD_LOCK(); - rp->rc_flag |= RC_REPMBUF; - } - } - rp->rc_flag &= ~RC_LOCKED; - if (rp->rc_flag & RC_WANTED) { - rp->rc_flag &= ~RC_WANTED; - wakeup(rp); - } - return; - } - } - NFS_DPF(RC, ("L%03x", nd->nd_retxid & 0xfff)); -} - -/* - * Clean out the cache. Called when the last nfsd terminates. - */ -void -nfsrv_cleancache(void) -{ - struct nfsrvcache *rp, *nextrp; - - NFSD_LOCK_ASSERT(); - - TAILQ_FOREACH_SAFE(rp, &nfsrvlruhead, rc_lru, nextrp) { - LIST_REMOVE(rp, rc_hash); - TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); - if (rp->rc_flag & RC_REPMBUF) - m_freem(rp->rc_reply); - if (rp->rc_flag & RC_NAM) - free(rp->rc_nam, M_SONAME); - free(rp, M_NFSD); - } - numnfsrvcache = 0; -} - -#endif /* NFS_LEGACYRPC */ diff --git a/sys/nfsserver/nfs_srvkrpc.c b/sys/nfsserver/nfs_srvkrpc.c index 99edac5..54b1c4a 100644 --- a/sys/nfsserver/nfs_srvkrpc.c +++ b/sys/nfsserver/nfs_srvkrpc.c @@ -75,7 +75,6 @@ __FBSDID("$FreeBSD$"); #include <rpc/replay.h> #include <nfs/xdr_subs.h> -#include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfsserver/nfs.h> #include <nfsserver/nfsm_subs.h> @@ -84,8 +83,6 @@ __FBSDID("$FreeBSD$"); #include <security/mac/mac_framework.h> -#ifndef NFS_LEGACYRPC - static MALLOC_DEFINE(M_NFSSVC, "nfss_srvsock", "Nfs server structure"); MALLOC_DEFINE(M_NFSRVDESC, "nfss_srvdesc", "NFS server socket descriptor"); @@ -607,5 +604,3 @@ nfsrv_init(int terminating) NFSD_LOCK(); } - -#endif /* !NFS_LEGACYRPC */ diff --git a/sys/nfsserver/nfs_srvsock.c b/sys/nfsserver/nfs_srvsock.c deleted file mode 100644 index b5c3fa2..0000000 --- a/sys/nfsserver/nfs_srvsock.c +++ /dev/null @@ -1,818 +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 <sys/param.h> -#include <sys/systm.h> -#include <sys/jail.h> -#include <sys/kernel.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/protosw.h> -#include <sys/refcount.h> -#include <sys/signalvar.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/sysctl.h> -#include <sys/syslog.h> -#include <sys/vnode.h> - -#include <netinet/in.h> -#include <netinet/tcp.h> - -#include <nfs/rpcv2.h> -#include <nfs/nfsproto.h> -#include <nfsserver/nfs.h> -#include <nfs/xdr_subs.h> -#include <nfsserver/nfsm_subs.h> - -#include <security/mac/mac_framework.h> - -#ifdef NFS_LEGACYRPC - -#define TRUE 1 -#define FALSE 0 - -static int nfs_realign_test; -static int nfs_realign_count; - -SYSCTL_DECL(_vfs_nfsrv); - -SYSCTL_INT(_vfs_nfsrv, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, ""); -SYSCTL_INT(_vfs_nfsrv, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, ""); - - -/* - * There is a congestion window for outstanding rpcs maintained per mount - * point. The cwnd size is adjusted in roughly the way that: - * Van Jacobson, Congestion avoidance and Control, In "Proceedings of - * SIGCOMM '88". ACM, August 1988. - * describes for TCP. The cwnd size is chopped in half on a retransmit timeout - * and incremented by 1/cwnd when each rpc reply is received and a full cwnd - * of rpcs is in progress. - * (The sent count and cwnd are scaled for integer arith.) - * Variants of "slow start" were tried and were found to be too much of a - * performance hit (ave. rtt 3 times larger), - * I suspect due to the large rtt that nfs rpcs have. - */ -#define NFS_CWNDSCALE 256 -#define NFS_MAXCWND (NFS_CWNDSCALE * 32) -struct callout nfsrv_callout; - -static void nfs_realign(struct mbuf **pm, int hsiz); /* XXX SHARED */ -static int nfsrv_getstream(struct nfssvc_sock *, int); - -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 -}; - - -/* - * 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; - - nd->nd_repstat = err; - if (err && (nd->nd_flag & ND_NFSV3) == 0) /* XXX recheck */ - siz = 0; - MGETHDR(mreq, M_WAIT, MT_DATA); - mb = mreq; - /* - * If this is a big reply, use a cluster else - * try and leave leading space for the lower level headers. - */ - mreq->m_len = 6 * NFSX_UNSIGNED; - siz += RPC_REPLYSIZ; - if ((max_hdr + siz) >= MINCLSIZE) { - MCLGET(mreq, M_WAIT); - } else - mreq->m_data += min(max_hdr, M_TRAILINGSPACE(mreq)); - tl = mtod(mreq, u_int32_t *); - bpos = ((caddr_t)tl) + mreq->m_len; - *tl++ = txdr_unsigned(nd->nd_retxid); - *tl++ = nfsrv_rpc_reply; - if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { - *tl++ = nfsrv_rpc_msgdenied; - if (err & NFSERR_AUTHERR) { - *tl++ = nfsrv_rpc_autherr; - *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); - mreq->m_len -= NFSX_UNSIGNED; - bpos -= NFSX_UNSIGNED; - } else { - *tl++ = nfsrv_rpc_mismatch; - *tl++ = txdr_unsigned(RPC_VER2); - *tl = txdr_unsigned(RPC_VER2); - } - } else { - *tl++ = nfsrv_rpc_msgaccepted; - /* - * Send a RPCAUTH_NULL verifier - no Kerberos. - */ - *tl++ = 0; - *tl++ = 0; - switch (err) { - case EPROGUNAVAIL: - *tl = txdr_unsigned(RPC_PROGUNAVAIL); - break; - case EPROGMISMATCH: - *tl = txdr_unsigned(RPC_PROGMISMATCH); - tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(2); - *tl = txdr_unsigned(3); - break; - case EPROCUNAVAIL: - *tl = txdr_unsigned(RPC_PROCUNAVAIL); - break; - case EBADRPC: - *tl = txdr_unsigned(RPC_GARBAGE); - break; - default: - *tl = 0; - if (err != NFSERR_RETVOID) { - tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); - if (err) - *tl = txdr_unsigned(nfsrv_errmap(nd, err)); - else - *tl = 0; - } - break; - } - } - *mbp = mb; - *bposp = bpos; - if (err != 0 && err != NFSERR_RETVOID) - nfsrvstats.srvrpc_errs++; - return mreq; -} - - -/* - * nfs_realign: - * - * 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.realign_count and realign_test to check this. - */ -static void -nfs_realign(struct mbuf **pm, int hsiz) /* XXX COMMON */ -{ - struct mbuf *m; - struct mbuf *n = NULL; - int off = 0; - - ++nfs_realign_test; - while ((m = *pm) != NULL) { - if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { - MGET(n, M_WAIT, MT_DATA); - if (m->m_len >= MINCLSIZE) { - MCLGET(n, M_WAIT); - } - n->m_len = 0; - break; - } - pm = &m->m_next; - } - - /* - * If n is non-NULL, loop on m copying data, then replace the - * portion of the chain that had to be realigned. - */ - if (n != NULL) { - ++nfs_realign_count; - while (m) { - m_copyback(n, off, m->m_len, mtod(m, caddr_t)); - off += m->m_len; - m = m->m_next; - } - m_freem(*pm); - *pm = n; - } -} - - -/* - * Parse an RPC request - * - verify it - * - fill in the cred struct. - */ -int -nfs_getreq(struct nfsrv_descript *nd, struct nfsd *nfsd, int has_header) -{ - int len, i; - u_int32_t *tl; - caddr_t dpos; - u_int32_t nfsvers, auth_type; - int error = 0; - struct mbuf *mrep, *md; - - NFSD_LOCK_ASSERT(); - - mrep = nd->nd_mrep; - md = nd->nd_md; - dpos = nd->nd_dpos; - if (has_header) { - tl = nfsm_dissect_nonblock(u_int32_t *, 10 * NFSX_UNSIGNED); - nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++); - if (*tl++ != nfsrv_rpc_call) { - m_freem(mrep); - return (EBADRPC); - } - } else - tl = nfsm_dissect_nonblock(u_int32_t *, 8 * NFSX_UNSIGNED); - nd->nd_repstat = 0; - nd->nd_flag = 0; - if (*tl++ != nfsrv_rpc_vers) { - nd->nd_repstat = ERPCMISMATCH; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - if (*tl != nfsrv_nfs_prog) { - nd->nd_repstat = EPROGUNAVAIL; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - tl++; - nfsvers = fxdr_unsigned(u_int32_t, *tl++); - if (nfsvers < NFS_VER2 || nfsvers > NFS_VER3) { - nd->nd_repstat = EPROGMISMATCH; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++); - if (nd->nd_procnum == NFSPROC_NULL) - return (0); - if (nfsvers == NFS_VER3) { - nd->nd_flag = ND_NFSV3; - if (nd->nd_procnum >= NFS_NPROCS) { - nd->nd_repstat = EPROCUNAVAIL; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - } else { - if (nd->nd_procnum > NFSV2PROC_STATFS) { - nd->nd_repstat = EPROCUNAVAIL; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - /* Map the v2 procedure numbers into v3 ones */ - nd->nd_procnum = nfsrv_nfsv3_procid[nd->nd_procnum]; - } - auth_type = *tl++; - len = fxdr_unsigned(int, *tl++); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } - - /* - * Handle auth_unix; - */ - if (auth_type == nfsrv_rpc_auth_unix) { - len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > NFS_MAXNAMLEN) { - m_freem(mrep); - return (EBADRPC); - } - nfsm_adv(nfsm_rndup(len)); - tl = nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED); - nd->nd_cr->cr_uid = nd->nd_cr->cr_ruid = - nd->nd_cr->cr_svuid = fxdr_unsigned(uid_t, *tl++); - nd->nd_cr->cr_groups[0] = nd->nd_cr->cr_rgid = - nd->nd_cr->cr_svgid = fxdr_unsigned(gid_t, *tl++); -#ifdef MAC - mac_cred_associate_nfsd(nd->nd_cr); -#endif - len = fxdr_unsigned(int, *tl); - if (len < 0 || len > RPCAUTH_UNIXGIDS) { - m_freem(mrep); - return (EBADRPC); - } - tl = nfsm_dissect_nonblock(u_int32_t *, (len + 2) * NFSX_UNSIGNED); - for (i = 1; i <= len; i++) - if (i < XU_NGROUPS) - nd->nd_cr->cr_groups[i] = fxdr_unsigned(gid_t, *tl++); - else - tl++; - nd->nd_cr->cr_ngroups = MIN(XU_NGROUPS, len + 1); - if (nd->nd_cr->cr_ngroups > 1) - nfsrvw_sort(nd->nd_cr->cr_groups, nd->nd_cr->cr_ngroups); - len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } - if (len > 0) - nfsm_adv(nfsm_rndup(len)); - nd->nd_credflavor = RPCAUTH_UNIX; - } else { - nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - - nd->nd_md = md; - nd->nd_dpos = dpos; - return (0); -nfsmout: - return (error); -} - -/* - * Socket upcall routine for the nfsd sockets. - * The caddr_t arg is a pointer to the "struct nfssvc_sock". - * Essentially do as much as possible non-blocking, else punt and it will - * be called with M_WAIT from an nfsd. - */ -int -nfsrv_rcv(struct socket *so, void *arg, int waitflag) -{ - struct nfssvc_sock *slp = (struct nfssvc_sock *)arg; - struct mbuf *m; - struct mbuf *mp; - struct sockaddr *nam; - struct uio auio; - int flags, error; - - NFSD_UNLOCK_ASSERT(); - - /* XXXRW: Unlocked read. */ - if ((slp->ns_flag & SLP_VALID) == 0) - return (SU_OK); - - /* - * We can't do this in the context of a socket callback - * because we're called with locks held. - * XXX: SMP - */ - if (waitflag == M_DONTWAIT) { - NFSD_LOCK(); - slp->ns_flag |= SLP_NEEDQ; - goto dorecs; - } - - - NFSD_LOCK(); - auio.uio_td = NULL; - if (so->so_type == SOCK_STREAM) { - /* - * If there are already records on the queue, defer soreceive() - * to an nfsd so that there is feedback to the TCP layer that - * the nfs servers are heavily loaded. - */ - if (STAILQ_FIRST(&slp->ns_rec) != NULL && - waitflag == M_DONTWAIT) { - slp->ns_flag |= SLP_NEEDQ; - goto dorecs; - } - - /* - * Do soreceive(). - */ - auio.uio_resid = 1000000000; - flags = MSG_DONTWAIT; - NFSD_UNLOCK(); - error = soreceive(so, &nam, &auio, &mp, NULL, &flags); - NFSD_LOCK(); - if (error || mp == NULL) { - if (error == EWOULDBLOCK) - slp->ns_flag |= SLP_NEEDQ; - else - slp->ns_flag |= SLP_DISCONN; - goto dorecs; - } - m = mp; - if (slp->ns_rawend) { - slp->ns_rawend->m_next = m; - slp->ns_cc += 1000000000 - auio.uio_resid; - } else { - slp->ns_raw = m; - slp->ns_cc = 1000000000 - auio.uio_resid; - } - while (m->m_next) - m = m->m_next; - slp->ns_rawend = m; - - /* - * Now try and parse record(s) out of the raw stream data. - */ - error = nfsrv_getstream(slp, waitflag); - if (error) { - if (error == EPERM) - slp->ns_flag |= SLP_DISCONN; - else - slp->ns_flag |= SLP_NEEDQ; - } - } else { - do { - auio.uio_resid = 1000000000; - flags = MSG_DONTWAIT; - NFSD_UNLOCK(); - error = soreceive(so, &nam, &auio, &mp, NULL, &flags); - if (mp) { - struct nfsrv_rec *rec; - rec = malloc(sizeof(struct nfsrv_rec), - M_NFSRVDESC, - waitflag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); - if (!rec) { - if (nam) - free(nam, M_SONAME); - m_freem(mp); - NFSD_LOCK(); - continue; - } - nfs_realign(&mp, 10 * NFSX_UNSIGNED); - NFSD_LOCK(); - rec->nr_address = nam; - rec->nr_packet = mp; - STAILQ_INSERT_TAIL(&slp->ns_rec, rec, nr_link); - } else - NFSD_LOCK(); - if (error) { - if ((so->so_proto->pr_flags & PR_CONNREQUIRED) - && error != EWOULDBLOCK) { - slp->ns_flag |= SLP_DISCONN; - goto dorecs; - } - } - } while (mp); - } - - /* - * Now try and process the request records, non-blocking. - */ -dorecs: - if (waitflag == M_DONTWAIT && - (STAILQ_FIRST(&slp->ns_rec) != NULL || - (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) - nfsrv_wakenfsd(slp); - NFSD_UNLOCK(); - return (SU_OK); -} - -/* - * Try and extract an RPC request from the mbuf data list received on a - * stream socket. The "waitflag" argument indicates whether or not it - * can sleep. - */ -static int -nfsrv_getstream(struct nfssvc_sock *slp, int waitflag) -{ - struct mbuf *m, **mpp; - char *cp1, *cp2; - int len; - struct mbuf *om, *m2, *recm; - u_int32_t recmark; - - NFSD_LOCK_ASSERT(); - - if (slp->ns_flag & SLP_GETSTREAM) - panic("nfs getstream"); - slp->ns_flag |= SLP_GETSTREAM; - for (;;) { - if (slp->ns_reclen == 0) { - if (slp->ns_cc < NFSX_UNSIGNED) { - slp->ns_flag &= ~SLP_GETSTREAM; - return (0); - } - m = slp->ns_raw; - if (m->m_len >= NFSX_UNSIGNED) { - bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED); - m->m_data += NFSX_UNSIGNED; - m->m_len -= NFSX_UNSIGNED; - } else { - cp1 = (caddr_t)&recmark; - cp2 = mtod(m, caddr_t); - while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) { - while (m->m_len == 0) { - m = m->m_next; - cp2 = mtod(m, caddr_t); - } - *cp1++ = *cp2++; - m->m_data++; - m->m_len--; - } - } - slp->ns_cc -= NFSX_UNSIGNED; - recmark = ntohl(recmark); - slp->ns_reclen = recmark & ~0x80000000; - if (recmark & 0x80000000) - slp->ns_flag |= SLP_LASTFRAG; - else - slp->ns_flag &= ~SLP_LASTFRAG; - if (slp->ns_reclen > NFS_MAXPACKET || slp->ns_reclen <= 0) { - slp->ns_flag &= ~SLP_GETSTREAM; - return (EPERM); - } - } - - /* - * Now get the record part. - * - * Note that slp->ns_reclen may be 0. Linux sometimes - * generates 0-length RPCs. - */ - recm = NULL; - if (slp->ns_cc == slp->ns_reclen) { - recm = slp->ns_raw; - slp->ns_raw = slp->ns_rawend = NULL; - slp->ns_cc = slp->ns_reclen = 0; - } else if (slp->ns_cc > slp->ns_reclen) { - len = 0; - m = slp->ns_raw; - om = NULL; - - while (len < slp->ns_reclen) { - if ((len + m->m_len) > slp->ns_reclen) { - NFSD_UNLOCK(); - m2 = m_copym(m, 0, slp->ns_reclen - len, - waitflag); - NFSD_LOCK(); - if (m2) { - if (om) { - om->m_next = m2; - recm = slp->ns_raw; - } else - recm = m2; - m->m_data += slp->ns_reclen - len; - m->m_len -= slp->ns_reclen - len; - len = slp->ns_reclen; - } else { - slp->ns_flag &= ~SLP_GETSTREAM; - return (EWOULDBLOCK); - } - } else if ((len + m->m_len) == slp->ns_reclen) { - om = m; - len += m->m_len; - m = m->m_next; - recm = slp->ns_raw; - om->m_next = NULL; - } else { - om = m; - len += m->m_len; - m = m->m_next; - } - } - slp->ns_raw = m; - slp->ns_cc -= len; - slp->ns_reclen = 0; - } else { - slp->ns_flag &= ~SLP_GETSTREAM; - return (0); - } - - /* - * Accumulate the fragments into a record. - */ - mpp = &slp->ns_frag; - while (*mpp) - mpp = &((*mpp)->m_next); - *mpp = recm; - if (slp->ns_flag & SLP_LASTFRAG) { - struct nfsrv_rec *rec; - NFSD_UNLOCK(); - rec = malloc(sizeof(struct nfsrv_rec), M_NFSRVDESC, - waitflag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); - if (rec) { - nfs_realign(&slp->ns_frag, 10 * NFSX_UNSIGNED); - rec->nr_address = NULL; - rec->nr_packet = slp->ns_frag; - NFSD_LOCK(); - STAILQ_INSERT_TAIL(&slp->ns_rec, rec, nr_link); - } else { - NFSD_LOCK(); - } - if (!rec) { - m_freem(slp->ns_frag); - } - slp->ns_frag = NULL; - } - } -} - -/* - * Parse an RPC header. - */ -int -nfsrv_dorec(struct nfssvc_sock *slp, struct nfsd *nfsd, - struct nfsrv_descript **ndp) -{ - struct nfsrv_rec *rec; - struct mbuf *m; - struct sockaddr *nam; - struct nfsrv_descript *nd; - int error; - - NFSD_LOCK_ASSERT(); - - *ndp = NULL; - if ((slp->ns_flag & SLP_VALID) == 0 || - STAILQ_FIRST(&slp->ns_rec) == NULL) - return (ENOBUFS); - rec = STAILQ_FIRST(&slp->ns_rec); - KASSERT(rec->nr_packet != NULL, ("nfsrv_dorec: missing mbuf")); - STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link); - nam = rec->nr_address; - m = rec->nr_packet; - free(rec, M_NFSRVDESC); - NFSD_UNLOCK(); - nd = malloc(sizeof (struct nfsrv_descript), - M_NFSRVDESC, M_WAITOK); - nd->nd_cr = crget(); - prison_hold(&prison0); - nd->nd_cr->cr_prison = &prison0; - NFSD_LOCK(); - nd->nd_md = nd->nd_mrep = m; - nd->nd_nam2 = nam; - nd->nd_dpos = mtod(m, caddr_t); - error = nfs_getreq(nd, nfsd, TRUE); - if (error) { - if (nam) { - free(nam, M_SONAME); - } - if (nd->nd_cr != NULL) - crfree(nd->nd_cr); - free((caddr_t)nd, M_NFSRVDESC); - return (error); - } - *ndp = nd; - nfsd->nfsd_nd = nd; - return (0); -} - -/* - * Search for a sleeping nfsd and wake it up. - * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the - * running nfsds will go look for the work in the nfssvc_sock list. - */ -void -nfsrv_wakenfsd(struct nfssvc_sock *slp) -{ - struct nfsd *nd; - - NFSD_LOCK_ASSERT(); - - if ((slp->ns_flag & SLP_VALID) == 0) - return; - TAILQ_FOREACH(nd, &nfsd_head, nfsd_chain) { - if (nd->nfsd_flag & NFSD_WAITING) { - nd->nfsd_flag &= ~NFSD_WAITING; - if (nd->nfsd_slp) - panic("nfsd wakeup"); - slp->ns_sref++; - nd->nfsd_slp = slp; - wakeup(nd); - return; - } - } - slp->ns_flag |= SLP_DOREC; - nfsd_head_flag |= NFSD_CHECKSLP; -} - -/* - * This is the nfs send routine. - * For the server side: - * - return EINTR or ERESTART if interrupted by a signal - * - return EPIPE if a connection is lost for connection based sockets (TCP...) - * - do any cleanup required by recoverable socket errors (?) - */ -int -nfsrv_send(struct socket *so, struct sockaddr *nam, struct mbuf *top) -{ - struct sockaddr *sendnam; - int error, soflags, flags; - - NFSD_UNLOCK_ASSERT(); - - soflags = so->so_proto->pr_flags; - if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) - sendnam = NULL; - else - sendnam = nam; - if (so->so_type == SOCK_SEQPACKET) - flags = MSG_EOR; - else - flags = 0; - - error = sosend(so, sendnam, 0, top, 0, flags, curthread/*XXX*/); - if (error == ENOBUFS && so->so_type == SOCK_DGRAM) - error = 0; - - if (error) { - log(LOG_INFO, "nfsd send error %d\n", error); - - /* - * Handle any recoverable (soft) socket errors here. (?) - */ - if (error != EINTR && error != ERESTART && - error != EWOULDBLOCK && error != EPIPE) - error = 0; - } - return (error); -} - -/* - * NFS server timer routine. - */ -void -nfsrv_timer(void *arg) -{ - struct nfssvc_sock *slp; - u_quad_t cur_usec; - - NFSD_LOCK(); - /* - * Scan the write gathering queues for writes that need to be - * completed now. - */ - cur_usec = nfs_curusec(); - TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) { - if (LIST_FIRST(&slp->ns_tq) && - LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) - nfsrv_wakenfsd(slp); - } - NFSD_UNLOCK(); - callout_reset(&nfsrv_callout, nfsrv_ticks, nfsrv_timer, NULL); -} - -#endif /* NFS_LEGACYRPC */ diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c index 87fda28..ee0614b 100644 --- a/sys/nfsserver/nfs_srvsubs.c +++ b/sys/nfsserver/nfs_srvsubs.c @@ -67,7 +67,8 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_extern.h> #include <vm/uma.h> -#include <nfs/rpcv2.h> +#include <rpc/rpc.h> + #include <nfs/nfsproto.h> #include <nfsserver/nfs.h> #include <nfs/xdr_subs.h> @@ -80,10 +81,7 @@ __FBSDID("$FreeBSD$"); * This is kinda hokey, but may save a little time doing byte swaps */ u_int32_t nfsrv_nfs_xdrneg1; -u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply, - nfsrv_rpc_msgdenied, nfsrv_rpc_autherr, - nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted; -u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false; +u_int32_t nfsrv_nfs_true, nfsrv_nfs_false; /* And other global data */ static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, @@ -93,13 +91,6 @@ static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, int nfsrv_ticks; -#ifdef NFS_LEGACYRPC -struct nfssvc_sockhead nfssvc_sockhead; -int nfssvc_sockhead_flag; -struct nfsd_head nfsd_head; -int nfsd_head_flag; -#endif - struct mtx nfsd_mtx; /* @@ -528,15 +519,6 @@ nfsrv_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); - nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); - nfsrv_rpc_call = txdr_unsigned(RPC_CALL); - nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); - nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); - nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); - nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); - nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); - nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); - nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); nfsrv_nfs_true = txdr_unsigned(TRUE); nfsrv_nfs_false = txdr_unsigned(FALSE); nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); @@ -544,18 +526,9 @@ nfsrv_modevent(module_t mod, int type, void *data) if (nfsrv_ticks < 1) nfsrv_ticks = 1; -#ifdef NFS_LEGACYRPC - nfsrv_initcache(); /* Init the server request cache */ NFSD_LOCK(); nfsrv_init(0); /* Init server data structures */ - callout_init(&nfsrv_callout, CALLOUT_MPSAFE); NFSD_UNLOCK(); - nfsrv_timer(0); -#else - NFSD_LOCK(); - nfsrv_init(0); /* Init server data structures */ - NFSD_UNLOCK(); -#endif nfsd_call_nfsserver = nfssvc_nfsserver; break; @@ -568,9 +541,6 @@ nfsrv_modevent(module_t mod, int type, void *data) nfsd_call_nfsserver = NULL; callout_drain(&nfsrv_callout); -#ifdef NFS_LEGACYRPC - nfsrv_destroycache(); /* Free the server request cache */ -#endif mtx_destroy(&nfsd_mtx); break; default: @@ -589,9 +559,7 @@ DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_VERSION(nfsserver, 1); MODULE_DEPEND(nfsserver, nfssvc, 1, 1, 1); -#ifndef NFS_LEGACYRPC MODULE_DEPEND(nfsserver, krpc, 1, 1, 1); -#endif /* * Set up nameidata for a lookup() call and do it. @@ -1128,7 +1096,7 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp, * old mountd that doesn't pass in a secflavor list. */ numsecflavors = 1; - authsys = RPCAUTH_UNIX; + authsys = AUTH_SYS; secflavors = &authsys; } credflavor = nfsd->nd_credflavor; @@ -1221,52 +1189,6 @@ nfs_ispublicfh(fhandle_t *fhp) return (TRUE); } -#ifdef NFS_LEGACYRPC - -/* - * This function compares two net addresses by family and returns TRUE - * if they are the same host. - * If there is any doubt, return FALSE. - * The AF_INET family is handled as a special case so that address mbufs - * don't need to be saved to store "struct in_addr", which is only 4 bytes. - */ -int -netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) -{ - struct sockaddr_in *inetaddr; - - NFSD_LOCK_DONTCARE(); - - switch (family) { - case AF_INET: - inetaddr = (struct sockaddr_in *)nam; - if (inetaddr->sin_family == AF_INET && - inetaddr->sin_addr.s_addr == haddr->had_inetaddr) - return (1); - break; -#ifdef INET6 - case AF_INET6: - { - register struct sockaddr_in6 *inet6addr1, *inet6addr2; - - inet6addr1 = (struct sockaddr_in6 *)nam; - inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; - /* XXX - should test sin6_scope_id ? */ - if (inet6addr1->sin6_family == AF_INET6 && - IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, - &inet6addr2->sin6_addr)) - return (1); - break; - } -#endif - default: - break; - }; - return (0); -} - -#endif - /* * Map errnos to NFS error numbers. For Version 3 also filter out error * numbers not specified for the associated procedure. diff --git a/sys/nfsserver/nfs_syscalls.c b/sys/nfsserver/nfs_syscalls.c deleted file mode 100644 index 29c9643..0000000 --- a/sys/nfsserver/nfs_syscalls.c +++ /dev/null @@ -1,723 +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 <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/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 <netinet/in.h> -#include <netinet/tcp.h> -#ifdef INET6 -#include <net/if.h> -#include <netinet6/in6_var.h> -#endif -#include <nfs/xdr_subs.h> -#include <nfs/rpcv2.h> -#include <nfs/nfsproto.h> -#include <nfsserver/nfs.h> -#include <nfsserver/nfsm_subs.h> -#include <nfsserver/nfsrvcache.h> - -#include <security/audit/audit.h> - -#ifdef NFS_LEGACYRPC - -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); - -int nfsd_waiting = 0; -int nfsrv_numnfsd = 0; -static int notstarted = 1; - -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 sockaddr *); -static void nfsrv_zapsock(struct nfssvc_sock *slp); -static int nfssvc_nfsd(void); - -extern u_long sb_max_adj; - -/* - * 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 sockaddr *nam; - struct nfsd_addsock_args nfsdarg; - int error; - - NFSD_LOCK(); - while (nfssvc_sockhead_flag & SLP_INIT) { - nfssvc_sockhead_flag |= SLP_WANTINIT; - (void) msleep(&nfssvc_sockhead, &nfsd_mtx, PSOCK, - "nfsd init", 0); - } - NFSD_UNLOCK(); - if (uap->flag & NFSSVC_ADDSOCK) { - error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); - if (error) - return (error); - if ((error = fget(td, nfsdarg.sock, &fp)) != 0) - return (error); - if (fp->f_type != DTYPE_SOCKET) { - fdrop(fp, td); - return (error); /* XXXRW: Should be EINVAL? */ - } - /* - * Get the client address for connected sockets. - */ - if (nfsdarg.name == NULL || nfsdarg.namelen == 0) - nam = NULL; - else { - error = getsockaddr(&nam, nfsdarg.name, - nfsdarg.namelen); - if (error) { - fdrop(fp, td); - return (error); - } - } - error = nfssvc_addsock(fp, nam); - fdrop(fp, td); - } else if (uap->flag & NFSSVC_OLDNFSD) { - error = nfssvc_nfsd(); - } else { - error = ENXIO; - } - return (error); -} - -/* - * Adds a socket to the list for servicing by nfsds. - */ -static int -nfssvc_addsock(struct file *fp, struct sockaddr *mynam) -{ - int siz; - struct nfssvc_sock *slp; - struct socket *so; - int error; - - so = fp->f_data; -#if 0 - /* - * XXXRW: If this code is ever enabled, there's a race when running - * MPSAFE. - */ - tslp = NULL; - /* - * Add it to the list, as required. - */ - if (so->so_proto->pr_protocol == IPPROTO_UDP) { - tslp = nfs_udpsock; - if (tslp->ns_flag & SLP_VALID) { - if (mynam != NULL) - free(mynam, M_SONAME); - return (EPERM); - } - } -#endif - siz = sb_max_adj; - error = soreserve(so, siz, siz); - if (error) { - if (mynam != NULL) - free(mynam, M_SONAME); - return (error); - } - - /* - * Set protocol specific options { for now TCP only } and - * reserve some space. For datagram sockets, this can get called - * repeatedly for the same socket, but that isn't harmful. - */ - if (so->so_type == SOCK_STREAM) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = SOL_SOCKET; - sopt.sopt_name = SO_KEEPALIVE; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - sosetopt(so, &sopt); - } - if (so->so_proto->pr_protocol == IPPROTO_TCP) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = IPPROTO_TCP; - sopt.sopt_name = TCP_NODELAY; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - sosetopt(so, &sopt); - } - SOCKBUF_LOCK(&so->so_rcv); - so->so_rcv.sb_flags &= ~SB_NOINTR; - so->so_rcv.sb_timeo = 0; - SOCKBUF_UNLOCK(&so->so_rcv); - SOCKBUF_LOCK(&so->so_snd); - so->so_snd.sb_flags &= ~SB_NOINTR; - so->so_snd.sb_timeo = 0; - SOCKBUF_UNLOCK(&so->so_snd); - - slp = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, - M_WAITOK | M_ZERO); - STAILQ_INIT(&slp->ns_rec); - NFSD_LOCK(); - TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); - - slp->ns_so = so; - slp->ns_nam = mynam; - fhold(fp); - slp->ns_fp = fp; - NFSD_UNLOCK(); - SOCKBUF_LOCK(&so->so_rcv); - soupcall_set(so, SO_RCV, nfsrv_rcv, slp); - SOCKBUF_UNLOCK(&so->so_rcv); - NFSD_LOCK(); - slp->ns_flag = (SLP_VALID | SLP_NEEDQ); - nfsrv_wakenfsd(slp); - NFSD_UNLOCK(); - return (0); -} - -/* - * Called by nfssvc() for nfsds. Just loops around servicing rpc requests - * until it is killed by a signal. - */ -static int -nfssvc_nfsd() -{ - int siz; - struct nfssvc_sock *slp; - struct nfsd *nfsd; - struct nfsrv_descript *nd = NULL; - struct mbuf *m, *mreq; - int error = 0, cacherep, s, sotype, writes_todo; - int procrastinate; - u_quad_t cur_usec; - -#ifndef nolint - cacherep = RC_DOIT; - writes_todo = 0; -#endif - nfsd = (struct nfsd *) - malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK | M_ZERO); - s = splnet(); - NFSD_LOCK(); - - TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); - nfsrv_numnfsd++; - - /* - * Loop getting rpc requests until SIGKILL. - */ - for (;;) { - if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { - while (nfsd->nfsd_slp == NULL && - (nfsd_head_flag & NFSD_CHECKSLP) == 0) { - nfsd->nfsd_flag |= NFSD_WAITING; - nfsd_waiting++; - error = msleep(nfsd, &nfsd_mtx, - PSOCK | PCATCH, "-", 0); - nfsd_waiting--; - if (error) - goto done; - } - if (nfsd->nfsd_slp == NULL && - (nfsd_head_flag & NFSD_CHECKSLP) != 0) { - TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) { - if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) - == (SLP_VALID | SLP_DOREC)) { - slp->ns_flag &= ~SLP_DOREC; - slp->ns_sref++; - nfsd->nfsd_slp = slp; - break; - } - } - if (slp == NULL) - nfsd_head_flag &= ~NFSD_CHECKSLP; - } - if ((slp = nfsd->nfsd_slp) == NULL) - continue; - if (slp->ns_flag & SLP_VALID) { - if (slp->ns_flag & SLP_DISCONN) - nfsrv_zapsock(slp); - else if (slp->ns_flag & SLP_NEEDQ) { - slp->ns_flag &= ~SLP_NEEDQ; - (void) nfs_slplock(slp, 1); - NFSD_UNLOCK(); - nfsrv_rcv(slp->ns_so, (caddr_t)slp, - M_WAIT); - NFSD_LOCK(); - nfs_slpunlock(slp); - } - error = nfsrv_dorec(slp, nfsd, &nd); - cur_usec = nfs_curusec(); - if (error && LIST_FIRST(&slp->ns_tq) && - LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) { - error = 0; - cacherep = RC_DOIT; - writes_todo = 1; - } else - writes_todo = 0; - nfsd->nfsd_flag |= NFSD_REQINPROG; - } - } else { - error = 0; - slp = nfsd->nfsd_slp; - } - if (error || (slp->ns_flag & SLP_VALID) == 0) { - if (nd) { - if (nd->nd_cr != NULL) - crfree(nd->nd_cr); - free((caddr_t)nd, M_NFSRVDESC); - nd = NULL; - } - nfsd->nfsd_slp = NULL; - nfsd->nfsd_flag &= ~NFSD_REQINPROG; - nfsrv_slpderef(slp); - continue; - } - splx(s); - sotype = slp->ns_so->so_type; - if (nd) { - getmicrotime(&nd->nd_starttime); - if (nd->nd_nam2) - nd->nd_nam = nd->nd_nam2; - else - nd->nd_nam = slp->ns_nam; - - /* - * Check to see if authorization is needed. - */ - cacherep = nfsrv_getcache(nd, &mreq); - - 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 - nd->nd_procnum = NFSPROC_NOOP; - nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); - cacherep = RC_DOIT; - 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); - } - } - - } - - /* - * Loop to get all the write rpc relies that have been - * gathered together. - */ - do { - switch (cacherep) { - case RC_DOIT: - if (nd && (nd->nd_flag & ND_NFSV3)) - procrastinate = nfsrvw_procrastinate_v3; - else - procrastinate = nfsrvw_procrastinate; - NFSD_UNLOCK(); - if (writes_todo || (!(nd->nd_flag & ND_NFSV3) && - nd->nd_procnum == NFSPROC_WRITE && - procrastinate > 0 && !notstarted)) - error = nfsrv_writegather(&nd, slp, &mreq); - else - error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, - slp, &mreq); - NFSD_LOCK(); - if (mreq == NULL) - break; - if (error != 0 && error != NFSERR_RETVOID) { - nfsrvstats.srv_errs++; - nfsrv_updatecache(nd, FALSE, mreq); - if (nd->nd_nam2) - free(nd->nd_nam2, M_SONAME); - break; - } - nfsrvstats.srvrpccnt[nd->nd_procnum]++; - nfsrv_updatecache(nd, TRUE, mreq); - nd->nd_mrep = NULL; - /* FALLTHROUGH */ - case RC_REPLY: - NFSD_UNLOCK(); - siz = m_length(mreq, NULL); - if (siz <= 0 || siz > NFS_MAXPACKET) { - printf("mbuf siz=%d\n",siz); - panic("Bad nfs svc reply"); - } - m = mreq; - m->m_pkthdr.len = siz; - m->m_pkthdr.rcvif = NULL; - /* - * For stream protocols, prepend a Sun RPC - * Record Mark. - */ - if (sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | siz); - } - NFSD_LOCK(); - if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) - (void) nfs_slplock(slp, 1); - if (slp->ns_flag & SLP_VALID) { - NFSD_UNLOCK(); - error = nfsrv_send(slp->ns_so, nd->nd_nam2, m); - NFSD_LOCK(); - } else { - error = EPIPE; - m_freem(m); - } - if (nd->nd_nam2) - free(nd->nd_nam2, M_SONAME); - if (nd->nd_mrep) - m_freem(nd->nd_mrep); - if (error == EPIPE) - nfsrv_zapsock(slp); - if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) - nfs_slpunlock(slp); - if (error == EINTR || error == ERESTART) { - if (nd->nd_cr != NULL) - crfree(nd->nd_cr); - free((caddr_t)nd, M_NFSRVDESC); - nfsrv_slpderef(slp); - s = splnet(); - goto done; - } - break; - case RC_DROPIT: - m_freem(nd->nd_mrep); - if (nd->nd_nam2) - free(nd->nd_nam2, M_SONAME); - break; - }; - if (nd) { - if (nd->nd_cr != NULL) - crfree(nd->nd_cr); - free((caddr_t)nd, M_NFSRVDESC); - nd = NULL; - } - - /* - * Check to see if there are outstanding writes that - * need to be serviced. - */ - cur_usec = nfs_curusec(); - s = splsoftclock(); - if (LIST_FIRST(&slp->ns_tq) && - LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) { - cacherep = RC_DOIT; - writes_todo = 1; - } else - writes_todo = 0; - splx(s); - } while (writes_todo); - s = splnet(); - if (nfsrv_dorec(slp, nfsd, &nd)) { - nfsd->nfsd_flag &= ~NFSD_REQINPROG; - nfsd->nfsd_slp = NULL; - nfsrv_slpderef(slp); - } - mtx_assert(&Giant, MA_NOTOWNED); - } -done: - mtx_assert(&Giant, MA_NOTOWNED); - TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); - splx(s); - free((caddr_t)nfsd, M_NFSD); - if (--nfsrv_numnfsd == 0) - nfsrv_init(TRUE); /* Reinitialize everything */ - NFSD_UNLOCK(); - return (error); -} - -/* - * Shut down a socket associated with an nfssvc_sock structure. - * Should be called with the send lock set, if required. - * The trick here is to increment the sref at the start, so that the nfsds - * will stop using it and clear ns_flag at the end so that it will not be - * reassigned during cleanup. - */ -static void -nfsrv_zapsock(struct nfssvc_sock *slp) -{ - struct nfsrv_descript *nwp, *nnwp; - struct socket *so; - struct file *fp; - struct nfsrv_rec *rec; - int s; - - NFSD_LOCK_ASSERT(); - - /* - * XXXRW: By clearing all flags, other threads/etc should ignore - * this slp and we can safely release nfsd_mtx so we can clean - * up the slp safely. - */ - slp->ns_flag &= ~SLP_ALLFLAGS; - fp = slp->ns_fp; - if (fp) { - NFSD_UNLOCK(); - slp->ns_fp = NULL; - so = slp->ns_so; - SOCKBUF_LOCK(&so->so_rcv); - soupcall_clear(so, SO_RCV); - SOCKBUF_UNLOCK(&so->so_rcv); - soshutdown(so, SHUT_RDWR); - closef(fp, NULL); - NFSD_LOCK(); - if (slp->ns_nam) - free(slp->ns_nam, M_SONAME); - m_freem(slp->ns_raw); - while ((rec = STAILQ_FIRST(&slp->ns_rec)) != NULL) { - STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link); - if (rec->nr_address) - free(rec->nr_address, M_SONAME); - m_freem(rec->nr_packet); - free(rec, M_NFSRVDESC); - } - s = splsoftclock(); - for (nwp = LIST_FIRST(&slp->ns_tq); nwp; nwp = nnwp) { - nnwp = LIST_NEXT(nwp, nd_tq); - LIST_REMOVE(nwp, nd_tq); - if (nwp->nd_cr != NULL) - crfree(nwp->nd_cr); - free((caddr_t)nwp, M_NFSRVDESC); - } - LIST_INIT(&slp->ns_tq); - splx(s); - } -} - -/* - * Derefence a server socket structure. If it has no more references and - * is no longer valid, you can throw it away. - */ -void -nfsrv_slpderef(struct nfssvc_sock *slp) -{ - - NFSD_LOCK_ASSERT(); - - if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { - TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); - free((caddr_t)slp, M_NFSSVC); - } -} - -/* - * Lock a socket against others. - * - * XXXRW: Wait argument is always 1 in the caller. Replace with a real - * sleep lock? - */ -int -nfs_slplock(struct nfssvc_sock *slp, int wait) -{ - int *statep = &slp->ns_solock; - - NFSD_LOCK_ASSERT(); - - if (!wait && (*statep & NFSRV_SNDLOCK)) - return(0); /* already locked, fail */ - while (*statep & NFSRV_SNDLOCK) { - *statep |= NFSRV_WANTSND; - (void) msleep(statep, &nfsd_mtx, PZERO - 1, "nfsslplck", 0); - } - *statep |= NFSRV_SNDLOCK; - return (1); -} - -/* - * Unlock the stream socket for others. - */ -void -nfs_slpunlock(struct nfssvc_sock *slp) -{ - int *statep = &slp->ns_solock; - - NFSD_LOCK_ASSERT(); - - if ((*statep & NFSRV_SNDLOCK) == 0) - panic("nfs slpunlock"); - *statep &= ~NFSRV_SNDLOCK; - if (*statep & NFSRV_WANTSND) { - *statep &= ~NFSRV_WANTSND; - wakeup(statep); - } -} - -/* - * 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) -{ - struct nfssvc_sock *slp, *nslp; - - NFSD_LOCK_ASSERT(); - - if (nfssvc_sockhead_flag & SLP_INIT) - panic("nfsd init"); - nfssvc_sockhead_flag |= SLP_INIT; - if (terminating) { - TAILQ_FOREACH_SAFE(slp, &nfssvc_sockhead, ns_chain, nslp) { - if (slp->ns_flag & SLP_VALID) - nfsrv_zapsock(slp); - TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); - free((caddr_t)slp, M_NFSSVC); - } - nfsrv_cleancache(); /* And clear out server cache */ - } else - nfs_pub.np_valid = 0; - - TAILQ_INIT(&nfssvc_sockhead); - nfssvc_sockhead_flag &= ~SLP_INIT; - if (nfssvc_sockhead_flag & SLP_WANTINIT) { - nfssvc_sockhead_flag &= ~SLP_WANTINIT; - wakeup(&nfssvc_sockhead); - } - - TAILQ_INIT(&nfsd_head); - nfsd_head_flag &= ~NFSD_CHECKSLP; - -#if 0 - nfs_udpsock = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); - STAILQ_INIT(&nfs_udpsock->ns_rec); - TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); - - nfs_cltpsock = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); - STAILQ_INIT(&nfs_cltpsock->ns_rec); - TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); -#endif -} - -#endif /* NFS_LEGACYRPC */ diff --git a/sys/nfsserver/nfsrvcache.h b/sys/nfsserver/nfsrvcache.h index 9c527e9..d4e31b1 100644 --- a/sys/nfsserver/nfsrvcache.h +++ b/sys/nfsserver/nfsrvcache.h @@ -44,46 +44,4 @@ #define NFSRVCACHE_MAX_SIZE 2048 #define NFSRVCACHE_MIN_SIZE 64 -#ifdef NFS_LEGACYRPC - -struct nfsrvcache { - TAILQ_ENTRY(nfsrvcache) rc_lru; /* LRU chain */ - LIST_ENTRY(nfsrvcache) rc_hash; /* Hash chain */ - u_int32_t rc_xid; /* rpc id number */ - union { - struct mbuf *ru_repmb; /* Reply mbuf list OR */ - int ru_repstat; /* Reply status */ - } rc_un; - union nethostaddr rc_haddr; /* Host address */ - u_int32_t rc_proc; /* rpc proc number */ - u_char rc_state; /* Current state of request */ - u_char rc_flag; /* Flag bits */ -}; - -#define rc_reply rc_un.ru_repmb -#define rc_status rc_un.ru_repstat -#define rc_inetaddr rc_haddr.had_inetaddr -#define rc_nam rc_haddr.had_nam - -/* Cache entry states */ -#define RC_UNUSED 0 -#define RC_INPROG 1 -#define RC_DONE 2 - -/* Return values */ -#define RC_DROPIT 0 -#define RC_REPLY 1 -#define RC_DOIT 2 - -/* Flag bits */ -#define RC_LOCKED 0x01 -#define RC_WANTED 0x02 -#define RC_REPSTATUS 0x04 -#define RC_REPMBUF 0x08 -/* free 0x10 */ -#define RC_INETADDR 0x20 -#define RC_NAM 0x40 - -#endif - #endif |