Author: dchagin
Date: Tue Feb 28 19:55:16 2017
New Revision: 314404
URL: https://svnweb.freebsd.org/changeset/base/314404

Log:
  Linux epoll return EEXIST on case when op is EPOLL_CTL_ADD, and the supplied
  file descriptor fd is already registered with this epoll instance.
  
  MFC after:    1 month

Modified:
  head/sys/compat/linux/linux_event.c

Modified: head/sys/compat/linux/linux_event.c
==============================================================================
--- head/sys/compat/linux/linux_event.c Tue Feb 28 19:54:22 2017        
(r314403)
+++ head/sys/compat/linux/linux_event.c Tue Feb 28 19:55:16 2017        
(r314404)
@@ -481,15 +481,34 @@ linux_epoll_ctl(struct thread *td, struc
 
        ciargs.changelist = kev;
 
+       if (args->op != LINUX_EPOLL_CTL_DEL) {
+               kev_flags = EV_ADD | EV_ENABLE;
+               error = epoll_to_kevent(td, epfp, args->fd, &le,
+                   &kev_flags, kev, &nchanges);
+               if (error != 0)
+                       goto leave0;
+       }
+
        switch (args->op) {
        case LINUX_EPOLL_CTL_MOD:
                error = epoll_delete_all_events(td, epfp, args->fd);
                if (error != 0)
                        goto leave0;
-               /* FALLTHROUGH */
+               break;
 
        case LINUX_EPOLL_CTL_ADD:
-                       kev_flags = EV_ADD | EV_ENABLE;
+               /*
+                * kqueue_register() return ENOENT if event does not exists
+                * and the EV_ADD flag is not set.
+                */
+               kev[0].flags &= ~EV_ADD;
+               error = kqfd_register(args->epfd, &kev[0], td, 1);
+               if (error != ENOENT) {
+                       error = EEXIST;
+                       goto leave0;
+               }
+               error = 0;
+               kev[0].flags |= EV_ADD;
                break;
 
        case LINUX_EPOLL_CTL_DEL:
@@ -502,11 +521,6 @@ linux_epoll_ctl(struct thread *td, struc
                goto leave0;
        }
 
-       error = epoll_to_kevent(td, epfp, args->fd, &le, &kev_flags,
-           kev, &nchanges);
-       if (error != 0)
-               goto leave0;
-
        epoll_fd_install(td, args->fd, le.data);
 
        error = kern_kevent_fp(td, epfp, nchanges, 0, &k_ops, NULL);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to