linux_event.c revision 293549
1/*- 2 * Copyright (c) 2007 Roman Divacky 3 * Copyright (c) 2014 Dmitry Chagin 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_event.c 293549 2016-01-09 16:48:50Z dchagin $"); 30 31#include "opt_compat.h" 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/imgact.h> 36#include <sys/kernel.h> 37#include <sys/limits.h> 38#include <sys/lock.h> 39#include <sys/mutex.h> 40#include <sys/capability.h> 41#include <sys/types.h> 42#include <sys/file.h> 43#include <sys/filedesc.h> 44#include <sys/errno.h> 45#include <sys/event.h> 46#include <sys/poll.h> 47#include <sys/proc.h> 48#include <sys/selinfo.h> 49#include <sys/sx.h> 50#include <sys/syscallsubr.h> 51#include <sys/timespec.h> 52 53#ifdef COMPAT_LINUX32 54#include <machine/../linux32/linux.h> 55#include <machine/../linux32/linux32_proto.h> 56#else 57#include <machine/../linux/linux.h> 58#include <machine/../linux/linux_proto.h> 59#endif 60 61#include <compat/linux/linux_emul.h> 62#include <compat/linux/linux_event.h> 63#include <compat/linux/linux_file.h> 64#include <compat/linux/linux_util.h> 65 66/* 67 * epoll defines 'struct epoll_event' with the field 'data' as 64 bits 68 * on all architectures. But on 32 bit architectures BSD 'struct kevent' only 69 * has 32 bit opaque pointer as 'udata' field. So we can't pass epoll supplied 70 * data verbatuim. Therefore we allocate 64-bit memory block to pass 71 * user supplied data for every file descriptor. 72 */ 73 74typedef uint64_t epoll_udata_t; 75 76struct epoll_emuldata { 77 uint32_t fdc; /* epoll udata max index */ 78 epoll_udata_t udata[1]; /* epoll user data vector */ 79}; 80 81#define EPOLL_DEF_SZ 16 82#define EPOLL_SIZE(fdn) \ 83 (sizeof(struct epoll_emuldata)+(fdn) * sizeof(epoll_udata_t)) 84 85struct epoll_event { 86 uint32_t events; 87 epoll_udata_t data; 88} 89#if defined(__amd64__) 90__attribute__((packed)) 91#endif 92; 93 94#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) 95 96static void epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata); 97static int epoll_to_kevent(struct thread *td, struct file *epfp, 98 int fd, struct epoll_event *l_event, int *kev_flags, 99 struct kevent *kevent, int *nkevents); 100static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event); 101static int epoll_kev_copyout(void *arg, struct kevent *kevp, int count); 102static int epoll_kev_copyin(void *arg, struct kevent *kevp, int count); 103static int epoll_delete_event(struct thread *td, struct file *epfp, 104 int fd, int filter); 105static int epoll_delete_all_events(struct thread *td, struct file *epfp, 106 int fd); 107 108struct epoll_copyin_args { 109 struct kevent *changelist; 110}; 111 112struct epoll_copyout_args { 113 struct epoll_event *leventlist; 114 struct proc *p; 115 uint32_t count; 116 int error; 117}; 118 119/* eventfd */ 120typedef uint64_t eventfd_t; 121 122static fo_rdwr_t eventfd_read; 123static fo_rdwr_t eventfd_write; 124static fo_truncate_t eventfd_truncate; 125static fo_ioctl_t eventfd_ioctl; 126static fo_poll_t eventfd_poll; 127static fo_kqfilter_t eventfd_kqfilter; 128static fo_stat_t eventfd_stat; 129static fo_close_t eventfd_close; 130 131static struct fileops eventfdops = { 132 .fo_read = eventfd_read, 133 .fo_write = eventfd_write, 134 .fo_truncate = eventfd_truncate, 135 .fo_ioctl = eventfd_ioctl, 136 .fo_poll = eventfd_poll, 137 .fo_kqfilter = eventfd_kqfilter, 138 .fo_stat = eventfd_stat, 139 .fo_close = eventfd_close, 140 .fo_chmod = invfo_chmod, 141 .fo_chown = invfo_chown, 142 .fo_sendfile = invfo_sendfile, 143 .fo_flags = DFLAG_PASSABLE 144}; 145 146static void filt_eventfddetach(struct knote *kn); 147static int filt_eventfdread(struct knote *kn, long hint); 148static int filt_eventfdwrite(struct knote *kn, long hint); 149 150static struct filterops eventfd_rfiltops = { 151 .f_isfd = 1, 152 .f_detach = filt_eventfddetach, 153 .f_event = filt_eventfdread 154}; 155static struct filterops eventfd_wfiltops = { 156 .f_isfd = 1, 157 .f_detach = filt_eventfddetach, 158 .f_event = filt_eventfdwrite 159}; 160 161struct eventfd { 162 eventfd_t efd_count; 163 uint32_t efd_flags; 164 struct selinfo efd_sel; 165 struct mtx efd_lock; 166}; 167 168static int eventfd_create(struct thread *td, uint32_t initval, int flags); 169 170 171static void 172epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata) 173{ 174 struct linux_pemuldata *pem; 175 struct epoll_emuldata *emd; 176 struct proc *p; 177 178 p = td->td_proc; 179 180 pem = pem_find(p); 181 KASSERT(pem != NULL, ("epoll proc emuldata not found.\n")); 182 183 LINUX_PEM_XLOCK(pem); 184 if (pem->epoll == NULL) { 185 emd = malloc(EPOLL_SIZE(fd), M_EPOLL, M_WAITOK); 186 emd->fdc = fd; 187 pem->epoll = emd; 188 } else { 189 emd = pem->epoll; 190 if (fd > emd->fdc) { 191 emd = realloc(emd, EPOLL_SIZE(fd), M_EPOLL, M_WAITOK); 192 emd->fdc = fd; 193 pem->epoll = emd; 194 } 195 } 196 emd->udata[fd] = udata; 197 LINUX_PEM_XUNLOCK(pem); 198} 199 200static int 201epoll_create_common(struct thread *td, int flags) 202{ 203 int error; 204 205 error = kern_kqueue(td, flags); 206 if (error) 207 return (error); 208 209 epoll_fd_install(td, EPOLL_DEF_SZ, 0); 210 211 return (0); 212} 213 214int 215linux_epoll_create(struct thread *td, struct linux_epoll_create_args *args) 216{ 217 218 /* 219 * args->size is unused. Linux just tests it 220 * and then forgets it as well. 221 */ 222 if (args->size <= 0) 223 return (EINVAL); 224 225 return (epoll_create_common(td, 0)); 226} 227 228int 229linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args) 230{ 231 int flags; 232 233 if ((args->flags & ~(LINUX_O_CLOEXEC)) != 0) 234 return (EINVAL); 235 236 flags = 0; 237 if ((args->flags & LINUX_O_CLOEXEC) != 0) 238 flags |= O_CLOEXEC; 239 240 return (epoll_create_common(td, flags)); 241} 242 243/* Structure converting function from epoll to kevent. */ 244static int 245epoll_to_kevent(struct thread *td, struct file *epfp, 246 int fd, struct epoll_event *l_event, int *kev_flags, 247 struct kevent *kevent, int *nkevents) 248{ 249 uint32_t levents = l_event->events; 250 struct linux_pemuldata *pem; 251 struct proc *p; 252 253 /* flags related to how event is registered */ 254 if ((levents & LINUX_EPOLLONESHOT) != 0) 255 *kev_flags |= EV_ONESHOT; 256 if ((levents & LINUX_EPOLLET) != 0) 257 *kev_flags |= EV_CLEAR; 258 259 /* flags related to what event is registered */ 260 if ((levents & LINUX_EPOLL_EVRD) != 0) { 261 EV_SET(kevent++, fd, EVFILT_READ, *kev_flags, 0, 0, 0); 262 ++(*nkevents); 263 } 264 if ((levents & LINUX_EPOLL_EVWR) != 0) { 265 EV_SET(kevent++, fd, EVFILT_WRITE, *kev_flags, 0, 0, 0); 266 ++(*nkevents); 267 } 268 269 if ((levents & ~(LINUX_EPOLL_EVSUP)) != 0) { 270 p = td->td_proc; 271 272 pem = pem_find(p); 273 KASSERT(pem != NULL, ("epoll proc emuldata not found.\n")); 274 KASSERT(pem->epoll != NULL, ("epoll proc epolldata not found.\n")); 275 276 LINUX_PEM_XLOCK(pem); 277 if ((pem->flags & LINUX_XUNSUP_EPOLL) == 0) { 278 pem->flags |= LINUX_XUNSUP_EPOLL; 279 LINUX_PEM_XUNLOCK(pem); 280 linux_msg(td, "epoll_ctl unsupported flags: 0x%x\n", 281 levents); 282 } else 283 LINUX_PEM_XUNLOCK(pem); 284 return (EINVAL); 285 } 286 287 return (0); 288} 289 290/* 291 * Structure converting function from kevent to epoll. In a case 292 * this is called on error in registration we store the error in 293 * event->data and pick it up later in linux_epoll_ctl(). 294 */ 295static void 296kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event) 297{ 298 299 if ((kevent->flags & EV_ERROR) != 0) 300 return; 301 302 switch (kevent->filter) { 303 case EVFILT_READ: 304 l_event->events = LINUX_EPOLLIN|LINUX_EPOLLRDNORM|LINUX_EPOLLPRI; 305 break; 306 case EVFILT_WRITE: 307 l_event->events = LINUX_EPOLLOUT|LINUX_EPOLLWRNORM; 308 break; 309 } 310} 311 312/* 313 * Copyout callback used by kevent. This converts kevent 314 * events to epoll events and copies them back to the 315 * userspace. This is also called on error on registering 316 * of the filter. 317 */ 318static int 319epoll_kev_copyout(void *arg, struct kevent *kevp, int count) 320{ 321 struct epoll_copyout_args *args; 322 struct linux_pemuldata *pem; 323 struct epoll_emuldata *emd; 324 struct epoll_event *eep; 325 int error, fd, i; 326 327 args = (struct epoll_copyout_args*) arg; 328 eep = malloc(sizeof(*eep) * count, M_EPOLL, M_WAITOK | M_ZERO); 329 330 pem = pem_find(args->p); 331 KASSERT(pem != NULL, ("epoll proc emuldata not found.\n")); 332 LINUX_PEM_SLOCK(pem); 333 emd = pem->epoll; 334 KASSERT(emd != NULL, ("epoll proc epolldata not found.\n")); 335 336 for (i = 0; i < count; i++) { 337 kevent_to_epoll(&kevp[i], &eep[i]); 338 339 fd = kevp[i].ident; 340 KASSERT(fd <= emd->fdc, ("epoll user data vector" 341 " is too small.\n")); 342 eep[i].data = emd->udata[fd]; 343 } 344 LINUX_PEM_SUNLOCK(pem); 345 346 error = copyout(eep, args->leventlist, count * sizeof(*eep)); 347 if (error == 0) { 348 args->leventlist += count; 349 args->count += count; 350 } else if (args->error == 0) 351 args->error = error; 352 353 free(eep, M_EPOLL); 354 return (error); 355} 356 357/* 358 * Copyin callback used by kevent. This copies already 359 * converted filters from kernel memory to the kevent 360 * internal kernel memory. Hence the memcpy instead of 361 * copyin. 362 */ 363static int 364epoll_kev_copyin(void *arg, struct kevent *kevp, int count) 365{ 366 struct epoll_copyin_args *args; 367 368 args = (struct epoll_copyin_args*) arg; 369 370 memcpy(kevp, args->changelist, count * sizeof(*kevp)); 371 args->changelist += count; 372 373 return (0); 374} 375 376/* 377 * Load epoll filter, convert it to kevent filter 378 * and load it into kevent subsystem. 379 */ 380int 381linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args) 382{ 383 struct file *epfp, *fp; 384 struct epoll_copyin_args ciargs; 385 struct kevent kev[2]; 386 struct kevent_copyops k_ops = { &ciargs, 387 NULL, 388 epoll_kev_copyin}; 389 struct epoll_event le; 390 cap_rights_t rights; 391 int kev_flags; 392 int nchanges = 0; 393 int error; 394 395 if (args->op != LINUX_EPOLL_CTL_DEL) { 396 error = copyin(args->event, &le, sizeof(le)); 397 if (error != 0) 398 return (error); 399 } 400 401 error = fget(td, args->epfd, 402 cap_rights_init(&rights, CAP_KQUEUE_CHANGE), &epfp); 403 if (error != 0) 404 return (error); 405 if (epfp->f_type != DTYPE_KQUEUE) 406 goto leave1; 407 408 /* Protect user data vector from incorrectly supplied fd. */ 409 error = fget(td, args->fd, cap_rights_init(&rights, CAP_POLL_EVENT), &fp); 410 if (error != 0) 411 goto leave1; 412 413 /* Linux disallows spying on himself */ 414 if (epfp == fp) { 415 error = EINVAL; 416 goto leave0; 417 } 418 419 ciargs.changelist = kev; 420 421 switch (args->op) { 422 case LINUX_EPOLL_CTL_MOD: 423 /* 424 * We don't memorize which events were set for this FD 425 * on this level, so just delete all we could have set: 426 * EVFILT_READ and EVFILT_WRITE, ignoring any errors 427 */ 428 error = epoll_delete_all_events(td, epfp, args->fd); 429 if (error) 430 goto leave0; 431 /* FALLTHROUGH */ 432 433 case LINUX_EPOLL_CTL_ADD: 434 kev_flags = EV_ADD | EV_ENABLE; 435 break; 436 437 case LINUX_EPOLL_CTL_DEL: 438 /* CTL_DEL means unregister this fd with this epoll */ 439 error = epoll_delete_all_events(td, epfp, args->fd); 440 goto leave0; 441 442 default: 443 error = EINVAL; 444 goto leave0; 445 } 446 447 error = epoll_to_kevent(td, epfp, args->fd, &le, &kev_flags, 448 kev, &nchanges); 449 if (error) 450 goto leave0; 451 452 epoll_fd_install(td, args->fd, le.data); 453 454 error = kern_kevent_fp(td, epfp, nchanges, 0, &k_ops, NULL); 455 456leave0: 457 fdrop(fp, td); 458 459leave1: 460 fdrop(epfp, td); 461 return (error); 462} 463 464/* 465 * Wait for a filter to be triggered on the epoll file descriptor. 466 */ 467int 468linux_epoll_wait(struct thread *td, struct linux_epoll_wait_args *args) 469{ 470 struct file *epfp; 471 struct timespec ts, *tsp; 472 cap_rights_t rights; 473 struct epoll_copyout_args coargs; 474 struct kevent_copyops k_ops = { &coargs, 475 epoll_kev_copyout, 476 NULL}; 477 int error; 478 479 if (args->maxevents <= 0 || args->maxevents > LINUX_MAX_EVENTS) 480 return (EINVAL); 481 482 error = fget(td, args->epfd, 483 cap_rights_init(&rights, CAP_KQUEUE_EVENT), &epfp); 484 if (error != 0) 485 return (error); 486 487 coargs.leventlist = args->events; 488 coargs.p = td->td_proc; 489 coargs.count = 0; 490 coargs.error = 0; 491 492 if (args->timeout != -1) { 493 if (args->timeout < 0) { 494 error = EINVAL; 495 goto leave; 496 } 497 /* Convert from milliseconds to timespec. */ 498 ts.tv_sec = args->timeout / 1000; 499 ts.tv_nsec = (args->timeout % 1000) * 1000000; 500 tsp = &ts; 501 } else { 502 tsp = NULL; 503 } 504 505 error = kern_kevent_fp(td, epfp, 0, args->maxevents, &k_ops, tsp); 506 if (error == 0 && coargs.error != 0) 507 error = coargs.error; 508 509 /* 510 * kern_kevent might return ENOMEM which is not expected from epoll_wait. 511 * Maybe we should translate that but I don't think it matters at all. 512 */ 513 if (error == 0) 514 td->td_retval[0] = coargs.count; 515leave: 516 fdrop(epfp, td); 517 return (error); 518} 519 520static int 521epoll_delete_event(struct thread *td, struct file *epfp, int fd, int filter) 522{ 523 struct epoll_copyin_args ciargs; 524 struct kevent kev; 525 struct kevent_copyops k_ops = { &ciargs, 526 NULL, 527 epoll_kev_copyin}; 528 int error; 529 530 ciargs.changelist = &kev; 531 EV_SET(&kev, fd, filter, EV_DELETE | EV_DISABLE, 0, 0, 0); 532 533 error = kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL); 534 535 /* 536 * here we ignore ENONT, because we don't keep track of events here 537 */ 538 if (error == ENOENT) 539 error = 0; 540 return (error); 541} 542 543static int 544epoll_delete_all_events(struct thread *td, struct file *epfp, int fd) 545{ 546 int error1, error2; 547 548 error1 = epoll_delete_event(td, epfp, fd, EVFILT_READ); 549 error2 = epoll_delete_event(td, epfp, fd, EVFILT_WRITE); 550 551 /* report any errors we got */ 552 return (error1 == 0 ? error2 : error1); 553} 554 555static int 556eventfd_create(struct thread *td, uint32_t initval, int flags) 557{ 558 struct filedesc *fdp; 559 struct eventfd *efd; 560 struct file *fp; 561 int fflags, fd, error; 562 563 fflags = 0; 564 if ((flags & LINUX_O_CLOEXEC) != 0) 565 fflags |= O_CLOEXEC; 566 567 fdp = td->td_proc->p_fd; 568 error = falloc(td, &fp, &fd, fflags); 569 if (error) 570 return (error); 571 572 efd = malloc(sizeof(*efd), M_EPOLL, M_WAITOK | M_ZERO); 573 efd->efd_flags = flags; 574 efd->efd_count = initval; 575 mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF); 576 577 knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock); 578 579 fflags = FREAD | FWRITE; 580 if ((flags & LINUX_O_NONBLOCK) != 0) 581 fflags |= FNONBLOCK; 582 583 finit(fp, fflags, DTYPE_LINUXEFD, efd, &eventfdops); 584 fdrop(fp, td); 585 586 td->td_retval[0] = fd; 587 return (error); 588} 589 590int 591linux_eventfd(struct thread *td, struct linux_eventfd_args *args) 592{ 593 594 return (eventfd_create(td, args->initval, 0)); 595} 596 597int 598linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args) 599{ 600 601 if ((args->flags & ~(LINUX_O_CLOEXEC|LINUX_O_NONBLOCK|LINUX_EFD_SEMAPHORE)) != 0) 602 return (EINVAL); 603 604 return (eventfd_create(td, args->initval, args->flags)); 605} 606 607static int 608eventfd_close(struct file *fp, struct thread *td) 609{ 610 struct eventfd *efd; 611 612 efd = fp->f_data; 613 if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) 614 return (EBADF); 615 616 seldrain(&efd->efd_sel); 617 knlist_destroy(&efd->efd_sel.si_note); 618 619 fp->f_ops = &badfileops; 620 mtx_destroy(&efd->efd_lock); 621 free(efd, M_EPOLL); 622 623 return (0); 624} 625 626static int 627eventfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred, 628 int flags, struct thread *td) 629{ 630 struct eventfd *efd; 631 eventfd_t count; 632 int error; 633 634 efd = fp->f_data; 635 if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) 636 return (EBADF); 637 638 if (uio->uio_resid < sizeof(eventfd_t)) 639 return (EINVAL); 640 641 error = 0; 642 mtx_lock(&efd->efd_lock); 643retry: 644 if (efd->efd_count == 0) { 645 if ((efd->efd_flags & LINUX_O_NONBLOCK) != 0) { 646 mtx_unlock(&efd->efd_lock); 647 return (EAGAIN); 648 } 649 error = mtx_sleep(&efd->efd_count, &efd->efd_lock, PCATCH, "lefdrd", 0); 650 if (error == 0) 651 goto retry; 652 } 653 if (error == 0) { 654 if ((efd->efd_flags & LINUX_EFD_SEMAPHORE) != 0) { 655 count = 1; 656 --efd->efd_count; 657 } else { 658 count = efd->efd_count; 659 efd->efd_count = 0; 660 } 661 KNOTE_LOCKED(&efd->efd_sel.si_note, 0); 662 selwakeup(&efd->efd_sel); 663 wakeup(&efd->efd_count); 664 mtx_unlock(&efd->efd_lock); 665 error = uiomove(&count, sizeof(eventfd_t), uio); 666 } else 667 mtx_unlock(&efd->efd_lock); 668 669 return (error); 670} 671 672static int 673eventfd_write(struct file *fp, struct uio *uio, struct ucred *active_cred, 674 int flags, struct thread *td) 675{ 676 struct eventfd *efd; 677 eventfd_t count; 678 int error; 679 680 efd = fp->f_data; 681 if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) 682 return (EBADF); 683 684 if (uio->uio_resid < sizeof(eventfd_t)) 685 return (EINVAL); 686 687 error = uiomove(&count, sizeof(eventfd_t), uio); 688 if (error) 689 return (error); 690 if (count == UINT64_MAX) 691 return (EINVAL); 692 693 mtx_lock(&efd->efd_lock); 694retry: 695 if (UINT64_MAX - efd->efd_count <= count) { 696 if ((efd->efd_flags & LINUX_O_NONBLOCK) != 0) { 697 mtx_unlock(&efd->efd_lock); 698 return (EAGAIN); 699 } 700 error = mtx_sleep(&efd->efd_count, &efd->efd_lock, 701 PCATCH, "lefdwr", 0); 702 if (error == 0) 703 goto retry; 704 } 705 if (error == 0) { 706 efd->efd_count += count; 707 KNOTE_LOCKED(&efd->efd_sel.si_note, 0); 708 selwakeup(&efd->efd_sel); 709 wakeup(&efd->efd_count); 710 } 711 mtx_unlock(&efd->efd_lock); 712 713 return (error); 714} 715 716static int 717eventfd_poll(struct file *fp, int events, struct ucred *active_cred, 718 struct thread *td) 719{ 720 struct eventfd *efd; 721 int revents = 0; 722 723 efd = fp->f_data; 724 if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) 725 return (POLLERR); 726 727 mtx_lock(&efd->efd_lock); 728 if ((events & (POLLIN|POLLRDNORM)) && efd->efd_count > 0) 729 revents |= events & (POLLIN|POLLRDNORM); 730 if ((events & (POLLOUT|POLLWRNORM)) && UINT64_MAX - 1 > efd->efd_count) 731 revents |= events & (POLLOUT|POLLWRNORM); 732 if (revents == 0) 733 selrecord(td, &efd->efd_sel); 734 mtx_unlock(&efd->efd_lock); 735 736 return (revents); 737} 738 739/*ARGSUSED*/ 740static int 741eventfd_kqfilter(struct file *fp, struct knote *kn) 742{ 743 struct eventfd *efd; 744 745 efd = fp->f_data; 746 if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) 747 return (EINVAL); 748 749 mtx_lock(&efd->efd_lock); 750 switch (kn->kn_filter) { 751 case EVFILT_READ: 752 kn->kn_fop = &eventfd_rfiltops; 753 break; 754 case EVFILT_WRITE: 755 kn->kn_fop = &eventfd_wfiltops; 756 break; 757 default: 758 mtx_unlock(&efd->efd_lock); 759 return (EINVAL); 760 } 761 762 kn->kn_hook = efd; 763 knlist_add(&efd->efd_sel.si_note, kn, 1); 764 mtx_unlock(&efd->efd_lock); 765 766 return (0); 767} 768 769static void 770filt_eventfddetach(struct knote *kn) 771{ 772 struct eventfd *efd = kn->kn_hook; 773 774 mtx_lock(&efd->efd_lock); 775 knlist_remove(&efd->efd_sel.si_note, kn, 1); 776 mtx_unlock(&efd->efd_lock); 777} 778 779/*ARGSUSED*/ 780static int 781filt_eventfdread(struct knote *kn, long hint) 782{ 783 struct eventfd *efd = kn->kn_hook; 784 int ret; 785 786 mtx_assert(&efd->efd_lock, MA_OWNED); 787 ret = (efd->efd_count > 0); 788 789 return (ret); 790} 791 792/*ARGSUSED*/ 793static int 794filt_eventfdwrite(struct knote *kn, long hint) 795{ 796 struct eventfd *efd = kn->kn_hook; 797 int ret; 798 799 mtx_assert(&efd->efd_lock, MA_OWNED); 800 ret = (UINT64_MAX - 1 > efd->efd_count); 801 802 return (ret); 803} 804 805/*ARGSUSED*/ 806static int 807eventfd_truncate(struct file *fp, off_t length, struct ucred *active_cred, 808 struct thread *td) 809{ 810 811 return (ENXIO); 812} 813 814/*ARGSUSED*/ 815static int 816eventfd_ioctl(struct file *fp, u_long cmd, void *data, 817 struct ucred *active_cred, struct thread *td) 818{ 819 820 return (ENXIO); 821} 822 823/*ARGSUSED*/ 824static int 825eventfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred, 826 struct thread *td) 827{ 828 829 return (ENXIO); 830} 831