| 1 | /* |
| 2 | * Copyright (c) 1989 The Regents of the University of California. |
| 3 | * 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 | * %sccs.include.redist.c% |
| 9 | * |
| 10 | * @(#)nfs_syscalls.c 7.33 (Berkeley) %G% |
| 11 | */ |
| 12 | |
| 13 | #include "param.h" |
| 14 | #include "systm.h" |
| 15 | #include "kernel.h" |
| 16 | #include "file.h" |
| 17 | #include "stat.h" |
| 18 | #include "vnode.h" |
| 19 | #include "mount.h" |
| 20 | #include "proc.h" |
| 21 | #include "uio.h" |
| 22 | #include "malloc.h" |
| 23 | #include "buf.h" |
| 24 | #include "mbuf.h" |
| 25 | #include "socket.h" |
| 26 | #include "socketvar.h" |
| 27 | #include "domain.h" |
| 28 | #include "protosw.h" |
| 29 | #include "namei.h" |
| 30 | #include "netinet/in.h" |
| 31 | #include "netinet/tcp.h" |
| 32 | #ifdef ISO |
| 33 | #include "netiso/iso.h" |
| 34 | #endif |
| 35 | #include "machine/endian.h" |
| 36 | #include "rpcv2.h" |
| 37 | #include "nfsv2.h" |
| 38 | #include "nfs.h" |
| 39 | #include "nfsrvcache.h" |
| 40 | #include "nfsmount.h" |
| 41 | #include "nqnfs.h" |
| 42 | |
| 43 | /* Global defs. */ |
| 44 | extern u_long nfs_prog, nfs_vers; |
| 45 | extern int (*nfsrv_procs[NFS_NPROCS])(); |
| 46 | extern struct buf *nfs_bqueuehead, **nfs_bqueuetail; |
| 47 | extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; |
| 48 | extern int nfs_numasync; |
| 49 | extern time_t nqnfsstarttime; |
| 50 | extern struct nfsrv_req nsrvq_head; |
| 51 | extern struct nfsd nfsd_head; |
| 52 | extern int nqsrv_writeslack; |
| 53 | struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; |
| 54 | int nuidhash_max = NFS_MAXUIDHASH; |
| 55 | static int nfs_numnfsd = 0; |
| 56 | int nfsd_waiting = 0; |
| 57 | static int notstarted = 1; |
| 58 | static int modify_flag = 0; |
| 59 | void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock(); |
| 60 | void nfsrv_slpderef(), nfsrv_init(); |
| 61 | |
| 62 | #define TRUE 1 |
| 63 | #define FALSE 0 |
| 64 | |
| 65 | static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; |
| 66 | /* |
| 67 | * NFS server system calls |
| 68 | * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c |
| 69 | */ |
| 70 | |
| 71 | /* |
| 72 | * Get file handle system call |
| 73 | */ |
| 74 | struct getfh_args { |
| 75 | char *fname; |
| 76 | fhandle_t *fhp; |
| 77 | }; |
| 78 | getfh(p, uap, retval) |
| 79 | struct proc *p; |
| 80 | register struct getfh_args *uap; |
| 81 | int *retval; |
| 82 | { |
| 83 | register struct vnode *vp; |
| 84 | fhandle_t fh; |
| 85 | int error; |
| 86 | struct nameidata nd; |
| 87 | |
| 88 | /* |
| 89 | * Must be super user |
| 90 | */ |
| 91 | if (error = suser(p->p_ucred, &p->p_acflag)) |
| 92 | return (error); |
| 93 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); |
| 94 | if (error = namei(&nd)) |
| 95 | return (error); |
| 96 | vp = nd.ni_vp; |
| 97 | bzero((caddr_t)&fh, sizeof(fh)); |
| 98 | fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; |
| 99 | error = VFS_VPTOFH(vp, &fh.fh_fid); |
| 100 | vput(vp); |
| 101 | if (error) |
| 102 | return (error); |
| 103 | error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); |
| 104 | return (error); |
| 105 | } |
| 106 | |
| 107 | static struct nfssvc_sock nfssvc_sockhead; |
| 108 | |
| 109 | #define SLP_DEREFFREE 0x100 |
| 110 | #define SLP_CLRFREE 0x200 |
| 111 | |
| 112 | /* |
| 113 | * Nfs server psuedo system call for the nfsd's |
| 114 | * Based on the flag value it either: |
| 115 | * - adds a socket to the selection list |
| 116 | * - remains in the kernel as an nfsd |
| 117 | * - remains in the kernel as an nfsiod |
| 118 | */ |
| 119 | struct nfssvc_args { |
| 120 | int flag; |
| 121 | caddr_t argp; |
| 122 | }; |
| 123 | nfssvc(p, uap, retval) |
| 124 | struct proc *p; |
| 125 | register struct nfssvc_args *uap; |
| 126 | int *retval; |
| 127 | { |
| 128 | struct nameidata nd; |
| 129 | struct file *fp; |
| 130 | struct mbuf *nam; |
| 131 | struct nfsd_args nfsdarg; |
| 132 | struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; |
| 133 | struct nfsd_cargs ncd; |
| 134 | struct nfsd *nfsd; |
| 135 | struct nfssvc_sock *slp; |
| 136 | struct nfsuid *nuidp, **nuh; |
| 137 | struct nfsmount *nmp; |
| 138 | int error; |
| 139 | |
| 140 | /* |
| 141 | * Must be super user |
| 142 | */ |
| 143 | if (error = suser(p->p_ucred, &p->p_acflag)) |
| 144 | return (error); |
| 145 | while (nfssvc_sockhead.ns_flag & SLP_INIT) { |
| 146 | nfssvc_sockhead.ns_flag |= SLP_WANTINIT; |
| 147 | (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); |
| 148 | } |
| 149 | if (uap->flag & NFSSVC_BIOD) |
| 150 | error = nfssvc_iod(p); |
| 151 | else if (uap->flag & NFSSVC_MNTD) { |
| 152 | if (error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd))) |
| 153 | return (error); |
| 154 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, |
| 155 | ncd.ncd_dirp, p); |
| 156 | if (error = namei(&nd)) |
| 157 | return (error); |
| 158 | if ((nd.ni_vp->v_flag & VROOT) == 0) |
| 159 | error = EINVAL; |
| 160 | nmp = VFSTONFS(nd.ni_vp->v_mount); |
| 161 | vput(nd.ni_vp); |
| 162 | if (error) |
| 163 | return (error); |
| 164 | else if (nmp->nm_flag & NFSMNT_MNTD) |
| 165 | return (0); |
| 166 | nmp->nm_flag |= NFSMNT_MNTD; |
| 167 | error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, |
| 168 | uap->argp, p); |
| 169 | } else if (uap->flag & NFSSVC_ADDSOCK) { |
| 170 | if (error = copyin(uap->argp, (caddr_t)&nfsdarg, |
| 171 | sizeof(nfsdarg))) |
| 172 | return (error); |
| 173 | if (error = getsock(p->p_fd, nfsdarg.sock, &fp)) |
| 174 | return (error); |
| 175 | /* |
| 176 | * Get the client address for connected sockets. |
| 177 | */ |
| 178 | if (nfsdarg.name == NULL || nfsdarg.namelen == 0) |
| 179 | nam = (struct mbuf *)0; |
| 180 | else if (error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, |
| 181 | MT_SONAME)) |
| 182 | return (error); |
| 183 | error = nfssvc_addsock(fp, nam); |
| 184 | } else { |
| 185 | if (error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd))) |
| 186 | return (error); |
| 187 | if ((uap->flag & NFSSVC_AUTHIN) && (nfsd = nsd->nsd_nfsd) && |
| 188 | (nfsd->nd_slp->ns_flag & SLP_VALID)) { |
| 189 | slp = nfsd->nd_slp; |
| 190 | if (slp->ns_numuids < nuidhash_max) { |
| 191 | slp->ns_numuids++; |
| 192 | nuidp = (struct nfsuid *) |
| 193 | malloc(sizeof (struct nfsuid), M_NFSUID, M_WAITOK); |
| 194 | } else |
| 195 | nuidp = (struct nfsuid *)0; |
| 196 | if ((slp->ns_flag & SLP_VALID) == 0) { |
| 197 | if (nuidp) |
| 198 | free((caddr_t)nuidp, M_NFSUID); |
| 199 | } else { |
| 200 | if (nuidp == (struct nfsuid *)0) { |
| 201 | nuidp = slp->ns_lruprev; |
| 202 | remque(nuidp); |
| 203 | if (nuidp->nu_hprev) |
| 204 | nuidp->nu_hprev->nu_hnext = nuidp->nu_hnext; |
| 205 | if (nuidp->nu_hnext) |
| 206 | nuidp->nu_hnext->nu_hprev = nuidp->nu_hprev; |
| 207 | } |
| 208 | nuidp->nu_cr = nsd->nsd_cr; |
| 209 | nuidp->nu_cr.cr_ref = 1; |
| 210 | nuidp->nu_uid = nsd->nsd_uid; |
| 211 | insque(nuidp, (struct nfsuid *)slp); |
| 212 | nuh = &slp->ns_uidh[NUIDHASH(nsd->nsd_uid)]; |
| 213 | if (nuidp->nu_hnext = *nuh) |
| 214 | nuidp->nu_hnext->nu_hprev = nuidp; |
| 215 | nuidp->nu_hprev = (struct nfsuid *)0; |
| 216 | *nuh = nuidp; |
| 217 | } |
| 218 | } |
| 219 | if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) |
| 220 | nfsd->nd_flag |= NFSD_AUTHFAIL; |
| 221 | error = nfssvc_nfsd(nsd, uap->argp, p); |
| 222 | } |
| 223 | if (error == EINTR || error == ERESTART) |
| 224 | error = 0; |
| 225 | return (error); |
| 226 | } |
| 227 | |
| 228 | /* |
| 229 | * Adds a socket to the list for servicing by nfsds. |
| 230 | */ |
| 231 | nfssvc_addsock(fp, mynam) |
| 232 | struct file *fp; |
| 233 | struct mbuf *mynam; |
| 234 | { |
| 235 | register struct mbuf *m; |
| 236 | register int siz; |
| 237 | register struct nfssvc_sock *slp; |
| 238 | register struct socket *so; |
| 239 | struct nfssvc_sock *tslp; |
| 240 | int error, s; |
| 241 | |
| 242 | so = (struct socket *)fp->f_data; |
| 243 | tslp = (struct nfssvc_sock *)0; |
| 244 | /* |
| 245 | * Add it to the list, as required. |
| 246 | */ |
| 247 | if (so->so_proto->pr_protocol == IPPROTO_UDP) { |
| 248 | tslp = nfs_udpsock; |
| 249 | if (tslp->ns_flag & SLP_VALID) { |
| 250 | m_freem(mynam); |
| 251 | return (EPERM); |
| 252 | } |
| 253 | #ifdef ISO |
| 254 | } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { |
| 255 | tslp = nfs_cltpsock; |
| 256 | if (tslp->ns_flag & SLP_VALID) { |
| 257 | m_freem(mynam); |
| 258 | return (EPERM); |
| 259 | } |
| 260 | #endif /* ISO */ |
| 261 | } |
| 262 | if (so->so_type == SOCK_STREAM) |
| 263 | siz = NFS_MAXPACKET + sizeof (u_long); |
| 264 | else |
| 265 | siz = NFS_MAXPACKET; |
| 266 | if (error = soreserve(so, siz, siz)) { |
| 267 | m_freem(mynam); |
| 268 | return (error); |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | * Set protocol specific options { for now TCP only } and |
| 273 | * reserve some space. For datagram sockets, this can get called |
| 274 | * repeatedly for the same socket, but that isn't harmful. |
| 275 | */ |
| 276 | if (so->so_type == SOCK_STREAM) { |
| 277 | MGET(m, M_WAIT, MT_SOOPTS); |
| 278 | *mtod(m, int *) = 1; |
| 279 | m->m_len = sizeof(int); |
| 280 | sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); |
| 281 | } |
| 282 | if (so->so_proto->pr_domain->dom_family == AF_INET && |
| 283 | so->so_proto->pr_protocol == IPPROTO_TCP) { |
| 284 | MGET(m, M_WAIT, MT_SOOPTS); |
| 285 | *mtod(m, int *) = 1; |
| 286 | m->m_len = sizeof(int); |
| 287 | sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); |
| 288 | } |
| 289 | so->so_rcv.sb_flags &= ~SB_NOINTR; |
| 290 | so->so_rcv.sb_timeo = 0; |
| 291 | so->so_snd.sb_flags &= ~SB_NOINTR; |
| 292 | so->so_snd.sb_timeo = 0; |
| 293 | if (tslp) |
| 294 | slp = tslp; |
| 295 | else { |
| 296 | slp = (struct nfssvc_sock *) |
| 297 | malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); |
| 298 | printf("Alloc nfssvc_sock 0x%x\n", slp); |
| 299 | bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); |
| 300 | slp->ns_prev = nfssvc_sockhead.ns_prev; |
| 301 | slp->ns_prev->ns_next = slp; |
| 302 | slp->ns_next = &nfssvc_sockhead; |
| 303 | nfssvc_sockhead.ns_prev = slp; |
| 304 | slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp; |
| 305 | } |
| 306 | slp->ns_so = so; |
| 307 | slp->ns_nam = mynam; |
| 308 | fp->f_count++; |
| 309 | slp->ns_fp = fp; |
| 310 | s = splnet(); |
| 311 | so->so_upcallarg = (caddr_t)slp; |
| 312 | so->so_upcall = nfsrv_rcv; |
| 313 | slp->ns_flag = (SLP_VALID | SLP_NEEDQ); |
| 314 | nfsrv_wakenfsd(slp); |
| 315 | splx(s); |
| 316 | return (0); |
| 317 | } |
| 318 | |
| 319 | /* |
| 320 | * Called by nfssvc() for nfsds. Just loops around servicing rpc requests |
| 321 | * until it is killed by a signal. |
| 322 | */ |
| 323 | nfssvc_nfsd(nsd, argp, p) |
| 324 | struct nfsd_srvargs *nsd; |
| 325 | caddr_t argp; |
| 326 | struct proc *p; |
| 327 | { |
| 328 | register struct mbuf *m, *nam2; |
| 329 | register int siz; |
| 330 | register struct nfssvc_sock *slp; |
| 331 | register struct socket *so; |
| 332 | register int *solockp; |
| 333 | struct nfssvc_sock *oslp; |
| 334 | struct nfsd *nd = nsd->nsd_nfsd; |
| 335 | struct mbuf *mreq, *nam; |
| 336 | int error, cacherep, s; |
| 337 | int sotype; |
| 338 | |
| 339 | s = splnet(); |
| 340 | if (nd == (struct nfsd *)0) { |
| 341 | nsd->nsd_nfsd = nd = (struct nfsd *) |
| 342 | malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); |
| 343 | bzero((caddr_t)nd, sizeof (struct nfsd)); |
| 344 | nd->nd_procp = p; |
| 345 | nd->nd_cr.cr_ref = 1; |
| 346 | insque(nd, &nfsd_head); |
| 347 | nfs_numnfsd++; |
| 348 | } |
| 349 | /* |
| 350 | * Loop getting rpc requests until SIGKILL. |
| 351 | */ |
| 352 | for (;;) { |
| 353 | if ((nd->nd_flag & NFSD_REQINPROG) == 0) { |
| 354 | while (nd->nd_slp == (struct nfssvc_sock *)0 && |
| 355 | (nfsd_head.nd_flag & NFSD_CHECKSLP) == 0) { |
| 356 | nd->nd_flag |= NFSD_WAITING; |
| 357 | nfsd_waiting++; |
| 358 | error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0); |
| 359 | nfsd_waiting--; |
| 360 | if (error) |
| 361 | goto done; |
| 362 | } |
| 363 | if (nd->nd_slp == (struct nfssvc_sock *)0 && |
| 364 | (nfsd_head.nd_flag & NFSD_CHECKSLP)) { |
| 365 | slp = nfssvc_sockhead.ns_next; |
| 366 | while (slp != &nfssvc_sockhead) { |
| 367 | if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) |
| 368 | == (SLP_VALID | SLP_DOREC)) { |
| 369 | slp->ns_flag &= ~SLP_DOREC; |
| 370 | slp->ns_sref++; |
| 371 | nd->nd_slp = slp; |
| 372 | break; |
| 373 | } |
| 374 | slp = slp->ns_next; |
| 375 | } |
| 376 | if (slp == &nfssvc_sockhead) |
| 377 | nfsd_head.nd_flag &= ~NFSD_CHECKSLP; |
| 378 | } |
| 379 | if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0) |
| 380 | continue; |
| 381 | if (slp->ns_flag & SLP_VALID) { |
| 382 | if (slp->ns_flag & SLP_DISCONN) |
| 383 | nfsrv_zapsock(slp); |
| 384 | else if (slp->ns_flag & SLP_NEEDQ) { |
| 385 | slp->ns_flag &= ~SLP_NEEDQ; |
| 386 | (void) nfs_sndlock(&slp->ns_solock, |
| 387 | (struct nfsreq *)0); |
| 388 | nfsrv_rcv(slp->ns_so, (caddr_t)slp, |
| 389 | M_WAIT); |
| 390 | nfs_sndunlock(&slp->ns_solock); |
| 391 | } |
| 392 | error = nfsrv_dorec(slp, nd); |
| 393 | nd->nd_flag |= NFSD_REQINPROG; |
| 394 | } |
| 395 | } else { |
| 396 | error = 0; |
| 397 | slp = nd->nd_slp; |
| 398 | } |
| 399 | if (error || (slp->ns_flag & SLP_VALID) == 0) { |
| 400 | nd->nd_slp = (struct nfssvc_sock *)0; |
| 401 | nd->nd_flag &= ~NFSD_REQINPROG; |
| 402 | nfsrv_slpderef(slp); |
| 403 | continue; |
| 404 | } |
| 405 | splx(s); |
| 406 | so = slp->ns_so; |
| 407 | sotype = so->so_type; |
| 408 | |
| 409 | /* |
| 410 | * Check to see if authorization is needed. |
| 411 | */ |
| 412 | if (nd->nd_flag & NFSD_NEEDAUTH) { |
| 413 | nd->nd_flag &= ~NFSD_NEEDAUTH; |
| 414 | nsd->nsd_uid = nd->nd_cr.cr_uid; |
| 415 | nsd->nsd_haddr = |
| 416 | mtod(slp->ns_nam, struct sockaddr_in *)->sin_addr.s_addr; |
| 417 | nsd->nsd_authlen = nd->nd_authlen; |
| 418 | (void) copyout(nd->nd_authstr, nsd->nsd_authstr, |
| 419 | nd->nd_authlen); |
| 420 | (void) copyout((caddr_t)nsd, argp, sizeof (*nsd)); |
| 421 | return (ENEEDAUTH); |
| 422 | } |
| 423 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) |
| 424 | solockp = &slp->ns_solock; |
| 425 | else |
| 426 | solockp = (int *)0; |
| 427 | /* |
| 428 | * nam == nam2 for connectionless protocols such as UDP |
| 429 | * nam2 == NULL for connection based protocols to disable |
| 430 | * recent request caching. |
| 431 | */ |
| 432 | nam2 = nd->nd_nam; |
| 433 | |
| 434 | if (nam2) { |
| 435 | nam = nam2; |
| 436 | cacherep = nfsrv_getcache(nam2, nd, &mreq); |
| 437 | } else { |
| 438 | nam = slp->ns_nam; |
| 439 | cacherep = RC_DOIT; |
| 440 | } |
| 441 | |
| 442 | /* |
| 443 | * Check for just starting up for NQNFS and send |
| 444 | * fake "try again later" replies to the NQNFS clients. |
| 445 | */ |
| 446 | if (notstarted && nqnfsstarttime <= time.tv_sec) { |
| 447 | if (modify_flag) { |
| 448 | nqnfsstarttime = time.tv_sec + nqsrv_writeslack; |
| 449 | modify_flag = 0; |
| 450 | } else |
| 451 | notstarted = 0; |
| 452 | } |
| 453 | if (notstarted) { |
| 454 | if (nd->nd_nqlflag == NQL_NOVAL) |
| 455 | cacherep = RC_DROPIT; |
| 456 | else if (nd->nd_procnum != NFSPROC_WRITE) { |
| 457 | nd->nd_procnum = NFSPROC_NOOP; |
| 458 | nd->nd_repstat = NQNFS_TRYLATER; |
| 459 | cacherep = RC_DOIT; |
| 460 | } else |
| 461 | modify_flag = 1; |
| 462 | } else if (nd->nd_flag & NFSD_AUTHFAIL) { |
| 463 | nd->nd_flag &= ~NFSD_AUTHFAIL; |
| 464 | nd->nd_procnum = NFSPROC_NOOP; |
| 465 | nd->nd_repstat = NQNFS_AUTHERR; |
| 466 | cacherep = RC_DOIT; |
| 467 | } |
| 468 | |
| 469 | switch (cacherep) { |
| 470 | case RC_DOIT: |
| 471 | error = (*(nfsrv_procs[nd->nd_procnum]))(nd, |
| 472 | nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr, |
| 473 | nam, &mreq); |
| 474 | if (nd->nd_cr.cr_ref != 1) { |
| 475 | printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref); |
| 476 | panic("nfssvc cref"); |
| 477 | } |
| 478 | if (error) { |
| 479 | if (nd->nd_procnum != NQNFSPROC_VACATED) |
| 480 | nfsstats.srv_errs++; |
| 481 | if (nam2) { |
| 482 | nfsrv_updatecache(nam2, nd, FALSE, mreq); |
| 483 | m_freem(nam2); |
| 484 | } |
| 485 | break; |
| 486 | } |
| 487 | nfsstats.srvrpccnt[nd->nd_procnum]++; |
| 488 | if (nam2) |
| 489 | nfsrv_updatecache(nam2, nd, TRUE, mreq); |
| 490 | nd->nd_mrep = (struct mbuf *)0; |
| 491 | case RC_REPLY: |
| 492 | m = mreq; |
| 493 | siz = 0; |
| 494 | while (m) { |
| 495 | siz += m->m_len; |
| 496 | m = m->m_next; |
| 497 | } |
| 498 | if (siz <= 0 || siz > NFS_MAXPACKET) { |
| 499 | printf("mbuf siz=%d\n",siz); |
| 500 | panic("Bad nfs svc reply"); |
| 501 | } |
| 502 | m = mreq; |
| 503 | m->m_pkthdr.len = siz; |
| 504 | m->m_pkthdr.rcvif = (struct ifnet *)0; |
| 505 | /* |
| 506 | * For stream protocols, prepend a Sun RPC |
| 507 | * Record Mark. |
| 508 | */ |
| 509 | if (sotype == SOCK_STREAM) { |
| 510 | M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); |
| 511 | *mtod(m, u_long *) = htonl(0x80000000 | siz); |
| 512 | } |
| 513 | if (solockp) |
| 514 | (void) nfs_sndlock(solockp, (struct nfsreq *)0); |
| 515 | if (slp->ns_flag & SLP_VALID) |
| 516 | error = nfs_send(so, nam2, m, (struct nfsreq *)0); |
| 517 | else { |
| 518 | error = EPIPE; |
| 519 | m_freem(m); |
| 520 | } |
| 521 | if (nam2) |
| 522 | MFREE(nam2, m); |
| 523 | if (nd->nd_mrep) |
| 524 | m_freem(nd->nd_mrep); |
| 525 | if (error == EPIPE) |
| 526 | nfsrv_zapsock(slp); |
| 527 | if (solockp) |
| 528 | nfs_sndunlock(solockp); |
| 529 | if (error == EINTR || error == ERESTART) { |
| 530 | nfsrv_slpderef(slp); |
| 531 | s = splnet(); |
| 532 | goto done; |
| 533 | } |
| 534 | break; |
| 535 | case RC_DROPIT: |
| 536 | m_freem(nd->nd_mrep); |
| 537 | m_freem(nam2); |
| 538 | break; |
| 539 | }; |
| 540 | s = splnet(); |
| 541 | if (nfsrv_dorec(slp, nd)) { |
| 542 | nd->nd_flag &= ~NFSD_REQINPROG; |
| 543 | nd->nd_slp = (struct nfssvc_sock *)0; |
| 544 | nfsrv_slpderef(slp); |
| 545 | } |
| 546 | #ifdef DIAGNOSTIC |
| 547 | if (p->p_spare[0]) |
| 548 | panic("nfssvc: M_NAMEI"); |
| 549 | if (p->p_spare[1]) |
| 550 | panic("nfssvc: STARTSAVE"); |
| 551 | #endif |
| 552 | } |
| 553 | done: |
| 554 | remque(nd); |
| 555 | splx(s); |
| 556 | free((caddr_t)nd, M_NFSD); |
| 557 | nsd->nsd_nfsd = (struct nfsd *)0; |
| 558 | if (--nfs_numnfsd == 0) |
| 559 | nfsrv_init(TRUE); /* Reinitialize everything */ |
| 560 | return (error); |
| 561 | } |
| 562 | |
| 563 | /* |
| 564 | * Asynchronous I/O daemons for client nfs. |
| 565 | * These babies just pretend to be disk interrupt service routines. |
| 566 | * They are mainly here for read ahead/write behind. |
| 567 | * Never returns unless it fails or gets killed. |
| 568 | */ |
| 569 | nfssvc_iod(p) |
| 570 | struct proc *p; |
| 571 | { |
| 572 | register struct buf *bp, *dp; |
| 573 | register int i, myiod; |
| 574 | int error = 0; |
| 575 | |
| 576 | /* |
| 577 | * Assign my position or return error if too many already running |
| 578 | */ |
| 579 | myiod = -1; |
| 580 | for (i = 0; i < NFS_MAXASYNCDAEMON; i++) |
| 581 | if (nfs_asyncdaemon[i] == 0) { |
| 582 | nfs_asyncdaemon[i]++; |
| 583 | myiod = i; |
| 584 | break; |
| 585 | } |
| 586 | if (myiod == -1) |
| 587 | return (EBUSY); |
| 588 | nfs_numasync++; |
| 589 | /* |
| 590 | * Just loop around doin our stuff until SIGKILL |
| 591 | */ |
| 592 | for (;;) { |
| 593 | while (nfs_bqueuehead == NULL && error == 0) { |
| 594 | nfs_iodwant[myiod] = p; |
| 595 | error = tsleep((caddr_t)&nfs_iodwant[myiod], |
| 596 | PWAIT | PCATCH, "nfsidl", 0); |
| 597 | nfs_iodwant[myiod] = (struct proc *)0; |
| 598 | } |
| 599 | while ((bp = nfs_bqueuehead) != NULL) { |
| 600 | /* Take one off the front of the list */ |
| 601 | if (dp = bp->b_actf) |
| 602 | dp->b_actb = bp->b_actb; |
| 603 | else |
| 604 | nfs_bqueuetail = bp->b_actb; |
| 605 | *bp->b_actb = dp; |
| 606 | (void) nfs_doio(bp, (struct proc *)0); |
| 607 | } |
| 608 | if (error) { |
| 609 | nfs_asyncdaemon[myiod] = 0; |
| 610 | nfs_numasync--; |
| 611 | return (error); |
| 612 | } |
| 613 | } |
| 614 | } |
| 615 | |
| 616 | /* |
| 617 | * Shut down a socket associated with an nfssvc_sock structure. |
| 618 | * Should be called with the send lock set, if required. |
| 619 | * The trick here is to increment the sref at the start, so that the nfsds |
| 620 | * will stop using it and clear ns_flag at the end so that it will not be |
| 621 | * reassigned during cleanup. |
| 622 | */ |
| 623 | nfsrv_zapsock(slp) |
| 624 | register struct nfssvc_sock *slp; |
| 625 | { |
| 626 | register struct nfsuid *nuidp, *onuidp; |
| 627 | register int i; |
| 628 | struct socket *so; |
| 629 | struct file *fp; |
| 630 | struct mbuf *m; |
| 631 | |
| 632 | slp->ns_flag &= ~SLP_ALLFLAGS; |
| 633 | if (fp = slp->ns_fp) { |
| 634 | slp->ns_fp = (struct file *)0; |
| 635 | so = slp->ns_so; |
| 636 | so->so_upcall = NULL; |
| 637 | soshutdown(so, 2); |
| 638 | closef(fp, (struct proc *)0); |
| 639 | if (slp->ns_nam) |
| 640 | MFREE(slp->ns_nam, m); |
| 641 | m_freem(slp->ns_raw); |
| 642 | m_freem(slp->ns_rec); |
| 643 | nuidp = slp->ns_lrunext; |
| 644 | while (nuidp != (struct nfsuid *)slp) { |
| 645 | onuidp = nuidp; |
| 646 | nuidp = nuidp->nu_lrunext; |
| 647 | free((caddr_t)onuidp, M_NFSUID); |
| 648 | } |
| 649 | slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp; |
| 650 | for (i = 0; i < NUIDHASHSIZ; i++) |
| 651 | slp->ns_uidh[i] = (struct nfsuid *)0; |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | /* |
| 656 | * Get an authorization string for the uid by having the mount_nfs sitting |
| 657 | * on this mount point porpous out of the kernel and do it. |
| 658 | */ |
| 659 | nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len) |
| 660 | register struct nfsmount *nmp; |
| 661 | struct nfsreq *rep; |
| 662 | struct ucred *cred; |
| 663 | int *auth_type; |
| 664 | char **auth_str; |
| 665 | int *auth_len; |
| 666 | { |
| 667 | int error = 0; |
| 668 | |
| 669 | while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) { |
| 670 | nmp->nm_flag |= NFSMNT_WANTAUTH; |
| 671 | (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, |
| 672 | "nfsauth1", 2 * hz); |
| 673 | if (error = nfs_sigintr(nmp, rep, rep->r_procp)) { |
| 674 | nmp->nm_flag &= ~NFSMNT_WANTAUTH; |
| 675 | return (error); |
| 676 | } |
| 677 | } |
| 678 | nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); |
| 679 | nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); |
| 680 | nmp->nm_authuid = cred->cr_uid; |
| 681 | wakeup((caddr_t)&nmp->nm_authstr); |
| 682 | |
| 683 | /* |
| 684 | * And wait for mount_nfs to do its stuff. |
| 685 | */ |
| 686 | while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) { |
| 687 | (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, |
| 688 | "nfsauth2", 2 * hz); |
| 689 | error = nfs_sigintr(nmp, rep, rep->r_procp); |
| 690 | } |
| 691 | if (nmp->nm_flag & NFSMNT_AUTHERR) { |
| 692 | nmp->nm_flag &= ~NFSMNT_AUTHERR; |
| 693 | error = EAUTH; |
| 694 | } |
| 695 | if (error) |
| 696 | free((caddr_t)*auth_str, M_TEMP); |
| 697 | else { |
| 698 | *auth_type = nmp->nm_authtype; |
| 699 | *auth_len = nmp->nm_authlen; |
| 700 | } |
| 701 | nmp->nm_flag &= ~NFSMNT_HASAUTH; |
| 702 | nmp->nm_flag |= NFSMNT_WAITAUTH; |
| 703 | if (nmp->nm_flag & NFSMNT_WANTAUTH) { |
| 704 | nmp->nm_flag &= ~NFSMNT_WANTAUTH; |
| 705 | wakeup((caddr_t)&nmp->nm_authtype); |
| 706 | } |
| 707 | return (error); |
| 708 | } |
| 709 | |
| 710 | /* |
| 711 | * Derefence a server socket structure. If it has no more references and |
| 712 | * is no longer valid, you can throw it away. |
| 713 | */ |
| 714 | void |
| 715 | nfsrv_slpderef(slp) |
| 716 | register struct nfssvc_sock *slp; |
| 717 | { |
| 718 | if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { |
| 719 | #ifdef NOTYET |
| 720 | slp->ns_prev->ns_next = slp->ns_next; |
| 721 | slp->ns_next->ns_prev = slp->ns_prev; |
| 722 | free((caddr_t)slp, M_NFSSVC); |
| 723 | #else |
| 724 | if (slp->ns_flag & SLP_DEREFFREE) |
| 725 | panic("deref dup free 0x%x of deref free\n", slp); |
| 726 | else { |
| 727 | slp->ns_prev->ns_next = slp->ns_next; |
| 728 | slp->ns_next->ns_prev = slp->ns_prev; |
| 729 | } |
| 730 | if (slp->ns_flag & SLP_CLRFREE) |
| 731 | panic("deref dup free 0x%x of clrall free\n", slp); |
| 732 | slp->ns_flag |= SLP_DEREFFREE; |
| 733 | printf("Free deref sock 0x%x\n", slp); |
| 734 | #endif |
| 735 | } |
| 736 | } |
| 737 | |
| 738 | /* |
| 739 | * Initialize the data structures for the server. |
| 740 | * Handshake with any new nfsds starting up to avoid any chance of |
| 741 | * corruption. |
| 742 | */ |
| 743 | void |
| 744 | nfsrv_init(terminating) |
| 745 | int terminating; |
| 746 | { |
| 747 | register struct nfssvc_sock *slp; |
| 748 | struct nfssvc_sock *oslp; |
| 749 | |
| 750 | if (nfssvc_sockhead.ns_flag & SLP_INIT) |
| 751 | panic("nfsd init"); |
| 752 | nfssvc_sockhead.ns_flag |= SLP_INIT; |
| 753 | if (terminating) { |
| 754 | slp = nfssvc_sockhead.ns_next; |
| 755 | while (slp != &nfssvc_sockhead) { |
| 756 | if (slp->ns_flag & SLP_VALID) |
| 757 | nfsrv_zapsock(slp); |
| 758 | slp->ns_next->ns_prev = slp->ns_prev; |
| 759 | slp->ns_prev->ns_next = slp->ns_next; |
| 760 | oslp = slp; |
| 761 | slp = slp->ns_next; |
| 762 | #ifdef NOTYET |
| 763 | free((caddr_t)oslp, M_NFSSVC); |
| 764 | #else |
| 765 | if (oslp->ns_flag & SLP_DEREFFREE) |
| 766 | panic("clrall dup free 0x%x of deref free\n", |
| 767 | oslp); |
| 768 | if (oslp->ns_flag & SLP_CLRFREE) |
| 769 | panic("clrall dup free 0x%x of clrall free\n", |
| 770 | oslp); |
| 771 | oslp->ns_flag |= SLP_CLRFREE; |
| 772 | printf("Free all socks 0x%x\n", oslp); |
| 773 | #endif |
| 774 | } |
| 775 | nfsrv_cleancache(); /* And clear out server cache */ |
| 776 | } |
| 777 | nfs_udpsock = (struct nfssvc_sock *) |
| 778 | malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); |
| 779 | printf("Alloc nfs_udpsock 0x%x\n", nfs_udpsock); |
| 780 | bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); |
| 781 | nfs_cltpsock = (struct nfssvc_sock *) |
| 782 | malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); |
| 783 | printf("Alloc nfs_cltpsock 0x%x\n", nfs_cltpsock); |
| 784 | bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); |
| 785 | nfssvc_sockhead.ns_next = nfs_udpsock; |
| 786 | nfs_udpsock->ns_next = nfs_cltpsock; |
| 787 | nfs_cltpsock->ns_next = &nfssvc_sockhead; |
| 788 | nfssvc_sockhead.ns_prev = nfs_cltpsock; |
| 789 | nfs_cltpsock->ns_prev = nfs_udpsock; |
| 790 | nfs_udpsock->ns_prev = &nfssvc_sockhead; |
| 791 | nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev = |
| 792 | (struct nfsuid *)nfs_udpsock; |
| 793 | nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev = |
| 794 | (struct nfsuid *)nfs_cltpsock; |
| 795 | nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head; |
| 796 | nfsd_head.nd_flag = 0; |
| 797 | nfssvc_sockhead.ns_flag &= ~SLP_INIT; |
| 798 | if (nfssvc_sockhead.ns_flag & SLP_WANTINIT) { |
| 799 | nfssvc_sockhead.ns_flag &= ~SLP_WANTINIT; |
| 800 | wakeup((caddr_t)&nfssvc_sockhead); |
| 801 | } |
| 802 | } |