Author: hselasky
Date: Fri Jun  2 16:52:18 2017
New Revision: 319501
URL: https://svnweb.freebsd.org/changeset/base/319501

Log:
  Improve kqueue() support in the LinuxKPI. Some applications using the
  kqueue() does not set non-blocking I/O mode for event driven read of
  file descriptors. This means the LinuxKPI internal kqueue read and
  write event flags must be updated before the next read and/or write
  system call. Else the read and/or write system call may block. This
  can happen when there is no more data to read following a previous
  read event. Then the application also gets blocked from processing
  other events. This situation can also be solved by the applications
  setting and using non-blocking I/O mode.
  
  MFC after:            1 week
  Sponsored by:         Mellanox Technologies

Modified:
  head/sys/compat/linuxkpi/common/src/linux_compat.c

Modified: head/sys/compat/linuxkpi/common/src/linux_compat.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_compat.c  Fri Jun  2 16:30:40 
2017        (r319500)
+++ head/sys/compat/linuxkpi/common/src/linux_compat.c  Fri Jun  2 16:52:18 
2017        (r319501)
@@ -438,7 +438,7 @@ linux_kq_lock_unowned(void *arg)
 }
 
 static void
-linux_dev_kqfilter_poll(struct linux_file *);
+linux_dev_kqfilter_poll(struct linux_file *, int);
 
 struct linux_file *
 linux_file_alloc(void)
@@ -856,9 +856,11 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t 
                current->bsd_ioctl_len = 0;
        }
 
-       if (error == EWOULDBLOCK)
-               linux_dev_kqfilter_poll(filp);
-       else if (error == ERESTARTSYS)
+       if (error == EWOULDBLOCK) {
+               /* update kqfilter status, if any */
+               linux_dev_kqfilter_poll(filp,
+                   LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE);
+       } else if (error == ERESTARTSYS)
                error = ERESTART;
        return (error);
 }
@@ -893,14 +895,15 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int 
                        uio->uio_resid -= bytes;
                } else {
                        error = -bytes;
-                       if (error == EWOULDBLOCK)
-                               linux_dev_kqfilter_poll(filp);
-                       else if (error == ERESTARTSYS)
+                       if (error == ERESTARTSYS)
                                error = ERESTART;
                }
        } else
                error = ENXIO;
 
+       /* update kqfilter status, if any */
+       linux_dev_kqfilter_poll(filp, LINUX_KQ_FLAG_HAS_READ);
+
        return (error);
 }
 
@@ -934,14 +937,15 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int
                        uio->uio_resid -= bytes;
                } else {
                        error = -bytes;
-                       if (error == EWOULDBLOCK)
-                               linux_dev_kqfilter_poll(filp);
-                       else if (error == ERESTARTSYS)
+                       if (error == ERESTARTSYS)
                                error = ERESTART;
                }
        } else
                error = ENXIO;
 
+       /* update kqfilter status, if any */
+       linux_dev_kqfilter_poll(filp, LINUX_KQ_FLAG_HAS_WRITE);
+
        return (error);
 }
 
@@ -1032,21 +1036,20 @@ static struct filterops linux_dev_kqfiltops_write = {
 };
 
 static void
-linux_dev_kqfilter_poll(struct linux_file *filp)
+linux_dev_kqfilter_poll(struct linux_file *filp, int kqflags)
 {
        int temp;
 
-       spin_lock(&filp->f_kqlock);
-       temp = (filp->f_kqflags & (LINUX_KQ_FLAG_HAS_READ | 
LINUX_KQ_FLAG_HAS_WRITE));
-       filp->f_kqflags &= ~(LINUX_KQ_FLAG_NEED_READ | 
LINUX_KQ_FLAG_NEED_WRITE);
-       spin_unlock(&filp->f_kqlock);
-
-       if (temp != 0) {
+       if (filp->f_kqflags & kqflags) {
                /* get the latest polling state */
                temp = filp->f_op->poll(filp, NULL);
 
+               spin_lock(&filp->f_kqlock);
+               /* clear kqflags */
+               filp->f_kqflags &= ~(LINUX_KQ_FLAG_NEED_READ |
+                   LINUX_KQ_FLAG_NEED_WRITE);
+               /* update kqflags */
                if (temp & (POLLIN | POLLOUT)) {
-                       spin_lock(&filp->f_kqlock);
                        if (temp & POLLIN)
                                filp->f_kqflags |= LINUX_KQ_FLAG_NEED_READ;
                        if (temp & POLLOUT)
@@ -1054,8 +1057,8 @@ linux_dev_kqfilter_poll(struct linux_file *filp)
 
                        /* make sure the "knote" gets woken up */
                        KNOTE_LOCKED(&filp->f_selinfo.si_note, 0);
-                       spin_unlock(&filp->f_kqlock);
                }
+               spin_unlock(&filp->f_kqlock);
        }
 }
 
@@ -1099,7 +1102,10 @@ linux_dev_kqfilter(struct cdev *dev, struct knote *kn)
 
        if (error == 0) {
                linux_set_current(td);
-               linux_dev_kqfilter_poll(filp);
+
+               /* update kqfilter status, if any */
+               linux_dev_kqfilter_poll(filp,
+                   LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE);
        }
        return (error);
 }
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to