Revert r255672, it has some serious flaws, leaking file references etc.

Approved by:	re (delphij)
This commit is contained in:
Roman Divacky 2013-09-18 18:48:33 +00:00
parent 70ccaaf58e
commit b12698e1a1
14 changed files with 69 additions and 736 deletions

View File

@ -70,6 +70,9 @@ DUMMY(pivot_root);
DUMMY(mincore); DUMMY(mincore);
DUMMY(ptrace); DUMMY(ptrace);
DUMMY(lookup_dcookie); DUMMY(lookup_dcookie);
DUMMY(epoll_create);
DUMMY(epoll_ctl);
DUMMY(epoll_wait);
DUMMY(remap_file_pages); DUMMY(remap_file_pages);
DUMMY(timer_create); DUMMY(timer_create);
DUMMY(timer_settime); DUMMY(timer_settime);
@ -126,6 +129,7 @@ DUMMY(timerfd_gettime);
/* linux 2.6.27: */ /* linux 2.6.27: */
DUMMY(signalfd4); DUMMY(signalfd4);
DUMMY(eventfd2); DUMMY(eventfd2);
DUMMY(epoll_create1);
DUMMY(dup3); DUMMY(dup3);
DUMMY(inotify_init1); DUMMY(inotify_init1);
/* linux 2.6.30: */ /* linux 2.6.30: */

View File

@ -430,11 +430,9 @@
251 AUE_NULL UNIMPL 251 AUE_NULL UNIMPL
252 AUE_EXIT STD { int linux_exit_group(int error_code); } 252 AUE_EXIT STD { int linux_exit_group(int error_code); }
253 AUE_NULL STD { int linux_lookup_dcookie(void); } 253 AUE_NULL STD { int linux_lookup_dcookie(void); }
254 AUE_NULL STD { int linux_epoll_create(l_int size); } 254 AUE_NULL STD { int linux_epoll_create(void); }
255 AUE_NULL STD { int linux_epoll_ctl(l_int epfd, l_int op, l_int fd, \ 255 AUE_NULL STD { int linux_epoll_ctl(void); }
struct linux_epoll_event *event); } 256 AUE_NULL STD { int linux_epoll_wait(void); }
256 AUE_NULL STD { int linux_epoll_wait(l_int epfd, struct linux_epoll_event *events, \
l_int maxevents, l_int timeout); }
257 AUE_NULL STD { int linux_remap_file_pages(void); } 257 AUE_NULL STD { int linux_remap_file_pages(void); }
258 AUE_NULL STD { int linux_set_tid_address(int *tidptr); } 258 AUE_NULL STD { int linux_set_tid_address(int *tidptr); }
259 AUE_NULL STD { int linux_timer_create(void); } 259 AUE_NULL STD { int linux_timer_create(void); }
@ -536,7 +534,7 @@
; linux 2.6.27: ; linux 2.6.27:
327 AUE_NULL STD { int linux_signalfd4(void); } 327 AUE_NULL STD { int linux_signalfd4(void); }
328 AUE_NULL STD { int linux_eventfd2(void); } 328 AUE_NULL STD { int linux_eventfd2(void); }
329 AUE_NULL STD { int linux_epoll_create1(l_int flags); } 329 AUE_NULL STD { int linux_epoll_create1(void); }
330 AUE_NULL STD { int linux_dup3(void); } 330 AUE_NULL STD { int linux_dup3(void); }
331 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); } 331 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); }
332 AUE_NULL STD { int linux_inotify_init1(void); } 332 AUE_NULL STD { int linux_inotify_init1(void); }

View File

