make kernel includes standard
[unix-history] / usr / src / sys / nfs / nfs_syscalls.c
CommitLineData
a2907882
KM
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 *
dbf0c423 8 * %sccs.include.redist.c%
a2907882 9 *
5548a02f 10 * @(#)nfs_syscalls.c 7.35 (Berkeley) %G%
a2907882
KM
11 */
12
331f8bac
KM
13#include <sys/param.h>
14#include <sys/systm.h>
15#include <sys/kernel.h>
16#include <sys/file.h>
17#include <sys/stat.h>
18#include <sys/vnode.h>
19#include <sys/mount.h>
20#include <sys/proc.h>
21#include <sys/uio.h>
22#include <sys/malloc.h>
23#include <sys/buf.h>
24#include <sys/mbuf.h>
25#include <sys/socket.h>
26#include <sys/socketvar.h>
27#include <sys/domain.h>
28#include <sys/protosw.h>
29#include <sys/namei.h>
5548a02f 30
331f8bac
KM
31#include <netinet/in.h>
32#include <netinet/tcp.h>
2c5b44a2 33#ifdef ISO
331f8bac 34#include <netiso/iso.h>
2c5b44a2 35#endif
331f8bac
KM
36#include <nfs/rpcv2.h>
37#include <nfs/nfsv2.h>
38#include <nfs/nfs.h>
39#include <nfs/nfsrvcache.h>
40#include <nfs/nfsmount.h>
41#include <nfs/nqnfs.h>
a2907882
KM
42
43/* Global defs. */
44extern u_long nfs_prog, nfs_vers;
45extern int (*nfsrv_procs[NFS_NPROCS])();
331f8bac 46extern struct queue_entry nfs_bufq;
f0f1cbaa 47extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
2c5b44a2
KM
48extern int nfs_numasync;
49extern time_t nqnfsstarttime;
50extern struct nfsrv_req nsrvq_head;
51extern struct nfsd nfsd_head;
52extern int nqsrv_writeslack;
53struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
54int nuidhash_max = NFS_MAXUIDHASH;
55static int nfs_numnfsd = 0;
56int nfsd_waiting = 0;
57static int notstarted = 1;
58static int modify_flag = 0;
59void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock();
c0ef7143 60void nfsrv_slpderef(), nfsrv_init();
a2907882 61
86fae39b
KM
62#define TRUE 1
63#define FALSE 0
64
1c89915d 65static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
a2907882
KM
66/*
67 * NFS server system calls
68 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
69 */
a2907882
KM
70
71/*
72 * Get file handle system call
73 */
9e97623a
CT
74struct getfh_args {
75 char *fname;
76 fhandle_t *fhp;
77};
170bfd05
KM
78getfh(p, uap, retval)
79 struct proc *p;
9e97623a 80 register struct getfh_args *uap;
170bfd05
KM
81 int *retval;
82{
a2907882
KM
83 register struct vnode *vp;
84 fhandle_t fh;
85 int error;
9b7788f3 86 struct nameidata nd;
a2907882
KM
87
88 /*
89 * Must be super user
90 */
9b929e63 91 if (error = suser(p->p_ucred, &p->p_acflag))
56459273 92 return (error);
daf8dcc8
KM
93 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
94 if (error = namei(&nd))
56459273 95 return (error);
daf8dcc8 96 vp = nd.ni_vp;
a2907882 97 bzero((caddr_t)&fh, sizeof(fh));
54fb9dc2 98 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
a2907882
KM
99 error = VFS_VPTOFH(vp, &fh.fh_fid);
100 vput(vp);
101 if (error)
56459273 102 return (error);
a2907882 103 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
56459273 104 return (error);
a2907882
KM
105}
106
2c5b44a2
KM
107static struct nfssvc_sock nfssvc_sockhead;
108
46f88eb2
KM
109#define SLP_DEREFFREE 0x100
110#define SLP_CLRFREE 0x200
111
a2907882
KM
112/*
113 * Nfs server psuedo system call for the nfsd's
2c5b44a2
KM
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
a2907882 118 */
9e97623a
CT
119struct nfssvc_args {
120 int flag;
121 caddr_t argp;
122};
170bfd05
KM
123nfssvc(p, uap, retval)
124 struct proc *p;
9e97623a 125 register struct nfssvc_args *uap;
170bfd05
KM
126 int *retval;
127{
2c5b44a2 128 struct nameidata nd;
a2907882 129 struct file *fp;
2c5b44a2
KM
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;
a2907882
KM
139
140 /*
141 * Must be super user
142 */
9b929e63 143 if (error = suser(p->p_ucred, &p->p_acflag))
4b91b0f3 144 return (error);
c0ef7143
KM
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);
2c5b44a2
KM
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);
daf8dcc8
KM
154 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
155 ncd.ncd_dirp, p);
156 if (error = namei(&nd))
2c5b44a2
KM
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;
daf8dcc8
KM
167 error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
168 uap->argp, p);
2c5b44a2 169 } else if (uap->flag & NFSSVC_ADDSOCK) {
daf8dcc8
KM
170 if (error = copyin(uap->argp, (caddr_t)&nfsdarg,
171 sizeof(nfsdarg)))
2c5b44a2
KM
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) &&
a5a4c300 188 (nfsd->nd_slp->ns_flag & SLP_VALID)) {
2c5b44a2
KM
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;
a5a4c300 196 if ((slp->ns_flag & SLP_VALID) == 0) {
2c5b44a2
KM
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 */
231nfssvc_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
a2907882 242 so = (struct socket *)fp->f_data;
2c5b44a2
KM
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 */
2c5b44a2
KM
261 }
262 if (so->so_type == SOCK_STREAM)
263 siz = NFS_MAXPACKET + sizeof (u_long);
f0f1cbaa 264 else
2c5b44a2
KM
265 siz = NFS_MAXPACKET;
266 if (error = soreserve(so, siz, siz)) {
267 m_freem(mynam);
268 return (error);
269 }
f0f1cbaa
KM
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 */
2c5b44a2 276 if (so->so_type == SOCK_STREAM) {
f0f1cbaa
KM
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 &&
2c5b44a2 283 so->so_proto->pr_protocol == IPPROTO_TCP) {
f0f1cbaa
KM
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;
2c5b44a2
KM
293 if (tslp)
294 slp = tslp;
295 else {
296 slp = (struct nfssvc_sock *)
297 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
46f88eb2 298 printf("Alloc nfssvc_sock 0x%x\n", slp);
2c5b44a2
KM
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);
2c5b44a2
KM
314 nfsrv_wakenfsd(slp);
315 splx(s);
316 return (0);
317}
f0f1cbaa 318
2c5b44a2
KM
319/*
320 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
321 * until it is killed by a signal.
322 */
323nfssvc_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;
a5a4c300 333 struct nfssvc_sock *oslp;
2c5b44a2
KM
334 struct nfsd *nd = nsd->nsd_nfsd;
335 struct mbuf *mreq, *nam;
336 int error, cacherep, s;
337 int sotype;
338
a5a4c300 339 s = splnet();
2c5b44a2
KM
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));
2c5b44a2 344 nd->nd_procp = p;
a5a4c300 345 nd->nd_cr.cr_ref = 1;
2c5b44a2 346 insque(nd, &nfsd_head);
2c5b44a2
KM
347 nfs_numnfsd++;
348 }
a2907882 349 /*
2c5b44a2 350 * Loop getting rpc requests until SIGKILL.
a2907882
KM
351 */
352 for (;;) {
2c5b44a2 353 if ((nd->nd_flag & NFSD_REQINPROG) == 0) {
2c5b44a2
KM
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++;
a5a4c300 358 error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0);
2c5b44a2 359 nfsd_waiting--;
a5a4c300
KM
360 if (error)
361 goto done;
170bfd05 362 }
2c5b44a2
KM
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) {
a5a4c300
KM
367 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
368 == (SLP_VALID | SLP_DOREC)) {
369 slp->ns_flag &= ~SLP_DOREC;
c0ef7143 370 slp->ns_sref++;
2c5b44a2 371 nd->nd_slp = slp;
2c5b44a2
KM
372 break;
373 }
374 slp = slp->ns_next;
375 }
376 if (slp == &nfssvc_sockhead)
377 nfsd_head.nd_flag &= ~NFSD_CHECKSLP;
378 }
c0ef7143 379 if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0)
2c5b44a2 380 continue;
c0ef7143
KM
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;
2c5b44a2 394 }
a5a4c300
KM
395 } else {
396 error = 0;
2c5b44a2 397 slp = nd->nd_slp;
a5a4c300
KM
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);
2c5b44a2
KM
406 so = slp->ns_so;
407 sotype = so->so_type;
f0f1cbaa 408
2c5b44a2
KM
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;
f0f1cbaa 425 else
2c5b44a2 426 solockp = (int *)0;
2c5b44a2
KM
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;
f0f1cbaa 466 cacherep = RC_DOIT;
2c5b44a2
KM
467 }
468
f0f1cbaa 469 switch (cacherep) {
e8540f59 470 case RC_DOIT:
2c5b44a2
KM
471 error = (*(nfsrv_procs[nd->nd_procnum]))(nd,
472 nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr,
473 nam, &mreq);
a5a4c300
KM
474 if (nd->nd_cr.cr_ref != 1) {
475 printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref);
476 panic("nfssvc cref");
477 }
2c5b44a2
KM
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);
f0f1cbaa 484 }
e8540f59
KM
485 break;
486 }
2c5b44a2
KM
487 nfsstats.srvrpccnt[nd->nd_procnum]++;
488 if (nam2)
489 nfsrv_updatecache(nam2, nd, TRUE, mreq);
490 nd->nd_mrep = (struct mbuf *)0;
e8540f59
KM
491 case RC_REPLY:
492 m = mreq;
493 siz = 0;
494 while (m) {
495 siz += m->m_len;
496 m = m->m_next;
497 }
f0f1cbaa 498 if (siz <= 0 || siz > NFS_MAXPACKET) {
e8540f59
KM
499 printf("mbuf siz=%d\n",siz);
500 panic("Bad nfs svc reply");
501 }
2c5b44a2
KM
502 m = mreq;
503 m->m_pkthdr.len = siz;
504 m->m_pkthdr.rcvif = (struct ifnet *)0;
f0f1cbaa 505 /*
2c5b44a2 506 * For stream protocols, prepend a Sun RPC
f0f1cbaa
KM
507 * Record Mark.
508 */
2c5b44a2
KM
509 if (sotype == SOCK_STREAM) {
510 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
511 *mtod(m, u_long *) = htonl(0x80000000 | siz);
f0f1cbaa 512 }
2c5b44a2
KM
513 if (solockp)
514 (void) nfs_sndlock(solockp, (struct nfsreq *)0);
a5a4c300 515 if (slp->ns_flag & SLP_VALID)
2c5b44a2
KM
516 error = nfs_send(so, nam2, m, (struct nfsreq *)0);
517 else {
518 error = EPIPE;
519 m_freem(m);
f0f1cbaa 520 }
2c5b44a2
KM
521 if (nam2)
522 MFREE(nam2, m);
523 if (nd->nd_mrep)
524 m_freem(nd->nd_mrep);
525 if (error == EPIPE)
a5a4c300 526 nfsrv_zapsock(slp);
2c5b44a2
KM
527 if (solockp)
528 nfs_sndunlock(solockp);
a5a4c300
KM
529 if (error == EINTR || error == ERESTART) {
530 nfsrv_slpderef(slp);
531 s = splnet();
2c5b44a2 532 goto done;
a5a4c300 533 }
e8540f59
KM
534 break;
535 case RC_DROPIT:
2c5b44a2
KM
536 m_freem(nd->nd_mrep);
537 m_freem(nam2);
e8540f59
KM
538 break;
539 };
a5a4c300
KM
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 }
7860f57a
KM
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
a2907882 552 }
2c5b44a2 553done:
2c5b44a2
KM
554 remque(nd);
555 splx(s);
556 free((caddr_t)nd, M_NFSD);
557 nsd->nsd_nfsd = (struct nfsd *)0;
c0ef7143
KM
558 if (--nfs_numnfsd == 0)
559 nfsrv_init(TRUE); /* Reinitialize everything */
56459273 560 return (error);
a2907882 561}
9238aa59 562
9238aa59 563/*
2c5b44a2
KM
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.
9238aa59 568 */
2c5b44a2 569nfssvc_iod(p)
170bfd05 570 struct proc *p;
9238aa59
RM
571{
572 register struct buf *bp, *dp;
1c89915d 573 register int i, myiod;
2c5b44a2 574 int error = 0;
9238aa59 575
ffe6f482
KM
576 /*
577 * Assign my position or return error if too many already running
578 */
1c89915d
KM
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)
56459273 587 return (EBUSY);
1c89915d 588 nfs_numasync++;
9238aa59 589 /*
ffe6f482 590 * Just loop around doin our stuff until SIGKILL
9238aa59
RM
591 */
592 for (;;) {
331f8bac 593 while (nfs_bufq.qe_next == NULL && error == 0) {
cd4ee8a8 594 nfs_iodwant[myiod] = p;
1c89915d
KM
595 error = tsleep((caddr_t)&nfs_iodwant[myiod],
596 PWAIT | PCATCH, "nfsidl", 0);
597 nfs_iodwant[myiod] = (struct proc *)0;
598 }
331f8bac 599 while ((bp = nfs_bufq.qe_next) != NULL) {
4f47a2d0 600 /* Take one off the front of the list */
331f8bac 601 queue_remove(&nfs_bufq, bp, struct buf *, b_freelist);
2c5b44a2 602 (void) nfs_doio(bp, (struct proc *)0);
9238aa59 603 }
1c89915d
KM
604 if (error) {
605 nfs_asyncdaemon[myiod] = 0;
606 nfs_numasync--;
607 return (error);
9238aa59 608 }
9238aa59
RM
609 }
610}
2c5b44a2
KM
611
612/*
613 * Shut down a socket associated with an nfssvc_sock structure.
614 * Should be called with the send lock set, if required.
615 * The trick here is to increment the sref at the start, so that the nfsds
616 * will stop using it and clear ns_flag at the end so that it will not be
617 * reassigned during cleanup.
618 */
a5a4c300 619nfsrv_zapsock(slp)
2c5b44a2 620 register struct nfssvc_sock *slp;
2c5b44a2
KM
621{
622 register struct nfsuid *nuidp, *onuidp;
623 register int i;
624 struct socket *so;
625 struct file *fp;
626 struct mbuf *m;
627
c0ef7143 628 slp->ns_flag &= ~SLP_ALLFLAGS;
2c5b44a2
KM
629 if (fp = slp->ns_fp) {
630 slp->ns_fp = (struct file *)0;
2c5b44a2 631 so = slp->ns_so;
a5a4c300 632 so->so_upcall = NULL;
2c5b44a2 633 soshutdown(so, 2);
a5a4c300 634 closef(fp, (struct proc *)0);
2c5b44a2
KM
635 if (slp->ns_nam)
636 MFREE(slp->ns_nam, m);
637 m_freem(slp->ns_raw);
638 m_freem(slp->ns_rec);
639 nuidp = slp->ns_lrunext;
640 while (nuidp != (struct nfsuid *)slp) {
641 onuidp = nuidp;
642 nuidp = nuidp->nu_lrunext;
643 free((caddr_t)onuidp, M_NFSUID);
644 }
645 slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
646 for (i = 0; i < NUIDHASHSIZ; i++)
647 slp->ns_uidh[i] = (struct nfsuid *)0;
2c5b44a2
KM
648 }
649}
650
651/*
652 * Get an authorization string for the uid by having the mount_nfs sitting
653 * on this mount point porpous out of the kernel and do it.
654 */
655nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
656 register struct nfsmount *nmp;
657 struct nfsreq *rep;
658 struct ucred *cred;
659 int *auth_type;
660 char **auth_str;
661 int *auth_len;
662{
663 int error = 0;
664
665 while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
666 nmp->nm_flag |= NFSMNT_WANTAUTH;
667 (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
668 "nfsauth1", 2 * hz);
669 if (error = nfs_sigintr(nmp, rep, rep->r_procp)) {
670 nmp->nm_flag &= ~NFSMNT_WANTAUTH;
671 return (error);
672 }
673 }
674 nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
675 nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
676 nmp->nm_authuid = cred->cr_uid;
677 wakeup((caddr_t)&nmp->nm_authstr);
678
679 /*
680 * And wait for mount_nfs to do its stuff.
681 */
682 while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
683 (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
684 "nfsauth2", 2 * hz);
685 error = nfs_sigintr(nmp, rep, rep->r_procp);
686 }
687 if (nmp->nm_flag & NFSMNT_AUTHERR) {
688 nmp->nm_flag &= ~NFSMNT_AUTHERR;
689 error = EAUTH;
690 }
691 if (error)
692 free((caddr_t)*auth_str, M_TEMP);
693 else {
694 *auth_type = nmp->nm_authtype;
695 *auth_len = nmp->nm_authlen;
696 }
697 nmp->nm_flag &= ~NFSMNT_HASAUTH;
698 nmp->nm_flag |= NFSMNT_WAITAUTH;
699 if (nmp->nm_flag & NFSMNT_WANTAUTH) {
700 nmp->nm_flag &= ~NFSMNT_WANTAUTH;
701 wakeup((caddr_t)&nmp->nm_authtype);
702 }
703 return (error);
704}
a5a4c300
KM
705
706/*
707 * Derefence a server socket structure. If it has no more references and
708 * is no longer valid, you can throw it away.
709 */
710void
711nfsrv_slpderef(slp)
712 register struct nfssvc_sock *slp;
713{
714 if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
46f88eb2 715#ifdef NOTYET
a5a4c300
KM
716 slp->ns_prev->ns_next = slp->ns_next;
717 slp->ns_next->ns_prev = slp->ns_prev;
718 free((caddr_t)slp, M_NFSSVC);
46f88eb2
KM
719#else
720 if (slp->ns_flag & SLP_DEREFFREE)
721 panic("deref dup free 0x%x of deref free\n", slp);
722 else {
723 slp->ns_prev->ns_next = slp->ns_next;
724 slp->ns_next->ns_prev = slp->ns_prev;
725 }
726 if (slp->ns_flag & SLP_CLRFREE)
727 panic("deref dup free 0x%x of clrall free\n", slp);
728 slp->ns_flag |= SLP_DEREFFREE;
729 printf("Free deref sock 0x%x\n", slp);
730#endif
a5a4c300
KM
731 }
732}
c0ef7143
KM
733
734/*
735 * Initialize the data structures for the server.
736 * Handshake with any new nfsds starting up to avoid any chance of
737 * corruption.
738 */
739void
740nfsrv_init(terminating)
741 int terminating;
742{
743 register struct nfssvc_sock *slp;
744 struct nfssvc_sock *oslp;
745
746 if (nfssvc_sockhead.ns_flag & SLP_INIT)
747 panic("nfsd init");
748 nfssvc_sockhead.ns_flag |= SLP_INIT;
749 if (terminating) {
750 slp = nfssvc_sockhead.ns_next;
751 while (slp != &nfssvc_sockhead) {
752 if (slp->ns_flag & SLP_VALID)
753 nfsrv_zapsock(slp);
754 slp->ns_next->ns_prev = slp->ns_prev;
755 slp->ns_prev->ns_next = slp->ns_next;
756 oslp = slp;
757 slp = slp->ns_next;
46f88eb2 758#ifdef NOTYET
c0ef7143 759 free((caddr_t)oslp, M_NFSSVC);
46f88eb2
KM
760#else
761 if (oslp->ns_flag & SLP_DEREFFREE)
762 panic("clrall dup free 0x%x of deref free\n",
763 oslp);
764 if (oslp->ns_flag & SLP_CLRFREE)
765 panic("clrall dup free 0x%x of clrall free\n",
766 oslp);
767 oslp->ns_flag |= SLP_CLRFREE;
768 printf("Free all socks 0x%x\n", oslp);
769#endif
c0ef7143
KM
770 }
771 nfsrv_cleancache(); /* And clear out server cache */
772 }
773 nfs_udpsock = (struct nfssvc_sock *)
774 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
46f88eb2 775 printf("Alloc nfs_udpsock 0x%x\n", nfs_udpsock);
c0ef7143
KM
776 bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
777 nfs_cltpsock = (struct nfssvc_sock *)
778 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
46f88eb2 779 printf("Alloc nfs_cltpsock 0x%x\n", nfs_cltpsock);
c0ef7143
KM
780 bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
781 nfssvc_sockhead.ns_next = nfs_udpsock;
782 nfs_udpsock->ns_next = nfs_cltpsock;
783 nfs_cltpsock->ns_next = &nfssvc_sockhead;
784 nfssvc_sockhead.ns_prev = nfs_cltpsock;
785 nfs_cltpsock->ns_prev = nfs_udpsock;
786 nfs_udpsock->ns_prev = &nfssvc_sockhead;
787 nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev =
788 (struct nfsuid *)nfs_udpsock;
789 nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev =
790 (struct nfsuid *)nfs_cltpsock;
791 nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head;
792 nfsd_head.nd_flag = 0;
793 nfssvc_sockhead.ns_flag &= ~SLP_INIT;
794 if (nfssvc_sockhead.ns_flag & SLP_WANTINIT) {
795 nfssvc_sockhead.ns_flag &= ~SLP_WANTINIT;
796 wakeup((caddr_t)&nfssvc_sockhead);
797 }
798}