nfs_nfsiod.c revision 8876
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94 37 * $Id: nfs_syscalls.c,v 1.5 1994/10/17 17:47:38 phk Exp $ 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/file.h> 44#include <sys/stat.h> 45#include <sys/vnode.h> 46#include <sys/mount.h> 47#include <sys/proc.h> 48#include <sys/uio.h> 49#include <sys/malloc.h> 50#include <sys/buf.h> 51#include <sys/mbuf.h> 52#include <sys/socket.h> 53#include <sys/socketvar.h> 54#include <sys/domain.h> 55#include <sys/protosw.h> 56#include <sys/namei.h> 57#include <sys/syslog.h> 58 59#include <netinet/in.h> 60#include <netinet/tcp.h> 61#ifdef ISO 62#include <netiso/iso.h> 63#endif 64#include <nfs/rpcv2.h> 65#include <nfs/nfsv2.h> 66#include <nfs/nfs.h> 67#include <nfs/nfsrvcache.h> 68#include <nfs/nfsmount.h> 69#include <nfs/nfsnode.h> 70#include <nfs/nqnfs.h> 71#include <nfs/nfsrtt.h> 72 73void nfsrv_zapsock __P((struct nfssvc_sock *)); 74 75/* Global defs. */ 76extern u_long nfs_prog, nfs_vers; 77extern int (*nfsrv_procs[NFS_NPROCS])(); 78extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 79extern int nfs_numasync; 80extern time_t nqnfsstarttime; 81extern int nqsrv_writeslack; 82extern int nfsrtton; 83struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; 84int nuidhash_max = NFS_MAXUIDHASH; 85static int nfs_numnfsd = 0; 86int nfsd_waiting = 0; 87static int notstarted = 1; 88static int modify_flag = 0; 89static struct nfsdrt nfsdrt; 90void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock(); 91static void nfsd_rt(); 92void nfsrv_slpderef(); 93 94#define TRUE 1 95#define FALSE 0 96 97static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 98/* 99 * NFS server system calls 100 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 101 */ 102 103/* 104 * Get file handle system call 105 */ 106struct getfh_args { 107 char *fname; 108 fhandle_t *fhp; 109}; 110int 111getfh(p, uap, retval) 112 struct proc *p; 113 register struct getfh_args *uap; 114 int *retval; 115{ 116 register struct vnode *vp; 117 fhandle_t fh; 118 int error; 119 struct nameidata nd; 120 121 /* 122 * Must be super user 123 */ 124 error = suser(p->p_ucred, &p->p_acflag); 125 if(error) 126 return (error); 127 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128 error = namei(&nd); 129 if (error) 130 return (error); 131 vp = nd.ni_vp; 132 bzero((caddr_t)&fh, sizeof(fh)); 133 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 134 error = VFS_VPTOFH(vp, &fh.fh_fid); 135 vput(vp); 136 if (error) 137 return (error); 138 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 139 return (error); 140} 141 142/* 143 * Nfs server psuedo system call for the nfsd's 144 * Based on the flag value it either: 145 * - adds a socket to the selection list 146 * - remains in the kernel as an nfsd 147 * - remains in the kernel as an nfsiod 148 */ 149struct nfssvc_args { 150 int flag; 151 caddr_t argp; 152}; 153int 154nfssvc(p, uap, retval) 155 struct proc *p; 156 register struct nfssvc_args *uap; 157 int *retval; 158{ 159 struct nameidata nd; 160 struct file *fp; 161 struct mbuf *nam; 162 struct nfsd_args nfsdarg; 163 struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 164 struct nfsd_cargs ncd; 165 struct nfsd *nfsd; 166 struct nfssvc_sock *slp; 167 struct nfsuid *nuidp; 168 struct nfsmount *nmp; 169 int error; 170 171 /* 172 * Must be super user 173 */ 174 error = suser(p->p_ucred, &p->p_acflag); 175 if(error) 176 return (error); 177 while (nfssvc_sockhead_flag & SLP_INIT) { 178 nfssvc_sockhead_flag |= SLP_WANTINIT; 179 (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 180 } 181 if (uap->flag & NFSSVC_BIOD) 182 error = nfssvc_iod(p); 183 else if (uap->flag & NFSSVC_MNTD) { 184 error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); 185 if (error) 186 return (error); 187 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 188 ncd.ncd_dirp, p); 189 error = namei(&nd); 190 if (error) 191 return (error); 192 if ((nd.ni_vp->v_flag & VROOT) == 0) 193 error = EINVAL; 194 nmp = VFSTONFS(nd.ni_vp->v_mount); 195 vput(nd.ni_vp); 196 if (error) 197 return (error); 198 if ((nmp->nm_flag & NFSMNT_MNTD) && 199 (uap->flag & NFSSVC_GOTAUTH) == 0) 200 return (0); 201 nmp->nm_flag |= NFSMNT_MNTD; 202 error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, 203 uap->argp, p); 204 } else if (uap->flag & NFSSVC_ADDSOCK) { 205 error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); 206 if (error) 207 return (error); 208 error = getsock(p->p_fd, nfsdarg.sock, &fp); 209 if (error) 210 return (error); 211 /* 212 * Get the client address for connected sockets. 213 */ 214 if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 215 nam = (struct mbuf *)0; 216 else { 217 error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, 218 MT_SONAME); 219 if (error) 220 return (error); 221 } 222 error = nfssvc_addsock(fp, nam); 223 } else { 224 error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); 225 if (error) 226 return (error); 227 if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && 228 (nfsd->nd_slp->ns_flag & SLP_VALID)) { 229 slp = nfsd->nd_slp; 230 231 /* 232 * First check to see if another nfsd has already 233 * added this credential. 234 */ 235 for (nuidp = NUIDHASH(slp, nsd->nsd_uid)->lh_first; 236 nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 237 if (nuidp->nu_uid == nsd->nsd_uid) 238 break; 239 } 240 if (!nuidp) { 241 /* 242 * Nope, so we will. 243 */ 244 if (slp->ns_numuids < nuidhash_max) { 245 slp->ns_numuids++; 246 nuidp = (struct nfsuid *) 247 malloc(sizeof (struct nfsuid), M_NFSUID, 248 M_WAITOK); 249 } else 250 nuidp = (struct nfsuid *)0; 251 if ((slp->ns_flag & SLP_VALID) == 0) { 252 if (nuidp) 253 free((caddr_t)nuidp, M_NFSUID); 254 } else { 255 if (nuidp == (struct nfsuid *)0) { 256 nuidp = slp->ns_uidlruhead.tqh_first; 257 LIST_REMOVE(nuidp, nu_hash); 258 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 259 nu_lru); 260 } 261 nuidp->nu_cr = nsd->nsd_cr; 262 if (nuidp->nu_cr.cr_ngroups > NGROUPS) 263 nuidp->nu_cr.cr_ngroups = NGROUPS; 264 nuidp->nu_cr.cr_ref = 1; 265 nuidp->nu_uid = nsd->nsd_uid; 266 TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 267 nu_lru); 268 LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 269 nuidp, nu_hash); 270 271 } 272 } 273 } 274 if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) 275 nfsd->nd_flag |= NFSD_AUTHFAIL; 276 error = nfssvc_nfsd(nsd, uap->argp, p); 277 } 278 if (error == EINTR || error == ERESTART) 279 error = 0; 280 return (error); 281} 282 283/* 284 * Adds a socket to the list for servicing by nfsds. 285 */ 286int 287nfssvc_addsock(fp, mynam) 288 struct file *fp; 289 struct mbuf *mynam; 290{ 291 register struct mbuf *m; 292 register int siz; 293 register struct nfssvc_sock *slp; 294 register struct socket *so; 295 struct nfssvc_sock *tslp; 296 int error, s; 297 298 so = (struct socket *)fp->f_data; 299 tslp = (struct nfssvc_sock *)0; 300 /* 301 * Add it to the list, as required. 302 */ 303 if (so->so_proto->pr_protocol == IPPROTO_UDP) { 304 tslp = nfs_udpsock; 305 if (tslp->ns_flag & SLP_VALID) { 306 m_freem(mynam); 307 return (EPERM); 308 } 309#ifdef ISO 310 } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 311 tslp = nfs_cltpsock; 312 if (tslp->ns_flag & SLP_VALID) { 313 m_freem(mynam); 314 return (EPERM); 315 } 316#endif /* ISO */ 317 } 318 if (so->so_type == SOCK_STREAM) 319 siz = NFS_MAXPACKET + sizeof (u_long); 320 else 321 siz = NFS_MAXPACKET; 322 error = soreserve(so, siz, siz); 323 if (error) { 324 m_freem(mynam); 325 return (error); 326 } 327 328 /* 329 * Set protocol specific options { for now TCP only } and 330 * reserve some space. For datagram sockets, this can get called 331 * repeatedly for the same socket, but that isn't harmful. 332 */ 333 if (so->so_type == SOCK_STREAM) { 334 MGET(m, M_WAIT, MT_SOOPTS); 335 *mtod(m, int *) = 1; 336 m->m_len = sizeof(int); 337 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 338 } 339 if (so->so_proto->pr_domain->dom_family == AF_INET && 340 so->so_proto->pr_protocol == IPPROTO_TCP) { 341 MGET(m, M_WAIT, MT_SOOPTS); 342 *mtod(m, int *) = 1; 343 m->m_len = sizeof(int); 344 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 345 } 346 so->so_rcv.sb_flags &= ~SB_NOINTR; 347 so->so_rcv.sb_timeo = 0; 348 so->so_snd.sb_flags &= ~SB_NOINTR; 349 so->so_snd.sb_timeo = 0; 350 if (tslp) 351 slp = tslp; 352 else { 353 slp = (struct nfssvc_sock *) 354 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 355 bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); 356 slp->ns_uidhashtbl = 357 hashinit(NUIDHASHSIZ, M_NFSSVC, &slp->ns_uidhash); 358 TAILQ_INIT(&slp->ns_uidlruhead); 359 TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 360 } 361 slp->ns_so = so; 362 slp->ns_nam = mynam; 363 fp->f_count++; 364 slp->ns_fp = fp; 365 s = splnet(); 366 so->so_upcallarg = (caddr_t)slp; 367 so->so_upcall = nfsrv_rcv; 368 slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 369 nfsrv_wakenfsd(slp); 370 splx(s); 371 return (0); 372} 373 374/* 375 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 376 * until it is killed by a signal. 377 */ 378int 379nfssvc_nfsd(nsd, argp, p) 380 struct nfsd_srvargs *nsd; 381 caddr_t argp; 382 struct proc *p; 383{ 384 register struct mbuf *m, *nam2; 385 register int siz; 386 register struct nfssvc_sock *slp; 387 register struct socket *so; 388 register int *solockp; 389 struct nfsd *nd = nsd->nsd_nfsd; 390 struct mbuf *mreq, *nam; 391 struct timeval starttime; 392 struct nfsuid *uidp; 393 int error = 0, cacherep, s; 394 int sotype; 395 396 s = splnet(); 397 if (nd == (struct nfsd *)0) { 398 nsd->nsd_nfsd = nd = (struct nfsd *) 399 malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); 400 bzero((caddr_t)nd, sizeof (struct nfsd)); 401 nd->nd_procp = p; 402 nd->nd_cr.cr_ref = 1; 403 TAILQ_INSERT_TAIL(&nfsd_head, nd, nd_chain); 404 nd->nd_nqlflag = NQL_NOVAL; 405 nfs_numnfsd++; 406 } 407 /* 408 * Loop getting rpc requests until SIGKILL. 409 */ 410 for (;;) { 411 if ((nd->nd_flag & NFSD_REQINPROG) == 0) { 412 while (nd->nd_slp == (struct nfssvc_sock *)0 && 413 (nfsd_head_flag & NFSD_CHECKSLP) == 0) { 414 nd->nd_flag |= NFSD_WAITING; 415 nfsd_waiting++; 416 error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0); 417 nfsd_waiting--; 418 if (error) 419 goto done; 420 } 421 if (nd->nd_slp == (struct nfssvc_sock *)0 && 422 (nfsd_head_flag & NFSD_CHECKSLP) != 0) { 423 for (slp = nfssvc_sockhead.tqh_first; slp != 0; 424 slp = slp->ns_chain.tqe_next) { 425 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) 426 == (SLP_VALID | SLP_DOREC)) { 427 slp->ns_flag &= ~SLP_DOREC; 428 slp->ns_sref++; 429 nd->nd_slp = slp; 430 break; 431 } 432 } 433 if (slp == 0) 434 nfsd_head_flag &= ~NFSD_CHECKSLP; 435 } 436 if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0) 437 continue; 438 if (slp->ns_flag & SLP_VALID) { 439 if (slp->ns_flag & SLP_DISCONN) 440 nfsrv_zapsock(slp); 441 else if (slp->ns_flag & SLP_NEEDQ) { 442 slp->ns_flag &= ~SLP_NEEDQ; 443 (void) nfs_sndlock(&slp->ns_solock, 444 (struct nfsreq *)0); 445 nfsrv_rcv(slp->ns_so, (caddr_t)slp, 446 M_WAIT); 447 nfs_sndunlock(&slp->ns_solock); 448 } 449 error = nfsrv_dorec(slp, nd); 450 nd->nd_flag |= NFSD_REQINPROG; 451 } 452 } else { 453 error = 0; 454 slp = nd->nd_slp; 455 } 456 if (error || (slp->ns_flag & SLP_VALID) == 0) { 457 nd->nd_slp = (struct nfssvc_sock *)0; 458 nd->nd_flag &= ~NFSD_REQINPROG; 459 nfsrv_slpderef(slp); 460 continue; 461 } 462 splx(s); 463 so = slp->ns_so; 464 sotype = so->so_type; 465 starttime = time; 466 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 467 solockp = &slp->ns_solock; 468 else 469 solockp = (int *)0; 470 /* 471 * nam == nam2 for connectionless protocols such as UDP 472 * nam2 == NULL for connection based protocols to disable 473 * recent request caching. 474 */ 475 nam2 = nd->nd_nam; 476 if (nam2) { 477 nam = nam2; 478 cacherep = RC_CHECKIT; 479 } else { 480 nam = slp->ns_nam; 481 cacherep = RC_DOIT; 482 } 483 484 /* 485 * Check to see if authorization is needed. 486 */ 487 if (nd->nd_flag & NFSD_NEEDAUTH) { 488 static int logauth = 0; 489 490 nd->nd_flag &= ~NFSD_NEEDAUTH; 491 /* 492 * Check for a mapping already installed. 493 */ 494 for (uidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first; 495 uidp != 0; uidp = uidp->nu_hash.le_next) { 496 if (uidp->nu_uid == nd->nd_cr.cr_uid) 497 break; 498 } 499 if (!uidp) { 500 nsd->nsd_uid = nd->nd_cr.cr_uid; 501 if (nam2 && logauth++ == 0) 502 log(LOG_WARNING, "Kerberized NFS using UDP\n"); 503 nsd->nsd_haddr = 504 mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 505 nsd->nsd_authlen = nd->nd_authlen; 506 if (copyout(nd->nd_authstr, nsd->nsd_authstr, 507 nd->nd_authlen) == 0 && 508 copyout((caddr_t)nsd, argp, sizeof (*nsd)) == 0) 509 return (ENEEDAUTH); 510 cacherep = RC_DROPIT; 511 } 512 } 513 if (cacherep == RC_CHECKIT) 514 cacherep = nfsrv_getcache(nam2, nd, &mreq); 515 516 /* 517 * Check for just starting up for NQNFS and send 518 * fake "try again later" replies to the NQNFS clients. 519 */ 520 if (notstarted && nqnfsstarttime <= time.tv_sec) { 521 if (modify_flag) { 522 nqnfsstarttime = time.tv_sec + nqsrv_writeslack; 523 modify_flag = 0; 524 } else 525 notstarted = 0; 526 } 527 if (notstarted) { 528 if (nd->nd_nqlflag == NQL_NOVAL) 529 cacherep = RC_DROPIT; 530 else if (nd->nd_procnum != NFSPROC_WRITE) { 531 nd->nd_procnum = NFSPROC_NOOP; 532 nd->nd_repstat = NQNFS_TRYLATER; 533 cacherep = RC_DOIT; 534 } else 535 modify_flag = 1; 536 } else if (nd->nd_flag & NFSD_AUTHFAIL) { 537 nd->nd_flag &= ~NFSD_AUTHFAIL; 538 nd->nd_procnum = NFSPROC_NOOP; 539 nd->nd_repstat = NQNFS_AUTHERR; 540 cacherep = RC_DOIT; 541 } 542 543 switch (cacherep) { 544 case RC_DOIT: 545 error = (*(nfsrv_procs[nd->nd_procnum]))(nd, 546 nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr, 547 nam, &mreq); 548 if (nd->nd_cr.cr_ref != 1) { 549 printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref); 550 panic("nfssvc cref"); 551 } 552 if (error) { 553 if (nd->nd_procnum != NQNFSPROC_VACATED) 554 nfsstats.srv_errs++; 555 if (nam2) { 556 nfsrv_updatecache(nam2, nd, FALSE, mreq); 557 m_freem(nam2); 558 } 559 break; 560 } 561 nfsstats.srvrpccnt[nd->nd_procnum]++; 562 if (nam2) 563 nfsrv_updatecache(nam2, nd, TRUE, mreq); 564 nd->nd_mrep = (struct mbuf *)0; 565 case RC_REPLY: 566 m = mreq; 567 siz = 0; 568 while (m) { 569 siz += m->m_len; 570 m = m->m_next; 571 } 572 if (siz <= 0 || siz > NFS_MAXPACKET) { 573 printf("mbuf siz=%d\n",siz); 574 panic("Bad nfs svc reply"); 575 } 576 m = mreq; 577 m->m_pkthdr.len = siz; 578 m->m_pkthdr.rcvif = (struct ifnet *)0; 579 /* 580 * For stream protocols, prepend a Sun RPC 581 * Record Mark. 582 */ 583 if (sotype == SOCK_STREAM) { 584 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 585 *mtod(m, u_long *) = htonl(0x80000000 | siz); 586 } 587 if (solockp) 588 (void) nfs_sndlock(solockp, (struct nfsreq *)0); 589 if (slp->ns_flag & SLP_VALID) 590 error = nfs_send(so, nam2, m, (struct nfsreq *)0); 591 else { 592 error = EPIPE; 593 m_freem(m); 594 } 595 if (nfsrtton) 596 nfsd_rt(&starttime, sotype, nd, nam, cacherep); 597 if (nam2) 598 MFREE(nam2, m); 599 if (nd->nd_mrep) 600 m_freem(nd->nd_mrep); 601 if (error == EPIPE) 602 nfsrv_zapsock(slp); 603 if (solockp) 604 nfs_sndunlock(solockp); 605 if (error == EINTR || error == ERESTART) { 606 nfsrv_slpderef(slp); 607 s = splnet(); 608 goto done; 609 } 610 break; 611 case RC_DROPIT: 612 if (nfsrtton) 613 nfsd_rt(&starttime, sotype, nd, nam, cacherep); 614 m_freem(nd->nd_mrep); 615 m_freem(nam2); 616 break; 617 }; 618 s = splnet(); 619 if (nfsrv_dorec(slp, nd)) { 620 nd->nd_flag &= ~NFSD_REQINPROG; 621 nd->nd_slp = (struct nfssvc_sock *)0; 622 nfsrv_slpderef(slp); 623 } 624 } 625done: 626 TAILQ_REMOVE(&nfsd_head, nd, nd_chain); 627 splx(s); 628 free((caddr_t)nd, M_NFSD); 629 nsd->nsd_nfsd = (struct nfsd *)0; 630 if (--nfs_numnfsd == 0) 631 nfsrv_init(TRUE); /* Reinitialize everything */ 632 return (error); 633} 634 635/* 636 * Asynchronous I/O daemons for client nfs. 637 * They do read-ahead and write-behind operations on the block I/O cache. 638 * Never returns unless it fails or gets killed. 639 */ 640int 641nfssvc_iod(p) 642 struct proc *p; 643{ 644 register struct buf *bp; 645 register int i, myiod; 646 int error = 0; 647 648 /* 649 * Assign my position or return error if too many already running 650 */ 651 myiod = -1; 652 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 653 if (nfs_asyncdaemon[i] == 0) { 654 nfs_asyncdaemon[i]++; 655 myiod = i; 656 break; 657 } 658 if (myiod == -1) 659 return (EBUSY); 660 nfs_numasync++; 661 /* 662 * Just loop around doin our stuff until SIGKILL 663 */ 664 for (;;) { 665 while (nfs_bufq.tqh_first == NULL && error == 0) { 666 nfs_iodwant[myiod] = p; 667 error = tsleep((caddr_t)&nfs_iodwant[myiod], 668 PWAIT | PCATCH, "nfsidl", 0); 669 } 670 while ((bp = nfs_bufq.tqh_first) != NULL) { 671 /* Take one off the front of the list */ 672 TAILQ_REMOVE(&nfs_bufq, bp, b_freelist); 673 if (bp->b_flags & B_READ) 674 (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 675 else 676 (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 677 } 678 if (error) { 679 nfs_asyncdaemon[myiod] = 0; 680 nfs_numasync--; 681 return (error); 682 } 683 } 684} 685 686/* 687 * Shut down a socket associated with an nfssvc_sock structure. 688 * Should be called with the send lock set, if required. 689 * The trick here is to increment the sref at the start, so that the nfsds 690 * will stop using it and clear ns_flag at the end so that it will not be 691 * reassigned during cleanup. 692 */ 693void 694nfsrv_zapsock(slp) 695 register struct nfssvc_sock *slp; 696{ 697 register struct nfsuid *nuidp, *nnuidp; 698 struct socket *so; 699 struct file *fp; 700 struct mbuf *m; 701 702 slp->ns_flag &= ~SLP_ALLFLAGS; 703 fp = slp->ns_fp; 704 if (fp) { 705 slp->ns_fp = (struct file *)0; 706 so = slp->ns_so; 707 so->so_upcall = NULL; 708 soshutdown(so, 2); 709 closef(fp, (struct proc *)0); 710 if (slp->ns_nam) 711 MFREE(slp->ns_nam, m); 712 m_freem(slp->ns_raw); 713 m_freem(slp->ns_rec); 714 for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 715 nuidp = nnuidp) { 716 nnuidp = nuidp->nu_lru.tqe_next; 717 LIST_REMOVE(nuidp, nu_hash); 718 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 719 free((caddr_t)nuidp, M_NFSUID); 720 } 721 } 722} 723 724/* 725 * Get an authorization string for the uid by having the mount_nfs sitting 726 * on this mount point porpous out of the kernel and do it. 727 */ 728int 729nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len) 730 register struct nfsmount *nmp; 731 struct nfsreq *rep; 732 struct ucred *cred; 733 int *auth_type; 734 char **auth_str; 735 int *auth_len; 736{ 737 int error = 0; 738 739 while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) { 740 nmp->nm_flag |= NFSMNT_WANTAUTH; 741 (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 742 "nfsauth1", 2 * hz); 743 error = nfs_sigintr(nmp, rep, rep->r_procp); 744 if (error) { 745 nmp->nm_flag &= ~NFSMNT_WANTAUTH; 746 return (error); 747 } 748 } 749 nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); 750 nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 751 nmp->nm_authuid = cred->cr_uid; 752 wakeup((caddr_t)&nmp->nm_authstr); 753 754 /* 755 * And wait for mount_nfs to do its stuff. 756 */ 757 while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) { 758 (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 759 "nfsauth2", 2 * hz); 760 error = nfs_sigintr(nmp, rep, rep->r_procp); 761 } 762 if (nmp->nm_flag & NFSMNT_AUTHERR) { 763 nmp->nm_flag &= ~NFSMNT_AUTHERR; 764 error = EAUTH; 765 } 766 if (error) 767 free((caddr_t)*auth_str, M_TEMP); 768 else { 769 *auth_type = nmp->nm_authtype; 770 *auth_len = nmp->nm_authlen; 771 } 772 nmp->nm_flag &= ~NFSMNT_HASAUTH; 773 nmp->nm_flag |= NFSMNT_WAITAUTH; 774 if (nmp->nm_flag & NFSMNT_WANTAUTH) { 775 nmp->nm_flag &= ~NFSMNT_WANTAUTH; 776 wakeup((caddr_t)&nmp->nm_authtype); 777 } 778 return (error); 779} 780 781/* 782 * Derefence a server socket structure. If it has no more references and 783 * is no longer valid, you can throw it away. 784 */ 785void 786nfsrv_slpderef(slp) 787 register struct nfssvc_sock *slp; 788{ 789 if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { 790 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 791 free((caddr_t)slp, M_NFSSVC); 792 } 793} 794 795/* 796 * Initialize the data structures for the server. 797 * Handshake with any new nfsds starting up to avoid any chance of 798 * corruption. 799 */ 800void 801nfsrv_init(terminating) 802 int terminating; 803{ 804 register struct nfssvc_sock *slp, *nslp; 805 806 if (nfssvc_sockhead_flag & SLP_INIT) 807 panic("nfsd init"); 808 nfssvc_sockhead_flag |= SLP_INIT; 809 if (terminating) { 810 for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { 811 nslp = slp->ns_chain.tqe_next; 812 if (slp->ns_flag & SLP_VALID) 813 nfsrv_zapsock(slp); 814 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 815 free((caddr_t)slp, M_NFSSVC); 816 } 817 nfsrv_cleancache(); /* And clear out server cache */ 818 } 819 820 TAILQ_INIT(&nfssvc_sockhead); 821 nfssvc_sockhead_flag &= ~SLP_INIT; 822 if (nfssvc_sockhead_flag & SLP_WANTINIT) { 823 nfssvc_sockhead_flag &= ~SLP_WANTINIT; 824 wakeup((caddr_t)&nfssvc_sockhead); 825 } 826 827 TAILQ_INIT(&nfsd_head); 828 nfsd_head_flag &= ~NFSD_CHECKSLP; 829 830 nfs_udpsock = (struct nfssvc_sock *) 831 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 832 bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); 833 nfs_udpsock->ns_uidhashtbl = 834 hashinit(NUIDHASHSIZ, M_NFSSVC, &nfs_udpsock->ns_uidhash); 835 TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); 836 TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); 837 838 nfs_cltpsock = (struct nfssvc_sock *) 839 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 840 bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); 841 nfs_cltpsock->ns_uidhashtbl = 842 hashinit(NUIDHASHSIZ, M_NFSSVC, &nfs_cltpsock->ns_uidhash); 843 TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); 844 TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); 845} 846 847/* 848 * Add entries to the server monitor log. 849 */ 850static void 851nfsd_rt(startp, sotype, nd, nam, cacherep) 852 struct timeval *startp; 853 int sotype; 854 register struct nfsd *nd; 855 struct mbuf *nam; 856 int cacherep; 857{ 858 register struct drt *rt; 859 860 rt = &nfsdrt.drt[nfsdrt.pos]; 861 if (cacherep == RC_DOIT) 862 rt->flag = 0; 863 else if (cacherep == RC_REPLY) 864 rt->flag = DRT_CACHEREPLY; 865 else 866 rt->flag = DRT_CACHEDROP; 867 if (sotype == SOCK_STREAM) 868 rt->flag |= DRT_TCP; 869 if (nd->nd_nqlflag != NQL_NOVAL) 870 rt->flag |= DRT_NQNFS; 871 rt->proc = nd->nd_procnum; 872 if (mtod(nam, struct sockaddr *)->sa_family == AF_INET) 873 rt->ipadr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 874 else 875 rt->ipadr = INADDR_ANY; 876 rt->resptime = ((time.tv_sec - startp->tv_sec) * 1000000) + 877 (time.tv_usec - startp->tv_usec); 878 rt->tstamp = time; 879 nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; 880} 881