Remove the old kernel RPC implementation and the NFS_LEGACYRPC option.
Approved by: re
This commit is contained in:
parent
58c6a70a52
commit
b49a2b39fd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195202
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
108
sys/nfs/rpcv2.h
108
sys/nfs/rpcv2.h
@ -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
|
@ -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--;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
@ -193,87 +186,6 @@ nfsm_reqhead(struct vnode *vp, u_long procid, int hsiz)
|
||||
return (mb);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -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",
|
||||
|
@ -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 @@ nfs_flush(struct vnode *vp, int waitfor, int commit)
|
||||
&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;
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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 *,
|
||||
|
@ -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 */
|
||||
|
@ -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 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
|
||||
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
|
||||
|
@ -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 */
|
@ -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 */
|
||||
|
@ -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 */
|
@ -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.
|
||||
|
@ -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 */
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user