|
@@ -94,6 +94,11 @@
|
|
/* Epoll private bits inside the event mask */
|
|
/* Epoll private bits inside the event mask */
|
|
#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE)
|
|
#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE)
|
|
|
|
|
|
|
|
+#define EPOLLINOUT_BITS (POLLIN | POLLOUT)
|
|
|
|
+
|
|
|
|
+#define EPOLLEXCLUSIVE_OK_BITS (EPOLLINOUT_BITS | POLLERR | POLLHUP | \
|
|
|
|
+ EPOLLWAKEUP | EPOLLET | EPOLLEXCLUSIVE)
|
|
|
|
+
|
|
/* Maximum number of nesting allowed inside epoll sets */
|
|
/* Maximum number of nesting allowed inside epoll sets */
|
|
#define EP_MAX_NESTS 4
|
|
#define EP_MAX_NESTS 4
|
|
|
|
|
|
@@ -1068,7 +1073,22 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
|
|
* wait list.
|
|
* wait list.
|
|
*/
|
|
*/
|
|
if (waitqueue_active(&ep->wq)) {
|
|
if (waitqueue_active(&ep->wq)) {
|
|
- ewake = 1;
|
|
|
|
|
|
+ if ((epi->event.events & EPOLLEXCLUSIVE) &&
|
|
|
|
+ !((unsigned long)key & POLLFREE)) {
|
|
|
|
+ switch ((unsigned long)key & EPOLLINOUT_BITS) {
|
|
|
|
+ case POLLIN:
|
|
|
|
+ if (epi->event.events & POLLIN)
|
|
|
|
+ ewake = 1;
|
|
|
|
+ break;
|
|
|
|
+ case POLLOUT:
|
|
|
|
+ if (epi->event.events & POLLOUT)
|
|
|
|
+ ewake = 1;
|
|
|
|
+ break;
|
|
|
|
+ case 0:
|
|
|
|
+ ewake = 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
wake_up_locked(&ep->wq);
|
|
wake_up_locked(&ep->wq);
|
|
}
|
|
}
|
|
if (waitqueue_active(&ep->poll_wait))
|
|
if (waitqueue_active(&ep->poll_wait))
|
|
@@ -1875,9 +1895,13 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
|
* so EPOLLEXCLUSIVE is not allowed for a EPOLL_CTL_MOD operation.
|
|
* so EPOLLEXCLUSIVE is not allowed for a EPOLL_CTL_MOD operation.
|
|
* Also, we do not currently supported nested exclusive wakeups.
|
|
* Also, we do not currently supported nested exclusive wakeups.
|
|
*/
|
|
*/
|
|
- if ((epds.events & EPOLLEXCLUSIVE) && (op == EPOLL_CTL_MOD ||
|
|
|
|
- (op == EPOLL_CTL_ADD && is_file_epoll(tf.file))))
|
|
|
|
- goto error_tgt_fput;
|
|
|
|
|
|
+ if (epds.events & EPOLLEXCLUSIVE) {
|
|
|
|
+ if (op == EPOLL_CTL_MOD)
|
|
|
|
+ goto error_tgt_fput;
|
|
|
|
+ if (op == EPOLL_CTL_ADD && (is_file_epoll(tf.file) ||
|
|
|
|
+ (epds.events & ~EPOLLEXCLUSIVE_OK_BITS)))
|
|
|
|
+ goto error_tgt_fput;
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* At this point it is safe to assume that the "private_data" contains
|
|
* At this point it is safe to assume that the "private_data" contains
|
|
@@ -1950,8 +1974,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
|
break;
|
|
break;
|
|
case EPOLL_CTL_MOD:
|
|
case EPOLL_CTL_MOD:
|
|
if (epi) {
|
|
if (epi) {
|
|
- epds.events |= POLLERR | POLLHUP;
|
|
|
|
- error = ep_modify(ep, epi, &epds);
|
|
|
|
|
|
+ if (!(epi->event.events & EPOLLEXCLUSIVE)) {
|
|
|
|
+ epds.events |= POLLERR | POLLHUP;
|
|
|
|
+ error = ep_modify(ep, epi, &epds);
|
|
|
|
+ }
|
|
} else
|
|
} else
|
|
error = -ENOENT;
|
|
error = -ENOENT;
|
|
break;
|
|
break;
|