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