[RFC PATCH 3/3] epoll: add read()/write()/ioctl() operations
The eventpoll implementation is largely interface-agnostic, aside from the userspace structure format and epoll_ctl(). Particularly as each field of the structure is handled independently, replacing usage of epoll_event internally was straighforward and clarifies the code some. As for epoll_ctl(), its functionality was moved into the new ep_eventpoll_write() function, and epoll_ctl() just hands off its work to it. The ep_eventpoll_read() function is very similar to epoll_wait(), which remains independent but shares the vast majority of code for minimal redundancy. Finally, ep_eventpoll_ioctl() is a simple interface to configure a default timeout for read() operations on the given eventpoll. Signed-off-by: Nathaniel Yazdani --- diff --git a/fs/eventpoll.c b/fs/eventpoll.c index af90312..7f0ce59 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -168,8 +168,11 @@ struct epitem { /* wakeup_source used when EPOLLWAKEUP is set */ struct wakeup_source __rcu *ws; - /* The structure that describe the interested events and the source fd */ - struct epoll_event event; + /* Interested events */ + int events; + + /* The userspace identifier for this entry */ + long long ident; }; /* @@ -216,6 +219,9 @@ struct eventpoll { struct file *file; + /* Default timeout */ + int timeout; + /* used to optimize loop detection check */ int visited; struct list_head visited_list_link; @@ -251,6 +257,13 @@ struct ep_send_events_data { struct epoll_event __user *events; }; +/* ep_scan_ready_list() callback data for ep_send_epes() */ +struct ep_send_epes_data +{ + int max; + struct epoll __user *epes; +}; + /* * Configuration options available inside /proc/sys/fs/epoll/ */ @@ -795,9 +808,9 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file) static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt) { - pt->_key = epi->event.events; + pt->_key = epi->events; - return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events; + return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->events; } static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, @@ -881,8 +894,8 @@ static int ep_show_fdinfo(struct seq_file *m, struct file *f) struct epitem *epi = rb_entry(rbp, struct epitem, rbn); ret = seq_printf(m, "tfd: %8d events: %8x data: %16llx\n", -epi->ffd.fd, epi->event.events, -(long long)epi->event.data); +epi->ffd.fd, epi->events, +(long long)epi->ident); if (ret) break; } @@ -892,6 +905,15 @@ static int ep_show_fdinfo(struct seq_file *m, struct file *f) } #endif +static ssize_t ep_eventpoll_write(struct file *file, const char __user *buf, + size_t bufsz, loff_t *pos); + +static ssize_t ep_eventpoll_read(struct file *file, char __user *buf, +size_t bufsz, loff_t *pos); + +static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + /* File callbacks that implement the eventpoll file behaviour */ static const struct file_operations eventpoll_fops = { #ifdef CONFIG_PROC_FS @@ -899,6 +921,9 @@ static const struct file_operations eventpoll_fops = { #endif .release= ep_eventpoll_release, .poll = ep_eventpoll_poll, + .read = ep_eventpoll_read, + .write = ep_eventpoll_write, + .unlocked_ioctl = ep_eventpoll_ioctl, .llseek = noop_llseek, }; @@ -1025,7 +1050,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k * EPOLLONESHOT bit that disables the descriptor when an event is received, * until the next EPOLL_CTL_MOD will be issued. */ - if (!(epi->event.events & ~EP_PRIVATE_BITS)) + if (!(epi->events & ~EP_PRIVATE_BITS)) goto out_unlock; /* @@ -1034,7 +1059,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k * callback. We need to be able to handle both cases here, hence the * test for "key" != NULL before the event match test. */ - if (key && !((unsigned long) key & epi->event.events)) + if (key && !((unsigned long) key & epi->events)) goto out_unlock; /* @@ -1264,7 +1289,7 @@ static noinline void ep_destroy_wakeup_source(struct epitem *epi) /* * Must be called with "mtx" held. */ -static int ep_insert(struct eventpoll *ep, struct epoll_event *event, +static int ep_insert(struct eventpoll *ep, long long ident, int events, struct file *tfile, int fd, int
[RFC PATCH 3/3] epoll: add read()/write()/ioctl() operations
The eventpoll implementation is largely interface-agnostic, aside from the userspace structure format and epoll_ctl(). Particularly as each field of the structure is handled independently, replacing usage of epoll_event internally was straighforward and clarifies the code some. As for epoll_ctl(), its functionality was moved into the new ep_eventpoll_write() function, and epoll_ctl() just hands off its work to it. The ep_eventpoll_read() function is very similar to epoll_wait(), which remains independent but shares the vast majority of code for minimal redundancy. Finally, ep_eventpoll_ioctl() is a simple interface to configure a default timeout for read() operations on the given eventpoll. Signed-off-by: Nathaniel Yazdani n1ght.4nd@gmail.com --- diff --git a/fs/eventpoll.c b/fs/eventpoll.c index af90312..7f0ce59 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -168,8 +168,11 @@ struct epitem { /* wakeup_source used when EPOLLWAKEUP is set */ struct wakeup_source __rcu *ws; - /* The structure that describe the interested events and the source fd */ - struct epoll_event event; + /* Interested events */ + int events; + + /* The userspace identifier for this entry */ + long long ident; }; /* @@ -216,6 +219,9 @@ struct eventpoll { struct file *file; + /* Default timeout */ + int timeout; + /* used to optimize loop detection check */ int visited; struct list_head visited_list_link; @@ -251,6 +257,13 @@ struct ep_send_events_data { struct epoll_event __user *events; }; +/* ep_scan_ready_list() callback data for ep_send_epes() */ +struct ep_send_epes_data +{ + int max; + struct epoll __user *epes; +}; + /* * Configuration options available inside /proc/sys/fs/epoll/ */ @@ -795,9 +808,9 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file) static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt) { - pt-_key = epi-event.events; + pt-_key = epi-events; - return epi-ffd.file-f_op-poll(epi-ffd.file, pt) epi-event.events; + return epi-ffd.file-f_op-poll(epi-ffd.file, pt) epi-events; } static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, @@ -881,8 +894,8 @@ static int ep_show_fdinfo(struct seq_file *m, struct file *f) struct epitem *epi = rb_entry(rbp, struct epitem, rbn); ret = seq_printf(m, tfd: %8d events: %8x data: %16llx\n, -epi-ffd.fd, epi-event.events, -(long long)epi-event.data); +epi-ffd.fd, epi-events, +(long long)epi-ident); if (ret) break; } @@ -892,6 +905,15 @@ static int ep_show_fdinfo(struct seq_file *m, struct file *f) } #endif +static ssize_t ep_eventpoll_write(struct file *file, const char __user *buf, + size_t bufsz, loff_t *pos); + +static ssize_t ep_eventpoll_read(struct file *file, char __user *buf, +size_t bufsz, loff_t *pos); + +static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + /* File callbacks that implement the eventpoll file behaviour */ static const struct file_operations eventpoll_fops = { #ifdef CONFIG_PROC_FS @@ -899,6 +921,9 @@ static const struct file_operations eventpoll_fops = { #endif .release= ep_eventpoll_release, .poll = ep_eventpoll_poll, + .read = ep_eventpoll_read, + .write = ep_eventpoll_write, + .unlocked_ioctl = ep_eventpoll_ioctl, .llseek = noop_llseek, }; @@ -1025,7 +1050,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k * EPOLLONESHOT bit that disables the descriptor when an event is received, * until the next EPOLL_CTL_MOD will be issued. */ - if (!(epi-event.events ~EP_PRIVATE_BITS)) + if (!(epi-events ~EP_PRIVATE_BITS)) goto out_unlock; /* @@ -1034,7 +1059,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k * callback. We need to be able to handle both cases here, hence the * test for key != NULL before the event match test. */ - if (key !((unsigned long) key epi-event.events)) + if (key !((unsigned long) key epi-events)) goto out_unlock; /* @@ -1264,7 +1289,7 @@ static noinline void ep_destroy_wakeup_source(struct epitem *epi) /* * Must be called with mtx held. */ -static int ep_insert(struct eventpoll *ep, struct epoll_event *event, +static int ep_insert(struct eventpoll *ep, long long ident, int events, struct file *tfile, int fd, int full_check) {