@ -1,554 +0,0 @@
/*-
* Copyright (c) 2007 Roman Divacky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_ktrace.h"
#include <sys/limits.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/capability.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/errno.h>
#include <sys/event.h>
#include <sys/proc.h>
#include <sys/sysproto.h>
#include <sys/syscallsubr.h>
#include <sys/timespec.h>
#include <compat/linux/linux_epoll.h>
#include <compat/linux/linux_util.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
#include <machine/../linux32/linux32_proto.h>
#else
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
#endif
#define ktrepoll_events(evt, count) \
ktrstruct("linux_epoll_event", (evt), count * sizeof(*evt))
/*
* epoll defines 'struct epoll_event' with the field 'data' as 64 bits
* on all architectures. But on 32 bit architectures BSD 'struct kevent' only
* has 32 bit opaque pointer as 'udata' field. So we can't pass epoll supplied
* data verbatuim. Therefore on 32 bit architectures we allocate 64-bit memory
* block to pass user supplied data for every file descriptor.
*/
typedef uint64_t epoll_udata_t;
#if defined(__i386__)
#define EPOLL_WIDE_USER_DATA 1
#else
#define EPOLL_WIDE_USER_DATA 0
#endif
#if EPOLL_WIDE_USER_DATA
/*
* Approach similar to epoll_user_data could also be used to
* keep track of event bits per file descriptor for all architectures.
* However, it isn't obvious that such tracking would be beneficial
* in practice.
*/
struct epoll_user_data {
unsigned sz;
epoll_udata_t data[1];
};
static MALLOC_DEFINE(M_LINUX_EPOLL, "epoll", "memory for epoll system");
#define EPOLL_USER_DATA_SIZE(ndata) \
(sizeof(struct epoll_user_data)+((ndata)-1)*sizeof(epoll_udata_t))
#define EPOLL_USER_DATA_MARGIN 16
static void epoll_init_user_data(struct thread *td, struct file *epfp);
static void epoll_set_user_data(struct thread *td, struct file *epfp, int fd, epoll_udata_t user_data);
static epoll_udata_t epoll_get_user_data(struct thread *td, struct file *epfp, int fd);
static fo_close_t epoll_close;
/* overload kqueue fileops */
static struct fileops epollops = {
.fo_read = kqueue_read,
.fo_write = kqueue_write,
.fo_truncate = kqueue_truncate,
.fo_ioctl = kqueue_ioctl,
.fo_poll = kqueue_poll,
.fo_kqfilter = kqueue_kqfilter,
.fo_stat = kqueue_stat,
.fo_close = epoll_close,
.fo_chmod = invfo_chmod,
.fo_chown = invfo_chown,
.fo_sendfile = invfo_sendfile,
};
#endif
static struct file* epoll_fget(struct thread *td, int epfd);
struct epoll_copyin_args {
struct kevent *changelist;
};
struct epoll_copyout_args {
struct linux_epoll_event *leventlist;
int count;
int error;
#if KTRACE || EPOLL_WIDE_USER_DATA
struct thread *td;
#endif
#if EPOLL_WIDE_USER_DATA
struct file *epfp;
#endif
};
/* Create a new epoll file descriptor. */
static int
linux_epoll_create_common(struct thread *td)
{
struct file *fp;
int error;
error = kern_kqueue_locked(td, &fp);
#if EPOLL_WIDE_USER_DATA
if (error == 0) {
epoll_init_user_data(td, fp);
fdrop(fp, td);
}
#endif
return (error);
}
int
linux_epoll_create(struct thread *td, struct linux_epoll_create_args *args)
{
if (args->size <= 0)
return (EINVAL);
/* args->size is unused. Linux just tests it
* and then forgets it as well. */
return (linux_epoll_create_common(td));
}
int
linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args)
{
int error;
error = linux_epoll_create_common(td);
if (!error) {
if (args->flags & LINUX_EPOLL_CLOEXEC)
td->td_proc->p_fd->fd_ofiles[td->td_retval[0]].fde_flags |= UF_EXCLOSE;
if (args->flags & LINUX_EPOLL_NONBLOCK)
linux_msg(td, "epoll_create1 doesn't yet support EPOLL_NONBLOCK flag\n");
}
return (error);
}
/* Structure converting function from epoll to kevent. */
static int
linux_epoll_to_kevent(struct thread *td,
#if EPOLL_WIDE_USER_DATA
struct file *epfp,
#endif
int fd, struct linux_epoll_event *l_event, int kev_flags, struct kevent *kevent, int *nkevents)
{
/* flags related to how event is registered */
if (l_event->events & LINUX_EPOLLONESHOT)
kev_flags |= EV_ONESHOT;
if (l_event->events & LINUX_EPOLLET) {
kev_flags |= EV_CLEAR;
}
/* flags related to what event is registered */
if (l_event->events & LINUX_EPOLLIN ||
l_event->events & LINUX_EPOLLRDNORM ||
l_event->events & LINUX_EPOLLPRI ||
l_event->events & LINUX_EPOLLRDHUP) {
EV_SET(kevent++, fd, EVFILT_READ, kev_flags, 0, 0,
(void*)(EPOLL_WIDE_USER_DATA ? 0 : l_event->data));
++*nkevents;
}
if (l_event->events & LINUX_EPOLLOUT ||
l_event->events & LINUX_EPOLLWRNORM) {
EV_SET(kevent++, fd, EVFILT_WRITE, kev_flags, 0, 0,
(void*)(EPOLL_WIDE_USER_DATA ? 0 : l_event->data));
++*nkevents;
}
if (l_event->events & LINUX_EPOLLRDBAND ||
l_event->events & LINUX_EPOLLWRBAND ||
l_event->events & LINUX_EPOLLHUP ||
l_event->events & LINUX_EPOLLMSG ||
l_event->events & LINUX_EPOLLWAKEUP ||
l_event->events & LINUX_EPOLLERR) {
linux_msg(td, "epoll_ctl doesn't yet support some event flags supplied: 0x%x\n",
l_event->events);
return (EINVAL);
}
#if EPOLL_WIDE_USER_DATA
epoll_set_user_data(td, epfp, fd, l_event->data);
#endif
return (0);
}
/*
* Structure converting function from kevent to epoll. In a case
* this is called on error in registration we store the error in
* event->data and pick it up later in linux_epoll_ctl().
*/
static void
linux_kevent_to_epoll(
#if EPOLL_WIDE_USER_DATA
struct thread *td, struct file *epfp,
#endif
struct kevent *kevent, struct linux_epoll_event *l_event)
{
if ((kevent->flags & EV_ERROR) == 0)
switch (kevent->filter) {
case EVFILT_READ:
l_event->events = LINUX_EPOLLIN|LINUX_EPOLLRDNORM|LINUX_EPOLLPRI;
break;
case EVFILT_WRITE:
l_event->events = LINUX_EPOLLOUT|LINUX_EPOLLWRNORM;
break;
}
#if EPOLL_WIDE_USER_DATA
l_event->data = epoll_get_user_data(td, epfp, kevent->ident);
#else
l_event->data = (epoll_udata_t)kevent->udata;
#endif
}
/*
* Copyout callback used by kevent. This converts kevent
* events to epoll events and copies them back to the
* userspace. This is also called on error on registering
* of the filter.
*/
static int
epoll_kev_copyout(void *arg, struct kevent *kevp, int count)
{
struct epoll_copyout_args *args;
struct linux_epoll_event *eep;
int error, i;
args = (struct epoll_copyout_args*) arg;
eep = malloc(sizeof(*eep) * count, M_TEMP, M_WAITOK | M_ZERO);
for (i = 0; i < count; i++)
linux_kevent_to_epoll(
#if EPOLL_WIDE_USER_DATA
args->td, args->epfp,
#endif
&kevp[i], &eep[i]);
error = copyout(eep, args->leventlist, count * sizeof(*eep));
if (!error) {
args->leventlist += count;
args->count += count;
} else if (!args->error)
args->error = error;
#ifdef KTRACE
if (KTRPOINT(args->td, KTR_STRUCT))
ktrepoll_events(eep, count);
#endif
free(eep, M_TEMP);
return (error);
}
/*
* Copyin callback used by kevent. This copies already
* converted filters from kernel memory to the kevent
* internal kernel memory. Hence the memcpy instead of
* copyin.
*/
static int
epoll_kev_copyin(void *arg, struct kevent *kevp, int count)
{
struct epoll_copyin_args *args;
args = (struct epoll_copyin_args*) arg;
memcpy(kevp, args->changelist, count * sizeof(*kevp));
args->changelist += count;
return (0);
}
static int
ignore_enoent(int error) {
if (error == ENOENT)
error = 0;
return (error);
}
static int
delete_event(struct thread *td, struct file *epfp, int fd, int filter)
{
struct epoll_copyin_args ciargs;
struct kevent kev;
struct kevent_copyops k_ops = { &ciargs,
NULL,
epoll_kev_copyin};
ciargs.changelist = &kev;
EV_SET(&kev, fd, filter, EV_DELETE | EV_DISABLE, 0, 0, 0);
return (kern_kevent_locked(td, epfp, 1, 0, &k_ops, NULL));
}
static int
delete_all_events(struct thread *td, struct file *epfp, int fd)
{
/* here we ignore ENONT, because we don't keep track of events here */
int error1, error2;
error1 = ignore_enoent(delete_event(td, epfp, fd, EVFILT_READ));
error2 = ignore_enoent(delete_event(td, epfp, fd, EVFILT_WRITE));
/* report any errors we got */
if (error1)
return (error1);
if (error2)
return (error2);
return (0);
}
/*
* Load epoll filter, convert it to kevent filter
* and load it into kevent subsystem.
*/
int
linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args)
{
struct file *epfp;
struct epoll_copyin_args ciargs;
struct kevent kev[2];
struct kevent_copyops k_ops = { &ciargs,
NULL,
epoll_kev_copyin};
struct linux_epoll_event le;
int kev_flags;
int nchanges = 0;
int error;
if (args->epfd == args->fd)
return (EINVAL);
if (args->op != LINUX_EPOLL_CTL_DEL) {
error = copyin(args->event, &le, sizeof(le));
if (error)
return (error);
}
#ifdef DEBUG
if (ldebug(epoll_ctl))
printf(ARGS(epoll_ctl,"%i, %i, %i, %u"), args->epfd, args->op,
args->fd, le.events);
#endif
#ifdef KTRACE
if (KTRPOINT(td, KTR_STRUCT) && args->op != LINUX_EPOLL_CTL_DEL)
ktrepoll_events(&le, 1);
#endif
epfp = epoll_fget(td, args->epfd);
ciargs.changelist = kev;
switch (args->op) {
case LINUX_EPOLL_CTL_MOD:
/* we don't memorize which events were set for this FD
on this level, so just delete all we could have set:
EVFILT_READ and EVFILT_WRITE, ignoring any errors
*/
error = delete_all_events(td, epfp, args->fd);
if (error)
goto leave;
/* FALLTHROUGH */
case LINUX_EPOLL_CTL_ADD:
kev_flags = EV_ADD | EV_ENABLE;
break;
case LINUX_EPOLL_CTL_DEL:
/* CTL_DEL means unregister this fd with this epoll */
error = delete_all_events(td, epfp, args->fd);
goto leave;
default:
error = EINVAL;
goto leave;
}
error = linux_epoll_to_kevent(td,
#if EPOLL_WIDE_USER_DATA
epfp,
#endif
args->fd, &le, kev_flags, kev, &nchanges);
if (error)
goto leave;
error = kern_kevent_locked(td, epfp, nchanges, 0, &k_ops, NULL);
leave:
fdrop(epfp, td);
return (error);
}
/*
* Wait for a filter to be triggered on the epoll file descriptor. */
int
linux_epoll_wait(struct thread *td, struct linux_epoll_wait_args *args)
{
struct file *epfp;
struct timespec ts, *tsp;
struct epoll_copyout_args coargs;
struct kevent_copyops k_ops = { &coargs,
epoll_kev_copyout,
NULL};
int error;
if (args->maxevents <= 0 || args->maxevents > LINUX_MAX_EVENTS)
return (EINVAL);
epfp = epoll_fget(td, args->epfd);
coargs.leventlist = args->events;
coargs.count = 0;
coargs.error = 0;
#if defined(KTRACE) || EPOLL_WIDE_USER_DATA
coargs.td = td;
#endif
#if EPOLL_WIDE_USER_DATA
coargs.epfp = epfp;
#endif
if (args->timeout != -1) {
if (args->timeout < 0) {
error = EINVAL;
goto leave;
}
/* Convert from milliseconds to timespec. */
ts.tv_sec = args->timeout / 1000;
ts.tv_nsec = (args->timeout % 1000) * 1000000;
tsp = &ts;
} else {
tsp = NULL;
}
error = kern_kevent_locked(td, epfp, 0, args->maxevents, &k_ops, tsp);
if (!error && coargs.error)
error = coargs.error;
/*
* kern_keven might return ENOMEM which is not expected from epoll_wait.
* Maybe we should translate that but I don't think it matters at all.
*/
if (!error)
td->td_retval[0] = coargs.count;
leave:
fdrop(epfp, td);
return (error);
}
#if EPOLL_WIDE_USER_DATA
/*
* we store user_data vector in an unused for kqueue descriptor
* field fvn_epollpriv in struct file.
*/
#define EPOLL_USER_DATA_GET(epfp) \
((struct epoll_user_data*)(epfp)->f_vnun.fvn_epollpriv)
#define EPOLL_USER_DATA_SET(epfp, udv) \
(epfp)->f_vnun.fvn_epollpriv = (udv)
static void
epoll_init_user_data(struct thread *td, struct file *epfp)
{
struct epoll_user_data *udv;
/* override file ops to have our close operation */
atomic_store_rel_ptr((volatile uintptr_t *)&epfp->f_ops, (uintptr_t)&epollops);
/* allocate epoll_user_data initially for up to 16 file descriptor values */
udv = malloc(EPOLL_USER_DATA_SIZE(EPOLL_USER_DATA_MARGIN), M_LINUX_EPOLL, M_WAITOK);
udv->sz = EPOLL_USER_DATA_MARGIN;
EPOLL_USER_DATA_SET(epfp, udv);
}
static void
epoll_set_user_data(struct thread *td, struct file *epfp, int fd, epoll_udata_t user_data)
{
struct epoll_user_data *udv = EPOLL_USER_DATA_GET(epfp);
if (fd >= udv->sz) {
udv = realloc(udv, EPOLL_USER_DATA_SIZE(fd + EPOLL_USER_DATA_MARGIN), M_LINUX_EPOLL, M_WAITOK);
udv->sz = fd + EPOLL_USER_DATA_MARGIN;
EPOLL_USER_DATA_SET(epfp, udv);
}
udv->data[fd] = user_data;
}
static epoll_udata_t
epoll_get_user_data(struct thread *td, struct file *epfp, int fd)
{
struct epoll_user_data *udv = EPOLL_USER_DATA_GET(epfp);
if (fd >= udv->sz)
panic("epoll: user data vector is too small");
return (udv->data[fd]);
}
/*ARGSUSED*/
static int
epoll_close(struct file *epfp, struct thread *td)
{
/* free user data vector */
free(EPOLL_USER_DATA_GET(epfp), M_LINUX_EPOLL);
/* over to kqueue parent */
return (kqueue_close(epfp, td));
}
#endif
static struct file*
epoll_fget(struct thread *td, int epfd)
{
struct file *fp;
cap_rights_t rights;
if (fget(td, epfd, cap_rights_init(&rights, CAP_POLL_EVENT), &fp) != 0)
panic("epoll: no file object found for kqueue descriptor");
return (fp);
}

