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