Date: Fri, 2 Jun 2017 16:52:18 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r319501 - head/sys/compat/linuxkpi/common/src Message-ID: <201706021652.v52GqIS7028920@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201706021652.v52GqIS7028920>