View File

@ -1,68 +0,0 @@
/*-
* Copyright (c) 2007 Roman Divacky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _LINUX_EPOLL_H_
#define _LINUX_EPOLL_H_
#ifdef __amd64__
#define EPOLL_PACKED __packed
#else
#define EPOLL_PACKED
#endif
struct linux_epoll_event {
uint32_t events;
uint64_t data;
} EPOLL_PACKED;
#define LINUX_EPOLLIN 0x001
#define LINUX_EPOLLPRI 0x002
#define LINUX_EPOLLOUT 0x004
#define LINUX_EPOLLRDNORM 0x040
#define LINUX_EPOLLRDBAND 0x080
#define LINUX_EPOLLWRNORM 0x100
#define LINUX_EPOLLWRBAND 0x200
#define LINUX_EPOLLMSG 0x400
#define LINUX_EPOLLERR 0x008
#define LINUX_EPOLLHUP 0x010
#define LINUX_EPOLLRDHUP 0x2000
#define LINUX_EPOLLWAKEUP 1u<<29
#define LINUX_EPOLLONESHOT 1u<<30
#define LINUX_EPOLLET 1u<<31
#define LINUX_EPOLL_CTL_ADD 1
#define LINUX_EPOLL_CTL_DEL 2
#define LINUX_EPOLL_CTL_MOD 3
#define LINUX_EPOLL_CLOEXEC 02000000
#define LINUX_EPOLL_NONBLOCK 00004000
#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct linux_epoll_event))
#endif /* !_LINUX_EPOLL_H_ */

