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