Commit | Line | Data |
---|---|---|
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 | * |
331f8bac | 10 | * @(#)nfs_syscalls.c 7.34 (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> | |
30 | #include <netinet/in.h> | |
31 | #include <netinet/tcp.h> | |
2c5b44a2 | 32 | #ifdef ISO |
331f8bac | 33 | #include <netiso/iso.h> |
2c5b44a2 | 34 | #endif |
331f8bac KM |
35 | #include <machine/endian.h> |
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. */ | |
44 | extern u_long nfs_prog, nfs_vers; | |
45 | extern int (*nfsrv_procs[NFS_NPROCS])(); | |
331f8bac | 46 | extern struct queue_entry nfs_bufq; |
f0f1cbaa | 47 | extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; |
2c5b44a2 KM |
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(); | |
c0ef7143 | 60 | void nfsrv_slpderef(), nfsrv_init(); |
a2907882 | 61 | |
86fae39b KM |
62 | #define TRUE 1 |
63 | #define FALSE 0 | |
64 | ||
1c89915d | 65 | static 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 |
74 | struct getfh_args { |
75 | char *fname; | |
76 | fhandle_t *fhp; | |
77 | }; | |
170bfd05 KM |
78 | getfh(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 |
107 | static 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 |
119 | struct nfssvc_args { |
120 | int flag; | |
121 | caddr_t argp; | |
122 | }; | |
170bfd05 KM |
123 | nfssvc(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 | */ | |
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 | ||
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 | */ | |
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; | |
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 | 553 | done: |
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 | 569 | nfssvc_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 | 619 | nfsrv_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 | */ | |
655 | nfs_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 | */ | |
710 | void | |
711 | nfsrv_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 | */ | |
739 | void | |
740 | nfsrv_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 | } |