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