View File

@ -467,7 +467,6 @@ amd64/linux32/linux32_support.s optional compat_linux32 \
dependency "linux32_assym.h" dependency "linux32_assym.h"
amd64/linux32/linux32_sysent.c optional compat_linux32 amd64/linux32/linux32_sysent.c optional compat_linux32
amd64/linux32/linux32_sysvec.c optional compat_linux32 amd64/linux32/linux32_sysvec.c optional compat_linux32
compat/linux/linux_epoll.c optional compat_linux32
compat/linux/linux_emul.c optional compat_linux32 compat/linux/linux_emul.c optional compat_linux32
compat/linux/linux_file.c optional compat_linux32 compat/linux/linux_file.c optional compat_linux32
compat/linux/linux_fork.c optional compat_linux32 compat/linux/linux_fork.c optional compat_linux32

View File

@ -80,7 +80,6 @@ hptrr_lib.o optional hptrr \
cddl/contrib/opensolaris/common/atomic/i386/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}" cddl/contrib/opensolaris/common/atomic/i386/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}"
compat/linprocfs/linprocfs.c optional linprocfs compat/linprocfs/linprocfs.c optional linprocfs
compat/linsysfs/linsysfs.c optional linsysfs compat/linsysfs/linsysfs.c optional linsysfs
compat/linux/linux_epoll.c optional compat_linux
compat/linux/linux_emul.c optional compat_linux compat/linux/linux_emul.c optional compat_linux
compat/linux/linux_file.c optional compat_linux compat/linux/linux_file.c optional compat_linux
compat/linux/linux_fork.c optional compat_linux compat/linux/linux_fork.c optional compat_linux

