xref: /freebsd/sys/fs/nfs/nfs_commonkrpc.c (revision 4517fbfd4251180147082f94253c4347fa44f570)
19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
49ec7b004SRick Macklem  * Copyright (c) 1989, 1991, 1993, 1995
59ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
69ec7b004SRick Macklem  *
79ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem  *
109ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem  * are met:
139ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem  *    without specific prior written permission.
219ec7b004SRick Macklem  *
229ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem  * SUCH DAMAGE.
339ec7b004SRick Macklem  *
349ec7b004SRick Macklem  */
359ec7b004SRick Macklem 
369ec7b004SRick Macklem #include <sys/cdefs.h>
379ec7b004SRick Macklem /*
389ec7b004SRick Macklem  * Socket operations for use by nfs
399ec7b004SRick Macklem  */
409ec7b004SRick Macklem 
419ec7b004SRick Macklem #include "opt_kgssapi.h"
429ec7b004SRick Macklem #include "opt_nfs.h"
439ec7b004SRick Macklem 
449ec7b004SRick Macklem #include <sys/param.h>
459ec7b004SRick Macklem #include <sys/systm.h>
469ec7b004SRick Macklem #include <sys/kernel.h>
479ec7b004SRick Macklem #include <sys/limits.h>
489ec7b004SRick Macklem #include <sys/lock.h>
499ec7b004SRick Macklem #include <sys/malloc.h>
509ec7b004SRick Macklem #include <sys/mbuf.h>
519ec7b004SRick Macklem #include <sys/mount.h>
529ec7b004SRick Macklem #include <sys/mutex.h>
539ec7b004SRick Macklem #include <sys/proc.h>
549ec7b004SRick Macklem #include <sys/signalvar.h>
559ec7b004SRick Macklem #include <sys/syscallsubr.h>
569ec7b004SRick Macklem #include <sys/sysctl.h>
579ec7b004SRick Macklem #include <sys/syslog.h>
589ec7b004SRick Macklem #include <sys/vnode.h>
599ec7b004SRick Macklem 
609ec7b004SRick Macklem #include <rpc/rpc.h>
61c59e4cc3SRick Macklem #include <rpc/krpc.h>
629ec7b004SRick Macklem 
639ec7b004SRick Macklem #include <kgssapi/krb5/kcrypto.h>
649ec7b004SRick Macklem 
659ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
669ec7b004SRick Macklem 
678f0e65c9SRick Macklem #ifdef KDTRACE_HOOKS
688f0e65c9SRick Macklem #include <sys/dtrace_bsd.h>
698f0e65c9SRick Macklem 
708f0e65c9SRick Macklem dtrace_nfsclient_nfs23_start_probe_func_t
718f0e65c9SRick Macklem 		dtrace_nfscl_nfs234_start_probe;
728f0e65c9SRick Macklem 
738f0e65c9SRick Macklem dtrace_nfsclient_nfs23_done_probe_func_t
748f0e65c9SRick Macklem 		dtrace_nfscl_nfs234_done_probe;
758f0e65c9SRick Macklem 
768f0e65c9SRick Macklem /*
778f0e65c9SRick Macklem  * Registered probes by RPC type.
788f0e65c9SRick Macklem  */
791f60bfd8SRick Macklem uint32_t	nfscl_nfs2_start_probes[NFSV41_NPROCS + 1];
801f60bfd8SRick Macklem uint32_t	nfscl_nfs2_done_probes[NFSV41_NPROCS + 1];
818f0e65c9SRick Macklem 
821f60bfd8SRick Macklem uint32_t	nfscl_nfs3_start_probes[NFSV41_NPROCS + 1];
831f60bfd8SRick Macklem uint32_t	nfscl_nfs3_done_probes[NFSV41_NPROCS + 1];
848f0e65c9SRick Macklem 
851f60bfd8SRick Macklem uint32_t	nfscl_nfs4_start_probes[NFSV41_NPROCS + 1];
861f60bfd8SRick Macklem uint32_t	nfscl_nfs4_done_probes[NFSV41_NPROCS + 1];
878f0e65c9SRick Macklem #endif
888f0e65c9SRick Macklem 
899ec7b004SRick Macklem NFSSTATESPINLOCK;
909ec7b004SRick Macklem NFSREQSPINLOCK;
911f60bfd8SRick Macklem NFSDLOCKMUTEX;
92b2fc0141SRick Macklem NFSCLSTATEMUTEX;
93a63b5d48SRick Macklem extern struct nfsstatsv1 nfsstatsv1;
949ec7b004SRick Macklem extern struct nfsreqhead nfsd_reqq;
959ec7b004SRick Macklem extern int nfscl_ticks;
969ec7b004SRick Macklem extern void (*ncl_call_invalcaches)(struct vnode *);
971f60bfd8SRick Macklem extern int nfs_numnfscbd;
981f60bfd8SRick Macklem extern int nfscl_debuglevel;
99cecf6c6eSRick Macklem extern int nfsrv_lease;
1009ec7b004SRick Macklem 
1011f60bfd8SRick Macklem SVCPOOL		*nfscbd_pool;
102c5f4772cSRick Macklem int		nfs_bufpackets = 4;
1039ec7b004SRick Macklem static int	nfsrv_gsscallbackson = 0;
1049ec7b004SRick Macklem static int	nfs_reconnects;
1059ec7b004SRick Macklem static int	nfs3_jukebox_delay = 10;
1069ec7b004SRick Macklem static int	nfs_skip_wcc_data_onerr = 1;
107cecf6c6eSRick Macklem static int	nfs_dsretries = 2;
1085a95a6e8SRick Macklem static struct timespec	nfs_trylater_max = {
1095a95a6e8SRick Macklem 	.tv_sec		= NFS_TRYLATERDEL,
1105a95a6e8SRick Macklem 	.tv_nsec	= 0,
1115a95a6e8SRick Macklem };
1129ec7b004SRick Macklem 
1131f376590SRick Macklem SYSCTL_DECL(_vfs_nfs);
1149ec7b004SRick Macklem 
1151f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0,
1169ec7b004SRick Macklem     "Buffer reservation size 2 < x < 64");
1171f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0,
1189ec7b004SRick Macklem     "Number of times the nfs client has had to reconnect");
1191f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0,
1209ec7b004SRick Macklem     "Number of seconds to delay a retry after receiving EJUKEBOX");
1211f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0,
1229ec7b004SRick Macklem     "Disable weak cache consistency checking when server returns an error");
123cecf6c6eSRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, dsretries, CTLFLAG_RW, &nfs_dsretries, 0,
124cecf6c6eSRick Macklem     "Number of retries for a DS RPC before failure");
1259ec7b004SRick Macklem 
1269ec7b004SRick Macklem static void	nfs_down(struct nfsmount *, struct thread *, const char *,
1279ec7b004SRick Macklem     int, int);
1289ec7b004SRick Macklem static void	nfs_up(struct nfsmount *, struct thread *, const char *,
1299ec7b004SRick Macklem     int, int);
1309ec7b004SRick Macklem static int	nfs_msg(struct thread *, const char *, const char *, int);
1319ec7b004SRick Macklem 
1329ec7b004SRick Macklem struct nfs_cached_auth {
1339ec7b004SRick Macklem 	int		ca_refs; /* refcount, including 1 from the cache */
1349ec7b004SRick Macklem 	uid_t		ca_uid;	 /* uid that corresponds to this auth */
1359ec7b004SRick Macklem 	AUTH		*ca_auth; /* RPC auth handle */
1369ec7b004SRick Macklem };
1379ec7b004SRick Macklem 
13823d9efa7SRick Macklem static int nfsv2_procid[NFS_V3NPROCS] = {
13923d9efa7SRick Macklem 	NFSV2PROC_NULL,
14023d9efa7SRick Macklem 	NFSV2PROC_GETATTR,
14123d9efa7SRick Macklem 	NFSV2PROC_SETATTR,
14223d9efa7SRick Macklem 	NFSV2PROC_LOOKUP,
14323d9efa7SRick Macklem 	NFSV2PROC_NOOP,
14423d9efa7SRick Macklem 	NFSV2PROC_READLINK,
14523d9efa7SRick Macklem 	NFSV2PROC_READ,
14623d9efa7SRick Macklem 	NFSV2PROC_WRITE,
14723d9efa7SRick Macklem 	NFSV2PROC_CREATE,
14823d9efa7SRick Macklem 	NFSV2PROC_MKDIR,
14923d9efa7SRick Macklem 	NFSV2PROC_SYMLINK,
15023d9efa7SRick Macklem 	NFSV2PROC_CREATE,
15123d9efa7SRick Macklem 	NFSV2PROC_REMOVE,
15223d9efa7SRick Macklem 	NFSV2PROC_RMDIR,
15323d9efa7SRick Macklem 	NFSV2PROC_RENAME,
15423d9efa7SRick Macklem 	NFSV2PROC_LINK,
15523d9efa7SRick Macklem 	NFSV2PROC_READDIR,
15623d9efa7SRick Macklem 	NFSV2PROC_NOOP,
15723d9efa7SRick Macklem 	NFSV2PROC_STATFS,
15823d9efa7SRick Macklem 	NFSV2PROC_NOOP,
15923d9efa7SRick Macklem 	NFSV2PROC_NOOP,
16023d9efa7SRick Macklem 	NFSV2PROC_NOOP,
16123d9efa7SRick Macklem };
16223d9efa7SRick Macklem 
1639ec7b004SRick Macklem /*
164896516e5SRick Macklem  * This static array indicates that a NFSv4 RPC should use
165896516e5SRick Macklem  * RPCSEC_GSS, if the mount indicates that via sec=krb5[ip].
166896516e5SRick Macklem  * System RPCs that do not use file handles will be false
167896516e5SRick Macklem  * in this array so that they will use AUTH_SYS when the
168896516e5SRick Macklem  * "syskrb5" mount option is specified, along with
169896516e5SRick Macklem  * "sec=krb5[ip]".
170896516e5SRick Macklem  */
171896516e5SRick Macklem static bool nfscl_use_gss[NFSV42_NPROCS] = {
172896516e5SRick Macklem 	true,
173896516e5SRick Macklem 	true,
174896516e5SRick Macklem 	true,
175896516e5SRick Macklem 	true,
176896516e5SRick Macklem 	true,
177896516e5SRick Macklem 	true,
178896516e5SRick Macklem 	true,
179896516e5SRick Macklem 	true,
180896516e5SRick Macklem 	true,
181896516e5SRick Macklem 	true,
182896516e5SRick Macklem 	true,
183896516e5SRick Macklem 	true,
184896516e5SRick Macklem 	true,
185896516e5SRick Macklem 	true,
186896516e5SRick Macklem 	true,
187896516e5SRick Macklem 	true,
188896516e5SRick Macklem 	true,
189896516e5SRick Macklem 	true,
190896516e5SRick Macklem 	true,
191896516e5SRick Macklem 	true,
192896516e5SRick Macklem 	true,
193896516e5SRick Macklem 	true,
194896516e5SRick Macklem 	true,
195896516e5SRick Macklem 	false,		/* SetClientID */
196896516e5SRick Macklem 	false,		/* SetClientIDConfirm */
197896516e5SRick Macklem 	true,
198896516e5SRick Macklem 	true,
199896516e5SRick Macklem 	true,
200896516e5SRick Macklem 	true,
201896516e5SRick Macklem 	true,
202896516e5SRick Macklem 	true,
203896516e5SRick Macklem 	true,
204896516e5SRick Macklem 	false,		/* Renew */
205896516e5SRick Macklem 	true,
206896516e5SRick Macklem 	false,		/* ReleaseLockOwn */
207896516e5SRick Macklem 	true,
208896516e5SRick Macklem 	true,
209896516e5SRick Macklem 	true,
210896516e5SRick Macklem 	true,
211896516e5SRick Macklem 	true,
212896516e5SRick Macklem 	true,
213896516e5SRick Macklem 	false,		/* ExchangeID */
214896516e5SRick Macklem 	false,		/* CreateSession */
215896516e5SRick Macklem 	false,		/* DestroySession */
216896516e5SRick Macklem 	false,		/* DestroyClientID */
217896516e5SRick Macklem 	false,		/* FreeStateID */
218896516e5SRick Macklem 	true,
219896516e5SRick Macklem 	true,
220896516e5SRick Macklem 	true,
221896516e5SRick Macklem 	true,
222896516e5SRick Macklem 	false,		/* ReclaimComplete */
223896516e5SRick Macklem 	true,
224896516e5SRick Macklem 	true,
225896516e5SRick Macklem 	true,
226896516e5SRick Macklem 	true,
227896516e5SRick Macklem 	true,
228896516e5SRick Macklem 	true,
229896516e5SRick Macklem 	true,
230896516e5SRick Macklem 	true,
231896516e5SRick Macklem 	true,
232896516e5SRick Macklem 	true,
233896516e5SRick Macklem 	true,
234896516e5SRick Macklem 	true,
235896516e5SRick Macklem 	true,
236896516e5SRick Macklem 	true,
237896516e5SRick Macklem 	false,		/* BindConnectionToSession */
238896516e5SRick Macklem 	true,
239896516e5SRick Macklem 	true,
240896516e5SRick Macklem 	true,
241896516e5SRick Macklem 	true,
242896516e5SRick Macklem };
243896516e5SRick Macklem 
244896516e5SRick Macklem /*
2459ec7b004SRick Macklem  * Initialize sockets and congestion for a new NFS connection.
2469ec7b004SRick Macklem  * We do not free the sockaddr if error.
247ba6cce3aSRick Macklem  * Which arguments are set to NULL indicate what kind of call it is.
248ba6cce3aSRick Macklem  * cred == NULL --> a call to connect to a pNFS DS
249ba6cce3aSRick Macklem  * nmp == NULL --> indicates an upcall to userland or a NFSv4.0 callback
2509ec7b004SRick Macklem  */
2519ec7b004SRick Macklem int
newnfs_connect(struct nfsmount * nmp,struct nfssockreq * nrp,struct ucred * cred,NFSPROC_T * p,int callback_retry_mult,bool dotls,struct __rpc_client ** clipp)2529ec7b004SRick Macklem newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
2531e0a518dSRick Macklem     struct ucred *cred, NFSPROC_T *p, int callback_retry_mult, bool dotls,
2541e0a518dSRick Macklem     struct __rpc_client **clipp)
2559ec7b004SRick Macklem {
2569ec7b004SRick Macklem 	int rcvreserve, sndreserve;
257d1c5e240SRick Macklem 	int pktscale, pktscalesav;
2589ec7b004SRick Macklem 	struct sockaddr *saddr;
2599ec7b004SRick Macklem 	struct ucred *origcred;
2609ec7b004SRick Macklem 	CLIENT *client;
2619ec7b004SRick Macklem 	struct netconfig *nconf;
2629ec7b004SRick Macklem 	struct socket *so;
263a9285ae5SZack Kirsch 	int one = 1, retries, error = 0;
2649ec7b004SRick Macklem 	struct thread *td = curthread;
2651f60bfd8SRick Macklem 	SVCXPRT *xprt;
266713f46acSRick Macklem 	struct timeval timo;
267c5f4772cSRick Macklem 	uint64_t tval;
2689ec7b004SRick Macklem 
2699ec7b004SRick Macklem 	/*
2709ec7b004SRick Macklem 	 * We need to establish the socket using the credentials of
2719ec7b004SRick Macklem 	 * the mountpoint.  Some parts of this process (such as
2729ec7b004SRick Macklem 	 * sobind() and soconnect()) will use the curent thread's
2739ec7b004SRick Macklem 	 * credential instead of the socket credential.  To work
2749ec7b004SRick Macklem 	 * around this, temporarily change the current thread's
2759ec7b004SRick Macklem 	 * credential to that of the mountpoint.
2769ec7b004SRick Macklem 	 *
2779ec7b004SRick Macklem 	 * XXX: It would be better to explicitly pass the correct
2789ec7b004SRick Macklem 	 * credential to sobind() and soconnect().
2799ec7b004SRick Macklem 	 */
2809ec7b004SRick Macklem 	origcred = td->td_ucred;
2819ec7b004SRick Macklem 
2829ec7b004SRick Macklem 	/*
2839ec7b004SRick Macklem 	 * Use the credential in nr_cred, if not NULL.
2849ec7b004SRick Macklem 	 */
2859ec7b004SRick Macklem 	if (nrp->nr_cred != NULL)
2869ec7b004SRick Macklem 		td->td_ucred = nrp->nr_cred;
2879ec7b004SRick Macklem 	else
2889ec7b004SRick Macklem 		td->td_ucred = cred;
2899ec7b004SRick Macklem 	saddr = nrp->nr_nam;
2909ec7b004SRick Macklem 
2919ec7b004SRick Macklem 	if (saddr->sa_family == AF_INET)
2929ec7b004SRick Macklem 		if (nrp->nr_sotype == SOCK_DGRAM)
2939ec7b004SRick Macklem 			nconf = getnetconfigent("udp");
2949ec7b004SRick Macklem 		else
2959ec7b004SRick Macklem 			nconf = getnetconfigent("tcp");
2969ec7b004SRick Macklem 	else
2979ec7b004SRick Macklem 		if (nrp->nr_sotype == SOCK_DGRAM)
2989ec7b004SRick Macklem 			nconf = getnetconfigent("udp6");
2999ec7b004SRick Macklem 		else
3009ec7b004SRick Macklem 			nconf = getnetconfigent("tcp6");
3019ec7b004SRick Macklem 
3029ec7b004SRick Macklem 	pktscale = nfs_bufpackets;
3039ec7b004SRick Macklem 	if (pktscale < 2)
3049ec7b004SRick Macklem 		pktscale = 2;
3059ec7b004SRick Macklem 	if (pktscale > 64)
3069ec7b004SRick Macklem 		pktscale = 64;
307d1c5e240SRick Macklem 	pktscalesav = pktscale;
3089ec7b004SRick Macklem 	/*
3099ec7b004SRick Macklem 	 * soreserve() can fail if sb_max is too small, so shrink pktscale
3109ec7b004SRick Macklem 	 * and try again if there is an error.
3119ec7b004SRick Macklem 	 * Print a log message suggesting increasing sb_max.
3129ec7b004SRick Macklem 	 * Creating a socket and doing this is necessary since, if the
3139ec7b004SRick Macklem 	 * reservation sizes are too large and will make soreserve() fail,
3149ec7b004SRick Macklem 	 * the connection will work until a large send is attempted and
3159ec7b004SRick Macklem 	 * then it will loop in the krpc code.
3169ec7b004SRick Macklem 	 */
3179ec7b004SRick Macklem 	so = NULL;
3189ec7b004SRick Macklem 	saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *);
3199ec7b004SRick Macklem 	error = socreate(saddr->sa_family, &so, nrp->nr_sotype,
3209ec7b004SRick Macklem 	    nrp->nr_soproto, td->td_ucred, td);
321355b3b7fSMark Johnston 	if (error != 0)
322a9285ae5SZack Kirsch 		goto out;
3239ec7b004SRick Macklem 	do {
324d1c5e240SRick Macklem 	    if (error != 0 && pktscale > 2) {
325d1c5e240SRick Macklem 		if (nmp != NULL && nrp->nr_sotype == SOCK_STREAM &&
326c5f4772cSRick Macklem 		    pktscale == pktscalesav) {
327c5f4772cSRick Macklem 		    /*
328c5f4772cSRick Macklem 		     * Suggest vfs.nfs.bufpackets * maximum RPC message,
329c5f4772cSRick Macklem 		     * adjusted for the sb_max->sb_max_adj conversion of
330c5f4772cSRick Macklem 		     * MCLBYTES / (MSIZE + MCLBYTES) as the minimum setting
331c5f4772cSRick Macklem 		     * for kern.ipc.maxsockbuf.
332c5f4772cSRick Macklem 		     */
333c5f4772cSRick Macklem 		    tval = (NFS_MAXBSIZE + NFS_MAXXDR) * nfs_bufpackets;
334c5f4772cSRick Macklem 		    tval *= MSIZE + MCLBYTES;
335c5f4772cSRick Macklem 		    tval += MCLBYTES - 1; /* Round up divide by MCLBYTES. */
336c5f4772cSRick Macklem 		    tval /= MCLBYTES;
337c5f4772cSRick Macklem 		    printf("Consider increasing kern.ipc.maxsockbuf to a "
338c5f4772cSRick Macklem 			"minimum of %ju to support %ubyte NFS I/O\n",
339c5f4772cSRick Macklem 			(uintmax_t)tval, NFS_MAXBSIZE);
340c5f4772cSRick Macklem 		}
3419ec7b004SRick Macklem 		pktscale--;
342d1c5e240SRick Macklem 	    }
3439ec7b004SRick Macklem 	    if (nrp->nr_sotype == SOCK_DGRAM) {
3449ec7b004SRick Macklem 		if (nmp != NULL) {
3459ec7b004SRick Macklem 			sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
3469ec7b004SRick Macklem 			    pktscale;
3479ec7b004SRick Macklem 			rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
3489ec7b004SRick Macklem 			    pktscale;
3499ec7b004SRick Macklem 		} else {
3509ec7b004SRick Macklem 			sndreserve = rcvreserve = 1024 * pktscale;
3519ec7b004SRick Macklem 		}
3529ec7b004SRick Macklem 	    } else {
3539ec7b004SRick Macklem 		if (nrp->nr_sotype != SOCK_STREAM)
3549ec7b004SRick Macklem 			panic("nfscon sotype");
3559ec7b004SRick Macklem 		if (nmp != NULL) {
356c5f4772cSRick Macklem 			sndreserve = (NFS_MAXBSIZE + NFS_MAXXDR) *
357c5f4772cSRick Macklem 			    pktscale;
358c5f4772cSRick Macklem 			rcvreserve = (NFS_MAXBSIZE + NFS_MAXXDR) *
359c5f4772cSRick Macklem 			    pktscale;
3609ec7b004SRick Macklem 		} else {
3619ec7b004SRick Macklem 			sndreserve = rcvreserve = 1024 * pktscale;
3629ec7b004SRick Macklem 		}
3639ec7b004SRick Macklem 	    }
3649ec7b004SRick Macklem 	    error = soreserve(so, sndreserve, rcvreserve);
365d1c5e240SRick Macklem 	    if (error != 0 && nmp != NULL && nrp->nr_sotype == SOCK_STREAM &&
366d1c5e240SRick Macklem 		pktscale <= 2)
367d1c5e240SRick Macklem 		printf("Must increase kern.ipc.maxsockbuf or reduce"
368d1c5e240SRick Macklem 		    " rsize, wsize\n");
3699ec7b004SRick Macklem 	} while (error != 0 && pktscale > 2);
3709ec7b004SRick Macklem 	soclose(so);
371355b3b7fSMark Johnston 	if (error != 0)
372a9285ae5SZack Kirsch 		goto out;
3739ec7b004SRick Macklem 
3749ec7b004SRick Macklem 	client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog,
3759ec7b004SRick Macklem 	    nrp->nr_vers, sndreserve, rcvreserve);
376c15882f0SRick Macklem 	CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
3779ec7b004SRick Macklem 	if (nmp != NULL) {
3789ec7b004SRick Macklem 		if ((nmp->nm_flag & NFSMNT_INT))
3799ec7b004SRick Macklem 			CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
3809ec7b004SRick Macklem 		if ((nmp->nm_flag & NFSMNT_RESVPORT))
3819ec7b004SRick Macklem 			CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
382665b1365SRick Macklem 		if (NFSHASTLS(nmp)) {
3836e4b6ff8SRick Macklem 			CLNT_CONTROL(client, CLSET_TLS, &one);
384665b1365SRick Macklem 			if (nmp->nm_tlscertname != NULL)
385665b1365SRick Macklem 				CLNT_CONTROL(client, CLSET_TLSCERTNAME,
386665b1365SRick Macklem 				    nmp->nm_tlscertname);
387665b1365SRick Macklem 		}
388713f46acSRick Macklem 		if (NFSHASSOFT(nmp)) {
389713f46acSRick Macklem 			if (nmp->nm_sotype == SOCK_DGRAM)
390713f46acSRick Macklem 				/*
391713f46acSRick Macklem 				 * For UDP, the large timeout for a reconnect
392713f46acSRick Macklem 				 * will be set to "nm_retry * nm_timeo / 2", so
393713f46acSRick Macklem 				 * we only want to do 2 reconnect timeout
394713f46acSRick Macklem 				 * retries.
395713f46acSRick Macklem 				 */
396713f46acSRick Macklem 				retries = 2;
3979ec7b004SRick Macklem 			else
398713f46acSRick Macklem 				retries = nmp->nm_retry;
399713f46acSRick Macklem 		} else
4009ec7b004SRick Macklem 			retries = INT_MAX;
401ba6cce3aSRick Macklem 		if (NFSHASNFSV4N(nmp)) {
402ba6cce3aSRick Macklem 			if (cred != NULL) {
403cecf6c6eSRick Macklem 				if (NFSHASSOFT(nmp)) {
404cecf6c6eSRick Macklem 					/*
405cecf6c6eSRick Macklem 					 * This should be a DS mount.
406cecf6c6eSRick Macklem 					 * Use CLSET_TIMEOUT to set the timeout
407cecf6c6eSRick Macklem 					 * for connections to DSs instead of
408cecf6c6eSRick Macklem 					 * specifying a timeout on each RPC.
409cecf6c6eSRick Macklem 					 * This is done so that SO_SNDTIMEO
410cecf6c6eSRick Macklem 					 * is set on the TCP socket as well
411cecf6c6eSRick Macklem 					 * as specifying a time limit when
412cecf6c6eSRick Macklem 					 * waiting for an RPC reply.  Useful
413cecf6c6eSRick Macklem 					 * if the send queue for the TCP
414cecf6c6eSRick Macklem 					 * connection has become constipated,
415cecf6c6eSRick Macklem 					 * due to a failed DS.
416cecf6c6eSRick Macklem 					 * The choice of lease_duration / 4 is
417cecf6c6eSRick Macklem 					 * fairly arbitrary, but seems to work
418cecf6c6eSRick Macklem 					 * ok, with a lower bound of 10sec.
419cecf6c6eSRick Macklem 					 */
420cecf6c6eSRick Macklem 					timo.tv_sec = nfsrv_lease / 4;
421cecf6c6eSRick Macklem 					if (timo.tv_sec < 10)
422cecf6c6eSRick Macklem 						timo.tv_sec = 10;
423cecf6c6eSRick Macklem 					timo.tv_usec = 0;
424cecf6c6eSRick Macklem 					CLNT_CONTROL(client, CLSET_TIMEOUT,
425cecf6c6eSRick Macklem 					    &timo);
426cecf6c6eSRick Macklem 				}
4271f60bfd8SRick Macklem 				/*
428ba6cce3aSRick Macklem 				 * Make sure the nfscbd_pool doesn't get
429ba6cce3aSRick Macklem 				 * destroyed while doing this.
4301f60bfd8SRick Macklem 				 */
4311f60bfd8SRick Macklem 				NFSD_LOCK();
4321f60bfd8SRick Macklem 				if (nfs_numnfscbd > 0) {
4331f60bfd8SRick Macklem 					nfs_numnfscbd++;
4341f60bfd8SRick Macklem 					NFSD_UNLOCK();
435ba6cce3aSRick Macklem 					xprt = svc_vc_create_backchannel(
436ba6cce3aSRick Macklem 					    nfscbd_pool);
437ba6cce3aSRick Macklem 					CLNT_CONTROL(client, CLSET_BACKCHANNEL,
438ba6cce3aSRick Macklem 					    xprt);
4391f60bfd8SRick Macklem 					NFSD_LOCK();
4401f60bfd8SRick Macklem 					nfs_numnfscbd--;
4411f60bfd8SRick Macklem 					if (nfs_numnfscbd == 0)
4421f60bfd8SRick Macklem 						wakeup(&nfs_numnfscbd);
4431f60bfd8SRick Macklem 				}
4441f60bfd8SRick Macklem 				NFSD_UNLOCK();
445ba6cce3aSRick Macklem 			} else {
446ba6cce3aSRick Macklem 				/*
447ba6cce3aSRick Macklem 				 * cred == NULL for a DS connect.
448ba6cce3aSRick Macklem 				 * For connects to a DS, set a retry limit
449ba6cce3aSRick Macklem 				 * so that failed DSs will be detected.
450ba6cce3aSRick Macklem 				 * This is ok for NFSv4.1, since a DS does
451ba6cce3aSRick Macklem 				 * not maintain open/lock state and is the
452ba6cce3aSRick Macklem 				 * only case where using a "soft" mount is
453ba6cce3aSRick Macklem 				 * recommended for NFSv4.
454cecf6c6eSRick Macklem 				 * For mounts from the MDS to DS, this is done
455cecf6c6eSRick Macklem 				 * via mount options, but that is not the case
456cecf6c6eSRick Macklem 				 * here.  The retry limit here can be adjusted
457cecf6c6eSRick Macklem 				 * via the sysctl vfs.nfs.dsretries.
458cecf6c6eSRick Macklem 				 * See the comment above w.r.t. timeout.
459ba6cce3aSRick Macklem 				 */
460cecf6c6eSRick Macklem 				timo.tv_sec = nfsrv_lease / 4;
461cecf6c6eSRick Macklem 				if (timo.tv_sec < 10)
462cecf6c6eSRick Macklem 					timo.tv_sec = 10;
463cecf6c6eSRick Macklem 				timo.tv_usec = 0;
464cecf6c6eSRick Macklem 				CLNT_CONTROL(client, CLSET_TIMEOUT, &timo);
465cecf6c6eSRick Macklem 				retries = nfs_dsretries;
466ba6cce3aSRick Macklem 			}
4671f60bfd8SRick Macklem 		}
4689ec7b004SRick Macklem 	} else {
4699ec7b004SRick Macklem 		/*
4709ec7b004SRick Macklem 		 * Three cases:
4719ec7b004SRick Macklem 		 * - Null RPC callback to client
4729ec7b004SRick Macklem 		 * - Non-Null RPC callback to client, wait a little longer
4739ec7b004SRick Macklem 		 * - upcalls to nfsuserd and gssd (clp == NULL)
4749ec7b004SRick Macklem 		 */
4759ec7b004SRick Macklem 		if (callback_retry_mult == 0) {
4769ec7b004SRick Macklem 			retries = NFSV4_UPCALLRETRY;
4779ec7b004SRick Macklem 			CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
4789ec7b004SRick Macklem 		} else {
4799ec7b004SRick Macklem 			retries = NFSV4_CALLBACKRETRY * callback_retry_mult;
4809ec7b004SRick Macklem 		}
48102511d21SRick Macklem 		if (dotls)
48202511d21SRick Macklem 			CLNT_CONTROL(client, CLSET_TLS, &one);
4839ec7b004SRick Macklem 	}
4849ec7b004SRick Macklem 	CLNT_CONTROL(client, CLSET_RETRIES, &retries);
4859ec7b004SRick Macklem 
486713f46acSRick Macklem 	if (nmp != NULL) {
487713f46acSRick Macklem 		/*
488713f46acSRick Macklem 		 * For UDP, there are 2 timeouts:
489713f46acSRick Macklem 		 * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer
490713f46acSRick Macklem 		 *   that does a retransmit of an RPC request using the same
491713f46acSRick Macklem 		 *   socket and xid. This is what you normally want to do,
492713f46acSRick Macklem 		 *   since NFS servers depend on "same xid" for their
493713f46acSRick Macklem 		 *   Duplicate Request Cache.
494713f46acSRick Macklem 		 * - timeout specified in CLNT_CALL_MBUF(), which specifies when
495713f46acSRick Macklem 		 *   retransmits on the same socket should fail and a fresh
496713f46acSRick Macklem 		 *   socket created. Each of these timeouts counts as one
497713f46acSRick Macklem 		 *   CLSET_RETRIES as set above.
498713f46acSRick Macklem 		 * Set the initial retransmit timeout for UDP. This timeout
499713f46acSRick Macklem 		 * doesn't exist for TCP and the following call just fails,
500713f46acSRick Macklem 		 * which is ok.
501713f46acSRick Macklem 		 */
502713f46acSRick Macklem 		timo.tv_sec = nmp->nm_timeo / NFS_HZ;
503713f46acSRick Macklem 		timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
504713f46acSRick Macklem 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo);
505713f46acSRick Macklem 	}
506713f46acSRick Macklem 
5071e0a518dSRick Macklem 	/*
5081e0a518dSRick Macklem 	 * *clipp is &nrp->nr_client or &nm_aconn[nmp->nm_nextaconn].
5091e0a518dSRick Macklem 	 * The latter case is for additional connections specified by the
5101e0a518dSRick Macklem 	 * "nconnect" mount option.  nr_mtx etc is used for these additional
5111e0a518dSRick Macklem 	 * connections, as well as nr_client in the nfssockreq
5121e0a518dSRick Macklem 	 * structure for the mount.
5131e0a518dSRick Macklem 	 */
5149ec7b004SRick Macklem 	mtx_lock(&nrp->nr_mtx);
5151e0a518dSRick Macklem 	if (*clipp != NULL) {
516cc085ba8SRick Macklem 		mtx_unlock(&nrp->nr_mtx);
5179ec7b004SRick Macklem 		/*
5189ec7b004SRick Macklem 		 * Someone else already connected.
5199ec7b004SRick Macklem 		 */
5209ec7b004SRick Macklem 		CLNT_RELEASE(client);
5219ec7b004SRick Macklem 	} else {
5221e0a518dSRick Macklem 		*clipp = client;
5239ec7b004SRick Macklem 		/*
524cc085ba8SRick Macklem 		 * Protocols that do not require connections may be optionally
525cc085ba8SRick Macklem 		 * left unconnected for servers that reply from a port other
526cc085ba8SRick Macklem 		 * than NFS_PORT.
5279ec7b004SRick Macklem 		 */
5289ec7b004SRick Macklem 		if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) {
5299ec7b004SRick Macklem 			mtx_unlock(&nrp->nr_mtx);
5309ec7b004SRick Macklem 			CLNT_CONTROL(client, CLSET_CONNECT, &one);
531cc085ba8SRick Macklem 		} else
5329ec7b004SRick Macklem 			mtx_unlock(&nrp->nr_mtx);
5339ec7b004SRick Macklem 	}
5349ec7b004SRick Macklem 
535355b3b7fSMark Johnston out:
5369ec7b004SRick Macklem 	/* Restore current thread's credentials. */
5379ec7b004SRick Macklem 	td->td_ucred = origcred;
538a9285ae5SZack Kirsch 
539a9285ae5SZack Kirsch 	NFSEXITCODE(error);
540a9285ae5SZack Kirsch 	return (error);
5419ec7b004SRick Macklem }
5429ec7b004SRick Macklem 
5439ec7b004SRick Macklem /*
5449ec7b004SRick Macklem  * NFS disconnect. Clean up and unlink.
5459ec7b004SRick Macklem  */
5469ec7b004SRick Macklem void
newnfs_disconnect(struct nfsmount * nmp,struct nfssockreq * nrp)5471e0a518dSRick Macklem newnfs_disconnect(struct nfsmount *nmp, struct nfssockreq *nrp)
5489ec7b004SRick Macklem {
5491e0a518dSRick Macklem 	CLIENT *client, *aconn[NFS_MAXNCONN - 1];
5501e0a518dSRick Macklem 	int i;
5519ec7b004SRick Macklem 
5529ec7b004SRick Macklem 	mtx_lock(&nrp->nr_mtx);
5539ec7b004SRick Macklem 	if (nrp->nr_client != NULL) {
5549ec7b004SRick Macklem 		client = nrp->nr_client;
5559ec7b004SRick Macklem 		nrp->nr_client = NULL;
5561e0a518dSRick Macklem 		if (nmp != NULL && nmp->nm_aconnect > 0) {
5571e0a518dSRick Macklem 			for (i = 0; i < nmp->nm_aconnect; i++) {
5581e0a518dSRick Macklem 				aconn[i] = nmp->nm_aconn[i];
5591e0a518dSRick Macklem 				nmp->nm_aconn[i] = NULL;
5601e0a518dSRick Macklem 			}
5611e0a518dSRick Macklem 		}
5629ec7b004SRick Macklem 		mtx_unlock(&nrp->nr_mtx);
5637e7fd7d1SRick Macklem 		rpc_gss_secpurge_call(client);
5649ec7b004SRick Macklem 		CLNT_CLOSE(client);
5659ec7b004SRick Macklem 		CLNT_RELEASE(client);
5661e0a518dSRick Macklem 		if (nmp != NULL && nmp->nm_aconnect > 0) {
5671e0a518dSRick Macklem 			for (i = 0; i < nmp->nm_aconnect; i++) {
5681e0a518dSRick Macklem 				if (aconn[i] != NULL) {
5691e0a518dSRick Macklem 					rpc_gss_secpurge_call(aconn[i]);
5701e0a518dSRick Macklem 					CLNT_CLOSE(aconn[i]);
5711e0a518dSRick Macklem 					CLNT_RELEASE(aconn[i]);
5721e0a518dSRick Macklem 				}
5731e0a518dSRick Macklem 			}
5741e0a518dSRick Macklem 		}
5759ec7b004SRick Macklem 	} else {
5769ec7b004SRick Macklem 		mtx_unlock(&nrp->nr_mtx);
5779ec7b004SRick Macklem 	}
5789ec7b004SRick Macklem }
5799ec7b004SRick Macklem 
5809ec7b004SRick Macklem static AUTH *
nfs_getauth(struct nfssockreq * nrp,int secflavour,char * clnt_principal,char * srv_principal,gss_OID mech_oid,struct ucred * cred)5819ec7b004SRick Macklem nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal,
5829ec7b004SRick Macklem     char *srv_principal, gss_OID mech_oid, struct ucred *cred)
5839ec7b004SRick Macklem {
5849ec7b004SRick Macklem 	rpc_gss_service_t svc;
5859ec7b004SRick Macklem 	AUTH *auth;
5869ec7b004SRick Macklem 
5879ec7b004SRick Macklem 	switch (secflavour) {
5889ec7b004SRick Macklem 	case RPCSEC_GSS_KRB5:
5899ec7b004SRick Macklem 	case RPCSEC_GSS_KRB5I:
5909ec7b004SRick Macklem 	case RPCSEC_GSS_KRB5P:
5919ec7b004SRick Macklem 		if (!mech_oid) {
5927e7fd7d1SRick Macklem 			if (!rpc_gss_mech_to_oid_call("kerberosv5", &mech_oid))
5939ec7b004SRick Macklem 				return (NULL);
5949ec7b004SRick Macklem 		}
5959ec7b004SRick Macklem 		if (secflavour == RPCSEC_GSS_KRB5)
5969ec7b004SRick Macklem 			svc = rpc_gss_svc_none;
5979ec7b004SRick Macklem 		else if (secflavour == RPCSEC_GSS_KRB5I)
5989ec7b004SRick Macklem 			svc = rpc_gss_svc_integrity;
5999ec7b004SRick Macklem 		else
6009ec7b004SRick Macklem 			svc = rpc_gss_svc_privacy;
6019ec7b004SRick Macklem 
602dd7d42a1SRick Macklem 		if (clnt_principal == NULL) {
603dd7d42a1SRick Macklem 			NFSCL_DEBUG(1, "nfs_getauth: clnt princ=NULL, "
604dd7d42a1SRick Macklem 			    "srv princ=%s\n", srv_principal);
6057e7fd7d1SRick Macklem 			auth = rpc_gss_secfind_call(nrp->nr_client, cred,
606e2b84e03SRick Macklem 			    srv_principal, mech_oid, svc);
607dd7d42a1SRick Macklem 		} else {
608dd7d42a1SRick Macklem 			NFSCL_DEBUG(1, "nfs_getauth: clnt princ=%s "
609dd7d42a1SRick Macklem 			    "srv princ=%s\n", clnt_principal, srv_principal);
61088a2437aSRick Macklem 			auth = rpc_gss_seccreate_call(nrp->nr_client, cred,
61188a2437aSRick Macklem 			    clnt_principal, srv_principal, "kerberosv5",
61288a2437aSRick Macklem 			    svc, NULL, NULL, NULL);
61388a2437aSRick Macklem 			return (auth);
61488a2437aSRick Macklem 		}
61563bde62eSRick Macklem 		if (auth != NULL)
616e2b84e03SRick Macklem 			return (auth);
61763bde62eSRick Macklem 		/* fallthrough */
6189ec7b004SRick Macklem 	case AUTH_SYS:
6199ec7b004SRick Macklem 	default:
6209ec7b004SRick Macklem 		return (authunix_create(cred));
6219ec7b004SRick Macklem 	}
6229ec7b004SRick Macklem }
6239ec7b004SRick Macklem 
6249ec7b004SRick Macklem /*
6259ec7b004SRick Macklem  * Callback from the RPC code to generate up/down notifications.
6269ec7b004SRick Macklem  */
6279ec7b004SRick Macklem 
6289ec7b004SRick Macklem struct nfs_feedback_arg {
6299ec7b004SRick Macklem 	struct nfsmount *nf_mount;
6309ec7b004SRick Macklem 	int		nf_lastmsg;	/* last tprintf */
6319ec7b004SRick Macklem 	int		nf_tprintfmsg;
6329ec7b004SRick Macklem 	struct thread	*nf_td;
6339ec7b004SRick Macklem };
6349ec7b004SRick Macklem 
6359ec7b004SRick Macklem static void
nfs_feedback(int type,int proc,void * arg)6369ec7b004SRick Macklem nfs_feedback(int type, int proc, void *arg)
6379ec7b004SRick Macklem {
6389ec7b004SRick Macklem 	struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg;
6399ec7b004SRick Macklem 	struct nfsmount *nmp = nf->nf_mount;
640a89a2c8bSJohn Baldwin 	time_t now;
6419ec7b004SRick Macklem 
6429ec7b004SRick Macklem 	switch (type) {
6439ec7b004SRick Macklem 	case FEEDBACK_REXMIT2:
6449ec7b004SRick Macklem 	case FEEDBACK_RECONNECT:
645a89a2c8bSJohn Baldwin 		now = NFSD_MONOSEC;
646a89a2c8bSJohn Baldwin 		if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now) {
6479ec7b004SRick Macklem 			nfs_down(nmp, nf->nf_td,
6489ec7b004SRick Macklem 			    "not responding", 0, NFSSTA_TIMEO);
6499ec7b004SRick Macklem 			nf->nf_tprintfmsg = TRUE;
650a89a2c8bSJohn Baldwin 			nf->nf_lastmsg = now;
6519ec7b004SRick Macklem 		}
6529ec7b004SRick Macklem 		break;
6539ec7b004SRick Macklem 
6549ec7b004SRick Macklem 	case FEEDBACK_OK:
6559ec7b004SRick Macklem 		nfs_up(nf->nf_mount, nf->nf_td,
6569ec7b004SRick Macklem 		    "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg);
6579ec7b004SRick Macklem 		break;
6589ec7b004SRick Macklem 	}
6599ec7b004SRick Macklem }
6609ec7b004SRick Macklem 
6619ec7b004SRick Macklem /*
6629ec7b004SRick Macklem  * newnfs_request - goes something like this
6639ec7b004SRick Macklem  *	- does the rpc by calling the krpc layer
6649ec7b004SRick Macklem  *	- break down rpc header and return with nfs reply
6659ec7b004SRick Macklem  * nb: always frees up nd_mreq mbuf list
6669ec7b004SRick Macklem  */
6679ec7b004SRick Macklem int
newnfs_request(struct nfsrv_descript * nd,struct nfsmount * nmp,struct nfsclient * clp,struct nfssockreq * nrp,vnode_t vp,struct thread * td,struct ucred * cred,u_int32_t prog,u_int32_t vers,u_char * retsum,int toplevel,u_int64_t * xidp,struct nfsclsession * dssep)6689ec7b004SRick Macklem newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
6699ec7b004SRick Macklem     struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp,
6709ec7b004SRick Macklem     struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
671b2fc0141SRick Macklem     u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *dssep)
6729ec7b004SRick Macklem {
673b97a4788SRick Macklem 	uint32_t retseq, retval, retval0, slotseq, *tl;
6741f60bfd8SRick Macklem 	int i = 0, j = 0, opcnt, set_sigset = 0, slot;
675151ba793SAlexander Kabaev 	int error = 0, usegssname = 0, secflavour = AUTH_SYS;
676b2fc0141SRick Macklem 	int freeslot, maxslot, reterr, slotpos, timeo;
6779ec7b004SRick Macklem 	u_int16_t procnum;
6785a95a6e8SRick Macklem 	u_int nextconn;
6799ec7b004SRick Macklem 	struct nfs_feedback_arg nf;
680a89a2c8bSJohn Baldwin 	struct timeval timo;
6819ec7b004SRick Macklem 	AUTH *auth;
6829ec7b004SRick Macklem 	struct rpc_callextra ext;
6839ec7b004SRick Macklem 	enum clnt_stat stat;
6849ec7b004SRick Macklem 	struct nfsreq *rep = NULL;
68588a2437aSRick Macklem 	char *srv_principal = NULL, *clnt_principal = NULL;
686089f366aSRick Macklem 	sigset_t oldset;
68723b35663SRick Macklem 	struct ucred *authcred;
688b2fc0141SRick Macklem 	struct nfsclsession *sep;
689b2fc0141SRick Macklem 	uint8_t sessionid[NFSX_V4SESSIONID];
6901e0a518dSRick Macklem 	bool nextconn_set;
6915a95a6e8SRick Macklem 	struct timespec trylater_delay, ts, waituntil;
6929ec7b004SRick Macklem 
6935a95a6e8SRick Macklem 	/* Initially 1msec. */
6945a95a6e8SRick Macklem 	trylater_delay.tv_sec = 0;
6955a95a6e8SRick Macklem 	trylater_delay.tv_nsec = 1000000;
696b2fc0141SRick Macklem 	sep = dssep;
6979ec7b004SRick Macklem 	if (xidp != NULL)
6989ec7b004SRick Macklem 		*xidp = 0;
6999ec7b004SRick Macklem 	/* Reject requests while attempting a forced unmount. */
70016f300faSRick Macklem 	if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
7019ec7b004SRick Macklem 		m_freem(nd->nd_mreq);
7029ec7b004SRick Macklem 		return (ESTALE);
7039ec7b004SRick Macklem 	}
7049ec7b004SRick Macklem 
70523b35663SRick Macklem 	/*
70623b35663SRick Macklem 	 * Set authcred, which is used to acquire RPC credentials to
70723b35663SRick Macklem 	 * the cred argument, by default. The crhold() should not be
70823b35663SRick Macklem 	 * necessary, but will ensure that some future code change
70923b35663SRick Macklem 	 * doesn't result in the credential being free'd prematurely.
71023b35663SRick Macklem 	 */
71123b35663SRick Macklem 	authcred = crhold(cred);
71223b35663SRick Macklem 
713089f366aSRick Macklem 	/* For client side interruptible mounts, mask off the signals. */
714089f366aSRick Macklem 	if (nmp != NULL && td != NULL && NFSHASINT(nmp)) {
715089f366aSRick Macklem 		newnfs_set_sigmask(td, &oldset);
716089f366aSRick Macklem 		set_sigset = 1;
717089f366aSRick Macklem 	}
718089f366aSRick Macklem 
7199ec7b004SRick Macklem 	/*
7201e0a518dSRick Macklem 	 * If not already connected call newnfs_connect now.
72163bde62eSRick Macklem 	 */
72263bde62eSRick Macklem 	if (nrp->nr_client == NULL)
7231e0a518dSRick Macklem 		newnfs_connect(nmp, nrp, cred, td, 0, false, &nrp->nr_client);
7241e0a518dSRick Macklem 
72580e5955bSRick Macklem 	/*
72680e5955bSRick Macklem 	 * If the "nconnect" mount option was specified and this RPC is
72780e5955bSRick Macklem 	 * one that can have a large RPC message and is being done through
72880e5955bSRick Macklem 	 * the NFS/MDS server, use an additional connection. (When the RPC is
72980e5955bSRick Macklem 	 * being done through the server/MDS, nrp == &nmp->nm_sockreq.)
73080e5955bSRick Macklem 	 * The "nconnect" mount option normally has minimal effect when the
73180e5955bSRick Macklem 	 * "pnfs" mount option is specified, since only Readdir RPCs are
73280e5955bSRick Macklem 	 * normally done through the NFS/MDS server.
73380e5955bSRick Macklem 	 */
7341e0a518dSRick Macklem 	nextconn_set = false;
73580e5955bSRick Macklem 	if (nmp != NULL && nmp->nm_aconnect > 0 && nrp == &nmp->nm_sockreq &&
7361e0a518dSRick Macklem 	    (nd->nd_procnum == NFSPROC_READ ||
7371e0a518dSRick Macklem 	     nd->nd_procnum == NFSPROC_READDIR ||
7381e0a518dSRick Macklem 	     nd->nd_procnum == NFSPROC_READDIRPLUS ||
7391e0a518dSRick Macklem 	     nd->nd_procnum == NFSPROC_WRITE)) {
7401e0a518dSRick Macklem 		nextconn = atomic_fetchadd_int(&nmp->nm_nextaconn, 1);
7411e0a518dSRick Macklem 		nextconn %= nmp->nm_aconnect;
7421e0a518dSRick Macklem 		nextconn_set = true;
7431e0a518dSRick Macklem 		if (nmp->nm_aconn[nextconn] == NULL)
7441e0a518dSRick Macklem 			newnfs_connect(nmp, nrp, cred, td, 0, false,
7451e0a518dSRick Macklem 			    &nmp->nm_aconn[nextconn]);
7461e0a518dSRick Macklem 	}
74763bde62eSRick Macklem 
74863bde62eSRick Macklem 	/*
7499ec7b004SRick Macklem 	 * For a client side mount, nmp is != NULL and clp == NULL. For
7509ec7b004SRick Macklem 	 * server calls (callbacks or upcalls), nmp == NULL.
7519ec7b004SRick Macklem 	 */
7529ec7b004SRick Macklem 	if (clp != NULL) {
7539ec7b004SRick Macklem 		NFSLOCKSTATE();
7549ec7b004SRick Macklem 		if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) {
7559ec7b004SRick Macklem 			secflavour = RPCSEC_GSS_KRB5;
7569ec7b004SRick Macklem 			if (nd->nd_procnum != NFSPROC_NULL) {
7579ec7b004SRick Macklem 				if (clp->lc_flags & LCL_GSSINTEGRITY)
7589ec7b004SRick Macklem 					secflavour = RPCSEC_GSS_KRB5I;
7599ec7b004SRick Macklem 				else if (clp->lc_flags & LCL_GSSPRIVACY)
7609ec7b004SRick Macklem 					secflavour = RPCSEC_GSS_KRB5P;
7619ec7b004SRick Macklem 			}
7629ec7b004SRick Macklem 		}
7639ec7b004SRick Macklem 		NFSUNLOCKSTATE();
7649ec7b004SRick Macklem 	} else if (nmp != NULL && NFSHASKERB(nmp) &&
765896516e5SRick Macklem 	     nd->nd_procnum != NFSPROC_NULL && (!NFSHASSYSKRB5(nmp) ||
766896516e5SRick Macklem 	     nfscl_use_gss[nd->nd_procnum])) {
7679ec7b004SRick Macklem 		if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0)
7689ec7b004SRick Macklem 			nd->nd_flag |= ND_USEGSSNAME;
76963bde62eSRick Macklem 		if ((nd->nd_flag & ND_USEGSSNAME) != 0) {
77063bde62eSRick Macklem 			/*
77163bde62eSRick Macklem 			 * If there is a client side host based credential,
77263bde62eSRick Macklem 			 * use that, otherwise use the system uid, if set.
77323b35663SRick Macklem 			 * The system uid is in the nmp->nm_sockreq.nr_cred
77423b35663SRick Macklem 			 * credentials.
77563bde62eSRick Macklem 			 */
77663bde62eSRick Macklem 			if (nmp->nm_krbnamelen > 0) {
7779ec7b004SRick Macklem 				usegssname = 1;
77888a2437aSRick Macklem 				clnt_principal = nmp->nm_krbname;
77963bde62eSRick Macklem 			} else if (nmp->nm_uid != (uid_t)-1) {
78023b35663SRick Macklem 				KASSERT(nmp->nm_sockreq.nr_cred != NULL,
78123b35663SRick Macklem 				    ("newnfs_request: NULL nr_cred"));
78223b35663SRick Macklem 				crfree(authcred);
78323b35663SRick Macklem 				authcred = crhold(nmp->nm_sockreq.nr_cred);
78463bde62eSRick Macklem 			}
78563bde62eSRick Macklem 		} else if (nmp->nm_krbnamelen == 0 &&
78663bde62eSRick Macklem 		    nmp->nm_uid != (uid_t)-1 && cred->cr_uid == (uid_t)0) {
78763bde62eSRick Macklem 			/*
78863bde62eSRick Macklem 			 * If there is no host based principal name and
78963bde62eSRick Macklem 			 * the system uid is set and this is root, use the
79063bde62eSRick Macklem 			 * system uid, since root won't have user
79163bde62eSRick Macklem 			 * credentials in a credentials cache file.
79223b35663SRick Macklem 			 * The system uid is in the nmp->nm_sockreq.nr_cred
79323b35663SRick Macklem 			 * credentials.
79463bde62eSRick Macklem 			 */
79523b35663SRick Macklem 			KASSERT(nmp->nm_sockreq.nr_cred != NULL,
79623b35663SRick Macklem 			    ("newnfs_request: NULL nr_cred"));
79723b35663SRick Macklem 			crfree(authcred);
79823b35663SRick Macklem 			authcred = crhold(nmp->nm_sockreq.nr_cred);
79963bde62eSRick Macklem 		}
8009ec7b004SRick Macklem 		if (NFSHASINTEGRITY(nmp))
8019ec7b004SRick Macklem 			secflavour = RPCSEC_GSS_KRB5I;
8029ec7b004SRick Macklem 		else if (NFSHASPRIVACY(nmp))
8039ec7b004SRick Macklem 			secflavour = RPCSEC_GSS_KRB5P;
8049ec7b004SRick Macklem 		else
8059ec7b004SRick Macklem 			secflavour = RPCSEC_GSS_KRB5;
806dd7d42a1SRick Macklem 		if (nrp->nr_srvprinc[0] == '\0')
8079ec7b004SRick Macklem 			srv_principal = NFSMNT_SRVKRBNAME(nmp);
808dd7d42a1SRick Macklem 		else
809dd7d42a1SRick Macklem 			srv_principal = nrp->nr_srvprinc;
810896516e5SRick Macklem 	} else if (nmp != NULL && (!NFSHASKERB(nmp) || NFSHASSYSKRB5(nmp)) &&
81172b7c8ddSRick Macklem 	    nd->nd_procnum != NFSPROC_NULL &&
81272b7c8ddSRick Macklem 	    (nd->nd_flag & ND_USEGSSNAME) != 0) {
81372b7c8ddSRick Macklem 		/*
81472b7c8ddSRick Macklem 		 * Use the uid that did the mount when the RPC is doing
81572b7c8ddSRick Macklem 		 * NFSv4 system operations, as indicated by the
81672b7c8ddSRick Macklem 		 * ND_USEGSSNAME flag, for the AUTH_SYS case.
81723b35663SRick Macklem 		 * The credentials in nm_sockreq.nr_cred were used for the
81823b35663SRick Macklem 		 * mount.
81972b7c8ddSRick Macklem 		 */
82023b35663SRick Macklem 		KASSERT(nmp->nm_sockreq.nr_cred != NULL,
82123b35663SRick Macklem 		    ("newnfs_request: NULL nr_cred"));
82223b35663SRick Macklem 		crfree(authcred);
82323b35663SRick Macklem 		authcred = crhold(nmp->nm_sockreq.nr_cred);
8249ec7b004SRick Macklem 	}
8259ec7b004SRick Macklem 
8269ec7b004SRick Macklem 	if (nmp != NULL) {
8279ec7b004SRick Macklem 		bzero(&nf, sizeof(struct nfs_feedback_arg));
8289ec7b004SRick Macklem 		nf.nf_mount = nmp;
8299ec7b004SRick Macklem 		nf.nf_td = td;
830a89a2c8bSJohn Baldwin 		nf.nf_lastmsg = NFSD_MONOSEC -
8319ec7b004SRick Macklem 		    ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay));
8329ec7b004SRick Macklem 	}
8339ec7b004SRick Macklem 
83415e8331fSRick Macklem 	if (nd->nd_procnum == NFSPROC_NULL)
83515e8331fSRick Macklem 		auth = authnone_create();
83688a2437aSRick Macklem 	else if (usegssname) {
83788a2437aSRick Macklem 		/*
83888a2437aSRick Macklem 		 * For this case, the authenticator is held in the
83988a2437aSRick Macklem 		 * nfssockreq structure, so don't release the reference count
84088a2437aSRick Macklem 		 * held on it. --> Don't AUTH_DESTROY() it in this function.
84188a2437aSRick Macklem 		 */
84288a2437aSRick Macklem 		if (nrp->nr_auth == NULL)
84388a2437aSRick Macklem 			nrp->nr_auth = nfs_getauth(nrp, secflavour,
84488a2437aSRick Macklem 			    clnt_principal, srv_principal, NULL, authcred);
8459ec7b004SRick Macklem 		else
84688a2437aSRick Macklem 			rpc_gss_refresh_auth_call(nrp->nr_auth);
84788a2437aSRick Macklem 		auth = nrp->nr_auth;
84888a2437aSRick Macklem 	} else
8499ec7b004SRick Macklem 		auth = nfs_getauth(nrp, secflavour, NULL,
85023b35663SRick Macklem 		    srv_principal, NULL, authcred);
85123b35663SRick Macklem 	crfree(authcred);
8529ec7b004SRick Macklem 	if (auth == NULL) {
8539ec7b004SRick Macklem 		m_freem(nd->nd_mreq);
854089f366aSRick Macklem 		if (set_sigset)
855089f366aSRick Macklem 			newnfs_restore_sigmask(td, &oldset);
8569ec7b004SRick Macklem 		return (EACCES);
8579ec7b004SRick Macklem 	}
8589ec7b004SRick Macklem 	bzero(&ext, sizeof(ext));
8599ec7b004SRick Macklem 	ext.rc_auth = auth;
8609ec7b004SRick Macklem 	if (nmp != NULL) {
8619ec7b004SRick Macklem 		ext.rc_feedback = nfs_feedback;
8629ec7b004SRick Macklem 		ext.rc_feedback_arg = &nf;
8639ec7b004SRick Macklem 	}
8649ec7b004SRick Macklem 
8659ec7b004SRick Macklem 	procnum = nd->nd_procnum;
8669ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) &&
86715e8331fSRick Macklem 	    nd->nd_procnum != NFSPROC_NULL &&
8689ec7b004SRick Macklem 	    nd->nd_procnum != NFSV4PROC_CBCOMPOUND)
8699ec7b004SRick Macklem 		procnum = NFSV4PROC_COMPOUND;
8709ec7b004SRick Macklem 
8719ec7b004SRick Macklem 	if (nmp != NULL) {
872a63b5d48SRick Macklem 		NFSINCRGLOBAL(nfsstatsv1.rpcrequests);
87323d9efa7SRick Macklem 
87423d9efa7SRick Macklem 		/* Map the procnum to the old NFSv2 one, as required. */
87523d9efa7SRick Macklem 		if ((nd->nd_flag & ND_NFSV2) != 0) {
87623d9efa7SRick Macklem 			if (nd->nd_procnum < NFS_V3NPROCS)
87723d9efa7SRick Macklem 				procnum = nfsv2_procid[nd->nd_procnum];
87823d9efa7SRick Macklem 			else
87923d9efa7SRick Macklem 				procnum = NFSV2PROC_NOOP;
88023d9efa7SRick Macklem 		}
88123d9efa7SRick Macklem 
8829ec7b004SRick Macklem 		/*
8839ec7b004SRick Macklem 		 * Now only used for the R_DONTRECOVER case, but until that is
8849ec7b004SRick Macklem 		 * supported within the krpc code, I need to keep a queue of
8859ec7b004SRick Macklem 		 * outstanding RPCs for nfsv4 client requests.
8869ec7b004SRick Macklem 		 */
8879ec7b004SRick Macklem 		if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND)
888222daa42SConrad Meyer 			rep = malloc(sizeof(struct nfsreq),
8899ec7b004SRick Macklem 			    M_NFSDREQ, M_WAITOK);
8908f0e65c9SRick Macklem #ifdef KDTRACE_HOOKS
8918f0e65c9SRick Macklem 		if (dtrace_nfscl_nfs234_start_probe != NULL) {
8928f0e65c9SRick Macklem 			uint32_t probe_id;
8938f0e65c9SRick Macklem 			int probe_procnum;
8948f0e65c9SRick Macklem 
8958f0e65c9SRick Macklem 			if (nd->nd_flag & ND_NFSV4) {
8968f0e65c9SRick Macklem 				probe_id =
8978f0e65c9SRick Macklem 				    nfscl_nfs4_start_probes[nd->nd_procnum];
8988f0e65c9SRick Macklem 				probe_procnum = nd->nd_procnum;
8998f0e65c9SRick Macklem 			} else if (nd->nd_flag & ND_NFSV3) {
9008f0e65c9SRick Macklem 				probe_id = nfscl_nfs3_start_probes[procnum];
9018f0e65c9SRick Macklem 				probe_procnum = procnum;
9028f0e65c9SRick Macklem 			} else {
9038f0e65c9SRick Macklem 				probe_id =
9048f0e65c9SRick Macklem 				    nfscl_nfs2_start_probes[nd->nd_procnum];
9058f0e65c9SRick Macklem 				probe_procnum = procnum;
9068f0e65c9SRick Macklem 			}
9078f0e65c9SRick Macklem 			if (probe_id != 0)
9088f0e65c9SRick Macklem 				(dtrace_nfscl_nfs234_start_probe)
9098f0e65c9SRick Macklem 				    (probe_id, vp, nd->nd_mreq, cred,
9108f0e65c9SRick Macklem 				     probe_procnum);
9118f0e65c9SRick Macklem 		}
9128f0e65c9SRick Macklem #endif
9139ec7b004SRick Macklem 	}
9141f60bfd8SRick Macklem 	freeslot = -1;		/* Set to slot that needs to be free'd */
9159ec7b004SRick Macklem tryagain:
9161f60bfd8SRick Macklem 	slot = -1;		/* Slot that needs a sequence# increment. */
917713f46acSRick Macklem 	/*
918713f46acSRick Macklem 	 * This timeout specifies when a new socket should be created,
919713f46acSRick Macklem 	 * along with new xid values. For UDP, this should be done
920713f46acSRick Macklem 	 * infrequently, since retransmits of RPC requests should normally
921713f46acSRick Macklem 	 * use the same xid.
922713f46acSRick Macklem 	 */
9239ec7b004SRick Macklem 	if (nmp == NULL) {
924fc0dc940SRick Macklem 		if (clp == NULL) {
9259ec7b004SRick Macklem 			timo.tv_sec = NFSV4_UPCALLTIMEO;
926fc0dc940SRick Macklem 			timo.tv_usec = 0;
927fc0dc940SRick Macklem 		} else {
928fc0dc940SRick Macklem 			timo.tv_sec = NFSV4_CALLBACKTIMEO / 1000;
929fc0dc940SRick Macklem 			timo.tv_usec = NFSV4_CALLBACKTIMEO * 1000;
930fc0dc940SRick Macklem 		}
9319ec7b004SRick Macklem 	} else {
9329ec7b004SRick Macklem 		if (nrp->nr_sotype != SOCK_DGRAM) {
9339ec7b004SRick Macklem 			timo.tv_usec = 0;
9349ec7b004SRick Macklem 			if ((nmp->nm_flag & NFSMNT_NFSV4))
9359ec7b004SRick Macklem 				timo.tv_sec = INT_MAX;
9369ec7b004SRick Macklem 			else
9379ec7b004SRick Macklem 				timo.tv_sec = NFS_TCPTIMEO;
9389ec7b004SRick Macklem 		} else {
939713f46acSRick Macklem 			if (NFSHASSOFT(nmp)) {
940713f46acSRick Macklem 				/*
941713f46acSRick Macklem 				 * CLSET_RETRIES is set to 2, so this should be
942713f46acSRick Macklem 				 * half of the total timeout required.
943713f46acSRick Macklem 				 */
944713f46acSRick Macklem 				timeo = nmp->nm_retry * nmp->nm_timeo / 2;
945713f46acSRick Macklem 				if (timeo < 1)
946713f46acSRick Macklem 					timeo = 1;
947713f46acSRick Macklem 				timo.tv_sec = timeo / NFS_HZ;
948713f46acSRick Macklem 				timo.tv_usec = (timeo % NFS_HZ) * 1000000 /
949713f46acSRick Macklem 				    NFS_HZ;
950713f46acSRick Macklem 			} else {
951713f46acSRick Macklem 				/* For UDP hard mounts, use a large value. */
952713f46acSRick Macklem 				timo.tv_sec = NFS_MAXTIMEO / NFS_HZ;
953713f46acSRick Macklem 				timo.tv_usec = 0;
954713f46acSRick Macklem 			}
9559ec7b004SRick Macklem 		}
9569ec7b004SRick Macklem 
9579ec7b004SRick Macklem 		if (rep != NULL) {
9589ec7b004SRick Macklem 			rep->r_flags = 0;
9599ec7b004SRick Macklem 			rep->r_nmp = nmp;
9609ec7b004SRick Macklem 			/*
9619ec7b004SRick Macklem 			 * Chain request into list of outstanding requests.
9629ec7b004SRick Macklem 			 */
9639ec7b004SRick Macklem 			NFSLOCKREQ();
9649ec7b004SRick Macklem 			TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain);
9659ec7b004SRick Macklem 			NFSUNLOCKREQ();
9669ec7b004SRick Macklem 		}
9679ec7b004SRick Macklem 	}
9689ec7b004SRick Macklem 
9699ec7b004SRick Macklem 	nd->nd_mrep = NULL;
970c59e4cc3SRick Macklem 	if (clp != NULL && sep != NULL)
971c59e4cc3SRick Macklem 		stat = clnt_bck_call(nrp->nr_client, &ext, procnum,
972c59e4cc3SRick Macklem 		    nd->nd_mreq, &nd->nd_mrep, timo, sep->nfsess_xprt);
9731e0a518dSRick Macklem 	else if (nextconn_set)
9741e0a518dSRick Macklem 		/*
9751e0a518dSRick Macklem 		 * When there are multiple TCP connections, send the
9761e0a518dSRick Macklem 		 * RPCs with large messages on the alternate TCP
9771e0a518dSRick Macklem 		 * connection(s) in a round robin fashion.
9781e0a518dSRick Macklem 		 * The small RPC messages are sent on the default
9791e0a518dSRick Macklem 		 * TCP connection because they do not require much
9801e0a518dSRick Macklem 		 * network bandwidth and separating them from the
9811e0a518dSRick Macklem 		 * large RPC messages avoids them getting "log jammed"
9821e0a518dSRick Macklem 		 * behind several large RPC messages.
9831e0a518dSRick Macklem 		 */
9841e0a518dSRick Macklem 		stat = CLNT_CALL_MBUF(nmp->nm_aconn[nextconn],
9851e0a518dSRick Macklem 		    &ext, procnum, nd->nd_mreq, &nd->nd_mrep, timo);
986c59e4cc3SRick Macklem 	else
987c59e4cc3SRick Macklem 		stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum,
988c59e4cc3SRick Macklem 		    nd->nd_mreq, &nd->nd_mrep, timo);
989ba6cce3aSRick Macklem 	NFSCL_DEBUG(2, "clnt call=%d\n", stat);
9909ec7b004SRick Macklem 
9919ec7b004SRick Macklem 	if (rep != NULL) {
9929ec7b004SRick Macklem 		/*
9939ec7b004SRick Macklem 		 * RPC done, unlink the request.
9949ec7b004SRick Macklem 		 */
9959ec7b004SRick Macklem 		NFSLOCKREQ();
9969ec7b004SRick Macklem 		TAILQ_REMOVE(&nfsd_reqq, rep, r_chain);
9979ec7b004SRick Macklem 		NFSUNLOCKREQ();
9989ec7b004SRick Macklem 	}
9999ec7b004SRick Macklem 
10009ec7b004SRick Macklem 	/*
10019ec7b004SRick Macklem 	 * If there was a successful reply and a tprintf msg.
10029ec7b004SRick Macklem 	 * tprintf a response.
10039ec7b004SRick Macklem 	 */
10049ec7b004SRick Macklem 	if (stat == RPC_SUCCESS) {
10059ec7b004SRick Macklem 		error = 0;
10069ec7b004SRick Macklem 	} else if (stat == RPC_TIMEDOUT) {
1007a63b5d48SRick Macklem 		NFSINCRGLOBAL(nfsstatsv1.rpctimeouts);
10089ec7b004SRick Macklem 		error = ETIMEDOUT;
10099ec7b004SRick Macklem 	} else if (stat == RPC_VERSMISMATCH) {
1010a63b5d48SRick Macklem 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
10119ec7b004SRick Macklem 		error = EOPNOTSUPP;
10129ec7b004SRick Macklem 	} else if (stat == RPC_PROGVERSMISMATCH) {
1013a63b5d48SRick Macklem 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
10149ec7b004SRick Macklem 		error = EPROTONOSUPPORT;
1015ba6cce3aSRick Macklem 	} else if (stat == RPC_CANTSEND || stat == RPC_CANTRECV ||
1016981ef322SRick Macklem 	     stat == RPC_SYSTEMERROR || stat == RPC_INTR) {
1017ba6cce3aSRick Macklem 		/* Check for a session slot that needs to be free'd. */
1018ba6cce3aSRick Macklem 		if ((nd->nd_flag & (ND_NFSV41 | ND_HASSLOTID)) ==
1019ba6cce3aSRick Macklem 		    (ND_NFSV41 | ND_HASSLOTID) && nmp != NULL &&
1020ba6cce3aSRick Macklem 		    nd->nd_procnum != NFSPROC_NULL) {
1021ba6cce3aSRick Macklem 			/*
1022ba6cce3aSRick Macklem 			 * This should only occur when either the MDS or
1023ba6cce3aSRick Macklem 			 * a client has an RPC against a DS fail.
1024ba6cce3aSRick Macklem 			 * This happens because these cases use "soft"
1025ba6cce3aSRick Macklem 			 * connections that can time out and fail.
1026ba6cce3aSRick Macklem 			 * The slot used for this RPC is now in a
1027ba6cce3aSRick Macklem 			 * non-deterministic state, but if the slot isn't
1028ba6cce3aSRick Macklem 			 * free'd, threads can get stuck waiting for a slot.
1029ba6cce3aSRick Macklem 			 */
1030ba6cce3aSRick Macklem 			if (sep == NULL)
1031ba6cce3aSRick Macklem 				sep = nfsmnt_mdssession(nmp);
1032ba6cce3aSRick Macklem 			/*
1033ba6cce3aSRick Macklem 			 * Bump the sequence# out of range, so that reuse of
1034ba6cce3aSRick Macklem 			 * this slot will result in an NFSERR_SEQMISORDERED
1035ba6cce3aSRick Macklem 			 * error and not a bogus cached RPC reply.
1036ba6cce3aSRick Macklem 			 */
1037ba6cce3aSRick Macklem 			mtx_lock(&sep->nfsess_mtx);
1038ba6cce3aSRick Macklem 			sep->nfsess_slotseq[nd->nd_slotid] += 10;
1039981ef322SRick Macklem 			sep->nfsess_badslots |= (0x1ULL << nd->nd_slotid);
1040ba6cce3aSRick Macklem 			mtx_unlock(&sep->nfsess_mtx);
1041ba6cce3aSRick Macklem 			/* And free the slot. */
1042b97a4788SRick Macklem 			nfsv4_freeslot(sep, nd->nd_slotid, true);
1043ba6cce3aSRick Macklem 		}
1044981ef322SRick Macklem 		if (stat == RPC_INTR)
1045981ef322SRick Macklem 			error = EINTR;
1046981ef322SRick Macklem 		else {
1047a63b5d48SRick Macklem 			NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
1048ba6cce3aSRick Macklem 			error = ENXIO;
1049981ef322SRick Macklem 		}
1050a5581308SRick Macklem 	} else if (stat == RPC_AUTHERROR) {
1051a5581308SRick Macklem 		/* Check for a session slot that needs to be free'd. */
1052a5581308SRick Macklem 		if ((nd->nd_flag & (ND_NFSV41 | ND_HASSLOTID)) ==
1053a5581308SRick Macklem 		    (ND_NFSV41 | ND_HASSLOTID) && nmp != NULL &&
1054a5581308SRick Macklem 		    nd->nd_procnum != NFSPROC_NULL) {
1055a5581308SRick Macklem 			/*
1056a5581308SRick Macklem 			 * This can occur when a Kerberos/RPCSEC_GSS session
1057a5581308SRick Macklem 			 * expires, due to TGT expiration.
1058a5581308SRick Macklem 			 * Free the slot, resetting the slot's sequence#.
1059a5581308SRick Macklem 			 */
1060a5581308SRick Macklem 			if (sep == NULL)
1061a5581308SRick Macklem 				sep = nfsmnt_mdssession(nmp);
1062a5581308SRick Macklem 			nfsv4_freeslot(sep, nd->nd_slotid, true);
1063a5581308SRick Macklem 		}
1064a5581308SRick Macklem 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
1065a5581308SRick Macklem 		error = EACCES;
10669ec7b004SRick Macklem 	} else {
1067a63b5d48SRick Macklem 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
10689ec7b004SRick Macklem 		error = EACCES;
10699ec7b004SRick Macklem 	}
10709ec7b004SRick Macklem 	if (error) {
10719ec7b004SRick Macklem 		m_freem(nd->nd_mreq);
107288a2437aSRick Macklem 		if (usegssname == 0)
10739ec7b004SRick Macklem 			AUTH_DESTROY(auth);
10749ec7b004SRick Macklem 		if (rep != NULL)
1075222daa42SConrad Meyer 			free(rep, M_NFSDREQ);
1076089f366aSRick Macklem 		if (set_sigset)
1077089f366aSRick Macklem 			newnfs_restore_sigmask(td, &oldset);
10789ec7b004SRick Macklem 		return (error);
10799ec7b004SRick Macklem 	}
10809ec7b004SRick Macklem 
10819ec7b004SRick Macklem 	KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n"));
10829ec7b004SRick Macklem 
108305c965a2SRick Macklem 	/*
108405c965a2SRick Macklem 	 * Search for any mbufs that are not a multiple of 4 bytes long
108505c965a2SRick Macklem 	 * or with m_data not longword aligned.
108605c965a2SRick Macklem 	 * These could cause pointer alignment problems, so copy them to
108705c965a2SRick Macklem 	 * well aligned mbufs.
108805c965a2SRick Macklem 	 */
1089d96b98a3SKenneth D. Merry 	newnfs_realign(&nd->nd_mrep, M_WAITOK);
10909ec7b004SRick Macklem 	nd->nd_md = nd->nd_mrep;
1091e3e7c612SRick Macklem 	nd->nd_dpos = mtod(nd->nd_md, caddr_t);
10929ec7b004SRick Macklem 	nd->nd_repstat = 0;
1093c59e4cc3SRick Macklem 	if (nd->nd_procnum != NFSPROC_NULL &&
1094c59e4cc3SRick Macklem 	    nd->nd_procnum != NFSV4PROC_CBNULL) {
10951f60bfd8SRick Macklem 		/* If sep == NULL, set it to the default in nmp. */
10961f60bfd8SRick Macklem 		if (sep == NULL && nmp != NULL)
1097b2fc0141SRick Macklem 			sep = nfsmnt_mdssession(nmp);
10989ec7b004SRick Macklem 		/*
10999ec7b004SRick Macklem 		 * and now the actual NFS xdr.
11009ec7b004SRick Macklem 		 */
11019ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11029ec7b004SRick Macklem 		nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl);
11031f60bfd8SRick Macklem 		if (nd->nd_repstat >= 10000)
11041f60bfd8SRick Macklem 			NFSCL_DEBUG(1, "proc=%d reps=%d\n", (int)nd->nd_procnum,
11051f60bfd8SRick Macklem 			    (int)nd->nd_repstat);
11061f60bfd8SRick Macklem 
11071f60bfd8SRick Macklem 		/*
11081f60bfd8SRick Macklem 		 * Get rid of the tag, return count and SEQUENCE result for
11091f60bfd8SRick Macklem 		 * NFSv4.
11101f60bfd8SRick Macklem 		 */
11118e1906f7SRick Macklem 		if ((nd->nd_flag & ND_NFSV4) != 0 && nd->nd_repstat !=
11128e1906f7SRick Macklem 		    NFSERR_MINORVERMISMATCH) {
11131f60bfd8SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11141f60bfd8SRick Macklem 			i = fxdr_unsigned(int, *tl);
11151f60bfd8SRick Macklem 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
11161f60bfd8SRick Macklem 			if (error)
11171f60bfd8SRick Macklem 				goto nfsmout;
11181f60bfd8SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
11191f60bfd8SRick Macklem 			opcnt = fxdr_unsigned(int, *tl++);
11201f60bfd8SRick Macklem 			i = fxdr_unsigned(int, *tl++);
11211f60bfd8SRick Macklem 			j = fxdr_unsigned(int, *tl);
11221f60bfd8SRick Macklem 			if (j >= 10000)
11231f60bfd8SRick Macklem 				NFSCL_DEBUG(1, "fop=%d fst=%d\n", i, j);
11241f60bfd8SRick Macklem 			/*
11251f60bfd8SRick Macklem 			 * If the first op is Sequence, free up the slot.
11261f60bfd8SRick Macklem 			 */
1127c59e4cc3SRick Macklem 			if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) ||
1128981ef322SRick Macklem 			   (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0)) {
11291f60bfd8SRick Macklem 				NFSCL_DEBUG(1, "failed seq=%d\n", j);
1130981ef322SRick Macklem 				if (sep != NULL && i == NFSV4OP_SEQUENCE &&
1131981ef322SRick Macklem 				    j == NFSERR_SEQMISORDERED) {
1132981ef322SRick Macklem 					mtx_lock(&sep->nfsess_mtx);
1133981ef322SRick Macklem 					sep->nfsess_badslots |=
1134981ef322SRick Macklem 					    (0x1ULL << nd->nd_slotid);
1135981ef322SRick Macklem 					mtx_unlock(&sep->nfsess_mtx);
1136981ef322SRick Macklem 				}
1137981ef322SRick Macklem 			}
113873b1879cSRick Macklem 			if (((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) ||
113973b1879cSRick Macklem 			    (clp != NULL && i == NFSV4OP_CBSEQUENCE &&
114073b1879cSRick Macklem 			    j == 0)) && sep != NULL) {
1141c59e4cc3SRick Macklem 				if (i == NFSV4OP_SEQUENCE)
1142c59e4cc3SRick Macklem 					NFSM_DISSECT(tl, uint32_t *,
1143c59e4cc3SRick Macklem 					    NFSX_V4SESSIONID +
11441f60bfd8SRick Macklem 					    5 * NFSX_UNSIGNED);
1145c59e4cc3SRick Macklem 				else
1146c59e4cc3SRick Macklem 					NFSM_DISSECT(tl, uint32_t *,
1147c59e4cc3SRick Macklem 					    NFSX_V4SESSIONID +
1148c59e4cc3SRick Macklem 					    4 * NFSX_UNSIGNED);
11491f60bfd8SRick Macklem 				mtx_lock(&sep->nfsess_mtx);
1150b2fc0141SRick Macklem 				if (bcmp(tl, sep->nfsess_sessionid,
1151b2fc0141SRick Macklem 				    NFSX_V4SESSIONID) == 0) {
11521f60bfd8SRick Macklem 					tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
11531f60bfd8SRick Macklem 					retseq = fxdr_unsigned(uint32_t, *tl++);
11541f60bfd8SRick Macklem 					slot = fxdr_unsigned(int, *tl++);
11551c15c8c0SRick Macklem 					if ((nd->nd_flag & ND_HASSLOTID) != 0) {
1156981ef322SRick Macklem 						if (slot >= NFSV4_SLOTS ||
1157981ef322SRick Macklem 						    (i == NFSV4OP_CBSEQUENCE &&
1158981ef322SRick Macklem 						     slot >= NFSV4_CBSLOTS)) {
1159981ef322SRick Macklem 							printf("newnfs_request:"
1160981ef322SRick Macklem 							    " Bogus slot\n");
1161981ef322SRick Macklem 							slot = nd->nd_slotid;
1162981ef322SRick Macklem 						} else if (slot !=
1163981ef322SRick Macklem 						    nd->nd_slotid) {
11641c15c8c0SRick Macklem 						    printf("newnfs_request:"
11651c15c8c0SRick Macklem 							" Wrong session "
1166981ef322SRick Macklem 							"srvslot=%d "
1167981ef322SRick Macklem 							"slot=%d\n", slot,
1168981ef322SRick Macklem 							nd->nd_slotid);
1169981ef322SRick Macklem 						    if (i == NFSV4OP_SEQUENCE) {
1170981ef322SRick Macklem 							/*
1171981ef322SRick Macklem 							 * Mark both slots as
1172981ef322SRick Macklem 							 * bad, because we do
1173981ef322SRick Macklem 							 * not know if the
1174981ef322SRick Macklem 							 * server has advanced
1175981ef322SRick Macklem 							 * the sequence# for
1176981ef322SRick Macklem 							 * either of them.
1177981ef322SRick Macklem 							 */
1178981ef322SRick Macklem 							sep->nfsess_badslots |=
1179981ef322SRick Macklem 							    (0x1ULL << slot);
1180981ef322SRick Macklem 							sep->nfsess_badslots |=
1181981ef322SRick Macklem 							    (0x1ULL <<
1182981ef322SRick Macklem 							     nd->nd_slotid);
1183981ef322SRick Macklem 						    }
11841c15c8c0SRick Macklem 						    slot = nd->nd_slotid;
11851c15c8c0SRick Macklem 						}
11862b612c9dSRick Macklem 						freeslot = slot;
11871c15c8c0SRick Macklem 					} else if (slot != 0) {
11881c15c8c0SRick Macklem 						printf("newnfs_request: Bad "
11891c15c8c0SRick Macklem 						    "session slot=%d\n", slot);
11901c15c8c0SRick Macklem 						slot = 0;
11911c15c8c0SRick Macklem 					}
11921f60bfd8SRick Macklem 					if (retseq != sep->nfsess_slotseq[slot])
1193b2fc0141SRick Macklem 						printf("retseq diff 0x%x\n",
1194b2fc0141SRick Macklem 						    retseq);
1195b97a4788SRick Macklem 					retval0 = fxdr_unsigned(uint32_t,*tl++);
1196b97a4788SRick Macklem 					retval = fxdr_unsigned(uint32_t, *tl);
1197b2fc0141SRick Macklem 					if ((retval + 1) < sep->nfsess_foreslots
1198b97a4788SRick Macklem 					    ) {
1199b2fc0141SRick Macklem 						sep->nfsess_foreslots = (retval
1200b2fc0141SRick Macklem 						    + 1);
1201b97a4788SRick Macklem 						nfs_resetslots(sep);
1202b97a4788SRick Macklem 					} else if ((retval + 1) >
1203b97a4788SRick Macklem 					    sep->nfsess_foreslots) {
1204b97a4788SRick Macklem 						if (retval0 > retval)
1205b97a4788SRick Macklem 							printf("Sess:highest > "
1206b97a4788SRick Macklem 							    "target_highest\n");
1207b97a4788SRick Macklem 						sep->nfsess_foreslots =
1208b97a4788SRick Macklem 						    (retval < NFSV4_SLOTS) ?
1209b97a4788SRick Macklem 						    (retval + 1) : NFSV4_SLOTS;
1210b97a4788SRick Macklem 					}
1211b2fc0141SRick Macklem 				}
12121f60bfd8SRick Macklem 				mtx_unlock(&sep->nfsess_mtx);
12131f60bfd8SRick Macklem 
12141f60bfd8SRick Macklem 				/* Grab the op and status for the next one. */
12151f60bfd8SRick Macklem 				if (opcnt > 1) {
12161f60bfd8SRick Macklem 					NFSM_DISSECT(tl, uint32_t *,
12171f60bfd8SRick Macklem 					    2 * NFSX_UNSIGNED);
12181f60bfd8SRick Macklem 					i = fxdr_unsigned(int, *tl++);
12191f60bfd8SRick Macklem 					j = fxdr_unsigned(int, *tl);
12201f60bfd8SRick Macklem 				}
12211f60bfd8SRick Macklem 			}
12221f60bfd8SRick Macklem 		}
12239ec7b004SRick Macklem 		if (nd->nd_repstat != 0) {
1224b2fc0141SRick Macklem 			if (nd->nd_repstat == NFSERR_BADSESSION &&
122573b1879cSRick Macklem 			    nmp != NULL && dssep == NULL &&
122673b1879cSRick Macklem 			    (nd->nd_flag & ND_NFSV41) != 0) {
1227b2fc0141SRick Macklem 				/*
1228b2fc0141SRick Macklem 				 * If this is a client side MDS RPC, mark
1229b2fc0141SRick Macklem 				 * the MDS session defunct and initiate
1230b2fc0141SRick Macklem 				 * recovery, as required.
1231b2fc0141SRick Macklem 				 * The nfsess_defunct field is protected by
1232b2fc0141SRick Macklem 				 * the NFSLOCKMNT()/nm_mtx lock and not the
1233b2fc0141SRick Macklem 				 * nfsess_mtx lock to simplify its handling,
1234b2fc0141SRick Macklem 				 * for the MDS session. This lock is also
1235b2fc0141SRick Macklem 				 * sufficient for nfsess_sessionid, since it
1236b2fc0141SRick Macklem 				 * never changes in the structure.
1237b2fc0141SRick Macklem 				 */
1238b2fc0141SRick Macklem 				NFSCL_DEBUG(1, "Got badsession\n");
1239b2fc0141SRick Macklem 				NFSLOCKCLSTATE();
1240b2fc0141SRick Macklem 				NFSLOCKMNT(nmp);
1241db7257efSRick Macklem 				if (TAILQ_EMPTY(&nmp->nm_sess)) {
1242db7257efSRick Macklem 					NFSUNLOCKMNT(nmp);
1243db7257efSRick Macklem 					NFSUNLOCKCLSTATE();
1244db7257efSRick Macklem 					printf("If server has not rebooted, "
1245db7257efSRick Macklem 					    "check NFS clients for unique "
1246db7257efSRick Macklem 					    "/etc/hostid's\n");
1247db7257efSRick Macklem 					goto out;
1248db7257efSRick Macklem 				}
1249b2fc0141SRick Macklem 				sep = NFSMNT_MDSSESSION(nmp);
1250b2fc0141SRick Macklem 				if (bcmp(sep->nfsess_sessionid, nd->nd_sequence,
1251b2fc0141SRick Macklem 				    NFSX_V4SESSIONID) == 0) {
12520685c73cSRick Macklem 					printf("Initiate recovery. If server "
12530685c73cSRick Macklem 					    "has not rebooted, "
12540685c73cSRick Macklem 					    "check NFS clients for unique "
12550685c73cSRick Macklem 					    "/etc/hostid's\n");
1256b2fc0141SRick Macklem 					/* Initiate recovery. */
1257b2fc0141SRick Macklem 					sep->nfsess_defunct = 1;
1258b2fc0141SRick Macklem 					NFSCL_DEBUG(1, "Marked defunct\n");
1259b2fc0141SRick Macklem 					if (nmp->nm_clp != NULL) {
1260b2fc0141SRick Macklem 						nmp->nm_clp->nfsc_flags |=
1261b2fc0141SRick Macklem 						    NFSCLFLAGS_RECOVER;
1262b2fc0141SRick Macklem 						wakeup(nmp->nm_clp);
1263b2fc0141SRick Macklem 					}
1264b2fc0141SRick Macklem 				}
1265b2fc0141SRick Macklem 				NFSUNLOCKCLSTATE();
1266b2fc0141SRick Macklem 				/*
1267b2fc0141SRick Macklem 				 * Sleep for up to 1sec waiting for a new
1268b2fc0141SRick Macklem 				 * session.
1269b2fc0141SRick Macklem 				 */
1270b2fc0141SRick Macklem 				mtx_sleep(&nmp->nm_sess, &nmp->nm_mtx, PZERO,
1271b2fc0141SRick Macklem 				    "nfsbadsess", hz);
1272b2fc0141SRick Macklem 				/*
1273b2fc0141SRick Macklem 				 * Get the session again, in case a new one
1274b2fc0141SRick Macklem 				 * has been created during the sleep.
1275b2fc0141SRick Macklem 				 */
1276b2fc0141SRick Macklem 				sep = NFSMNT_MDSSESSION(nmp);
1277b2fc0141SRick Macklem 				NFSUNLOCKMNT(nmp);
1278b2fc0141SRick Macklem 				if ((nd->nd_flag & ND_LOOPBADSESS) != 0) {
1279b2fc0141SRick Macklem 					reterr = nfsv4_sequencelookup(nmp, sep,
1280b2fc0141SRick Macklem 					    &slotpos, &maxslot, &slotseq,
128140ada74eSRick Macklem 					    sessionid, true);
1282b2fc0141SRick Macklem 					if (reterr == 0) {
1283b2fc0141SRick Macklem 						/* Fill in new session info. */
1284b2fc0141SRick Macklem 						NFSCL_DEBUG(1,
1285b2fc0141SRick Macklem 						  "Filling in new sequence\n");
1286b2fc0141SRick Macklem 						tl = nd->nd_sequence;
1287b2fc0141SRick Macklem 						bcopy(sessionid, tl,
1288b2fc0141SRick Macklem 						    NFSX_V4SESSIONID);
1289b2fc0141SRick Macklem 						tl += NFSX_V4SESSIONID /
1290b2fc0141SRick Macklem 						    NFSX_UNSIGNED;
1291b2fc0141SRick Macklem 						*tl++ = txdr_unsigned(slotseq);
1292b2fc0141SRick Macklem 						*tl++ = txdr_unsigned(slotpos);
1293b2fc0141SRick Macklem 						*tl = txdr_unsigned(maxslot);
1294fb29f817SRick Macklem 						nd->nd_slotid = slotpos;
1295fb29f817SRick Macklem 						nd->nd_flag |= ND_HASSLOTID;
1296b2fc0141SRick Macklem 					}
1297b2fc0141SRick Macklem 					if (reterr == NFSERR_BADSESSION ||
1298b2fc0141SRick Macklem 					    reterr == 0) {
1299b2fc0141SRick Macklem 						NFSCL_DEBUG(1,
1300b2fc0141SRick Macklem 						    "Badsession looping\n");
1301b2fc0141SRick Macklem 						m_freem(nd->nd_mrep);
1302b2fc0141SRick Macklem 						nd->nd_mrep = NULL;
1303b2fc0141SRick Macklem 						goto tryagain;
1304b2fc0141SRick Macklem 					}
1305b2fc0141SRick Macklem 					nd->nd_repstat = reterr;
1306b2fc0141SRick Macklem 					NFSCL_DEBUG(1, "Got err=%d\n", reterr);
1307b2fc0141SRick Macklem 				}
1308b2fc0141SRick Macklem 			}
130993df87f2SRick Macklem 			/*
131093df87f2SRick Macklem 			 * When clp != NULL, it is a callback and all
131193df87f2SRick Macklem 			 * callback operations can be retried for NFSERR_DELAY.
131293df87f2SRick Macklem 			 */
13136a536ceeSRick Macklem 			if (((nd->nd_repstat == NFSERR_DELAY ||
13146a536ceeSRick Macklem 			      nd->nd_repstat == NFSERR_GRACE) &&
131593df87f2SRick Macklem 			     (nd->nd_flag & ND_NFSV4) && (clp != NULL ||
131693df87f2SRick Macklem 			     (nd->nd_procnum != NFSPROC_DELEGRETURN &&
13179ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_SETATTR &&
13189ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_READ &&
13191f60bfd8SRick Macklem 			     nd->nd_procnum != NFSPROC_READDS &&
13209ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_WRITE &&
13211f60bfd8SRick Macklem 			     nd->nd_procnum != NFSPROC_WRITEDS &&
13229ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_OPEN &&
1323f5ff282bSRick Macklem 			     nd->nd_procnum != NFSPROC_OPENLAYGET &&
13249ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_CREATE &&
1325f5ff282bSRick Macklem 			     nd->nd_procnum != NFSPROC_CREATELAYGET &&
13269ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_OPENCONFIRM &&
13279ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_OPENDOWNGRADE &&
13289ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_CLOSE &&
13299ec7b004SRick Macklem 			     nd->nd_procnum != NFSPROC_LOCK &&
133093df87f2SRick Macklem 			     nd->nd_procnum != NFSPROC_LOCKU))) ||
13319ec7b004SRick Macklem 			    (nd->nd_repstat == NFSERR_DELAY &&
13329ec7b004SRick Macklem 			     (nd->nd_flag & ND_NFSV4) == 0) ||
1333c4e29825SRick Macklem 			    nd->nd_repstat == NFSERR_RESOURCE ||
1334c4e29825SRick Macklem 			    nd->nd_repstat == NFSERR_RETRYUNCACHEDREP) {
13355a95a6e8SRick Macklem 				/* Clip at NFS_TRYLATERDEL. */
13365a95a6e8SRick Macklem 				if (timespeccmp(&trylater_delay,
13375a95a6e8SRick Macklem 				    &nfs_trylater_max, >))
13385a95a6e8SRick Macklem 					trylater_delay = nfs_trylater_max;
13395a95a6e8SRick Macklem 				getnanouptime(&waituntil);
13405a95a6e8SRick Macklem 				timespecadd(&waituntil, &trylater_delay,
13415a95a6e8SRick Macklem 				    &waituntil);
13425a95a6e8SRick Macklem 				do {
13435a95a6e8SRick Macklem 					nfs_catnap(PZERO, 0, "nfstry");
13445a95a6e8SRick Macklem 					getnanouptime(&ts);
13455a95a6e8SRick Macklem 				} while (timespeccmp(&ts, &waituntil, <));
13465a95a6e8SRick Macklem 				timespecadd(&trylater_delay, &trylater_delay,
13475a95a6e8SRick Macklem 				    &trylater_delay);	/* Double each time. */
13481f60bfd8SRick Macklem 				if (slot != -1) {
13491f60bfd8SRick Macklem 					mtx_lock(&sep->nfsess_mtx);
13501f60bfd8SRick Macklem 					sep->nfsess_slotseq[slot]++;
13511f60bfd8SRick Macklem 					*nd->nd_slotseq = txdr_unsigned(
13521f60bfd8SRick Macklem 					    sep->nfsess_slotseq[slot]);
13531f60bfd8SRick Macklem 					mtx_unlock(&sep->nfsess_mtx);
13541f60bfd8SRick Macklem 				}
13557bb55defSRick Macklem 				m_freem(nd->nd_mrep);
13567bb55defSRick Macklem 				nd->nd_mrep = NULL;
13579ec7b004SRick Macklem 				goto tryagain;
13589ec7b004SRick Macklem 			}
13599ec7b004SRick Macklem 
13609ec7b004SRick Macklem 			/*
13619ec7b004SRick Macklem 			 * If the File Handle was stale, invalidate the
13629ec7b004SRick Macklem 			 * lookup cache, just in case.
13639ec7b004SRick Macklem 			 * (vp != NULL implies a client side call)
13649ec7b004SRick Macklem 			 */
13659ec7b004SRick Macklem 			if (nd->nd_repstat == ESTALE && vp != NULL) {
13669ec7b004SRick Macklem 				cache_purge(vp);
13679ec7b004SRick Macklem 				if (ncl_call_invalcaches != NULL)
13689ec7b004SRick Macklem 					(*ncl_call_invalcaches)(vp);
13699ec7b004SRick Macklem 			}
13709ec7b004SRick Macklem 		}
13711f60bfd8SRick Macklem 		if ((nd->nd_flag & ND_NFSV4) != 0) {
13721f60bfd8SRick Macklem 			/* Free the slot, as required. */
13731f60bfd8SRick Macklem 			if (freeslot != -1)
137487597731SRick Macklem 				nfsv4_freeslot(sep, freeslot, false);
13759ec7b004SRick Macklem 			/*
13761f60bfd8SRick Macklem 			 * If this op is Putfh, throw its results away.
13779ec7b004SRick Macklem 			 */
13781f60bfd8SRick Macklem 			if (j >= 10000)
13791f60bfd8SRick Macklem 				NFSCL_DEBUG(1, "nop=%d nst=%d\n", i, j);
13801f60bfd8SRick Macklem 			if (nmp != NULL && i == NFSV4OP_PUTFH && j == 0) {
13819ec7b004SRick Macklem 				NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED);
13829ec7b004SRick Macklem 				i = fxdr_unsigned(int, *tl++);
13839ec7b004SRick Macklem 				j = fxdr_unsigned(int, *tl);
13841f60bfd8SRick Macklem 				if (j >= 10000)
13851f60bfd8SRick Macklem 					NFSCL_DEBUG(1, "n2op=%d n2st=%d\n", i,
13861f60bfd8SRick Macklem 					    j);
13879ec7b004SRick Macklem 				/*
13889ec7b004SRick Macklem 				 * All Compounds that do an Op that must
13899ec7b004SRick Macklem 				 * be in sequence consist of NFSV4OP_PUTFH
13909ec7b004SRick Macklem 				 * followed by one of these. As such, we
13919ec7b004SRick Macklem 				 * can determine if the seqid# should be
13929ec7b004SRick Macklem 				 * incremented, here.
13939ec7b004SRick Macklem 				 */
13949ec7b004SRick Macklem 				if ((i == NFSV4OP_OPEN ||
13959ec7b004SRick Macklem 				     i == NFSV4OP_OPENCONFIRM ||
13969ec7b004SRick Macklem 				     i == NFSV4OP_OPENDOWNGRADE ||
13979ec7b004SRick Macklem 				     i == NFSV4OP_CLOSE ||
13989ec7b004SRick Macklem 				     i == NFSV4OP_LOCK ||
13999ec7b004SRick Macklem 				     i == NFSV4OP_LOCKU) &&
14009ec7b004SRick Macklem 				    (j == 0 ||
14019ec7b004SRick Macklem 				     (j != NFSERR_STALECLIENTID &&
14029ec7b004SRick Macklem 				      j != NFSERR_STALESTATEID &&
14039ec7b004SRick Macklem 				      j != NFSERR_BADSTATEID &&
14049ec7b004SRick Macklem 				      j != NFSERR_BADSEQID &&
14059ec7b004SRick Macklem 				      j != NFSERR_BADXDR &&
14069ec7b004SRick Macklem 				      j != NFSERR_RESOURCE &&
14079ec7b004SRick Macklem 				      j != NFSERR_NOFILEHANDLE)))
14089ec7b004SRick Macklem 					nd->nd_flag |= ND_INCRSEQID;
14091f60bfd8SRick Macklem 			}
14109ec7b004SRick Macklem 			/*
14111f60bfd8SRick Macklem 			 * If this op's status is non-zero, mark
14129ec7b004SRick Macklem 			 * that there is no more data to process.
14130596f343SRick Macklem 			 * The exception is Setattr, which always has xdr
14140596f343SRick Macklem 			 * when it has failed.
14159ec7b004SRick Macklem 			 */
14160596f343SRick Macklem 			if (j != 0 && i != NFSV4OP_SETATTR)
14179ec7b004SRick Macklem 				nd->nd_flag |= ND_NOMOREDATA;
14189ec7b004SRick Macklem 
14199ec7b004SRick Macklem 			/*
14209ec7b004SRick Macklem 			 * If R_DONTRECOVER is set, replace the stale error
14219ec7b004SRick Macklem 			 * reply, so that recovery isn't initiated.
14229ec7b004SRick Macklem 			 */
14239ec7b004SRick Macklem 			if ((nd->nd_repstat == NFSERR_STALECLIENTID ||
14241f60bfd8SRick Macklem 			     nd->nd_repstat == NFSERR_BADSESSION ||
14259ec7b004SRick Macklem 			     nd->nd_repstat == NFSERR_STALESTATEID) &&
14269ec7b004SRick Macklem 			    rep != NULL && (rep->r_flags & R_DONTRECOVER))
14279ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_STALEDONTRECOVER;
14289ec7b004SRick Macklem 		}
142915e8331fSRick Macklem 	}
1430db7257efSRick Macklem out:
14319ec7b004SRick Macklem 
14328f0e65c9SRick Macklem #ifdef KDTRACE_HOOKS
14338f0e65c9SRick Macklem 	if (nmp != NULL && dtrace_nfscl_nfs234_done_probe != NULL) {
14348f0e65c9SRick Macklem 		uint32_t probe_id;
14358f0e65c9SRick Macklem 		int probe_procnum;
14368f0e65c9SRick Macklem 
14378f0e65c9SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
14388f0e65c9SRick Macklem 			probe_id = nfscl_nfs4_done_probes[nd->nd_procnum];
14398f0e65c9SRick Macklem 			probe_procnum = nd->nd_procnum;
14408f0e65c9SRick Macklem 		} else if (nd->nd_flag & ND_NFSV3) {
14418f0e65c9SRick Macklem 			probe_id = nfscl_nfs3_done_probes[procnum];
14428f0e65c9SRick Macklem 			probe_procnum = procnum;
14438f0e65c9SRick Macklem 		} else {
14448f0e65c9SRick Macklem 			probe_id = nfscl_nfs2_done_probes[nd->nd_procnum];
14458f0e65c9SRick Macklem 			probe_procnum = procnum;
14468f0e65c9SRick Macklem 		}
14478f0e65c9SRick Macklem 		if (probe_id != 0)
14488f0e65c9SRick Macklem 			(dtrace_nfscl_nfs234_done_probe)(probe_id, vp,
14498f0e65c9SRick Macklem 			    nd->nd_mreq, cred, probe_procnum, 0);
14508f0e65c9SRick Macklem 	}
14518f0e65c9SRick Macklem #endif
14528f0e65c9SRick Macklem 
14539ec7b004SRick Macklem 	m_freem(nd->nd_mreq);
145488a2437aSRick Macklem 	if (usegssname == 0)
14559ec7b004SRick Macklem 		AUTH_DESTROY(auth);
14569ec7b004SRick Macklem 	if (rep != NULL)
1457222daa42SConrad Meyer 		free(rep, M_NFSDREQ);
1458089f366aSRick Macklem 	if (set_sigset)
1459089f366aSRick Macklem 		newnfs_restore_sigmask(td, &oldset);
14609ec7b004SRick Macklem 	return (0);
14619ec7b004SRick Macklem nfsmout:
14629f6624d3SRick Macklem 	m_freem(nd->nd_mrep);
14639f6624d3SRick Macklem 	m_freem(nd->nd_mreq);
146488a2437aSRick Macklem 	if (usegssname == 0)
14659ec7b004SRick Macklem 		AUTH_DESTROY(auth);
14669ec7b004SRick Macklem 	if (rep != NULL)
1467222daa42SConrad Meyer 		free(rep, M_NFSDREQ);
1468089f366aSRick Macklem 	if (set_sigset)
1469089f366aSRick Macklem 		newnfs_restore_sigmask(td, &oldset);
14709ec7b004SRick Macklem 	return (error);
14719ec7b004SRick Macklem }
14729ec7b004SRick Macklem 
14739ec7b004SRick Macklem /*
1474b97a4788SRick Macklem  * Reset slots above nfsess_foreslots that are not busy.
1475b97a4788SRick Macklem  */
1476*4517fbfdSRick Macklem void
nfs_resetslots(struct nfsclsession * sep)1477b97a4788SRick Macklem nfs_resetslots(struct nfsclsession *sep)
1478b97a4788SRick Macklem {
1479b97a4788SRick Macklem 	int i;
1480b97a4788SRick Macklem 	uint64_t bitval;
1481b97a4788SRick Macklem 
1482*4517fbfdSRick Macklem 	mtx_assert(&sep->nfsess_mtx, MA_OWNED);
1483b97a4788SRick Macklem 	bitval = (1 << sep->nfsess_foreslots);
1484b97a4788SRick Macklem 	for (i = sep->nfsess_foreslots; i < NFSV4_SLOTS; i++) {
1485b97a4788SRick Macklem 		if ((sep->nfsess_slots & bitval) == 0 &&
1486b97a4788SRick Macklem 		    (sep->nfsess_badslots & bitval) == 0)
1487b97a4788SRick Macklem 			sep->nfsess_slotseq[i] = 0;
1488b97a4788SRick Macklem 		bitval <<= 1;
1489b97a4788SRick Macklem 	}
1490b97a4788SRick Macklem }
1491b97a4788SRick Macklem 
1492b97a4788SRick Macklem /*
14939ec7b004SRick Macklem  * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
14949ec7b004SRick Macklem  * wait for all requests to complete. This is used by forced unmounts
14959ec7b004SRick Macklem  * to terminate any outstanding RPCs.
14969ec7b004SRick Macklem  */
14979ec7b004SRick Macklem int
newnfs_nmcancelreqs(struct nfsmount * nmp)14989ec7b004SRick Macklem newnfs_nmcancelreqs(struct nfsmount *nmp)
14999ec7b004SRick Macklem {
150063918d38SRick Macklem 	struct nfsclds *dsp;
150163918d38SRick Macklem 	struct __rpc_client *cl;
1502ae49051cSRick Macklem 	int i;
15039ec7b004SRick Macklem 
15049ec7b004SRick Macklem 	if (nmp->nm_sockreq.nr_client != NULL)
15059ec7b004SRick Macklem 		CLNT_CLOSE(nmp->nm_sockreq.nr_client);
1506ae49051cSRick Macklem 	for (i = 0; i < nmp->nm_aconnect; i++)
1507ae49051cSRick Macklem 		if (nmp->nm_aconn[i] != NULL)
1508ae49051cSRick Macklem 			CLNT_CLOSE(nmp->nm_aconn[i]);
150963918d38SRick Macklem lookformore:
151063918d38SRick Macklem 	NFSLOCKMNT(nmp);
151163918d38SRick Macklem 	TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
151263918d38SRick Macklem 		NFSLOCKDS(dsp);
151363918d38SRick Macklem 		if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
151463918d38SRick Macklem 		    (dsp->nfsclds_flags & NFSCLDS_CLOSED) == 0 &&
151563918d38SRick Macklem 		    dsp->nfsclds_sockp != NULL &&
151663918d38SRick Macklem 		    dsp->nfsclds_sockp->nr_client != NULL) {
151763918d38SRick Macklem 			dsp->nfsclds_flags |= NFSCLDS_CLOSED;
151863918d38SRick Macklem 			cl = dsp->nfsclds_sockp->nr_client;
151963918d38SRick Macklem 			NFSUNLOCKDS(dsp);
152063918d38SRick Macklem 			NFSUNLOCKMNT(nmp);
152163918d38SRick Macklem 			CLNT_CLOSE(cl);
152263918d38SRick Macklem 			goto lookformore;
152363918d38SRick Macklem 		}
152463918d38SRick Macklem 		NFSUNLOCKDS(dsp);
152563918d38SRick Macklem 	}
152663918d38SRick Macklem 	NFSUNLOCKMNT(nmp);
15279ec7b004SRick Macklem 	return (0);
15289ec7b004SRick Macklem }
15299ec7b004SRick Macklem 
15309ec7b004SRick Macklem /*
15319ec7b004SRick Macklem  * Any signal that can interrupt an NFS operation in an intr mount
15329ec7b004SRick Macklem  * should be added to this set. SIGSTOP and SIGKILL cannot be masked.
15339ec7b004SRick Macklem  */
15349ec7b004SRick Macklem int newnfs_sig_set[] = {
15359ec7b004SRick Macklem 	SIGINT,
15369ec7b004SRick Macklem 	SIGTERM,
15379ec7b004SRick Macklem 	SIGHUP,
15389ec7b004SRick Macklem 	SIGKILL,
15399ec7b004SRick Macklem 	SIGQUIT
15409ec7b004SRick Macklem };
15419ec7b004SRick Macklem 
15429ec7b004SRick Macklem /*
15439ec7b004SRick Macklem  * Check to see if one of the signals in our subset is pending on
15449ec7b004SRick Macklem  * the process (in an intr mount).
15459ec7b004SRick Macklem  */
15469ec7b004SRick Macklem static int
nfs_sig_pending(sigset_t set)15479ec7b004SRick Macklem nfs_sig_pending(sigset_t set)
15489ec7b004SRick Macklem {
15499ec7b004SRick Macklem 	int i;
15509ec7b004SRick Macklem 
155102abd400SPedro F. Giffuni 	for (i = 0 ; i < nitems(newnfs_sig_set); i++)
15529ec7b004SRick Macklem 		if (SIGISMEMBER(set, newnfs_sig_set[i]))
15539ec7b004SRick Macklem 			return (1);
15549ec7b004SRick Macklem 	return (0);
15559ec7b004SRick Macklem }
15569ec7b004SRick Macklem 
15579ec7b004SRick Macklem /*
15589ec7b004SRick Macklem  * The set/restore sigmask functions are used to (temporarily) overwrite
1559a120a7a3SJohn Baldwin  * the thread td_sigmask during an RPC call (for example). These are also
15609ec7b004SRick Macklem  * used in other places in the NFS client that might tsleep().
15619ec7b004SRick Macklem  */
15629ec7b004SRick Macklem void
newnfs_set_sigmask(struct thread * td,sigset_t * oldset)15639ec7b004SRick Macklem newnfs_set_sigmask(struct thread *td, sigset_t *oldset)
15649ec7b004SRick Macklem {
15659ec7b004SRick Macklem 	sigset_t newset;
15669ec7b004SRick Macklem 	int i;
15679ec7b004SRick Macklem 	struct proc *p;
15689ec7b004SRick Macklem 
15699ec7b004SRick Macklem 	SIGFILLSET(newset);
15709ec7b004SRick Macklem 	if (td == NULL)
15719ec7b004SRick Macklem 		td = curthread; /* XXX */
15729ec7b004SRick Macklem 	p = td->td_proc;
15739ec7b004SRick Macklem 	/* Remove the NFS set of signals from newset */
15749ec7b004SRick Macklem 	PROC_LOCK(p);
15759ec7b004SRick Macklem 	mtx_lock(&p->p_sigacts->ps_mtx);
157602abd400SPedro F. Giffuni 	for (i = 0 ; i < nitems(newnfs_sig_set); i++) {
15779ec7b004SRick Macklem 		/*
15789ec7b004SRick Macklem 		 * But make sure we leave the ones already masked
15799ec7b004SRick Macklem 		 * by the process, ie. remove the signal from the
15809ec7b004SRick Macklem 		 * temporary signalmask only if it wasn't already
15819ec7b004SRick Macklem 		 * in p_sigmask.
15829ec7b004SRick Macklem 		 */
15839ec7b004SRick Macklem 		if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) &&
15849ec7b004SRick Macklem 		    !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i]))
15859ec7b004SRick Macklem 			SIGDELSET(newset, newnfs_sig_set[i]);
15869ec7b004SRick Macklem 	}
15879ec7b004SRick Macklem 	mtx_unlock(&p->p_sigacts->ps_mtx);
1588a120a7a3SJohn Baldwin 	kern_sigprocmask(td, SIG_SETMASK, &newset, oldset,
1589a120a7a3SJohn Baldwin 	    SIGPROCMASK_PROC_LOCKED);
15909ec7b004SRick Macklem 	PROC_UNLOCK(p);
15919ec7b004SRick Macklem }
15929ec7b004SRick Macklem 
15939ec7b004SRick Macklem void
newnfs_restore_sigmask(struct thread * td,sigset_t * set)15949ec7b004SRick Macklem newnfs_restore_sigmask(struct thread *td, sigset_t *set)
15959ec7b004SRick Macklem {
15969ec7b004SRick Macklem 	if (td == NULL)
15979ec7b004SRick Macklem 		td = curthread; /* XXX */
15989ec7b004SRick Macklem 	kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0);
15999ec7b004SRick Macklem }
16009ec7b004SRick Macklem 
16019ec7b004SRick Macklem /*
16029ec7b004SRick Macklem  * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the
16039ec7b004SRick Macklem  * old one after msleep() returns.
16049ec7b004SRick Macklem  */
16059ec7b004SRick Macklem int
newnfs_msleep(struct thread * td,void * ident,struct mtx * mtx,int priority,char * wmesg,int timo)16069ec7b004SRick Macklem newnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo)
16079ec7b004SRick Macklem {
16089ec7b004SRick Macklem 	sigset_t oldset;
16099ec7b004SRick Macklem 	int error;
16109ec7b004SRick Macklem 
16119ec7b004SRick Macklem 	if ((priority & PCATCH) == 0)
16129ec7b004SRick Macklem 		return msleep(ident, mtx, priority, wmesg, timo);
16139ec7b004SRick Macklem 	if (td == NULL)
16149ec7b004SRick Macklem 		td = curthread; /* XXX */
16159ec7b004SRick Macklem 	newnfs_set_sigmask(td, &oldset);
16169ec7b004SRick Macklem 	error = msleep(ident, mtx, priority, wmesg, timo);
16179ec7b004SRick Macklem 	newnfs_restore_sigmask(td, &oldset);
16189ec7b004SRick Macklem 	return (error);
16199ec7b004SRick Macklem }
16209ec7b004SRick Macklem 
16219ec7b004SRick Macklem /*
16229ec7b004SRick Macklem  * Test for a termination condition pending on the process.
16239ec7b004SRick Macklem  * This is used for NFSMNT_INT mounts.
16249ec7b004SRick Macklem  */
16259ec7b004SRick Macklem int
newnfs_sigintr(struct nfsmount * nmp,struct thread * td)16269ec7b004SRick Macklem newnfs_sigintr(struct nfsmount *nmp, struct thread *td)
16279ec7b004SRick Macklem {
16289ec7b004SRick Macklem 	struct proc *p;
16299ec7b004SRick Macklem 	sigset_t tmpset;
16309ec7b004SRick Macklem 
16319ec7b004SRick Macklem 	/* Terminate all requests while attempting a forced unmount. */
163216f300faSRick Macklem 	if (NFSCL_FORCEDISM(nmp->nm_mountp))
16339ec7b004SRick Macklem 		return (EIO);
16349ec7b004SRick Macklem 	if (!(nmp->nm_flag & NFSMNT_INT))
16359ec7b004SRick Macklem 		return (0);
16369ec7b004SRick Macklem 	if (td == NULL)
16379ec7b004SRick Macklem 		return (0);
16389ec7b004SRick Macklem 	p = td->td_proc;
16399ec7b004SRick Macklem 	PROC_LOCK(p);
16409ec7b004SRick Macklem 	tmpset = p->p_siglist;
16419ec7b004SRick Macklem 	SIGSETOR(tmpset, td->td_siglist);
16429ec7b004SRick Macklem 	SIGSETNAND(tmpset, td->td_sigmask);
16439ec7b004SRick Macklem 	mtx_lock(&p->p_sigacts->ps_mtx);
16449ec7b004SRick Macklem 	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
16459ec7b004SRick Macklem 	mtx_unlock(&p->p_sigacts->ps_mtx);
16469ec7b004SRick Macklem 	if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist))
16479ec7b004SRick Macklem 	    && nfs_sig_pending(tmpset)) {
16489ec7b004SRick Macklem 		PROC_UNLOCK(p);
16499ec7b004SRick Macklem 		return (EINTR);
16509ec7b004SRick Macklem 	}
16519ec7b004SRick Macklem 	PROC_UNLOCK(p);
16529ec7b004SRick Macklem 	return (0);
16539ec7b004SRick Macklem }
16549ec7b004SRick Macklem 
16559ec7b004SRick Macklem static int
nfs_msg(struct thread * td,const char * server,const char * msg,int error)16569ec7b004SRick Macklem nfs_msg(struct thread *td, const char *server, const char *msg, int error)
16579ec7b004SRick Macklem {
16589ec7b004SRick Macklem 	struct proc *p;
16599ec7b004SRick Macklem 
16609ec7b004SRick Macklem 	p = td ? td->td_proc : NULL;
16619ec7b004SRick Macklem 	if (error) {
1662c15882f0SRick Macklem 		tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n",
16639ec7b004SRick Macklem 		    server, msg, error);
16649ec7b004SRick Macklem 	} else {
1665c15882f0SRick Macklem 		tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg);
16669ec7b004SRick Macklem 	}
16679ec7b004SRick Macklem 	return (0);
16689ec7b004SRick Macklem }
16699ec7b004SRick Macklem 
16709ec7b004SRick Macklem static void
nfs_down(struct nfsmount * nmp,struct thread * td,const char * msg,int error,int flags)16719ec7b004SRick Macklem nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg,
16729ec7b004SRick Macklem     int error, int flags)
16739ec7b004SRick Macklem {
16749ec7b004SRick Macklem 	if (nmp == NULL)
16759ec7b004SRick Macklem 		return;
16769ec7b004SRick Macklem 	mtx_lock(&nmp->nm_mtx);
16779ec7b004SRick Macklem 	if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) {
16789ec7b004SRick Macklem 		nmp->nm_state |= NFSSTA_TIMEO;
16799ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
16809ec7b004SRick Macklem 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
16819ec7b004SRick Macklem 		    VQ_NOTRESP, 0);
16829ec7b004SRick Macklem 	} else
16839ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
16849ec7b004SRick Macklem 	mtx_lock(&nmp->nm_mtx);
16859ec7b004SRick Macklem 	if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
16869ec7b004SRick Macklem 		nmp->nm_state |= NFSSTA_LOCKTIMEO;
16879ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
16889ec7b004SRick Macklem 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
16899ec7b004SRick Macklem 		    VQ_NOTRESPLOCK, 0);
16909ec7b004SRick Macklem 	} else
16919ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
16929ec7b004SRick Macklem 	nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error);
16939ec7b004SRick Macklem }
16949ec7b004SRick Macklem 
16959ec7b004SRick Macklem static void
nfs_up(struct nfsmount * nmp,struct thread * td,const char * msg,int flags,int tprintfmsg)16969ec7b004SRick Macklem nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg,
16979ec7b004SRick Macklem     int flags, int tprintfmsg)
16989ec7b004SRick Macklem {
16999ec7b004SRick Macklem 	if (nmp == NULL)
17009ec7b004SRick Macklem 		return;
17019ec7b004SRick Macklem 	if (tprintfmsg) {
17029ec7b004SRick Macklem 		nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0);
17039ec7b004SRick Macklem 	}
17049ec7b004SRick Macklem 
17059ec7b004SRick Macklem 	mtx_lock(&nmp->nm_mtx);
17069ec7b004SRick Macklem 	if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) {
17079ec7b004SRick Macklem 		nmp->nm_state &= ~NFSSTA_TIMEO;
17089ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
17099ec7b004SRick Macklem 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
17109ec7b004SRick Macklem 		    VQ_NOTRESP, 1);
17119ec7b004SRick Macklem 	} else
17129ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
17139ec7b004SRick Macklem 
17149ec7b004SRick Macklem 	mtx_lock(&nmp->nm_mtx);
17159ec7b004SRick Macklem 	if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) {
17169ec7b004SRick Macklem 		nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
17179ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
17189ec7b004SRick Macklem 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
17199ec7b004SRick Macklem 		    VQ_NOTRESPLOCK, 1);
17209ec7b004SRick Macklem 	} else
17219ec7b004SRick Macklem 		mtx_unlock(&nmp->nm_mtx);
17229ec7b004SRick Macklem }
1723