1 1.3 andvar /* $NetBSD: nfs_commonkrpc.c,v 1.3 2023/06/16 19:40:46 andvar Exp $ */ 2 1.1 dholland /*- 3 1.1 dholland * Copyright (c) 1989, 1991, 1993, 1995 4 1.1 dholland * The Regents of the University of California. All rights reserved. 5 1.1 dholland * 6 1.1 dholland * This code is derived from software contributed to Berkeley by 7 1.1 dholland * Rick Macklem at The University of Guelph. 8 1.1 dholland * 9 1.1 dholland * Redistribution and use in source and binary forms, with or without 10 1.1 dholland * modification, are permitted provided that the following conditions 11 1.1 dholland * are met: 12 1.1 dholland * 1. Redistributions of source code must retain the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer. 14 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer in the 16 1.1 dholland * documentation and/or other materials provided with the distribution. 17 1.1 dholland * 4. Neither the name of the University nor the names of its contributors 18 1.1 dholland * may be used to endorse or promote products derived from this software 19 1.1 dholland * without specific prior written permission. 20 1.1 dholland * 21 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 dholland * SUCH DAMAGE. 32 1.1 dholland * 33 1.1 dholland */ 34 1.1 dholland 35 1.1 dholland #include <sys/cdefs.h> 36 1.2 pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfs/nfs_commonkrpc.c 304026 2016-08-12 22:44:59Z rmacklem "); */ 37 1.3 andvar __RCSID("$NetBSD: nfs_commonkrpc.c,v 1.3 2023/06/16 19:40:46 andvar Exp $"); 38 1.1 dholland 39 1.1 dholland /* 40 1.1 dholland * Socket operations for use by nfs 41 1.1 dholland */ 42 1.1 dholland 43 1.2 pgoyette #ifdef _KERNEL_OPT 44 1.2 pgoyette #include "opt_dtrace.h" 45 1.2 pgoyette #include "opt_newnfs.h" 46 1.2 pgoyette #if 0 47 1.1 dholland #include "opt_kgssapi.h" 48 1.2 pgoyette #endif 49 1.2 pgoyette #endif 50 1.1 dholland 51 1.1 dholland #include <sys/param.h> 52 1.1 dholland #include <sys/systm.h> 53 1.1 dholland #include <sys/kernel.h> 54 1.1 dholland #include <sys/limits.h> 55 1.1 dholland #include <sys/lock.h> 56 1.1 dholland #include <sys/malloc.h> 57 1.1 dholland #include <sys/mbuf.h> 58 1.1 dholland #include <sys/mount.h> 59 1.1 dholland #include <sys/mutex.h> 60 1.1 dholland #include <sys/proc.h> 61 1.1 dholland #include <sys/signalvar.h> 62 1.1 dholland #include <sys/syscallsubr.h> 63 1.1 dholland #include <sys/sysctl.h> 64 1.1 dholland #include <sys/syslog.h> 65 1.1 dholland #include <sys/vnode.h> 66 1.1 dholland 67 1.1 dholland #include <rpc/rpc.h> 68 1.2 pgoyette #include <fs/nfs/common/krpc.h> 69 1.1 dholland 70 1.1 dholland #include <kgssapi/krb5/kcrypto.h> 71 1.1 dholland 72 1.2 pgoyette #include <fs/nfs/common/nfsport.h> 73 1.1 dholland 74 1.1 dholland #ifdef KDTRACE_HOOKS 75 1.1 dholland #include <sys/dtrace_bsd.h> 76 1.1 dholland 77 1.1 dholland dtrace_nfsclient_nfs23_start_probe_func_t 78 1.1 dholland dtrace_nfscl_nfs234_start_probe; 79 1.1 dholland 80 1.1 dholland dtrace_nfsclient_nfs23_done_probe_func_t 81 1.1 dholland dtrace_nfscl_nfs234_done_probe; 82 1.1 dholland 83 1.1 dholland /* 84 1.1 dholland * Registered probes by RPC type. 85 1.1 dholland */ 86 1.1 dholland uint32_t nfscl_nfs2_start_probes[NFSV41_NPROCS + 1]; 87 1.1 dholland uint32_t nfscl_nfs2_done_probes[NFSV41_NPROCS + 1]; 88 1.1 dholland 89 1.1 dholland uint32_t nfscl_nfs3_start_probes[NFSV41_NPROCS + 1]; 90 1.1 dholland uint32_t nfscl_nfs3_done_probes[NFSV41_NPROCS + 1]; 91 1.1 dholland 92 1.1 dholland uint32_t nfscl_nfs4_start_probes[NFSV41_NPROCS + 1]; 93 1.1 dholland uint32_t nfscl_nfs4_done_probes[NFSV41_NPROCS + 1]; 94 1.1 dholland #endif 95 1.1 dholland 96 1.1 dholland NFSSTATESPINLOCK; 97 1.1 dholland NFSREQSPINLOCK; 98 1.1 dholland NFSDLOCKMUTEX; 99 1.2 pgoyette extern struct nfsstatsv1 nfsstatsv1; 100 1.1 dholland extern struct nfsreqhead nfsd_reqq; 101 1.1 dholland extern int nfscl_ticks; 102 1.1 dholland extern void (*ncl_call_invalcaches)(struct vnode *); 103 1.1 dholland extern int nfs_numnfscbd; 104 1.1 dholland extern int nfscl_debuglevel; 105 1.1 dholland 106 1.1 dholland SVCPOOL *nfscbd_pool; 107 1.1 dholland static int nfsrv_gsscallbackson = 0; 108 1.1 dholland static int nfs_bufpackets = 4; 109 1.1 dholland static int nfs_reconnects; 110 1.1 dholland static int nfs3_jukebox_delay = 10; 111 1.1 dholland static int nfs_skip_wcc_data_onerr = 1; 112 1.1 dholland 113 1.1 dholland SYSCTL_DECL(_vfs_nfs); 114 1.1 dholland 115 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, 116 1.1 dholland "Buffer reservation size 2 < x < 64"); 117 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, 118 1.1 dholland "Number of times the nfs client has had to reconnect"); 119 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0, 120 1.1 dholland "Number of seconds to delay a retry after receiving EJUKEBOX"); 121 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0, 122 1.1 dholland "Disable weak cache consistency checking when server returns an error"); 123 1.1 dholland 124 1.1 dholland static void nfs_down(struct nfsmount *, struct thread *, const char *, 125 1.1 dholland int, int); 126 1.1 dholland static void nfs_up(struct nfsmount *, struct thread *, const char *, 127 1.1 dholland int, int); 128 1.1 dholland static int nfs_msg(struct thread *, const char *, const char *, int); 129 1.1 dholland 130 1.1 dholland struct nfs_cached_auth { 131 1.1 dholland int ca_refs; /* refcount, including 1 from the cache */ 132 1.1 dholland uid_t ca_uid; /* uid that corresponds to this auth */ 133 1.1 dholland AUTH *ca_auth; /* RPC auth handle */ 134 1.1 dholland }; 135 1.1 dholland 136 1.1 dholland static int nfsv2_procid[NFS_V3NPROCS] = { 137 1.1 dholland NFSV2PROC_NULL, 138 1.1 dholland NFSV2PROC_GETATTR, 139 1.1 dholland NFSV2PROC_SETATTR, 140 1.1 dholland NFSV2PROC_LOOKUP, 141 1.1 dholland NFSV2PROC_NOOP, 142 1.1 dholland NFSV2PROC_READLINK, 143 1.1 dholland NFSV2PROC_READ, 144 1.1 dholland NFSV2PROC_WRITE, 145 1.1 dholland NFSV2PROC_CREATE, 146 1.1 dholland NFSV2PROC_MKDIR, 147 1.1 dholland NFSV2PROC_SYMLINK, 148 1.1 dholland NFSV2PROC_CREATE, 149 1.1 dholland NFSV2PROC_REMOVE, 150 1.1 dholland NFSV2PROC_RMDIR, 151 1.1 dholland NFSV2PROC_RENAME, 152 1.1 dholland NFSV2PROC_LINK, 153 1.1 dholland NFSV2PROC_READDIR, 154 1.1 dholland NFSV2PROC_NOOP, 155 1.1 dholland NFSV2PROC_STATFS, 156 1.1 dholland NFSV2PROC_NOOP, 157 1.1 dholland NFSV2PROC_NOOP, 158 1.1 dholland NFSV2PROC_NOOP, 159 1.1 dholland }; 160 1.1 dholland 161 1.1 dholland /* 162 1.1 dholland * Initialize sockets and congestion for a new NFS connection. 163 1.1 dholland * We do not free the sockaddr if error. 164 1.1 dholland */ 165 1.1 dholland int 166 1.1 dholland newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, 167 1.1 dholland struct ucred *cred, NFSPROC_T *p, int callback_retry_mult) 168 1.1 dholland { 169 1.1 dholland int rcvreserve, sndreserve; 170 1.1 dholland int pktscale; 171 1.1 dholland struct sockaddr *saddr; 172 1.1 dholland struct ucred *origcred; 173 1.1 dholland CLIENT *client; 174 1.1 dholland struct netconfig *nconf; 175 1.1 dholland struct socket *so; 176 1.1 dholland int one = 1, retries, error = 0; 177 1.1 dholland struct thread *td = curthread; 178 1.1 dholland SVCXPRT *xprt; 179 1.1 dholland struct timeval timo; 180 1.1 dholland 181 1.1 dholland /* 182 1.1 dholland * We need to establish the socket using the credentials of 183 1.1 dholland * the mountpoint. Some parts of this process (such as 184 1.3 andvar * sobind() and soconnect()) will use the current thread's 185 1.1 dholland * credential instead of the socket credential. To work 186 1.1 dholland * around this, temporarily change the current thread's 187 1.1 dholland * credential to that of the mountpoint. 188 1.1 dholland * 189 1.1 dholland * XXX: It would be better to explicitly pass the correct 190 1.1 dholland * credential to sobind() and soconnect(). 191 1.1 dholland */ 192 1.1 dholland origcred = td->td_ucred; 193 1.1 dholland 194 1.1 dholland /* 195 1.1 dholland * Use the credential in nr_cred, if not NULL. 196 1.1 dholland */ 197 1.1 dholland if (nrp->nr_cred != NULL) 198 1.1 dholland td->td_ucred = nrp->nr_cred; 199 1.1 dholland else 200 1.1 dholland td->td_ucred = cred; 201 1.1 dholland saddr = nrp->nr_nam; 202 1.1 dholland 203 1.1 dholland if (saddr->sa_family == AF_INET) 204 1.1 dholland if (nrp->nr_sotype == SOCK_DGRAM) 205 1.1 dholland nconf = getnetconfigent("udp"); 206 1.1 dholland else 207 1.1 dholland nconf = getnetconfigent("tcp"); 208 1.1 dholland else 209 1.1 dholland if (nrp->nr_sotype == SOCK_DGRAM) 210 1.1 dholland nconf = getnetconfigent("udp6"); 211 1.1 dholland else 212 1.1 dholland nconf = getnetconfigent("tcp6"); 213 1.1 dholland 214 1.1 dholland pktscale = nfs_bufpackets; 215 1.1 dholland if (pktscale < 2) 216 1.1 dholland pktscale = 2; 217 1.1 dholland if (pktscale > 64) 218 1.1 dholland pktscale = 64; 219 1.1 dholland /* 220 1.1 dholland * soreserve() can fail if sb_max is too small, so shrink pktscale 221 1.1 dholland * and try again if there is an error. 222 1.1 dholland * Print a log message suggesting increasing sb_max. 223 1.1 dholland * Creating a socket and doing this is necessary since, if the 224 1.1 dholland * reservation sizes are too large and will make soreserve() fail, 225 1.1 dholland * the connection will work until a large send is attempted and 226 1.1 dholland * then it will loop in the krpc code. 227 1.1 dholland */ 228 1.1 dholland so = NULL; 229 1.1 dholland saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *); 230 1.1 dholland error = socreate(saddr->sa_family, &so, nrp->nr_sotype, 231 1.1 dholland nrp->nr_soproto, td->td_ucred, td); 232 1.1 dholland if (error) { 233 1.1 dholland td->td_ucred = origcred; 234 1.1 dholland goto out; 235 1.1 dholland } 236 1.1 dholland do { 237 1.1 dholland if (error != 0 && pktscale > 2) 238 1.1 dholland pktscale--; 239 1.1 dholland if (nrp->nr_sotype == SOCK_DGRAM) { 240 1.1 dholland if (nmp != NULL) { 241 1.1 dholland sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) * 242 1.1 dholland pktscale; 243 1.1 dholland rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) * 244 1.1 dholland pktscale; 245 1.1 dholland } else { 246 1.1 dholland sndreserve = rcvreserve = 1024 * pktscale; 247 1.1 dholland } 248 1.1 dholland } else { 249 1.1 dholland if (nrp->nr_sotype != SOCK_STREAM) 250 1.1 dholland panic("nfscon sotype"); 251 1.1 dholland if (nmp != NULL) { 252 1.1 dholland sndreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR + 253 1.1 dholland sizeof (u_int32_t)) * pktscale; 254 1.1 dholland rcvreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR + 255 1.1 dholland sizeof (u_int32_t)) * pktscale; 256 1.1 dholland } else { 257 1.1 dholland sndreserve = rcvreserve = 1024 * pktscale; 258 1.1 dholland } 259 1.1 dholland } 260 1.1 dholland error = soreserve(so, sndreserve, rcvreserve); 261 1.1 dholland } while (error != 0 && pktscale > 2); 262 1.1 dholland soclose(so); 263 1.1 dholland if (error) { 264 1.1 dholland td->td_ucred = origcred; 265 1.1 dholland goto out; 266 1.1 dholland } 267 1.1 dholland 268 1.1 dholland client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog, 269 1.1 dholland nrp->nr_vers, sndreserve, rcvreserve); 270 1.2 pgoyette CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq"); 271 1.1 dholland if (nmp != NULL) { 272 1.1 dholland if ((nmp->nm_flag & NFSMNT_INT)) 273 1.1 dholland CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one); 274 1.1 dholland if ((nmp->nm_flag & NFSMNT_RESVPORT)) 275 1.1 dholland CLNT_CONTROL(client, CLSET_PRIVPORT, &one); 276 1.1 dholland if (NFSHASSOFT(nmp)) { 277 1.1 dholland if (nmp->nm_sotype == SOCK_DGRAM) 278 1.1 dholland /* 279 1.1 dholland * For UDP, the large timeout for a reconnect 280 1.1 dholland * will be set to "nm_retry * nm_timeo / 2", so 281 1.1 dholland * we only want to do 2 reconnect timeout 282 1.1 dholland * retries. 283 1.1 dholland */ 284 1.1 dholland retries = 2; 285 1.1 dholland else 286 1.1 dholland retries = nmp->nm_retry; 287 1.1 dholland } else 288 1.1 dholland retries = INT_MAX; 289 1.1 dholland if (NFSHASNFSV4N(nmp)) { 290 1.1 dholland /* 291 1.1 dholland * Make sure the nfscbd_pool doesn't get destroyed 292 1.1 dholland * while doing this. 293 1.1 dholland */ 294 1.1 dholland NFSD_LOCK(); 295 1.1 dholland if (nfs_numnfscbd > 0) { 296 1.1 dholland nfs_numnfscbd++; 297 1.1 dholland NFSD_UNLOCK(); 298 1.1 dholland xprt = svc_vc_create_backchannel(nfscbd_pool); 299 1.1 dholland CLNT_CONTROL(client, CLSET_BACKCHANNEL, xprt); 300 1.1 dholland NFSD_LOCK(); 301 1.1 dholland nfs_numnfscbd--; 302 1.1 dholland if (nfs_numnfscbd == 0) 303 1.1 dholland wakeup(&nfs_numnfscbd); 304 1.1 dholland } 305 1.1 dholland NFSD_UNLOCK(); 306 1.1 dholland } 307 1.1 dholland } else { 308 1.1 dholland /* 309 1.1 dholland * Three cases: 310 1.1 dholland * - Null RPC callback to client 311 1.1 dholland * - Non-Null RPC callback to client, wait a little longer 312 1.1 dholland * - upcalls to nfsuserd and gssd (clp == NULL) 313 1.1 dholland */ 314 1.1 dholland if (callback_retry_mult == 0) { 315 1.1 dholland retries = NFSV4_UPCALLRETRY; 316 1.1 dholland CLNT_CONTROL(client, CLSET_PRIVPORT, &one); 317 1.1 dholland } else { 318 1.1 dholland retries = NFSV4_CALLBACKRETRY * callback_retry_mult; 319 1.1 dholland } 320 1.1 dholland } 321 1.1 dholland CLNT_CONTROL(client, CLSET_RETRIES, &retries); 322 1.1 dholland 323 1.1 dholland if (nmp != NULL) { 324 1.1 dholland /* 325 1.1 dholland * For UDP, there are 2 timeouts: 326 1.1 dholland * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer 327 1.1 dholland * that does a retransmit of an RPC request using the same 328 1.1 dholland * socket and xid. This is what you normally want to do, 329 1.1 dholland * since NFS servers depend on "same xid" for their 330 1.1 dholland * Duplicate Request Cache. 331 1.1 dholland * - timeout specified in CLNT_CALL_MBUF(), which specifies when 332 1.1 dholland * retransmits on the same socket should fail and a fresh 333 1.1 dholland * socket created. Each of these timeouts counts as one 334 1.1 dholland * CLSET_RETRIES as set above. 335 1.1 dholland * Set the initial retransmit timeout for UDP. This timeout 336 1.1 dholland * doesn't exist for TCP and the following call just fails, 337 1.1 dholland * which is ok. 338 1.1 dholland */ 339 1.1 dholland timo.tv_sec = nmp->nm_timeo / NFS_HZ; 340 1.1 dholland timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ; 341 1.1 dholland CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo); 342 1.1 dholland } 343 1.1 dholland 344 1.1 dholland mtx_lock(&nrp->nr_mtx); 345 1.1 dholland if (nrp->nr_client != NULL) { 346 1.2 pgoyette mtx_unlock(&nrp->nr_mtx); 347 1.1 dholland /* 348 1.1 dholland * Someone else already connected. 349 1.1 dholland */ 350 1.1 dholland CLNT_RELEASE(client); 351 1.1 dholland } else { 352 1.1 dholland nrp->nr_client = client; 353 1.2 pgoyette /* 354 1.2 pgoyette * Protocols that do not require connections may be optionally 355 1.2 pgoyette * left unconnected for servers that reply from a port other 356 1.2 pgoyette * than NFS_PORT. 357 1.2 pgoyette */ 358 1.2 pgoyette if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) { 359 1.2 pgoyette mtx_unlock(&nrp->nr_mtx); 360 1.2 pgoyette CLNT_CONTROL(client, CLSET_CONNECT, &one); 361 1.2 pgoyette } else 362 1.2 pgoyette mtx_unlock(&nrp->nr_mtx); 363 1.1 dholland } 364 1.1 dholland 365 1.1 dholland 366 1.1 dholland /* Restore current thread's credentials. */ 367 1.1 dholland td->td_ucred = origcred; 368 1.1 dholland 369 1.1 dholland out: 370 1.1 dholland NFSEXITCODE(error); 371 1.1 dholland return (error); 372 1.1 dholland } 373 1.1 dholland 374 1.1 dholland /* 375 1.1 dholland * NFS disconnect. Clean up and unlink. 376 1.1 dholland */ 377 1.1 dholland void 378 1.1 dholland newnfs_disconnect(struct nfssockreq *nrp) 379 1.1 dholland { 380 1.1 dholland CLIENT *client; 381 1.1 dholland 382 1.1 dholland mtx_lock(&nrp->nr_mtx); 383 1.1 dholland if (nrp->nr_client != NULL) { 384 1.1 dholland client = nrp->nr_client; 385 1.1 dholland nrp->nr_client = NULL; 386 1.1 dholland mtx_unlock(&nrp->nr_mtx); 387 1.1 dholland rpc_gss_secpurge_call(client); 388 1.1 dholland CLNT_CLOSE(client); 389 1.1 dholland CLNT_RELEASE(client); 390 1.1 dholland } else { 391 1.1 dholland mtx_unlock(&nrp->nr_mtx); 392 1.1 dholland } 393 1.1 dholland } 394 1.1 dholland 395 1.1 dholland static AUTH * 396 1.1 dholland nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, 397 1.1 dholland char *srv_principal, gss_OID mech_oid, struct ucred *cred) 398 1.1 dholland { 399 1.1 dholland rpc_gss_service_t svc; 400 1.1 dholland AUTH *auth; 401 1.1 dholland 402 1.1 dholland switch (secflavour) { 403 1.1 dholland case RPCSEC_GSS_KRB5: 404 1.1 dholland case RPCSEC_GSS_KRB5I: 405 1.1 dholland case RPCSEC_GSS_KRB5P: 406 1.1 dholland if (!mech_oid) { 407 1.1 dholland if (!rpc_gss_mech_to_oid_call("kerberosv5", &mech_oid)) 408 1.1 dholland return (NULL); 409 1.1 dholland } 410 1.1 dholland if (secflavour == RPCSEC_GSS_KRB5) 411 1.1 dholland svc = rpc_gss_svc_none; 412 1.1 dholland else if (secflavour == RPCSEC_GSS_KRB5I) 413 1.1 dholland svc = rpc_gss_svc_integrity; 414 1.1 dholland else 415 1.1 dholland svc = rpc_gss_svc_privacy; 416 1.1 dholland 417 1.1 dholland if (clnt_principal == NULL) 418 1.1 dholland auth = rpc_gss_secfind_call(nrp->nr_client, cred, 419 1.1 dholland srv_principal, mech_oid, svc); 420 1.1 dholland else { 421 1.1 dholland auth = rpc_gss_seccreate_call(nrp->nr_client, cred, 422 1.1 dholland clnt_principal, srv_principal, "kerberosv5", 423 1.1 dholland svc, NULL, NULL, NULL); 424 1.1 dholland return (auth); 425 1.1 dholland } 426 1.1 dholland if (auth != NULL) 427 1.1 dholland return (auth); 428 1.1 dholland /* fallthrough */ 429 1.1 dholland case AUTH_SYS: 430 1.1 dholland default: 431 1.1 dholland return (authunix_create(cred)); 432 1.1 dholland 433 1.1 dholland } 434 1.1 dholland } 435 1.1 dholland 436 1.1 dholland /* 437 1.1 dholland * Callback from the RPC code to generate up/down notifications. 438 1.1 dholland */ 439 1.1 dholland 440 1.1 dholland struct nfs_feedback_arg { 441 1.1 dholland struct nfsmount *nf_mount; 442 1.1 dholland int nf_lastmsg; /* last tprintf */ 443 1.1 dholland int nf_tprintfmsg; 444 1.1 dholland struct thread *nf_td; 445 1.1 dholland }; 446 1.1 dholland 447 1.1 dholland static void 448 1.1 dholland nfs_feedback(int type, int proc, void *arg) 449 1.1 dholland { 450 1.1 dholland struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg; 451 1.1 dholland struct nfsmount *nmp = nf->nf_mount; 452 1.1 dholland time_t now; 453 1.1 dholland 454 1.1 dholland switch (type) { 455 1.1 dholland case FEEDBACK_REXMIT2: 456 1.1 dholland case FEEDBACK_RECONNECT: 457 1.1 dholland now = NFSD_MONOSEC; 458 1.1 dholland if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now) { 459 1.1 dholland nfs_down(nmp, nf->nf_td, 460 1.1 dholland "not responding", 0, NFSSTA_TIMEO); 461 1.1 dholland nf->nf_tprintfmsg = TRUE; 462 1.1 dholland nf->nf_lastmsg = now; 463 1.1 dholland } 464 1.1 dholland break; 465 1.1 dholland 466 1.1 dholland case FEEDBACK_OK: 467 1.1 dholland nfs_up(nf->nf_mount, nf->nf_td, 468 1.1 dholland "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg); 469 1.1 dholland break; 470 1.1 dholland } 471 1.1 dholland } 472 1.1 dholland 473 1.1 dholland /* 474 1.1 dholland * newnfs_request - goes something like this 475 1.1 dholland * - does the rpc by calling the krpc layer 476 1.1 dholland * - break down rpc header and return with nfs reply 477 1.1 dholland * nb: always frees up nd_mreq mbuf list 478 1.1 dholland */ 479 1.1 dholland int 480 1.1 dholland newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, 481 1.1 dholland struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp, 482 1.1 dholland struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers, 483 1.1 dholland u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *sep) 484 1.1 dholland { 485 1.1 dholland u_int32_t retseq, retval, *tl; 486 1.1 dholland time_t waituntil; 487 1.1 dholland int i = 0, j = 0, opcnt, set_sigset = 0, slot; 488 1.1 dholland int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS; 489 1.1 dholland int freeslot, timeo; 490 1.1 dholland u_int16_t procnum; 491 1.1 dholland u_int trylater_delay = 1; 492 1.1 dholland struct nfs_feedback_arg nf; 493 1.1 dholland struct timeval timo; 494 1.1 dholland AUTH *auth; 495 1.1 dholland struct rpc_callextra ext; 496 1.1 dholland enum clnt_stat stat; 497 1.1 dholland struct nfsreq *rep = NULL; 498 1.1 dholland char *srv_principal = NULL, *clnt_principal = NULL; 499 1.1 dholland sigset_t oldset; 500 1.1 dholland struct ucred *authcred; 501 1.1 dholland 502 1.1 dholland if (xidp != NULL) 503 1.1 dholland *xidp = 0; 504 1.1 dholland /* Reject requests while attempting a forced unmount. */ 505 1.1 dholland if (nmp != NULL && (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)) { 506 1.1 dholland m_freem(nd->nd_mreq); 507 1.1 dholland return (ESTALE); 508 1.1 dholland } 509 1.1 dholland 510 1.1 dholland /* 511 1.1 dholland * Set authcred, which is used to acquire RPC credentials to 512 1.1 dholland * the cred argument, by default. The crhold() should not be 513 1.1 dholland * necessary, but will ensure that some future code change 514 1.1 dholland * doesn't result in the credential being free'd prematurely. 515 1.1 dholland */ 516 1.1 dholland authcred = crhold(cred); 517 1.1 dholland 518 1.1 dholland /* For client side interruptible mounts, mask off the signals. */ 519 1.1 dholland if (nmp != NULL && td != NULL && NFSHASINT(nmp)) { 520 1.1 dholland newnfs_set_sigmask(td, &oldset); 521 1.1 dholland set_sigset = 1; 522 1.1 dholland } 523 1.1 dholland 524 1.1 dholland /* 525 1.1 dholland * XXX if not already connected call nfs_connect now. Longer 526 1.1 dholland * term, change nfs_mount to call nfs_connect unconditionally 527 1.1 dholland * and let clnt_reconnect_create handle reconnects. 528 1.1 dholland */ 529 1.1 dholland if (nrp->nr_client == NULL) 530 1.1 dholland newnfs_connect(nmp, nrp, cred, td, 0); 531 1.1 dholland 532 1.1 dholland /* 533 1.1 dholland * For a client side mount, nmp is != NULL and clp == NULL. For 534 1.1 dholland * server calls (callbacks or upcalls), nmp == NULL. 535 1.1 dholland */ 536 1.1 dholland if (clp != NULL) { 537 1.1 dholland NFSLOCKSTATE(); 538 1.1 dholland if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) { 539 1.1 dholland secflavour = RPCSEC_GSS_KRB5; 540 1.1 dholland if (nd->nd_procnum != NFSPROC_NULL) { 541 1.1 dholland if (clp->lc_flags & LCL_GSSINTEGRITY) 542 1.1 dholland secflavour = RPCSEC_GSS_KRB5I; 543 1.1 dholland else if (clp->lc_flags & LCL_GSSPRIVACY) 544 1.1 dholland secflavour = RPCSEC_GSS_KRB5P; 545 1.1 dholland } 546 1.1 dholland } 547 1.1 dholland NFSUNLOCKSTATE(); 548 1.1 dholland } else if (nmp != NULL && NFSHASKERB(nmp) && 549 1.1 dholland nd->nd_procnum != NFSPROC_NULL) { 550 1.1 dholland if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0) 551 1.1 dholland nd->nd_flag |= ND_USEGSSNAME; 552 1.1 dholland if ((nd->nd_flag & ND_USEGSSNAME) != 0) { 553 1.1 dholland /* 554 1.1 dholland * If there is a client side host based credential, 555 1.1 dholland * use that, otherwise use the system uid, if set. 556 1.1 dholland * The system uid is in the nmp->nm_sockreq.nr_cred 557 1.1 dholland * credentials. 558 1.1 dholland */ 559 1.1 dholland if (nmp->nm_krbnamelen > 0) { 560 1.1 dholland usegssname = 1; 561 1.1 dholland clnt_principal = nmp->nm_krbname; 562 1.1 dholland } else if (nmp->nm_uid != (uid_t)-1) { 563 1.1 dholland KASSERT(nmp->nm_sockreq.nr_cred != NULL, 564 1.1 dholland ("newnfs_request: NULL nr_cred")); 565 1.1 dholland crfree(authcred); 566 1.1 dholland authcred = crhold(nmp->nm_sockreq.nr_cred); 567 1.1 dholland } 568 1.1 dholland } else if (nmp->nm_krbnamelen == 0 && 569 1.1 dholland nmp->nm_uid != (uid_t)-1 && cred->cr_uid == (uid_t)0) { 570 1.1 dholland /* 571 1.1 dholland * If there is no host based principal name and 572 1.1 dholland * the system uid is set and this is root, use the 573 1.1 dholland * system uid, since root won't have user 574 1.1 dholland * credentials in a credentials cache file. 575 1.1 dholland * The system uid is in the nmp->nm_sockreq.nr_cred 576 1.1 dholland * credentials. 577 1.1 dholland */ 578 1.1 dholland KASSERT(nmp->nm_sockreq.nr_cred != NULL, 579 1.1 dholland ("newnfs_request: NULL nr_cred")); 580 1.1 dholland crfree(authcred); 581 1.1 dholland authcred = crhold(nmp->nm_sockreq.nr_cred); 582 1.1 dholland } 583 1.1 dholland if (NFSHASINTEGRITY(nmp)) 584 1.1 dholland secflavour = RPCSEC_GSS_KRB5I; 585 1.1 dholland else if (NFSHASPRIVACY(nmp)) 586 1.1 dholland secflavour = RPCSEC_GSS_KRB5P; 587 1.1 dholland else 588 1.1 dholland secflavour = RPCSEC_GSS_KRB5; 589 1.1 dholland srv_principal = NFSMNT_SRVKRBNAME(nmp); 590 1.1 dholland } else if (nmp != NULL && !NFSHASKERB(nmp) && 591 1.1 dholland nd->nd_procnum != NFSPROC_NULL && 592 1.1 dholland (nd->nd_flag & ND_USEGSSNAME) != 0) { 593 1.1 dholland /* 594 1.1 dholland * Use the uid that did the mount when the RPC is doing 595 1.1 dholland * NFSv4 system operations, as indicated by the 596 1.1 dholland * ND_USEGSSNAME flag, for the AUTH_SYS case. 597 1.1 dholland * The credentials in nm_sockreq.nr_cred were used for the 598 1.1 dholland * mount. 599 1.1 dholland */ 600 1.1 dholland KASSERT(nmp->nm_sockreq.nr_cred != NULL, 601 1.1 dholland ("newnfs_request: NULL nr_cred")); 602 1.1 dholland crfree(authcred); 603 1.1 dholland authcred = crhold(nmp->nm_sockreq.nr_cred); 604 1.1 dholland } 605 1.1 dholland 606 1.1 dholland if (nmp != NULL) { 607 1.1 dholland bzero(&nf, sizeof(struct nfs_feedback_arg)); 608 1.1 dholland nf.nf_mount = nmp; 609 1.1 dholland nf.nf_td = td; 610 1.1 dholland nf.nf_lastmsg = NFSD_MONOSEC - 611 1.1 dholland ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay)); 612 1.1 dholland } 613 1.1 dholland 614 1.1 dholland if (nd->nd_procnum == NFSPROC_NULL) 615 1.1 dholland auth = authnone_create(); 616 1.1 dholland else if (usegssname) { 617 1.1 dholland /* 618 1.1 dholland * For this case, the authenticator is held in the 619 1.1 dholland * nfssockreq structure, so don't release the reference count 620 1.1 dholland * held on it. --> Don't AUTH_DESTROY() it in this function. 621 1.1 dholland */ 622 1.1 dholland if (nrp->nr_auth == NULL) 623 1.1 dholland nrp->nr_auth = nfs_getauth(nrp, secflavour, 624 1.1 dholland clnt_principal, srv_principal, NULL, authcred); 625 1.1 dholland else 626 1.1 dholland rpc_gss_refresh_auth_call(nrp->nr_auth); 627 1.1 dholland auth = nrp->nr_auth; 628 1.1 dholland } else 629 1.1 dholland auth = nfs_getauth(nrp, secflavour, NULL, 630 1.1 dholland srv_principal, NULL, authcred); 631 1.1 dholland crfree(authcred); 632 1.1 dholland if (auth == NULL) { 633 1.1 dholland m_freem(nd->nd_mreq); 634 1.1 dholland if (set_sigset) 635 1.1 dholland newnfs_restore_sigmask(td, &oldset); 636 1.1 dholland return (EACCES); 637 1.1 dholland } 638 1.1 dholland bzero(&ext, sizeof(ext)); 639 1.1 dholland ext.rc_auth = auth; 640 1.1 dholland if (nmp != NULL) { 641 1.1 dholland ext.rc_feedback = nfs_feedback; 642 1.1 dholland ext.rc_feedback_arg = &nf; 643 1.1 dholland } 644 1.1 dholland 645 1.1 dholland procnum = nd->nd_procnum; 646 1.1 dholland if ((nd->nd_flag & ND_NFSV4) && 647 1.1 dholland nd->nd_procnum != NFSPROC_NULL && 648 1.1 dholland nd->nd_procnum != NFSV4PROC_CBCOMPOUND) 649 1.1 dholland procnum = NFSV4PROC_COMPOUND; 650 1.1 dholland 651 1.1 dholland if (nmp != NULL) { 652 1.2 pgoyette NFSINCRGLOBAL(nfsstatsv1.rpcrequests); 653 1.1 dholland 654 1.1 dholland /* Map the procnum to the old NFSv2 one, as required. */ 655 1.1 dholland if ((nd->nd_flag & ND_NFSV2) != 0) { 656 1.1 dholland if (nd->nd_procnum < NFS_V3NPROCS) 657 1.1 dholland procnum = nfsv2_procid[nd->nd_procnum]; 658 1.1 dholland else 659 1.1 dholland procnum = NFSV2PROC_NOOP; 660 1.1 dholland } 661 1.1 dholland 662 1.1 dholland /* 663 1.1 dholland * Now only used for the R_DONTRECOVER case, but until that is 664 1.1 dholland * supported within the krpc code, I need to keep a queue of 665 1.1 dholland * outstanding RPCs for nfsv4 client requests. 666 1.1 dholland */ 667 1.1 dholland if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND) 668 1.1 dholland MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), 669 1.1 dholland M_NFSDREQ, M_WAITOK); 670 1.1 dholland #ifdef KDTRACE_HOOKS 671 1.1 dholland if (dtrace_nfscl_nfs234_start_probe != NULL) { 672 1.1 dholland uint32_t probe_id; 673 1.1 dholland int probe_procnum; 674 1.1 dholland 675 1.1 dholland if (nd->nd_flag & ND_NFSV4) { 676 1.1 dholland probe_id = 677 1.1 dholland nfscl_nfs4_start_probes[nd->nd_procnum]; 678 1.1 dholland probe_procnum = nd->nd_procnum; 679 1.1 dholland } else if (nd->nd_flag & ND_NFSV3) { 680 1.1 dholland probe_id = nfscl_nfs3_start_probes[procnum]; 681 1.1 dholland probe_procnum = procnum; 682 1.1 dholland } else { 683 1.1 dholland probe_id = 684 1.1 dholland nfscl_nfs2_start_probes[nd->nd_procnum]; 685 1.1 dholland probe_procnum = procnum; 686 1.1 dholland } 687 1.1 dholland if (probe_id != 0) 688 1.1 dholland (dtrace_nfscl_nfs234_start_probe) 689 1.1 dholland (probe_id, vp, nd->nd_mreq, cred, 690 1.1 dholland probe_procnum); 691 1.1 dholland } 692 1.1 dholland #endif 693 1.1 dholland } 694 1.1 dholland trycnt = 0; 695 1.1 dholland freeslot = -1; /* Set to slot that needs to be free'd */ 696 1.1 dholland tryagain: 697 1.1 dholland slot = -1; /* Slot that needs a sequence# increment. */ 698 1.1 dholland /* 699 1.1 dholland * This timeout specifies when a new socket should be created, 700 1.1 dholland * along with new xid values. For UDP, this should be done 701 1.1 dholland * infrequently, since retransmits of RPC requests should normally 702 1.1 dholland * use the same xid. 703 1.1 dholland */ 704 1.1 dholland if (nmp == NULL) { 705 1.1 dholland timo.tv_usec = 0; 706 1.1 dholland if (clp == NULL) 707 1.1 dholland timo.tv_sec = NFSV4_UPCALLTIMEO; 708 1.1 dholland else 709 1.1 dholland timo.tv_sec = NFSV4_CALLBACKTIMEO; 710 1.1 dholland } else { 711 1.1 dholland if (nrp->nr_sotype != SOCK_DGRAM) { 712 1.1 dholland timo.tv_usec = 0; 713 1.1 dholland if ((nmp->nm_flag & NFSMNT_NFSV4)) 714 1.1 dholland timo.tv_sec = INT_MAX; 715 1.1 dholland else 716 1.1 dholland timo.tv_sec = NFS_TCPTIMEO; 717 1.1 dholland } else { 718 1.1 dholland if (NFSHASSOFT(nmp)) { 719 1.1 dholland /* 720 1.1 dholland * CLSET_RETRIES is set to 2, so this should be 721 1.1 dholland * half of the total timeout required. 722 1.1 dholland */ 723 1.1 dholland timeo = nmp->nm_retry * nmp->nm_timeo / 2; 724 1.1 dholland if (timeo < 1) 725 1.1 dholland timeo = 1; 726 1.1 dholland timo.tv_sec = timeo / NFS_HZ; 727 1.1 dholland timo.tv_usec = (timeo % NFS_HZ) * 1000000 / 728 1.1 dholland NFS_HZ; 729 1.1 dholland } else { 730 1.1 dholland /* For UDP hard mounts, use a large value. */ 731 1.1 dholland timo.tv_sec = NFS_MAXTIMEO / NFS_HZ; 732 1.1 dholland timo.tv_usec = 0; 733 1.1 dholland } 734 1.1 dholland } 735 1.1 dholland 736 1.1 dholland if (rep != NULL) { 737 1.1 dholland rep->r_flags = 0; 738 1.1 dholland rep->r_nmp = nmp; 739 1.1 dholland /* 740 1.1 dholland * Chain request into list of outstanding requests. 741 1.1 dholland */ 742 1.1 dholland NFSLOCKREQ(); 743 1.1 dholland TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain); 744 1.1 dholland NFSUNLOCKREQ(); 745 1.1 dholland } 746 1.1 dholland } 747 1.1 dholland 748 1.1 dholland nd->nd_mrep = NULL; 749 1.2 pgoyette if (clp != NULL && sep != NULL) 750 1.2 pgoyette stat = clnt_bck_call(nrp->nr_client, &ext, procnum, 751 1.2 pgoyette nd->nd_mreq, &nd->nd_mrep, timo, sep->nfsess_xprt); 752 1.2 pgoyette else 753 1.2 pgoyette stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, 754 1.2 pgoyette nd->nd_mreq, &nd->nd_mrep, timo); 755 1.1 dholland 756 1.1 dholland if (rep != NULL) { 757 1.1 dholland /* 758 1.1 dholland * RPC done, unlink the request. 759 1.1 dholland */ 760 1.1 dholland NFSLOCKREQ(); 761 1.1 dholland TAILQ_REMOVE(&nfsd_reqq, rep, r_chain); 762 1.1 dholland NFSUNLOCKREQ(); 763 1.1 dholland } 764 1.1 dholland 765 1.1 dholland /* 766 1.1 dholland * If there was a successful reply and a tprintf msg. 767 1.1 dholland * tprintf a response. 768 1.1 dholland */ 769 1.1 dholland if (stat == RPC_SUCCESS) { 770 1.1 dholland error = 0; 771 1.1 dholland } else if (stat == RPC_TIMEDOUT) { 772 1.2 pgoyette NFSINCRGLOBAL(nfsstatsv1.rpctimeouts); 773 1.1 dholland error = ETIMEDOUT; 774 1.1 dholland } else if (stat == RPC_VERSMISMATCH) { 775 1.2 pgoyette NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); 776 1.1 dholland error = EOPNOTSUPP; 777 1.1 dholland } else if (stat == RPC_PROGVERSMISMATCH) { 778 1.2 pgoyette NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); 779 1.1 dholland error = EPROTONOSUPPORT; 780 1.1 dholland } else if (stat == RPC_INTR) { 781 1.1 dholland error = EINTR; 782 1.1 dholland } else { 783 1.2 pgoyette NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); 784 1.1 dholland error = EACCES; 785 1.1 dholland } 786 1.1 dholland if (error) { 787 1.1 dholland m_freem(nd->nd_mreq); 788 1.1 dholland if (usegssname == 0) 789 1.1 dholland AUTH_DESTROY(auth); 790 1.1 dholland if (rep != NULL) 791 1.1 dholland FREE((caddr_t)rep, M_NFSDREQ); 792 1.1 dholland if (set_sigset) 793 1.1 dholland newnfs_restore_sigmask(td, &oldset); 794 1.1 dholland return (error); 795 1.1 dholland } 796 1.1 dholland 797 1.1 dholland KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n")); 798 1.1 dholland 799 1.1 dholland /* 800 1.1 dholland * Search for any mbufs that are not a multiple of 4 bytes long 801 1.1 dholland * or with m_data not longword aligned. 802 1.1 dholland * These could cause pointer alignment problems, so copy them to 803 1.1 dholland * well aligned mbufs. 804 1.1 dholland */ 805 1.1 dholland newnfs_realign(&nd->nd_mrep, M_WAITOK); 806 1.1 dholland nd->nd_md = nd->nd_mrep; 807 1.1 dholland nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 808 1.1 dholland nd->nd_repstat = 0; 809 1.2 pgoyette if (nd->nd_procnum != NFSPROC_NULL && 810 1.2 pgoyette nd->nd_procnum != NFSV4PROC_CBNULL) { 811 1.1 dholland /* If sep == NULL, set it to the default in nmp. */ 812 1.1 dholland if (sep == NULL && nmp != NULL) 813 1.1 dholland sep = NFSMNT_MDSSESSION(nmp); 814 1.1 dholland /* 815 1.1 dholland * and now the actual NFS xdr. 816 1.1 dholland */ 817 1.1 dholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 818 1.1 dholland nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl); 819 1.1 dholland if (nd->nd_repstat >= 10000) 820 1.1 dholland NFSCL_DEBUG(1, "proc=%d reps=%d\n", (int)nd->nd_procnum, 821 1.1 dholland (int)nd->nd_repstat); 822 1.1 dholland 823 1.1 dholland /* 824 1.1 dholland * Get rid of the tag, return count and SEQUENCE result for 825 1.1 dholland * NFSv4. 826 1.1 dholland */ 827 1.1 dholland if ((nd->nd_flag & ND_NFSV4) != 0) { 828 1.1 dholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 829 1.1 dholland i = fxdr_unsigned(int, *tl); 830 1.1 dholland error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 831 1.1 dholland if (error) 832 1.1 dholland goto nfsmout; 833 1.1 dholland NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 834 1.1 dholland opcnt = fxdr_unsigned(int, *tl++); 835 1.1 dholland i = fxdr_unsigned(int, *tl++); 836 1.1 dholland j = fxdr_unsigned(int, *tl); 837 1.1 dholland if (j >= 10000) 838 1.1 dholland NFSCL_DEBUG(1, "fop=%d fst=%d\n", i, j); 839 1.1 dholland /* 840 1.1 dholland * If the first op is Sequence, free up the slot. 841 1.1 dholland */ 842 1.2 pgoyette if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) || 843 1.2 pgoyette (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0)) 844 1.1 dholland NFSCL_DEBUG(1, "failed seq=%d\n", j); 845 1.2 pgoyette if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) || 846 1.2 pgoyette (clp != NULL && i == NFSV4OP_CBSEQUENCE && j == 0) 847 1.2 pgoyette ) { 848 1.2 pgoyette if (i == NFSV4OP_SEQUENCE) 849 1.2 pgoyette NFSM_DISSECT(tl, uint32_t *, 850 1.2 pgoyette NFSX_V4SESSIONID + 851 1.2 pgoyette 5 * NFSX_UNSIGNED); 852 1.2 pgoyette else 853 1.2 pgoyette NFSM_DISSECT(tl, uint32_t *, 854 1.2 pgoyette NFSX_V4SESSIONID + 855 1.2 pgoyette 4 * NFSX_UNSIGNED); 856 1.1 dholland mtx_lock(&sep->nfsess_mtx); 857 1.1 dholland tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 858 1.1 dholland retseq = fxdr_unsigned(uint32_t, *tl++); 859 1.1 dholland slot = fxdr_unsigned(int, *tl++); 860 1.1 dholland freeslot = slot; 861 1.1 dholland if (retseq != sep->nfsess_slotseq[slot]) 862 1.1 dholland printf("retseq diff 0x%x\n", retseq); 863 1.1 dholland retval = fxdr_unsigned(uint32_t, *++tl); 864 1.1 dholland if ((retval + 1) < sep->nfsess_foreslots) 865 1.1 dholland sep->nfsess_foreslots = (retval + 1); 866 1.1 dholland else if ((retval + 1) > sep->nfsess_foreslots) 867 1.1 dholland sep->nfsess_foreslots = (retval < 64) ? 868 1.1 dholland (retval + 1) : 64; 869 1.1 dholland mtx_unlock(&sep->nfsess_mtx); 870 1.1 dholland 871 1.1 dholland /* Grab the op and status for the next one. */ 872 1.1 dholland if (opcnt > 1) { 873 1.1 dholland NFSM_DISSECT(tl, uint32_t *, 874 1.1 dholland 2 * NFSX_UNSIGNED); 875 1.1 dholland i = fxdr_unsigned(int, *tl++); 876 1.1 dholland j = fxdr_unsigned(int, *tl); 877 1.1 dholland } 878 1.1 dholland } 879 1.1 dholland } 880 1.1 dholland if (nd->nd_repstat != 0) { 881 1.1 dholland if (((nd->nd_repstat == NFSERR_DELAY || 882 1.1 dholland nd->nd_repstat == NFSERR_GRACE) && 883 1.1 dholland (nd->nd_flag & ND_NFSV4) && 884 1.1 dholland nd->nd_procnum != NFSPROC_DELEGRETURN && 885 1.1 dholland nd->nd_procnum != NFSPROC_SETATTR && 886 1.1 dholland nd->nd_procnum != NFSPROC_READ && 887 1.1 dholland nd->nd_procnum != NFSPROC_READDS && 888 1.1 dholland nd->nd_procnum != NFSPROC_WRITE && 889 1.1 dholland nd->nd_procnum != NFSPROC_WRITEDS && 890 1.1 dholland nd->nd_procnum != NFSPROC_OPEN && 891 1.1 dholland nd->nd_procnum != NFSPROC_CREATE && 892 1.1 dholland nd->nd_procnum != NFSPROC_OPENCONFIRM && 893 1.1 dholland nd->nd_procnum != NFSPROC_OPENDOWNGRADE && 894 1.1 dholland nd->nd_procnum != NFSPROC_CLOSE && 895 1.1 dholland nd->nd_procnum != NFSPROC_LOCK && 896 1.1 dholland nd->nd_procnum != NFSPROC_LOCKU) || 897 1.1 dholland (nd->nd_repstat == NFSERR_DELAY && 898 1.1 dholland (nd->nd_flag & ND_NFSV4) == 0) || 899 1.1 dholland nd->nd_repstat == NFSERR_RESOURCE) { 900 1.1 dholland if (trylater_delay > NFS_TRYLATERDEL) 901 1.1 dholland trylater_delay = NFS_TRYLATERDEL; 902 1.1 dholland waituntil = NFSD_MONOSEC + trylater_delay; 903 1.1 dholland while (NFSD_MONOSEC < waituntil) 904 1.1 dholland (void) nfs_catnap(PZERO, 0, "nfstry"); 905 1.1 dholland trylater_delay *= 2; 906 1.1 dholland if (slot != -1) { 907 1.1 dholland mtx_lock(&sep->nfsess_mtx); 908 1.1 dholland sep->nfsess_slotseq[slot]++; 909 1.1 dholland *nd->nd_slotseq = txdr_unsigned( 910 1.1 dholland sep->nfsess_slotseq[slot]); 911 1.1 dholland mtx_unlock(&sep->nfsess_mtx); 912 1.1 dholland } 913 1.1 dholland m_freem(nd->nd_mrep); 914 1.1 dholland nd->nd_mrep = NULL; 915 1.1 dholland goto tryagain; 916 1.1 dholland } 917 1.1 dholland 918 1.1 dholland /* 919 1.1 dholland * If the File Handle was stale, invalidate the 920 1.1 dholland * lookup cache, just in case. 921 1.1 dholland * (vp != NULL implies a client side call) 922 1.1 dholland */ 923 1.1 dholland if (nd->nd_repstat == ESTALE && vp != NULL) { 924 1.1 dholland cache_purge(vp); 925 1.1 dholland if (ncl_call_invalcaches != NULL) 926 1.1 dholland (*ncl_call_invalcaches)(vp); 927 1.1 dholland } 928 1.1 dholland } 929 1.1 dholland if ((nd->nd_flag & ND_NFSV4) != 0) { 930 1.1 dholland /* Free the slot, as required. */ 931 1.1 dholland if (freeslot != -1) 932 1.1 dholland nfsv4_freeslot(sep, freeslot); 933 1.1 dholland /* 934 1.1 dholland * If this op is Putfh, throw its results away. 935 1.1 dholland */ 936 1.1 dholland if (j >= 10000) 937 1.1 dholland NFSCL_DEBUG(1, "nop=%d nst=%d\n", i, j); 938 1.1 dholland if (nmp != NULL && i == NFSV4OP_PUTFH && j == 0) { 939 1.1 dholland NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED); 940 1.1 dholland i = fxdr_unsigned(int, *tl++); 941 1.1 dholland j = fxdr_unsigned(int, *tl); 942 1.1 dholland if (j >= 10000) 943 1.1 dholland NFSCL_DEBUG(1, "n2op=%d n2st=%d\n", i, 944 1.1 dholland j); 945 1.1 dholland /* 946 1.1 dholland * All Compounds that do an Op that must 947 1.1 dholland * be in sequence consist of NFSV4OP_PUTFH 948 1.1 dholland * followed by one of these. As such, we 949 1.1 dholland * can determine if the seqid# should be 950 1.1 dholland * incremented, here. 951 1.1 dholland */ 952 1.1 dholland if ((i == NFSV4OP_OPEN || 953 1.1 dholland i == NFSV4OP_OPENCONFIRM || 954 1.1 dholland i == NFSV4OP_OPENDOWNGRADE || 955 1.1 dholland i == NFSV4OP_CLOSE || 956 1.1 dholland i == NFSV4OP_LOCK || 957 1.1 dholland i == NFSV4OP_LOCKU) && 958 1.1 dholland (j == 0 || 959 1.1 dholland (j != NFSERR_STALECLIENTID && 960 1.1 dholland j != NFSERR_STALESTATEID && 961 1.1 dholland j != NFSERR_BADSTATEID && 962 1.1 dholland j != NFSERR_BADSEQID && 963 1.1 dholland j != NFSERR_BADXDR && 964 1.1 dholland j != NFSERR_RESOURCE && 965 1.1 dholland j != NFSERR_NOFILEHANDLE))) 966 1.1 dholland nd->nd_flag |= ND_INCRSEQID; 967 1.1 dholland } 968 1.1 dholland /* 969 1.1 dholland * If this op's status is non-zero, mark 970 1.1 dholland * that there is no more data to process. 971 1.1 dholland */ 972 1.1 dholland if (j) 973 1.1 dholland nd->nd_flag |= ND_NOMOREDATA; 974 1.1 dholland 975 1.1 dholland /* 976 1.1 dholland * If R_DONTRECOVER is set, replace the stale error 977 1.1 dholland * reply, so that recovery isn't initiated. 978 1.1 dholland */ 979 1.1 dholland if ((nd->nd_repstat == NFSERR_STALECLIENTID || 980 1.1 dholland nd->nd_repstat == NFSERR_BADSESSION || 981 1.1 dholland nd->nd_repstat == NFSERR_STALESTATEID) && 982 1.1 dholland rep != NULL && (rep->r_flags & R_DONTRECOVER)) 983 1.1 dholland nd->nd_repstat = NFSERR_STALEDONTRECOVER; 984 1.1 dholland } 985 1.1 dholland } 986 1.1 dholland 987 1.1 dholland #ifdef KDTRACE_HOOKS 988 1.1 dholland if (nmp != NULL && dtrace_nfscl_nfs234_done_probe != NULL) { 989 1.1 dholland uint32_t probe_id; 990 1.1 dholland int probe_procnum; 991 1.1 dholland 992 1.1 dholland if (nd->nd_flag & ND_NFSV4) { 993 1.1 dholland probe_id = nfscl_nfs4_done_probes[nd->nd_procnum]; 994 1.1 dholland probe_procnum = nd->nd_procnum; 995 1.1 dholland } else if (nd->nd_flag & ND_NFSV3) { 996 1.1 dholland probe_id = nfscl_nfs3_done_probes[procnum]; 997 1.1 dholland probe_procnum = procnum; 998 1.1 dholland } else { 999 1.1 dholland probe_id = nfscl_nfs2_done_probes[nd->nd_procnum]; 1000 1.1 dholland probe_procnum = procnum; 1001 1.1 dholland } 1002 1.1 dholland if (probe_id != 0) 1003 1.1 dholland (dtrace_nfscl_nfs234_done_probe)(probe_id, vp, 1004 1.1 dholland nd->nd_mreq, cred, probe_procnum, 0); 1005 1.1 dholland } 1006 1.1 dholland #endif 1007 1.1 dholland 1008 1.1 dholland m_freem(nd->nd_mreq); 1009 1.1 dholland if (usegssname == 0) 1010 1.1 dholland AUTH_DESTROY(auth); 1011 1.1 dholland if (rep != NULL) 1012 1.1 dholland FREE((caddr_t)rep, M_NFSDREQ); 1013 1.1 dholland if (set_sigset) 1014 1.1 dholland newnfs_restore_sigmask(td, &oldset); 1015 1.1 dholland return (0); 1016 1.1 dholland nfsmout: 1017 1.1 dholland mbuf_freem(nd->nd_mrep); 1018 1.1 dholland mbuf_freem(nd->nd_mreq); 1019 1.1 dholland if (usegssname == 0) 1020 1.1 dholland AUTH_DESTROY(auth); 1021 1.1 dholland if (rep != NULL) 1022 1.1 dholland FREE((caddr_t)rep, M_NFSDREQ); 1023 1.1 dholland if (set_sigset) 1024 1.1 dholland newnfs_restore_sigmask(td, &oldset); 1025 1.1 dholland return (error); 1026 1.1 dholland } 1027 1.1 dholland 1028 1.1 dholland /* 1029 1.1 dholland * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and 1030 1.1 dholland * wait for all requests to complete. This is used by forced unmounts 1031 1.1 dholland * to terminate any outstanding RPCs. 1032 1.1 dholland */ 1033 1.1 dholland int 1034 1.1 dholland newnfs_nmcancelreqs(struct nfsmount *nmp) 1035 1.1 dholland { 1036 1.1 dholland 1037 1.1 dholland if (nmp->nm_sockreq.nr_client != NULL) 1038 1.1 dholland CLNT_CLOSE(nmp->nm_sockreq.nr_client); 1039 1.1 dholland return (0); 1040 1.1 dholland } 1041 1.1 dholland 1042 1.1 dholland /* 1043 1.1 dholland * Any signal that can interrupt an NFS operation in an intr mount 1044 1.1 dholland * should be added to this set. SIGSTOP and SIGKILL cannot be masked. 1045 1.1 dholland */ 1046 1.1 dholland int newnfs_sig_set[] = { 1047 1.1 dholland SIGINT, 1048 1.1 dholland SIGTERM, 1049 1.1 dholland SIGHUP, 1050 1.1 dholland SIGKILL, 1051 1.1 dholland SIGQUIT 1052 1.1 dholland }; 1053 1.1 dholland 1054 1.1 dholland /* 1055 1.1 dholland * Check to see if one of the signals in our subset is pending on 1056 1.1 dholland * the process (in an intr mount). 1057 1.1 dholland */ 1058 1.1 dholland static int 1059 1.1 dholland nfs_sig_pending(sigset_t set) 1060 1.1 dholland { 1061 1.1 dholland int i; 1062 1.1 dholland 1063 1.2 pgoyette for (i = 0 ; i < nitems(newnfs_sig_set); i++) 1064 1.1 dholland if (SIGISMEMBER(set, newnfs_sig_set[i])) 1065 1.1 dholland return (1); 1066 1.1 dholland return (0); 1067 1.1 dholland } 1068 1.1 dholland 1069 1.1 dholland /* 1070 1.1 dholland * The set/restore sigmask functions are used to (temporarily) overwrite 1071 1.1 dholland * the thread td_sigmask during an RPC call (for example). These are also 1072 1.1 dholland * used in other places in the NFS client that might tsleep(). 1073 1.1 dholland */ 1074 1.1 dholland void 1075 1.1 dholland newnfs_set_sigmask(struct thread *td, sigset_t *oldset) 1076 1.1 dholland { 1077 1.1 dholland sigset_t newset; 1078 1.1 dholland int i; 1079 1.1 dholland struct proc *p; 1080 1.1 dholland 1081 1.1 dholland SIGFILLSET(newset); 1082 1.1 dholland if (td == NULL) 1083 1.1 dholland td = curthread; /* XXX */ 1084 1.1 dholland p = td->td_proc; 1085 1.1 dholland /* Remove the NFS set of signals from newset */ 1086 1.1 dholland PROC_LOCK(p); 1087 1.1 dholland mtx_lock(&p->p_sigacts->ps_mtx); 1088 1.2 pgoyette for (i = 0 ; i < nitems(newnfs_sig_set); i++) { 1089 1.1 dholland /* 1090 1.1 dholland * But make sure we leave the ones already masked 1091 1.1 dholland * by the process, ie. remove the signal from the 1092 1.1 dholland * temporary signalmask only if it wasn't already 1093 1.1 dholland * in p_sigmask. 1094 1.1 dholland */ 1095 1.1 dholland if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) && 1096 1.1 dholland !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i])) 1097 1.1 dholland SIGDELSET(newset, newnfs_sig_set[i]); 1098 1.1 dholland } 1099 1.1 dholland mtx_unlock(&p->p_sigacts->ps_mtx); 1100 1.1 dholland kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 1101 1.1 dholland SIGPROCMASK_PROC_LOCKED); 1102 1.1 dholland PROC_UNLOCK(p); 1103 1.1 dholland } 1104 1.1 dholland 1105 1.1 dholland void 1106 1.1 dholland newnfs_restore_sigmask(struct thread *td, sigset_t *set) 1107 1.1 dholland { 1108 1.1 dholland if (td == NULL) 1109 1.1 dholland td = curthread; /* XXX */ 1110 1.1 dholland kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); 1111 1.1 dholland } 1112 1.1 dholland 1113 1.1 dholland /* 1114 1.1 dholland * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the 1115 1.1 dholland * old one after msleep() returns. 1116 1.1 dholland */ 1117 1.1 dholland int 1118 1.1 dholland newnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo) 1119 1.1 dholland { 1120 1.1 dholland sigset_t oldset; 1121 1.1 dholland int error; 1122 1.1 dholland struct proc *p; 1123 1.1 dholland 1124 1.1 dholland if ((priority & PCATCH) == 0) 1125 1.1 dholland return msleep(ident, mtx, priority, wmesg, timo); 1126 1.1 dholland if (td == NULL) 1127 1.1 dholland td = curthread; /* XXX */ 1128 1.1 dholland newnfs_set_sigmask(td, &oldset); 1129 1.1 dholland error = msleep(ident, mtx, priority, wmesg, timo); 1130 1.1 dholland newnfs_restore_sigmask(td, &oldset); 1131 1.1 dholland p = td->td_proc; 1132 1.1 dholland return (error); 1133 1.1 dholland } 1134 1.1 dholland 1135 1.1 dholland /* 1136 1.1 dholland * Test for a termination condition pending on the process. 1137 1.1 dholland * This is used for NFSMNT_INT mounts. 1138 1.1 dholland */ 1139 1.1 dholland int 1140 1.1 dholland newnfs_sigintr(struct nfsmount *nmp, struct thread *td) 1141 1.1 dholland { 1142 1.1 dholland struct proc *p; 1143 1.1 dholland sigset_t tmpset; 1144 1.1 dholland 1145 1.1 dholland /* Terminate all requests while attempting a forced unmount. */ 1146 1.1 dholland if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 1147 1.1 dholland return (EIO); 1148 1.1 dholland if (!(nmp->nm_flag & NFSMNT_INT)) 1149 1.1 dholland return (0); 1150 1.1 dholland if (td == NULL) 1151 1.1 dholland return (0); 1152 1.1 dholland p = td->td_proc; 1153 1.1 dholland PROC_LOCK(p); 1154 1.1 dholland tmpset = p->p_siglist; 1155 1.1 dholland SIGSETOR(tmpset, td->td_siglist); 1156 1.1 dholland SIGSETNAND(tmpset, td->td_sigmask); 1157 1.1 dholland mtx_lock(&p->p_sigacts->ps_mtx); 1158 1.1 dholland SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); 1159 1.1 dholland mtx_unlock(&p->p_sigacts->ps_mtx); 1160 1.1 dholland if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist)) 1161 1.1 dholland && nfs_sig_pending(tmpset)) { 1162 1.1 dholland PROC_UNLOCK(p); 1163 1.1 dholland return (EINTR); 1164 1.1 dholland } 1165 1.1 dholland PROC_UNLOCK(p); 1166 1.1 dholland return (0); 1167 1.1 dholland } 1168 1.1 dholland 1169 1.1 dholland static int 1170 1.1 dholland nfs_msg(struct thread *td, const char *server, const char *msg, int error) 1171 1.1 dholland { 1172 1.1 dholland struct proc *p; 1173 1.1 dholland 1174 1.1 dholland p = td ? td->td_proc : NULL; 1175 1.1 dholland if (error) { 1176 1.2 pgoyette tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", 1177 1.1 dholland server, msg, error); 1178 1.1 dholland } else { 1179 1.2 pgoyette tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg); 1180 1.1 dholland } 1181 1.1 dholland return (0); 1182 1.1 dholland } 1183 1.1 dholland 1184 1.1 dholland static void 1185 1.1 dholland nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg, 1186 1.1 dholland int error, int flags) 1187 1.1 dholland { 1188 1.1 dholland if (nmp == NULL) 1189 1.1 dholland return; 1190 1.1 dholland mtx_lock(&nmp->nm_mtx); 1191 1.1 dholland if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) { 1192 1.1 dholland nmp->nm_state |= NFSSTA_TIMEO; 1193 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1194 1.1 dholland vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 1195 1.1 dholland VQ_NOTRESP, 0); 1196 1.1 dholland } else 1197 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1198 1.1 dholland mtx_lock(&nmp->nm_mtx); 1199 1.1 dholland if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) { 1200 1.1 dholland nmp->nm_state |= NFSSTA_LOCKTIMEO; 1201 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1202 1.1 dholland vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 1203 1.1 dholland VQ_NOTRESPLOCK, 0); 1204 1.1 dholland } else 1205 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1206 1.1 dholland nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); 1207 1.1 dholland } 1208 1.1 dholland 1209 1.1 dholland static void 1210 1.1 dholland nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, 1211 1.1 dholland int flags, int tprintfmsg) 1212 1.1 dholland { 1213 1.1 dholland if (nmp == NULL) 1214 1.1 dholland return; 1215 1.1 dholland if (tprintfmsg) { 1216 1.1 dholland nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); 1217 1.1 dholland } 1218 1.1 dholland 1219 1.1 dholland mtx_lock(&nmp->nm_mtx); 1220 1.1 dholland if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) { 1221 1.1 dholland nmp->nm_state &= ~NFSSTA_TIMEO; 1222 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1223 1.1 dholland vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 1224 1.1 dholland VQ_NOTRESP, 1); 1225 1.1 dholland } else 1226 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1227 1.1 dholland 1228 1.1 dholland mtx_lock(&nmp->nm_mtx); 1229 1.1 dholland if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) { 1230 1.1 dholland nmp->nm_state &= ~NFSSTA_LOCKTIMEO; 1231 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1232 1.1 dholland vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 1233 1.1 dholland VQ_NOTRESPLOCK, 1); 1234 1.1 dholland } else 1235 1.1 dholland mtx_unlock(&nmp->nm_mtx); 1236 1.1 dholland } 1237 1.1 dholland 1238