nfs_krpc.c revision 195203
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 195203 2009-06-30 19:10:17Z dfr $"); 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_realign_test; 91static int nfs_realign_count; 92static int nfs_bufpackets = 4; 93static int nfs_reconnects; 94static int nfs3_jukebox_delay = 10; 95static int nfs_skip_wcc_data_onerr = 1; 96static int fake_wchan; 97 98SYSCTL_DECL(_vfs_nfs); 99 100SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, 101 "Number of realign tests done"); 102SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, 103 "Number of mbuf realignments done"); 104SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, 105 "Buffer reservation size 2 < x < 64"); 106SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, 107 "Number of times the nfs client has had to reconnect"); 108SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0, 109 "Number of seconds to delay a retry after receiving EJUKEBOX"); 110SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0, 111 "Disable weak cache consistency checking when server returns an error"); 112 113static void nfs_down(struct nfsmount *, struct thread *, const char *, 114 int, int); 115static void nfs_up(struct nfsmount *, struct thread *, const char *, 116 int, int); 117static int nfs_msg(struct thread *, const char *, const char *, int); 118 119extern int nfsv2_procid[]; 120 121struct nfs_cached_auth { 122 int ca_refs; /* refcount, including 1 from the cache */ 123 uid_t ca_uid; /* uid that corresponds to this auth */ 124 AUTH *ca_auth; /* RPC auth handle */ 125}; 126 127/* 128 * RTT estimator 129 */ 130 131static enum nfs_rto_timer_t nfs_proct[NFS_NPROCS] = { 132 NFS_DEFAULT_TIMER, /* NULL */ 133 NFS_GETATTR_TIMER, /* GETATTR */ 134 NFS_DEFAULT_TIMER, /* SETATTR */ 135 NFS_LOOKUP_TIMER, /* LOOKUP */ 136 NFS_GETATTR_TIMER, /* ACCESS */ 137 NFS_READ_TIMER, /* READLINK */ 138 NFS_READ_TIMER, /* READ */ 139 NFS_WRITE_TIMER, /* WRITE */ 140 NFS_DEFAULT_TIMER, /* CREATE */ 141 NFS_DEFAULT_TIMER, /* MKDIR */ 142 NFS_DEFAULT_TIMER, /* SYMLINK */ 143 NFS_DEFAULT_TIMER, /* MKNOD */ 144 NFS_DEFAULT_TIMER, /* REMOVE */ 145 NFS_DEFAULT_TIMER, /* RMDIR */ 146 NFS_DEFAULT_TIMER, /* RENAME */ 147 NFS_DEFAULT_TIMER, /* LINK */ 148 NFS_READ_TIMER, /* READDIR */ 149 NFS_READ_TIMER, /* READDIRPLUS */ 150 NFS_DEFAULT_TIMER, /* FSSTAT */ 151 NFS_DEFAULT_TIMER, /* FSINFO */ 152 NFS_DEFAULT_TIMER, /* PATHCONF */ 153 NFS_DEFAULT_TIMER, /* COMMIT */ 154 NFS_DEFAULT_TIMER, /* NOOP */ 155}; 156 157/* 158 * Choose the correct RTT timer for this NFS procedure. 159 */ 160static inline enum nfs_rto_timer_t 161nfs_rto_timer(u_int32_t procnum) 162{ 163 return nfs_proct[procnum]; 164} 165 166/* 167 * Initialize the RTT estimator state for a new mount point. 168 */ 169static void 170nfs_init_rtt(struct nfsmount *nmp) 171{ 172 int i; 173 174 for (i = 0; i < NFS_MAX_TIMER; i++) { 175 nmp->nm_timers[i].rt_srtt = hz; 176 nmp->nm_timers[i].rt_deviate = 0; 177 nmp->nm_timers[i].rt_rtxcur = hz; 178 } 179} 180 181/* 182 * Initialize sockets and congestion for a new NFS connection. 183 * We do not free the sockaddr if error. 184 */ 185int 186nfs_connect(struct nfsmount *nmp) 187{ 188 int rcvreserve, sndreserve; 189 int pktscale; 190 struct sockaddr *saddr; 191 struct ucred *origcred; 192 struct thread *td = curthread; 193 CLIENT *client; 194 struct netconfig *nconf; 195 rpcvers_t vers; 196 int one = 1, retries; 197 198 /* 199 * We need to establish the socket using the credentials of 200 * the mountpoint. Some parts of this process (such as 201 * sobind() and soconnect()) will use the curent thread's 202 * credential instead of the socket credential. To work 203 * around this, temporarily change the current thread's 204 * credential to that of the mountpoint. 205 * 206 * XXX: It would be better to explicitly pass the correct 207 * credential to sobind() and soconnect(). 208 */ 209 origcred = td->td_ucred; 210 td->td_ucred = nmp->nm_mountp->mnt_cred; 211 saddr = nmp->nm_nam; 212 213 vers = NFS_VER2; 214 if (nmp->nm_flag & NFSMNT_NFSV3) 215 vers = NFS_VER3; 216 else if (nmp->nm_flag & NFSMNT_NFSV4) 217 vers = NFS_VER4; 218 if (saddr->sa_family == AF_INET) 219 if (nmp->nm_sotype == SOCK_DGRAM) 220 nconf = getnetconfigent("udp"); 221 else 222 nconf = getnetconfigent("tcp"); 223 else 224 if (nmp->nm_sotype == SOCK_DGRAM) 225 nconf = getnetconfigent("udp6"); 226 else 227 nconf = getnetconfigent("tcp6"); 228 229 /* 230 * Get buffer reservation size from sysctl, but impose reasonable 231 * limits. 232 */ 233 pktscale = nfs_bufpackets; 234 if (pktscale < 2) 235 pktscale = 2; 236 if (pktscale > 64) 237 pktscale = 64; 238 mtx_lock(&nmp->nm_mtx); 239 if (nmp->nm_sotype == SOCK_DGRAM) { 240 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale; 241 rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + 242 NFS_MAXPKTHDR) * pktscale; 243 } else if (nmp->nm_sotype == SOCK_SEQPACKET) { 244 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale; 245 rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + 246 NFS_MAXPKTHDR) * pktscale; 247 } else { 248 if (nmp->nm_sotype != SOCK_STREAM) 249 panic("nfscon sotype"); 250 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + 251 sizeof (u_int32_t)) * pktscale; 252 rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + 253 sizeof (u_int32_t)) * pktscale; 254 } 255 mtx_unlock(&nmp->nm_mtx); 256 257 client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers, 258 sndreserve, rcvreserve); 259 CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq"); 260 if (nmp->nm_flag & NFSMNT_INT) 261 CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one); 262 if (nmp->nm_flag & NFSMNT_RESVPORT) 263 CLNT_CONTROL(client, CLSET_PRIVPORT, &one); 264 if (nmp->nm_flag & NFSMNT_SOFT) 265 retries = nmp->nm_retry; 266 else 267 retries = INT_MAX; 268 CLNT_CONTROL(client, CLSET_RETRIES, &retries); 269 270 mtx_lock(&nmp->nm_mtx); 271 if (nmp->nm_client) { 272 /* 273 * Someone else already connected. 274 */ 275 CLNT_RELEASE(client); 276 } else { 277 nmp->nm_client = client; 278 } 279 280 /* 281 * Protocols that do not require connections may be optionally left 282 * unconnected for servers that reply from a port other than NFS_PORT. 283 */ 284 if (!(nmp->nm_flag & NFSMNT_NOCONN)) { 285 mtx_unlock(&nmp->nm_mtx); 286 CLNT_CONTROL(client, CLSET_CONNECT, &one); 287 } else { 288 mtx_unlock(&nmp->nm_mtx); 289 } 290 291 /* Restore current thread's credentials. */ 292 td->td_ucred = origcred; 293 294 mtx_lock(&nmp->nm_mtx); 295 /* Initialize other non-zero congestion variables */ 296 nfs_init_rtt(nmp); 297 mtx_unlock(&nmp->nm_mtx); 298 return (0); 299} 300 301/* 302 * NFS disconnect. Clean up and unlink. 303 */ 304void 305nfs_disconnect(struct nfsmount *nmp) 306{ 307 CLIENT *client; 308 309 mtx_lock(&nmp->nm_mtx); 310 if (nmp->nm_client) { 311 client = nmp->nm_client; 312 nmp->nm_client = NULL; 313 mtx_unlock(&nmp->nm_mtx); 314#ifdef KGSSAPI 315 rpc_gss_secpurge(client); 316#endif 317 CLNT_CLOSE(client); 318 CLNT_RELEASE(client); 319 } else { 320 mtx_unlock(&nmp->nm_mtx); 321 } 322} 323 324void 325nfs_safedisconnect(struct nfsmount *nmp) 326{ 327 328 nfs_disconnect(nmp); 329} 330 331static AUTH * 332nfs_getauth(struct nfsmount *nmp, struct ucred *cred) 333{ 334#ifdef KGSSAPI 335 rpc_gss_service_t svc; 336 AUTH *auth; 337#endif 338 339 switch (nmp->nm_secflavor) { 340#ifdef KGSSAPI 341 case RPCSEC_GSS_KRB5: 342 case RPCSEC_GSS_KRB5I: 343 case RPCSEC_GSS_KRB5P: 344 if (!nmp->nm_mech_oid) { 345 if (!rpc_gss_mech_to_oid("kerberosv5", 346 &nmp->nm_mech_oid)) 347 return (NULL); 348 } 349 if (nmp->nm_secflavor == RPCSEC_GSS_KRB5) 350 svc = rpc_gss_svc_none; 351 else if (nmp->nm_secflavor == RPCSEC_GSS_KRB5I) 352 svc = rpc_gss_svc_integrity; 353 else 354 svc = rpc_gss_svc_privacy; 355 auth = rpc_gss_secfind(nmp->nm_client, cred, 356 nmp->nm_principal, nmp->nm_mech_oid, svc); 357 if (auth) 358 return (auth); 359 /* fallthrough */ 360#endif 361 case AUTH_SYS: 362 default: 363 return (authunix_create(cred)); 364 365 } 366} 367 368/* 369 * Callback from the RPC code to generate up/down notifications. 370 */ 371 372struct nfs_feedback_arg { 373 struct nfsmount *nf_mount; 374 int nf_lastmsg; /* last tprintf */ 375 int nf_tprintfmsg; 376 struct thread *nf_td; 377}; 378 379static void 380nfs_feedback(int type, int proc, void *arg) 381{ 382 struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg; 383 struct nfsmount *nmp = nf->nf_mount; 384 struct timeval now; 385 386 getmicrouptime(&now); 387 388 switch (type) { 389 case FEEDBACK_REXMIT2: 390 case FEEDBACK_RECONNECT: 391 if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) { 392 nfs_down(nmp, nf->nf_td, 393 "not responding", 0, NFSSTA_TIMEO); 394 nf->nf_tprintfmsg = TRUE; 395 nf->nf_lastmsg = now.tv_sec; 396 } 397 break; 398 399 case FEEDBACK_OK: 400 nfs_up(nf->nf_mount, nf->nf_td, 401 "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg); 402 break; 403 } 404} 405 406/* 407 * nfs_realign: 408 * 409 * Check for badly aligned mbuf data and realign by copying the unaligned 410 * portion of the data into a new mbuf chain and freeing the portions 411 * of the old chain that were replaced. 412 * 413 * We cannot simply realign the data within the existing mbuf chain 414 * because the underlying buffers may contain other rpc commands and 415 * we cannot afford to overwrite them. 416 * 417 * We would prefer to avoid this situation entirely. The situation does 418 * not occur with NFS/UDP and is supposed to only occassionally occur 419 * with TCP. Use vfs.nfs.realign_count and realign_test to check this. 420 * 421 */ 422static int 423nfs_realign(struct mbuf **pm, int hsiz) 424{ 425 struct mbuf *m, *n; 426 int off, space; 427 428 ++nfs_realign_test; 429 while ((m = *pm) != NULL) { 430 if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { 431 /* 432 * NB: we can't depend on m_pkthdr.len to help us 433 * decide what to do here. May not be worth doing 434 * the m_length calculation as m_copyback will 435 * expand the mbuf chain below as needed. 436 */ 437 space = m_length(m, NULL); 438 if (space >= MINCLSIZE) { 439 /* NB: m_copyback handles space > MCLBYTES */ 440 n = m_getcl(M_DONTWAIT, MT_DATA, 0); 441 } else 442 n = m_get(M_DONTWAIT, MT_DATA); 443 if (n == NULL) 444 return (ENOMEM); 445 /* 446 * Align the remainder of the mbuf chain. 447 */ 448 n->m_len = 0; 449 off = 0; 450 while (m != NULL) { 451 m_copyback(n, off, m->m_len, mtod(m, caddr_t)); 452 off += m->m_len; 453 m = m->m_next; 454 } 455 m_freem(*pm); 456 *pm = n; 457 ++nfs_realign_count; 458 break; 459 } 460 pm = &m->m_next; 461 } 462 return (0); 463} 464 465/* 466 * nfs_request - goes something like this 467 * - fill in request struct 468 * - links it into list 469 * - calls nfs_send() for first transmit 470 * - calls nfs_receive() to get reply 471 * - break down rpc header and return with nfs reply pointed to 472 * by mrep or error 473 * nb: always frees up mreq mbuf list 474 */ 475int 476nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum, 477 struct thread *td, struct ucred *cred, struct mbuf **mrp, 478 struct mbuf **mdp, caddr_t *dposp) 479{ 480 struct mbuf *mrep; 481 u_int32_t *tl; 482 struct nfsmount *nmp; 483 struct mbuf *md; 484 time_t waituntil; 485 caddr_t dpos; 486 int error = 0; 487 struct timeval now; 488 AUTH *auth = NULL; 489 enum nfs_rto_timer_t timer; 490 struct nfs_feedback_arg nf; 491 struct rpc_callextra ext; 492 enum clnt_stat stat; 493 struct timeval timo; 494 495 /* Reject requests while attempting a forced unmount. */ 496 if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) { 497 m_freem(mreq); 498 return (ESTALE); 499 } 500 nmp = VFSTONFS(vp->v_mount); 501 bzero(&nf, sizeof(struct nfs_feedback_arg)); 502 nf.nf_mount = nmp; 503 nf.nf_td = td; 504 getmicrouptime(&now); 505 nf.nf_lastmsg = now.tv_sec - 506 ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay)); 507 508 /* 509 * XXX if not already connected call nfs_connect now. Longer 510 * term, change nfs_mount to call nfs_connect unconditionally 511 * and let clnt_reconnect_create handle reconnects. 512 */ 513 if (!nmp->nm_client) 514 nfs_connect(nmp); 515 516 auth = nfs_getauth(nmp, cred); 517 if (!auth) { 518 m_freem(mreq); 519 return (EACCES); 520 } 521 bzero(&ext, sizeof(ext)); 522 ext.rc_auth = auth; 523 524 ext.rc_feedback = nfs_feedback; 525 ext.rc_feedback_arg = &nf; 526 527 /* 528 * Use a conservative timeout for RPCs other than getattr, 529 * lookup, read or write. The justification for doing "other" 530 * this way is that these RPCs happen so infrequently that 531 * timer est. would probably be stale. Also, since many of 532 * these RPCs are non-idempotent, a conservative timeout is 533 * desired. 534 */ 535 timer = nfs_rto_timer(procnum); 536 if (timer != NFS_DEFAULT_TIMER) { 537 ext.rc_timers = &nmp->nm_timers[timer - 1]; 538 } else { 539 ext.rc_timers = NULL; 540 } 541 542#ifdef KDTRACE_HOOKS 543 if (dtrace_nfsclient_nfs23_start_probe != NULL) { 544 uint32_t probe_id; 545 int probe_procnum; 546 547 if (nmp->nm_flag & NFSMNT_NFSV3) { 548 probe_id = nfsclient_nfs3_start_probes[procnum]; 549 probe_procnum = procnum; 550 } else { 551 probe_id = nfsclient_nfs2_start_probes[procnum]; 552 probe_procnum = nfsv2_procid[procnum]; 553 } 554 if (probe_id != 0) 555 (dtrace_nfsclient_nfs23_start_probe)(probe_id, vp, 556 mreq, cred, probe_procnum); 557 } 558#endif 559 560 nfsstats.rpcrequests++; 561tryagain: 562 timo.tv_sec = nmp->nm_timeo / NFS_HZ; 563 timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ; 564 mrep = NULL; 565 stat = CLNT_CALL_MBUF(nmp->nm_client, &ext, 566 (nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum], 567 mreq, &mrep, timo); 568 569 /* 570 * If there was a successful reply and a tprintf msg. 571 * tprintf a response. 572 */ 573 if (stat == RPC_SUCCESS) { 574 error = 0; 575 } else if (stat == RPC_TIMEDOUT) { 576 error = ETIMEDOUT; 577 } else if (stat == RPC_VERSMISMATCH) { 578 error = EOPNOTSUPP; 579 } else if (stat == RPC_PROGVERSMISMATCH) { 580 error = EPROTONOSUPPORT; 581 } else { 582 error = EACCES; 583 } 584 if (error) 585 goto nfsmout; 586 587 KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n")); 588 589 /* 590 * Search for any mbufs that are not a multiple of 4 bytes long 591 * or with m_data not longword aligned. 592 * These could cause pointer alignment problems, so copy them to 593 * well aligned mbufs. 594 */ 595 error = nfs_realign(&mrep, 2 * NFSX_UNSIGNED); 596 if (error == ENOMEM) { 597 m_freem(mrep); 598 AUTH_DESTROY(auth); 599 return (error); 600 } 601 602 md = mrep; 603 dpos = mtod(mrep, caddr_t); 604 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED); 605 if (*tl != 0) { 606 error = fxdr_unsigned(int, *tl); 607 if ((nmp->nm_flag & NFSMNT_NFSV3) && 608 error == NFSERR_TRYLATER) { 609 m_freem(mrep); 610 error = 0; 611 waituntil = time_second + nfs3_jukebox_delay; 612 while (time_second < waituntil) { 613 (void) tsleep(&fake_wchan, PSOCK, "nqnfstry", hz); 614 } 615 goto tryagain; 616 } 617 618 /* 619 * If the File Handle was stale, invalidate the lookup 620 * cache, just in case. 621 */ 622 if (error == ESTALE) 623 nfs_purgecache(vp); 624 /* 625 * Skip wcc data on NFS errors for now. NetApp filers 626 * return corrupt postop attrs in the wcc data for NFS 627 * err EROFS. Not sure if they could return corrupt 628 * postop attrs for others errors. 629 */ 630 if ((nmp->nm_flag & NFSMNT_NFSV3) && !nfs_skip_wcc_data_onerr) { 631 *mrp = mrep; 632 *mdp = md; 633 *dposp = dpos; 634 error |= NFSERR_RETERR; 635 } else 636 m_freem(mrep); 637 goto nfsmout; 638 } 639 640#ifdef KDTRACE_HOOKS 641 if (dtrace_nfsclient_nfs23_done_probe != NULL) { 642 uint32_t probe_id; 643 int probe_procnum; 644 645 if (nmp->nm_flag & NFSMNT_NFSV3) { 646 probe_id = nfsclient_nfs3_done_probes[procnum]; 647 probe_procnum = procnum; 648 } else { 649 probe_id = nfsclient_nfs2_done_probes[procnum]; 650 probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ? 651 procnum : nfsv2_procid[procnum]; 652 } 653 if (probe_id != 0) 654 (dtrace_nfsclient_nfs23_done_probe)(probe_id, vp, 655 mreq, cred, probe_procnum, 0); 656 } 657#endif 658 m_freem(mreq); 659 *mrp = mrep; 660 *mdp = md; 661 *dposp = dpos; 662 AUTH_DESTROY(auth); 663 return (0); 664 665nfsmout: 666#ifdef KDTRACE_HOOKS 667 if (dtrace_nfsclient_nfs23_done_probe != NULL) { 668 uint32_t probe_id; 669 int probe_procnum; 670 671 if (nmp->nm_flag & NFSMNT_NFSV3) { 672 probe_id = nfsclient_nfs3_done_probes[procnum]; 673 probe_procnum = procnum; 674 } else { 675 probe_id = nfsclient_nfs2_done_probes[procnum]; 676 probe_procnum = (nmp->nm_flag & NFSMNT_NFSV3) ? 677 procnum : nfsv2_procid[procnum]; 678 } 679 if (probe_id != 0) 680 (dtrace_nfsclient_nfs23_done_probe)(probe_id, vp, 681 mreq, cred, probe_procnum, error); 682 } 683#endif 684 m_freem(mreq); 685 if (auth) 686 AUTH_DESTROY(auth); 687 return (error); 688} 689 690/* 691 * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and 692 * wait for all requests to complete. This is used by forced unmounts 693 * to terminate any outstanding RPCs. 694 */ 695int 696nfs_nmcancelreqs(struct nfsmount *nmp) 697{ 698 699 if (nmp->nm_client) 700 CLNT_CLOSE(nmp->nm_client); 701 return (0); 702} 703 704/* 705 * Any signal that can interrupt an NFS operation in an intr mount 706 * should be added to this set. SIGSTOP and SIGKILL cannot be masked. 707 */ 708int nfs_sig_set[] = { 709 SIGINT, 710 SIGTERM, 711 SIGHUP, 712 SIGKILL, 713 SIGSTOP, 714 SIGQUIT 715}; 716 717/* 718 * Check to see if one of the signals in our subset is pending on 719 * the process (in an intr mount). 720 */ 721static int 722nfs_sig_pending(sigset_t set) 723{ 724 int i; 725 726 for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) 727 if (SIGISMEMBER(set, nfs_sig_set[i])) 728 return (1); 729 return (0); 730} 731 732/* 733 * The set/restore sigmask functions are used to (temporarily) overwrite 734 * the process p_sigmask during an RPC call (for example). These are also 735 * used in other places in the NFS client that might tsleep(). 736 */ 737void 738nfs_set_sigmask(struct thread *td, sigset_t *oldset) 739{ 740 sigset_t newset; 741 int i; 742 struct proc *p; 743 744 SIGFILLSET(newset); 745 if (td == NULL) 746 td = curthread; /* XXX */ 747 p = td->td_proc; 748 /* Remove the NFS set of signals from newset */ 749 PROC_LOCK(p); 750 mtx_lock(&p->p_sigacts->ps_mtx); 751 for (i = 0 ; i < sizeof(nfs_sig_set)/sizeof(int) ; i++) { 752 /* 753 * But make sure we leave the ones already masked 754 * by the process, ie. remove the signal from the 755 * temporary signalmask only if it wasn't already 756 * in p_sigmask. 757 */ 758 if (!SIGISMEMBER(td->td_sigmask, nfs_sig_set[i]) && 759 !SIGISMEMBER(p->p_sigacts->ps_sigignore, nfs_sig_set[i])) 760 SIGDELSET(newset, nfs_sig_set[i]); 761 } 762 mtx_unlock(&p->p_sigacts->ps_mtx); 763 PROC_UNLOCK(p); 764 kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); 765} 766 767void 768nfs_restore_sigmask(struct thread *td, sigset_t *set) 769{ 770 if (td == NULL) 771 td = curthread; /* XXX */ 772 kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); 773} 774 775/* 776 * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the 777 * old one after msleep() returns. 778 */ 779int 780nfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo) 781{ 782 sigset_t oldset; 783 int error; 784 struct proc *p; 785 786 if ((priority & PCATCH) == 0) 787 return msleep(ident, mtx, priority, wmesg, timo); 788 if (td == NULL) 789 td = curthread; /* XXX */ 790 nfs_set_sigmask(td, &oldset); 791 error = msleep(ident, mtx, priority, wmesg, timo); 792 nfs_restore_sigmask(td, &oldset); 793 p = td->td_proc; 794 return (error); 795} 796 797/* 798 * Test for a termination condition pending on the process. 799 * This is used for NFSMNT_INT mounts. 800 */ 801int 802nfs_sigintr(struct nfsmount *nmp, struct thread *td) 803{ 804 struct proc *p; 805 sigset_t tmpset; 806 807 /* Terminate all requests while attempting a forced unmount. */ 808 if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 809 return (EIO); 810 if (!(nmp->nm_flag & NFSMNT_INT)) 811 return (0); 812 if (td == NULL) 813 return (0); 814 p = td->td_proc; 815 PROC_LOCK(p); 816 tmpset = p->p_siglist; 817 SIGSETOR(tmpset, td->td_siglist); 818 SIGSETNAND(tmpset, td->td_sigmask); 819 mtx_lock(&p->p_sigacts->ps_mtx); 820 SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); 821 mtx_unlock(&p->p_sigacts->ps_mtx); 822 if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist)) 823 && nfs_sig_pending(tmpset)) { 824 PROC_UNLOCK(p); 825 return (EINTR); 826 } 827 PROC_UNLOCK(p); 828 return (0); 829} 830 831static int 832nfs_msg(struct thread *td, const char *server, const char *msg, int error) 833{ 834 struct proc *p; 835 836 p = td ? td->td_proc : NULL; 837 if (error) { 838 tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", server, 839 msg, error); 840 } else { 841 tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg); 842 } 843 return (0); 844} 845 846static void 847nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg, 848 int error, int flags) 849{ 850 if (nmp == NULL) 851 return; 852 mtx_lock(&nmp->nm_mtx); 853 if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) { 854 nmp->nm_state |= NFSSTA_TIMEO; 855 mtx_unlock(&nmp->nm_mtx); 856 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 857 VQ_NOTRESP, 0); 858 } else 859 mtx_unlock(&nmp->nm_mtx); 860 mtx_lock(&nmp->nm_mtx); 861 if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) { 862 nmp->nm_state |= NFSSTA_LOCKTIMEO; 863 mtx_unlock(&nmp->nm_mtx); 864 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 865 VQ_NOTRESPLOCK, 0); 866 } else 867 mtx_unlock(&nmp->nm_mtx); 868 nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); 869} 870 871static void 872nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, 873 int flags, int tprintfmsg) 874{ 875 if (nmp == NULL) 876 return; 877 if (tprintfmsg) { 878 nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); 879 } 880 881 mtx_lock(&nmp->nm_mtx); 882 if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) { 883 nmp->nm_state &= ~NFSSTA_TIMEO; 884 mtx_unlock(&nmp->nm_mtx); 885 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 886 VQ_NOTRESP, 1); 887 } else 888 mtx_unlock(&nmp->nm_mtx); 889 890 mtx_lock(&nmp->nm_mtx); 891 if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) { 892 nmp->nm_state &= ~NFSSTA_LOCKTIMEO; 893 mtx_unlock(&nmp->nm_mtx); 894 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 895 VQ_NOTRESPLOCK, 1); 896 } else 897 mtx_unlock(&nmp->nm_mtx); 898} 899