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