nfs_krpc.c revision 203732
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 203732 2010-02-09 23:45:14Z marius $"); 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_nfs); 97 98SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, 99 "Buffer reservation size 2 < x < 64"); 100SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, 101 "Number of times the nfs client has had to reconnect"); 102SYSCTL_INT(_vfs_nfs, 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_nfs, 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#ifdef KGSSAPI 310 rpc_gss_secpurge(client); 311#endif 312 CLNT_CLOSE(client); 313 CLNT_RELEASE(client); 314 } else 315 mtx_unlock(&nmp->nm_mtx); 316} 317 318void 319nfs_safedisconnect(struct nfsmount *nmp) 320{ 321 322 nfs_disconnect(nmp); 323} 324 325static AUTH * 326nfs_getauth(struct nfsmount *nmp, struct ucred *cred) 327{ 328#ifdef KGSSAPI 329 rpc_gss_service_t svc; 330 AUTH *auth; 331#endif 332 333 switch (nmp->nm_secflavor) { 334#ifdef KGSSAPI 335 case RPCSEC_GSS_KRB5: 336 case RPCSEC_GSS_KRB5I: 337 case RPCSEC_GSS_KRB5P: 338 if (!nmp->nm_mech_oid) 339 if (!rpc_gss_mech_to_oid("kerberosv5", 340 &nmp->nm_mech_oid)) 341 return (NULL); 342 if (nmp->nm_secflavor == RPCSEC_GSS_KRB5) 343 svc = rpc_gss_svc_none; 344 else if (nmp->nm_secflavor == RPCSEC_GSS_KRB5I) 345 svc = rpc_gss_svc_integrity; 346 else 347 svc = rpc_gss_svc_privacy; 348 auth = rpc_gss_secfind(nmp->nm_client, cred, 349 nmp->nm_principal, nmp->nm_mech_oid, svc); 350 if (auth) 351 return (auth); 352 /* fallthrough */ 353#endif 354 case AUTH_SYS: 355 default: 356 return (authunix_create(cred)); 357 358 } 359} 360 361/* 362 * Callback from the RPC code to generate up/down notifications. 363 */ 364 365struct nfs_feedback_arg { 366 struct nfsmount *nf_mount; 367 int nf_lastmsg; /* last tprintf */ 368 int nf_tprintfmsg; 369 struct thread *nf_td; 370}; 371 372static void 373nfs_feedback(int type, int proc, void *arg) 374{ 375 struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg; 376 struct nfsmount *nmp = nf->nf_mount; 377 struct timeval now; 378 379 getmicrouptime(&now); 380 381 switch (type) { 382 case FEEDBACK_REXMIT2: 383 case FEEDBACK_RECONNECT: 384 if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) { 385 nfs_down(nmp, nf->nf_td, 386 "not responding", 0, NFSSTA_TIMEO); 387 nf->nf_tprintfmsg = TRUE; 388 nf->nf_lastmsg = now.tv_sec; 389 } 390 break; 391 392 case FEEDBACK_OK: 393 nfs_up(nf->nf_mount, nf->nf_td, 394 "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg); 395 break; 396 } 397} 398 399/* 400 * nfs_request - goes something like this 401 * - fill in request struct 402 * - links it into list 403 * - calls nfs_send() for first transmit 404 * - calls nfs_receive() to get reply 405 * - break down rpc header and return with nfs reply pointed to 406 * by mrep or error 407 * nb: always frees up mreq mbuf list 408 */ 409int 410nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum, 411 struct thread *td, struct ucred *cred, struct mbuf **mrp, 412 struct mbuf **mdp, caddr_t *dposp) 413{ 414 struct mbuf *mrep; 415 u_int32_t *tl; 416 struct nfsmount *nmp; 417 struct mbuf *md; 418 time_t waituntil; 419 caddr_t dpos; 420 int error = 0; 421 struct timeval now; 422 AUTH *auth = NULL; 423 enum nfs_rto_timer_t timer; 424 struct nfs_feedback_arg nf; 425 struct rpc_callextra ext; 426 enum clnt_stat stat; 427 struct timeval timo; 428 429 /* Reject requests while attempting a forced unmount. */ 430 if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) { 431 m_freem(mreq); 432 return (ESTALE); 433 } 434 nmp = VFSTONFS(vp->v_mount); 435 bzero(&nf, sizeof(struct nfs_feedback_arg)); 436 nf.nf_mount = nmp; 437 nf.nf_td = td; 438 getmicrouptime(&now); 439 nf.nf_lastmsg = now.tv_sec - 440 ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay)); 441 442 /* 443 * XXX if not already connected call nfs_connect now. Longer 444 * term, change nfs_mount to call nfs_connect unconditionally 445 * and let clnt_reconnect_create handle reconnects. 446 */ 447 if (!nmp->nm_client) 448 nfs_connect(nmp); 449 450 auth = nfs_getauth(nmp, cred); 451 if (!auth) { 452 m_freem(mreq); 453 return (EACCES); 454 } 455 bzero(&ext, sizeof(ext)); 456 ext.rc_auth = auth; 457 458 ext.rc_feedback = nfs_feedback; 459 ext.rc_feedback_arg = &nf; 460 461 /* 462 * Use a conservative timeout for RPCs other than getattr, 463 * lookup, read or write. The justification for doing "other" 464 * this way is that these RPCs happen so infrequently that 465 * timer est. would probably be stale. Also, since many of 466 * these RPCs are non-idempotent, a conservative timeout is 467 * desired. 468 */ 469 timer = nfs_rto_timer(procnum); 470 if (timer != NFS_DEFAULT_TIMER) 471 ext.rc_timers = &nmp->nm_timers[timer - 1]; 472 else 473 ext.rc_timers = NULL; 474 475#ifdef KDTRACE_HOOKS 476 if (dtrace_nfsclient_nfs23_start_probe != NULL) { 477 uint32_t probe_id; 478 int probe_procnum; 479 480 if (nmp->nm_flag & NFSMNT_NFSV3) { 481 probe_id = nfsclient_nfs3_start_probes[procnum]; 482 probe_procnum = procnum; 483 } else { 484 probe_id = nfsclient_nfs2_start_probes[procnum]; 485 probe_procnum = nfsv2_procid[procnum]; 486 } 487 if (probe_id != 0) 488 (dtrace_nfsclient_nfs23_start_probe)(probe_id, vp, 489 mreq, cred, probe_procnum); 490 } 491#endif 492 493 nfsstats.rpcrequests++; 494tryagain: 495 timo.tv_sec = nmp->nm_timeo / NFS_HZ; 496 timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ; 497 mrep = NULL; 498 stat = CLNT_CALL_MBUF(nmp->nm_client, &ext, 499 (nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum], 500 mreq, &mrep, timo); 501 502 /* 503 * If there was a successful reply and a tprintf msg. 504 * tprintf a response. 505 */ 506 if (stat == RPC_SUCCESS) 507 error = 0; 508 else if (stat == RPC_TIMEDOUT) 509 error = ETIMEDOUT; 510 else if (stat == RPC_VERSMISMATCH) 511 error = EOPNOTSUPP; 512 else if (stat == RPC_PROGVERSMISMATCH) 513 error = EPROTONOSUPPORT; 514 else 515 error = EACCES; 516 if (error) 517 goto nfsmout; 518 519 KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n")); 520 521 /* 522 * Search for any mbufs that are not a multiple of 4 bytes long 523 * or with m_data not longword aligned. 524 * These could cause pointer alignment problems, so copy them to 525 * well aligned mbufs. 526 */ 527 error = nfs_realign(&mrep, M_DONTWAIT); 528 if (error == ENOMEM) { 529 m_freem(mrep); 530 AUTH_DESTROY(auth); 531 return (error); 532 } 533 534 md = mrep; 535 dpos = mtod(mrep, caddr_t); 536 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED); 537 if (*tl != 0) { 538 error = fxdr_unsigned(int, *tl); 539 if ((nmp->nm_flag & NFSMNT_NFSV3) && 540 error == NFSERR_TRYLATER) { 541 m_freem(mrep); 542 error = 0; 543 waituntil = time_second + nfs3_jukebox_delay; 544 while (time_second < waituntil) 545 (void)tsleep(&fake_wchan, PSOCK, "nqnfstry", 546 hz); 547 goto tryagain; 548 } 549 550 /* 551 * If the File Handle was stale, invalidate the lookup 552 * cache, just in case. 553 */ 554 if (error == ESTALE) 555 nfs_purgecache(vp); 556 /* 557 * Skip wcc data on NFS errors for now. NetApp filers 558 * return corrupt postop attrs in the wcc data for NFS 559 * err EROFS. Not sure if they could return corrupt 560 * postop attrs for others errors. 561 */ 562 if ((nmp->nm_flag & NFSMNT_NFSV3) && 563 !nfs_skip_wcc_data_onerr) { 564 *mrp = mrep; 565 *mdp = md; 566 *dposp = dpos; 567 error |= NFSERR_RETERR; 568 } else 569 m_freem(mrep); 570 goto nfsmout; 571 } 572 573#ifdef KDTRACE_HOOKS 574 if (dtrace_nfsclient_nfs23_done_probe != NULL) { 575 uint32_t probe_id; 576 int probe_procnum; 577 578 if (nmp->nm_flag & NFSMNT_NFSV3) { 579 probe_id = nfsclient_nfs3_done_probes[procnum]; 580 probe_procnum = procnum; 581 } else { 582 probe_id = nfsclient_nfs2_done_probes[procnum]; 583 probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ? 584 procnum : nfsv2_procid[procnum]; 585 } 586 if (probe_id != 0) 587 (dtrace_nfsclient_nfs23_done_probe)(probe_id, vp, 588 mreq, cred, probe_procnum, 0); 589 } 590#endif 591 m_freem(mreq); 592 *mrp = mrep; 593 *mdp = md; 594 *dposp = dpos; 595 AUTH_DESTROY(auth); 596 return (0); 597 598nfsmout: 599#ifdef KDTRACE_HOOKS 600 if (dtrace_nfsclient_nfs23_done_probe != NULL) { 601 uint32_t probe_id; 602 int probe_procnum; 603 604 if (nmp->nm_flag & NFSMNT_NFSV3) { 605 probe_id = nfsclient_nfs3_done_probes[procnum]; 606 probe_procnum = procnum; 607 } else { 608 probe_id = nfsclient_nfs2_done_probes[procnum]; 609 probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ? 610 procnum : nfsv2_procid[procnum]; 611 } 612 if (probe_id != 0) 613 (dtrace_nfsclient_nfs23_done_probe)(probe_id, vp, 614 mreq, cred, probe_procnum, error); 615 } 616#endif 617 m_freem(mreq); 618 if (auth) 619 AUTH_DESTROY(auth); 620 return (error); 621} 622 623/* 624 * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and 625 * wait for all requests to complete. This is used by forced unmounts 626 * to terminate any outstanding RPCs. 627 */ 628int 629nfs_nmcancelreqs(struct nfsmount *nmp) 630{ 631 632 if (nmp->nm_client) 633 CLNT_CLOSE(nmp->nm_client); 634 return (0); 635} 636 637/* 638 * Any signal that can interrupt an NFS operation in an intr mount 639 * should be added to this set. SIGSTOP and SIGKILL cannot be masked. 640 */ 641int nfs_sig_set[] = { 642 SIGINT, 643 SIGTERM, 644 SIGHUP, 645 SIGKILL, 646 SIGSTOP, 647 SIGQUIT 648}; 649 650/* 651 * Check to see if one of the signals in our subset is pending on 652 * the process (in an intr mount). 653 */ 654static int 655nfs_sig_pending(sigset_t set) 656{ 657 int i; 658 659 for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) 660 if (SIGISMEMBER(set, nfs_sig_set[i])) 661 return (1); 662 return (0); 663} 664 665/* 666 * The set/restore sigmask functions are used to (temporarily) overwrite 667 * the process p_sigmask during an RPC call (for example). These are also 668 * used in other places in the NFS client that might tsleep(). 669 */ 670void 671nfs_set_sigmask(struct thread *td, sigset_t *oldset) 672{ 673 sigset_t newset; 674 int i; 675 struct proc *p; 676 677 SIGFILLSET(newset); 678 if (td == NULL) 679 td = curthread; /* XXX */ 680 p = td->td_proc; 681 /* Remove the NFS set of signals from newset. */ 682 PROC_LOCK(p); 683 mtx_lock(&p->p_sigacts->ps_mtx); 684 for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) { 685 /* 686 * But make sure we leave the ones already masked 687 * by the process, i.e. remove the signal from the 688 * temporary signalmask only if it wasn't already 689 * in p_sigmask. 690 */ 691 if (!SIGISMEMBER(td->td_sigmask, nfs_sig_set[i]) && 692 !SIGISMEMBER(p->p_sigacts->ps_sigignore, nfs_sig_set[i])) 693 SIGDELSET(newset, nfs_sig_set[i]); 694 } 695 mtx_unlock(&p->p_sigacts->ps_mtx); 696 PROC_UNLOCK(p); 697 kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); 698} 699 700void 701nfs_restore_sigmask(struct thread *td, sigset_t *set) 702{ 703 if (td == NULL) 704 td = curthread; /* XXX */ 705 kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); 706} 707 708/* 709 * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the 710 * old one after msleep() returns. 711 */ 712int 713nfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, 714 char *wmesg, int timo) 715{ 716 sigset_t oldset; 717 int error; 718 struct proc *p; 719 720 if ((priority & PCATCH) == 0) 721 return msleep(ident, mtx, priority, wmesg, timo); 722 if (td == NULL) 723 td = curthread; /* XXX */ 724 nfs_set_sigmask(td, &oldset); 725 error = msleep(ident, mtx, priority, wmesg, timo); 726 nfs_restore_sigmask(td, &oldset); 727 p = td->td_proc; 728 return (error); 729} 730 731/* 732 * Test for a termination condition pending on the process. 733 * This is used for NFSMNT_INT mounts. 734 */ 735int 736nfs_sigintr(struct nfsmount *nmp, struct thread *td) 737{ 738 struct proc *p; 739 sigset_t tmpset; 740 741 /* Terminate all requests while attempting a forced unmount. */ 742 if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 743 return (EIO); 744 if (!(nmp->nm_flag & NFSMNT_INT)) 745 return (0); 746 if (td == NULL) 747 return (0); 748 p = td->td_proc; 749 PROC_LOCK(p); 750 tmpset = p->p_siglist; 751 SIGSETOR(tmpset, td->td_siglist); 752 SIGSETNAND(tmpset, td->td_sigmask); 753 mtx_lock(&p->p_sigacts->ps_mtx); 754 SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); 755 mtx_unlock(&p->p_sigacts->ps_mtx); 756 if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist)) 757 && nfs_sig_pending(tmpset)) { 758 PROC_UNLOCK(p); 759 return (EINTR); 760 } 761 PROC_UNLOCK(p); 762 return (0); 763} 764 765static int 766nfs_msg(struct thread *td, const char *server, const char *msg, int error) 767{ 768 struct proc *p; 769 770 p = td ? td->td_proc : NULL; 771 if (error) 772 tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", server, 773 msg, error); 774 else 775 tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg); 776 return (0); 777} 778 779static void 780nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg, 781 int error, int flags) 782{ 783 if (nmp == NULL) 784 return; 785 mtx_lock(&nmp->nm_mtx); 786 if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) { 787 nmp->nm_state |= NFSSTA_TIMEO; 788 mtx_unlock(&nmp->nm_mtx); 789 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 790 VQ_NOTRESP, 0); 791 } else 792 mtx_unlock(&nmp->nm_mtx); 793 mtx_lock(&nmp->nm_mtx); 794 if ((flags & NFSSTA_LOCKTIMEO) && 795 !(nmp->nm_state & NFSSTA_LOCKTIMEO)) { 796 nmp->nm_state |= NFSSTA_LOCKTIMEO; 797 mtx_unlock(&nmp->nm_mtx); 798 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 799 VQ_NOTRESPLOCK, 0); 800 } else 801 mtx_unlock(&nmp->nm_mtx); 802 nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); 803} 804 805static void 806nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, 807 int flags, int tprintfmsg) 808{ 809 if (nmp == NULL) 810 return; 811 if (tprintfmsg) 812 nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); 813 814 mtx_lock(&nmp->nm_mtx); 815 if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) { 816 nmp->nm_state &= ~NFSSTA_TIMEO; 817 mtx_unlock(&nmp->nm_mtx); 818 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 819 VQ_NOTRESP, 1); 820 } else 821 mtx_unlock(&nmp->nm_mtx); 822 823 mtx_lock(&nmp->nm_mtx); 824 if ((flags & NFSSTA_LOCKTIMEO) && 825 (nmp->nm_state & NFSSTA_LOCKTIMEO)) { 826 nmp->nm_state &= ~NFSSTA_LOCKTIMEO; 827 mtx_unlock(&nmp->nm_mtx); 828 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 829 VQ_NOTRESPLOCK, 1); 830 } else 831 mtx_unlock(&nmp->nm_mtx); 832} 833