1 /* $NetBSD: nfs_syscalls.c,v 1.40 2000/05/07 01:38:36 tsarna Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 39 */ 40 41 #include "fs_nfs.h" 42 #include "opt_nfsserver.h" 43 #include "opt_iso.h" 44 #include "opt_compat_netbsd.h" 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/file.h> 50 #include <sys/stat.h> 51 #include <sys/vnode.h> 52 #include <sys/mount.h> 53 #include <sys/proc.h> 54 #include <sys/uio.h> 55 #include <sys/malloc.h> 56 #include <sys/buf.h> 57 #include <sys/mbuf.h> 58 #include <sys/socket.h> 59 #include <sys/socketvar.h> 60 #include <sys/signalvar.h> 61 #include <sys/domain.h> 62 #include <sys/protosw.h> 63 #include <sys/namei.h> 64 #include <sys/syslog.h> 65 #include <sys/filedesc.h> 66 #include <sys/kthread.h> 67 68 #include <sys/syscallargs.h> 69 70 #include <netinet/in.h> 71 #include <netinet/tcp.h> 72 #ifdef ISO 73 #include <netiso/iso.h> 74 #endif 75 #include <nfs/xdr_subs.h> 76 #include <nfs/rpcv2.h> 77 #include <nfs/nfsproto.h> 78 #include <nfs/nfs.h> 79 #include <nfs/nfsm_subs.h> 80 #include <nfs/nfsrvcache.h> 81 #include <nfs/nfsmount.h> 82 #include <nfs/nfsnode.h> 83 #include <nfs/nqnfs.h> 84 #include <nfs/nfsrtt.h> 85 #include <nfs/nfs_var.h> 86 87 /* Global defs. */ 88 extern int32_t (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *, 89 struct nfssvc_sock *, 90 struct proc *, struct mbuf **)); 91 extern int nfs_numasync; 92 extern time_t nqnfsstarttime; 93 extern int nqsrv_writeslack; 94 extern int nfsrtton; 95 extern struct nfsstats nfsstats; 96 extern int nfsrvw_procrastinate; 97 struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; 98 int nuidhash_max = NFS_MAXUIDHASH; 99 int nfsd_waiting = 0; 100 #ifdef NFSSERVER 101 static int nfs_numnfsd = 0; 102 static int notstarted = 1; 103 static int modify_flag = 0; 104 static struct nfsdrt nfsdrt; 105 #endif 106 107 #define TRUE 1 108 #define FALSE 0 109 110 #ifdef NFS 111 static struct proc *nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 112 int nfs_niothreads = -1; /* == "0, and has never been set" */ 113 #endif 114 115 #ifdef NFSSERVER 116 static void nfsd_rt __P((int, struct nfsrv_descript *, int)); 117 #endif 118 119 /* 120 * NFS server system calls 121 */ 122 123 124 /* 125 * Nfs server pseudo system call for the nfsd's 126 * Based on the flag value it either: 127 * - adds a socket to the selection list 128 * - remains in the kernel as an nfsd 129 * - remains in the kernel as an nfsiod 130 */ 131 int 132 sys_nfssvc(p, v, retval) 133 struct proc *p; 134 void *v; 135 register_t *retval; 136 { 137 struct sys_nfssvc_args /* { 138 syscallarg(int) flag; 139 syscallarg(caddr_t) argp; 140 } */ *uap = v; 141 int error; 142 #ifdef NFS 143 struct nameidata nd; 144 struct nfsmount *nmp; 145 struct nfsd_cargs ncd; 146 #endif 147 #ifdef NFSSERVER 148 struct file *fp; 149 struct mbuf *nam; 150 struct nfsd_args nfsdarg; 151 struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 152 struct nfsd *nfsd; 153 struct nfssvc_sock *slp; 154 struct nfsuid *nuidp; 155 #endif 156 157 /* 158 * Must be super user 159 */ 160 error = suser(p->p_ucred, &p->p_acflag); 161 if(error) 162 return (error); 163 while (nfssvc_sockhead_flag & SLP_INIT) { 164 nfssvc_sockhead_flag |= SLP_WANTINIT; 165 (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 166 } 167 if (SCARG(uap, flag) & NFSSVC_BIOD) { 168 #if defined(NFS) && defined(COMPAT_14) 169 error = nfssvc_iod(p); 170 #else 171 error = ENOSYS; 172 #endif 173 } else if (SCARG(uap, flag) & NFSSVC_MNTD) { 174 #ifndef NFS 175 error = ENOSYS; 176 #else 177 error = copyin(SCARG(uap, argp), (caddr_t)&ncd, sizeof (ncd)); 178 if (error) 179 return (error); 180 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 181 ncd.ncd_dirp, p); 182 error = namei(&nd); 183 if (error) 184 return (error); 185 if ((nd.ni_vp->v_flag & VROOT) == 0) 186 error = EINVAL; 187 nmp = VFSTONFS(nd.ni_vp->v_mount); 188 vput(nd.ni_vp); 189 if (error) 190 return (error); 191 if ((nmp->nm_iflag & NFSMNT_MNTD) && 192 (SCARG(uap, flag) & NFSSVC_GOTAUTH) == 0) 193 return (0); 194 nmp->nm_iflag |= NFSMNT_MNTD; 195 error = nqnfs_clientd(nmp, p->p_ucred, &ncd, SCARG(uap, flag), 196 SCARG(uap, argp), p); 197 #endif /* NFS */ 198 } else if (SCARG(uap, flag) & NFSSVC_ADDSOCK) { 199 #ifndef NFSSERVER 200 error = ENOSYS; 201 #else 202 error = copyin(SCARG(uap, argp), (caddr_t)&nfsdarg, 203 sizeof(nfsdarg)); 204 if (error) 205 return (error); 206 /* getsock() will use the descriptor for us */ 207 error = getsock(p->p_fd, nfsdarg.sock, &fp); 208 if (error) 209 return (error); 210 /* 211 * Get the client address for connected sockets. 212 */ 213 if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 214 nam = (struct mbuf *)0; 215 else { 216 error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, 217 MT_SONAME); 218 if (error) { 219 FILE_UNUSE(fp, NULL); 220 return (error); 221 } 222 } 223 error = nfssvc_addsock(fp, nam); 224 FILE_UNUSE(fp, NULL); 225 #endif /* !NFSSERVER */ 226 } else { 227 #ifndef NFSSERVER 228 error = ENOSYS; 229 #else 230 error = copyin(SCARG(uap, argp), (caddr_t)nsd, sizeof (*nsd)); 231 if (error) 232 return (error); 233 if ((SCARG(uap, flag) & NFSSVC_AUTHIN) && 234 ((nfsd = nsd->nsd_nfsd)) != NULL && 235 (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { 236 slp = nfsd->nfsd_slp; 237 238 /* 239 * First check to see if another nfsd has already 240 * added this credential. 241 */ 242 for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; 243 nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 244 if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && 245 (!nfsd->nfsd_nd->nd_nam2 || 246 netaddr_match(NU_NETFAM(nuidp), 247 &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) 248 break; 249 } 250 if (nuidp) { 251 nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); 252 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 253 } else { 254 /* 255 * Nope, so we will. 256 */ 257 if (slp->ns_numuids < nuidhash_max) { 258 slp->ns_numuids++; 259 nuidp = (struct nfsuid *) 260 malloc(sizeof (struct nfsuid), M_NFSUID, 261 M_WAITOK); 262 } else 263 nuidp = (struct nfsuid *)0; 264 if ((slp->ns_flag & SLP_VALID) == 0) { 265 if (nuidp) 266 free((caddr_t)nuidp, M_NFSUID); 267 } else { 268 if (nuidp == (struct nfsuid *)0) { 269 nuidp = slp->ns_uidlruhead.tqh_first; 270 LIST_REMOVE(nuidp, nu_hash); 271 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 272 nu_lru); 273 if (nuidp->nu_flag & NU_NAM) 274 m_freem(nuidp->nu_nam); 275 } 276 nuidp->nu_flag = 0; 277 nuidp->nu_cr = nsd->nsd_cr; 278 if (nuidp->nu_cr.cr_ngroups > NGROUPS) 279 nuidp->nu_cr.cr_ngroups = NGROUPS; 280 nuidp->nu_cr.cr_ref = 1; 281 nuidp->nu_timestamp = nsd->nsd_timestamp; 282 nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl; 283 /* 284 * and save the session key in nu_key. 285 */ 286 memcpy(nuidp->nu_key, nsd->nsd_key, 287 sizeof(nsd->nsd_key)); 288 if (nfsd->nfsd_nd->nd_nam2) { 289 struct sockaddr_in *saddr; 290 291 saddr = mtod(nfsd->nfsd_nd->nd_nam2, 292 struct sockaddr_in *); 293 switch (saddr->sin_family) { 294 case AF_INET: 295 nuidp->nu_flag |= NU_INETADDR; 296 nuidp->nu_inetaddr = 297 saddr->sin_addr.s_addr; 298 break; 299 case AF_ISO: 300 default: 301 nuidp->nu_flag |= NU_NAM; 302 nuidp->nu_nam = m_copym( 303 nfsd->nfsd_nd->nd_nam2, 0, 304 M_COPYALL, M_WAIT); 305 break; 306 }; 307 } 308 TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 309 nu_lru); 310 LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 311 nuidp, nu_hash); 312 nfsrv_setcred(&nuidp->nu_cr, 313 &nfsd->nfsd_nd->nd_cr); 314 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 315 } 316 } 317 } 318 if ((SCARG(uap, flag) & NFSSVC_AUTHINFAIL) && 319 (nfsd = nsd->nsd_nfsd)) 320 nfsd->nfsd_flag |= NFSD_AUTHFAIL; 321 error = nfssvc_nfsd(nsd, SCARG(uap, argp), p); 322 #endif /* !NFSSERVER */ 323 } 324 if (error == EINTR || error == ERESTART) 325 error = 0; 326 return (error); 327 } 328 329 #ifdef NFSSERVER 330 /* 331 * Adds a socket to the list for servicing by nfsds. 332 */ 333 int 334 nfssvc_addsock(fp, mynam) 335 struct file *fp; 336 struct mbuf *mynam; 337 { 338 struct mbuf *m; 339 int siz; 340 struct nfssvc_sock *slp; 341 struct socket *so; 342 struct nfssvc_sock *tslp; 343 int error, s; 344 345 so = (struct socket *)fp->f_data; 346 tslp = (struct nfssvc_sock *)0; 347 /* 348 * Add it to the list, as required. 349 */ 350 if (so->so_proto->pr_protocol == IPPROTO_UDP) { 351 tslp = nfs_udpsock; 352 if (tslp->ns_flag & SLP_VALID) { 353 m_freem(mynam); 354 return (EPERM); 355 } 356 #ifdef ISO 357 } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 358 tslp = nfs_cltpsock; 359 if (tslp->ns_flag & SLP_VALID) { 360 m_freem(mynam); 361 return (EPERM); 362 } 363 #endif /* ISO */ 364 } 365 if (so->so_type == SOCK_STREAM) 366 siz = NFS_MAXPACKET + sizeof (u_long); 367 else 368 siz = NFS_MAXPACKET; 369 error = soreserve(so, siz, siz); 370 if (error) { 371 m_freem(mynam); 372 return (error); 373 } 374 375 /* 376 * Set protocol specific options { for now TCP only } and 377 * reserve some space. For datagram sockets, this can get called 378 * repeatedly for the same socket, but that isn't harmful. 379 */ 380 if (so->so_type == SOCK_STREAM) { 381 MGET(m, M_WAIT, MT_SOOPTS); 382 *mtod(m, int32_t *) = 1; 383 m->m_len = sizeof(int32_t); 384 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 385 } 386 if (so->so_proto->pr_domain->dom_family == AF_INET && 387 so->so_proto->pr_protocol == IPPROTO_TCP) { 388 MGET(m, M_WAIT, MT_SOOPTS); 389 *mtod(m, int32_t *) = 1; 390 m->m_len = sizeof(int32_t); 391 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 392 } 393 so->so_rcv.sb_flags &= ~SB_NOINTR; 394 so->so_rcv.sb_timeo = 0; 395 so->so_snd.sb_flags &= ~SB_NOINTR; 396 so->so_snd.sb_timeo = 0; 397 if (tslp) 398 slp = tslp; 399 else { 400 slp = (struct nfssvc_sock *) 401 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 402 memset((caddr_t)slp, 0, sizeof (struct nfssvc_sock)); 403 TAILQ_INIT(&slp->ns_uidlruhead); 404 TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 405 } 406 slp->ns_so = so; 407 slp->ns_nam = mynam; 408 fp->f_count++; 409 slp->ns_fp = fp; 410 s = splsoftnet(); 411 so->so_upcallarg = (caddr_t)slp; 412 so->so_upcall = nfsrv_rcv; 413 so->so_rcv.sb_flags |= SB_UPCALL; 414 slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 415 nfsrv_wakenfsd(slp); 416 splx(s); 417 return (0); 418 } 419 420 /* 421 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 422 * until it is killed by a signal. 423 */ 424 int 425 nfssvc_nfsd(nsd, argp, p) 426 struct nfsd_srvargs *nsd; 427 caddr_t argp; 428 struct proc *p; 429 { 430 struct mbuf *m; 431 int siz; 432 struct nfssvc_sock *slp; 433 struct socket *so; 434 int *solockp; 435 struct nfsd *nfsd = nsd->nsd_nfsd; 436 struct nfsrv_descript *nd = NULL; 437 struct mbuf *mreq; 438 int error = 0, cacherep, s, sotype, writes_todo; 439 u_quad_t cur_usec; 440 441 #ifndef nolint 442 cacherep = RC_DOIT; 443 writes_todo = 0; 444 #endif 445 s = splsoftnet(); 446 if (nfsd == (struct nfsd *)0) { 447 nsd->nsd_nfsd = nfsd = (struct nfsd *) 448 malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); 449 memset((caddr_t)nfsd, 0, sizeof (struct nfsd)); 450 nfsd->nfsd_procp = p; 451 TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); 452 nfs_numnfsd++; 453 } 454 p->p_holdcnt++; 455 /* 456 * Loop getting rpc requests until SIGKILL. 457 */ 458 for (;;) { 459 if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { 460 while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 461 (nfsd_head_flag & NFSD_CHECKSLP) == 0) { 462 nfsd->nfsd_flag |= NFSD_WAITING; 463 nfsd_waiting++; 464 error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, 465 "nfsd", 0); 466 nfsd_waiting--; 467 if (error) 468 goto done; 469 } 470 if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 471 (nfsd_head_flag & NFSD_CHECKSLP) != 0) { 472 for (slp = nfssvc_sockhead.tqh_first; slp != 0; 473 slp = slp->ns_chain.tqe_next) { 474 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) 475 == (SLP_VALID | SLP_DOREC)) { 476 slp->ns_flag &= ~SLP_DOREC; 477 slp->ns_sref++; 478 nfsd->nfsd_slp = slp; 479 break; 480 } 481 } 482 if (slp == 0) 483 nfsd_head_flag &= ~NFSD_CHECKSLP; 484 } 485 if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) 486 continue; 487 if (slp->ns_flag & SLP_VALID) { 488 if (slp->ns_flag & SLP_DISCONN) 489 nfsrv_zapsock(slp); 490 else if (slp->ns_flag & SLP_NEEDQ) { 491 slp->ns_flag &= ~SLP_NEEDQ; 492 (void) nfs_sndlock(&slp->ns_solock, 493 (struct nfsreq *)0); 494 nfsrv_rcv(slp->ns_so, (caddr_t)slp, 495 M_WAIT); 496 nfs_sndunlock(&slp->ns_solock); 497 } 498 error = nfsrv_dorec(slp, nfsd, &nd); 499 cur_usec = (u_quad_t)time.tv_sec * 1000000 + 500 (u_quad_t)time.tv_usec; 501 if (error && slp->ns_tq.lh_first && 502 slp->ns_tq.lh_first->nd_time <= cur_usec) { 503 error = 0; 504 cacherep = RC_DOIT; 505 writes_todo = 1; 506 } else 507 writes_todo = 0; 508 nfsd->nfsd_flag |= NFSD_REQINPROG; 509 } 510 } else { 511 error = 0; 512 slp = nfsd->nfsd_slp; 513 } 514 if (error || (slp->ns_flag & SLP_VALID) == 0) { 515 if (nd) { 516 free((caddr_t)nd, M_NFSRVDESC); 517 nd = NULL; 518 } 519 nfsd->nfsd_slp = (struct nfssvc_sock *)0; 520 nfsd->nfsd_flag &= ~NFSD_REQINPROG; 521 nfsrv_slpderef(slp); 522 continue; 523 } 524 splx(s); 525 so = slp->ns_so; 526 sotype = so->so_type; 527 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 528 solockp = &slp->ns_solock; 529 else 530 solockp = (int *)0; 531 if (nd) { 532 nd->nd_starttime = time; 533 if (nd->nd_nam2) 534 nd->nd_nam = nd->nd_nam2; 535 else 536 nd->nd_nam = slp->ns_nam; 537 538 /* 539 * Check to see if authorization is needed. 540 */ 541 if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { 542 nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; 543 nsd->nsd_haddr = mtod(nd->nd_nam, 544 struct sockaddr_in *)->sin_addr.s_addr; 545 nsd->nsd_authlen = nfsd->nfsd_authlen; 546 nsd->nsd_verflen = nfsd->nfsd_verflen; 547 if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, 548 nfsd->nfsd_authlen) && 549 !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, 550 nfsd->nfsd_verflen) && 551 !copyout((caddr_t)nsd, argp, sizeof (*nsd))) { 552 p->p_holdcnt--; 553 return (ENEEDAUTH); 554 } 555 cacherep = RC_DROPIT; 556 } else 557 cacherep = nfsrv_getcache(nd, slp, &mreq); 558 559 /* 560 * Check for just starting up for NQNFS and send 561 * fake "try again later" replies to the NQNFS clients. 562 */ 563 if (notstarted && nqnfsstarttime <= time.tv_sec) { 564 if (modify_flag) { 565 nqnfsstarttime = time.tv_sec + nqsrv_writeslack; 566 modify_flag = 0; 567 } else 568 notstarted = 0; 569 } 570 if (notstarted) { 571 if ((nd->nd_flag & ND_NQNFS) == 0) 572 cacherep = RC_DROPIT; 573 else if (nd->nd_procnum != NFSPROC_WRITE) { 574 nd->nd_procnum = NFSPROC_NOOP; 575 nd->nd_repstat = NQNFS_TRYLATER; 576 cacherep = RC_DOIT; 577 } else 578 modify_flag = 1; 579 } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { 580 nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; 581 nd->nd_procnum = NFSPROC_NOOP; 582 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 583 cacherep = RC_DOIT; 584 } 585 } 586 587 /* 588 * Loop to get all the write rpc relies that have been 589 * gathered together. 590 */ 591 do { 592 #ifdef DIAGNOSTIC 593 int lockcount; 594 #endif 595 switch (cacherep) { 596 case RC_DOIT: 597 #ifdef DIAGNOSTIC 598 /* 599 * NFS server procs should neither release 600 * locks already held, nor leave things 601 * locked. Catch this sooner, rather than 602 * later (when we try to relock something we 603 * already have locked). Careful inspection 604 * of the failing routine usually turns up the 605 * lock leak.. once we know what it is.. 606 */ 607 lockcount = p->p_locks; 608 #endif 609 if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && 610 nfsrvw_procrastinate > 0 && !notstarted)) 611 error = nfsrv_writegather(&nd, slp, 612 nfsd->nfsd_procp, &mreq); 613 else 614 error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, 615 slp, nfsd->nfsd_procp, &mreq); 616 #ifdef DIAGNOSTIC 617 if (p->p_locks != lockcount) { 618 /* 619 * If you see this panic, audit 620 * nfsrv3_procs[nd->nd_procnum] for vnode 621 * locking errors (usually, it's due to 622 * forgetting to vput() something). 623 */ 624 panic("nfsd: locking botch in op %d", 625 nd ? nd->nd_procnum : -1); 626 } 627 #endif 628 if (mreq == NULL) 629 break; 630 if (error) { 631 if (nd->nd_procnum != NQNFSPROC_VACATED) 632 nfsstats.srv_errs++; 633 nfsrv_updatecache(nd, FALSE, mreq); 634 if (nd->nd_nam2) 635 m_freem(nd->nd_nam2); 636 break; 637 } 638 nfsstats.srvrpccnt[nd->nd_procnum]++; 639 nfsrv_updatecache(nd, TRUE, mreq); 640 nd->nd_mrep = (struct mbuf *)0; 641 case RC_REPLY: 642 m = mreq; 643 siz = 0; 644 while (m) { 645 siz += m->m_len; 646 m = m->m_next; 647 } 648 if (siz <= 0 || siz > NFS_MAXPACKET) { 649 printf("mbuf siz=%d\n",siz); 650 panic("Bad nfs svc reply"); 651 } 652 m = mreq; 653 m->m_pkthdr.len = siz; 654 m->m_pkthdr.rcvif = (struct ifnet *)0; 655 /* 656 * For stream protocols, prepend a Sun RPC 657 * Record Mark. 658 */ 659 if (sotype == SOCK_STREAM) { 660 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 661 *mtod(m, u_int32_t *) = htonl(0x80000000 | siz); 662 } 663 if (solockp) 664 (void) nfs_sndlock(solockp, (struct nfsreq *)0); 665 if (slp->ns_flag & SLP_VALID) 666 error = nfs_send(so, nd->nd_nam2, m, NULL); 667 else { 668 error = EPIPE; 669 m_freem(m); 670 } 671 if (nfsrtton) 672 nfsd_rt(sotype, nd, cacherep); 673 if (nd->nd_nam2) 674 MFREE(nd->nd_nam2, m); 675 if (nd->nd_mrep) 676 m_freem(nd->nd_mrep); 677 if (error == EPIPE) 678 nfsrv_zapsock(slp); 679 if (solockp) 680 nfs_sndunlock(solockp); 681 if (error == EINTR || error == ERESTART) { 682 free((caddr_t)nd, M_NFSRVDESC); 683 nfsrv_slpderef(slp); 684 s = splsoftnet(); 685 goto done; 686 } 687 break; 688 case RC_DROPIT: 689 if (nfsrtton) 690 nfsd_rt(sotype, nd, cacherep); 691 m_freem(nd->nd_mrep); 692 m_freem(nd->nd_nam2); 693 break; 694 }; 695 if (nd) { 696 FREE((caddr_t)nd, M_NFSRVDESC); 697 nd = NULL; 698 } 699 700 /* 701 * Check to see if there are outstanding writes that 702 * need to be serviced. 703 */ 704 cur_usec = (u_quad_t)time.tv_sec * 1000000 + 705 (u_quad_t)time.tv_usec; 706 s = splsoftclock(); 707 if (slp->ns_tq.lh_first && 708 slp->ns_tq.lh_first->nd_time <= cur_usec) { 709 cacherep = RC_DOIT; 710 writes_todo = 1; 711 } else 712 writes_todo = 0; 713 splx(s); 714 } while (writes_todo); 715 s = splsoftnet(); 716 if (nfsrv_dorec(slp, nfsd, &nd)) { 717 nfsd->nfsd_flag &= ~NFSD_REQINPROG; 718 nfsd->nfsd_slp = NULL; 719 nfsrv_slpderef(slp); 720 } 721 } 722 done: 723 p->p_holdcnt--; 724 TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); 725 splx(s); 726 free((caddr_t)nfsd, M_NFSD); 727 nsd->nsd_nfsd = (struct nfsd *)0; 728 if (--nfs_numnfsd == 0) 729 nfsrv_init(TRUE); /* Reinitialize everything */ 730 return (error); 731 } 732 733 /* 734 * Shut down a socket associated with an nfssvc_sock structure. 735 * Should be called with the send lock set, if required. 736 * The trick here is to increment the sref at the start, so that the nfsds 737 * will stop using it and clear ns_flag at the end so that it will not be 738 * reassigned during cleanup. 739 */ 740 void 741 nfsrv_zapsock(slp) 742 struct nfssvc_sock *slp; 743 { 744 struct nfsuid *nuidp, *nnuidp; 745 struct nfsrv_descript *nwp, *nnwp; 746 struct socket *so; 747 struct file *fp; 748 struct mbuf *m; 749 int s; 750 751 slp->ns_flag &= ~SLP_ALLFLAGS; 752 fp = slp->ns_fp; 753 if (fp) { 754 FILE_USE(fp); 755 slp->ns_fp = (struct file *)0; 756 so = slp->ns_so; 757 so->so_upcall = NULL; 758 so->so_upcallarg = NULL; 759 so->so_rcv.sb_flags &= ~SB_UPCALL; 760 soshutdown(so, 2); 761 closef(fp, (struct proc *)0); 762 if (slp->ns_nam) 763 MFREE(slp->ns_nam, m); 764 m_freem(slp->ns_raw); 765 m_freem(slp->ns_rec); 766 for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 767 nuidp = nnuidp) { 768 nnuidp = nuidp->nu_lru.tqe_next; 769 LIST_REMOVE(nuidp, nu_hash); 770 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 771 if (nuidp->nu_flag & NU_NAM) 772 m_freem(nuidp->nu_nam); 773 free((caddr_t)nuidp, M_NFSUID); 774 } 775 s = splsoftclock(); 776 for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { 777 nnwp = nwp->nd_tq.le_next; 778 LIST_REMOVE(nwp, nd_tq); 779 free((caddr_t)nwp, M_NFSRVDESC); 780 } 781 LIST_INIT(&slp->ns_tq); 782 splx(s); 783 } 784 } 785 786 /* 787 * Derefence a server socket structure. If it has no more references and 788 * is no longer valid, you can throw it away. 789 */ 790 void 791 nfsrv_slpderef(slp) 792 struct nfssvc_sock *slp; 793 { 794 if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { 795 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 796 free((caddr_t)slp, M_NFSSVC); 797 } 798 } 799 800 /* 801 * Initialize the data structures for the server. 802 * Handshake with any new nfsds starting up to avoid any chance of 803 * corruption. 804 */ 805 void 806 nfsrv_init(terminating) 807 int terminating; 808 { 809 struct nfssvc_sock *slp, *nslp; 810 811 if (nfssvc_sockhead_flag & SLP_INIT) 812 panic("nfsd init"); 813 nfssvc_sockhead_flag |= SLP_INIT; 814 if (terminating) { 815 for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { 816 nslp = slp->ns_chain.tqe_next; 817 if (slp->ns_flag & SLP_VALID) 818 nfsrv_zapsock(slp); 819 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 820 free((caddr_t)slp, M_NFSSVC); 821 } 822 nfsrv_cleancache(); /* And clear out server cache */ 823 } else 824 nfs_pub.np_valid = 0; 825 826 TAILQ_INIT(&nfssvc_sockhead); 827 nfssvc_sockhead_flag &= ~SLP_INIT; 828 if (nfssvc_sockhead_flag & SLP_WANTINIT) { 829 nfssvc_sockhead_flag &= ~SLP_WANTINIT; 830 wakeup((caddr_t)&nfssvc_sockhead); 831 } 832 833 TAILQ_INIT(&nfsd_head); 834 nfsd_head_flag &= ~NFSD_CHECKSLP; 835 836 nfs_udpsock = (struct nfssvc_sock *) 837 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 838 memset((caddr_t)nfs_udpsock, 0, sizeof (struct nfssvc_sock)); 839 TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); 840 TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); 841 842 nfs_cltpsock = (struct nfssvc_sock *) 843 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 844 memset((caddr_t)nfs_cltpsock, 0, sizeof (struct nfssvc_sock)); 845 TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); 846 TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); 847 } 848 849 /* 850 * Add entries to the server monitor log. 851 */ 852 static void 853 nfsd_rt(sotype, nd, cacherep) 854 int sotype; 855 struct nfsrv_descript *nd; 856 int cacherep; 857 { 858 struct drt *rt; 859 860 rt = &nfsdrt.drt[nfsdrt.pos]; 861 if (cacherep == RC_DOIT) 862 rt->flag = 0; 863 else if (cacherep == RC_REPLY) 864 rt->flag = DRT_CACHEREPLY; 865 else 866 rt->flag = DRT_CACHEDROP; 867 if (sotype == SOCK_STREAM) 868 rt->flag |= DRT_TCP; 869 if (nd->nd_flag & ND_NQNFS) 870 rt->flag |= DRT_NQNFS; 871 else if (nd->nd_flag & ND_NFSV3) 872 rt->flag |= DRT_NFSV3; 873 rt->proc = nd->nd_procnum; 874 if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET) 875 rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr; 876 else 877 rt->ipadr = INADDR_ANY; 878 rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) + 879 (time.tv_usec - nd->nd_starttime.tv_usec); 880 rt->tstamp = time; 881 nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; 882 } 883 #endif /* NFSSERVER */ 884 885 #ifdef NFS 886 887 int nfs_defect = 0; 888 /* 889 * Asynchronous I/O threads for client nfs. 890 * They do read-ahead and write-behind operations on the block I/O cache. 891 * Never returns unless it fails or gets killed. 892 */ 893 894 int 895 nfssvc_iod(p) 896 struct proc *p; 897 { 898 struct buf *bp; 899 int i, myiod; 900 struct nfsmount *nmp; 901 int error = 0; 902 903 /* 904 * Assign my position or return error if too many already running 905 */ 906 myiod = -1; 907 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 908 if (nfs_asyncdaemon[i] == NULL) { 909 myiod = i; 910 break; 911 } 912 if (myiod == -1) 913 return (EBUSY); 914 nfs_asyncdaemon[myiod] = p; 915 nfs_numasync++; 916 p->p_holdcnt++; 917 /* 918 * Just loop around doin our stuff until SIGKILL 919 */ 920 for (;;) { 921 while (((nmp = nfs_iodmount[myiod]) == NULL 922 || nmp->nm_bufq.tqh_first == NULL) 923 && error == 0) { 924 if (nmp) 925 nmp->nm_bufqiods--; 926 nfs_iodwant[myiod] = p; 927 nfs_iodmount[myiod] = NULL; 928 error = tsleep((caddr_t)&nfs_iodwant[myiod], 929 PWAIT | PCATCH, "nfsidl", 0); 930 } 931 if (error) { 932 if (nmp) 933 nmp->nm_bufqiods--; 934 nfs_iodmount[myiod] = NULL; 935 break; 936 } 937 while ((bp = nmp->nm_bufq.tqh_first) != NULL) { 938 /* Take one off the front of the list */ 939 TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 940 nmp->nm_bufqlen--; 941 if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { 942 nmp->nm_bufqwant = FALSE; 943 wakeup(&nmp->nm_bufq); 944 } 945 if (bp->b_flags & B_READ) 946 (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 947 else 948 (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 949 /* 950 * If there are more than one iod on this mount, then defect 951 * so that the iods can be shared out fairly between the mounts 952 */ 953 if (nfs_defect && nmp->nm_bufqiods > 1) { 954 nfs_iodmount[myiod] = NULL; 955 nmp->nm_bufqiods--; 956 break; 957 } 958 } 959 } 960 p->p_holdcnt--; 961 nfs_asyncdaemon[myiod] = NULL; 962 nfs_numasync--; 963 964 return (error); 965 } 966 967 void 968 start_nfsio(arg) 969 void *arg; 970 { 971 nfssvc_iod(curproc); 972 973 kthread_exit(0); 974 } 975 976 void 977 nfs_getset_niothreads(set) 978 int set; 979 { 980 int i, have, start; 981 982 for (have = 0, i = 0; i < NFS_MAXASYNCDAEMON; i++) 983 if (nfs_asyncdaemon[i] != NULL) 984 have++; 985 986 if (set) { 987 /* clamp to sane range */ 988 nfs_niothreads = max(0, min(nfs_niothreads, NFS_MAXASYNCDAEMON)); 989 990 start = nfs_niothreads - have; 991 992 while (start > 0) { 993 kthread_create1(start_nfsio, NULL, NULL, "nfsio"); 994 start--; 995 } 996 997 for (i = 0; (start < 0) && (i < NFS_MAXASYNCDAEMON); i++) 998 if (nfs_asyncdaemon[i] != NULL) { 999 psignal(nfs_asyncdaemon[i], SIGKILL); 1000 start++; 1001 } 1002 } else { 1003 if (nfs_niothreads >= 0) 1004 nfs_niothreads = have; 1005 } 1006 } 1007 1008 /* 1009 * Get an authorization string for the uid by having the mount_nfs sitting 1010 * on this mount point porpous out of the kernel and do it. 1011 */ 1012 int 1013 nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) 1014 struct nfsmount *nmp; 1015 struct nfsreq *rep; 1016 struct ucred *cred; 1017 char **auth_str; 1018 int *auth_len; 1019 char *verf_str; 1020 int *verf_len; 1021 NFSKERBKEY_T key; /* return session key */ 1022 { 1023 int error = 0; 1024 1025 while ((nmp->nm_iflag & NFSMNT_WAITAUTH) == 0) { 1026 nmp->nm_iflag |= NFSMNT_WANTAUTH; 1027 (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 1028 "nfsauth1", 2 * hz); 1029 error = nfs_sigintr(nmp, rep, rep->r_procp); 1030 if (error) { 1031 nmp->nm_iflag &= ~NFSMNT_WANTAUTH; 1032 return (error); 1033 } 1034 } 1035 nmp->nm_iflag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); 1036 nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 1037 nmp->nm_authlen = RPCAUTH_MAXSIZ; 1038 nmp->nm_verfstr = verf_str; 1039 nmp->nm_verflen = *verf_len; 1040 nmp->nm_authuid = cred->cr_uid; 1041 wakeup((caddr_t)&nmp->nm_authstr); 1042 1043 /* 1044 * And wait for mount_nfs to do its stuff. 1045 */ 1046 while ((nmp->nm_iflag & NFSMNT_HASAUTH) == 0 && error == 0) { 1047 (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 1048 "nfsauth2", 2 * hz); 1049 error = nfs_sigintr(nmp, rep, rep->r_procp); 1050 } 1051 if (nmp->nm_iflag & NFSMNT_AUTHERR) { 1052 nmp->nm_iflag &= ~NFSMNT_AUTHERR; 1053 error = EAUTH; 1054 } 1055 if (error) 1056 free((caddr_t)*auth_str, M_TEMP); 1057 else { 1058 *auth_len = nmp->nm_authlen; 1059 *verf_len = nmp->nm_verflen; 1060 memcpy((caddr_t)key, (caddr_t)nmp->nm_key, sizeof (key)); 1061 } 1062 nmp->nm_iflag &= ~NFSMNT_HASAUTH; 1063 nmp->nm_iflag |= NFSMNT_WAITAUTH; 1064 if (nmp->nm_iflag & NFSMNT_WANTAUTH) { 1065 nmp->nm_iflag &= ~NFSMNT_WANTAUTH; 1066 wakeup((caddr_t)&nmp->nm_authtype); 1067 } 1068 return (error); 1069 } 1070 1071 /* 1072 * Get a nickname authenticator and verifier. 1073 */ 1074 int 1075 nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) 1076 struct nfsmount *nmp; 1077 struct ucred *cred; 1078 char **auth_str; 1079 int *auth_len; 1080 char *verf_str; 1081 int verf_len; 1082 { 1083 struct nfsuid *nuidp; 1084 u_int32_t *nickp, *verfp; 1085 struct timeval ktvin, ktvout; 1086 1087 #ifdef DIAGNOSTIC 1088 if (verf_len < (4 * NFSX_UNSIGNED)) 1089 panic("nfs_getnickauth verf too small"); 1090 #endif 1091 for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; 1092 nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 1093 if (nuidp->nu_cr.cr_uid == cred->cr_uid) 1094 break; 1095 } 1096 if (!nuidp || nuidp->nu_expire < time.tv_sec) 1097 return (EACCES); 1098 1099 /* 1100 * Move to the end of the lru list (end of lru == most recently used). 1101 */ 1102 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); 1103 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); 1104 1105 nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); 1106 *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); 1107 *nickp = txdr_unsigned(nuidp->nu_nickname); 1108 *auth_str = (char *)nickp; 1109 *auth_len = 2 * NFSX_UNSIGNED; 1110 1111 /* 1112 * Now we must encrypt the verifier and package it up. 1113 */ 1114 verfp = (u_int32_t *)verf_str; 1115 *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); 1116 if (time.tv_sec > nuidp->nu_timestamp.tv_sec || 1117 (time.tv_sec == nuidp->nu_timestamp.tv_sec && 1118 time.tv_usec > nuidp->nu_timestamp.tv_usec)) 1119 nuidp->nu_timestamp = time; 1120 else 1121 nuidp->nu_timestamp.tv_usec++; 1122 ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); 1123 ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); 1124 1125 /* 1126 * Now encrypt the timestamp verifier in ecb mode using the session 1127 * key. 1128 */ 1129 #ifdef NFSKERB 1130 XXX 1131 #endif 1132 1133 *verfp++ = ktvout.tv_sec; 1134 *verfp++ = ktvout.tv_usec; 1135 *verfp = 0; 1136 return (0); 1137 } 1138 1139 /* 1140 * Save the current nickname in a hash list entry on the mount point. 1141 */ 1142 int 1143 nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) 1144 struct nfsmount *nmp; 1145 struct ucred *cred; 1146 int len; 1147 NFSKERBKEY_T key; 1148 struct mbuf **mdp; 1149 char **dposp; 1150 struct mbuf *mrep; 1151 { 1152 struct nfsuid *nuidp; 1153 u_int32_t *tl; 1154 int32_t t1; 1155 struct mbuf *md = *mdp; 1156 struct timeval ktvin, ktvout; 1157 u_int32_t nick; 1158 char *dpos = *dposp, *cp2; 1159 int deltasec, error = 0; 1160 1161 if (len == (3 * NFSX_UNSIGNED)) { 1162 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1163 ktvin.tv_sec = *tl++; 1164 ktvin.tv_usec = *tl++; 1165 nick = fxdr_unsigned(u_int32_t, *tl); 1166 1167 /* 1168 * Decrypt the timestamp in ecb mode. 1169 */ 1170 #ifdef NFSKERB 1171 XXX 1172 #endif 1173 ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); 1174 ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); 1175 deltasec = time.tv_sec - ktvout.tv_sec; 1176 if (deltasec < 0) 1177 deltasec = -deltasec; 1178 /* 1179 * If ok, add it to the hash list for the mount point. 1180 */ 1181 if (deltasec <= NFS_KERBCLOCKSKEW) { 1182 if (nmp->nm_numuids < nuidhash_max) { 1183 nmp->nm_numuids++; 1184 nuidp = (struct nfsuid *) 1185 malloc(sizeof (struct nfsuid), M_NFSUID, 1186 M_WAITOK); 1187 } else { 1188 nuidp = nmp->nm_uidlruhead.tqh_first; 1189 LIST_REMOVE(nuidp, nu_hash); 1190 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, 1191 nu_lru); 1192 } 1193 nuidp->nu_flag = 0; 1194 nuidp->nu_cr.cr_uid = cred->cr_uid; 1195 nuidp->nu_expire = time.tv_sec + NFS_KERBTTL; 1196 nuidp->nu_timestamp = ktvout; 1197 nuidp->nu_nickname = nick; 1198 memcpy(nuidp->nu_key, key, sizeof (key)); 1199 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, 1200 nu_lru); 1201 LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), 1202 nuidp, nu_hash); 1203 } 1204 } else 1205 nfsm_adv(nfsm_rndup(len)); 1206 nfsmout: 1207 *mdp = md; 1208 *dposp = dpos; 1209 return (error); 1210 } 1211 #endif /* NFS */ 1212