more-or-less working with new proc & user structs
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
da7c5cc6 1/*
c4ec2128
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
dbf0c423 5 * %sccs.include.redist.c%
c4ec2128 6 *
8429d022 7 * @(#)sys_generic.c 7.26 (Berkeley) %G%
da7c5cc6 8 */
ffe28cfe 9
94368568
JB
10#include "param.h"
11#include "systm.h"
d9c2f47f 12#include "user.h"
5e00df3b 13#include "filedesc.h"
94368568
JB
14#include "ioctl.h"
15#include "file.h"
16#include "proc.h"
17#include "uio.h"
18#include "kernel.h"
19#include "stat.h"
e0b18aec 20#include "malloc.h"
46814581
MK
21#ifdef KTRACE
22#include "ktrace.h"
23#endif
ffe28cfe
BJ
24
25/*
26 * Read system call.
27 */
25ed1cf1 28/* ARGSUSED */
c9714ae3
KM
29read(p, uap, retval)
30 struct proc *p;
31 register struct args {
ffe28cfe
BJ
32 int fdes;
33 char *cbuf;
34 unsigned count;
c9714ae3
KM
35 } *uap;
36 int *retval;
37{
c4ec2128 38 register struct file *fp;
5e00df3b 39 register struct filedesc *fdp = p->p_fd;
32a43ee2
BJ
40 struct uio auio;
41 struct iovec aiov;
c4ec2128
KM
42 long cnt, error = 0;
43#ifdef KTRACE
44 struct iovec ktriov;
45#endif
ffe28cfe 46
8429d022 47 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
5e00df3b 48 (fp = OFILE(fdp, uap->fdes)) == NULL ||
c4ec2128 49 (fp->f_flag & FREAD) == 0)
d9c2f47f 50 return (EBADF);
32a43ee2
BJ
51 aiov.iov_base = (caddr_t)uap->cbuf;
52 aiov.iov_len = uap->count;
53 auio.uio_iov = &aiov;
54 auio.uio_iovcnt = 1;
c4ec2128
KM
55 auio.uio_resid = uap->count;
56 auio.uio_rw = UIO_READ;
57 auio.uio_segflg = UIO_USERSPACE;
58#ifdef KTRACE
59 /*
60 * if tracing, save a copy of iovec
61 */
c9714ae3 62 if (KTRPOINT(p, KTR_GENIO))
c4ec2128
KM
63 ktriov = aiov;
64#endif
65 cnt = uap->count;
9754d709
MK
66 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
67 if (auio.uio_resid != cnt && (error == ERESTART ||
68 error == EINTR || error == EWOULDBLOCK))
69 error = 0;
c4ec2128
KM
70 cnt -= auio.uio_resid;
71#ifdef KTRACE
c9714ae3 72 if (KTRPOINT(p, KTR_GENIO) && error == 0)
51322105 73 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
c4ec2128 74#endif
c9714ae3 75 *retval = cnt;
d9c2f47f 76 return (error);
b9429893
BJ
77}
78
c9714ae3
KM
79/*
80 * Scatter read system call.
81 */
25ed1cf1 82/* ARGSUSED */
c9714ae3
KM
83readv(p, uap, retval)
84 struct proc *p;
85 register struct args {
b9429893
BJ
86 int fdes;
87 struct iovec *iovp;
31286ce2 88 unsigned iovcnt;
c9714ae3
KM
89 } *uap;
90 int *retval;
91{
c4ec2128 92 register struct file *fp;
5e00df3b 93 register struct filedesc *fdp = p->p_fd;
b9429893 94 struct uio auio;
c4ec2128 95 register struct iovec *iov;
c9773de9 96 struct iovec *saveiov;
c4ec2128
KM
97 struct iovec aiov[UIO_SMALLIOV];
98 long i, cnt, error = 0;
c9773de9 99 unsigned iovlen;
c4ec2128
KM
100#ifdef KTRACE
101 struct iovec *ktriov = NULL;
102#endif
b9429893 103
8429d022 104 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
5e00df3b 105 (fp = OFILE(fdp, uap->fdes)) == NULL ||
c4ec2128 106 (fp->f_flag & FREAD) == 0)
d9c2f47f 107 return (EBADF);
c9773de9
MK
108 /* note: can't use iovlen until iovcnt is validated */
109 iovlen = uap->iovcnt * sizeof (struct iovec);
46814581 110 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128 111 if (uap->iovcnt > UIO_MAXIOV)
d9c2f47f 112 return (EINVAL);
c9773de9
MK
113 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
114 saveiov = iov;
46814581
MK
115 } else
116 iov = aiov;
117 auio.uio_iov = iov;
b9429893 118 auio.uio_iovcnt = uap->iovcnt;
c4ec2128
KM
119 auio.uio_rw = UIO_READ;
120 auio.uio_segflg = UIO_USERSPACE;
c9773de9 121 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
46814581 122 goto done;
c4ec2128
KM
123 auio.uio_resid = 0;
124 for (i = 0; i < uap->iovcnt; i++) {
125 if (iov->iov_len < 0) {
126 error = EINVAL;
127 goto done;
128 }
129 auio.uio_resid += iov->iov_len;
130 if (auio.uio_resid < 0) {
131 error = EINVAL;
132 goto done;
133 }
134 iov++;
135 }
136#ifdef KTRACE
137 /*
138 * if tracing, save a copy of iovec
139 */
c9714ae3 140 if (KTRPOINT(p, KTR_GENIO)) {
c4ec2128
KM
141 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
142 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
143 }
144#endif
145 cnt = auio.uio_resid;
9754d709
MK
146 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
147 if (auio.uio_resid != cnt && (error == ERESTART ||
148 error == EINTR || error == EWOULDBLOCK))
149 error = 0;
c4ec2128
KM
150 cnt -= auio.uio_resid;
151#ifdef KTRACE
152 if (ktriov != NULL) {
e64d087d 153 if (error == 0)
51322105
KM
154 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
155 cnt, error);
c4ec2128
KM
156 FREE(ktriov, M_TEMP);
157 }
158#endif
c9714ae3 159 *retval = cnt;
46814581 160done:
c4ec2128 161 if (uap->iovcnt > UIO_SMALLIOV)
c9773de9 162 FREE(saveiov, M_IOV);
d9c2f47f 163 return (error);
ffe28cfe
BJ
164}
165
166/*
167 * Write system call
168 */
c9714ae3
KM
169write(p, uap, retval)
170 struct proc *p;
171 register struct args {
ffe28cfe
BJ
172 int fdes;
173 char *cbuf;
31286ce2 174 unsigned count;
c9714ae3
KM
175 } *uap;
176 int *retval;
177{
c4ec2128 178 register struct file *fp;
5e00df3b 179 register struct filedesc *fdp = p->p_fd;
b9429893
BJ
180 struct uio auio;
181 struct iovec aiov;
c4ec2128
KM
182 long cnt, error = 0;
183#ifdef KTRACE
184 struct iovec ktriov;
185#endif
ffe28cfe 186
8429d022 187 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
5e00df3b 188 (fp = OFILE(fdp, uap->fdes)) == NULL ||
c4ec2128 189 (fp->f_flag & FWRITE) == 0)
d9c2f47f 190 return (EBADF);
c4ec2128
KM
191 aiov.iov_base = (caddr_t)uap->cbuf;
192 aiov.iov_len = uap->count;
b9429893
BJ
193 auio.uio_iov = &aiov;
194 auio.uio_iovcnt = 1;
c4ec2128
KM
195 auio.uio_resid = uap->count;
196 auio.uio_rw = UIO_WRITE;
197 auio.uio_segflg = UIO_USERSPACE;
198#ifdef KTRACE
199 /*
200 * if tracing, save a copy of iovec
201 */
c9714ae3 202 if (KTRPOINT(p, KTR_GENIO))
c4ec2128
KM
203 ktriov = aiov;
204#endif
205 cnt = uap->count;
9754d709
MK
206 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
207 if (auio.uio_resid != cnt && (error == ERESTART ||
208 error == EINTR || error == EWOULDBLOCK))
209 error = 0;
210 if (error == EPIPE)
c9714ae3 211 psignal(p, SIGPIPE);
9754d709 212 }
c4ec2128
KM
213 cnt -= auio.uio_resid;
214#ifdef KTRACE
c9714ae3
KM
215 if (KTRPOINT(p, KTR_GENIO) && error == 0)
216 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
51322105 217 &ktriov, cnt, error);
c4ec2128 218#endif
c9714ae3 219 *retval = cnt;
d9c2f47f 220 return (error);
b9429893
BJ
221}
222
c9714ae3
KM
223/*
224 * Gather write system call
225 */
226writev(p, uap, retval)
227 struct proc *p;
228 register struct args {
b9429893
BJ
229 int fdes;
230 struct iovec *iovp;
31286ce2 231 unsigned iovcnt;
c9714ae3
KM
232 } *uap;
233 int *retval;
234{
c4ec2128 235 register struct file *fp;
5e00df3b 236 register struct filedesc *fdp = p->p_fd;
b9429893 237 struct uio auio;
c4ec2128 238 register struct iovec *iov;
c9773de9 239 struct iovec *saveiov;
c4ec2128
KM
240 struct iovec aiov[UIO_SMALLIOV];
241 long i, cnt, error = 0;
c9773de9 242 unsigned iovlen;
c4ec2128
KM
243#ifdef KTRACE
244 struct iovec *ktriov = NULL;
245#endif
b9429893 246
8429d022 247 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
5e00df3b 248 (fp = OFILE(fdp, uap->fdes)) == NULL ||
c4ec2128 249 (fp->f_flag & FWRITE) == 0)
d9c2f47f 250 return (EBADF);
c9773de9
MK
251 /* note: can't use iovlen until iovcnt is validated */
252 iovlen = uap->iovcnt * sizeof (struct iovec);
46814581 253 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128 254 if (uap->iovcnt > UIO_MAXIOV)
d9c2f47f 255 return (EINVAL);
c9773de9
MK
256 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
257 saveiov = iov;
46814581
MK
258 } else
259 iov = aiov;
260 auio.uio_iov = iov;
b9429893 261 auio.uio_iovcnt = uap->iovcnt;
c4ec2128
KM
262 auio.uio_rw = UIO_WRITE;
263 auio.uio_segflg = UIO_USERSPACE;
c9773de9 264 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
46814581 265 goto done;
c4ec2128
KM
266 auio.uio_resid = 0;
267 for (i = 0; i < uap->iovcnt; i++) {
b9429893 268 if (iov->iov_len < 0) {
c4ec2128
KM
269 error = EINVAL;
270 goto done;
b9429893 271 }
c4ec2128
KM
272 auio.uio_resid += iov->iov_len;
273 if (auio.uio_resid < 0) {
274 error = EINVAL;
275 goto done;
b9429893 276 }
2a0114a8 277 iov++;
b9429893 278 }
46814581 279#ifdef KTRACE
c4ec2128
KM
280 /*
281 * if tracing, save a copy of iovec
282 */
c9714ae3 283 if (KTRPOINT(p, KTR_GENIO)) {
46814581 284 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
c4ec2128 285 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
46814581
MK
286 }
287#endif
c4ec2128 288 cnt = auio.uio_resid;
9754d709
MK
289 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
290 if (auio.uio_resid != cnt && (error == ERESTART ||
291 error == EINTR || error == EWOULDBLOCK))
292 error = 0;
293 if (error == EPIPE)
c9714ae3 294 psignal(p, SIGPIPE);
9754d709 295 }
c4ec2128 296 cnt -= auio.uio_resid;
46814581
MK
297#ifdef KTRACE
298 if (ktriov != NULL) {
e64d087d 299 if (error == 0)
c9714ae3 300 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
51322105 301 ktriov, cnt, error);
46814581
MK
302 FREE(ktriov, M_TEMP);
303 }
304#endif
c9714ae3 305 *retval = cnt;
c4ec2128
KM
306done:
307 if (uap->iovcnt > UIO_SMALLIOV)
c9773de9 308 FREE(saveiov, M_IOV);
d9c2f47f 309 return (error);
4147b3f6 310}
ffe28cfe
BJ
311
312/*
313 * Ioctl system call
ffe28cfe 314 */
c9714ae3
KM
315/* ARGSUSED */
316ioctl(p, uap, retval)
317 struct proc *p;
318 register struct args {
ffe28cfe
BJ
319 int fdes;
320 int cmd;
321 caddr_t cmarg;
c9714ae3
KM
322 } *uap;
323 int *retval;
324{
325 register struct file *fp;
5e00df3b 326 register struct filedesc *fdp = p->p_fd;
9754d709 327 register int com, error;
b9429893 328 register u_int size;
e0b18aec 329 caddr_t memp = 0;
c0bb7b0e 330#define STK_PARAMS 128
08eb908c
MK
331 char stkbuf[STK_PARAMS];
332 caddr_t data = stkbuf;
ffe28cfe 333
8429d022 334 if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
5e00df3b 335 (fp = OFILE(fdp, uap->fdes)) == NULL)
d9c2f47f 336 return (EBADF);
9754d709 337 if ((fp->f_flag & (FREAD|FWRITE)) == 0)
d9c2f47f 338 return (EBADF);
4b72e2f9
SL
339 com = uap->cmd;
340
4b72e2f9 341 if (com == FIOCLEX) {
5e00df3b 342 OFILEFLAGS(fdp, uap->fdes) |= UF_EXCLOSE;
d9c2f47f 343 return (0);
ffe28cfe 344 }
4b72e2f9 345 if (com == FIONCLEX) {
5e00df3b 346 OFILEFLAGS(fdp, uap->fdes) &= ~UF_EXCLOSE;
d9c2f47f 347 return (0);
ffe28cfe 348 }
4b72e2f9
SL
349
350 /*
351 * Interpret high order word to find
352 * amount of data to be copied to/from the
353 * user's address space.
4b72e2f9 354 */
c0bb7b0e 355 size = IOCPARM_LEN(com);
9754d709 356 if (size > IOCPARM_MAX)
d9c2f47f 357 return (ENOTTY);
08eb908c 358 if (size > sizeof (stkbuf)) {
f452da3a 359 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
e0b18aec 360 data = memp;
c0bb7b0e 361 }
471f17ed
SL
362 if (com&IOC_IN) {
363 if (size) {
9754d709
MK
364 error = copyin(uap->cmarg, data, (u_int)size);
365 if (error) {
e0b18aec
KM
366 if (memp)
367 free(memp, M_IOCTLOPS);
d9c2f47f 368 return (error);
e0b18aec 369 }
471f17ed
SL
370 } else
371 *(caddr_t *)data = uap->cmarg;
372 } else if ((com&IOC_OUT) && size)
373 /*
46814581
MK
374 * Zero the buffer so the user always
375 * gets back something deterministic.
471f17ed 376 */
c0bb7b0e 377 bzero(data, size);
a76b60f6
SL
378 else if (com&IOC_VOID)
379 *(caddr_t *)data = uap->cmarg;
4b72e2f9 380
88a7a62a
SL
381 switch (com) {
382
383 case FIONBIO:
9754d709 384 error = fset(fp, FNDELAY, *(int *)data);
c0bb7b0e 385 break;
88a7a62a
SL
386
387 case FIOASYNC:
9754d709 388 error = fset(fp, FASYNC, *(int *)data);
c0bb7b0e 389 break;
88a7a62a
SL
390
391 case FIOSETOWN:
9754d709 392 error = fsetown(fp, *(int *)data);
c0bb7b0e 393 break;
4b72e2f9 394
88a7a62a 395 case FIOGETOWN:
9754d709 396 error = fgetown(fp, (int *)data);
c0bb7b0e
MK
397 break;
398 default:
8429d022 399 error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
c0bb7b0e
MK
400 /*
401 * Copy any data to user, size was
402 * already set and checked above.
403 */
9754d709
MK
404 if (error == 0 && (com&IOC_OUT) && size)
405 error = copyout(data, uap->cmarg, (u_int)size);
c0bb7b0e 406 break;
88a7a62a 407 }
e0b18aec
KM
408 if (memp)
409 free(memp, M_IOCTLOPS);
d9c2f47f 410 return (error);
ffe28cfe
BJ
411}
412
88a7a62a 413int nselcoll;
d441e5bc 414
ffe28cfe 415/*
88a7a62a 416 * Select system call.
ffe28cfe 417 */
c9714ae3
KM
418select(p, uap, retval)
419 register struct proc *p;
420 register struct args {
88a7a62a 421 int nd;
b8e71e77 422 fd_set *in, *ou, *ex;
88a7a62a 423 struct timeval *tv;
c9714ae3
KM
424 } *uap;
425 int *retval;
426{
b8e71e77 427 fd_set ibits[3], obits[3];
88a7a62a 428 struct timeval atv;
9754d709 429 int s, ncoll, ni, error = 0, timo;
88a7a62a 430
01b0e233
MK
431 bzero((caddr_t)ibits, sizeof(ibits));
432 bzero((caddr_t)obits, sizeof(obits));
8429d022
MK
433 if (uap->nd > p->p_fd->fd_nfiles)
434 uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */
b8e71e77 435 ni = howmany(uap->nd, NFDBITS);
88a7a62a
SL
436
437#define getbits(name, x) \
438 if (uap->name) { \
9754d709 439 error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
01b0e233 440 (unsigned)(ni * sizeof(fd_mask))); \
9754d709 441 if (error) \
88a7a62a 442 goto done; \
d441e5bc 443 }
88a7a62a
SL
444 getbits(in, 0);
445 getbits(ou, 1);
446 getbits(ex, 2);
447#undef getbits
448
449 if (uap->tv) {
9754d709 450 error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
88a7a62a 451 sizeof (atv));
9754d709 452 if (error)
88a7a62a
SL
453 goto done;
454 if (itimerfix(&atv)) {
9754d709 455 error = EINVAL;
88a7a62a
SL
456 goto done;
457 }
c4e1f1e5 458 s = splhigh(); timevaladd(&atv, &time); splx(s);
9754d709
MK
459 timo = hzto(&atv);
460 } else
461 timo = 0;
88a7a62a
SL
462retry:
463 ncoll = nselcoll;
c9714ae3 464 p->p_flag |= SSEL;
8429d022 465 error = selscan(p, ibits, obits, uap->nd, retval);
c9714ae3 466 if (error || *retval)
88a7a62a 467 goto done;
c4e1f1e5 468 s = splhigh();
e394e134
SL
469 /* this should be timercmp(&time, &atv, >=) */
470 if (uap->tv && (time.tv_sec > atv.tv_sec ||
471 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
88a7a62a
SL
472 splx(s);
473 goto done;
474 }
c9714ae3 475 if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
88a7a62a
SL
476 splx(s);
477 goto retry;
478 }
c9714ae3 479 p->p_flag &= ~SSEL;
9754d709 480 error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
88a7a62a 481 splx(s);
9754d709
MK
482 if (error == 0)
483 goto retry;
88a7a62a 484done:
c9714ae3 485 p->p_flag &= ~SSEL;
9754d709
MK
486 /* select is not restarted after signals... */
487 if (error == ERESTART)
488 error = EINTR;
489 if (error == EWOULDBLOCK)
490 error = 0;
88a7a62a
SL
491#define putbits(name, x) \
492 if (uap->name) { \
9754d709 493 int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
01b0e233 494 (unsigned)(ni * sizeof(fd_mask))); \
9754d709
MK
495 if (error2) \
496 error = error2; \
88a7a62a 497 }
9754d709 498 if (error == 0) {
79f403fc
MK
499 putbits(in, 0);
500 putbits(ou, 1);
501 putbits(ex, 2);
88a7a62a 502#undef putbits
79f403fc 503 }
d9c2f47f 504 return (error);
88a7a62a
SL
505}
506
8429d022
MK
507selscan(p, ibits, obits, nfd, retval)
508 struct proc *p;
b8e71e77 509 fd_set *ibits, *obits;
c9714ae3 510 int nfd, *retval;
88a7a62a 511{
8429d022 512 register struct filedesc *fdp = p->p_fd;
b8e71e77
MK
513 register int which, i, j;
514 register fd_mask bits;
88a7a62a
SL
515 int flag;
516 struct file *fp;
c9714ae3 517 int error = 0, n = 0;
88a7a62a
SL
518
519 for (which = 0; which < 3; which++) {
88a7a62a
SL
520 switch (which) {
521
522 case 0:
523 flag = FREAD; break;
524
525 case 1:
526 flag = FWRITE; break;
527
528 case 2:
529 flag = 0; break;
530 }
b8e71e77
MK
531 for (i = 0; i < nfd; i += NFDBITS) {
532 bits = ibits[which].fds_bits[i/NFDBITS];
d441e5bc
MK
533 while ((j = ffs(bits)) && i + --j < nfd) {
534 bits &= ~(1 << j);
5e00df3b 535 fp = OFILE(fdp, i + j);
d441e5bc 536 if (fp == NULL) {
c9714ae3 537 error = EBADF;
d441e5bc
MK
538 break;
539 }
8429d022 540 if ((*fp->f_ops->fo_select)(fp, flag, p)) {
b8e71e77 541 FD_SET(i + j, &obits[which]);
d441e5bc
MK
542 n++;
543 }
88a7a62a
SL
544 }
545 }
546 }
c9714ae3
KM
547 *retval = n;
548 return (error);
88a7a62a
SL
549}
550
ffe28cfe 551/*ARGSUSED*/
8429d022 552seltrue(dev, flag, p)
88a7a62a
SL
553 dev_t dev;
554 int flag;
8429d022 555 struct proc *p;
ffe28cfe
BJ
556{
557
88a7a62a 558 return (1);
ffe28cfe 559}
1edb1cf8 560
88a7a62a
SL
561selwakeup(p, coll)
562 register struct proc *p;
563 int coll;
1edb1cf8
BJ
564{
565
88a7a62a
SL
566 if (coll) {
567 nselcoll++;
568 wakeup((caddr_t)&selwait);
569 }
570 if (p) {
c4e1f1e5 571 int s = splhigh();
6bc3aba9
MK
572 if (p->p_wchan == (caddr_t)&selwait) {
573 if (p->p_stat == SSLEEP)
574 setrun(p);
575 else
576 unsleep(p);
577 } else if (p->p_flag & SSEL)
88a7a62a
SL
578 p->p_flag &= ~SSEL;
579 splx(s);
580 }
1edb1cf8 581}