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