summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/eventpoll.c94
-rw-r--r--include/linux/eventpoll.h8
2 files changed, 51 insertions, 51 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index b839cc02eb0e..a569e98d4a99 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -224,11 +224,6 @@
#define EP_ITEM_COST (sizeof(struct epitem) + sizeof(struct eppoll_entry))
-struct epoll_filefd {
- struct file *file;
- int fd;
-} __packed;
-
/* Wait structure used by the poll hooks */
struct eppoll_entry {
/* List header used to link this structure to the "struct epitem" */
@@ -273,7 +268,7 @@ struct epitem {
struct epitem *ovflist_next;
/* The file descriptor information this item refers to */
- struct epoll_filefd ffd;
+ struct epoll_key ffd;
/* List containing poll wait queues */
struct eppoll_entry *pwqlist;
@@ -526,22 +521,13 @@ static void __init epoll_sysctls_init(void)
static const struct file_operations eventpoll_fops;
-static inline bool is_file_epoll(struct file *f)
+bool is_file_epoll(struct file *f)
{
return f->f_op == &eventpoll_fops;
}
-/* Setup the structure that is used as key for the RB tree */
-static inline void ep_set_ffd(struct epoll_filefd *ffd,
- struct file *file, int fd)
-{
- ffd->file = file;
- ffd->fd = fd;
-}
-
/* Compare RB tree keys */
-static inline int ep_cmp_ffd(struct epoll_filefd *p1,
- struct epoll_filefd *p2)
+static inline int ep_cmp_ffd(struct epoll_key *p1, struct epoll_key *p2)
{
return (p1->file > p2->file ? +1:
(p1->file < p2->file ? -1 : p1->fd - p2->fd));
@@ -1437,17 +1423,15 @@ static int ep_alloc(struct eventpoll **pep)
* are protected by the "mtx" mutex, and ep_find() must be called with
* "mtx" held.
*/
-static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
+static struct epitem *ep_find(struct eventpoll *ep, struct epoll_key *tf)
{
int kcmp;
struct rb_node *rbp;
struct epitem *epi, *epir = NULL;
- struct epoll_filefd ffd;
- ep_set_ffd(&ffd, file, fd);
for (rbp = ep->rbr.rb_root.rb_node; rbp; ) {
epi = rb_entry(rbp, struct epitem, rbn);
- kcmp = ep_cmp_ffd(&ffd, &epi->ffd);
+ kcmp = ep_cmp_ffd(tf, &epi->ffd);
if (kcmp > 0)
rbp = rbp->rb_right;
else if (kcmp < 0)
@@ -1787,8 +1771,8 @@ allocate:
/*
* Charge the user's epoll_watches quota, allocate a fresh epitem for
- * @tfile/@fd, and initialize its fields. The returned item is not yet
- * linked into any data structure; the caller must install it via
+ * @tf, and initialize its fields. The returned item is not yet linked
+ * into any data structure; the caller must install it via
* ep_register_epitem() (which takes over on success) or kmem_cache_free()
* it and decrement epoll_watches on its own.
*
@@ -1797,7 +1781,7 @@ allocate:
*/
static struct epitem *ep_alloc_epitem(struct eventpoll *ep,
const struct epoll_event *event,
- struct file *tfile, int fd)
+ struct epoll_key *tf)
{
struct epitem *epi;
@@ -1814,7 +1798,7 @@ static struct epitem *ep_alloc_epitem(struct eventpoll *ep,
INIT_LIST_HEAD(&epi->rdllink);
epi->ep = ep;
- ep_set_ffd(&epi->ffd, tfile, fd);
+ epi->ffd = *tf;
epi->event = *event;
epi_clear_ovflist(epi);
@@ -1871,8 +1855,8 @@ static int ep_register_epitem(struct ep_ctl_ctx *ctx, struct eventpoll *ep,
* Must be called with "mtx" held.
*/
static int ep_insert(struct ep_ctl_ctx *ctx, struct eventpoll *ep,
- const struct epoll_event *event, struct file *tfile,
- int fd, int full_check)
+ const struct epoll_event *event, struct epoll_key *tf,
+ int full_check)
{
int error, pwake = 0;
__poll_t revents;
@@ -1880,12 +1864,12 @@ static int ep_insert(struct ep_ctl_ctx *ctx, struct eventpoll *ep,
struct ep_pqueue epq;
struct eventpoll *tep = NULL;
- if (is_file_epoll(tfile))
- tep = tfile->private_data;
+ if (is_file_epoll(tf->file))
+ tep = tf->file->private_data;
lockdep_assert_irqs_enabled();
- epi = ep_alloc_epitem(ep, event, tfile, fd);
+ epi = ep_alloc_epitem(ep, event, tf);
if (IS_ERR(epi))
return PTR_ERR(epi);
@@ -2610,8 +2594,8 @@ static void ep_ctl_unlock(struct ep_ctl_ctx *ctx, struct eventpoll *ep,
}
}
-int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
- bool nonblock)
+int do_epoll_ctl_file(struct file *f, int op, struct epoll_key *tf,
+ struct epoll_event *epds, bool nonblock)
{
int error;
int full_check;
@@ -2619,17 +2603,8 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
struct epitem *epi;
struct ep_ctl_ctx ctx = { };
- CLASS(fd, f)(epfd);
- if (fd_empty(f))
- return -EBADF;
-
- /* Get the "struct file *" for the target file */
- CLASS(fd, tf)(fd);
- if (fd_empty(tf))
- return -EBADF;
-
/* The target file descriptor must support poll */
- if (!file_can_poll(fd_file(tf)))
+ if (!file_can_poll(tf->file))
return -EPERM;
/* Check if EPOLLWAKEUP is allowed */
@@ -2637,10 +2612,10 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
ep_take_care_of_epollwakeup(epds);
/*
- * The @epfd file must itself be an eventpoll, and we do not permit
+ * The @f file must itself be an eventpoll, and we do not permit
* adding an epoll file descriptor inside itself.
*/
- if (fd_file(f) == fd_file(tf) || !is_file_epoll(fd_file(f)))
+ if (f == tf->file || !is_file_epoll(f))
return -EINVAL;
/*
@@ -2651,15 +2626,14 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
if (ep_op_has_event(op) && (epds->events & EPOLLEXCLUSIVE)) {
if (op == EPOLL_CTL_MOD)
return -EINVAL;
- if (op == EPOLL_CTL_ADD && (is_file_epoll(fd_file(tf)) ||
+ if (op == EPOLL_CTL_ADD && (is_file_epoll(tf->file) ||
(epds->events & ~EPOLLEXCLUSIVE_OK_BITS)))
return -EINVAL;
}
- ep = fd_file(f)->private_data;
+ ep = f->private_data;
- full_check = ep_ctl_lock(&ctx, ep, op, fd_file(f), fd_file(tf),
- nonblock);
+ full_check = ep_ctl_lock(&ctx, ep, op, f, tf->file, nonblock);
if (full_check < 0)
return full_check;
@@ -2667,15 +2641,14 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
* Look the target up in ep's RB tree. We hold ep->mtx, so the
* item stays valid until we release.
*/
- epi = ep_find(ep, fd_file(tf), fd);
+ epi = ep_find(ep, tf);
error = -EINVAL;
switch (op) {
case EPOLL_CTL_ADD:
if (!epi) {
epds->events |= EPOLLERR | EPOLLHUP;
- error = ep_insert(&ctx, ep, epds, fd_file(tf), fd,
- full_check);
+ error = ep_insert(&ctx, ep, epds, tf, full_check);
} else
error = -EEXIST;
break;
@@ -2706,6 +2679,25 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
return error;
}
+int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
+ bool nonblock)
+{
+ struct epoll_key efd;
+
+ CLASS(fd, f)(epfd);
+ if (fd_empty(f))
+ return -EBADF;
+
+ /* Get the "struct file *" for the target file */
+ CLASS(fd, tf)(fd);
+ if (fd_empty(tf))
+ return -EBADF;
+
+ efd.file = fd_file(tf);
+ efd.fd = fd;
+ return do_epoll_ctl_file(fd_file(f), op, &efd, epds, nonblock);
+}
+
/*
* The following function implements the controller interface for
* the eventpoll file that enables the insertion/removal/change of
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
index 728fb5dee5ed..de1c738aa8ad 100644
--- a/include/linux/eventpoll.h
+++ b/include/linux/eventpoll.h
@@ -61,8 +61,16 @@ static inline void eventpoll_release(struct file *file)
eventpoll_release_file(file);
}
+struct epoll_key {
+ struct file *file;
+ int fd;
+} __packed;
+
+int do_epoll_ctl_file(struct file *f, int op, struct epoll_key *tf,
+ struct epoll_event *epds, bool nonblock);
int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
bool nonblock);
+bool is_file_epoll(struct file *f);
/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
static inline int ep_op_has_event(int op)