1 | /* $NetBSD: sys_descrip.c,v 1.30 2014/09/05 09:20:59 matt Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | /* |
30 | * Copyright (c) 1982, 1986, 1989, 1991, 1993 |
31 | * The Regents of the University of California. All rights reserved. |
32 | * (c) UNIX System Laboratories, Inc. |
33 | * All or some portions of this file are derived from material licensed |
34 | * to the University of California by American Telephone and Telegraph |
35 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
36 | * the permission of UNIX System Laboratories, Inc. |
37 | * |
38 | * Redistribution and use in source and binary forms, with or without |
39 | * modification, are permitted provided that the following conditions |
40 | * are met: |
41 | * 1. Redistributions of source code must retain the above copyright |
42 | * notice, this list of conditions and the following disclaimer. |
43 | * 2. Redistributions in binary form must reproduce the above copyright |
44 | * notice, this list of conditions and the following disclaimer in the |
45 | * documentation and/or other materials provided with the distribution. |
46 | * 3. Neither the name of the University nor the names of its contributors |
47 | * may be used to endorse or promote products derived from this software |
48 | * without specific prior written permission. |
49 | * |
50 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
51 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
52 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
53 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
54 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
55 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
56 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
57 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
58 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
59 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
60 | * SUCH DAMAGE. |
61 | * |
62 | * @(#)kern_descrip.c 8.8 (Berkeley) 2/14/95 |
63 | */ |
64 | |
65 | /* |
66 | * System calls on descriptors. |
67 | */ |
68 | |
69 | #include <sys/cdefs.h> |
70 | __KERNEL_RCSID(0, "$NetBSD: sys_descrip.c,v 1.30 2014/09/05 09:20:59 matt Exp $" ); |
71 | |
72 | #include <sys/param.h> |
73 | #include <sys/systm.h> |
74 | #include <sys/filedesc.h> |
75 | #include <sys/kernel.h> |
76 | #include <sys/vnode.h> |
77 | #include <sys/proc.h> |
78 | #include <sys/file.h> |
79 | #include <sys/namei.h> |
80 | #include <sys/socket.h> |
81 | #include <sys/socketvar.h> |
82 | #include <sys/stat.h> |
83 | #include <sys/ioctl.h> |
84 | #include <sys/fcntl.h> |
85 | #include <sys/kmem.h> |
86 | #include <sys/pool.h> |
87 | #include <sys/syslog.h> |
88 | #include <sys/unistd.h> |
89 | #include <sys/resourcevar.h> |
90 | #include <sys/conf.h> |
91 | #include <sys/event.h> |
92 | #include <sys/kauth.h> |
93 | #include <sys/atomic.h> |
94 | #include <sys/mount.h> |
95 | #include <sys/syscallargs.h> |
96 | |
97 | #include <uvm/uvm_readahead.h> |
98 | |
99 | /* |
100 | * Duplicate a file descriptor. |
101 | */ |
102 | int |
103 | sys_dup(struct lwp *l, const struct sys_dup_args *uap, register_t *retval) |
104 | { |
105 | /* { |
106 | syscallarg(int) fd; |
107 | } */ |
108 | int error, newfd, oldfd; |
109 | file_t *fp; |
110 | |
111 | oldfd = SCARG(uap, fd); |
112 | |
113 | if ((fp = fd_getfile(oldfd)) == NULL) { |
114 | return EBADF; |
115 | } |
116 | error = fd_dup(fp, 0, &newfd, false); |
117 | fd_putfile(oldfd); |
118 | *retval = newfd; |
119 | return error; |
120 | } |
121 | |
122 | /* |
123 | * Duplicate a file descriptor to a particular value. |
124 | */ |
125 | int |
126 | dodup(struct lwp *l, int from, int to, int flags, register_t *retval) |
127 | { |
128 | int error; |
129 | file_t *fp; |
130 | |
131 | if ((fp = fd_getfile(from)) == NULL) |
132 | return EBADF; |
133 | mutex_enter(&fp->f_lock); |
134 | fp->f_count++; |
135 | mutex_exit(&fp->f_lock); |
136 | fd_putfile(from); |
137 | |
138 | if ((u_int)to >= curproc->p_rlimit[RLIMIT_NOFILE].rlim_cur || |
139 | (u_int)to >= maxfiles) |
140 | error = EBADF; |
141 | else if (from == to) |
142 | error = 0; |
143 | else |
144 | error = fd_dup2(fp, to, flags); |
145 | closef(fp); |
146 | *retval = to; |
147 | |
148 | return error; |
149 | } |
150 | |
151 | int |
152 | sys_dup3(struct lwp *l, const struct sys_dup3_args *uap, register_t *retval) |
153 | { |
154 | /* { |
155 | syscallarg(int) from; |
156 | syscallarg(int) to; |
157 | syscallarg(int) flags; |
158 | } */ |
159 | return dodup(l, SCARG(uap, from), SCARG(uap, to), SCARG(uap, flags), |
160 | retval); |
161 | } |
162 | |
163 | int |
164 | sys_dup2(struct lwp *l, const struct sys_dup2_args *uap, register_t *retval) |
165 | { |
166 | /* { |
167 | syscallarg(int) from; |
168 | syscallarg(int) to; |
169 | } */ |
170 | return dodup(l, SCARG(uap, from), SCARG(uap, to), 0, retval); |
171 | } |
172 | |
173 | /* |
174 | * fcntl call which is being passed to the file's fs. |
175 | */ |
176 | static int |
177 | fcntl_forfs(int fd, file_t *fp, int cmd, void *arg) |
178 | { |
179 | int error; |
180 | u_int size; |
181 | void *data, *memp; |
182 | #define STK_PARAMS 128 |
183 | char stkbuf[STK_PARAMS]; |
184 | |
185 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) |
186 | return (EBADF); |
187 | |
188 | /* |
189 | * Interpret high order word to find amount of data to be |
190 | * copied to/from the user's address space. |
191 | */ |
192 | size = (size_t)F_PARAM_LEN(cmd); |
193 | if (size > F_PARAM_MAX) |
194 | return (EINVAL); |
195 | memp = NULL; |
196 | if (size > sizeof(stkbuf)) { |
197 | memp = kmem_alloc(size, KM_SLEEP); |
198 | data = memp; |
199 | } else |
200 | data = stkbuf; |
201 | if (cmd & F_FSIN) { |
202 | if (size) { |
203 | error = copyin(arg, data, size); |
204 | if (error) { |
205 | if (memp) |
206 | kmem_free(memp, size); |
207 | return (error); |
208 | } |
209 | } else |
210 | *(void **)data = arg; |
211 | } else if ((cmd & F_FSOUT) != 0 && size != 0) { |
212 | /* |
213 | * Zero the buffer so the user always |
214 | * gets back something deterministic. |
215 | */ |
216 | memset(data, 0, size); |
217 | } else if (cmd & F_FSVOID) |
218 | *(void **)data = arg; |
219 | |
220 | |
221 | error = (*fp->f_ops->fo_fcntl)(fp, cmd, data); |
222 | |
223 | /* |
224 | * Copy any data to user, size was |
225 | * already set and checked above. |
226 | */ |
227 | if (error == 0 && (cmd & F_FSOUT) && size) |
228 | error = copyout(data, arg, size); |
229 | if (memp) |
230 | kmem_free(memp, size); |
231 | return (error); |
232 | } |
233 | |
234 | int |
235 | do_fcntl_lock(int fd, int cmd, struct flock *fl) |
236 | { |
237 | file_t *fp; |
238 | vnode_t *vp; |
239 | proc_t *p; |
240 | int error, flg; |
241 | |
242 | if ((fp = fd_getfile(fd)) == NULL) |
243 | return EBADF; |
244 | if (fp->f_type != DTYPE_VNODE) { |
245 | fd_putfile(fd); |
246 | return EINVAL; |
247 | } |
248 | vp = fp->f_vnode; |
249 | if (fl->l_whence == SEEK_CUR) |
250 | fl->l_start += fp->f_offset; |
251 | |
252 | flg = F_POSIX; |
253 | p = curproc; |
254 | |
255 | switch (cmd) { |
256 | case F_SETLKW: |
257 | flg |= F_WAIT; |
258 | /* Fall into F_SETLK */ |
259 | |
260 | case F_SETLK: |
261 | switch (fl->l_type) { |
262 | case F_RDLCK: |
263 | if ((fp->f_flag & FREAD) == 0) { |
264 | error = EBADF; |
265 | break; |
266 | } |
267 | if ((p->p_flag & PK_ADVLOCK) == 0) { |
268 | mutex_enter(p->p_lock); |
269 | p->p_flag |= PK_ADVLOCK; |
270 | mutex_exit(p->p_lock); |
271 | } |
272 | error = VOP_ADVLOCK(vp, p, F_SETLK, fl, flg); |
273 | break; |
274 | |
275 | case F_WRLCK: |
276 | if ((fp->f_flag & FWRITE) == 0) { |
277 | error = EBADF; |
278 | break; |
279 | } |
280 | if ((p->p_flag & PK_ADVLOCK) == 0) { |
281 | mutex_enter(p->p_lock); |
282 | p->p_flag |= PK_ADVLOCK; |
283 | mutex_exit(p->p_lock); |
284 | } |
285 | error = VOP_ADVLOCK(vp, p, F_SETLK, fl, flg); |
286 | break; |
287 | |
288 | case F_UNLCK: |
289 | error = VOP_ADVLOCK(vp, p, F_UNLCK, fl, F_POSIX); |
290 | break; |
291 | |
292 | default: |
293 | error = EINVAL; |
294 | break; |
295 | } |
296 | break; |
297 | |
298 | case F_GETLK: |
299 | if (fl->l_type != F_RDLCK && |
300 | fl->l_type != F_WRLCK && |
301 | fl->l_type != F_UNLCK) { |
302 | error = EINVAL; |
303 | break; |
304 | } |
305 | error = VOP_ADVLOCK(vp, p, F_GETLK, fl, F_POSIX); |
306 | break; |
307 | |
308 | default: |
309 | error = EINVAL; |
310 | break; |
311 | } |
312 | |
313 | fd_putfile(fd); |
314 | return error; |
315 | } |
316 | |
317 | /* |
318 | * The file control system call. |
319 | */ |
320 | int |
321 | sys_fcntl(struct lwp *l, const struct sys_fcntl_args *uap, register_t *retval) |
322 | { |
323 | /* { |
324 | syscallarg(int) fd; |
325 | syscallarg(int) cmd; |
326 | syscallarg(void *) arg; |
327 | } */ |
328 | int fd, i, tmp, error, cmd, newmin; |
329 | filedesc_t *fdp; |
330 | file_t *fp; |
331 | struct flock fl; |
332 | bool cloexec = false; |
333 | |
334 | fd = SCARG(uap, fd); |
335 | cmd = SCARG(uap, cmd); |
336 | fdp = l->l_fd; |
337 | error = 0; |
338 | |
339 | switch (cmd) { |
340 | case F_CLOSEM: |
341 | if (fd < 0) |
342 | return EBADF; |
343 | while ((i = fdp->fd_lastfile) >= fd) { |
344 | if (fd_getfile(i) == NULL) { |
345 | /* Another thread has updated. */ |
346 | continue; |
347 | } |
348 | fd_close(i); |
349 | } |
350 | return 0; |
351 | |
352 | case F_MAXFD: |
353 | *retval = fdp->fd_lastfile; |
354 | return 0; |
355 | |
356 | case F_SETLKW: |
357 | case F_SETLK: |
358 | case F_GETLK: |
359 | error = copyin(SCARG(uap, arg), &fl, sizeof(fl)); |
360 | if (error) |
361 | return error; |
362 | error = do_fcntl_lock(fd, cmd, &fl); |
363 | if (cmd == F_GETLK && error == 0) |
364 | error = copyout(&fl, SCARG(uap, arg), sizeof(fl)); |
365 | return error; |
366 | |
367 | default: |
368 | /* Handled below */ |
369 | break; |
370 | } |
371 | |
372 | if ((fp = fd_getfile(fd)) == NULL) |
373 | return (EBADF); |
374 | |
375 | if ((cmd & F_FSCTL)) { |
376 | error = fcntl_forfs(fd, fp, cmd, SCARG(uap, arg)); |
377 | fd_putfile(fd); |
378 | return error; |
379 | } |
380 | |
381 | switch (cmd) { |
382 | case F_DUPFD_CLOEXEC: |
383 | cloexec = true; |
384 | /*FALLTHROUGH*/ |
385 | case F_DUPFD: |
386 | newmin = (long)SCARG(uap, arg); |
387 | if ((u_int)newmin >= |
388 | l->l_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur || |
389 | (u_int)newmin >= maxfiles) { |
390 | fd_putfile(fd); |
391 | return EINVAL; |
392 | } |
393 | error = fd_dup(fp, newmin, &i, cloexec); |
394 | *retval = i; |
395 | break; |
396 | |
397 | case F_GETFD: |
398 | *retval = fdp->fd_dt->dt_ff[fd]->ff_exclose; |
399 | break; |
400 | |
401 | case F_SETFD: |
402 | fd_set_exclose(l, fd, |
403 | ((long)SCARG(uap, arg) & FD_CLOEXEC) != 0); |
404 | break; |
405 | |
406 | case F_GETNOSIGPIPE: |
407 | *retval = (fp->f_flag & FNOSIGPIPE) != 0; |
408 | break; |
409 | |
410 | case F_SETNOSIGPIPE: |
411 | if (SCARG(uap, arg)) |
412 | atomic_or_uint(&fp->f_flag, FNOSIGPIPE); |
413 | else |
414 | atomic_and_uint(&fp->f_flag, ~FNOSIGPIPE); |
415 | *retval = 0; |
416 | break; |
417 | |
418 | case F_GETFL: |
419 | *retval = OFLAGS(fp->f_flag); |
420 | break; |
421 | |
422 | case F_SETFL: |
423 | /* XXX not guaranteed to be atomic. */ |
424 | tmp = FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS; |
425 | error = (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &tmp); |
426 | if (error) |
427 | break; |
428 | i = tmp ^ fp->f_flag; |
429 | if (i & FNONBLOCK) { |
430 | int flgs = tmp & FNONBLOCK; |
431 | error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, &flgs); |
432 | if (error) { |
433 | (*fp->f_ops->fo_fcntl)(fp, F_SETFL, |
434 | &fp->f_flag); |
435 | break; |
436 | } |
437 | } |
438 | if (i & FASYNC) { |
439 | int flgs = tmp & FASYNC; |
440 | error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, &flgs); |
441 | if (error) { |
442 | if (i & FNONBLOCK) { |
443 | tmp = fp->f_flag & FNONBLOCK; |
444 | (void)(*fp->f_ops->fo_ioctl)(fp, |
445 | FIONBIO, &tmp); |
446 | } |
447 | (*fp->f_ops->fo_fcntl)(fp, F_SETFL, |
448 | &fp->f_flag); |
449 | break; |
450 | } |
451 | } |
452 | fp->f_flag = (fp->f_flag & ~FCNTLFLAGS) | tmp; |
453 | break; |
454 | |
455 | case F_GETOWN: |
456 | error = (*fp->f_ops->fo_ioctl)(fp, FIOGETOWN, &tmp); |
457 | *retval = tmp; |
458 | break; |
459 | |
460 | case F_SETOWN: |
461 | tmp = (int)(uintptr_t) SCARG(uap, arg); |
462 | error = (*fp->f_ops->fo_ioctl)(fp, FIOSETOWN, &tmp); |
463 | break; |
464 | |
465 | default: |
466 | error = EINVAL; |
467 | } |
468 | |
469 | fd_putfile(fd); |
470 | return (error); |
471 | } |
472 | |
473 | /* |
474 | * Close a file descriptor. |
475 | */ |
476 | int |
477 | sys_close(struct lwp *l, const struct sys_close_args *uap, register_t *retval) |
478 | { |
479 | /* { |
480 | syscallarg(int) fd; |
481 | } */ |
482 | int error; |
483 | |
484 | if (fd_getfile(SCARG(uap, fd)) == NULL) { |
485 | return EBADF; |
486 | } |
487 | |
488 | error = fd_close(SCARG(uap, fd)); |
489 | if (error == ERESTART) { |
490 | #ifdef DIAGNOSTIC |
491 | printf("pid %d: close returned ERESTART\n" , |
492 | (int)l->l_proc->p_pid); |
493 | #endif |
494 | error = EINTR; |
495 | } |
496 | |
497 | return error; |
498 | } |
499 | |
500 | /* |
501 | * Return status information about a file descriptor. |
502 | * Common function for compat code. |
503 | */ |
504 | int |
505 | do_sys_fstat(int fd, struct stat *sb) |
506 | { |
507 | file_t *fp; |
508 | int error; |
509 | |
510 | if ((fp = fd_getfile(fd)) == NULL) { |
511 | return EBADF; |
512 | } |
513 | error = (*fp->f_ops->fo_stat)(fp, sb); |
514 | fd_putfile(fd); |
515 | |
516 | return error; |
517 | } |
518 | |
519 | /* |
520 | * Return status information about a file descriptor. |
521 | */ |
522 | int |
523 | sys___fstat50(struct lwp *l, const struct sys___fstat50_args *uap, |
524 | register_t *retval) |
525 | { |
526 | /* { |
527 | syscallarg(int) fd; |
528 | syscallarg(struct stat *) sb; |
529 | } */ |
530 | struct stat sb; |
531 | int error; |
532 | |
533 | error = do_sys_fstat(SCARG(uap, fd), &sb); |
534 | if (error == 0) { |
535 | error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); |
536 | } |
537 | return error; |
538 | } |
539 | |
540 | /* |
541 | * Return pathconf information about a file descriptor. |
542 | */ |
543 | int |
544 | sys_fpathconf(struct lwp *l, const struct sys_fpathconf_args *uap, |
545 | register_t *retval) |
546 | { |
547 | /* { |
548 | syscallarg(int) fd; |
549 | syscallarg(int) name; |
550 | } */ |
551 | int fd, error; |
552 | file_t *fp; |
553 | |
554 | fd = SCARG(uap, fd); |
555 | error = 0; |
556 | |
557 | if ((fp = fd_getfile(fd)) == NULL) { |
558 | return (EBADF); |
559 | } |
560 | switch (fp->f_type) { |
561 | case DTYPE_SOCKET: |
562 | case DTYPE_PIPE: |
563 | if (SCARG(uap, name) != _PC_PIPE_BUF) |
564 | error = EINVAL; |
565 | else |
566 | *retval = PIPE_BUF; |
567 | break; |
568 | |
569 | case DTYPE_VNODE: |
570 | error = VOP_PATHCONF(fp->f_vnode, SCARG(uap, name), retval); |
571 | break; |
572 | |
573 | case DTYPE_KQUEUE: |
574 | error = EINVAL; |
575 | break; |
576 | |
577 | default: |
578 | error = EOPNOTSUPP; |
579 | break; |
580 | } |
581 | |
582 | fd_putfile(fd); |
583 | return (error); |
584 | } |
585 | |
586 | /* |
587 | * Apply an advisory lock on a file descriptor. |
588 | * |
589 | * Just attempt to get a record lock of the requested type on |
590 | * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). |
591 | */ |
592 | /* ARGSUSED */ |
593 | int |
594 | sys_flock(struct lwp *l, const struct sys_flock_args *uap, register_t *retval) |
595 | { |
596 | /* { |
597 | syscallarg(int) fd; |
598 | syscallarg(int) how; |
599 | } */ |
600 | int fd, how, error; |
601 | file_t *fp; |
602 | vnode_t *vp; |
603 | struct flock lf; |
604 | |
605 | fd = SCARG(uap, fd); |
606 | how = SCARG(uap, how); |
607 | error = 0; |
608 | |
609 | if ((fp = fd_getfile(fd)) == NULL) { |
610 | return EBADF; |
611 | } |
612 | if (fp->f_type != DTYPE_VNODE) { |
613 | fd_putfile(fd); |
614 | return EOPNOTSUPP; |
615 | } |
616 | |
617 | vp = fp->f_vnode; |
618 | lf.l_whence = SEEK_SET; |
619 | lf.l_start = 0; |
620 | lf.l_len = 0; |
621 | |
622 | switch (how & ~LOCK_NB) { |
623 | case LOCK_UN: |
624 | lf.l_type = F_UNLCK; |
625 | atomic_and_uint(&fp->f_flag, ~FHASLOCK); |
626 | error = VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); |
627 | fd_putfile(fd); |
628 | return error; |
629 | case LOCK_EX: |
630 | lf.l_type = F_WRLCK; |
631 | break; |
632 | case LOCK_SH: |
633 | lf.l_type = F_RDLCK; |
634 | break; |
635 | default: |
636 | fd_putfile(fd); |
637 | return EINVAL; |
638 | } |
639 | |
640 | atomic_or_uint(&fp->f_flag, FHASLOCK); |
641 | if (how & LOCK_NB) { |
642 | error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK); |
643 | } else { |
644 | error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT); |
645 | } |
646 | fd_putfile(fd); |
647 | return error; |
648 | } |
649 | |
650 | int |
651 | do_posix_fadvise(int fd, off_t offset, off_t len, int advice) |
652 | { |
653 | file_t *fp; |
654 | vnode_t *vp; |
655 | off_t endoffset; |
656 | int error; |
657 | |
658 | CTASSERT(POSIX_FADV_NORMAL == UVM_ADV_NORMAL); |
659 | CTASSERT(POSIX_FADV_RANDOM == UVM_ADV_RANDOM); |
660 | CTASSERT(POSIX_FADV_SEQUENTIAL == UVM_ADV_SEQUENTIAL); |
661 | |
662 | if (len == 0) { |
663 | endoffset = INT64_MAX; |
664 | } else if (len > 0 && (INT64_MAX - offset) >= len) { |
665 | endoffset = offset + len; |
666 | } else { |
667 | return EINVAL; |
668 | } |
669 | if ((fp = fd_getfile(fd)) == NULL) { |
670 | return EBADF; |
671 | } |
672 | if (fp->f_type != DTYPE_VNODE) { |
673 | if (fp->f_type == DTYPE_PIPE || fp->f_type == DTYPE_SOCKET) { |
674 | error = ESPIPE; |
675 | } else { |
676 | error = EOPNOTSUPP; |
677 | } |
678 | fd_putfile(fd); |
679 | return error; |
680 | } |
681 | |
682 | switch (advice) { |
683 | case POSIX_FADV_WILLNEED: |
684 | case POSIX_FADV_DONTNEED: |
685 | vp = fp->f_vnode; |
686 | if (vp->v_type != VREG && vp->v_type != VBLK) { |
687 | fd_putfile(fd); |
688 | return 0; |
689 | } |
690 | break; |
691 | } |
692 | |
693 | switch (advice) { |
694 | case POSIX_FADV_NORMAL: |
695 | case POSIX_FADV_RANDOM: |
696 | case POSIX_FADV_SEQUENTIAL: |
697 | /* |
698 | * We ignore offset and size. Must lock the file to |
699 | * do this, as f_advice is sub-word sized. |
700 | */ |
701 | mutex_enter(&fp->f_lock); |
702 | fp->f_advice = (u_char)advice; |
703 | mutex_exit(&fp->f_lock); |
704 | error = 0; |
705 | break; |
706 | |
707 | case POSIX_FADV_WILLNEED: |
708 | vp = fp->f_vnode; |
709 | error = uvm_readahead(&vp->v_uobj, offset, endoffset - offset); |
710 | break; |
711 | |
712 | case POSIX_FADV_DONTNEED: |
713 | vp = fp->f_vnode; |
714 | /* |
715 | * Align the region to page boundaries as VOP_PUTPAGES expects |
716 | * by shrinking it. We shrink instead of expand because we |
717 | * do not want to deactivate cache outside of the requested |
718 | * region. It means that if the specified region is smaller |
719 | * than PAGE_SIZE, we do nothing. |
720 | */ |
721 | if (round_page(offset) < trunc_page(endoffset) && |
722 | offset <= round_page(offset)) { |
723 | mutex_enter(vp->v_interlock); |
724 | error = VOP_PUTPAGES(vp, |
725 | round_page(offset), trunc_page(endoffset), |
726 | PGO_DEACTIVATE | PGO_CLEANIT); |
727 | } else { |
728 | error = 0; |
729 | } |
730 | break; |
731 | |
732 | case POSIX_FADV_NOREUSE: |
733 | /* Not implemented yet. */ |
734 | error = 0; |
735 | break; |
736 | default: |
737 | error = EINVAL; |
738 | break; |
739 | } |
740 | |
741 | fd_putfile(fd); |
742 | return error; |
743 | } |
744 | |
745 | int |
746 | sys___posix_fadvise50(struct lwp *l, |
747 | const struct sys___posix_fadvise50_args *uap, |
748 | register_t *retval) |
749 | { |
750 | /* { |
751 | syscallarg(int) fd; |
752 | syscallarg(int) pad; |
753 | syscallarg(off_t) offset; |
754 | syscallarg(off_t) len; |
755 | syscallarg(int) advice; |
756 | } */ |
757 | |
758 | *retval = do_posix_fadvise(SCARG(uap, fd), SCARG(uap, offset), |
759 | SCARG(uap, len), SCARG(uap, advice)); |
760 | |
761 | return 0; |
762 | } |
763 | |
764 | int |
765 | sys_pipe(struct lwp *l, const void *v, register_t *retval) |
766 | { |
767 | return pipe1(l, retval, 0); |
768 | } |
769 | |
770 | int |
771 | sys_pipe2(struct lwp *l, const struct sys_pipe2_args *uap, register_t *retval) |
772 | { |
773 | /* { |
774 | syscallarg(int[2]) fildes; |
775 | syscallarg(int) flags; |
776 | } */ |
777 | int fd[2], error; |
778 | |
779 | if ((error = pipe1(l, retval, SCARG(uap, flags))) != 0) |
780 | return error; |
781 | fd[0] = retval[0]; |
782 | fd[1] = retval[1]; |
783 | if ((error = copyout(fd, SCARG(uap, fildes), sizeof(fd))) != 0) |
784 | return error; |
785 | retval[0] = 0; |
786 | return 0; |
787 | } |
788 | |