nfs_krpc.c revision 227690
1/*- 2 * Copyright (c) 1989, 1991, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_krpc.c 227690 2011-11-19 03:20:15Z rmacklem $"); 37 38/* 39 * Socket operations for use by nfs 40 */ 41 42#include "opt_inet6.h" 43#include "opt_kdtrace.h" 44#include "opt_kgssapi.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/limits.h> 50#include <sys/lock.h> 51#include <sys/malloc.h> 52#include <sys/mbuf.h> 53#include <sys/mount.h> 54#include <sys/mutex.h> 55#include <sys/proc.h> 56#include <sys/signalvar.h> 57#include <sys/syscallsubr.h> 58#include <sys/sysctl.h> 59#include <sys/syslog.h> 60#include <sys/vnode.h> 61 62#include <rpc/rpc.h> 63 64#include <nfs/nfsproto.h> 65#include <nfsclient/nfs.h> 66#include <nfs/xdr_subs.h> 67#include <nfsclient/nfsm_subs.h> 68#include <nfsclient/nfsmount.h> 69#include <nfsclient/nfsnode.h> 70 71#ifdef KDTRACE_HOOKS 72#include <sys/dtrace_bsd.h> 73 74dtrace_nfsclient_nfs23_start_probe_func_t 75 dtrace_nfsclient_nfs23_start_probe; 76 77dtrace_nfsclient_nfs23_done_probe_func_t 78 dtrace_nfsclient_nfs23_done_probe; 79 80/* 81 * Registered probes by RPC type. 82 */ 83uint32_t nfsclient_nfs2_start_probes[NFS_NPROCS]; 84uint32_t nfsclient_nfs2_done_probes[NFS_NPROCS]; 85 86uint32_t nfsclient_nfs3_start_probes[NFS_NPROCS]; 87uint32_t nfsclient_nfs3_done_probes[NFS_NPROCS]; 88#endif 89 90static int nfs_bufpackets = 4; 91static int nfs_reconnects; 92static int nfs3_jukebox_delay = 10; 93static int nfs_skip_wcc_data_onerr = 1; 94static int fake_wchan; 95 96SYSCTL_DECL(_vfs_oldnfs); 97 98SYSCTL_INT(_vfs_oldnfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, 99 "Buffer reservation size 2 < x < 64"); 100SYSCTL_INT(_vfs_oldnfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, 101 "Number of times the nfs client has had to reconnect"); 102SYSCTL_INT(_vfs_oldnfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, 103 &nfs3_jukebox_delay, 0, 104 "Number of seconds to delay a retry after receiving EJUKEBOX"); 105SYSCTL_INT(_vfs_oldnfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, 106 &nfs_skip_wcc_data_onerr, 0, 107 "Disable weak cache consistency checking when server returns an error"); 108 109static void nfs_down(struct nfsmount *, struct thread *, const char *, 110 int, int); 111static void nfs_up(struct nfsmount *, struct thread *, const char *, 112 int, int); 113static int nfs_msg(struct thread *, const char *, const char *, int); 114 115extern int nfsv2_procid[]; 116 117struct nfs_cached_auth { 118 int ca_refs; /* refcount, including 1 from the cache */ 119 uid_t ca_uid; /* uid that corresponds to this auth */ 120 AUTH *ca_auth; /* RPC auth handle */ 121}; 122 123/* 124 * RTT estimator 125 */ 126 127static enum nfs_rto_timer_t nfs_proct[NFS_NPROCS] = { 128 NFS_DEFAULT_TIMER, /* NULL */ 129 NFS_GETATTR_TIMER, /* GETATTR */ 130 NFS_DEFAULT_TIMER, /* SETATTR */ 131 NFS_LOOKUP_TIMER, /* LOOKUP */ 132 NFS_GETATTR_TIMER, /* ACCESS */ 133 NFS_READ_TIMER, /* READLINK */ 134 NFS_READ_TIMER, /* READ */ 135 NFS_WRITE_TIMER, /* WRITE */ 136 NFS_DEFAULT_TIMER, /* CREATE */ 137 NFS_DEFAULT_TIMER, /* MKDIR */ 138 NFS_DEFAULT_TIMER, /* SYMLINK */ 139 NFS_DEFAULT_TIMER, /* MKNOD */ 140 NFS_DEFAULT_TIMER, /* REMOVE */ 141 NFS_DEFAULT_TIMER, /* RMDIR */ 142 NFS_DEFAULT_TIMER, /* RENAME */ 143 NFS_DEFAULT_TIMER, /* LINK */ 144 NFS_READ_TIMER, /* READDIR */ 145 NFS_READ_TIMER, /* READDIRPLUS */ 146 NFS_DEFAULT_TIMER, /* FSSTAT */ 147 NFS_DEFAULT_TIMER, /* FSINFO */ 148 NFS_DEFAULT_TIMER, /* PATHCONF */ 149 NFS_DEFAULT_TIMER, /* COMMIT */ 150 NFS_DEFAULT_TIMER, /* NOOP */ 151}; 152 153/* 154 * Choose the correct RTT timer for this NFS procedure. 155 */ 156static inline enum nfs_rto_timer_t 157nfs_rto_timer(u_int32_t procnum) 158{ 159 160 return (nfs_proct[procnum]); 161} 162 163/* 164 * Initialize the RTT estimator state for a new mount point. 165 */ 166static void 167nfs_init_rtt(struct nfsmount *nmp) 168{ 169 int i; 170 171 for (i = 0; i < NFS_MAX_TIMER; i++) { 172 nmp->nm_timers[i].rt_srtt = hz; 173 nmp->nm_timers[i].rt_deviate = 0; 174 nmp->nm_timers[i].rt_rtxcur = hz; 175 } 176} 177 178/* 179 * Initialize sockets and congestion for a new NFS connection. 180 * We do not free the sockaddr if error. 181 */ 182int 183nfs_connect(struct nfsmount *nmp) 184{ 185 int rcvreserve, sndreserve; 186 int pktscale; 187 struct sockaddr *saddr; 188 struct ucred *origcred; 189 struct thread *td = curthread; 190 CLIENT *client; 191 struct netconfig *nconf; 192 rpcvers_t vers; 193 int one = 1, retries; 194 195 /* 196 * We need to establish the socket using the credentials of 197 * the mountpoint. Some parts of this process (such as 198 * sobind() and soconnect()) will use the curent thread's 199 * credential instead of the socket credential. To work 200 * around this, temporarily change the current thread's 201 * credential to that of the mountpoint. 202 * 203 * XXX: It would be better to explicitly pass the correct 204 * credential to sobind() and soconnect(). 205 */ 206 origcred = td->td_ucred; 207 td->td_ucred = nmp->nm_mountp->mnt_cred; 208 saddr = nmp->nm_nam; 209 210 vers = NFS_VER2; 211 if (nmp->nm_flag & NFSMNT_NFSV3) 212 vers = NFS_VER3; 213 else if (nmp->nm_flag & NFSMNT_NFSV4) 214 vers = NFS_VER4; 215 if (saddr->sa_family == AF_INET) 216 if (nmp->nm_sotype == SOCK_DGRAM) 217 nconf = getnetconfigent("udp"); 218 else 219 nconf = getnetconfigent("tcp"); 220 else 221 if (nmp->nm_sotype == SOCK_DGRAM) 222 nconf = getnetconfigent("udp6"); 223 else 224 nconf = getnetconfigent("tcp6"); 225 226 /* 227 * Get buffer reservation size from sysctl, but impose reasonable 228 * limits. 229 */ 230 pktscale = nfs_bufpackets; 231 if (pktscale < 2) 232 pktscale = 2; 233 if (pktscale > 64) 234 pktscale = 64; 235 mtx_lock(&nmp->nm_mtx); 236 if (nmp->nm_sotype == SOCK_DGRAM) { 237 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale; 238 rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + 239 NFS_MAXPKTHDR) * pktscale; 240 } else if (nmp->nm_sotype == SOCK_SEQPACKET) { 241 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale; 242 rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + 243 NFS_MAXPKTHDR) * pktscale; 244 } else { 245 if (nmp->nm_sotype != SOCK_STREAM) 246 panic("nfscon sotype"); 247 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + 248 sizeof (u_int32_t)) * pktscale; 249 rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + 250 sizeof (u_int32_t)) * pktscale; 251 } 252 mtx_unlock(&nmp->nm_mtx); 253 254 client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers, 255 sndreserve, rcvreserve); 256 CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq"); 257 if (nmp->nm_flag & NFSMNT_INT) 258 CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one); 259 if (nmp->nm_flag & NFSMNT_RESVPORT) 260 CLNT_CONTROL(client, CLSET_PRIVPORT, &one); 261 if (nmp->nm_flag & NFSMNT_SOFT) 262 retries = nmp->nm_retry; 263 else 264 retries = INT_MAX; 265 CLNT_CONTROL(client, CLSET_RETRIES, &retries); 266 267 mtx_lock(&nmp->nm_mtx); 268 if (nmp->nm_client) { 269 /* 270 * Someone else already connected. 271 */ 272 CLNT_RELEASE(client); 273 } else 274 nmp->nm_client = client; 275 276 /* 277 * Protocols that do not require connections may be optionally left 278 * unconnected for servers that reply from a port other than NFS_PORT. 279 */ 280 if (!(nmp->nm_flag & NFSMNT_NOCONN)) { 281 mtx_unlock(&nmp->nm_mtx); 282 CLNT_CONTROL(client, CLSET_CONNECT, &one); 283 } else 284 mtx_unlock(&nmp->nm_mtx); 285 286 /* Restore current thread's credentials. */ 287 td->td_ucred = origcred; 288 289 mtx_lock(&nmp->nm_mtx); 290 /* Initialize other non-zero congestion variables. */ 291 nfs_init_rtt(nmp); 292 mtx_unlock(&nmp->nm_mtx); 293 return (0); 294} 295 296/* 297 * NFS disconnect. Clean up and unlink. 298 */ 299void 300nfs_disconnect(struct nfsmount *nmp) 301{ 302 CLIENT *client; 303 304 mtx_lock(&nmp->nm_mtx); 305 if (nmp->nm_client) { 306 client = nmp->nm_client; 307 nmp->nm_client = NULL; 308 mtx_unlock(&nmp->nm_mtx); 309 rpc_gss_secpurge_call(client); 310 CLNT_CLOSE(client); 311 CLNT_RELEASE(client); 312 } else 313 mtx_unlock(&nmp->nm_mtx); 314} 315 316void 317nfs_safedisconnect(struct nfsmount *nmp) 318{ 319 320 nfs_disconnect(nmp); 321} 322 323static AUTH * 324nfs_getauth(struct nfsmount *nmp, struct ucred *cred) 325{ 326 rpc_gss_service_t svc; 327 AUTH *auth; 328 329 switch (nmp->nm_secflavor) { 330 case RPCSEC_GSS_KRB5: 331 case RPCSEC_GSS_KRB5I: 332 case RPCSEC_GSS_KRB5P: 333 if (!nmp->nm_mech_oid) 334 if (!rpc_gss_mech_to_oid_call("kerberosv5", 335 &nmp->nm_mech_oid)) 336 return (NULL); 337 if (nmp->nm_secflavor == RPCSEC_GSS_KRB5) 338 svc = rpc_gss_svc_none; 339 else if (nmp->nm_secflavor == RPCSEC_GSS_KRB5I) 340 svc = rpc_gss_svc_integrity; 341 else 342 svc = rpc_gss_svc_privacy; 343 auth = rpc_gss_secfind_call(nmp->nm_client, cred, 344 nmp->nm_principal, nmp->nm_mech_oid, svc); 345 if (auth) 346 return (auth); 347 /* fallthrough */ 348 case AUTH_SYS: 349 default: 350 return (authunix_create(cred)); 351 352 } 353} 354 355/* 356 * Callback from the RPC code to generate up/down notifications. 357 */ 358 359struct nfs_feedback_arg { 360 struct nfsmount *nf_mount; 361 int nf_lastmsg; /* last tprintf */ 362 int nf_tprintfmsg; 363 struct thread *nf_td; 364}; 365 366static void 367nfs_feedback(int type, int proc, void *arg) 368{ 369 struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg; 370 struct nfsmount *nmp = nf->nf_mount; 371 struct timeval now; 372 373 getmicrouptime(&now); 374 375 switch (type) { 376 case FEEDBACK_REXMIT2: 377 case FEEDBACK_RECONNECT: 378 if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) { 379 nfs_down(nmp, nf->nf_td, 380 "not responding", 0, NFSSTA_TIMEO); 381 nf->nf_tprintfmsg = TRUE; 382 nf->nf_lastmsg = now.tv_sec; 383 } 384 break; 385 386 case FEEDBACK_OK: 387 nfs_up(nf->nf_mount, nf->nf_td, 388 "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg); 389 break; 390 } 391} 392 393/* 394 * nfs_request - goes something like this 395 * - fill in request struct 396 * - links it into list 397 * - calls nfs_send() for first transmit 398 * - calls nfs_receive() to get reply 399 * - break down rpc header and return with nfs reply pointed to 400 * by mrep or error 401 * nb: always frees up mreq mbuf list 402 */ 403int 404nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum, 405 struct thread *td, struct ucred *cred, struct mbuf **mrp, 406 struct mbuf **mdp, caddr_t *dposp) 407{ 408 struct mbuf *mrep; 409 u_int32_t *tl; 410 struct nfsmount *nmp; 411 struct mbuf *md; 412 time_t waituntil; 413 caddr_t dpos; 414 int error = 0; 415 struct timeval now; 416 AUTH *auth = NULL; 417 enum nfs_rto_timer_t timer; 418 struct nfs_feedback_arg nf; 419 struct rpc_callextra ext; 420 enum clnt_stat stat; 421 struct timeval timo; 422 423 /* Reject requests while attempting a forced unmount. */ 424 if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) { 425 m_freem(mreq); 426 return (ESTALE); 427 } 428 nmp = VFSTONFS(vp->v_mount); 429 bzero(&nf, sizeof(struct nfs_feedback_arg)); 430 nf.nf_mount = nmp; 431 nf.nf_td = td; 432 getmicrouptime(&now); 433 nf.nf_lastmsg = now.tv_sec - 434 ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay)); 435 436 /* 437 * XXX if not already connected call nfs_connect now. Longer 438 * term, change nfs_mount to call nfs_connect unconditionally 439 * and let clnt_reconnect_create handle reconnects. 440 */ 441 if (!nmp->nm_client) 442 nfs_connect(nmp); 443 444 auth = nfs_getauth(nmp, cred); 445 if (!auth) { 446 m_freem(mreq); 447 return (EACCES); 448 } 449 bzero(&ext, sizeof(ext)); 450 ext.rc_auth = auth; 451 452 ext.rc_feedback = nfs_feedback; 453 ext.rc_feedback_arg = &nf; 454 455 /* 456 * Use a conservative timeout for RPCs other than getattr, 457 * lookup, read or write. The justification for doing "other" 458 * this way is that these RPCs happen so infrequently that 459 * timer est. would probably be stale. Also, since many of 460 * these RPCs are non-idempotent, a conservative timeout is 461 * desired. 462 */ 463 timer = nfs_rto_timer(procnum); 464 if (timer != NFS_DEFAULT_TIMER) 465 ext.rc_timers = &nmp->nm_timers[timer - 1]; 466 else 467 ext.rc_timers = NULL; 468 469#ifdef KDTRACE_HOOKS 470 if (dtrace_nfsclient_nfs23_start_probe != NULL) { 471 uint32_t probe_id; 472 int probe_procnum; 473 474 if (nmp->nm_flag & NFSMNT_NFSV3) { 475 probe_id = nfsclient_nfs3_start_probes[procnum]; 476 probe_procnum = procnum; 477 } else { 478 probe_id = nfsclient_nfs2_start_probes[procnum]; 479 probe_procnum = nfsv2_procid[procnum]; 480 } 481 if (probe_id != 0) 482 (dtrace_nfsclient_nfs23_start_probe)(probe_id, vp, 483 mreq, cred, probe_procnum); 484 } 485#endif 486 487 nfsstats.rpcrequests++; 488tryagain: 489 timo.tv_sec = nmp->nm_timeo / NFS_HZ; 490 timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ; 491 mrep = NULL; 492 stat = CLNT_CALL_MBUF(nmp->nm_client, &ext, 493 (nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum], 494 mreq, &mrep, timo); 495 496 /* 497 * If there was a successful reply and a tprintf msg. 498 * tprintf a response. 499 */ 500 if (stat == RPC_SUCCESS) 501 error = 0; 502 else if (stat == RPC_TIMEDOUT) 503 error = ETIMEDOUT; 504 else if (stat == RPC_VERSMISMATCH) 505 error = EOPNOTSUPP; 506 else if (stat == RPC_PROGVERSMISMATCH) 507 error = EPROTONOSUPPORT; 508 else 509 error = EACCES; 510 if (error) 511 goto nfsmout; 512 513 KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n")); 514 515 /* 516 * Search for any mbufs that are not a multiple of 4 bytes long 517 * or with m_data not longword aligned. 518 * These could cause pointer alignment problems, so copy them to 519 * well aligned mbufs. 520 */ 521 error = nfs_realign(&mrep, M_DONTWAIT); 522 if (error == ENOMEM) { 523 m_freem(mrep); 524 AUTH_DESTROY(auth); 525 return (error); 526 } 527 528 md = mrep; 529 dpos = mtod(mrep, caddr_t); 530 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED); 531 if (*tl != 0) { 532 error = fxdr_unsigned(int, *tl); 533 if ((nmp->nm_flag & NFSMNT_NFSV3) && 534 error == NFSERR_TRYLATER) { 535 m_freem(mrep); 536 error = 0; 537 waituntil = time_second + nfs3_jukebox_delay; 538 while (time_second < waituntil) 539 (void)tsleep(&fake_wchan, PSOCK, "nqnfstry", 540 hz); 541 goto tryagain; 542 } 543 /* 544 * Make sure NFSERR_RETERR isn't bogusly set by a server 545 * such as amd. (No actual NFS error has bit 31 set.) 546 */ 547 error &= ~NFSERR_RETERR; 548 549 /* 550 * If the File Handle was stale, invalidate the lookup 551 * cache, just in case. 552 */ 553 if (error == ESTALE) 554 nfs_purgecache(vp); 555 /* 556 * Skip wcc data on NFS errors for now. NetApp filers 557 * return corrupt postop attrs in the wcc data for NFS 558 * err EROFS. Not sure if they could return corrupt 559 * postop attrs for others errors. 560 */ 561 if ((nmp->nm_flag & NFSMNT_NFSV3) && 562 !nfs_skip_wcc_data_onerr) { 563 *mrp = mrep; 564 *mdp = md; 565 *dposp = dpos; 566 error |= NFSERR_RETERR; 567 } else 568 m_freem(mrep); 569 goto nfsmout; 570 } 571 572#ifdef KDTRACE_HOOKS 573 if (dtrace_nfsclient_nfs23_done_probe != NULL) { 574 uint32_t probe_id; 575 int probe_procnum; 576 577 if (nmp->nm_flag & NFSMNT_NFSV3) { 578 probe_id = nfsclient_nfs3_done_probes[procnum]; 579 probe_procnum = procnum; 580 } else { 581 probe_id = nfsclient_nfs2_done_probes[procnum]; 582 probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ? 583 procnum : nfsv2_procid[procnum]; 584 } 585 if (probe_id != 0) 586 (dtrace_nfsclient_nfs23_done_probe)(probe_id, vp, 587 mreq, cred, probe_procnum, 0); 588 } 589#endif 590 m_freem(mreq); 591 *mrp = mrep; 592 *mdp = md; 593 *dposp = dpos; 594 AUTH_DESTROY(auth); 595 return (0); 596 597nfsmout: 598#ifdef KDTRACE_HOOKS 599 if (dtrace_nfsclient_nfs23_done_probe != NULL) { 600 uint32_t probe_id; 601 int probe_procnum; 602 603 if (nmp->nm_flag & NFSMNT_NFSV3) { 604 probe_id = nfsclient_nfs3_done_probes[procnum]; 605 probe_procnum = procnum; 606 } else { 607 probe_id = nfsclient_nfs2_done_probes[procnum]; 608 probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ? 609 procnum : nfsv2_procid[procnum]; 610 } 611 if (probe_id != 0) 612 (dtrace_nfsclient_nfs23_done_probe)(probe_id, vp, 613 mreq, cred, probe_procnum, error); 614 } 615#endif 616 m_freem(mreq); 617 if (auth) 618 AUTH_DESTROY(auth); 619 return (error); 620} 621 622/* 623 * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and 624 * wait for all requests to complete. This is used by forced unmounts 625 * to terminate any outstanding RPCs. 626 */ 627int 628nfs_nmcancelreqs(struct nfsmount *nmp) 629{ 630 631 if (nmp->nm_client) 632 CLNT_CLOSE(nmp->nm_client); 633 return (0); 634} 635 636/* 637 * Any signal that can interrupt an NFS operation in an intr mount 638 * should be added to this set. SIGSTOP and SIGKILL cannot be masked. 639 */ 640int nfs_sig_set[] = { 641 SIGINT, 642 SIGTERM, 643 SIGHUP, 644 SIGKILL, 645 SIGSTOP, 646 SIGQUIT 647}; 648 649/* 650 * Check to see if one of the signals in our subset is pending on 651 * the process (in an intr mount). 652 */ 653static int 654nfs_sig_pending(sigset_t set) 655{ 656 int i; 657 658 for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) 659 if (SIGISMEMBER(set, nfs_sig_set[i])) 660 return (1); 661 return (0); 662} 663 664/* 665 * The set/restore sigmask functions are used to (temporarily) overwrite 666 * the process p_sigmask during an RPC call (for example). These are also 667 * used in other places in the NFS client that might tsleep(). 668 */ 669void 670nfs_set_sigmask(struct thread *td, sigset_t *oldset) 671{ 672 sigset_t newset; 673 int i; 674 struct proc *p; 675 676 SIGFILLSET(newset); 677 if (td == NULL) 678 td = curthread; /* XXX */ 679 p = td->td_proc; 680 /* Remove the NFS set of signals from newset. */ 681 PROC_LOCK(p); 682 mtx_lock(&p->p_sigacts->ps_mtx); 683 for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) { 684 /* 685 * But make sure we leave the ones already masked 686 * by the process, i.e. remove the signal from the 687 * temporary signalmask only if it wasn't already 688 * in p_sigmask. 689 */ 690 if (!SIGISMEMBER(td->td_sigmask, nfs_sig_set[i]) && 691 !SIGISMEMBER(p->p_sigacts->ps_sigignore, nfs_sig_set[i])) 692 SIGDELSET(newset, nfs_sig_set[i]); 693 } 694 mtx_unlock(&p->p_sigacts->ps_mtx); 695 PROC_UNLOCK(p); 696 kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); 697} 698 699void 700nfs_restore_sigmask(struct thread *td, sigset_t *set) 701{ 702 if (td == NULL) 703 td = curthread; /* XXX */ 704 kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); 705} 706 707/* 708 * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the 709 * old one after msleep() returns. 710 */ 711int 712nfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, 713 char *wmesg, int timo) 714{ 715 sigset_t oldset; 716 int error; 717 struct proc *p; 718 719 if ((priority & PCATCH) == 0) 720 return msleep(ident, mtx, priority, wmesg, timo); 721 if (td == NULL) 722 td = curthread; /* XXX */ 723 nfs_set_sigmask(td, &oldset); 724 error = msleep(ident, mtx, priority, wmesg, timo); 725 nfs_restore_sigmask(td, &oldset); 726 p = td->td_proc; 727 return (error); 728} 729 730/* 731 * Test for a termination condition pending on the process. 732 * This is used for NFSMNT_INT mounts. 733 */ 734int 735nfs_sigintr(struct nfsmount *nmp, struct thread *td) 736{ 737 struct proc *p; 738 sigset_t tmpset; 739 740 /* Terminate all requests while attempting a forced unmount. */ 741 if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 742 return (EIO); 743 if (!(nmp->nm_flag & NFSMNT_INT)) 744 return (0); 745 if (td == NULL) 746 return (0); 747 p = td->td_proc; 748 PROC_LOCK(p); 749 tmpset = p->p_siglist; 750 SIGSETOR(tmpset, td->td_siglist); 751 SIGSETNAND(tmpset, td->td_sigmask); 752 mtx_lock(&p->p_sigacts->ps_mtx); 753 SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); 754 mtx_unlock(&p->p_sigacts->ps_mtx); 755 if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist)) 756 && nfs_sig_pending(tmpset)) { 757 PROC_UNLOCK(p); 758 return (EINTR); 759 } 760 PROC_UNLOCK(p); 761 return (0); 762} 763 764static int 765nfs_msg(struct thread *td, const char *server, const char *msg, int error) 766{ 767 struct proc *p; 768 769 p = td ? td->td_proc : NULL; 770 if (error) 771 tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", server, 772 msg, error); 773 else 774 tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg); 775 return (0); 776} 777 778static void 779nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg, 780 int error, int flags) 781{ 782 if (nmp == NULL) 783 return; 784 mtx_lock(&nmp->nm_mtx); 785 if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) { 786 nmp->nm_state |= NFSSTA_TIMEO; 787 mtx_unlock(&nmp->nm_mtx); 788 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 789 VQ_NOTRESP, 0); 790 } else 791 mtx_unlock(&nmp->nm_mtx); 792 mtx_lock(&nmp->nm_mtx); 793 if ((flags & NFSSTA_LOCKTIMEO) && 794 !(nmp->nm_state & NFSSTA_LOCKTIMEO)) { 795 nmp->nm_state |= NFSSTA_LOCKTIMEO; 796 mtx_unlock(&nmp->nm_mtx); 797 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 798 VQ_NOTRESPLOCK, 0); 799 } else 800 mtx_unlock(&nmp->nm_mtx); 801 nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); 802} 803 804static void 805nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, 806 int flags, int tprintfmsg) 807{ 808 if (nmp == NULL) 809 return; 810 if (tprintfmsg) 811 nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); 812 813 mtx_lock(&nmp->nm_mtx); 814 if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) { 815 nmp->nm_state &= ~NFSSTA_TIMEO; 816 mtx_unlock(&nmp->nm_mtx); 817 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 818 VQ_NOTRESP, 1); 819 } else 820 mtx_unlock(&nmp->nm_mtx); 821 822 mtx_lock(&nmp->nm_mtx); 823 if ((flags & NFSSTA_LOCKTIMEO) && 824 (nmp->nm_state & NFSSTA_LOCKTIMEO)) { 825 nmp->nm_state &= ~NFSSTA_LOCKTIMEO; 826 mtx_unlock(&nmp->nm_mtx); 827 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 828 VQ_NOTRESPLOCK, 1); 829 } else 830 mtx_unlock(&nmp->nm_mtx); 831} 832