View File

@ -41,7 +41,6 @@ ukbdmap.h optional ukbd_dflt_keymap \
cddl/contrib/opensolaris/common/atomic/i386/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}" cddl/contrib/opensolaris/common/atomic/i386/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}"
compat/linprocfs/linprocfs.c optional linprocfs compat/linprocfs/linprocfs.c optional linprocfs
compat/linsysfs/linsysfs.c optional linsysfs compat/linsysfs/linsysfs.c optional linsysfs
compat/linux/linux_epoll.c optional compat_linux
compat/linux/linux_emul.c optional compat_linux compat/linux/linux_emul.c optional compat_linux
compat/linux/linux_file.c optional compat_linux compat/linux/linux_file.c optional compat_linux
compat/linux/linux_fork.c optional compat_linux compat/linux/linux_fork.c optional compat_linux

View File

@ -72,6 +72,9 @@ DUMMY(setfsgid);
DUMMY(pivot_root); DUMMY(pivot_root);
DUMMY(mincore); DUMMY(mincore);
DUMMY(lookup_dcookie); DUMMY(lookup_dcookie);
DUMMY(epoll_create);
DUMMY(epoll_ctl);
DUMMY(epoll_wait);
DUMMY(remap_file_pages); DUMMY(remap_file_pages);
DUMMY(fstatfs64); DUMMY(fstatfs64);
DUMMY(mbind); DUMMY(mbind);
@ -117,6 +120,7 @@ DUMMY(timerfd_gettime);
/* linux 2.6.27: */ /* linux 2.6.27: */
DUMMY(signalfd4); DUMMY(signalfd4);
DUMMY(eventfd2); DUMMY(eventfd2);
DUMMY(epoll_create1);
DUMMY(dup3); DUMMY(dup3);
DUMMY(inotify_init1); DUMMY(inotify_init1);
/* linux 2.6.30: */ /* linux 2.6.30: */

