xref: /netbsd-src/sys/fs/nfs/common/nfs_commonkrpc.c (revision ff4253031e9596a0a74486e02148bc755959e948)
1*ff425303Sandvar /*	$NetBSD: nfs_commonkrpc.c,v 1.3 2023/06/16 19:40:46 andvar Exp $	*/
26ca35587Sdholland /*-
36ca35587Sdholland  * Copyright (c) 1989, 1991, 1993, 1995
46ca35587Sdholland  *	The Regents of the University of California.  All rights reserved.
56ca35587Sdholland  *
66ca35587Sdholland  * This code is derived from software contributed to Berkeley by
76ca35587Sdholland  * Rick Macklem at The University of Guelph.
86ca35587Sdholland  *
96ca35587Sdholland  * Redistribution and use in source and binary forms, with or without
106ca35587Sdholland  * modification, are permitted provided that the following conditions
116ca35587Sdholland  * are met:
126ca35587Sdholland  * 1. Redistributions of source code must retain the above copyright
136ca35587Sdholland  *    notice, this list of conditions and the following disclaimer.
146ca35587Sdholland  * 2. Redistributions in binary form must reproduce the above copyright
156ca35587Sdholland  *    notice, this list of conditions and the following disclaimer in the
166ca35587Sdholland  *    documentation and/or other materials provided with the distribution.
176ca35587Sdholland  * 4. Neither the name of the University nor the names of its contributors
186ca35587Sdholland  *    may be used to endorse or promote products derived from this software
196ca35587Sdholland  *    without specific prior written permission.
206ca35587Sdholland  *
216ca35587Sdholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
226ca35587Sdholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
236ca35587Sdholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
246ca35587Sdholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
256ca35587Sdholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
266ca35587Sdholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276ca35587Sdholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
286ca35587Sdholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
296ca35587Sdholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
306ca35587Sdholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
316ca35587Sdholland  * SUCH DAMAGE.
326ca35587Sdholland  *
336ca35587Sdholland  */
346ca35587Sdholland 
356ca35587Sdholland #include <sys/cdefs.h>
36e81f0ea2Spgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfs/nfs_commonkrpc.c 304026 2016-08-12 22:44:59Z rmacklem "); */
37*ff425303Sandvar __RCSID("$NetBSD: nfs_commonkrpc.c,v 1.3 2023/06/16 19:40:46 andvar Exp $");
386ca35587Sdholland 
396ca35587Sdholland /*
406ca35587Sdholland  * Socket operations for use by nfs
416ca35587Sdholland  */
426ca35587Sdholland 
4388b1d6a6Spgoyette #ifdef _KERNEL_OPT
4488b1d6a6Spgoyette #include "opt_dtrace.h"
4588b1d6a6Spgoyette #include "opt_newnfs.h"
4688b1d6a6Spgoyette #if 0
476ca35587Sdholland #include "opt_kgssapi.h"
4888b1d6a6Spgoyette #endif
4988b1d6a6Spgoyette #endif
506ca35587Sdholland 
516ca35587Sdholland #include <sys/param.h>
526ca35587Sdholland #include <sys/systm.h>
536ca35587Sdholland #include <sys/kernel.h>
546ca35587Sdholland #include <sys/limits.h>
556ca35587Sdholland #include <sys/lock.h>
566ca35587Sdholland #include <sys/malloc.h>
576ca35587Sdholland #include <sys/mbuf.h>
586ca35587Sdholland #include <sys/mount.h>
596ca35587Sdholland #include <sys/mutex.h>
606ca35587Sdholland #include <sys/proc.h>
616ca35587Sdholland #include <sys/signalvar.h>
626ca35587Sdholland #include <sys/syscallsubr.h>
636ca35587Sdholland #include <sys/sysctl.h>
646ca35587Sdholland #include <sys/syslog.h>
656ca35587Sdholland #include <sys/vnode.h>
666ca35587Sdholland 
676ca35587Sdholland #include <rpc/rpc.h>
6888b1d6a6Spgoyette #include <fs/nfs/common/krpc.h>
696ca35587Sdholland 
706ca35587Sdholland #include <kgssapi/krb5/kcrypto.h>
716ca35587Sdholland 
7288b1d6a6Spgoyette #include <fs/nfs/common/nfsport.h>
736ca35587Sdholland 
746ca35587Sdholland #ifdef KDTRACE_HOOKS
756ca35587Sdholland #include <sys/dtrace_bsd.h>
766ca35587Sdholland 
776ca35587Sdholland dtrace_nfsclient_nfs23_start_probe_func_t
786ca35587Sdholland 		dtrace_nfscl_nfs234_start_probe;
796ca35587Sdholland 
806ca35587Sdholland dtrace_nfsclient_nfs23_done_probe_func_t
816ca35587Sdholland 		dtrace_nfscl_nfs234_done_probe;
826ca35587Sdholland 
836ca35587Sdholland /*
846ca35587Sdholland  * Registered probes by RPC type.
856ca35587Sdholland  */
866ca35587Sdholland uint32_t	nfscl_nfs2_start_probes[NFSV41_NPROCS + 1];
876ca35587Sdholland uint32_t	nfscl_nfs2_done_probes[NFSV41_NPROCS + 1];
886ca35587Sdholland 
896ca35587Sdholland uint32_t	nfscl_nfs3_start_probes[NFSV41_NPROCS + 1];
906ca35587Sdholland uint32_t	nfscl_nfs3_done_probes[NFSV41_NPROCS + 1];
916ca35587Sdholland 
926ca35587Sdholland uint32_t	nfscl_nfs4_start_probes[NFSV41_NPROCS + 1];
936ca35587Sdholland uint32_t	nfscl_nfs4_done_probes[NFSV41_NPROCS + 1];
946ca35587Sdholland #endif
956ca35587Sdholland 
966ca35587Sdholland NFSSTATESPINLOCK;
976ca35587Sdholland NFSREQSPINLOCK;
986ca35587Sdholland NFSDLOCKMUTEX;
99e81f0ea2Spgoyette extern struct nfsstatsv1 nfsstatsv1;
1006ca35587Sdholland extern struct nfsreqhead nfsd_reqq;
1016ca35587Sdholland extern int nfscl_ticks;
1026ca35587Sdholland extern void (*ncl_call_invalcaches)(struct vnode *);
1036ca35587Sdholland extern int nfs_numnfscbd;
1046ca35587Sdholland extern int nfscl_debuglevel;
1056ca35587Sdholland 
1066ca35587Sdholland SVCPOOL		*nfscbd_pool;
1076ca35587Sdholland static int	nfsrv_gsscallbackson = 0;
1086ca35587Sdholland static int	nfs_bufpackets = 4;
1096ca35587Sdholland static int	nfs_reconnects;
1106ca35587Sdholland static int	nfs3_jukebox_delay = 10;
1116ca35587Sdholland static int	nfs_skip_wcc_data_onerr = 1;
1126ca35587Sdholland 
1136ca35587Sdholland SYSCTL_DECL(_vfs_nfs);
1146ca35587Sdholland 
1156ca35587Sdholland SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0,
1166ca35587Sdholland     "Buffer reservation size 2 < x < 64");
1176ca35587Sdholland SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0,
1186ca35587Sdholland     "Number of times the nfs client has had to reconnect");
1196ca35587Sdholland SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0,
1206ca35587Sdholland     "Number of seconds to delay a retry after receiving EJUKEBOX");
1216ca35587Sdholland SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0,
1226ca35587Sdholland     "Disable weak cache consistency checking when server returns an error");
1236ca35587Sdholland 
1246ca35587Sdholland static void	nfs_down(struct nfsmount *, struct thread *, const char *,
1256ca35587Sdholland     int, int);
1266ca35587Sdholland static void	nfs_up(struct nfsmount *, struct thread *, const char *,
1276ca35587Sdholland     int, int);
1286ca35587Sdholland static int	nfs_msg(struct thread *, const char *, const char *, int);
1296ca35587Sdholland 
1306ca35587Sdholland struct nfs_cached_auth {
1316ca35587Sdholland 	int		ca_refs; /* refcount, including 1 from the cache */
1326ca35587Sdholland 	uid_t		ca_uid;	 /* uid that corresponds to this auth */
1336ca35587Sdholland 	AUTH		*ca_auth; /* RPC auth handle */
1346ca35587Sdholland };
1356ca35587Sdholland 
1366ca35587Sdholland static int nfsv2_procid[NFS_V3NPROCS] = {
1376ca35587Sdholland 	NFSV2PROC_NULL,
1386ca35587Sdholland 	NFSV2PROC_GETATTR,
1396ca35587Sdholland 	NFSV2PROC_SETATTR,
1406ca35587Sdholland 	NFSV2PROC_LOOKUP,
1416ca35587Sdholland 	NFSV2PROC_NOOP,
1426ca35587Sdholland 	NFSV2PROC_READLINK,
1436ca35587Sdholland 	NFSV2PROC_READ,
1446ca35587Sdholland 	NFSV2PROC_WRITE,
1456ca35587Sdholland 	NFSV2PROC_CREATE,
1466ca35587Sdholland 	NFSV2PROC_MKDIR,
1476ca35587Sdholland 	NFSV2PROC_SYMLINK,
1486ca35587Sdholland 	NFSV2PROC_CREATE,
1496ca35587Sdholland 	NFSV2PROC_REMOVE,
1506ca35587Sdholland 	NFSV2PROC_RMDIR,
1516ca35587Sdholland 	NFSV2PROC_RENAME,
1526ca35587Sdholland 	NFSV2PROC_LINK,
1536ca35587Sdholland 	NFSV2PROC_READDIR,
1546ca35587Sdholland 	NFSV2PROC_NOOP,
1556ca35587Sdholland 	NFSV2PROC_STATFS,
1566ca35587Sdholland 	NFSV2PROC_NOOP,
1576ca35587Sdholland 	NFSV2PROC_NOOP,
1586ca35587Sdholland 	NFSV2PROC_NOOP,
1596ca35587Sdholland };
1606ca35587Sdholland 
1616ca35587Sdholland /*
1626ca35587Sdholland  * Initialize sockets and congestion for a new NFS connection.
1636ca35587Sdholland  * We do not free the sockaddr if error.
1646ca35587Sdholland  */
1656ca35587Sdholland int
newnfs_connect(struct nfsmount * nmp,struct nfssockreq * nrp,struct ucred * cred,NFSPROC_T * p,int callback_retry_mult)1666ca35587Sdholland newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
1676ca35587Sdholland     struct ucred *cred, NFSPROC_T *p, int callback_retry_mult)
1686ca35587Sdholland {
1696ca35587Sdholland 	int rcvreserve, sndreserve;
1706ca35587Sdholland 	int pktscale;
1716ca35587Sdholland 	struct sockaddr *saddr;
1726ca35587Sdholland 	struct ucred *origcred;
1736ca35587Sdholland 	CLIENT *client;
1746ca35587Sdholland 	struct netconfig *nconf;
1756ca35587Sdholland 	struct socket *so;
1766ca35587Sdholland 	int one = 1, retries, error = 0;
1776ca35587Sdholland 	struct thread *td = curthread;
1786ca35587Sdholland 	SVCXPRT *xprt;
1796ca35587Sdholland 	struct timeval timo;
1806ca35587Sdholland 
1816ca35587Sdholland 	/*
1826ca35587Sdholland 	 * We need to establish the socket using the credentials of
1836ca35587Sdholland 	 * the mountpoint.  Some parts of this process (such as
184*ff425303Sandvar 	 * sobind() and soconnect()) will use the current thread's
1856ca35587Sdholland 	 * credential instead of the socket credential.  To work
1866ca35587Sdholland 	 * around this, temporarily change the current thread's
1876ca35587Sdholland 	 * credential to that of the mountpoint.
1886ca35587Sdholland 	 *
1896ca35587Sdholland 	 * XXX: It would be better to explicitly pass the correct
1906ca35587Sdholland 	 * credential to sobind() and soconnect().
1916ca35587Sdholland 	 */
1926ca35587Sdholland 	origcred = td->td_ucred;
1936ca35587Sdholland 
1946ca35587Sdholland 	/*
1956ca35587Sdholland 	 * Use the credential in nr_cred, if not NULL.
1966ca35587Sdholland 	 */
1976ca35587Sdholland 	if (nrp->nr_cred != NULL)
1986ca35587Sdholland 		td->td_ucred = nrp->nr_cred;
1996ca35587Sdholland 	else
2006ca35587Sdholland 		td->td_ucred = cred;
2016ca35587Sdholland 	saddr = nrp->nr_nam;
2026ca35587Sdholland 
2036ca35587Sdholland 	if (saddr->sa_family == AF_INET)
2046ca35587Sdholland 		if (nrp->nr_sotype == SOCK_DGRAM)
2056ca35587Sdholland 			nconf = getnetconfigent("udp");
2066ca35587Sdholland 		else
2076ca35587Sdholland 			nconf = getnetconfigent("tcp");
2086ca35587Sdholland 	else
2096ca35587Sdholland 		if (nrp->nr_sotype == SOCK_DGRAM)
2106ca35587Sdholland 			nconf = getnetconfigent("udp6");
2116ca35587Sdholland 		else
2126ca35587Sdholland 			nconf = getnetconfigent("tcp6");
2136ca35587Sdholland 
2146ca35587Sdholland 	pktscale = nfs_bufpackets;
2156ca35587Sdholland 	if (pktscale < 2)
2166ca35587Sdholland 		pktscale = 2;
2176ca35587Sdholland 	if (pktscale > 64)
2186ca35587Sdholland 		pktscale = 64;
2196ca35587Sdholland 	/*
2206ca35587Sdholland 	 * soreserve() can fail if sb_max is too small, so shrink pktscale
2216ca35587Sdholland 	 * and try again if there is an error.
2226ca35587Sdholland 	 * Print a log message suggesting increasing sb_max.
2236ca35587Sdholland 	 * Creating a socket and doing this is necessary since, if the
2246ca35587Sdholland 	 * reservation sizes are too large and will make soreserve() fail,
2256ca35587Sdholland 	 * the connection will work until a large send is attempted and
2266ca35587Sdholland 	 * then it will loop in the krpc code.
2276ca35587Sdholland 	 */
2286ca35587Sdholland 	so = NULL;
2296ca35587Sdholland 	saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *);
2306ca35587Sdholland 	error = socreate(saddr->sa_family, &so, nrp->nr_sotype,
2316ca35587Sdholland 	    nrp->nr_soproto, td->td_ucred, td);
2326ca35587Sdholland 	if (error) {
2336ca35587Sdholland 		td->td_ucred = origcred;
2346ca35587Sdholland 		goto out;
2356ca35587Sdholland 	}
2366ca35587Sdholland 	do {
2376ca35587Sdholland 	    if (error != 0 && pktscale > 2)
2386ca35587Sdholland 		pktscale--;
2396ca35587Sdholland 	    if (nrp->nr_sotype == SOCK_DGRAM) {
2406ca35587Sdholland 		if (nmp != NULL) {
2416ca35587Sdholland 			sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
2426ca35587Sdholland 			    pktscale;
2436ca35587Sdholland 			rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
2446ca35587Sdholland 			    pktscale;
2456ca35587Sdholland 		} else {
2466ca35587Sdholland 			sndreserve = rcvreserve = 1024 * pktscale;
2476ca35587Sdholland 		}
2486ca35587Sdholland 	    } else {
2496ca35587Sdholland 		if (nrp->nr_sotype != SOCK_STREAM)
2506ca35587Sdholland 			panic("nfscon sotype");
2516ca35587Sdholland 		if (nmp != NULL) {
2526ca35587Sdholland 			sndreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR +
2536ca35587Sdholland 			    sizeof (u_int32_t)) * pktscale;
2546ca35587Sdholland 			rcvreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR +
2556ca35587Sdholland 			    sizeof (u_int32_t)) * pktscale;
2566ca35587Sdholland 		} else {
2576ca35587Sdholland 			sndreserve = rcvreserve = 1024 * pktscale;
2586ca35587Sdholland 		}
2596ca35587Sdholland 	    }
2606ca35587Sdholland 	    error = soreserve(so, sndreserve, rcvreserve);
2616ca35587Sdholland 	} while (error != 0 && pktscale > 2);
2626ca35587Sdholland 	soclose(so);
2636ca35587Sdholland 	if (error) {
2646ca35587Sdholland 		td->td_ucred = origcred;
2656ca35587Sdholland 		goto out;
2666ca35587Sdholland 	}
2676ca35587Sdholland 
2686ca35587Sdholland 	client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog,
2696ca35587Sdholland 	    nrp->nr_vers, sndreserve, rcvreserve);
270e81f0ea2Spgoyette 	CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
2716ca35587Sdholland 	if (nmp != NULL) {
2726ca35587Sdholland 		if ((nmp->nm_flag & NFSMNT_INT))
2736ca35587Sdholland 			CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
2746ca35587Sdholland 		if ((nmp->nm_flag & NFSMNT_RESVPORT))
2756ca35587Sdholland 			CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
2766ca35587Sdholland 		if (NFSHASSOFT(nmp)) {
2776ca35587Sdholland 			if (nmp->nm_sotype == SOCK_DGRAM)
2786ca35587Sdholland 				/*
2796ca35587Sdholland 				 * For UDP, the large timeout for a reconnect
2806ca35587Sdholland 				 * will be set to "nm_retry * nm_timeo / 2", so
2816ca35587Sdholland 				 * we only want to do 2 reconnect timeout
2826ca35587Sdholland 				 * retries.
2836ca35587Sdholland 				 */
2846ca35587Sdholland 				retries = 2;
2856ca35587Sdholland 			else
2866ca35587Sdholland 				retries = nmp->nm_retry;
2876ca35587Sdholland 		} else
2886ca35587Sdholland 			retries = INT_MAX;
2896ca35587Sdholland 		if (NFSHASNFSV4N(nmp)) {
2906ca35587Sdholland 			/*
2916ca35587Sdholland 			 * Make sure the nfscbd_pool doesn't get destroyed
2926ca35587Sdholland 			 * while doing this.
2936ca35587Sdholland 			 */
2946ca35587Sdholland 			NFSD_LOCK();
2956ca35587Sdholland 			if (nfs_numnfscbd > 0) {
2966ca35587Sdholland 				nfs_numnfscbd++;
2976ca35587Sdholland 				NFSD_UNLOCK();
2986ca35587Sdholland 				xprt = svc_vc_create_backchannel(nfscbd_pool);
2996ca35587Sdholland 				CLNT_CONTROL(client, CLSET_BACKCHANNEL, xprt);
3006ca35587Sdholland 				NFSD_LOCK();
3016ca35587Sdholland 				nfs_numnfscbd--;
3026ca35587Sdholland 				if (nfs_numnfscbd == 0)
3036ca35587Sdholland 					wakeup(&nfs_numnfscbd);
3046ca35587Sdholland 			}
3056ca35587Sdholland 			NFSD_UNLOCK();
3066ca35587Sdholland 		}
3076ca35587Sdholland 	} else {
3086ca35587Sdholland 		/*
3096ca35587Sdholland 		 * Three cases:
3106ca35587Sdholland 		 * - Null RPC callback to client
3116ca35587Sdholland 		 * - Non-Null RPC callback to client, wait a little longer
3126ca35587Sdholland 		 * - upcalls to nfsuserd and gssd (clp == NULL)
3136ca35587Sdholland 		 */
3146ca35587Sdholland 		if (callback_retry_mult == 0) {
3156ca35587Sdholland 			retries = NFSV4_UPCALLRETRY;
3166ca35587Sdholland 			CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
3176ca35587Sdholland 		} else {
3186ca35587Sdholland 			retries = NFSV4_CALLBACKRETRY * callback_retry_mult;
3196ca35587Sdholland 		}
3206ca35587Sdholland 	}
3216ca35587Sdholland 	CLNT_CONTROL(client, CLSET_RETRIES, &retries);
3226ca35587Sdholland 
3236ca35587Sdholland 	if (nmp != NULL) {
3246ca35587Sdholland 		/*
3256ca35587Sdholland 		 * For UDP, there are 2 timeouts:
3266ca35587Sdholland 		 * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer
3276ca35587Sdholland 		 *   that does a retransmit of an RPC request using the same
3286ca35587Sdholland 		 *   socket and xid. This is what you normally want to do,
3296ca35587Sdholland 		 *   since NFS servers depend on "same xid" for their
3306ca35587Sdholland 		 *   Duplicate Request Cache.
3316ca35587Sdholland 		 * - timeout specified in CLNT_CALL_MBUF(), which specifies when
3326ca35587Sdholland 		 *   retransmits on the same socket should fail and a fresh
3336ca35587Sdholland 		 *   socket created. Each of these timeouts counts as one
3346ca35587Sdholland 		 *   CLSET_RETRIES as set above.
3356ca35587Sdholland 		 * Set the initial retransmit timeout for UDP. This timeout
3366ca35587Sdholland 		 * doesn't exist for TCP and the following call just fails,
3376ca35587Sdholland 		 * which is ok.
3386ca35587Sdholland 		 */
3396ca35587Sdholland 		timo.tv_sec = nmp->nm_timeo / NFS_HZ;
3406ca35587Sdholland 		timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
3416ca35587Sdholland 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo);
3426ca35587Sdholland 	}
3436ca35587Sdholland 
3446ca35587Sdholland 	mtx_lock(&nrp->nr_mtx);
3456ca35587Sdholland 	if (nrp->nr_client != NULL) {
346e81f0ea2Spgoyette 		mtx_unlock(&nrp->nr_mtx);
3476ca35587Sdholland 		/*
3486ca35587Sdholland 		 * Someone else already connected.
3496ca35587Sdholland 		 */
3506ca35587Sdholland 		CLNT_RELEASE(client);
3516ca35587Sdholland 	} else {
3526ca35587Sdholland 		nrp->nr_client = client;
3536ca35587Sdholland 		/*
354e81f0ea2Spgoyette 		 * Protocols that do not require connections may be optionally
355e81f0ea2Spgoyette 		 * left unconnected for servers that reply from a port other
356e81f0ea2Spgoyette 		 * than NFS_PORT.
3576ca35587Sdholland 		 */
3586ca35587Sdholland 		if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) {
3596ca35587Sdholland 			mtx_unlock(&nrp->nr_mtx);
3606ca35587Sdholland 			CLNT_CONTROL(client, CLSET_CONNECT, &one);
361e81f0ea2Spgoyette 		} else
3626ca35587Sdholland 			mtx_unlock(&nrp->nr_mtx);
3636ca35587Sdholland 	}
3646ca35587Sdholland 
365e81f0ea2Spgoyette 
3666ca35587Sdholland 	/* Restore current thread's credentials. */
3676ca35587Sdholland 	td->td_ucred = origcred;
3686ca35587Sdholland 
3696ca35587Sdholland out:
3706ca35587Sdholland 	NFSEXITCODE(error);
3716ca35587Sdholland 	return (error);
3726ca35587Sdholland }
3736ca35587Sdholland 
3746ca35587Sdholland /*
3756ca35587Sdholland  * NFS disconnect. Clean up and unlink.
3766ca35587Sdholland  */
3776ca35587Sdholland void
newnfs_disconnect(struct nfssockreq * nrp)3786ca35587Sdholland newnfs_disconnect(struct nfssockreq *nrp)
3796ca35587Sdholland {
3806ca35587Sdholland 	CLIENT *client;
3816ca35587Sdholland 
3826ca35587Sdholland 	mtx_lock(&nrp->nr_mtx);
3836ca35587Sdholland 	if (nrp->nr_client != NULL) {
3846ca35587Sdholland 		client = nrp->nr_client;
3856ca35587Sdholland 		nrp->nr_client = NULL;
3866ca35587Sdholland 		mtx_unlock(&nrp->nr_mtx);
3876ca35587Sdholland 		rpc_gss_secpurge_call(client);
3886ca35587Sdholland 		CLNT_CLOSE(client);
3896ca35587Sdholland 		CLNT_RELEASE(client);
3906ca35587Sdholland 	} else {
3916ca35587Sdholland 		mtx_unlock(&nrp->nr_mtx);
3926ca35587Sdholland 	}
3936ca35587Sdholland }
3946ca35587Sdholland 
3956ca35587Sdholland static AUTH *
nfs_getauth(struct nfssockreq * nrp,int secflavour,char * clnt_principal,char * srv_principal,gss_OID mech_oid,struct ucred * cred)3966ca35587Sdholland nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal,
3976ca35587Sdholland     char *srv_principal, gss_OID mech_oid, struct ucred *cred)
3986ca35587Sdholland {
3996ca35587Sdholland 	rpc_gss_service_t svc;
4006ca35587Sdholland 	AUTH *auth;
4016ca35587Sdholland 
4026ca35587Sdholland 	switch (secflavour) {
4036ca35587Sdholland 	case RPCSEC_GSS_KRB5:
4046ca35587Sdholland 	case RPCSEC_GSS_KRB5I:
4056ca35587Sdholland 	case RPCSEC_GSS_KRB5P:
4066ca35587Sdholland 		if (!mech_oid) {
4076ca35587Sdholland 			if (!rpc_gss_mech_to_oid_call("kerberosv5", &mech_oid))
4086ca35587Sdholland 				return (NULL);
4096ca35587Sdholland 		}
4106ca35587Sdholland 		if (secflavour == RPCSEC_GSS_KRB5)
4116ca35587Sdholland 			svc = rpc_gss_svc_none;
4126ca35587Sdholland 		else if (secflavour == RPCSEC_GSS_KRB5I)
4136ca35587Sdholland 			svc = rpc_gss_svc_integrity;
4146ca35587Sdholland 		else
4156ca35587Sdholland 			svc = rpc_gss_svc_privacy;
4166ca35587Sdholland 
4176ca35587Sdholland 		if (clnt_principal == NULL)
4186ca35587Sdholland 			auth = rpc_gss_secfind_call(nrp->nr_client, cred,
4196ca35587Sdholland 			    srv_principal, mech_oid, svc);
4206ca35587Sdholland 		else {
4216ca35587Sdholland 			auth = rpc_gss_seccreate_call(nrp->nr_client, cred,
4226ca35587Sdholland 			    clnt_principal, srv_principal, "kerberosv5",
4236ca35587Sdholland 			    svc, NULL, NULL, NULL);
4246ca35587Sdholland 			return (auth);
4256ca35587Sdholland 		}
4266ca35587Sdholland 		if (auth != NULL)
4276ca35587Sdholland 			return (auth);
4286ca35587Sdholland 		/* fallthrough */
4296ca35587Sdholland 	case AUTH_SYS:
4306ca35587Sdholland 	default:
4316ca35587Sdholland 		return (authunix_create(cred));
4326ca35587Sdholland 
4336ca35587Sdholland 	}
4346ca35587Sdholland }
4356ca35587Sdholland 
4366ca35587Sdholland /*
4376ca35587Sdholland  * Callback from the RPC code to generate up/down notifications.
4386ca35587Sdholland  */
4396ca35587Sdholland 
4406ca35587Sdholland struct nfs_feedback_arg {
4416ca35587Sdholland 	struct nfsmount *nf_mount;
4426ca35587Sdholland 	int		nf_lastmsg;	/* last tprintf */
4436ca35587Sdholland 	int		nf_tprintfmsg;
4446ca35587Sdholland 	struct thread	*nf_td;
4456ca35587Sdholland };
4466ca35587Sdholland 
4476ca35587Sdholland static void
nfs_feedback(int type,int proc,void * arg)4486ca35587Sdholland nfs_feedback(int type, int proc, void *arg)
4496ca35587Sdholland {
4506ca35587Sdholland 	struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg;
4516ca35587Sdholland 	struct nfsmount *nmp = nf->nf_mount;
4526ca35587Sdholland 	time_t now;
4536ca35587Sdholland 
4546ca35587Sdholland 	switch (type) {
4556ca35587Sdholland 	case FEEDBACK_REXMIT2:
4566ca35587Sdholland 	case FEEDBACK_RECONNECT:
4576ca35587Sdholland 		now = NFSD_MONOSEC;
4586ca35587Sdholland 		if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now) {
4596ca35587Sdholland 			nfs_down(nmp, nf->nf_td,
4606ca35587Sdholland 			    "not responding", 0, NFSSTA_TIMEO);
4616ca35587Sdholland 			nf->nf_tprintfmsg = TRUE;
4626ca35587Sdholland 			nf->nf_lastmsg = now;
4636ca35587Sdholland 		}
4646ca35587Sdholland 		break;
4656ca35587Sdholland 
4666ca35587Sdholland 	case FEEDBACK_OK:
4676ca35587Sdholland 		nfs_up(nf->nf_mount, nf->nf_td,
4686ca35587Sdholland 		    "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg);
4696ca35587Sdholland 		break;
4706ca35587Sdholland 	}
4716ca35587Sdholland }
4726ca35587Sdholland 
4736ca35587Sdholland /*
4746ca35587Sdholland  * newnfs_request - goes something like this
4756ca35587Sdholland  *	- does the rpc by calling the krpc layer
4766ca35587Sdholland  *	- break down rpc header and return with nfs reply
4776ca35587Sdholland  * nb: always frees up nd_mreq mbuf list
4786ca35587Sdholland  */
4796ca35587Sdholland 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 * sep)4806ca35587Sdholland newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
4816ca35587Sdholland     struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp,
4826ca35587Sdholland     struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
4836ca35587Sdholland     u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *sep)
4846ca35587Sdholland {
4856ca35587Sdholland 	u_int32_t retseq, retval, *tl;
4866ca35587Sdholland 	time_t waituntil;
4876ca35587Sdholland 	int i = 0, j = 0, opcnt, set_sigset = 0, slot;
4886ca35587Sdholland 	int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS;
4896ca35587Sdholland 	int freeslot, timeo;
4906ca35587Sdholland 	u_int16_t procnum;
4916ca35587Sdholland 	u_int trylater_delay = 1;
4926ca35587Sdholland 	struct nfs_feedback_arg nf;
4936ca35587Sdholland 	struct timeval timo;
4946ca35587Sdholland 	AUTH *auth;
4956ca35587Sdholland 	struct rpc_callextra ext;
4966ca35587Sdholland 	enum clnt_stat stat;
4976ca35587Sdholland 	struct nfsreq *rep = NULL;
4986ca35587Sdholland 	char *srv_principal = NULL, *clnt_principal = NULL;
4996ca35587Sdholland 	sigset_t oldset;
5006ca35587Sdholland 	struct ucred *authcred;
5016ca35587Sdholland 
5026ca35587Sdholland 	if (xidp != NULL)
5036ca35587Sdholland 		*xidp = 0;
5046ca35587Sdholland 	/* Reject requests while attempting a forced unmount. */
5056ca35587Sdholland 	if (nmp != NULL && (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)) {
5066ca35587Sdholland 		m_freem(nd->nd_mreq);
5076ca35587Sdholland 		return (ESTALE);
5086ca35587Sdholland 	}
5096ca35587Sdholland 
5106ca35587Sdholland 	/*
5116ca35587Sdholland 	 * Set authcred, which is used to acquire RPC credentials to
5126ca35587Sdholland 	 * the cred argument, by default. The crhold() should not be
5136ca35587Sdholland 	 * necessary, but will ensure that some future code change
5146ca35587Sdholland 	 * doesn't result in the credential being free'd prematurely.
5156ca35587Sdholland 	 */
5166ca35587Sdholland 	authcred = crhold(cred);
5176ca35587Sdholland 
5186ca35587Sdholland 	/* For client side interruptible mounts, mask off the signals. */
5196ca35587Sdholland 	if (nmp != NULL && td != NULL && NFSHASINT(nmp)) {
5206ca35587Sdholland 		newnfs_set_sigmask(td, &oldset);
5216ca35587Sdholland 		set_sigset = 1;
5226ca35587Sdholland 	}
5236ca35587Sdholland 
5246ca35587Sdholland 	/*
5256ca35587Sdholland 	 * XXX if not already connected call nfs_connect now. Longer
5266ca35587Sdholland 	 * term, change nfs_mount to call nfs_connect unconditionally
5276ca35587Sdholland 	 * and let clnt_reconnect_create handle reconnects.
5286ca35587Sdholland 	 */
5296ca35587Sdholland 	if (nrp->nr_client == NULL)
5306ca35587Sdholland 		newnfs_connect(nmp, nrp, cred, td, 0);
5316ca35587Sdholland 
5326ca35587Sdholland 	/*
5336ca35587Sdholland 	 * For a client side mount, nmp is != NULL and clp == NULL. For
5346ca35587Sdholland 	 * server calls (callbacks or upcalls), nmp == NULL.
5356ca35587Sdholland 	 */
5366ca35587Sdholland 	if (clp != NULL) {
5376ca35587Sdholland 		NFSLOCKSTATE();
5386ca35587Sdholland 		if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) {
5396ca35587Sdholland 			secflavour = RPCSEC_GSS_KRB5;
5406ca35587Sdholland 			if (nd->nd_procnum != NFSPROC_NULL) {
5416ca35587Sdholland 				if (clp->lc_flags & LCL_GSSINTEGRITY)
5426ca35587Sdholland 					secflavour = RPCSEC_GSS_KRB5I;
5436ca35587Sdholland 				else if (clp->lc_flags & LCL_GSSPRIVACY)
5446ca35587Sdholland 					secflavour = RPCSEC_GSS_KRB5P;
5456ca35587Sdholland 			}
5466ca35587Sdholland 		}
5476ca35587Sdholland 		NFSUNLOCKSTATE();
5486ca35587Sdholland 	} else if (nmp != NULL && NFSHASKERB(nmp) &&
5496ca35587Sdholland 	     nd->nd_procnum != NFSPROC_NULL) {
5506ca35587Sdholland 		if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0)
5516ca35587Sdholland 			nd->nd_flag |= ND_USEGSSNAME;
5526ca35587Sdholland 		if ((nd->nd_flag & ND_USEGSSNAME) != 0) {
5536ca35587Sdholland 			/*
5546ca35587Sdholland 			 * If there is a client side host based credential,
5556ca35587Sdholland 			 * use that, otherwise use the system uid, if set.
5566ca35587Sdholland 			 * The system uid is in the nmp->nm_sockreq.nr_cred
5576ca35587Sdholland 			 * credentials.
5586ca35587Sdholland 			 */
5596ca35587Sdholland 			if (nmp->nm_krbnamelen > 0) {
5606ca35587Sdholland 				usegssname = 1;
5616ca35587Sdholland 				clnt_principal = nmp->nm_krbname;
5626ca35587Sdholland 			} else if (nmp->nm_uid != (uid_t)-1) {
5636ca35587Sdholland 				KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5646ca35587Sdholland 				    ("newnfs_request: NULL nr_cred"));
5656ca35587Sdholland 				crfree(authcred);
5666ca35587Sdholland 				authcred = crhold(nmp->nm_sockreq.nr_cred);
5676ca35587Sdholland 			}
5686ca35587Sdholland 		} else if (nmp->nm_krbnamelen == 0 &&
5696ca35587Sdholland 		    nmp->nm_uid != (uid_t)-1 && cred->cr_uid == (uid_t)0) {
5706ca35587Sdholland 			/*
5716ca35587Sdholland 			 * If there is no host based principal name and
5726ca35587Sdholland 			 * the system uid is set and this is root, use the
5736ca35587Sdholland 			 * system uid, since root won't have user
5746ca35587Sdholland 			 * credentials in a credentials cache file.
5756ca35587Sdholland 			 * The system uid is in the nmp->nm_sockreq.nr_cred
5766ca35587Sdholland 			 * credentials.
5776ca35587Sdholland 			 */
5786ca35587Sdholland 			KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5796ca35587Sdholland 			    ("newnfs_request: NULL nr_cred"));
5806ca35587Sdholland 			crfree(authcred);
5816ca35587Sdholland 			authcred = crhold(nmp->nm_sockreq.nr_cred);
5826ca35587Sdholland 		}
5836ca35587Sdholland 		if (NFSHASINTEGRITY(nmp))
5846ca35587Sdholland 			secflavour = RPCSEC_GSS_KRB5I;
5856ca35587Sdholland 		else if (NFSHASPRIVACY(nmp))
5866ca35587Sdholland 			secflavour = RPCSEC_GSS_KRB5P;
5876ca35587Sdholland 		else
5886ca35587Sdholland 			secflavour = RPCSEC_GSS_KRB5;
5896ca35587Sdholland 		srv_principal = NFSMNT_SRVKRBNAME(nmp);
5906ca35587Sdholland 	} else if (nmp != NULL && !NFSHASKERB(nmp) &&
5916ca35587Sdholland 	    nd->nd_procnum != NFSPROC_NULL &&
5926ca35587Sdholland 	    (nd->nd_flag & ND_USEGSSNAME) != 0) {
5936ca35587Sdholland 		/*
5946ca35587Sdholland 		 * Use the uid that did the mount when the RPC is doing
5956ca35587Sdholland 		 * NFSv4 system operations, as indicated by the
5966ca35587Sdholland 		 * ND_USEGSSNAME flag, for the AUTH_SYS case.
5976ca35587Sdholland 		 * The credentials in nm_sockreq.nr_cred were used for the
5986ca35587Sdholland 		 * mount.
5996ca35587Sdholland 		 */
6006ca35587Sdholland 		KASSERT(nmp->nm_sockreq.nr_cred != NULL,
6016ca35587Sdholland 		    ("newnfs_request: NULL nr_cred"));
6026ca35587Sdholland 		crfree(authcred);
6036ca35587Sdholland 		authcred = crhold(nmp->nm_sockreq.nr_cred);
6046ca35587Sdholland 	}
6056ca35587Sdholland 
6066ca35587Sdholland 	if (nmp != NULL) {
6076ca35587Sdholland 		bzero(&nf, sizeof(struct nfs_feedback_arg));
6086ca35587Sdholland 		nf.nf_mount = nmp;
6096ca35587Sdholland 		nf.nf_td = td;
6106ca35587Sdholland 		nf.nf_lastmsg = NFSD_MONOSEC -
6116ca35587Sdholland 		    ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay));
6126ca35587Sdholland 	}
6136ca35587Sdholland 
6146ca35587Sdholland 	if (nd->nd_procnum == NFSPROC_NULL)
6156ca35587Sdholland 		auth = authnone_create();
6166ca35587Sdholland 	else if (usegssname) {
6176ca35587Sdholland 		/*
6186ca35587Sdholland 		 * For this case, the authenticator is held in the
6196ca35587Sdholland 		 * nfssockreq structure, so don't release the reference count
6206ca35587Sdholland 		 * held on it. --> Don't AUTH_DESTROY() it in this function.
6216ca35587Sdholland 		 */
6226ca35587Sdholland 		if (nrp->nr_auth == NULL)
6236ca35587Sdholland 			nrp->nr_auth = nfs_getauth(nrp, secflavour,
6246ca35587Sdholland 			    clnt_principal, srv_principal, NULL, authcred);
6256ca35587Sdholland 		else
6266ca35587Sdholland 			rpc_gss_refresh_auth_call(nrp->nr_auth);
6276ca35587Sdholland 		auth = nrp->nr_auth;
6286ca35587Sdholland 	} else
6296ca35587Sdholland 		auth = nfs_getauth(nrp, secflavour, NULL,
6306ca35587Sdholland 		    srv_principal, NULL, authcred);
6316ca35587Sdholland 	crfree(authcred);
6326ca35587Sdholland 	if (auth == NULL) {
6336ca35587Sdholland 		m_freem(nd->nd_mreq);
6346ca35587Sdholland 		if (set_sigset)
6356ca35587Sdholland 			newnfs_restore_sigmask(td, &oldset);
6366ca35587Sdholland 		return (EACCES);
6376ca35587Sdholland 	}
6386ca35587Sdholland 	bzero(&ext, sizeof(ext));
6396ca35587Sdholland 	ext.rc_auth = auth;
6406ca35587Sdholland 	if (nmp != NULL) {
6416ca35587Sdholland 		ext.rc_feedback = nfs_feedback;
6426ca35587Sdholland 		ext.rc_feedback_arg = &nf;
6436ca35587Sdholland 	}
6446ca35587Sdholland 
6456ca35587Sdholland 	procnum = nd->nd_procnum;
6466ca35587Sdholland 	if ((nd->nd_flag & ND_NFSV4) &&
6476ca35587Sdholland 	    nd->nd_procnum != NFSPROC_NULL &&
6486ca35587Sdholland 	    nd->nd_procnum != NFSV4PROC_CBCOMPOUND)
6496ca35587Sdholland 		procnum = NFSV4PROC_COMPOUND;
6506ca35587Sdholland 
6516ca35587Sdholland 	if (nmp != NULL) {
652e81f0ea2Spgoyette 		NFSINCRGLOBAL(nfsstatsv1.rpcrequests);
6536ca35587Sdholland 
6546ca35587Sdholland 		/* Map the procnum to the old NFSv2 one, as required. */
6556ca35587Sdholland 		if ((nd->nd_flag & ND_NFSV2) != 0) {
6566ca35587Sdholland 			if (nd->nd_procnum < NFS_V3NPROCS)
6576ca35587Sdholland 				procnum = nfsv2_procid[nd->nd_procnum];
6586ca35587Sdholland 			else
6596ca35587Sdholland 				procnum = NFSV2PROC_NOOP;
6606ca35587Sdholland 		}
6616ca35587Sdholland 
6626ca35587Sdholland 		/*
6636ca35587Sdholland 		 * Now only used for the R_DONTRECOVER case, but until that is
6646ca35587Sdholland 		 * supported within the krpc code, I need to keep a queue of
6656ca35587Sdholland 		 * outstanding RPCs for nfsv4 client requests.
6666ca35587Sdholland 		 */
6676ca35587Sdholland 		if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND)
6686ca35587Sdholland 			MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq),
6696ca35587Sdholland 			    M_NFSDREQ, M_WAITOK);
6706ca35587Sdholland #ifdef KDTRACE_HOOKS
6716ca35587Sdholland 		if (dtrace_nfscl_nfs234_start_probe != NULL) {
6726ca35587Sdholland 			uint32_t probe_id;
6736ca35587Sdholland 			int probe_procnum;
6746ca35587Sdholland 
6756ca35587Sdholland 			if (nd->nd_flag & ND_NFSV4) {
6766ca35587Sdholland 				probe_id =
6776ca35587Sdholland 				    nfscl_nfs4_start_probes[nd->nd_procnum];
6786ca35587Sdholland 				probe_procnum = nd->nd_procnum;
6796ca35587Sdholland 			} else if (nd->nd_flag & ND_NFSV3) {
6806ca35587Sdholland 				probe_id = nfscl_nfs3_start_probes[procnum];
6816ca35587Sdholland 				probe_procnum = procnum;
6826ca35587Sdholland 			} else {
6836ca35587Sdholland 				probe_id =
6846ca35587Sdholland 				    nfscl_nfs2_start_probes[nd->nd_procnum];
6856ca35587Sdholland 				probe_procnum = procnum;
6866ca35587Sdholland 			}
6876ca35587Sdholland 			if (probe_id != 0)
6886ca35587Sdholland 				(dtrace_nfscl_nfs234_start_probe)
6896ca35587Sdholland 				    (probe_id, vp, nd->nd_mreq, cred,
6906ca35587Sdholland 				     probe_procnum);
6916ca35587Sdholland 		}
6926ca35587Sdholland #endif
6936ca35587Sdholland 	}
6946ca35587Sdholland 	trycnt = 0;
6956ca35587Sdholland 	freeslot = -1;		/* Set to slot that needs to be free'd */
6966ca35587Sdholland tryagain:
6976ca35587Sdholland 	slot = -1;		/* Slot that needs a sequence# increment. */
6986ca35587Sdholland 	/*
6996ca35587Sdholland 	 * This timeout specifies when a new socket should be created,
7006ca35587Sdholland 	 * along with new xid values. For UDP, this should be done
7016ca35587Sdholland 	 * infrequently, since retransmits of RPC requests should normally
7026ca35587Sdholland 	 * use the same xid.
7036ca35587Sdholland 	 */
7046ca35587Sdholland 	if (nmp == NULL) {
7056ca35587Sdholland 		timo.tv_usec = 0;
7066ca35587Sdholland 		if (clp == NULL)
7076ca35587Sdholland 			timo.tv_sec = NFSV4_UPCALLTIMEO;
7086ca35587Sdholland 		else
7096ca35587Sdholland 			timo.tv_sec = NFSV4_CALLBACKTIMEO;
7106ca35587Sdholland 	} else {
7116ca35587Sdholland 		if (nrp->nr_sotype != SOCK_DGRAM) {
7126ca35587Sdholland 			timo.tv_usec = 0;
7136ca35587Sdholland 			if ((nmp->nm_flag & NFSMNT_NFSV4))
7146ca35587Sdholland 				timo.tv_sec = INT_MAX;
7156ca35587Sdholland 			else
7166ca35587Sdholland 				timo.tv_sec = NFS_TCPTIMEO;
7176ca35587Sdholland 		} else {
7186ca35587Sdholland 			if (NFSHASSOFT(nmp)) {
7196ca35587Sdholland 				/*
7206ca35587Sdholland 				 * CLSET_RETRIES is set to 2, so this should be
7216ca35587Sdholland 				 * half of the total timeout required.
7226ca35587Sdholland 				 */
7236ca35587Sdholland 				timeo = nmp->nm_retry * nmp->nm_timeo / 2;
7246ca35587Sdholland 				if (timeo < 1)
7256ca35587Sdholland 					timeo = 1;
7266ca35587Sdholland 				timo.tv_sec = timeo / NFS_HZ;
7276ca35587Sdholland 				timo.tv_usec = (timeo % NFS_HZ) * 1000000 /
7286ca35587Sdholland 				    NFS_HZ;
7296ca35587Sdholland 			} else {
7306ca35587Sdholland 				/* For UDP hard mounts, use a large value. */
7316ca35587Sdholland 				timo.tv_sec = NFS_MAXTIMEO / NFS_HZ;
7326ca35587Sdholland 				timo.tv_usec = 0;
7336ca35587Sdholland 			}
7346ca35587Sdholland 		}
7356ca35587Sdholland 
7366ca35587Sdholland 		if (rep != NULL) {
7376ca35587Sdholland 			rep->r_flags = 0;
7386ca35587Sdholland 			rep->r_nmp = nmp;
7396ca35587Sdholland 			/*
7406ca35587Sdholland 			 * Chain request into list of outstanding requests.
7416ca35587Sdholland 			 */
7426ca35587Sdholland 			NFSLOCKREQ();
7436ca35587Sdholland 			TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain);
7446ca35587Sdholland 			NFSUNLOCKREQ();
7456ca35587Sdholland 		}
7466ca35587Sdholland 	}
7476ca35587Sdholland 
7486ca35587Sdholland 	nd->nd_mrep = NULL;
749e81f0ea2Spgoyette 	if (clp != NULL && sep != NULL)
750e81f0ea2Spgoyette 		stat = clnt_bck_call(nrp->nr_client, &ext, procnum,
751e81f0ea2Spgoyette 		    nd->nd_mreq, &nd->nd_mrep, timo, sep->nfsess_xprt);
752e81f0ea2Spgoyette 	else
753e81f0ea2Spgoyette 		stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum,
754e81f0ea2Spgoyette 		    nd->nd_mreq, &nd->nd_mrep, timo);
7556ca35587Sdholland 
7566ca35587Sdholland 	if (rep != NULL) {
7576ca35587Sdholland 		/*
7586ca35587Sdholland 		 * RPC done, unlink the request.
7596ca35587Sdholland 		 */
7606ca35587Sdholland 		NFSLOCKREQ();
7616ca35587Sdholland 		TAILQ_REMOVE(&nfsd_reqq, rep, r_chain);
7626ca35587Sdholland 		NFSUNLOCKREQ();
7636ca35587Sdholland 	}
7646ca35587Sdholland 
7656ca35587Sdholland 	/*
7666ca35587Sdholland 	 * If there was a successful reply and a tprintf msg.
7676ca35587Sdholland 	 * tprintf a response.
7686ca35587Sdholland 	 */
7696ca35587Sdholland 	if (stat == RPC_SUCCESS) {
7706ca35587Sdholland 		error = 0;
7716ca35587Sdholland 	} else if (stat == RPC_TIMEDOUT) {
772e81f0ea2Spgoyette 		NFSINCRGLOBAL(nfsstatsv1.rpctimeouts);
7736ca35587Sdholland 		error = ETIMEDOUT;
7746ca35587Sdholland 	} else if (stat == RPC_VERSMISMATCH) {
775e81f0ea2Spgoyette 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
7766ca35587Sdholland 		error = EOPNOTSUPP;
7776ca35587Sdholland 	} else if (stat == RPC_PROGVERSMISMATCH) {
778e81f0ea2Spgoyette 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
7796ca35587Sdholland 		error = EPROTONOSUPPORT;
7806ca35587Sdholland 	} else if (stat == RPC_INTR) {
7816ca35587Sdholland 		error = EINTR;
7826ca35587Sdholland 	} else {
783e81f0ea2Spgoyette 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
7846ca35587Sdholland 		error = EACCES;
7856ca35587Sdholland 	}
7866ca35587Sdholland 	if (error) {
7876ca35587Sdholland 		m_freem(nd->nd_mreq);
7886ca35587Sdholland 		if (usegssname == 0)
7896ca35587Sdholland 			AUTH_DESTROY(auth);
7906ca35587Sdholland 		if (rep != NULL)
7916ca35587Sdholland 			FREE((caddr_t)rep, M_NFSDREQ);
7926ca35587Sdholland 		if (set_sigset)
7936ca35587Sdholland 			newnfs_restore_sigmask(td, &oldset);
7946ca35587Sdholland 		return (error);
7956ca35587Sdholland 	}
7966ca35587Sdholland 
7976ca35587Sdholland 	KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n"));
7986ca35587Sdholland 
7996ca35587Sdholland 	/*
8006ca35587Sdholland 	 * Search for any mbufs that are not a multiple of 4 bytes long
8016ca35587Sdholland 	 * or with m_data not longword aligned.
8026ca35587Sdholland 	 * These could cause pointer alignment problems, so copy them to
8036ca35587Sdholland 	 * well aligned mbufs.
8046ca35587Sdholland 	 */
8056ca35587Sdholland 	newnfs_realign(&nd->nd_mrep, M_WAITOK);
8066ca35587Sdholland 	nd->nd_md = nd->nd_mrep;
8076ca35587Sdholland 	nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
8086ca35587Sdholland 	nd->nd_repstat = 0;
809e81f0ea2Spgoyette 	if (nd->nd_procnum != NFSPROC_NULL &&
810e81f0ea2Spgoyette 	    nd->nd_procnum != NFSV4PROC_CBNULL) {
8116ca35587Sdholland 		/* If sep == NULL, set it to the default in nmp. */
8126ca35587Sdholland 		if (sep == NULL && nmp != NULL)
8136ca35587Sdholland 			sep = NFSMNT_MDSSESSION(nmp);
8146ca35587Sdholland 		/*
8156ca35587Sdholland 		 * and now the actual NFS xdr.
8166ca35587Sdholland 		 */
8176ca35587Sdholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
8186ca35587Sdholland 		nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl);
8196ca35587Sdholland 		if (nd->nd_repstat >= 10000)
8206ca35587Sdholland 			NFSCL_DEBUG(1, "proc=%d reps=%d\n", (int)nd->nd_procnum,
8216ca35587Sdholland 			    (int)nd->nd_repstat);
8226ca35587Sdholland 
8236ca35587Sdholland 		/*
8246ca35587Sdholland 		 * Get rid of the tag, return count and SEQUENCE result for
8256ca35587Sdholland 		 * NFSv4.
8266ca35587Sdholland 		 */
8276ca35587Sdholland 		if ((nd->nd_flag & ND_NFSV4) != 0) {
8286ca35587Sdholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
8296ca35587Sdholland 			i = fxdr_unsigned(int, *tl);
8306ca35587Sdholland 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
8316ca35587Sdholland 			if (error)
8326ca35587Sdholland 				goto nfsmout;
8336ca35587Sdholland 			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
8346ca35587Sdholland 			opcnt = fxdr_unsigned(int, *tl++);
8356ca35587Sdholland 			i = fxdr_unsigned(int, *tl++);
8366ca35587Sdholland 			j = fxdr_unsigned(int, *tl);
8376ca35587Sdholland 			if (j >= 10000)
8386ca35587Sdholland 				NFSCL_DEBUG(1, "fop=%d fst=%d\n", i, j);
8396ca35587Sdholland 			/*
8406ca35587Sdholland 			 * If the first op is Sequence, free up the slot.
8416ca35587Sdholland 			 */
842e81f0ea2Spgoyette 			if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) ||
843e81f0ea2Spgoyette 			    (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0))
8446ca35587Sdholland 				NFSCL_DEBUG(1, "failed seq=%d\n", j);
845e81f0ea2Spgoyette 			if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) ||
846e81f0ea2Spgoyette 			    (clp != NULL && i == NFSV4OP_CBSEQUENCE && j == 0)
847e81f0ea2Spgoyette 			    ) {
848e81f0ea2Spgoyette 				if (i == NFSV4OP_SEQUENCE)
849e81f0ea2Spgoyette 					NFSM_DISSECT(tl, uint32_t *,
850e81f0ea2Spgoyette 					    NFSX_V4SESSIONID +
8516ca35587Sdholland 					    5 * NFSX_UNSIGNED);
852e81f0ea2Spgoyette 				else
853e81f0ea2Spgoyette 					NFSM_DISSECT(tl, uint32_t *,
854e81f0ea2Spgoyette 					    NFSX_V4SESSIONID +
855e81f0ea2Spgoyette 					    4 * NFSX_UNSIGNED);
8566ca35587Sdholland 				mtx_lock(&sep->nfsess_mtx);
8576ca35587Sdholland 				tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
8586ca35587Sdholland 				retseq = fxdr_unsigned(uint32_t, *tl++);
8596ca35587Sdholland 				slot = fxdr_unsigned(int, *tl++);
8606ca35587Sdholland 				freeslot = slot;
8616ca35587Sdholland 				if (retseq != sep->nfsess_slotseq[slot])
8626ca35587Sdholland 					printf("retseq diff 0x%x\n", retseq);
8636ca35587Sdholland 				retval = fxdr_unsigned(uint32_t, *++tl);
8646ca35587Sdholland 				if ((retval + 1) < sep->nfsess_foreslots)
8656ca35587Sdholland 					sep->nfsess_foreslots = (retval + 1);
8666ca35587Sdholland 				else if ((retval + 1) > sep->nfsess_foreslots)
8676ca35587Sdholland 					sep->nfsess_foreslots = (retval < 64) ?
8686ca35587Sdholland 					    (retval + 1) : 64;
8696ca35587Sdholland 				mtx_unlock(&sep->nfsess_mtx);
8706ca35587Sdholland 
8716ca35587Sdholland 				/* Grab the op and status for the next one. */
8726ca35587Sdholland 				if (opcnt > 1) {
8736ca35587Sdholland 					NFSM_DISSECT(tl, uint32_t *,
8746ca35587Sdholland 					    2 * NFSX_UNSIGNED);
8756ca35587Sdholland 					i = fxdr_unsigned(int, *tl++);
8766ca35587Sdholland 					j = fxdr_unsigned(int, *tl);
8776ca35587Sdholland 				}
8786ca35587Sdholland 			}
8796ca35587Sdholland 		}
8806ca35587Sdholland 		if (nd->nd_repstat != 0) {
8816ca35587Sdholland 			if (((nd->nd_repstat == NFSERR_DELAY ||
8826ca35587Sdholland 			      nd->nd_repstat == NFSERR_GRACE) &&
8836ca35587Sdholland 			     (nd->nd_flag & ND_NFSV4) &&
8846ca35587Sdholland 			     nd->nd_procnum != NFSPROC_DELEGRETURN &&
8856ca35587Sdholland 			     nd->nd_procnum != NFSPROC_SETATTR &&
8866ca35587Sdholland 			     nd->nd_procnum != NFSPROC_READ &&
8876ca35587Sdholland 			     nd->nd_procnum != NFSPROC_READDS &&
8886ca35587Sdholland 			     nd->nd_procnum != NFSPROC_WRITE &&
8896ca35587Sdholland 			     nd->nd_procnum != NFSPROC_WRITEDS &&
8906ca35587Sdholland 			     nd->nd_procnum != NFSPROC_OPEN &&
8916ca35587Sdholland 			     nd->nd_procnum != NFSPROC_CREATE &&
8926ca35587Sdholland 			     nd->nd_procnum != NFSPROC_OPENCONFIRM &&
8936ca35587Sdholland 			     nd->nd_procnum != NFSPROC_OPENDOWNGRADE &&
8946ca35587Sdholland 			     nd->nd_procnum != NFSPROC_CLOSE &&
8956ca35587Sdholland 			     nd->nd_procnum != NFSPROC_LOCK &&
8966ca35587Sdholland 			     nd->nd_procnum != NFSPROC_LOCKU) ||
8976ca35587Sdholland 			    (nd->nd_repstat == NFSERR_DELAY &&
8986ca35587Sdholland 			     (nd->nd_flag & ND_NFSV4) == 0) ||
8996ca35587Sdholland 			    nd->nd_repstat == NFSERR_RESOURCE) {
9006ca35587Sdholland 				if (trylater_delay > NFS_TRYLATERDEL)
9016ca35587Sdholland 					trylater_delay = NFS_TRYLATERDEL;
9026ca35587Sdholland 				waituntil = NFSD_MONOSEC + trylater_delay;
9036ca35587Sdholland 				while (NFSD_MONOSEC < waituntil)
9046ca35587Sdholland 					(void) nfs_catnap(PZERO, 0, "nfstry");
9056ca35587Sdholland 				trylater_delay *= 2;
9066ca35587Sdholland 				if (slot != -1) {
9076ca35587Sdholland 					mtx_lock(&sep->nfsess_mtx);
9086ca35587Sdholland 					sep->nfsess_slotseq[slot]++;
9096ca35587Sdholland 					*nd->nd_slotseq = txdr_unsigned(
9106ca35587Sdholland 					    sep->nfsess_slotseq[slot]);
9116ca35587Sdholland 					mtx_unlock(&sep->nfsess_mtx);
9126ca35587Sdholland 				}
9136ca35587Sdholland 				m_freem(nd->nd_mrep);
9146ca35587Sdholland 				nd->nd_mrep = NULL;
9156ca35587Sdholland 				goto tryagain;
9166ca35587Sdholland 			}
9176ca35587Sdholland 
9186ca35587Sdholland 			/*
9196ca35587Sdholland 			 * If the File Handle was stale, invalidate the
9206ca35587Sdholland 			 * lookup cache, just in case.
9216ca35587Sdholland 			 * (vp != NULL implies a client side call)
9226ca35587Sdholland 			 */
9236ca35587Sdholland 			if (nd->nd_repstat == ESTALE && vp != NULL) {
9246ca35587Sdholland 				cache_purge(vp);
9256ca35587Sdholland 				if (ncl_call_invalcaches != NULL)
9266ca35587Sdholland 					(*ncl_call_invalcaches)(vp);
9276ca35587Sdholland 			}
9286ca35587Sdholland 		}
9296ca35587Sdholland 		if ((nd->nd_flag & ND_NFSV4) != 0) {
9306ca35587Sdholland 			/* Free the slot, as required. */
9316ca35587Sdholland 			if (freeslot != -1)
9326ca35587Sdholland 				nfsv4_freeslot(sep, freeslot);
9336ca35587Sdholland 			/*
9346ca35587Sdholland 			 * If this op is Putfh, throw its results away.
9356ca35587Sdholland 			 */
9366ca35587Sdholland 			if (j >= 10000)
9376ca35587Sdholland 				NFSCL_DEBUG(1, "nop=%d nst=%d\n", i, j);
9386ca35587Sdholland 			if (nmp != NULL && i == NFSV4OP_PUTFH && j == 0) {
9396ca35587Sdholland 				NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED);
9406ca35587Sdholland 				i = fxdr_unsigned(int, *tl++);
9416ca35587Sdholland 				j = fxdr_unsigned(int, *tl);
9426ca35587Sdholland 				if (j >= 10000)
9436ca35587Sdholland 					NFSCL_DEBUG(1, "n2op=%d n2st=%d\n", i,
9446ca35587Sdholland 					    j);
9456ca35587Sdholland 				/*
9466ca35587Sdholland 				 * All Compounds that do an Op that must
9476ca35587Sdholland 				 * be in sequence consist of NFSV4OP_PUTFH
9486ca35587Sdholland 				 * followed by one of these. As such, we
9496ca35587Sdholland 				 * can determine if the seqid# should be
9506ca35587Sdholland 				 * incremented, here.
9516ca35587Sdholland 				 */
9526ca35587Sdholland 				if ((i == NFSV4OP_OPEN ||
9536ca35587Sdholland 				     i == NFSV4OP_OPENCONFIRM ||
9546ca35587Sdholland 				     i == NFSV4OP_OPENDOWNGRADE ||
9556ca35587Sdholland 				     i == NFSV4OP_CLOSE ||
9566ca35587Sdholland 				     i == NFSV4OP_LOCK ||
9576ca35587Sdholland 				     i == NFSV4OP_LOCKU) &&
9586ca35587Sdholland 				    (j == 0 ||
9596ca35587Sdholland 				     (j != NFSERR_STALECLIENTID &&
9606ca35587Sdholland 				      j != NFSERR_STALESTATEID &&
9616ca35587Sdholland 				      j != NFSERR_BADSTATEID &&
9626ca35587Sdholland 				      j != NFSERR_BADSEQID &&
9636ca35587Sdholland 				      j != NFSERR_BADXDR &&
9646ca35587Sdholland 				      j != NFSERR_RESOURCE &&
9656ca35587Sdholland 				      j != NFSERR_NOFILEHANDLE)))
9666ca35587Sdholland 					nd->nd_flag |= ND_INCRSEQID;
9676ca35587Sdholland 			}
9686ca35587Sdholland 			/*
9696ca35587Sdholland 			 * If this op's status is non-zero, mark
9706ca35587Sdholland 			 * that there is no more data to process.
9716ca35587Sdholland 			 */
9726ca35587Sdholland 			if (j)
9736ca35587Sdholland 				nd->nd_flag |= ND_NOMOREDATA;
9746ca35587Sdholland 
9756ca35587Sdholland 			/*
9766ca35587Sdholland 			 * If R_DONTRECOVER is set, replace the stale error
9776ca35587Sdholland 			 * reply, so that recovery isn't initiated.
9786ca35587Sdholland 			 */
9796ca35587Sdholland 			if ((nd->nd_repstat == NFSERR_STALECLIENTID ||
9806ca35587Sdholland 			     nd->nd_repstat == NFSERR_BADSESSION ||
9816ca35587Sdholland 			     nd->nd_repstat == NFSERR_STALESTATEID) &&
9826ca35587Sdholland 			    rep != NULL && (rep->r_flags & R_DONTRECOVER))
9836ca35587Sdholland 				nd->nd_repstat = NFSERR_STALEDONTRECOVER;
9846ca35587Sdholland 		}
9856ca35587Sdholland 	}
9866ca35587Sdholland 
9876ca35587Sdholland #ifdef KDTRACE_HOOKS
9886ca35587Sdholland 	if (nmp != NULL && dtrace_nfscl_nfs234_done_probe != NULL) {
9896ca35587Sdholland 		uint32_t probe_id;
9906ca35587Sdholland 		int probe_procnum;
9916ca35587Sdholland 
9926ca35587Sdholland 		if (nd->nd_flag & ND_NFSV4) {
9936ca35587Sdholland 			probe_id = nfscl_nfs4_done_probes[nd->nd_procnum];
9946ca35587Sdholland 			probe_procnum = nd->nd_procnum;
9956ca35587Sdholland 		} else if (nd->nd_flag & ND_NFSV3) {
9966ca35587Sdholland 			probe_id = nfscl_nfs3_done_probes[procnum];
9976ca35587Sdholland 			probe_procnum = procnum;
9986ca35587Sdholland 		} else {
9996ca35587Sdholland 			probe_id = nfscl_nfs2_done_probes[nd->nd_procnum];
10006ca35587Sdholland 			probe_procnum = procnum;
10016ca35587Sdholland 		}
10026ca35587Sdholland 		if (probe_id != 0)
10036ca35587Sdholland 			(dtrace_nfscl_nfs234_done_probe)(probe_id, vp,
10046ca35587Sdholland 			    nd->nd_mreq, cred, probe_procnum, 0);
10056ca35587Sdholland 	}
10066ca35587Sdholland #endif
10076ca35587Sdholland 
10086ca35587Sdholland 	m_freem(nd->nd_mreq);
10096ca35587Sdholland 	if (usegssname == 0)
10106ca35587Sdholland 		AUTH_DESTROY(auth);
10116ca35587Sdholland 	if (rep != NULL)
10126ca35587Sdholland 		FREE((caddr_t)rep, M_NFSDREQ);
10136ca35587Sdholland 	if (set_sigset)
10146ca35587Sdholland 		newnfs_restore_sigmask(td, &oldset);
10156ca35587Sdholland 	return (0);
10166ca35587Sdholland nfsmout:
10176ca35587Sdholland 	mbuf_freem(nd->nd_mrep);
10186ca35587Sdholland 	mbuf_freem(nd->nd_mreq);
10196ca35587Sdholland 	if (usegssname == 0)
10206ca35587Sdholland 		AUTH_DESTROY(auth);
10216ca35587Sdholland 	if (rep != NULL)
10226ca35587Sdholland 		FREE((caddr_t)rep, M_NFSDREQ);
10236ca35587Sdholland 	if (set_sigset)
10246ca35587Sdholland 		newnfs_restore_sigmask(td, &oldset);
10256ca35587Sdholland 	return (error);
10266ca35587Sdholland }
10276ca35587Sdholland 
10286ca35587Sdholland /*
10296ca35587Sdholland  * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
10306ca35587Sdholland  * wait for all requests to complete. This is used by forced unmounts
10316ca35587Sdholland  * to terminate any outstanding RPCs.
10326ca35587Sdholland  */
10336ca35587Sdholland int
newnfs_nmcancelreqs(struct nfsmount * nmp)10346ca35587Sdholland newnfs_nmcancelreqs(struct nfsmount *nmp)
10356ca35587Sdholland {
10366ca35587Sdholland 
10376ca35587Sdholland 	if (nmp->nm_sockreq.nr_client != NULL)
10386ca35587Sdholland 		CLNT_CLOSE(nmp->nm_sockreq.nr_client);
10396ca35587Sdholland 	return (0);
10406ca35587Sdholland }
10416ca35587Sdholland 
10426ca35587Sdholland /*
10436ca35587Sdholland  * Any signal that can interrupt an NFS operation in an intr mount
10446ca35587Sdholland  * should be added to this set. SIGSTOP and SIGKILL cannot be masked.
10456ca35587Sdholland  */
10466ca35587Sdholland int newnfs_sig_set[] = {
10476ca35587Sdholland 	SIGINT,
10486ca35587Sdholland 	SIGTERM,
10496ca35587Sdholland 	SIGHUP,
10506ca35587Sdholland 	SIGKILL,
10516ca35587Sdholland 	SIGQUIT
10526ca35587Sdholland };
10536ca35587Sdholland 
10546ca35587Sdholland /*
10556ca35587Sdholland  * Check to see if one of the signals in our subset is pending on
10566ca35587Sdholland  * the process (in an intr mount).
10576ca35587Sdholland  */
10586ca35587Sdholland static int
nfs_sig_pending(sigset_t set)10596ca35587Sdholland nfs_sig_pending(sigset_t set)
10606ca35587Sdholland {
10616ca35587Sdholland 	int i;
10626ca35587Sdholland 
1063e81f0ea2Spgoyette 	for (i = 0 ; i < nitems(newnfs_sig_set); i++)
10646ca35587Sdholland 		if (SIGISMEMBER(set, newnfs_sig_set[i]))
10656ca35587Sdholland 			return (1);
10666ca35587Sdholland 	return (0);
10676ca35587Sdholland }
10686ca35587Sdholland 
10696ca35587Sdholland /*
10706ca35587Sdholland  * The set/restore sigmask functions are used to (temporarily) overwrite
10716ca35587Sdholland  * the thread td_sigmask during an RPC call (for example). These are also
10726ca35587Sdholland  * used in other places in the NFS client that might tsleep().
10736ca35587Sdholland  */
10746ca35587Sdholland void
newnfs_set_sigmask(struct thread * td,sigset_t * oldset)10756ca35587Sdholland newnfs_set_sigmask(struct thread *td, sigset_t *oldset)
10766ca35587Sdholland {
10776ca35587Sdholland 	sigset_t newset;
10786ca35587Sdholland 	int i;
10796ca35587Sdholland 	struct proc *p;
10806ca35587Sdholland 
10816ca35587Sdholland 	SIGFILLSET(newset);
10826ca35587Sdholland 	if (td == NULL)
10836ca35587Sdholland 		td = curthread; /* XXX */
10846ca35587Sdholland 	p = td->td_proc;
10856ca35587Sdholland 	/* Remove the NFS set of signals from newset */
10866ca35587Sdholland 	PROC_LOCK(p);
10876ca35587Sdholland 	mtx_lock(&p->p_sigacts->ps_mtx);
1088e81f0ea2Spgoyette 	for (i = 0 ; i < nitems(newnfs_sig_set); i++) {
10896ca35587Sdholland 		/*
10906ca35587Sdholland 		 * But make sure we leave the ones already masked
10916ca35587Sdholland 		 * by the process, ie. remove the signal from the
10926ca35587Sdholland 		 * temporary signalmask only if it wasn't already
10936ca35587Sdholland 		 * in p_sigmask.
10946ca35587Sdholland 		 */
10956ca35587Sdholland 		if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) &&
10966ca35587Sdholland 		    !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i]))
10976ca35587Sdholland 			SIGDELSET(newset, newnfs_sig_set[i]);
10986ca35587Sdholland 	}
10996ca35587Sdholland 	mtx_unlock(&p->p_sigacts->ps_mtx);
11006ca35587Sdholland 	kern_sigprocmask(td, SIG_SETMASK, &newset, oldset,
11016ca35587Sdholland 	    SIGPROCMASK_PROC_LOCKED);
11026ca35587Sdholland 	PROC_UNLOCK(p);
11036ca35587Sdholland }
11046ca35587Sdholland 
11056ca35587Sdholland void
newnfs_restore_sigmask(struct thread * td,sigset_t * set)11066ca35587Sdholland newnfs_restore_sigmask(struct thread *td, sigset_t *set)
11076ca35587Sdholland {
11086ca35587Sdholland 	if (td == NULL)
11096ca35587Sdholland 		td = curthread; /* XXX */
11106ca35587Sdholland 	kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0);
11116ca35587Sdholland }
11126ca35587Sdholland 
11136ca35587Sdholland /*
11146ca35587Sdholland  * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the
11156ca35587Sdholland  * old one after msleep() returns.
11166ca35587Sdholland  */
11176ca35587Sdholland int
newnfs_msleep(struct thread * td,void * ident,struct mtx * mtx,int priority,char * wmesg,int timo)11186ca35587Sdholland newnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo)
11196ca35587Sdholland {
11206ca35587Sdholland 	sigset_t oldset;
11216ca35587Sdholland 	int error;
11226ca35587Sdholland 	struct proc *p;
11236ca35587Sdholland 
11246ca35587Sdholland 	if ((priority & PCATCH) == 0)
11256ca35587Sdholland 		return msleep(ident, mtx, priority, wmesg, timo);
11266ca35587Sdholland 	if (td == NULL)
11276ca35587Sdholland 		td = curthread; /* XXX */
11286ca35587Sdholland 	newnfs_set_sigmask(td, &oldset);
11296ca35587Sdholland 	error = msleep(ident, mtx, priority, wmesg, timo);
11306ca35587Sdholland 	newnfs_restore_sigmask(td, &oldset);
11316ca35587Sdholland 	p = td->td_proc;
11326ca35587Sdholland 	return (error);
11336ca35587Sdholland }
11346ca35587Sdholland 
11356ca35587Sdholland /*
11366ca35587Sdholland  * Test for a termination condition pending on the process.
11376ca35587Sdholland  * This is used for NFSMNT_INT mounts.
11386ca35587Sdholland  */
11396ca35587Sdholland int
newnfs_sigintr(struct nfsmount * nmp,struct thread * td)11406ca35587Sdholland newnfs_sigintr(struct nfsmount *nmp, struct thread *td)
11416ca35587Sdholland {
11426ca35587Sdholland 	struct proc *p;
11436ca35587Sdholland 	sigset_t tmpset;
11446ca35587Sdholland 
11456ca35587Sdholland 	/* Terminate all requests while attempting a forced unmount. */
11466ca35587Sdholland 	if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
11476ca35587Sdholland 		return (EIO);
11486ca35587Sdholland 	if (!(nmp->nm_flag & NFSMNT_INT))
11496ca35587Sdholland 		return (0);
11506ca35587Sdholland 	if (td == NULL)
11516ca35587Sdholland 		return (0);
11526ca35587Sdholland 	p = td->td_proc;
11536ca35587Sdholland 	PROC_LOCK(p);
11546ca35587Sdholland 	tmpset = p->p_siglist;
11556ca35587Sdholland 	SIGSETOR(tmpset, td->td_siglist);
11566ca35587Sdholland 	SIGSETNAND(tmpset, td->td_sigmask);
11576ca35587Sdholland 	mtx_lock(&p->p_sigacts->ps_mtx);
11586ca35587Sdholland 	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
11596ca35587Sdholland 	mtx_unlock(&p->p_sigacts->ps_mtx);
11606ca35587Sdholland 	if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist))
11616ca35587Sdholland 	    && nfs_sig_pending(tmpset)) {
11626ca35587Sdholland 		PROC_UNLOCK(p);
11636ca35587Sdholland 		return (EINTR);
11646ca35587Sdholland 	}
11656ca35587Sdholland 	PROC_UNLOCK(p);
11666ca35587Sdholland 	return (0);
11676ca35587Sdholland }
11686ca35587Sdholland 
11696ca35587Sdholland static int
nfs_msg(struct thread * td,const char * server,const char * msg,int error)11706ca35587Sdholland nfs_msg(struct thread *td, const char *server, const char *msg, int error)
11716ca35587Sdholland {
11726ca35587Sdholland 	struct proc *p;
11736ca35587Sdholland 
11746ca35587Sdholland 	p = td ? td->td_proc : NULL;
11756ca35587Sdholland 	if (error) {
1176e81f0ea2Spgoyette 		tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n",
11776ca35587Sdholland 		    server, msg, error);
11786ca35587Sdholland 	} else {
1179e81f0ea2Spgoyette 		tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg);
11806ca35587Sdholland 	}
11816ca35587Sdholland 	return (0);
11826ca35587Sdholland }
11836ca35587Sdholland 
11846ca35587Sdholland static void
nfs_down(struct nfsmount * nmp,struct thread * td,const char * msg,int error,int flags)11856ca35587Sdholland nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg,
11866ca35587Sdholland     int error, int flags)
11876ca35587Sdholland {
11886ca35587Sdholland 	if (nmp == NULL)
11896ca35587Sdholland 		return;
11906ca35587Sdholland 	mtx_lock(&nmp->nm_mtx);
11916ca35587Sdholland 	if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) {
11926ca35587Sdholland 		nmp->nm_state |= NFSSTA_TIMEO;
11936ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
11946ca35587Sdholland 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
11956ca35587Sdholland 		    VQ_NOTRESP, 0);
11966ca35587Sdholland 	} else
11976ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
11986ca35587Sdholland 	mtx_lock(&nmp->nm_mtx);
11996ca35587Sdholland 	if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
12006ca35587Sdholland 		nmp->nm_state |= NFSSTA_LOCKTIMEO;
12016ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
12026ca35587Sdholland 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
12036ca35587Sdholland 		    VQ_NOTRESPLOCK, 0);
12046ca35587Sdholland 	} else
12056ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
12066ca35587Sdholland 	nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error);
12076ca35587Sdholland }
12086ca35587Sdholland 
12096ca35587Sdholland static void
nfs_up(struct nfsmount * nmp,struct thread * td,const char * msg,int flags,int tprintfmsg)12106ca35587Sdholland nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg,
12116ca35587Sdholland     int flags, int tprintfmsg)
12126ca35587Sdholland {
12136ca35587Sdholland 	if (nmp == NULL)
12146ca35587Sdholland 		return;
12156ca35587Sdholland 	if (tprintfmsg) {
12166ca35587Sdholland 		nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0);
12176ca35587Sdholland 	}
12186ca35587Sdholland 
12196ca35587Sdholland 	mtx_lock(&nmp->nm_mtx);
12206ca35587Sdholland 	if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) {
12216ca35587Sdholland 		nmp->nm_state &= ~NFSSTA_TIMEO;
12226ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
12236ca35587Sdholland 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
12246ca35587Sdholland 		    VQ_NOTRESP, 1);
12256ca35587Sdholland 	} else
12266ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
12276ca35587Sdholland 
12286ca35587Sdholland 	mtx_lock(&nmp->nm_mtx);
12296ca35587Sdholland 	if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) {
12306ca35587Sdholland 		nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
12316ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
12326ca35587Sdholland 		vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
12336ca35587Sdholland 		    VQ_NOTRESPLOCK, 1);
12346ca35587Sdholland 	} else
12356ca35587Sdholland 		mtx_unlock(&nmp->nm_mtx);
12366ca35587Sdholland }
12376ca35587Sdholland 
1238