epoll: support for disabling items, and a self-test app
Enhanced epoll_ctl to support EPOLL_CTL_DISABLE, which disables an epoll item. If epoll_ctl doesn't return -EBUSY in this case, it is then safe to delete the epoll item in a multi-threaded environment. Also added a new test_epoll self- test app to both demonstrate the need for this feature and test it. Signed-off-by: Paton J. Lewis <palewis@adobe.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Jason Baron <jbaron@redhat.com> Cc: Paul Holland <pholland@adobe.com> Cc: Davide Libenzi <davidel@xmailserver.org> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:

committed by
Linus Torvalds

parent
a0a0a7a94c
commit
03a7beb55b
@@ -346,7 +346,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p)
|
||||
/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
|
||||
static inline int ep_op_has_event(int op)
|
||||
{
|
||||
return op != EPOLL_CTL_DEL;
|
||||
return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD;
|
||||
}
|
||||
|
||||
/* Initialize the poll safe wake up structure */
|
||||
@@ -676,6 +676,34 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item
|
||||
* had no event flags set, indicating that another thread may be currently
|
||||
* handling that item's events (in the case that EPOLLONESHOT was being
|
||||
* used). Otherwise a zero result indicates that the item has been disabled
|
||||
* from receiving events. A disabled item may be re-enabled via
|
||||
* EPOLL_CTL_MOD. Must be called with "mtx" held.
|
||||
*/
|
||||
static int ep_disable(struct eventpoll *ep, struct epitem *epi)
|
||||
{
|
||||
int result = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
if (epi->event.events & ~EP_PRIVATE_BITS) {
|
||||
if (ep_is_linked(&epi->rdllink))
|
||||
list_del_init(&epi->rdllink);
|
||||
/* Ensure ep_poll_callback will not add epi back onto ready
|
||||
list: */
|
||||
epi->event.events &= EP_PRIVATE_BITS;
|
||||
}
|
||||
else
|
||||
result = -EBUSY;
|
||||
spin_unlock_irqrestore(&ep->lock, flags);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ep_free(struct eventpoll *ep)
|
||||
{
|
||||
struct rb_node *rbp;
|
||||
@@ -1020,8 +1048,6 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
|
||||
rb_insert_color(&epi->rbn, &ep->rbr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define PATH_ARR_SIZE 5
|
||||
/*
|
||||
* These are the number paths of length 1 to 5, that we are allowing to emanate
|
||||
@@ -1787,6 +1813,12 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
||||
} else
|
||||
error = -ENOENT;
|
||||
break;
|
||||
case EPOLL_CTL_DISABLE:
|
||||
if (epi)
|
||||
error = ep_disable(ep, epi);
|
||||
else
|
||||
error = -ENOENT;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&ep->mtx);
|
||||
|
||||
|
Reference in New Issue
Block a user