View File

@ -432,11 +432,9 @@
251 AUE_NULL UNIMPL 251 AUE_NULL UNIMPL
252 AUE_EXIT STD { int linux_exit_group(int error_code); } 252 AUE_EXIT STD { int linux_exit_group(int error_code); }
253 AUE_NULL STD { int linux_lookup_dcookie(void); } 253 AUE_NULL STD { int linux_lookup_dcookie(void); }
254 AUE_NULL STD { int linux_epoll_create(l_int size); } 254 AUE_NULL STD { int linux_epoll_create(void); }
255 AUE_NULL STD { int linux_epoll_ctl(l_int epfd, l_int op, l_int fd, \ 255 AUE_NULL STD { int linux_epoll_ctl(void); }
struct linux_epoll_event *event); } 256 AUE_NULL STD { int linux_epoll_wait(void); }
256 AUE_NULL STD { int linux_epoll_wait(l_int epfd, struct linux_epoll_event *events, \
l_int maxevents, l_int timeout); }
257 AUE_NULL STD { int linux_remap_file_pages(void); } 257 AUE_NULL STD { int linux_remap_file_pages(void); }
258 AUE_NULL STD { int linux_set_tid_address(int *tidptr); } 258 AUE_NULL STD { int linux_set_tid_address(int *tidptr); }
259 AUE_NULL STD { int linux_timer_create(clockid_t clock_id, \ 259 AUE_NULL STD { int linux_timer_create(clockid_t clock_id, \
@ -546,7 +544,7 @@
; linux 2.6.27: ; linux 2.6.27:
327 AUE_NULL STD { int linux_signalfd4(void); } 327 AUE_NULL STD { int linux_signalfd4(void); }
328 AUE_NULL STD { int linux_eventfd2(void); } 328 AUE_NULL STD { int linux_eventfd2(void); }
329 AUE_NULL STD { int linux_epoll_create1(l_int flags); } 329 AUE_NULL STD { int linux_epoll_create1(void); }
330 AUE_NULL STD { int linux_dup3(void); } 330 AUE_NULL STD { int linux_dup3(void); }
331 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); } 331 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); }
332 AUE_NULL STD { int linux_inotify_init1(void); } 332 AUE_NULL STD { int linux_inotify_init1(void); }

View File

