nfs_commonkrpc.c revision 224117
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1989, 1991, 1993, 1995
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Rick Macklem at The University of Guelph.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 4. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
311573Srgrimes *
321573Srgrimes */
331573Srgrimes
341573Srgrimes#include <sys/cdefs.h>
351573Srgrimes__FBSDID("$FreeBSD: head/sys/fs/nfs/nfs_commonkrpc.c 224117 2011-07-16 20:53:27Z rmacklem $");
361573Srgrimes
371573Srgrimes/*
3816586Sjraynard * Socket operations for use by nfs
391573Srgrimes */
4016586Sjraynard
4116586Sjraynard#include "opt_inet6.h"
4250476Speter#include "opt_kdtrace.h"
431573Srgrimes#include "opt_kgssapi.h"
441573Srgrimes#include "opt_nfs.h"
451573Srgrimes
461573Srgrimes#include <sys/param.h>
471573Srgrimes#include <sys/systm.h>
481573Srgrimes#include <sys/kernel.h>
491573Srgrimes#include <sys/limits.h>
501573Srgrimes#include <sys/lock.h>
5171579Sdeischen#include <sys/malloc.h>
521573Srgrimes#include <sys/mbuf.h>
531573Srgrimes#include <sys/mount.h>
541573Srgrimes#include <sys/mutex.h>
551573Srgrimes#include <sys/proc.h>
561573Srgrimes#include <sys/signalvar.h>
571573Srgrimes#include <sys/syscallsubr.h>
581573Srgrimes#include <sys/sysctl.h>
591573Srgrimes#include <sys/syslog.h>
601573Srgrimes#include <sys/vnode.h>
611573Srgrimes
621573Srgrimes#include <rpc/rpc.h>
631573Srgrimes
6471579Sdeischen#include <kgssapi/krb5/kcrypto.h>
651573Srgrimes
6671579Sdeischen#include <fs/nfs/nfsport.h>
671573Srgrimes
681573Srgrimes#ifdef KDTRACE_HOOKS
691573Srgrimes#include <sys/dtrace_bsd.h>
701573Srgrimes
711573Srgrimesdtrace_nfsclient_nfs23_start_probe_func_t
721573Srgrimes		dtrace_nfscl_nfs234_start_probe;
7384922Sdfr
7484922Sdfrdtrace_nfsclient_nfs23_done_probe_func_t
7584922Sdfr		dtrace_nfscl_nfs234_done_probe;
7684922Sdfr
7784922Sdfr/*
7884922Sdfr * Registered probes by RPC type.
7984922Sdfr */
8084922Sdfruint32_t	nfscl_nfs2_start_probes[NFS_NPROCS + 1];
8184922Sdfruint32_t	nfscl_nfs2_done_probes[NFS_NPROCS + 1];
8284922Sdfr
8384922Sdfruint32_t	nfscl_nfs3_start_probes[NFS_NPROCS + 1];
8484922Sdfruint32_t	nfscl_nfs3_done_probes[NFS_NPROCS + 1];
8584922Sdfr
8684922Sdfruint32_t	nfscl_nfs4_start_probes[NFS_NPROCS + 1];
8784922Sdfruint32_t	nfscl_nfs4_done_probes[NFS_NPROCS + 1];
8884922Sdfr#endif
8984922Sdfr
9084922SdfrNFSSTATESPINLOCK;
9184922SdfrNFSREQSPINLOCK;
9216586Sjraynardextern struct nfsstats newnfsstats;
9381975Skrisextern struct nfsreqhead nfsd_reqq;
9416586Sjraynardextern int nfscl_ticks;
9516586Sjraynardextern void (*ncl_call_invalcaches)(struct vnode *);
9684922Sdfr
9721674Sjkhstatic int	nfsrv_gsscallbackson = 0;
9816586Sjraynardstatic int	nfs_bufpackets = 4;
991573Srgrimesstatic int	nfs_reconnects;
1001573Srgrimesstatic int	nfs3_jukebox_delay = 10;
1011573Srgrimesstatic int	nfs_skip_wcc_data_onerr = 1;
1021573Srgrimesstatic int	nfs_keytab_enctype = ETYPE_DES_CBC_CRC;
1031573Srgrimes
10471579SdeischenSYSCTL_DECL(_vfs_nfs);
1051573Srgrimes
10671579SdeischenSYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0,
1071573Srgrimes    "Buffer reservation size 2 < x < 64");
1081573SrgrimesSYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0,
1091573Srgrimes    "Number of times the nfs client has had to reconnect");
1101573SrgrimesSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0,
1111573Srgrimes    "Number of seconds to delay a retry after receiving EJUKEBOX");
1121573SrgrimesSYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0,
1131573Srgrimes    "Disable weak cache consistency checking when server returns an error");
1141573SrgrimesSYSCTL_INT(_vfs_nfs, OID_AUTO, keytab_enctype, CTLFLAG_RW, &nfs_keytab_enctype, 0,
1151573Srgrimes    "Encryption type for the keytab entry used by nfs");
1161573Srgrimes
1171573Srgrimesstatic void	nfs_down(struct nfsmount *, struct thread *, const char *,
1181573Srgrimes    int, int);
1191573Srgrimesstatic void	nfs_up(struct nfsmount *, struct thread *, const char *,
1201573Srgrimes    int, int);
1211573Srgrimesstatic int	nfs_msg(struct thread *, const char *, const char *, int);
1221573Srgrimes
1231573Srgrimesstruct nfs_cached_auth {
12471579Sdeischen	int		ca_refs; /* refcount, including 1 from the cache */
1251573Srgrimes	uid_t		ca_uid;	 /* uid that corresponds to this auth */
1261573Srgrimes	AUTH		*ca_auth; /* RPC auth handle */
1271573Srgrimes};
1281573Srgrimes
1291573Srgrimesstatic int nfsv2_procid[NFS_V3NPROCS] = {
1301573Srgrimes	NFSV2PROC_NULL,
1311573Srgrimes	NFSV2PROC_GETATTR,
1321573Srgrimes	NFSV2PROC_SETATTR,
1331573Srgrimes	NFSV2PROC_LOOKUP,
1341573Srgrimes	NFSV2PROC_NOOP,
1351573Srgrimes	NFSV2PROC_READLINK,
1361573Srgrimes	NFSV2PROC_READ,
1371573Srgrimes	NFSV2PROC_WRITE,
1381573Srgrimes	NFSV2PROC_CREATE,
1391573Srgrimes	NFSV2PROC_MKDIR,
1401573Srgrimes	NFSV2PROC_SYMLINK,
1411573Srgrimes	NFSV2PROC_CREATE,
14271579Sdeischen	NFSV2PROC_REMOVE,
14371579Sdeischen	NFSV2PROC_RMDIR,
1441573Srgrimes	NFSV2PROC_RENAME,
1451573Srgrimes	NFSV2PROC_LINK,
1461573Srgrimes	NFSV2PROC_READDIR,
1471573Srgrimes	NFSV2PROC_NOOP,
1481573Srgrimes	NFSV2PROC_STATFS,
1491573Srgrimes	NFSV2PROC_NOOP,
1501573Srgrimes	NFSV2PROC_NOOP,
1511573Srgrimes	NFSV2PROC_NOOP,
1521573Srgrimes};
1531573Srgrimes
1541573Srgrimes/*
1551573Srgrimes * Initialize sockets and congestion for a new NFS connection.
1561573Srgrimes * We do not free the sockaddr if error.
1571573Srgrimes */
1581573Srgrimesint
1591573Srgrimesnewnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
1601573Srgrimes    struct ucred *cred, NFSPROC_T *p, int callback_retry_mult)
1611573Srgrimes{
1621573Srgrimes	int rcvreserve, sndreserve;
1631573Srgrimes	int pktscale;
16471579Sdeischen	struct sockaddr *saddr;
1651573Srgrimes	struct ucred *origcred;
1661573Srgrimes	CLIENT *client;
1671573Srgrimes	struct netconfig *nconf;
1681573Srgrimes	struct socket *so;
1691573Srgrimes	int one = 1, retries, error = 0;
1701573Srgrimes	struct thread *td = curthread;
1711573Srgrimes
1721573Srgrimes	/*
1731573Srgrimes	 * We need to establish the socket using the credentials of
1741573Srgrimes	 * the mountpoint.  Some parts of this process (such as
1751573Srgrimes	 * sobind() and soconnect()) will use the curent thread's
1761573Srgrimes	 * credential instead of the socket credential.  To work
1771573Srgrimes	 * around this, temporarily change the current thread's
1781573Srgrimes	 * credential to that of the mountpoint.
1791573Srgrimes	 *
1801573Srgrimes	 * XXX: It would be better to explicitly pass the correct
1811573Srgrimes	 * credential to sobind() and soconnect().
1821573Srgrimes	 */
1831573Srgrimes	origcred = td->td_ucred;
1841573Srgrimes
1851573Srgrimes	/*
1861573Srgrimes	 * Use the credential in nr_cred, if not NULL.
1871573Srgrimes	 */
1881573Srgrimes	if (nrp->nr_cred != NULL)
1891573Srgrimes		td->td_ucred = nrp->nr_cred;
1901573Srgrimes	else
1911573Srgrimes		td->td_ucred = cred;
1921573Srgrimes	saddr = nrp->nr_nam;
1931573Srgrimes
1941573Srgrimes	if (saddr->sa_family == AF_INET)
1951573Srgrimes		if (nrp->nr_sotype == SOCK_DGRAM)
1961573Srgrimes			nconf = getnetconfigent("udp");
1971573Srgrimes		else
1981573Srgrimes			nconf = getnetconfigent("tcp");
1991573Srgrimes	else
2001573Srgrimes		if (nrp->nr_sotype == SOCK_DGRAM)
2011573Srgrimes			nconf = getnetconfigent("udp6");
2021573Srgrimes		else
2031573Srgrimes			nconf = getnetconfigent("tcp6");
2041573Srgrimes
2051573Srgrimes	pktscale = nfs_bufpackets;
2061573Srgrimes	if (pktscale < 2)
2071573Srgrimes		pktscale = 2;
2081573Srgrimes	if (pktscale > 64)
2091573Srgrimes		pktscale = 64;
2101573Srgrimes	/*
2111573Srgrimes	 * soreserve() can fail if sb_max is too small, so shrink pktscale
2121573Srgrimes	 * and try again if there is an error.
2131573Srgrimes	 * Print a log message suggesting increasing sb_max.
2141573Srgrimes	 * Creating a socket and doing this is necessary since, if the
2151573Srgrimes	 * reservation sizes are too large and will make soreserve() fail,
2161573Srgrimes	 * the connection will work until a large send is attempted and
2171573Srgrimes	 * then it will loop in the krpc code.
2181573Srgrimes	 */
2191573Srgrimes	so = NULL;
22071579Sdeischen	saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *);
2211573Srgrimes	error = socreate(saddr->sa_family, &so, nrp->nr_sotype,
22271579Sdeischen	    nrp->nr_soproto, td->td_ucred, td);
22371579Sdeischen	if (error) {
2241573Srgrimes		td->td_ucred = origcred;
2251573Srgrimes		goto out;
2261573Srgrimes	}
2271573Srgrimes	do {
2281573Srgrimes	    if (error != 0 && pktscale > 2)
2291573Srgrimes		pktscale--;
2301573Srgrimes	    if (nrp->nr_sotype == SOCK_DGRAM) {
2311573Srgrimes		if (nmp != NULL) {
2321573Srgrimes			sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
2331573Srgrimes			    pktscale;
2341573Srgrimes			rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
2351573Srgrimes			    pktscale;
2361573Srgrimes		} else {
2371573Srgrimes			sndreserve = rcvreserve = 1024 * pktscale;
2381573Srgrimes		}
2391573Srgrimes	    } else {
2401573Srgrimes		if (nrp->nr_sotype != SOCK_STREAM)
2411573Srgrimes			panic("nfscon sotype");
2421573Srgrimes		if (nmp != NULL) {
2431573Srgrimes			sndreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR +
2441573Srgrimes			    sizeof (u_int32_t)) * pktscale;
2451573Srgrimes			rcvreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR +
2461573Srgrimes			    sizeof (u_int32_t)) * pktscale;
2471573Srgrimes		} else {
2481573Srgrimes			sndreserve = rcvreserve = 1024 * pktscale;
2491573Srgrimes		}
2501573Srgrimes	    }
2511573Srgrimes	    error = soreserve(so, sndreserve, rcvreserve);
2521573Srgrimes	} while (error != 0 && pktscale > 2);
2531573Srgrimes	soclose(so);
2541573Srgrimes	if (error) {
2551573Srgrimes		td->td_ucred = origcred;
2561573Srgrimes		goto out;
2571573Srgrimes	}
2581573Srgrimes
2591573Srgrimes	client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog,
2601573Srgrimes	    nrp->nr_vers, sndreserve, rcvreserve);
2611573Srgrimes	CLNT_CONTROL(client, CLSET_WAITCHAN, "newnfsreq");
2621573Srgrimes	if (nmp != NULL) {
2631573Srgrimes		if ((nmp->nm_flag & NFSMNT_INT))
2641573Srgrimes			CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
2651573Srgrimes		if ((nmp->nm_flag & NFSMNT_RESVPORT))
2661573Srgrimes			CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
2671573Srgrimes		if (NFSHASSOFT(nmp))
26871579Sdeischen			retries = nmp->nm_retry;
26971579Sdeischen		else
27071579Sdeischen			retries = INT_MAX;
27171579Sdeischen	} else {
27271579Sdeischen		/*
27371579Sdeischen		 * Three cases:
27471579Sdeischen		 * - Null RPC callback to client
27571579Sdeischen		 * - Non-Null RPC callback to client, wait a little longer
27671579Sdeischen		 * - upcalls to nfsuserd and gssd (clp == NULL)
27771579Sdeischen		 */
27871579Sdeischen		if (callback_retry_mult == 0) {
27971579Sdeischen			retries = NFSV4_UPCALLRETRY;
28071579Sdeischen			CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
28171579Sdeischen		} else {
2821573Srgrimes			retries = NFSV4_CALLBACKRETRY * callback_retry_mult;
28372291Sache		}
2841573Srgrimes	}
2851573Srgrimes	CLNT_CONTROL(client, CLSET_RETRIES, &retries);
2861573Srgrimes
2871573Srgrimes	mtx_lock(&nrp->nr_mtx);
2881573Srgrimes	if (nrp->nr_client != NULL) {
2891573Srgrimes		/*
29072523Stegge		 * Someone else already connected.
2911573Srgrimes		 */
2921573Srgrimes		CLNT_RELEASE(client);
2931573Srgrimes	} else {
2941573Srgrimes		nrp->nr_client = client;
2951573Srgrimes	}
2961573Srgrimes
2971573Srgrimes	/*
2981573Srgrimes	 * Protocols that do not require connections may be optionally left
29921674Sjkh	 * unconnected for servers that reply from a port other than NFS_PORT.
3001573Srgrimes	 */
3011573Srgrimes	if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) {
3021573Srgrimes		mtx_unlock(&nrp->nr_mtx);
3031573Srgrimes		CLNT_CONTROL(client, CLSET_CONNECT, &one);
3041573Srgrimes	} else {
3051573Srgrimes		mtx_unlock(&nrp->nr_mtx);
3061573Srgrimes	}
30731871Sbde
3081573Srgrimes	/* Restore current thread's credentials. */
3091573Srgrimes	td->td_ucred = origcred;
3101573Srgrimes
3111573Srgrimesout:
3121573Srgrimes	NFSEXITCODE(error);
31371579Sdeischen	return (error);
31471579Sdeischen}
31571579Sdeischen
3161573Srgrimes/*
31771579Sdeischen * NFS disconnect. Clean up and unlink.
3181573Srgrimes */
31971579Sdeischenvoid
32071579Sdeischennewnfs_disconnect(struct nfssockreq *nrp)
32171579Sdeischen{
32271579Sdeischen	CLIENT *client;
32371579Sdeischen
32471579Sdeischen	mtx_lock(&nrp->nr_mtx);
3251573Srgrimes	if (nrp->nr_client != NULL) {
3261573Srgrimes		client = nrp->nr_client;
3271573Srgrimes		nrp->nr_client = NULL;
3281573Srgrimes		mtx_unlock(&nrp->nr_mtx);
3291573Srgrimes		rpc_gss_secpurge_call(client);
33072291Sache		CLNT_CLOSE(client);
3311573Srgrimes		CLNT_RELEASE(client);
3321573Srgrimes	} else {
3331573Srgrimes		mtx_unlock(&nrp->nr_mtx);
3341573Srgrimes	}
3351573Srgrimes}
3361573Srgrimes
33772523Steggestatic AUTH *
3381573Srgrimesnfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal,
3391573Srgrimes    char *srv_principal, gss_OID mech_oid, struct ucred *cred)
3401573Srgrimes{
3411573Srgrimes	rpc_gss_service_t svc;
3421573Srgrimes	AUTH *auth;
34314727Sfenner#ifdef notyet
3441573Srgrimes	rpc_gss_options_req_t req_options;
34531983Sache#endif
3461573Srgrimes
3471573Srgrimes	switch (secflavour) {
3481573Srgrimes	case RPCSEC_GSS_KRB5:
3491573Srgrimes	case RPCSEC_GSS_KRB5I:
3501573Srgrimes	case RPCSEC_GSS_KRB5P:
3511573Srgrimes		if (!mech_oid) {
35284922Sdfr			if (!rpc_gss_mech_to_oid_call("kerberosv5", &mech_oid))
35384922Sdfr				return (NULL);
35421674Sjkh		}
35521674Sjkh		if (secflavour == RPCSEC_GSS_KRB5)
3561573Srgrimes			svc = rpc_gss_svc_none;
3571573Srgrimes		else if (secflavour == RPCSEC_GSS_KRB5I)
3581573Srgrimes			svc = rpc_gss_svc_integrity;
3591573Srgrimes		else
3601573Srgrimes			svc = rpc_gss_svc_privacy;
3611573Srgrimes#ifdef notyet
3621573Srgrimes		req_options.req_flags = GSS_C_MUTUAL_FLAG;
3631573Srgrimes		req_options.time_req = 0;
3641573Srgrimes		req_options.my_cred = GSS_C_NO_CREDENTIAL;
3651573Srgrimes		req_options.input_channel_bindings = NULL;
3661573Srgrimes		req_options.enc_type = nfs_keytab_enctype;
3671573Srgrimes
3681573Srgrimes		auth = rpc_gss_secfind_call(nrp->nr_client, cred,
3691573Srgrimes		    clnt_principal, srv_principal, mech_oid, svc,
3701573Srgrimes		    &req_options);
3711573Srgrimes#else
3721573Srgrimes		/*
3731573Srgrimes		 * Until changes to the rpcsec_gss code are committed,
3741573Srgrimes		 * there is no support for host based initiator
3751573Srgrimes		 * principals. As such, that case cannot yet be handled.
3761573Srgrimes		 */
3771573Srgrimes		if (clnt_principal == NULL)
3781573Srgrimes			auth = rpc_gss_secfind_call(nrp->nr_client, cred,
3791573Srgrimes			    srv_principal, mech_oid, svc);
3801573Srgrimes		else
3811573Srgrimes			auth = NULL;
3821573Srgrimes#endif
3831573Srgrimes		if (auth != NULL)
3841573Srgrimes			return (auth);
3851573Srgrimes		/* fallthrough */
3861573Srgrimes	case AUTH_SYS:
3871573Srgrimes	default:
3881573Srgrimes		return (authunix_create(cred));
3891573Srgrimes
3901573Srgrimes	}
3911573Srgrimes}
3921573Srgrimes
3931573Srgrimes/*
3941573Srgrimes * Callback from the RPC code to generate up/down notifications.
3951573Srgrimes */
3961573Srgrimes
3971573Srgrimesstruct nfs_feedback_arg {
39821674Sjkh	struct nfsmount *nf_mount;
39921674Sjkh	int		nf_lastmsg;	/* last tprintf */
40021674Sjkh	int		nf_tprintfmsg;
40121674Sjkh	struct thread	*nf_td;
40221674Sjkh};
40321674Sjkh
40484922Sdfrstatic void
40521674Sjkhnfs_feedback(int type, int proc, void *arg)
40621674Sjkh{
4071573Srgrimes	struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg;
4081573Srgrimes	struct nfsmount *nmp = nf->nf_mount;
4091573Srgrimes	struct timeval now;
4101573Srgrimes
4111573Srgrimes	getmicrouptime(&now);
41221674Sjkh
41321674Sjkh	switch (type) {
41421674Sjkh	case FEEDBACK_REXMIT2:
4151573Srgrimes	case FEEDBACK_RECONNECT:
41621674Sjkh		if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) {
41721674Sjkh			nfs_down(nmp, nf->nf_td,
41821674Sjkh			    "not responding", 0, NFSSTA_TIMEO);
4191573Srgrimes			nf->nf_tprintfmsg = TRUE;
42021674Sjkh			nf->nf_lastmsg = now.tv_sec;
42121674Sjkh		}
42221674Sjkh		break;
42321674Sjkh
42421674Sjkh	case FEEDBACK_OK:
42521674Sjkh		nfs_up(nf->nf_mount, nf->nf_td,
42621674Sjkh		    "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg);
42721674Sjkh		break;
42821674Sjkh	}
42921674Sjkh}
43021674Sjkh
43121674Sjkh/*
43221674Sjkh * newnfs_request - goes something like this
43321674Sjkh *	- does the rpc by calling the krpc layer
43421674Sjkh *	- break down rpc header and return with nfs reply
43521674Sjkh * nb: always frees up nd_mreq mbuf list
43621674Sjkh */
43721674Sjkhint
43821674Sjkhnewnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
43921674Sjkh    struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp,
44021674Sjkh    struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
44121674Sjkh    u_char *retsum, int toplevel, u_int64_t *xidp)
44221674Sjkh{
44321674Sjkh	u_int32_t *tl;
44421674Sjkh	time_t waituntil;
44521674Sjkh	int i, j, set_uid = 0, set_sigset = 0;
44672523Stegge	int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS;
44772523Stegge	u_int16_t procnum;
44872523Stegge	u_int trylater_delay = 1;
4491573Srgrimes	struct nfs_feedback_arg nf;
45071579Sdeischen	struct timeval timo, now;
4511573Srgrimes	AUTH *auth;
4521573Srgrimes	struct rpc_callextra ext;
4531573Srgrimes	enum clnt_stat stat;
4541573Srgrimes	struct nfsreq *rep = NULL;
45571579Sdeischen	char *srv_principal = NULL;
4561573Srgrimes	uid_t saved_uid = (uid_t)-1;
4571573Srgrimes	sigset_t oldset;
4581573Srgrimes
45921674Sjkh	if (xidp != NULL)
46021674Sjkh		*xidp = 0;
46121674Sjkh	/* Reject requests while attempting a forced unmount. */
4621573Srgrimes	if (nmp != NULL && (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)) {
4631573Srgrimes		m_freem(nd->nd_mreq);
4641573Srgrimes		return (ESTALE);
4651573Srgrimes	}
4661573Srgrimes
4671573Srgrimes	/* For client side interruptible mounts, mask off the signals. */
4681573Srgrimes	if (nmp != NULL && td != NULL && NFSHASINT(nmp)) {
4691573Srgrimes		newnfs_set_sigmask(td, &oldset);
4701573Srgrimes		set_sigset = 1;
4711573Srgrimes	}
4721573Srgrimes
4731573Srgrimes	/*
47432253Sache	 * XXX if not already connected call nfs_connect now. Longer
47531983Sache	 * term, change nfs_mount to call nfs_connect unconditionally
47631983Sache	 * and let clnt_reconnect_create handle reconnects.
47731983Sache	 */
4781573Srgrimes	if (nrp->nr_client == NULL)
4791573Srgrimes		newnfs_connect(nmp, nrp, cred, td, 0);
4801573Srgrimes
4811573Srgrimes	/*
4821573Srgrimes	 * For a client side mount, nmp is != NULL and clp == NULL. For
4831573Srgrimes	 * server calls (callbacks or upcalls), nmp == NULL.
4841573Srgrimes	 */
4851573Srgrimes	if (clp != NULL) {
4861573Srgrimes		NFSLOCKSTATE();
4871573Srgrimes		if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) {
4881573Srgrimes			secflavour = RPCSEC_GSS_KRB5;
4891573Srgrimes			if (nd->nd_procnum != NFSPROC_NULL) {
4901573Srgrimes				if (clp->lc_flags & LCL_GSSINTEGRITY)
4911573Srgrimes					secflavour = RPCSEC_GSS_KRB5I;
4921573Srgrimes				else if (clp->lc_flags & LCL_GSSPRIVACY)
4931573Srgrimes					secflavour = RPCSEC_GSS_KRB5P;
4941573Srgrimes			}
4951573Srgrimes		}
4961573Srgrimes		NFSUNLOCKSTATE();
4971573Srgrimes	} else if (nmp != NULL && NFSHASKERB(nmp) &&
4981573Srgrimes	     nd->nd_procnum != NFSPROC_NULL) {
4991573Srgrimes		if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0)
5001573Srgrimes			nd->nd_flag |= ND_USEGSSNAME;
5011573Srgrimes		if ((nd->nd_flag & ND_USEGSSNAME) != 0) {
5021573Srgrimes			/*
5031573Srgrimes			 * If there is a client side host based credential,
5041573Srgrimes			 * use that, otherwise use the system uid, if set.
5051573Srgrimes			 */
5061573Srgrimes			if (nmp->nm_krbnamelen > 0) {
5071573Srgrimes				usegssname = 1;
5081573Srgrimes			} else if (nmp->nm_uid != (uid_t)-1) {
5091573Srgrimes				saved_uid = cred->cr_uid;
5101573Srgrimes				cred->cr_uid = nmp->nm_uid;
5111573Srgrimes				set_uid = 1;
51221674Sjkh			}
51321674Sjkh		} else if (nmp->nm_krbnamelen == 0 &&
5141573Srgrimes		    nmp->nm_uid != (uid_t)-1 && cred->cr_uid == (uid_t)0) {
5151573Srgrimes			/*
5161573Srgrimes			 * If there is no host based principal name and
5171573Srgrimes			 * the system uid is set and this is root, use the
5181573Srgrimes			 * system uid, since root won't have user
5191573Srgrimes			 * credentials in a credentials cache file.
5201573Srgrimes			 */
5211573Srgrimes			saved_uid = cred->cr_uid;
5221573Srgrimes			cred->cr_uid = nmp->nm_uid;
5231573Srgrimes			set_uid = 1;
5241573Srgrimes		}
52521674Sjkh		if (NFSHASINTEGRITY(nmp))
5261573Srgrimes			secflavour = RPCSEC_GSS_KRB5I;
5271573Srgrimes		else if (NFSHASPRIVACY(nmp))
5281573Srgrimes			secflavour = RPCSEC_GSS_KRB5P;
5291573Srgrimes		else
5301573Srgrimes			secflavour = RPCSEC_GSS_KRB5;
5311573Srgrimes		srv_principal = NFSMNT_SRVKRBNAME(nmp);
5321573Srgrimes	} else if (nmp != NULL && !NFSHASKERB(nmp) &&
5331573Srgrimes	    nd->nd_procnum != NFSPROC_NULL &&
5341573Srgrimes	    (nd->nd_flag & ND_USEGSSNAME) != 0) {
5351573Srgrimes		/*
5361573Srgrimes		 * Use the uid that did the mount when the RPC is doing
5371573Srgrimes		 * NFSv4 system operations, as indicated by the
5381573Srgrimes		 * ND_USEGSSNAME flag, for the AUTH_SYS case.
5391573Srgrimes		 */
5401573Srgrimes		saved_uid = cred->cr_uid;
5411573Srgrimes		if (nmp->nm_uid != (uid_t)-1)
5421573Srgrimes			cred->cr_uid = nmp->nm_uid;
5431573Srgrimes		else
5441573Srgrimes			cred->cr_uid = 0;
5451573Srgrimes		set_uid = 1;
5461573Srgrimes	}
5471573Srgrimes
5481573Srgrimes	if (nmp != NULL) {
5491573Srgrimes		bzero(&nf, sizeof(struct nfs_feedback_arg));
5501573Srgrimes		nf.nf_mount = nmp;
55121674Sjkh		nf.nf_td = td;
55221674Sjkh		getmicrouptime(&now);
55321674Sjkh		nf.nf_lastmsg = now.tv_sec -
55421674Sjkh		    ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay));
55521674Sjkh	}
55621674Sjkh
55721674Sjkh	if (nd->nd_procnum == NFSPROC_NULL)
55821674Sjkh		auth = authnone_create();
55921674Sjkh	else if (usegssname)
5601573Srgrimes		auth = nfs_getauth(nrp, secflavour, nmp->nm_krbname,
5611573Srgrimes		    srv_principal, NULL, cred);
5621573Srgrimes	else
5631573Srgrimes		auth = nfs_getauth(nrp, secflavour, NULL,
5641573Srgrimes		    srv_principal, NULL, cred);
5651573Srgrimes	if (set_uid)
5661573Srgrimes		cred->cr_uid = saved_uid;
5671573Srgrimes	if (auth == NULL) {
5681573Srgrimes		m_freem(nd->nd_mreq);
5691573Srgrimes		if (set_sigset)
5701573Srgrimes			newnfs_restore_sigmask(td, &oldset);
57144674Sdfr		return (EACCES);
57244674Sdfr	}
57344674Sdfr	bzero(&ext, sizeof(ext));
57444674Sdfr	ext.rc_auth = auth;
5751573Srgrimes	if (nmp != NULL) {
5761573Srgrimes		ext.rc_feedback = nfs_feedback;
5771573Srgrimes		ext.rc_feedback_arg = &nf;
5781573Srgrimes	}
5791573Srgrimes
58021674Sjkh	procnum = nd->nd_procnum;
5811573Srgrimes	if ((nd->nd_flag & ND_NFSV4) &&
5821573Srgrimes	    nd->nd_procnum != NFSPROC_NULL &&
5831573Srgrimes	    nd->nd_procnum != NFSV4PROC_CBCOMPOUND)
5841573Srgrimes		procnum = NFSV4PROC_COMPOUND;
5851573Srgrimes
5861573Srgrimes	if (nmp != NULL) {
5871573Srgrimes		NFSINCRGLOBAL(newnfsstats.rpcrequests);
5881573Srgrimes
5891573Srgrimes		/* Map the procnum to the old NFSv2 one, as required. */
59021674Sjkh		if ((nd->nd_flag & ND_NFSV2) != 0) {
5911573Srgrimes			if (nd->nd_procnum < NFS_V3NPROCS)
5921573Srgrimes				procnum = nfsv2_procid[nd->nd_procnum];
5931573Srgrimes			else
5941573Srgrimes				procnum = NFSV2PROC_NOOP;
5951573Srgrimes		}
5961573Srgrimes
5971573Srgrimes		/*
5981573Srgrimes		 * Now only used for the R_DONTRECOVER case, but until that is
5991573Srgrimes		 * supported within the krpc code, I need to keep a queue of
6001573Srgrimes		 * outstanding RPCs for nfsv4 client requests.
6011573Srgrimes		 */
6021573Srgrimes		if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND)
6031573Srgrimes			MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq),
6041573Srgrimes			    M_NFSDREQ, M_WAITOK);
6057033Sbde#ifdef KDTRACE_HOOKS
6061573Srgrimes		if (dtrace_nfscl_nfs234_start_probe != NULL) {
6077033Sbde			uint32_t probe_id;
6087033Sbde			int probe_procnum;
6091573Srgrimes
6101573Srgrimes			if (nd->nd_flag & ND_NFSV4) {
6117033Sbde				probe_id =
6127033Sbde				    nfscl_nfs4_start_probes[nd->nd_procnum];
6137033Sbde				probe_procnum = nd->nd_procnum;
6141573Srgrimes			} else if (nd->nd_flag & ND_NFSV3) {
6157033Sbde				probe_id = nfscl_nfs3_start_probes[procnum];
61631871Sbde				probe_procnum = procnum;
61721674Sjkh			} else {
6187033Sbde				probe_id =
61921674Sjkh				    nfscl_nfs2_start_probes[nd->nd_procnum];
6201573Srgrimes				probe_procnum = procnum;
6211573Srgrimes			}
6221573Srgrimes			if (probe_id != 0)
6231573Srgrimes				(dtrace_nfscl_nfs234_start_probe)
6241573Srgrimes				    (probe_id, vp, nd->nd_mreq, cred,
6251573Srgrimes				     probe_procnum);
6261573Srgrimes		}
6271573Srgrimes#endif
6281573Srgrimes	}
6291573Srgrimes	trycnt = 0;
6301573Srgrimestryagain:
6311573Srgrimes	if (nmp == NULL) {
6321573Srgrimes		timo.tv_usec = 0;
6331573Srgrimes		if (clp == NULL)
63472523Stegge			timo.tv_sec = NFSV4_UPCALLTIMEO;
63572523Stegge		else
63672523Stegge			timo.tv_sec = NFSV4_CALLBACKTIMEO;
63772523Stegge	} else {
6381573Srgrimes		if (nrp->nr_sotype != SOCK_DGRAM) {
63972523Stegge			timo.tv_usec = 0;
6401573Srgrimes			if ((nmp->nm_flag & NFSMNT_NFSV4))
6411573Srgrimes				timo.tv_sec = INT_MAX;
6421573Srgrimes			else
6431573Srgrimes				timo.tv_sec = NFS_TCPTIMEO;
6441573Srgrimes		} else {
6458870Srgrimes			timo.tv_sec = nmp->nm_timeo / NFS_HZ;
6461573Srgrimes			timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ;
6471573Srgrimes		}
6481573Srgrimes
6491573Srgrimes		if (rep != NULL) {
6501573Srgrimes			rep->r_flags = 0;
6511573Srgrimes			rep->r_nmp = nmp;
6521573Srgrimes			/*
6531573Srgrimes			 * Chain request into list of outstanding requests.
6541573Srgrimes			 */
6551573Srgrimes			NFSLOCKREQ();
6561573Srgrimes			TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain);
6571573Srgrimes			NFSUNLOCKREQ();
6581573Srgrimes		}
6591573Srgrimes	}
6601573Srgrimes
6611573Srgrimes	nd->nd_mrep = NULL;
6621573Srgrimes	stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, nd->nd_mreq,
6631573Srgrimes	    &nd->nd_mrep, timo);
6641573Srgrimes
6651573Srgrimes	if (rep != NULL) {
6661573Srgrimes		/*
6671573Srgrimes		 * RPC done, unlink the request.
6681573Srgrimes		 */
6691573Srgrimes		NFSLOCKREQ();
6701573Srgrimes		TAILQ_REMOVE(&nfsd_reqq, rep, r_chain);
6711573Srgrimes		NFSUNLOCKREQ();
6721573Srgrimes	}
67331980Sache
6741573Srgrimes	/*
67531980Sache	 * If there was a successful reply and a tprintf msg.
6761573Srgrimes	 * tprintf a response.
67731980Sache	 */
6781573Srgrimes	if (stat == RPC_SUCCESS) {
67931980Sache		error = 0;
6801573Srgrimes	} else if (stat == RPC_TIMEDOUT) {
6811573Srgrimes		error = ETIMEDOUT;
6821573Srgrimes	} else if (stat == RPC_VERSMISMATCH) {
6831573Srgrimes		error = EOPNOTSUPP;
6841573Srgrimes	} else if (stat == RPC_PROGVERSMISMATCH) {
6851573Srgrimes		error = EPROTONOSUPPORT;
68621674Sjkh	} else {
6871573Srgrimes		error = EACCES;
6881573Srgrimes	}
6891573Srgrimes	if (error) {
6901573Srgrimes		m_freem(nd->nd_mreq);
6911573Srgrimes		AUTH_DESTROY(auth);
6921573Srgrimes		if (rep != NULL)
6931573Srgrimes			FREE((caddr_t)rep, M_NFSDREQ);
6941573Srgrimes		if (set_sigset)
6951573Srgrimes			newnfs_restore_sigmask(td, &oldset);
6961573Srgrimes		return (error);
6971573Srgrimes	}
6981573Srgrimes
69921674Sjkh	KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n"));
7001573Srgrimes
7011573Srgrimes	/*
7021573Srgrimes	 * Search for any mbufs that are not a multiple of 4 bytes long
7031573Srgrimes	 * or with m_data not longword aligned.
7041573Srgrimes	 * These could cause pointer alignment problems, so copy them to
7051573Srgrimes	 * well aligned mbufs.
70621674Sjkh	 */
7071573Srgrimes	newnfs_realign(&nd->nd_mrep);
7081573Srgrimes	nd->nd_md = nd->nd_mrep;
7091573Srgrimes	nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
7101573Srgrimes	nd->nd_repstat = 0;
7111573Srgrimes	if (nd->nd_procnum != NFSPROC_NULL) {
7121573Srgrimes		/*
7131573Srgrimes		 * and now the actual NFS xdr.
71416586Sjraynard		 */
7151573Srgrimes		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
7161573Srgrimes		nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl);
7171573Srgrimes		if (nd->nd_repstat != 0) {
7181573Srgrimes			if (((nd->nd_repstat == NFSERR_DELAY ||
7191573Srgrimes			      nd->nd_repstat == NFSERR_GRACE) &&
7201573Srgrimes			     (nd->nd_flag & ND_NFSV4) &&
7211573Srgrimes			     nd->nd_procnum != NFSPROC_DELEGRETURN &&
7221573Srgrimes			     nd->nd_procnum != NFSPROC_SETATTR &&
7231573Srgrimes			     nd->nd_procnum != NFSPROC_READ &&
7241573Srgrimes			     nd->nd_procnum != NFSPROC_WRITE &&
7251573Srgrimes			     nd->nd_procnum != NFSPROC_OPEN &&
7261573Srgrimes			     nd->nd_procnum != NFSPROC_CREATE &&
7271573Srgrimes			     nd->nd_procnum != NFSPROC_OPENCONFIRM &&
7281573Srgrimes			     nd->nd_procnum != NFSPROC_OPENDOWNGRADE &&
7291573Srgrimes			     nd->nd_procnum != NFSPROC_CLOSE &&
7301573Srgrimes			     nd->nd_procnum != NFSPROC_LOCK &&
73121674Sjkh			     nd->nd_procnum != NFSPROC_LOCKU) ||
7321573Srgrimes			    (nd->nd_repstat == NFSERR_DELAY &&
7331573Srgrimes			     (nd->nd_flag & ND_NFSV4) == 0) ||
7341573Srgrimes			    nd->nd_repstat == NFSERR_RESOURCE) {
7351573Srgrimes				if (trylater_delay > NFS_TRYLATERDEL)
7361573Srgrimes					trylater_delay = NFS_TRYLATERDEL;
7371573Srgrimes				waituntil = NFSD_MONOSEC + trylater_delay;
7381573Srgrimes				while (NFSD_MONOSEC < waituntil)
7391573Srgrimes					(void) nfs_catnap(PZERO, 0, "nfstry");
7401573Srgrimes				trylater_delay *= 2;
7411573Srgrimes				m_freem(nd->nd_mrep);
74221674Sjkh				nd->nd_mrep = NULL;
7431573Srgrimes				goto tryagain;
7441573Srgrimes			}
7451573Srgrimes
7461573Srgrimes			/*
7471573Srgrimes			 * If the File Handle was stale, invalidate the
7481573Srgrimes			 * lookup cache, just in case.
7491573Srgrimes			 * (vp != NULL implies a client side call)
7501573Srgrimes			 */
7511573Srgrimes			if (nd->nd_repstat == ESTALE && vp != NULL) {
7521573Srgrimes				cache_purge(vp);
7531573Srgrimes				if (ncl_call_invalcaches != NULL)
7541573Srgrimes					(*ncl_call_invalcaches)(vp);
7551573Srgrimes			}
7561573Srgrimes		}
7571573Srgrimes
7581573Srgrimes		/*
7591573Srgrimes		 * Get rid of the tag, return count, and PUTFH result for V4.
7601573Srgrimes		 */
7611573Srgrimes		if (nd->nd_flag & ND_NFSV4) {
7621573Srgrimes			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
7631573Srgrimes			i = fxdr_unsigned(int, *tl);
7641573Srgrimes			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
7651573Srgrimes			if (error)
7661573Srgrimes				goto nfsmout;
7671573Srgrimes			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
7681573Srgrimes			i = fxdr_unsigned(int, *++tl);
7691573Srgrimes
7701573Srgrimes			/*
7711573Srgrimes			 * If the first op's status is non-zero, mark that
7721573Srgrimes			 * there is no more data to process.
7731573Srgrimes			 */
7741573Srgrimes			if (*++tl)
7751573Srgrimes				nd->nd_flag |= ND_NOMOREDATA;
7761573Srgrimes
7771573Srgrimes			/*
7781573Srgrimes			 * If the first op is Putfh, throw its results away
7791573Srgrimes			 * and toss the op# and status for the first op.
7801573Srgrimes			 */
7811573Srgrimes			if (nmp != NULL && i == NFSV4OP_PUTFH && *tl == 0) {
7821573Srgrimes				NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED);
7831573Srgrimes				i = fxdr_unsigned(int, *tl++);
7841573Srgrimes				j = fxdr_unsigned(int, *tl);
7851573Srgrimes				/*
7861573Srgrimes				 * All Compounds that do an Op that must
7871573Srgrimes				 * be in sequence consist of NFSV4OP_PUTFH
7881573Srgrimes				 * followed by one of these. As such, we
7891573Srgrimes				 * can determine if the seqid# should be
7901573Srgrimes				 * incremented, here.
7911573Srgrimes				 */
7921573Srgrimes				if ((i == NFSV4OP_OPEN ||
7931573Srgrimes				     i == NFSV4OP_OPENCONFIRM ||
7941573Srgrimes				     i == NFSV4OP_OPENDOWNGRADE ||
7951573Srgrimes				     i == NFSV4OP_CLOSE ||
7961573Srgrimes				     i == NFSV4OP_LOCK ||
7971573Srgrimes				     i == NFSV4OP_LOCKU) &&
7981573Srgrimes				    (j == 0 ||
7991573Srgrimes				     (j != NFSERR_STALECLIENTID &&
8001573Srgrimes				      j != NFSERR_STALESTATEID &&
80114727Sfenner				      j != NFSERR_BADSTATEID &&
8021573Srgrimes				      j != NFSERR_BADSEQID &&
80314727Sfenner				      j != NFSERR_BADXDR &&
8041573Srgrimes				      j != NFSERR_RESOURCE &&
80514727Sfenner				      j != NFSERR_NOFILEHANDLE)))
8061573Srgrimes					nd->nd_flag |= ND_INCRSEQID;
80714727Sfenner				/*
8081573Srgrimes				 * If the first op's status is non-zero, mark
80931983Sache				 * that there is no more data to process.
81032253Sache				 */
81131983Sache				if (j)
81231983Sache					nd->nd_flag |= ND_NOMOREDATA;
81331983Sache			}
81431983Sache
8151573Srgrimes			/*
8161573Srgrimes			 * If R_DONTRECOVER is set, replace the stale error
8171573Srgrimes			 * reply, so that recovery isn't initiated.
8181573Srgrimes			 */
8191573Srgrimes			if ((nd->nd_repstat == NFSERR_STALECLIENTID ||
8201573Srgrimes			     nd->nd_repstat == NFSERR_STALESTATEID) &&
8211573Srgrimes			    rep != NULL && (rep->r_flags & R_DONTRECOVER))
8221573Srgrimes				nd->nd_repstat = NFSERR_STALEDONTRECOVER;
8231573Srgrimes		}
8241573Srgrimes	}
8251573Srgrimes
8261573Srgrimes#ifdef KDTRACE_HOOKS
8271573Srgrimes	if (nmp != NULL && dtrace_nfscl_nfs234_done_probe != NULL) {
8281573Srgrimes		uint32_t probe_id;
8291573Srgrimes		int probe_procnum;
8301573Srgrimes
8311573Srgrimes		if (nd->nd_flag & ND_NFSV4) {
8321573Srgrimes			probe_id = nfscl_nfs4_done_probes[nd->nd_procnum];
83314727Sfenner			probe_procnum = nd->nd_procnum;
8341573Srgrimes		} else if (nd->nd_flag & ND_NFSV3) {
8351573Srgrimes			probe_id = nfscl_nfs3_done_probes[procnum];
8361573Srgrimes			probe_procnum = procnum;
8371573Srgrimes		} else {
8381573Srgrimes			probe_id = nfscl_nfs2_done_probes[nd->nd_procnum];
8391573Srgrimes			probe_procnum = procnum;
8401573Srgrimes		}
8411573Srgrimes		if (probe_id != 0)
8427033Sbde			(dtrace_nfscl_nfs234_done_probe)(probe_id, vp,
84372291Sache			    nd->nd_mreq, cred, probe_procnum, 0);
84472291Sache	}
84572291Sache#endif
8461573Srgrimes
8471573Srgrimes	m_freem(nd->nd_mreq);
8481573Srgrimes	AUTH_DESTROY(auth);
84972291Sache	if (rep != NULL)
85072291Sache		FREE((caddr_t)rep, M_NFSDREQ);
8511573Srgrimes	if (set_sigset)
8521573Srgrimes		newnfs_restore_sigmask(td, &oldset);
8531573Srgrimes	return (0);
8541573Srgrimesnfsmout:
8551573Srgrimes	mbuf_freem(nd->nd_mrep);
8561573Srgrimes	mbuf_freem(nd->nd_mreq);
85772291Sache	AUTH_DESTROY(auth);
8581573Srgrimes	if (rep != NULL)
8591573Srgrimes		FREE((caddr_t)rep, M_NFSDREQ);
8601573Srgrimes	if (set_sigset)
86172291Sache		newnfs_restore_sigmask(td, &oldset);
8621573Srgrimes	return (error);
8631573Srgrimes}
8641573Srgrimes
8651573Srgrimes/*
8661573Srgrimes * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
86772291Sache * wait for all requests to complete. This is used by forced unmounts
8681573Srgrimes * to terminate any outstanding RPCs.
8697036Sbde */
8701573Srgrimesint
8711573Srgrimesnewnfs_nmcancelreqs(struct nfsmount *nmp)
8721573Srgrimes{
8731573Srgrimes
8741573Srgrimes	if (nmp->nm_sockreq.nr_client != NULL)
8751573Srgrimes		CLNT_CLOSE(nmp->nm_sockreq.nr_client);
8761573Srgrimes	return (0);
8771573Srgrimes}
8781573Srgrimes
8791573Srgrimes/*
8801573Srgrimes * Any signal that can interrupt an NFS operation in an intr mount
8811573Srgrimes * should be added to this set. SIGSTOP and SIGKILL cannot be masked.
8821573Srgrimes */
8831573Srgrimesint newnfs_sig_set[] = {
8841573Srgrimes	SIGINT,
8851573Srgrimes	SIGTERM,
8861573Srgrimes	SIGHUP,
88731983Sache	SIGKILL,
8881573Srgrimes	SIGSTOP,
8891573Srgrimes	SIGQUIT
8901573Srgrimes};
8911573Srgrimes
8921573Srgrimes/*
8931573Srgrimes * Check to see if one of the signals in our subset is pending on
89472523Stegge * the process (in an intr mount).
89572523Stegge */
89672523Steggestatic int
89772523Steggenfs_sig_pending(sigset_t set)
89813545Sjulian{
89913545Sjulian	int i;
90021674Sjkh
90121674Sjkh	for (i = 0 ; i < sizeof(newnfs_sig_set)/sizeof(int) ; i++)
90213545Sjulian		if (SIGISMEMBER(set, newnfs_sig_set[i]))
9031573Srgrimes			return (1);
9041573Srgrimes	return (0);
9051573Srgrimes}
90621674Sjkh
90721674Sjkh/*
90821674Sjkh * The set/restore sigmask functions are used to (temporarily) overwrite
90921674Sjkh * the process p_sigmask during an RPC call (for example). These are also
91021674Sjkh * used in other places in the NFS client that might tsleep().
91121674Sjkh */
91221674Sjkhvoid
91321674Sjkhnewnfs_set_sigmask(struct thread *td, sigset_t *oldset)
91421674Sjkh{
91521674Sjkh	sigset_t newset;
91621674Sjkh	int i;
91721674Sjkh	struct proc *p;
91821674Sjkh
91921674Sjkh	SIGFILLSET(newset);
92021674Sjkh	if (td == NULL)
92121674Sjkh		td = curthread; /* XXX */
92221674Sjkh	p = td->td_proc;
92321674Sjkh	/* Remove the NFS set of signals from newset */
92421674Sjkh	PROC_LOCK(p);
92521674Sjkh	mtx_lock(&p->p_sigacts->ps_mtx);
92621674Sjkh	for (i = 0 ; i < sizeof(newnfs_sig_set)/sizeof(int) ; i++) {
92721674Sjkh		/*
92821674Sjkh		 * But make sure we leave the ones already masked
92921674Sjkh		 * by the process, ie. remove the signal from the
93021674Sjkh		 * temporary signalmask only if it wasn't already
93170725Sarchie		 * in p_sigmask.
93221674Sjkh		 */
93321674Sjkh		if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) &&
93484922Sdfr		    !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i]))
93521674Sjkh			SIGDELSET(newset, newnfs_sig_set[i]);
93671579Sdeischen	}
93771579Sdeischen	mtx_unlock(&p->p_sigacts->ps_mtx);
93871579Sdeischen	PROC_UNLOCK(p);
93971579Sdeischen	kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0);
94071579Sdeischen}
94121674Sjkh
94221674Sjkhvoid
94321674Sjkhnewnfs_restore_sigmask(struct thread *td, sigset_t *set)
94421674Sjkh{
94521674Sjkh	if (td == NULL)
94621674Sjkh		td = curthread; /* XXX */
94721674Sjkh	kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0);
94821674Sjkh}
94921674Sjkh
95021674Sjkh/*
95121674Sjkh * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the
95221674Sjkh * old one after msleep() returns.
95321674Sjkh */
95470725Sarchieint
95570725Sarchienewnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo)
95621674Sjkh{
95721674Sjkh	sigset_t oldset;
95821674Sjkh	int error;
95921674Sjkh	struct proc *p;
96021674Sjkh
96121674Sjkh	if ((priority & PCATCH) == 0)
96221674Sjkh		return msleep(ident, mtx, priority, wmesg, timo);
96321674Sjkh	if (td == NULL)
96421674Sjkh		td = curthread; /* XXX */
96521674Sjkh	newnfs_set_sigmask(td, &oldset);
96621674Sjkh	error = msleep(ident, mtx, priority, wmesg, timo);
96721674Sjkh	newnfs_restore_sigmask(td, &oldset);
96821674Sjkh	p = td->td_proc;
96921674Sjkh	return (error);
97021674Sjkh}
97121674Sjkh
97221674Sjkh/*
97321674Sjkh * Test for a termination condition pending on the process.
97421674Sjkh * This is used for NFSMNT_INT mounts.
97521674Sjkh */
97621674Sjkhint
97721674Sjkhnewnfs_sigintr(struct nfsmount *nmp, struct thread *td)
97821674Sjkh{
97921674Sjkh	struct proc *p;
98021674Sjkh	sigset_t tmpset;
98121674Sjkh
98221674Sjkh	/* Terminate all requests while attempting a forced unmount. */
98321674Sjkh	if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
98421674Sjkh		return (EIO);
98521674Sjkh	if (!(nmp->nm_flag & NFSMNT_INT))
98621674Sjkh		return (0);
98721674Sjkh	if (td == NULL)
98821674Sjkh		return (0);
98921674Sjkh	p = td->td_proc;
99021674Sjkh	PROC_LOCK(p);
99121674Sjkh	tmpset = p->p_siglist;
99221674Sjkh	SIGSETOR(tmpset, td->td_siglist);
99321674Sjkh	SIGSETNAND(tmpset, td->td_sigmask);
99421674Sjkh	mtx_lock(&p->p_sigacts->ps_mtx);
99521674Sjkh	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
99621674Sjkh	mtx_unlock(&p->p_sigacts->ps_mtx);
99721674Sjkh	if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist))
99821674Sjkh	    && nfs_sig_pending(tmpset)) {
99921674Sjkh		PROC_UNLOCK(p);
100021674Sjkh		return (EINTR);
100121674Sjkh	}
100221674Sjkh	PROC_UNLOCK(p);
100321674Sjkh	return (0);
100421674Sjkh}
100521674Sjkh
100621674Sjkhstatic int
100721674Sjkhnfs_msg(struct thread *td, const char *server, const char *msg, int error)
100821674Sjkh{
100921674Sjkh	struct proc *p;
101021674Sjkh
101121674Sjkh	p = td ? td->td_proc : NULL;
101221674Sjkh	if (error) {
101321674Sjkh		tprintf(p, LOG_INFO, "newnfs server %s: %s, error %d\n",
101421674Sjkh		    server, msg, error);
101521674Sjkh	} else {
101621674Sjkh		tprintf(p, LOG_INFO, "newnfs server %s: %s\n", server, msg);
101721674Sjkh	}
101821674Sjkh	return (0);
101921674Sjkh}
102021674Sjkh
102121674Sjkhstatic void
102221674Sjkhnfs_down(struct nfsmount *nmp, struct thread *td, const char *msg,
102321674Sjkh    int error, int flags)
102421674Sjkh{
102521674Sjkh	if (nmp == NULL)
102621674Sjkh		return;
102721674Sjkh	mtx_lock(&nmp->nm_mtx);
102821674Sjkh	if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) {
102921674Sjkh		nmp->nm_state |= NFSSTA_TIMEO;
103021674Sjkh		mtx_unlock(&nmp->nm_mtx);
103121674Sjkh		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
103221674Sjkh		    VQ_NOTRESP, 0);
103321674Sjkh	} else
103421674Sjkh		mtx_unlock(&nmp->nm_mtx);
103521674Sjkh	mtx_lock(&nmp->nm_mtx);
103621674Sjkh	if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
103721674Sjkh		nmp->nm_state |= NFSSTA_LOCKTIMEO;
103821674Sjkh		mtx_unlock(&nmp->nm_mtx);
10391573Srgrimes		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
104021674Sjkh		    VQ_NOTRESPLOCK, 0);
104121674Sjkh	} else
104221674Sjkh		mtx_unlock(&nmp->nm_mtx);
104321674Sjkh	nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error);
104421674Sjkh}
104521674Sjkh
104621674Sjkhstatic void
104721674Sjkhnfs_up(struct nfsmount *nmp, struct thread *td, const char *msg,
104844674Sdfr    int flags, int tprintfmsg)
104944674Sdfr{
105044674Sdfr	if (nmp == NULL)
105144674Sdfr		return;
105221674Sjkh	if (tprintfmsg) {
105321674Sjkh		nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0);
105421674Sjkh	}
105521674Sjkh
105621674Sjkh	mtx_lock(&nmp->nm_mtx);
105721674Sjkh	if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) {
105821674Sjkh		nmp->nm_state &= ~NFSSTA_TIMEO;
105921674Sjkh		mtx_unlock(&nmp->nm_mtx);
106021674Sjkh		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
106121674Sjkh		    VQ_NOTRESP, 1);
106221674Sjkh	} else
106321674Sjkh		mtx_unlock(&nmp->nm_mtx);
106421674Sjkh
106521674Sjkh	mtx_lock(&nmp->nm_mtx);
106621674Sjkh	if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) {
106721674Sjkh		nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
106821674Sjkh		mtx_unlock(&nmp->nm_mtx);
106921674Sjkh		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
107021674Sjkh		    VQ_NOTRESPLOCK, 1);
107121674Sjkh	} else
107221674Sjkh		mtx_unlock(&nmp->nm_mtx);
107321674Sjkh}
107421674Sjkh
107521674Sjkh