@ -107,7 +107,16 @@ static void kqueue_wakeup(struct kqueue *kq);
static struct filterops *kqueue_fo_find(int filt); static struct filterops *kqueue_fo_find(int filt);
static void kqueue_fo_release(int filt); static void kqueue_fo_release(int filt);
struct fileops kqueueops = { static fo_rdwr_t kqueue_read;
static fo_rdwr_t kqueue_write;
static fo_truncate_t kqueue_truncate;
static fo_ioctl_t kqueue_ioctl;
static fo_poll_t kqueue_poll;
static fo_kqfilter_t kqueue_kqfilter;
static fo_stat_t kqueue_stat;
static fo_close_t kqueue_close;
static struct fileops kqueueops = {
.fo_read = kqueue_read, .fo_read = kqueue_read,
.fo_write = kqueue_write, .fo_write = kqueue_write,
.fo_truncate = kqueue_truncate, .fo_truncate = kqueue_truncate,
@ -294,7 +303,7 @@ filt_fileattach(struct knote *kn)
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_kqfilter(struct file *fp, struct knote *kn) kqueue_kqfilter(struct file *fp, struct knote *kn)
{ {
struct kqueue *kq = kn->kn_fp->f_data; struct kqueue *kq = kn->kn_fp->f_data;
@ -679,7 +688,34 @@ filt_usertouch(struct knote *kn, struct kevent *kev, u_long type)
int int
sys_kqueue(struct thread *td, struct kqueue_args *uap) sys_kqueue(struct thread *td, struct kqueue_args *uap)
{ {
return (kern_kqueue(td)); struct filedesc *fdp;
struct kqueue *kq;
struct file *fp;
int fd, error;
fdp = td->td_proc->p_fd;
error = falloc(td, &fp, &fd, 0);
if (error)
goto done2;
/* An extra reference on `fp' has been held for us by falloc(). */
kq = malloc(sizeof *kq, M_KQUEUE, M_WAITOK | M_ZERO);
mtx_init(&kq->kq_lock, "kqueue", NULL, MTX_DEF|MTX_DUPOK);
TAILQ_INIT(&kq->kq_head);
kq->kq_fdp = fdp;
knlist_init_mtx(&kq->kq_sel.si_note, &kq->kq_lock);
TASK_INIT(&kq->kq_task, 0, kqueue_task, kq);
FILEDESC_XLOCK(fdp);
TAILQ_INSERT_HEAD(&fdp->fd_kqlist, kq, kq_list);
FILEDESC_XUNLOCK(fdp);
finit(fp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops);
fdrop(fp, td);
td->td_retval[0] = fd;
done2:
return (error);
} }
#ifndef _SYS_SYSPROTO_H_ #ifndef _SYS_SYSPROTO_H_
@ -780,76 +816,20 @@ kevent_copyin(void *arg, struct kevent *kevp, int count)
return (error); return (error);
} }
int
kern_kqueue(struct thread *td)
{
struct file *fp;
int error;
error = kern_kqueue_locked(td, &fp);
fdrop(fp, td);
return (error);
}
int
kern_kqueue_locked(struct thread *td, struct file **fpp)
{
struct filedesc *fdp;
struct kqueue *kq;
struct file *fp;
int fd, error;
fdp = td->td_proc->p_fd;
error = falloc(td, &fp, &fd, 0);
if (error)
return (error);
/* An extra reference on `fp' has been held for us by falloc(). */
kq = malloc(sizeof *kq, M_KQUEUE, M_WAITOK | M_ZERO);
mtx_init(&kq->kq_lock, "kqueue", NULL, MTX_DEF|MTX_DUPOK);
TAILQ_INIT(&kq->kq_head);
kq->kq_fdp = fdp;
knlist_init_mtx(&kq->kq_sel.si_note, &kq->kq_lock);
TASK_INIT(&kq->kq_task, 0, kqueue_task, kq);
FILEDESC_XLOCK(fdp);
TAILQ_INSERT_HEAD(&fdp->fd_kqlist, kq, kq_list);
FILEDESC_XUNLOCK(fdp);
finit(fp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops);
td->td_retval[0] = fd;
*fpp = fp;
return (0);
}
int int
kern_kevent(struct thread *td, int fd, int nchanges, int nevents, kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout) struct kevent_copyops *k_ops, const struct timespec *timeout)
{
struct file *fp;
cap_rights_t rights;
int error;
if ((error = fget(td, fd, cap_rights_init(&rights, CAP_POST_EVENT), &fp)) != 0)
return (error);
error = kern_kevent_locked(td, fp, nchanges, nevents, k_ops, timeout);
fdrop(fp, td);
return (error);
}
int
kern_kevent_locked(struct thread *td, struct file *fp, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout)
{ {
struct kevent keva[KQ_NEVENTS]; struct kevent keva[KQ_NEVENTS];
struct kevent *kevp, *changes; struct kevent *kevp, *changes;
struct kqueue *kq; struct kqueue *kq;
struct file *fp;
cap_rights_t rights;
int i, n, nerrors, error; int i, n, nerrors, error;
error = fget(td, fd, cap_rights_init(&rights, CAP_POST_EVENT), &fp);
if (error != 0)
return (error);
if ((error = kqueue_acquire(fp, &kq)) != 0) if ((error = kqueue_acquire(fp, &kq)) != 0)
goto done_norel; goto done_norel;
@ -892,6 +872,7 @@ kern_kevent_locked(struct thread *td, struct file *fp, int nchanges, int nevents
done: done:
kqueue_release(kq, 0); kqueue_release(kq, 0);
done_norel: done_norel:
fdrop(fp, td);
return (error); return (error);
} }
@ -1545,7 +1526,7 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops,
* This could be expanded to call kqueue_scan, if desired. * This could be expanded to call kqueue_scan, if desired.
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_read(struct file *fp, struct uio *uio, struct ucred *active_cred, kqueue_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td) int flags, struct thread *td)
{ {
@ -1553,7 +1534,7 @@ kqueue_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_write(struct file *fp, struct uio *uio, struct ucred *active_cred, kqueue_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td) int flags, struct thread *td)
{ {
@ -1561,7 +1542,7 @@ kqueue_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_truncate(struct file *fp, off_t length, struct ucred *active_cred, kqueue_truncate(struct file *fp, off_t length, struct ucred *active_cred,
struct thread *td) struct thread *td)
{ {
@ -1570,7 +1551,7 @@ kqueue_truncate(struct file *fp, off_t length, struct ucred *active_cred,
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_ioctl(struct file *fp, u_long cmd, void *data, kqueue_ioctl(struct file *fp, u_long cmd, void *data,
struct ucred *active_cred, struct thread *td) struct ucred *active_cred, struct thread *td)
{ {
@ -1618,7 +1599,7 @@ kqueue_ioctl(struct file *fp, u_long cmd, void *data,
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_poll(struct file *fp, int events, struct ucred *active_cred, kqueue_poll(struct file *fp, int events, struct ucred *active_cred,
struct thread *td) struct thread *td)
{ {
@ -1645,7 +1626,7 @@ kqueue_poll(struct file *fp, int events, struct ucred *active_cred,
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_stat(struct file *fp, struct stat *st, struct ucred *active_cred, kqueue_stat(struct file *fp, struct stat *st, struct ucred *active_cred,
struct thread *td) struct thread *td)
{ {
@ -1663,7 +1644,7 @@ kqueue_stat(struct file *fp, struct stat *st, struct ucred *active_cred,
} }
/*ARGSUSED*/ /*ARGSUSED*/
int static int
kqueue_close(struct file *fp, struct thread *td) kqueue_close(struct file *fp, struct thread *td)
{ {
struct kqueue *kq = fp->f_data; struct kqueue *kq = fp->f_data;

View File

@ -9,7 +9,7 @@ CFLAGS+=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32
KMOD= linux KMOD= linux
SRCS= linux_fork.c linux${SFX}_dummy.c linux_emul.c linux_file.c \ SRCS= linux_fork.c linux${SFX}_dummy.c linux_emul.c linux_file.c \
linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c linux_epoll.c \ linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
linux${SFX}_machdep.c linux_mib.c linux_misc.c linux_signal.c \ linux${SFX}_machdep.c linux_mib.c linux_misc.c linux_signal.c \
linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \ linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \
linux${SFX}_sysvec.c linux_uid16.c linux_util.c linux_time.c \ linux${SFX}_sysvec.c linux_uid16.c linux_util.c linux_time.c \

View File

@ -236,9 +236,6 @@ struct proc;
struct knlist; struct knlist;
struct mtx; struct mtx;
struct rwlock; struct rwlock;
struct uio;
struct stat;
struct ucred;
extern void knote(struct knlist *list, long hint, int lockflags); extern void knote(struct knlist *list, long hint, int lockflags);
extern void knote_fork(struct knlist *list, int pid); extern void knote_fork(struct knlist *list, int pid);
@ -264,21 +261,6 @@ extern int kqfd_register(int fd, struct kevent *kev, struct thread *p,
extern int kqueue_add_filteropts(int filt, struct filterops *filtops); extern int kqueue_add_filteropts(int filt, struct filterops *filtops);
extern int kqueue_del_filteropts(int filt); extern int kqueue_del_filteropts(int filt);
int kqueue_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td);
int kqueue_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td);
int kqueue_truncate(struct file *fp, off_t length, struct ucred *active_cred,
struct thread *td);
int kqueue_ioctl(struct file *fp, u_long cmd, void *data,
struct ucred *active_cred, struct thread *td);
int kqueue_poll(struct file *fp, int events, struct ucred *active_cred,
struct thread *td);
int kqueue_kqfilter(struct file *fp, struct knote *kn);
int kqueue_stat(struct file *fp, struct stat *st, struct ucred *active_cred,
struct thread *td);
int kqueue_close(struct file *fp, struct thread *td);
#else /* !_KERNEL */ #else /* !_KERNEL */
#include <sys/cdefs.h> #include <sys/cdefs.h>

View File

@ -169,8 +169,6 @@ struct file {
union { union {
struct cdev_privdata *fvn_cdevpriv; struct cdev_privdata *fvn_cdevpriv;
/* (d) Private data for the cdev. */ /* (d) Private data for the cdev. */
void *fvn_epollpriv;
/* (d) Private data for the epoll. */
struct fadvise_info *fvn_advice; struct fadvise_info *fvn_advice;
} f_vnun; } f_vnun;
/* /*

View File

@ -121,13 +121,8 @@ int kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data);
int kern_jail(struct thread *td, struct jail *j); int kern_jail(struct thread *td, struct jail *j);
int kern_jail_get(struct thread *td, struct uio *options, int flags); int kern_jail_get(struct thread *td, struct uio *options, int flags);
int kern_jail_set(struct thread *td, struct uio *options, int flags); int kern_jail_set(struct thread *td, struct uio *options, int flags);
int kern_kqueue(struct thread *td);
int kern_kqueue_locked(struct thread *td, struct file **fpp);
int kern_kevent(struct thread *td, int fd, int nchanges, int nevents, int kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout); struct kevent_copyops *k_ops, const struct timespec *timeout);
int kern_kevent_locked(struct thread *td, struct file *fp, int nchanges,
int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout);
int kern_kldload(struct thread *td, const char *file, int *fileid); int kern_kldload(struct thread *td, const char *file, int *fileid);
int kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat); int kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat);
int kern_kldunload(struct thread *td, int fileid, int flags); int kern_kldunload(struct thread *td, int fileid, int flags);
@ -253,8 +248,6 @@ int kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
struct timeval *tptr, enum uio_seg tptrseg); struct timeval *tptr, enum uio_seg tptrseg);
int kern_utimesat(struct thread *td, int fd, char *path, int kern_utimesat(struct thread *td, int fd, char *path,
enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg); enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
int kern_utimensat(struct thread *td, int fd, char *path,
enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg);
int kern_wait(struct thread *td, pid_t pid, int *status, int options, int kern_wait(struct thread *td, pid_t pid, int *status, int options,
struct rusage *rup); struct rusage *rup);
int kern_wait6(struct thread *td, enum idtype idtype, id_t id, int *status, int kern_wait6(struct thread *td, enum idtype idtype, id_t id, int *status,